跳到主要內容

NLP Day 26 RAG 管線實作:文件切分、嵌入與檢索

NLP Day 26 RAG 管線實作:文件切分、嵌入與檢索

執行需求:Colab T4 可跑。本篇在 Colab 免費 T4(16 GB VRAM)上用一個真實的維基百科條目(台北,CC BY-SA 4.0)對照 three fixed strategies:fixed chunking、recursive chunking、semantic chunking。每種策略各切出約 40–60 段、用 paraphrase-multilingual-MiniLM-L12-v2 編碼、再用相同的 5 個查詢做檢索品質比較,整個流程約 8–10 分鐘(含模型下載)。CPU 也能跑但編碼時間會拉長到 20 分鐘以上。LangChain 0.3.x 提供 RecursiveCharacterTextSplitter、CharacterTextSplitter 等內建切分器,本篇會示範如何搭配自製的 semantic chunker。

引言

Day 25 我們把 RAG 拆成檢索、增強、生成三段,並指出一個關鍵觀念:「檢索品質決定 RAG 上限」。要提升檢索品質,最容易被忽略、卻影響最大的環節是「文件切分」。同一段維基百科文字,用 200 字一段切成 100 段、與用 1000 字一段切成 20 段,檢索結果可能差到 30% 的 recall@5。原因是切分粒度直接決定了「語意的最小單元」:太粗,每段含太多概念,語意被稀釋;太細,每段只講半件事,召回時無法形成完整上下文。

本篇會示範三種主流切分策略。Fixed chunking 是最直觀的「每 N 字切一段」,實作簡單但容易把句子切在奇怪的地方;recursive chunking 是 LangChain 0.3.x 預設的策略,依序嘗試段落、句子、單字等分隔符,盡量在語意邊界切;semantic chunking 用嵌入模型的相似度決定切點,相鄰句子相似度低就視為主題轉換處,是 2024 年開始流行的進階策略。我們會用同一個維基百科條目,把三種策略的切分結果與檢索品質並排比較,讓你看到「切分」這件事對 RAG 的實質影響。

讀完這篇你會了解:fixed / recursive / semantic 三種策略的差別、怎麼用 LangChain 0.3.x 的 text splitters、semantic chunker 要怎麼自己實作、以及在不同場景下該選哪一種。明天我們會把切完的段落送進查詢改寫與混合檢索,進一步提升檢索品質。

三種切分策略的核心觀念

Fixed chunking 是最簡單的「每 N 個字元切一段」。它的好處是實作簡單(text[i:i+N])、每段長度一致;壞處是會把句子甚至單字切在奇怪的位置(例如「深度學習是機器學習的[&#&#]一支」),語意不完整會讓嵌入向量失真、檢索召回率下降。實務上固定切分通常會加 overlap)讓相鄰段塊共用 10–20% 的字元,緩解切在邊界的問題;但這只是治標,真正的問題是 fixed chunking 不懂語意邊界。

Recursive chunking 是 LangChain 0.3.x 的預設策略(RecursiveCharacterTextSplitter)。它先嘗試用段落分隔符("\n\n")切,如果切出的段太長就改用句子分隔符(". " 或 "。 "),再太長就用單字分隔符(" "),最後退回字元切。這種「由粗到細」的策略可以盡量保留語意邊界,是大多數 RAG 系統的實務預設。Recursive 對「段落結構清晰」的文件(例如維基百科、論文、技術文件)特別有效;對「段落結構模糊」的文件(例如對話紀錄、逐字稿)會退化成 fixed。

Semantic chunking 是 2024 年開始流行的進階策略。它的核心想法是「相鄰句子的語意不連續時,就視為主題轉換」。實作上先用句子切分器把文章切成句,再用嵌入模型編碼每句,計算相鄰句子的 cosine 相似度;當相似度低於某個閾值(例如 0.5),就把這個位置當作切點。這個策略的好處是「語意完整」、壞處是「計算成本高」(每篇文章要 N 次嵌入)。本篇會示範如何用 sentence-transformers 自己實作一個 semantic chunker。

實務上還有更進階的策略——LLM 切分:用 LLM 直接讀段落、判斷哪裡是主題邊界、輸出結構化的切分結果(例如 JSON list of chunks)。這個策略對長文件的「隱含主題」切得很準,但成本是 LLM 呼叫費用與延遲;對中小企業來說,本篇示範的三種策略已經能覆蓋九成情境,LLM 切分留給對精度極度敏感的場景(例如法律文件、醫療紀錄)。另一個相關概念是「proposition chunking」:用 LLM 把段落拆成命題級的事實句子(fact-level propositions),每個命題作為一個 chunk——這是 2024 年底開始被廣泛引用的進階做法,特別適合問答密集、需要精準對應到單一事件的場景。

完整實作:同一條目、三種切分、檢索品質比較

以下範例在 Colab T4 上跑約 8–10 分鐘。我們用「台北」條目(CC BY-SA 4.0)做測試語料,分別用三種策略切分,再用 5 個查詢比較檢索結果。執行前需要:pip install langchain==0.3.7 langchain-text-splitters==0.3.0 qdrant-client==1.12.0 sentence-transformers==3.4.1 wikipedia-api==0.6.0。

# 1. 安裝套件
pip install -q langchain==0.3.7 langchain-text-splitters==0.3.0 qdrant-client==1.12.0 sentence-transformers==3.4.1 wikipedia-api==0.6.0

這段安裝四個套件。langchain 0.3 是當時穩定版(2025 年 3 月),提供 RecursiveCharacterTextSplitter 與 CharacterTextSplitter。langchain-text-splitters 0.3 是 0.3 系列拆分出來的獨立套件,專門放切分器。qdrant-client 與 sentence-transformers 沿用 Day 23–25 的版本。

# 2. 抓取「台北」條目作為測試語料
import wikipediaapi
WIKI = wikipediaapi.Wikipedia(user_agent="hao-code-nlp-day26", language="zh")
page = WIKI.page("台北")
DOC_TEXT = page.text
print(f"「台北」條目:{len(DOC_TEXT)} 字")
# 輸出:「台北」條目:12,450 字(實際會略有不同)

這段從維基百科抓取「台北」條目。page.text 回傳純文字內容、已去除 HTML 標籤。內容採 CC BY-SA 4.0 授權,這裡僅作為 RAG 切分實驗的測試語料,不作為事實依據。len(DOC_TEXT) 約 12,000 字,足以展示三種切分策略的差異;如果用更大語料(例如整個條目家族),切分差異會更明顯。

# 3. Fixed chunking:每 400 字切一段,overlap 50
def fixed_chunk(text: str, chunk_size: int = 400, overlap: int = 50) -> list[str]:
    chunks = []
    start = 0
    while start < len(text):
        end = start + chunk_size
        chunks.append(text[start:end])
        start = end - overlap
    return [c for c in chunks if c.strip()]

fixed_chunks = fixed_chunk(DOC_TEXT, chunk_size=400, overlap=50)
print(f"Fixed:{len(fixed_chunks)} 段,平均 {sum(len(c) for c in fixed_chunks) / len(fixed_chunks):.0f} 字")
# 輸出(實際會略有不同):Fixed:38 段,平均 360 字

這段是 fixed chunking 的最簡實作。chunk_size=400 是常見起點:對中文而言,400 字約 1–2 段維基百科文字,足以涵蓋一個小主題又不會太長。overlap=50 是經驗值,避免切在句子中間導致下一段開頭幾個字重複以維持上下文連貫。注意 text[start:end] 在中文字元上完全安全(不會切到半個字)。這個實作沒有任何語意判斷,是純粹的固定長度切分。

# 4. Recursive chunking:用 LangChain 0.3 的 RecursiveCharacterTextSplitter
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 中文分隔符:雙換行、句號、全形句號
SEPARATORS = ["\n\n", "。", "!", "?", "\n", ";", ",", " ", ""]

splitter = RecursiveCharacterTextSplitter(
    chunk_size=400,
    chunk_overlap=50,
    separators=SEPARATORS,
    length_function=len,
    is_separator_regex=False,
)
recursive_chunks = splitter.split_text(DOC_TEXT)
print(f"Recursive:{len(recursive_chunks)} 段,平均 {sum(len(c) for c in recursive_chunks) / len(recursive_chunks):.0f} 字")
# 輸出(實際會略有不同):Recursive:42 段,平均 370 字

這段用 LangChain 0.3 的 RecursiveCharacterTextSplitter。separators 給一個中文優先順序:先嘗試雙換行(段落邊界),再嘗試句號(句子邊界),再嘗試換行、半形分號、全形分號、全形逗號、空格,最後才退回單字切分。chunk_size=400、chunk_overlap=50 與 fixed 一致,方便對照。length_function=len 是中文字元的計算方式(不需 token 化,len(s) 直接回傳字元數)。

Recursive 比 fixed 多 4 段(42 vs 38),原因是 recursive 會優先在「雙換行」與「句號」切,固定長度只是上限。如果某個段落剛好 380 字,recursive 不會把它硬切到 400 字;fixed 則會把下一段的開頭硬塞進去。結果是 recursive 的段數更接近「語意單元數量」,平均長度更穩定。

# 5. Semantic chunking:用嵌入相似度決定切點(自製)
import numpy as np
import re
from sentence_transformers import SentenceTransformer

# 先用句號把文章切成句
SENTENCE_SEP = re.compile(r"(?<=。)\s*")
sentences = [s for s in SENTENCE_SEP.split(DOC_TEXT) if len(s.strip()) > 4]
print(f"句數:{len(sentences)}")

model = SentenceTransformer("sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2")

def semantic_chunk(sentences: list[str], similarity_threshold: float = 0.5) -> list[str]:
    """相鄰句子 cosine 相似度低於 threshold 就視為主題切換。"""
    embs = model.encode(sentences, convert_to_numpy=True)
    chunks = []
    buf = [sentences[0]]
    for i in range(1, len(sentences)):
        sim = float(np.dot(embs[i-1], embs[i]) / (np.linalg.norm(embs[i-1]) * np.linalg.norm(embs[i])))
        if sim < similarity_threshold:
            chunks.append("".join(buf))
            buf = [sentences[i]]
        else:
            buf.append(sentences[i])
    if buf:
        chunks.append("".join(buf))
    return [c for c in chunks if len(c) > 30]

semantic_chunks = semantic_chunk(sentences, similarity_threshold=0.5)
print(f"Semantic:{len(semantic_chunks)} 段,平均 {sum(len(c) for c in semantic_chunks) / len(semantic_chunks):.0f} 字")
# 輸出(實際會略有不同):Semantic:55 段,平均 220 字

這段自製 semantic chunker。先用 regex 以句號切句((?<=。)\s* 保留句號、只在後面加空格的時候切),再用 model.encode 把每句編碼成向量。迴圈計算相鄰句子的 cosine 相似度,低於 0.5 時視為主題轉換、累積成一個 chunk。Semantic 切出 55 段、平均 220 字,比 fixed 與 recursive 都短;原因是 semantic 會在「語意斷層」切,這種位置往往在兩三句話以內就出現。

# 6. 把三種切分結果編碼並寫進三個 Qdrant collection(沿用 Day 23/24 模式)
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct

client = QdrantClient(":memory:")

def build_collection(name: str, chunks: list[str]):
    client.create_collection(
        collection_name=name,
        vectors_config=VectorParams(size=384, distance=Distance.COSINE),
    )
    vectors = model.encode(chunks, batch_size=32, convert_to_numpy=True).tolist()
    points = [PointStruct(id=i, vector=v, payload={"text": t, "idx": i})
              for i, (v, t) in enumerate(zip(vectors, chunks))]
    client.upsert(collection_name=name, points=points)
    print(f"{name}:{len(points)} 點")

build_collection("fixed", fixed_chunks)
build_collection("recursive", recursive_chunks)
build_collection("semantic", semantic_chunks)
# 輸出(實際會略有不同):
# fixed:38 點
# recursive:42 點
# semantic:55 點

這段把三種切分結果編碼並寫進 Qdrant。build_collection 對每種策略做一次「建 collection → 編碼 → 上傳」,三個 collection 互相獨立。這樣設計是為了「同查詢對三種策略」的比較公平——只有切分不同,其餘(嵌入模型、距離度量、向量維度)完全相同。model.encode 在 T4 上編碼 55 段約 8 秒;55 段加上前面的 38 與 42 段,總編碼時間約 20 秒。

# 7. 五個查詢 × 三種策略的檢索結果比較
QUERIES = [
    "台北 101 的高度",
    "捷運系統的營運時間",
    "台北的歷史發展",
    "台北的地理位置",
    "夜市與小吃文化",
]

for q in QUERIES:
    q_vec = model.encode([q], convert_to_numpy=True).tolist()[0]
    print(f"\n=== 查詢:{q} ===")
    for name in ["fixed", "recursive", "semantic"]:
        hits = client.search(collection_name=name, query_vector=q_vec, limit=1)
        top = hits[0].payload["text"][:50].replace("\n", " ")
        print(f"  [{name:9s}] {top}…")
# 範例輸出(會因模型與切分略有不同):
# === 查詢:台北 101 的高度 ===
#   [fixed    ] 台北 101 是台灣最高的建築…
#   [recursive] 台北 101 是台灣最高的建築…
#   [semantic ] 台北 101 是台灣最高的建築,總高度 508 公尺…

這段用 5 個查詢對三種策略各跑一次檢索、印出 top-1 段落的開頭 50 字。實務上我們會看「top-1 是否真答到問題」、「top-3 中是否有完整段落」、「無關段落的比例」三項指標。在這個小型測試中,三種策略的 top-1 看起來都答對了,但當查詢更細節(例如「台北 101 的抗震設計」),semantic 與 recursive 往往能精準命中、fixed 容易召回「台北 101 的高度」這類粗略段落。本篇的對照只能展示「切分有差」,真正的評估需要更完整的 ground truth,這會留到 Day 29 的評估章節。

常見錯誤與踩雷

錯誤一:Fixed chunking 把一段中文切成半個字或半個詞。text[i:i+400] 在中文字元串上沒事,但如果你不小心用了 text.split()[:400](以詞切)會把段落順序打亂。對應排查:中文文件切分用字元索引(text[i:i+N]),不要用 split() 或 re.findall 先切詞再切片。

錯誤二:Recursive 的 separators 沒包含中文標點。預設 RecursiveCharacterTextSplitter 的 separators 是英文標點(["\n\n", "\n", " ", ""]),對中文文章會直接退回字元切分,失去語意邊界的意義。對應排查:給中文文章要明確加上 ["\n\n", "。", "!", "?", "\n", ";", ",", " ", ""],本篇的 SEPARATORS 是經驗起點。

錯誤三:Semantic chunking 的 similarity_threshold 設太高,導致每句都獨立成一段。threshold=0.5 是經驗值;如果設成 0.8,會幾乎每句都切、失去 chunk 意義。對應排查:先用一個小語料(例如 10 段)畫出相似度分佈直方圖,找「自然斷層」的相似度值,再設 threshold。

錯誤四:Semantic chunking 把長段落切成 0 字的空段。buf = [sentences[i]] 重新開始時若 sentences[i] 太短(例如只有標點),會出現 0 字空段。對應排查:在最後加 return [c for c in chunks if len(c) > 30] 過濾掉空段。

錯誤五:把切分後的 chunks 直接丟進 LLM,沒考慮 chunk 之間的順序。如果檢索回傳的 3 段來自文章的「開頭、中間、結尾」,LLM 會以為這是三個獨立的主題、無法拼接。對應排查:在 metadata 中存 chord_order(段落在原文的順序),增強階段把同一原文的相鄰段合併後再送進 prompt。

效能與實務提醒

三種切分策略的計算成本差異大。Fixed 是 O(N)(純字串切片)、Recursive 是 O(N×層數)(每層分隔符掃一次)、Semantic 是 O(N×K)(K 是嵌入呼叫次數)。本篇「台北」條目約 12,000 字、固定切 38 段約 0.01 秒、Recursive 約 0.1 秒、Semantic 約 8 秒。Semantic 在大規模語料上會是瓶頸,10 萬篇文章可能要 30 分鐘以上;實務上會把 Semantic 與 Recursive 並用:先用 Recursive 切成粗段(例如 1000 字),再用 Semantic 在粗段內細切。

另一個實務選擇是chunk 大小。本篇用 400 字、overlap 50,是中文短問答的甜蜜點。但對企業內部長文件(一份 50 頁的產品手冊),400 字太細;改用 800–1500 字、overlap 100–200 比較合理。原則是:chunk 越長,每段含越多概念(語意被稀釋);chunk 越短,每段含越少概念(缺上下文)。最佳值要靠 Day 29 的評估來定,不是猜的。

除了 chunk 大小,還有兩個常被忽略的設計選擇。第一是 overlap 大小:本篇固定 overlap=50,相當於 chunk_size 的 12.5%。這個比例對 400–800 字的 chunk 通常合適;對 1500 字以上的長 chunk 可以調到 8–10%。Overlap 太低容易在句子邊界丟失資訊,太高則會讓相鄰 chunks 高度重複、浪費儲存與計算。

一個常被忽略的設計點是metadata 設計。除了原文,metadata 至少要存 source(文件來源)、chunk_id(段塊 ID)、chunk_order(在原文的順序)、section(所在章節,例如「歷史」「地理」)。Day 24 我們已經示範過 metadata filter;今天則提醒:metadata 在切分階段就要設計好,後續檢索與生成才用得上。實務上 metadata 還會加上 created_at(建立時間)、author(作者)、version(版本)、tags(人工或自動產生的標籤)。這些欄位讓 Day 27 的混合檢索可以做更精準的 filter,也讓 Day 29 的評估能依 metadata 分群分析。

小結

今天把 RAG 管線的第一步「文件切分」展開成完整實作:我們用「台北」維基百科條目(CC BY-SA 4.0),對照了三種主流策略——fixed(38 段、平均 360 字)、recursive(42 段、平均 370 字)、semantic(55 段、平均 220 字)。Recursive 是 LangChain 0.3.x 的預設,適合大多數場景;Semantic 在「主題切換明顯」的文件上表現最好,但計算成本高;Fixed 是最簡單但容易切壞語意邊界的策略。重點回顧:chunk_size=400 + overlap=50 是中文短問答的起點、recursive 的 separators 一定要包含中文標點、semantic threshold 0.5 是經驗值、最佳 chunk 大小要靠評估而不是猜測。我們也展示了「同一查詢對三種策略」的並排比較,驗證了「切分對檢索品質有實質影響」這個核心觀念。

需要再次強調的是:沒有「最好」的切分策略。固定長度、語意邊界、計算成本三者永遠在權衡。對中文短問答、中等規模(< 10 萬段)的 RAG 系統,recursive 是穩定的預設;對需要極高召回率(例如法律、醫療)且願意承擔計算成本的場景,semantic 與 recursive 並用是最務實的選擇。明天我們會把切完的段落加上「查詢改寫」與「BM25 + 向量混合檢索」,用 reciprocal rank fusion 把兩個檢索器的結果融合,進一步提升 top-k 的品質。

結語

今天的重點是「把文件切分從直觀猜想變成可控實驗」。我們從「為什麼切分重要」出發,介紹了 fixed / recursive / semantic 三種策略的差異,用同一條維基百科條目把三種切分各做一次、用同一組查詢各跑一次檢索,並用 top-1 段落開頭印出來做粗略對照。讀完這篇你應該能回答:fixed 與 semantic 的核心差別是什麼?LangChain 0.3.x 的 RecursiveCharacterTextSplitter 為什麼要給中文文章加 separators?semantic chunking 的 threshold 怎麼設?chunk_size 與 overlap 怎麼選?metadata 在切分階段要設計哪些欄位?

切分只是檢索優化的一環。明天,我們會把切完的段落加上「查詢改寫」與「BM25 + 向量混合檢索」,用 reciprocal rank fusion 把兩個檢索器的結果融合,進一步提升 top-k 的品質。

延伸資源

  • LangChain 0.3 Text Splitters 官方文件(2025):https://python.langchain.com/docs/how_to/recursive_text_splitter/,RecursiveCharacterTextSplitter、CharacterTextSplitter、TokenTextSplitter 的完整 API。
  • LangChain 0.3 semantic chunking 官方文件(2025):https://python.langchain.com/docs/how_to/semantic-chunker/,內建的 SemanticChunker(基於百分位數的切分)與本篇自製版本的差異。
  • Greg Kamradt 的 semantic chunking 影片筆記(2024):https://github.com/FullStackRetrieval-com/RetrievalTutorials,5 Levels of Text Splitting 的原始碼與視覺化。
  • Qdrant 1.12 官方文件(2025):https://qdrant.tech/documentation/,create_collection、upsert、search 的完整 API。
  • Greg Kamradt 五段切分法影片(2024):YouTube 搜尋「5 Levels of Text Splitting」,從最簡字元切到 LLM 切分的視覺化對照。

留言

這個網誌中的熱門文章

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