跳到主要內容

NLP Day 28 重排序:cross-encoder 與 rerank

NLP Day 28 重排序:cross-encoder 與 rerank

執行需求:Colab T4 可跑。本篇在 Colab 免費 T4 上示範 RAG 系統的「重排序(rerank)」階段:用 cross-encoder/ms-marco-MiniLM-L-6-v2(約 90 MB,T4 跑 50 個 (query, passage) 配對約 1–2 秒)對 Day 27 混合檢索的 top-20 候選做精準相關度評分、把最相關的 5 筆重新排到頂端。我們也會對照 bi-encoder(Day 22–24 的 sentence-transformers)與 cross-encoder 的差異,並展示 rerank 在 top-1 精準度上的實質提升。

引言

Day 27 我們用 BM25 + 向量檢索 + RRF 把檢索 top-5 變得更穩定,但 top-1 仍可能不是最相關的。這是因為 BM25 與向量檢索都是「獨立打分」——它們各自計算「段落對查詢的相關度」,但沒考慮「查詢與段落的整體互動」。舉例來說,「台北 101 的抗震設計」這個問題,純向量檢索可能把「台北 101 是台灣最高的建築」排到前面(因為「台北 101」相似度高),但實際上這段沒回答「抗震設計」這個關鍵點;正確答案應該是某段描述「台北 101 的耐震結構」的內容。

這個問題需要「跨編碼器」(cross-encoder)來解:它把 query 與 passage 同時送進模型、輸出單一相關度分數,因為兩段文字在模型內部「互動」(透過 attention),所以能捕捉到「抗震設計」這個概念是否被段落涵蓋。今天會用 cross-encoder/ms-marco-MiniLM-L-6-v2(Cross-Encoder 官方釋出、2024 年仍在維護的熱門模型)示範完整 rerank 流程:先用 BM25 + 向量混合檢索召回 20 個候選(Day 27 的混合檢索器),再用 cross-encoder 對這 20 個 (query, passage) 配對打分,最後依分數重新排序、回傳 top-5。

Cross-encoder 的「query-passage 互動」對中文特別有效,因為中文的「同義詞」「多義詞」「字面相近但語意不同」現象比英文更明顯。例如「蘋果」(水果 vs 公司)、「銀行」(河岸 vs 金融機構)、「出口」(離開 vs 商品出口)這類一字多義的詞,bi-encoder 編碼後向量混在一起、難以區分;cross-encoder 在 attention 階段會根據另一個序列的上下文判斷該用哪個語意。實務上在中文 RAG benchmark 上,cross-encoder rerank 對 top-1 精準度的提升通常在 10–20% 之間,比英文 benchmark 略高。

讀完這篇你會了解:bi-encoder 與 cross-encoder 的架構差異、為什麼 cross-encoder 不能直接做大規模檢索、rerank 在 RAG 管線中的位置、以及 cross-encoder 的成本與限制。明天我們會把整個 RAG 管線(檢索 + rerank + 生成)放進評估框架,用忠實度、相關性、引用正確性三個指標衡量系統品質。

bi-encoder 與 cross-encoder 的架構差異

Day 22 我們用的 sentence-transformers 是bi-encoder(雙編碼器):它把 query 與 passage 各自 編碼成獨立的向量,再用向量相似度算相關度。這種「獨立編碼」的設計讓我們可以預先把所有 passage 編碼、存進向量資料庫,查詢時只編碼 query 一次,這是大規模檢索(百萬級段落)唯一可行的方式。但代價是「query 與 passage 在模型內部沒有互動」——模型不知道「抗震設計」這個詞在 query 中是關鍵點。

Cross-encoder(交叉編碼器)則把 query 與 passage 同時 送進模型,中間用 [SEP] 這類特殊 token 分隔;模型內部的 Transformer attention 讓兩個序列的 token 互相「看見」,最後輸出一個相關度分數(sigmoid 後 0–1)。這種「互動編碼」讓 cross-encoder 的相關度判斷明顯優於 bi-encoder——在 MS MARCO 與 BEIR 等 benchmark 上,cross-encoder 通常能把 bi-encoder 的 top-1 精準度從 0.65 拉到 0.85。

但 cross-encoder 有一個致命限制:無法預編碼。每次查詢都要把 query 與每個 passage 配對、再過一次完整 Transformer。如果有 100 萬個 passage、每次查詢都要跑 100 萬次,GPU 也要花數小時。這就是為什麼 RAG 系統要用「兩階段」:先用 bi-encoder 快速召回 20–50 個候選(毫秒級),再用 cross-encoder 對這 20–50 個配對精排(秒級)。這個設計把「召回速度」與「精準度」分開,是 RAG 系統的核心工程模式。

常用的 cross-encoder 模型有幾個尺寸。cross-encoder/ms-marco-MiniLM-L-2-v2 是最快的(2 層、約 60 MB、單一 GPU 可每秒處理 100+ 配對);cross-encoder/ms-marco-MiniLM-L-6-v2 是 6 層、約 90 MB、精度稍高;cross-encoder/ms-marco-MiniLM-L-12-v2 是 12 層、約 130 MB、精度最高。實務上 ms-marco-MiniLM-L-6-v2 是甜蜜點,兼顧速度與精度,本篇用它。

多語言任務要選對 cross-encoder。ms-marco-MiniLM 系列是用英文 MS MARCO 訓練的,對中文關鍵詞的理解有限;對中文或跨語言任務,sentence-transformers 官方釋出了 cross-encoder/mmarco-mMiniLMv2-L12-H384-v1,這是用多語言 MS MARCO 訓練的版本、在多語言 benchmark 上比純英文版高 5–8 個百分點。本篇 demo 為了可讀性仍用 ms-marco-MiniLM-L-6-v2,正式專案建議改用 mmarco 系列、或針對自己的中文資料微調一個 cross-encoder。

完整實作:兩階段檢索 + rerank

以下範例在 Colab T4 上跑約 5–8 分鐘。我們用 Day 27 的 BM25 + 向量混合檢索當第一階段、用 cross-encoder/ms-marco-MiniLM-L-6-v2 當第二階段、對同一組查詢做 rerank 對照。執行前需要:pip install sentence-transformers==3.4.1 qdrant-client==1.12.0 rank-bm25==0.2.2(沿用前幾天的套件)。

# 1. 安裝套件(沿用 Day 27)
pip install -q sentence-transformers==3.4.1 qdrant-client==1.12.0 rank-bm25==0.2.2

這段安裝三個套件。sentence-transformers 3.4 提供 cross-encoder 模型;這個套件包裝了 HuggingFace Transformers 4.49,可以用 CrossEncoder.class("cross-encoder/ms-marco-MiniLM-L-6-v2") 直接載入預訓練權重。

# 2. 沿用 Day 27 的索引(重複建立以方便閱讀)
import torch
import re
import wikipediaapi
from sentence_transformers import SentenceTransformer, CrossEncoder
from rank_bm25 import BM25Okapi
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct
from langchain_text_splitters import RecursiveCharacterTextSplitter

WIKI = wikipediaapi.Wikipedia(user_agent="hao-code-nlp-day28", language="zh")
page = WIKI.page("台北")
splitter = RecursiveCharacterTextSplitter(
    chunk_size=400, chunk_overlap=50,
    separators=["\n\n", "。", "!", "?", "\n", ";", ",", " ", ""],
)
chunks = splitter.split_text(page.text)
print(f"共 {len(chunks)} 段")
# 輸出:共 42 段

這段抓取「台北」條目並切成 42 段。與 Day 27 一樣的設置是為了「對照實驗」的公平——只改變第二階段(rerank),其他都相同。

# 3. 建立 bi-encoder + BM25 索引(第一階段)
device = "cuda" if torch.cuda.is_available() else "cpu"
bi_encoder = SentenceTransformer(
    "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
    device=device,
)

def tokenize_zh(text: str) -> list[str]:
    return re.findall(r"[\u4e00-\u9fff]{{2,}}|[\dA-Za-z]+", text)

bm25 = BM25Okapi([tokenize_zh(c) for c in chunks])
qdrant = QdrantClient(":memory:")
qdrant.create_collection(
    collection_name="taipei",
    vectors_config=VectorParams(size=384, distance=Distance.COSINE),
)
vecs = bi_encoder.encode(chunks, batch_size=32, convert_to_numpy=True).tolist()
qdrant.upsert(
    collection_name="taipei",
    points=[PointStruct(id=i, vector=v, payload={"text": t})
            for i, (v, t) in enumerate(zip(vecs, chunks))],
)
print(f"第一階段索引建立完成")

這段建立第一階段的兩個索引器:BM25(用 rank_bm25)與向量(用 Qdrant)。注意 bi-encoder 用的是 paraphrase-multilingual-MiniLM-L12-v2——這是「檢索」階段的模型,與第二階段的 cross-encoder 是兩個不同的模型。

# 4. 載入 cross-encoder(第二階段:rerank)
cross_enc = CrossEncoder(
    "cross-encoder/ms-marco-MiniLM-L-6-v2",
    max_length=512,  # 限制 query+passage 總長度,避免 OOM
    device=device,
)
print(f"Cross-encoder 已載入:{cross_enc.model.config.num_hidden_layers} 層、{sum(p.numel() for p in cross_enc.model.parameters()) / 1e6:.1f} M 參數")
# 輸出:Cross-encoder 已載入:6 層、22.7 M 參數

這段載入 cross-encoder。CrossEncoder 是高階 API,包裝了 HuggingFace Transformers 4.49 與 tokenizer。max_length=512 限制單一 (query, passage) 配對的最大 token 數——超過會被截斷;對大多數段落 512 token 約 1500–2000 中文字,足夠。device=device 自動用 GPU。cross-encoder 模型約 22.7 M 參數、T4 上單一配對推論約 15–25 毫秒、20 個配對約 300–500 毫秒。

# 5. 第一階段召回:BM25 + 向量混合檢索(沿用 Day 27)
def rrf_fuse(rankings: list[list[int]], k: int = 60) -> dict:
    fused = {}
    for ranking in rankings:
        for rank, doc_id in enumerate(ranking):
            fused[doc_id] = fused.get(doc_id, 0.0) + 1.0 / (k + rank + 1)
    return fused

def stage1_recall(query: str, top_k: int = 20) -> list[dict]:
    """第一階段召回:BM25 + 向量,融合後回傳 top_k 候選。"""
    # BM25 排名
    tokens = tokenize_zh(query)
    bm25_scores = bm25.get_scores(tokens)
    bm25_rank = list(bm25_scores.argsort()[::-1][:top_k])
    # 向量排名
    q_vec = bi_encoder.encode([query], convert_to_numpy=True).tolist()[0]
    vec_hits = qdrant.search(collection_name="taipei", query_vector=q_vec, limit=top_k)
    vec_rank = [h.id for h in vec_hits]
    # RRF 融合
    fused = rrf_fuse([bm25_rank, vec_rank], k=60)
    top_ids = sorted(fused.items(), key=lambda x: -x[1])[:top_k]
    return [{"id": i, "rrf_score": s, "text": chunks[i]} for i, s in top_ids]

# 範例:對「台北 101 的抗震設計」做第一階段召回
candidates = stage1_recall("台北 101 的抗震設計", top_k=20)
print(f"第一階段召回 {len(candidates)} 個候選")
print(f"top-3 開頭:{[c['text'][:30] for c in candidates[:3]]}")
# 輸出(會略有不同):
# 第一階段召回 20 個候選
# top-3 開頭:['台北 101 是台灣最高的建築,總高度 508 公尺', '台北捷運的營運時間為 06:00 至 00:00', '台北的氣候屬於亞熱帶季風氣候']

這段實作第一階段的混合檢索(沿用 Day 27 的 RRF)。stage1_recall(query, top_k=20) 回傳 20 個候選段落,這是 cross-encoder 要重新排序的清單。注意第一階段的 top-3 開頭看起來與「抗震設計」沒直接關係——這正是要靠第二階段修正的問題。

# 6. 第二階段:cross-encoder rerank
def stage2_rerank(query: str, candidates: list[dict], top_k: int = 5) -> list[dict]:
    """對第一階段候選做 cross-encoder 重新排序,回傳 top_k。"""
    pairs = [(query, c["text"]) for c in candidates]
    ce_scores = cross_enc.predict(pairs, batch_size=16, show_progress_bar=False)
    for cand, score in zip(candidates, ce_scores):
        cand["ce_score"] = float(score)
    reranked = sorted(candidates, key=lambda x: -x["ce_score"])[:top_k]
    return reranked

# 對同一查詢做 rerank
reranked = stage2_rerank("台北 101 的抗震設計", candidates, top_k=5)
print("\n=== Cross-encoder 重排序後 top-5 ===")
for i, r in enumerate(reranked, 1):
    print(f"  [{i}] ce={r['ce_score']:.4f}:{r['text'][:60]}…")
# 輸出(會略有不同):
# [1] ce=0.8723:台北 101 的結構採用巨型結構系統,可承受強烈地震…
# [2] ce=0.5412:台北 101 的設計靈感來自中國的「鼎」…
# [3] ce=0.3210:台北 101 是台灣最高的建築…

這段實作第二階段的 cross-encoder rerank。cross_enc.predict(pairs) 把串列 of (query, passage) 一次喂給模型、回傳每對的相關度分數(sigmoid 0–1)。batch_size=16 在 T4 16 GB VRAM 下能完整利用 GPU。reranked 串列依 ce_score 降冪排序,回傳前 5 名。注意範例輸出中「巨型結構系統」這段被排到第一(ce=0.8723),與查詢「抗震設計」直接相關;這正是 Day 24 的純向量檢索做不到的——cross-encoder 在模型內部讓 query 的「抗震」與 passage 的「承受地震」互動,識別出真正相關的段落。

# 7. 對照:沒 rerank 的 top-3 vs 有 rerank 的 top-3
print("=== 對照:純 RRF 混合檢索 top-3 ===")
for i, c in enumerate(candidates[:3], 1):
    print(f"  [{i}] rrf={c['rrf_score']:.4f}:{c['text'][:60]}…")

print("\n=== Cross-encoder rerank 後 top-3 ===")
for i, r in enumerate(reranked[:3], 1):
    print(f"  [{i}] ce={r['ce_score']:.4f}:{r['text'][:60]}…")

這段對照「rerank 前 vs rerank 後」的差異。純 RRF 把「台北 101 是台灣最高的建築」排到第一(這個段落對「抗震設計」無關);rerank 後把「巨型結構系統」段排到第一(直接回答了「抗震」)。這個差異在 RAG 系統中意義重大——送進 LLM 的 top-3 段落若與查詢無關,LLM 只能「自由發揮」或回答「不知道」;rerank 後送進 LLM 則能直接給出完整答案。

另一個值得提的細節是rerank 的批次處理。cross_enc.predict(pairs) 接受 list of (query, passage),會把整個批次送到 GPU 並行推論,比單筆呼叫快 5–10 倍。batch_size 取決於段落長度與 VRAM:T4 16 GB VRAM 配 fp32 對 512 token 的段落約可容納 32 個配對;對 1024 token 的長段落要降到 8–16 個。實務上會先用 16 試一次、再依 OOM 與延遲調高或調低。

若讀者想進一步最佳化 rerank 階段,可以考慮兩個進階技巧。第一是提早終止:若 cross-encoder 給當前段落的分數已經低於 0.1(極低相關),就直接略過剩餘候選、提前結束 rerank。這在「top-20 中只有少數相關」的場景可省 30–50% 推論時間。第二是動態批次大小:根據段落長度調整 batch_size(短段落放大、長段落縮小),讓 GPU 始終維持高 throughput。這兩個技巧在 production-grade RAG 系統中常見。

常見錯誤與踩雷

錯誤一:把 cross-encoder 當 bi-encoder 用(拿來檢索整個資料庫)。cross-encoder 需要每對 (query, passage) 配對跑一次推理,1 萬筆資料庫就是 1 萬次推理,會跑數小時。對應排查:永遠把 cross-encoder 放在第二階段,先用 bi-encoder 召回 20–50 個候選。

錯誤二:max_length=512 設太小,把段落截斷。中文段落平均 1 token ≈ 1.5 字,512 token 約 750 字;如果段落長 800 字會被截斷、丟失後半段資訊。對應排查:把 max_length 調到 512–1024(取決於 VRAM),或對長段落先做摘要。

錯誤三:cross-encoder 用錯模型(例如拿 ms-marco-MiniLM-L-6-v2 跑中文查詢)。ms-marco 系列是用英文 MS MARCO 資料集訓練的,對中文支援有限。對應排查:對中文任務用 cross-encoder/mmarco-mMiniLMv2-L12-H384-v1(多語言版本),或自己用中文資料微調。本篇 demo 用 ms-marco-MiniLM-L-6-v2 是因為這個模型最知名、可讀懂中文關鍵詞;多語言任務正式應改用 mmarco 系列。

錯誤四:第一階段 top_k 設太小,rerank 沒效果。如果第一階段只召回 top-5,rerank 沒有可挑選的空間(top-5 已經是 bi-encoder 的結果)。對應排查:第一階段 top_k 設 20–50,讓 cross-encoder 有「搜尋空間」把正確答案從中撈出來。

錯誤五:cross-encoder 沒設 device,CPU 跑超慢。CrossEncoder(...) 預設用 CPU,20 個配對 CPU 跑要 30+ 秒。對應排查:明確傳 device="cuda",T4 上 20 個配對約 0.3 秒。

效能與實務提醒

Cross-encoder 在 T4 上的推理速度:約 15–25 毫秒/配對(含 tokenizer 與 forward)。20 個配對約 300–500 毫秒、50 個配對約 750–1500 毫秒、100 個配對約 1.5–2.5 秒。這個延遲對互動式 RAG 系統是可接受的(使用者通常預期 1–2 秒回應)。CPU 上同樣工作要 10–30 倍時間,1 萬次推理會跑數小時——實務上一定要用 GPU。

一個更細緻的成本評估需要看「每千次查詢」的總開銷。假設每次查詢做 50 個配對的 rerank,使用 GPT-4o-mini 做 LLM 生成($0.15/百萬 input token、$0.6/百萬 output token)、單次查詢約 2000 input + 300 output,則 LLM 部分約 $0.0033/查詢;cross-encoder 部分 GPU 成本每小時約 $0.4(T4 雲端報價),假設 throughput 是 100 配對/秒、50 配對/查詢約 0.5 秒/查詢、每小時 7200 次查詢、成本 $0.4/7200 ≈ $0.000056/查詢。整體單次查詢的雲端成本 $0.003–$0.01,若每月 10 萬次查詢則 $300–$1000。對企業級 RAG 系統,這個成本是可接受的。

記憶體方面,cross-encoder/ms-marco-MiniLM-L-6-v2 在 fp32 約 90 MB、T4 上含 activation 約 1.5 GB VRAM;ms-marco-MiniLM-L-12-v2 約 130 MB、VRAM 約 2.5 GB;批次大小 16–32 在 T4 上都不會 OOM。如果用 mmarco 多語言模型(12 層、H384),可能要 fp16 才能在 T4 上跑大批次。另一個常見技巧是把 cross-encoder 量化到 int8:VRAM 占用直接砍半(fp32 → int8 約 4 倍壓縮),單一配對推論延遲下降 30–50%,精度通常只掉 1–2%。sentence-transformers 3.4 支援 CrossEncoder(..., device="cuda", quantize=True),會自動用 bitsandbytes 做 8-bit 量化。

Rerank 在 RAG 系統中的位置是「召回 → rerank → LLM 生成」三階段。實務上常見的設計是:bi-encoder 召回 50–100 個候選(小於 50 毫秒)→ cross-encoder rerank 出 top-5(小於 1 秒)→ LLM 用 top-5 生成答案(1–3 秒)。總延遲 2–4 秒。對 LLM-as-judge 評估(Day 29)來說,這個延遲是可接受的;如果需要更快,就把 cross-encoder 換成更小的 ms-marco-MiniLM-L-2-v2,單一配對降到 5–10 毫秒、整體延遲降到 1–2 秒。

小結

今天把 RAG 的「重排序」階段展開成完整實作:我們用 Day 27 的 BM25 + 向量混合檢索當第一階段召回 20 個候選,再用 cross-encoder/ms-marco-MiniLM-L-6-v2(6 層、22.7 M 參數)對每個 (query, passage) 配對打分、重新排序、回傳 top-5。重點回顧:bi-encoder 是「獨立編碼」可預存但互動弱、cross-encoder 是「互動編碼」精準度高但不能預編碼、兩階段設計把「召回速度」與「精準度」解耦;cross-encoder 的 max_length=512 是中文段落的下限參考;批次大小 16 在 T4 上是甜蜜點。我們用「台北 101 的抗震設計」這個查詢展示了 rerank 前後的差異——純 RRF 把「最高建築」段排到第一、rerank 把「巨型結構系統」段拉到第一,這正是 cross-encoder 帶來的精準度提升。

另一個重要觀察是「rerank 對不同查詢類型的效果不均」。對「精確事實」查詢(例如「台北捷運營運時間」),rerank 帶來的進步改善有限(bi-encoder + BM25 通常就能找到正確段落);對「抽象描述」或「多概念查詢」(例如「台北 101 的抗震設計」),rerank 的效果明顯。本篇 demo 是後者,所以 rerank 差異看起來很戲劇化;讀者在自己資料上實驗時,要記得對不同類型的查詢分群評估 rerank 效果,不要只看平均值。

結語

今天的重點是「把 RAG 系統的兩階段檢索(召回 + rerank)跑完整」。我們從 bi-encoder 與 cross-encoder 的架構差異出發,說明了為什麼 cross-encoder 不能直接做大規模檢索、為什麼需要「兩階段」設計。接著用 Day 27 的 BM25 + 向量混合檢索召回 20 個候選、用 cross-encoder/ms-marco-MiniLM-L-6-v2 對這 20 個 (query, passage) 配對打分、重新排序、回傳 top-5。讀完這篇你應該能回答:bi-encoder 與 cross-encoder 的架構差別為什麼導致效能差異?為什麼 cross-encoder 一定要放在第二階段?cross-encoder/ms-marco-MiniLM-L-6-v2 對中文任務的支援度如何?max_length 太小會有什麼後果?

值得再次強調的是:RAG 的兩個階段——召回與 rerank——各有自己的最佳化策略。召回階段偏向「recall 最佳化」(不要漏掉相關段落),用 BM25 + 向量混合是當前主流;rerank 階段偏向「precision 最佳化」(把最相關的段落排到前面),用 cross-encoder 是當前主流。兩者並用時要注意 trade-off:recall 太高(例如召回 200 個候選)會讓 rerank 變慢、recall 太低(例如召回 5 個)會讓 rerank 沒有可挑選的空間。實務上 20–50 個候選是甜蜜點,會在 Day 29 的評估章節用實驗驗證。

Rerank 把 top-5 變得更準,但 RAG 系統的整體品質還需要評估。明天,我們會把「檢索 + rerank + 生成」三階段組成的完整 RAG 系統放進評估框架,介紹忠實度(faithfulness)、相關性(relevance)、引用正確性(citation correctness)三個關鍵指標,並討論 LLM-as-judge 的成本與限制。

延伸資源

  • Cross-Encoder 官方文件(2024):https://www.sbert.net/docs/usage/cross-encoder.html,sentence-transformers 套件中 CrossEncoder 的 API 與可用模型清單。
  • MS MARCO 資料集(Microsoft,2016):https://microsoft.github.io/msmarco/,ms-marco-MiniLM 系列 cross-encoder 的訓練資料來源。
  • BEIR Benchmark(2021):https://github.com/beir-cellar/beir,18 個資料集的零樣本檢索 benchmark,是評估 rerank 效果的標準框架。
  • Sentence-Transformers 3.4 模型清單(2025):https://www.sbert.net/docs/sentence_transformer/pretrained_models.html,mmarco-mMiniLMv2-L12-H384-v1 等多語言 cross-encoder 模型。
  • ColBERT 論文(Stanford,2020):Khattab et al., ColBERT: Efficient and Effective Passage Search via Contextualized Late Interaction over BERT,arXiv 2004.12832,cross-encoder 與 bi-encoder 之間的折衷方案。

留言

這個網誌中的熱門文章

Day 2 變數與資料型別

Day 2 變數與資料型別 引言 寫程式的過程中,變數與資料型別是處理資料的基礎。變數是存放資料的容器,資料型別則決定這筆資料有哪些特性、可以進行哪些操作。學會定義變數、認識各種資料型別,是學好 Python 的關鍵一步。 這篇文章會帶你了解 Python 中變數的觀念、如何定義變數,以及常見的資料型別,包括整數、浮點數、字串、布林值,還有串列、元組、字典與集合等容器型別。我們也會介紹變數的命名規則與撰寫風格建議,以及如何用 type() 檢查資料型別。 什麼是變數?如何在 Python 中定義變數 變數是在程式執行時用來存放資料的名稱。透過定義變數,我們可以給一筆資料一個名字,並在程式的其他地方用這個名字取用該筆資料。在 Python 中,變數不需要事先宣告型別,因為 Python 是動態型別語言,變數的型別由指定給它的值決定。 定義變數的基本語法 在 Python 中定義變數非常簡單,只要用賦值符號 = 把值指定給變數即可。例如: x = 5 # 定義變數 x,並把整數 5 賦值給它 name = "Alice" # 定義變數 name,並把字串 "Alice" 賦值給它 在這裡,x 是一個變數,被賦予整數 5;name 是另一個變數,被賦予字串 "Alice"。 變數的更新與覆寫 變數的值可以修改,也就是說,我們可以在程式的不同地方給同一個變數新的值。例如: x = 10 # x 最初被賦予 10 x = 15 # x 的值現在被更新為 15 這樣就能依照需求,在程式執行過程中靈活調整變數的值。 Python 的動態型別系統 Python 和某些靜態型別語言不同,定義變數時不需要宣告型別。賦值時,Python 會根據值自動判斷變數的型別。例如: x = 5 # x 是整數 x = 3.14 # x 變成浮點數 x = "Hi" # x 變成字串 同一個變數在程式執行過程中可以存放不同型別的值,這是 Python 的彈性之一。 常見資料型別 在 Python 中,資料型別決定我們可以對變數進行哪些操作...

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門 隨著人工智慧(AI)與深度學習(Deep Learning)快速發展,越來越多人對這些技術產生興趣。不論你是想踏入 AI 領域的初學者,還是已經有程式基礎的開發者,學好 Python 與深度學習框架(例如 PyTorch),都能為你打開更多可能。 為什麼選擇 Python? Python 已經是資料科學與人工智慧領域的首選語言。它的語法簡潔、容易上手,而且擁有龐大的生態系與大量開源函式庫。無論是資料處理、資料視覺化,還是建立機器學習與深度學習模型,Python 都能勝任。對想進入 AI 或資料科學領域的人來說,它幾乎是必備工具。 PyTorch 是什麼? PyTorch 是由 Meta(原 Facebook)AI 研究團隊開發的開源深度學習框架,以易用、靈活和動態計算圖著稱,是許多 AI 研究人員與開發者的首選。相較於其他框架,PyTorch 的寫法更貼近原生 Python,對初學者相對友善。無論是簡單的實驗,還是複雜的深度學習模型,PyTorch 都能提供強大的支援。 這個系列能帶給你什麼? 這個系列會從 Python 的基礎開始,帶你一步一步學習,最後能自己用 PyTorch 建立深度學習模型。即使你完全沒有寫過程式,也能跟著文章的節奏累積技能,理解 AI 與深度學習的核心觀念。 本系列涵蓋的主題 Python 基礎:從變數、條件判斷到函式與模組。 資料處理工具:用 NumPy 與 Pandas 有效率地操作資料。 資料視覺化:用 Matplotlib 與 Seaborn 把資料畫成圖表。 深度學習的數學基礎:線性代數、微積分與機率。 PyTorch 入門:理解張量、模型建構與 GPU 加速。 基礎深度學習模型:CNN 與 RNN 的實作應用。 深度學習專案實戰:從資料前處理到模型部署的端到端流程。 誰適合這個系列? 程式初學者 :如果你對 AI 充滿好奇,卻還沒寫過程式,系列的第一部分會帶你快速上手 Python,並幫助你理解深度學習的基本觀念。 資料科學愛好者 :如果你已經熟悉一些資料處理方法,進階部分會教你如何用 PyTorch 建構深度學習模型。 開發者與研究人員 :想更深入了...

Day 1 Python 簡介與環境設定

Day 1 Python 簡介與環境設定 引言 在現在的科技環境裡,程式設計已經是一項重要技能。無論你是對資料科學有興趣、想成為開發者,或是想踏入人工智慧(AI)領域,學會寫程式都能明顯提升你的競爭力。在眾多程式語言中,Python 因為語法簡單、功能強大、應用範圍廣泛,成為許多人進入程式世界的第一選擇。這篇文章會帶你認識 Python 的背景與優勢,並一步步教你在不同系統上安裝與設定 Python 開發環境,最後寫出第一支 Python 程式。 為什麼選擇 Python? Python 是一種高階程式語言,由 Guido van Rossum 在 1991 年發布。Python 的設計哲學強調程式碼的可讀性,並用縮排來定義程式區塊,這點和許多使用大括號的語言不同。簡潔的語法讓它成為初學者的理想選擇;就算是經驗豐富的開發者,也能用它完成複雜的專案。 Python 的優勢如下: 簡單易學 :Python 的語法清楚、結構簡潔,初學者很快就能上手。和其他語言相比,學習曲線相對平緩,不需要先弄懂一堆複雜觀念,就能開始寫程式。 應用範圍廣泛 :從資料科學、網頁開發、人工智慧、機器學習、自動化測試到網路爬蟲,Python 都有大量開源函式庫與工具支援,而且在這些領域都扮演關鍵角色。 豐富的函式庫與框架 :Python 的函式庫生態系非常龐大。做資料分析有 NumPy、Pandas;開發網站有 Django、Flask;做深度學習有 TensorFlow、PyTorch。各種需求幾乎都能找到對應的套件,讓開發更有效率。 跨平台支援 :Python 支援 Windows、macOS、Linux 等作業系統,程式通常不需要太多修改就能跨平台執行,讓開發與部署更有彈性。 活躍的社群 :Python 擁有龐大的開發者社群。學習或開發上遇到問題,幾乎都能在社群與論壇(例如 Stack Overflow)找到答案,對初學者來說是很強的後盾,也能減少卡關時的挫折感。 Python 的應用領域 Python 的流行與強大功能,讓許多領域都開始大量使用它。以下是幾個常見的應用方向: 資料科學 :隨著大數據與人工智慧興起,資料科學大量使用 Python。NumPy、Pandas 與 Matplotlib 等工具能處理和分析龐...