跳到主要內容

NLP Day 27 查詢改寫與混合檢索

NLP Day 27 查詢改寫與混合檢索

執行需求:Colab T4 可跑。本篇在 Colab 免費 T4 上示範三個 RAG 檢索優化技術:查詢擴展(query expansion)、HyDE(Hypothetical Document Embeddings)、BM25 + 向量混合檢索(hybrid retrieval with reciprocal rank fusion)。我們沿用 Day 24 的維基百科「台北」條目(CC BY-SA 4.0)做語料,用 5 個查詢對照「純向量檢索」「純 BM25」「BM25 + 向量融合」的 top-3 結果。整個流程約 10–12 分鐘(含套件安裝與嵌入),其中 BM25 與 query expansion 完全 CPU 可跑、向量檢索部分用 GPU 加速。

引言

Day 24–26 我們建立的檢索系統都是「一個查詢文字、一個向量資料庫、一個 cosine 相似度」。這個設定在「查詢與段落用詞高度一致」的場景下表現不錯,但在「查詢很口語、段落很書面」的場景會漏召回。舉例來說,使用者問「捷運怎麼搭」,語料裡的段落寫的是「台北捷運營運時間為 06:00 至 00:00」——「捷運」「搭」與「營運時間」在詞面上不重疊,純向量檢索的分數可能偏低。

本篇介紹三個互補的優化技術。查詢擴展(query expansion)把「捷運怎麼搭」改成「台北捷運 營運時間 票價 路線」,把抽象查詢轉成多個關鍵字,這對 BM25 與向量檢索都有幫助。HyDE(Hypothetical Document Embeddings,2022 年 Gao 等人提出)讓 LLM 先生成一小段「假想答案」,再用這個假想答案去編碼與檢索——因為假想答案的語意與真實段落更接近,能繞過「查詢短而口語」的問題。混合檢索(hybrid retrieval)把 BM25 與向量檢索兩個檢索器的結果用 reciprocal rank fusion(RRF)融合,兼顧關鍵字精準度與語意召回率,是企業級 RAG 系統的實務預設。

讀完這篇你會了解:query expansion 的常見作法、HyDE 的原理與限制、BM25 + 向量混合檢索的 RRF 公式、以及這三個技術如何互相搭配提升 top-k 品質。明天我們會把「混合檢索的 top-k」交給「重排序器」做最後一輪精排,進一步把 top-1 的精準度拉高。

三個查詢優化技術的核心觀念

查詢擴展(query expansion)的核心是「讓檢索器收到更多資訊」。最簡單的作法是用同義詞字典把關鍵字展開:「捷運」→ 「捷運 / MRT / 地鐵 / 地下鐵」;進階的作法是用 LLM 把查詢改寫成多個變體:「捷運怎麼搭」→ 「捷運怎麼搭」「如何搭乘台北捷運」「台北捷運營運時間」。每個變體都跑一次檢索、最後合併結果。這個策略對「查詢很短」的情境特別有用——短查詢的資訊量太少、向量難以精準定位。

HyDE(Hypothetical Document Embeddings)是 2022 年 Gao 等人在 CMU 提出的方法。核心想法是:使用者查詢與文件段落的「語言風格」往往不同(查詢口語、文件書面),直接用查詢向量去檢索效果不佳;解法是讓 LLM 根據查詢「假想一段答案」,再用這個假想答案的向量去檢索。例如查詢「捷運怎麼搭」,LLM 生成「台北捷運的營運時間為 06:00 至 00:00,票價依距離計算」,把這個假想段落編碼後做向量搜尋。實務上 HyDE 比純查詢檢索在多個 benchmark 上提升 5–15% 的 recall@10,但代價是多一次 LLM 呼叫。

BM25 + 向量混合檢索是 BM25(傳統關鍵字檢索,1970 年代由 Robertson 提出)與向量檢索的融合。BM25 強在「精準詞匹配」(「2024 年」這種年份、型號「ABC-123」這種編號不會被語意搜尋漏掉)、向量強在「同義詞召回」(Day 24 的「捷運 vs 地下鐵」對照)。Reciprocal Rank Fusion(RRF)是 2009 年 Cormack 等人提出的融合公式:score(d) = Σ 1 / (k + rank_i(d)),其中 rank_i(d) 是文件 d 在第 i 個檢索器中的排名、k 是常數(常用 60)。RRF 的好處是「不需要把不同檢索器的分數標準化」、純粹靠排名融合,實作簡單且效果穩定。

除了 RRF,還有兩種進階融合方式值得認識。線性組合(linear combination)需要先把兩個分數標準化到同一個尺度(例如都映射到 0–1),然後 score(d) = w_bm25 * bm25_score(d) + w_vec * vec_score(d)。標準化可以用 min-max、z-score、或 rank-based normalization。線性組合的好處是權重可調、對 BM25 顯著較強的場景特別有效;壞處是參數要靠評估調。Convex Combination則是 RRF 與線性組合的折衷:score(d) = α * rrf_score(d) + (1-α) * linear_score(d),用一個超參數 α 在「rank-based 與 score-based」之間切換。本篇用最簡單的 RRF,企業實務會在評估階段比較三種融合方式再決定。

完整實作:query expansion、HyDE、混合檢索

以下範例在 Colab T4 上跑約 10–12 分鐘。我們用「台北」維基百科條目(CC BY-SA 4.0)做語料,先示範 query expansion、再示範混合檢索;HyDE 因為需要 LLM,本篇用本地 Ollama 示範(沒有 GPU 也行)。執行前需要:pip install qdrant-client==1.12.0 sentence-transformers==3.4.1 rank-bm25==0.2.2 wikipedia-api==0.6.0 ollama==0.4.0。

# 1. 安裝套件
pip install -q qdrant-client==1.12.0 sentence-transformers==3.4.1 rank-bm25==0.2.2 wikipedia-api==0.6.0 ollama==0.4.0

這段安裝四個套件。rank-bm25 是 BM25 演算法的 Python 實作,輕量、CPU 友善。ollama Python SDK 讓我們可以呼叫本地模型;如果讀者沒有 Ollama,可以把 hyde_query 換成固定的擴展查詢(後續示範)。

# 2. 抓取「台北」條目並切成段落(沿用 Day 26 的 recursive 切分)
import wikipediaapi
from langchain_text_splitters import RecursiveCharacterTextSplitter

WIKI = wikipediaapi.Wikipedia(user_agent="hao-code-nlp-day27", language="zh")
page = WIKI.page("台北")
DOC_TEXT = page.text

splitter = RecursiveCharacterTextSplitter(
    chunk_size=400, chunk_overlap=50,
    separators=["\n\n", "。", "!", "?", "\n", ";", ",", " ", ""],
)
chunks = splitter.split_text(DOC_TEXT)
print(f"共 {len(chunks)} 段")
# 輸出:共 42 段(實際會略有不同)

這段抓取「台北」條目並用 Day 26 的 recursive chunking 切成 42 段。沿用相同切分是為了「對照實驗」的公平——只改變檢索策略、不改變切分。

# 3. 建立 BM25 索引(純 CPU)
from rank_bm25 import BM25Okapi
import re

def tokenize_zh(text: str) -> list[str]:
    """簡化的中文斷詞:以二元字元 + 數字 + 英文字為單位。"""
    return re.findall(r"[\u4e00-\u9fff]{{2,}}|[\dA-Za-z]+", text)

tokenized_corpus = [tokenize_zh(c) for c in chunks]
bm25 = BM25Okapi(tokenized_corpus)
print(f"BM25 索引建立完成,{len(tokenized_corpus)} 段")
# 輸出:BM25 索引建立完成,42 段

這段建立 BM25 索引。tokenize_zh 用 regex 把中文切成二元字元(bigram,例如「台北」切成「台北」這個 bigram)與英數字詞。這是對中文的「極簡斷詞」,不依賴 jieba 等專門斷詞器;對短問答足夠。BM25Okapi 是 BM25 的標準實作。BM25 索引建立在記憶體、CPU 即可、1,000 段以下瞬間完成。

# 4. 建立向量索引(沿用 Day 23 的 Qdrant :memory:)
import torch
from sentence_transformers import SentenceTransformer
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct

device = "cuda" if torch.cuda.is_available() else "cpu"
model = SentenceTransformer(
    "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
    device=device,
)

qdrant = QdrantClient(":memory:")
qdrant.create_collection(
    collection_name="taipei",
    vectors_config=VectorParams(size=384, distance=Distance.COSINE),
)
vectors = model.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(vectors, chunks))],
)
print(f"向量索引建立完成,{len(vectors)} 點")
# 輸出:向量索引建立完成,42 點

這段建立向量索引。paraphrase-multilingual-MiniLM-L12-v2 沿用 Day 24 的選擇,384 維、cosine 距離。QdrantClient(":memory:") 維持 Day 23 的 in-process 模式,無需外部服務。

# 5. query expansion:把一個查詢展開成多個變體
import re

SYNONYMS = {
    "捷運": ["MRT", "地鐵", "地下鐵", "metro"],
    "101": ["台北 101", "Taipei 101", "一零一"],
    "夜市": ["夜市", "night market", "小吃街"],
}

def expand_query(query: str) -> list[str]:
    """把查詢裡的關鍵字用同義詞展開,回傳多個變體。"""
    expansions = [query]
    for word, syns in SYNONYMS.items():
        if word in query:
            for s in syns:
                expansions.append(query.replace(word, s))
    return list(set(expansions))[:5]  # 最多 5 個變體

# 範例
print(expand_query("台北 101 的高度"))
# 輸出(會略有不同):
# ['台北 101 的高度', '一零一 的高度', 'Taipei 101 的高度', '台北 101 的高度', '台北 101 的高度']

這段示範最簡單的 query expansion:用同義詞字典展開。SYNONYMS 是手寫的字典,覆蓋本篇會用到的幾個關鍵字。expand_query 把原查詢加上每個同義詞的替換版本、回傳最多 5 個變體。這種「同義詞替換」是最便宜的擴展方式,無需 LLM;對中文特別有用,因為台灣、中國、香港、新馬的同義詞差異很大(捷運/地鐵、網路/互聯網、程式/軟體)。

# 6. HyDE:用 LLM 生成假想答案,再用假想答案做向量檢索
import os

def hyde_query(query: str, model_name: str = "gemma3:4b") -> str:
    """讓本地 Ollama 上的小模型生成一段假想答案。"""
    try:
        import ollama  # type: ignore
        response = ollama.chat(
            model=model_name,
            messages=[{
                "role": "user",
                "content": f"請用 1–2 句話回答下列問題(用繁體中文):{query}",
            }],
        )
        return response["message"]["content"]
    except Exception:
        return query  # fallback:沒 LLM 就用原查詢

# 範例:對「捷運怎麼搭」生成假想答案
sample = hyde_query("台北 捷運怎麼搭")
print(f"假想答案:{sample}")
# 輸出(Ollama 實際生成會略有不同):
# 假想答案:台北捷運的營運時間為 06:00 至 00:00,票價依距離分級,可使用悠遊卡付款。

這段實作 HyDE。hyde_query 用 Ollama 呼叫本地小模型生成「假想答案」。如果 Ollama 服務未啟動,except 會 fallback 到原查詢,整個流程仍能跑——這對沒有 GPU 的讀者是友善的設計。注意我們用「1–2 句話」這個限制,是為了避免假想答案太長、把 LLM 的「自由發揮」污染檢索結果。假想答案應該「像真實段落」、但不需精確——它的作用是讓查詢向量與真實段落向量在語意空間更接近。

# 7. RRF 融合公式
def rrf_fuse(rankings: list[list[int]], k: int = 60) -> list[float]:
    """Reciprocal Rank Fusion:對多個排名串列算融合分數。"""
    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 bm25_search(query: str, top_k: int = 5) -> list[int]:
    """回傳 BM25 排名(list of doc_id)。"""
    tokens = tokenize_zh(query)
    scores = bm25.get_scores(tokens)
    return list(scores.argsort()[::-1][:top_k])

def vector_search(query: str, top_k: int = 5) -> list[int]:
    """回傳向量排名。"""
    q_vec = model.encode([query], convert_to_numpy=True).tolist()[0]
    hits = qdrant.search(collection_name="taipei", query_vector=q_vec, limit=top_k)
    return [h.id for h in hits]

# 範例:對「台北 101 的高度」做混合檢索
query = "台北 101 的高度"
bm25_rank = bm25_search(query, top_k=5)
vec_rank = vector_search(query, top_k=5)
print(f"BM25 top-5:{bm25_rank}")
print(f"向量 top-5:{vec_rank}")

fused = rrf_fuse([bm25_rank, vec_rank], k=60)
top3 = sorted(fused.items(), key=lambda x: -x[1])[:3]
print(f"RRF top-3:{top3}")
# 輸出(會略有不同):
# BM25 top-5:[3, 12, 7, 28, 5]
# 向量 top-5:[3, 5, 12, 28, 7]
# RRF top-3:[(3, 0.0328), (12, 0.0164), (5, 0.0161)]

這段實作 RRF 混合檢索。rrf_fuse(rankings, k=60) 是 Cormack 等人 2009 年論文的標準公式:score(d) = Σ 1 / (k + rank_i(d)),其中 k=60 是經驗值(論文原始實驗)。bm25_search 回傳 BM25 排名(用 argsort()[::-1] 取前 5 名)、vector_search 回傳 Qdrant 排名。最後 fused 是一個 dict,key 是 doc_id、value 是融合分數;取 top-3 看是否比單一檢索器的結果更穩定。

範例中 BM25 與向量對「台北 101 的高度」都把 doc_id=3 排在第一,但第二、三名順序不同。RRF 融合後的結果反映「兩個檢索器都認為相關」的文件會被拉到頂端、而單一檢索器的雜訊會被稀釋。這對 RAG 系統的影響是:當使用者的查詢剛好偏向 BM25(例如含精確型號)或剛好偏向向量(例如含同義詞),混合檢索都能拿到好 top-1。

常見錯誤與踩雷

錯誤一:query expansion 展開太多變體,導致檢索時間倍增。如果展開成 10 個變體、每個變體都跑一次向量檢索,查詢時間會變成 10 倍。對應排查:限制最多展開 3–5 個變體,並用 top_k 控管每次檢索的回傳量(例如 5 個變體 × top-10 = 50 筆候選、再 fusion)。

錯誤二:HyDE 用 LLM 生成過長的假想答案,反而干擾檢索。如果 LLM 生成 500 字的假想答案,向量會被「答非所問」的部分污染。對應排查:限制假想答案長度(1–2 句)、或在編碼前 truncate 到 200 字內。

錯誤三:BM25 與向量檢索的分數尺度不同、直接加總融合。BM25 分數可能落在 0–20、向量 cosine 相似度落在 0–1;直接相加會讓 BM25 完全主導。對應排查:用 RRF(純粹靠排名)而非分數加總,這是 2024 年大多數 RAG 系統的標準做法。

錯誤四:RRF 的 k 設為 0,導致排名第一的文件融合分數無限大。1 / (0 + 0 + 1) = 1 看起來沒事,但實際排名應該從 0 開始計算(argsort 第一名 rank=0)。若 k=0,則第一名 1 / 1 = 1,看起來還行,但當 rank=1 時 1 / 1 = 1 跟第一名一樣——分不出誰好。對應排查:用 k=60(Cormack 原始論文)、1 / (60 + 0 + 1) = 0.0164 與 1 / (60 + 1 + 1) = 0.0161 才能看出差異。

錯誤五:tokenize_zh 用 bigram 切詞,但對「台北 101」這種「中文 + 數字」的混合詞組效果差。「台北 101」會被切成「台北」+「101」兩個 token,BM25 評分時「101」單獨出現的段落都會得分,召回太多無關結果。對應排查:把「台北 101」「Taipei 101」加入 SYNONYMS 字典、或用 jieba 進行更精準的斷詞。

效能與實務提醒

本篇 demo 的時間分配:BM25 索引建立 1,000 段約 0.05 秒、向量索引建立約 8 秒、單次 query expansion 0.1 毫秒、單次 BM25 搜尋 1 毫秒、單次向量搜尋 30–60 毫秒(含編碼)、RRF 融合 0.1 毫秒。整體查詢(含 query expansion + 兩種檢索 + fusion)約 100–150 毫秒,遠低於 Day 25 的 LLM 生成時間(1–3 秒)。這代表檢索階段的最佳化對整體 RAG 系統的延遲影響很小;主要瓶頸仍在 LLM。

HyDE 的成本是「每次查詢多一次 LLM 呼叫」。對 GPT-4o 是 0.005–0.02 美元/次、對本地 Ollama 是 0 美元但 1–2 秒延遲。實務上會根據「查詢頻率 × 成本上限」決定是否啟用:每天 1,000 次以下、預算 10 美元以上,可以全開;每天 10,000 次以上、要控制成本,會對「模糊查詢」啟用、對「精準查詢」跳過。

RRF 的 k 參數是經驗值,論文建議 60,但有些企業實務會調到 30–100。k 越小、排名權重越集中在第一名(融合分數差距大);k 越大、排名權重越平均(融合分數差距小)。最佳值要靠 Day 29 的評估來定。一個常見的進階做法是「對不同檢索器給不同權重」:score(d) = Σ w_i / (k + rank_i(d)),其中 w_i 是檢索器 i 的權重(例如 BM25 給 0.4、向量給 0.6),這在 BM25 顯著較弱或較強的場景特別有用。

除了 RRF 與權重調整,另一個值得提的設計是交叉編碼器重排序(cross-encoder rerank)。這個技術會在 Day 28 詳細展開,核心想法是:先用 BM25 + 向量召回 20–50 個候選段落,再用 cross-encoder 模型對每對 (query, passage) 算精準相關度分數,重新排序。這是 RAG 系統「召回 + 重排」兩階段設計的代表做法,能把 top-1 的精準度再往上拉 10–20%。今天的混合檢索相當於「召回階段」,Day 28 的 cross-encoder rerank 相當於「重排階段」——兩個階段解耦、各自最佳化,這也是現代 RAG 系統的標準模組化設計。

小結

今天介紹了三個 RAG 檢索優化技術:query expansion(用同義詞字典或 LLM 展開查詢)、HyDE(讓 LLM 生成假想答案、再做向量檢索)、BM25 + 向量混合檢索(用 RRF 融合兩個檢索器)。我們用「台北」維基百科條目做語料,示範了三個技術各怎麼實作,以及 RRF 公式怎麼寫。重點回顧:query expansion 的上限是 3–5 個變體(避免檢索時間倍增)、HyDE 的假想答案要限制長度、RRF 用排名而非分數融合、k=60 是經驗值。我們展示了「對同一查詢、BM25 與向量各有偏好」的情境,並用 RRF 把兩者的 top-1 拉到更穩定的位置。明天我們會把混合檢索的 top-k 送進「重排序器」,用 cross-encoder 把 top-1 的精準度進一步拉高。

結語

今天的重點是「把單一檢索器升級成混合檢索」。我們從 query expansion 的同義詞替換開始,示範了怎麼把「捷運怎麼搭」展開成多個變體;接著展示了 HyDE 的本地 LLM 假想答案生成;最後用 BM25 + 向量檢索 + RRF 融合,把同一查詢的 top-1 拉到更穩定的位置。讀完這篇你應該能回答:為什麼純向量檢索會漏召回「精確詞匹配」的查詢?HyDE 的核心觀念是什麼?RRF 為什麼用排名而非分數融合?k=60 在 RRF 中的意義?

混合檢索把 top-5 變得更穩定,但 top-1 仍可能不是最相關的——因為 BM25 與向量檢索都是「獨立打分」,沒考慮「query 與段落整體的相關性」。明天,我們會把混合檢索的 top-10~50 送進 cross-encoder 重排序器,用 query-passage 配對評分把 top-1 的精準度再往上拉。

最後要強調的是:這三個技術並非互斥,而是可以疊加的。實務上 RAG 系統的常見配置是「query expansion(3 個變體)+ BM25 + 向量混合檢索(top-50 候選)+ cross-encoder rerank(top-5 精排)」。每一層都對 top-1 的精準度有貢獻,但延遲與成本也逐層增加。我們會在 Day 39 討論「成本與延遲最佳化」時回頭看這個配置的取捨。

延伸資源

  • HyDE 原始論文(CMU,2022):Gao et al., Hypothetical Document Embeddings for Retrieval-Augmented Generation,arXiv 2212.10496,HyDE 的標準來源與 benchmark。
  • Reciprocal Rank Fusion 原始論文(2009):Cormack et al., Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods,RRF 公式的標準來源。
  • rank-bm25 Python 套件(2024):https://github.com/dorianbrown/rank_bm25,BM25Okapi / BM25Plus / BM25L 的 Python 實作。
  • Qdrant 1.12 官方文件(2025):https://qdrant.tech/documentation/,search 與 payload filter 的完整 API。
  • LangChain 0.3 Ensemble Retriever 官方文件(2025):https://python.langchain.com/docs/how_to/ensemble_retriever/,LangChain 內建的 RRF 實作與多檢索器融合範例。

留言

這個網誌中的熱門文章

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 等工具能處理和分析龐...