在自然語言處理(NLP)領域,預訓練模型如 BERT 已成為解決許多任務的強大工具。在這篇文章中,我們深入探討如何利用 BERT 和 PyTorch 框架,從零開始構建一個中文文本分類模型,並詳細介紹資料處理、模型訓練與評估的每一個關鍵步驟。
一個成功的模型始於高品質的資料。我們的實作首先定義了 Config
類別來統一管理檔案路徑和類別標籤,這有助於提高程式碼的可維護性。所有資料處理邏輯都封裝在 load_and_split_data
函數中。
資料載入與分割
程式碼使用 pd.read_excel
從 Excel 檔案中載入資料,並透過 train_test_split
將其分割成訓練、驗證與測試集。這一步驟是為了確保模型在未見過的資料上也能表現良好。
資料不平衡處理
實際資料集常存在類別不平衡問題。我們的程式碼採用了 隨機下採樣 (Random Under-Sampling) 策略,這部分由 imblearn.under_sampling.RandomUnderSampler
函式庫實現。程式碼會自動計算出樣本最少的類別數量 min_class_count
,並設定 sampling_strategy
將所有類別的樣本數降至與之相同。
# 自動設置下采樣策略
if sampling_strategy is None:
min_class_count = np.min(np.bincount(y_train))
sampling_strategy = {label: min_class_count for label in np.unique(y_train)}
# 對訓練集進行下采樣
rus = RandomUnderSampler(sampling_strategy=sampling_strategy, random_state=42)
X_resampled, y_resampled = rus.fit_resample(X_train_df, y_train)
preprocess_text
函數負責進行基礎的文本清洗,如使用 re.sub(r'[A-Za-z0-9]+', '', text) 來移除英文和數字。同時,它也添加了簡單的 數據增強 (Data Augmentation) 技術,隨機打亂部分字詞順序,以增加訓練資料的多樣性。我們的模型基於 Hugging Face 的 BertForSequenceClassification,這是一個在 BERT 之上添加了一個分類層的預訓練模型,非常適合用於文本分類任務。
Tokenizer
在將文本輸入模型前,必須先轉換成模型能理解的數字格式。程式碼使用 BertTokenizer.from_pretrained('bert-base-chinese')
來初始化繁體中文的 tokenizer。tokenize_data
函數會調用 tokenizer.encode_plus
將文本轉換為 input_ids
和 attention_mask
,這兩個張量是 BERT 模型所需要的標準輸入。
自定義資料集 (TextDataset)
為了與 PyTorch
的 DataLoader
配合,我們創建了一個繼承自 torch.utils.data.Dataset
的類別。它的 __getitem__
方法定義了如何取出單個樣本,並以字典形式返回 input_ids
, attention_mask
和 labels
,方便 DataLoader
批量處理。
Focal Loss
處理類別不平衡的另一種有效方法是使用 FocalLoss
。程式碼中實現了一個自定義的 torch.nn.Module
類別。它會在訓練開始前,先透過 np.bincount(y_train)
計算出每個類別的樣本數,並據此計算出類別權重 class_weights
。然後,在 FocalLoss
的實例化中,將這個權重傳入,讓模型在訓練時更專注於難以分類的樣本。
# 計算類別權重
class_counts = np.bincount(y_train)
class_weights = 1.0 / class_counts
class_weights = torch.tensor(class_weights / class_weights.sum(), dtype=torch.float).to(DEVICE)
# 初始化 loss function
loss_fn = FocalLoss(alpha=class_weights)
train_model
函數是核心的訓練循環。它會讓模型進入訓練模式 (model.train()
)。在每個批次(batch
)中,程式碼會將資料移至 GPU (to(device)
),然後進行前向傳播(forward pass)計算損失 (loss.backward()
) 和權重更新 (optimizer.step()
)。# 訓練循環的關鍵步驟
outputs = model(input_ids, attention_mask=attention_mask)
loss = loss_fn(outputs.logits, labels)
loss.backward()
optimizer.step()
scheduler.step()
早停 (Early Stopping)
為了防止模型過度擬合,程式碼實現了早停機制。它會追蹤驗證集上的 val_f1
,並在 val_f1
連續幾輪沒有提升時(由 patience
變數控制),提前結束訓練,並載入表現最佳的模型。
評估指標
訓練結束後,evaluate_model
函數會在測試集上評估模型性能。除了常見的 classification_report
外,程式碼還使用 sklearn.metrics.confusion_matrix
計算混淆矩陣,並用 seaborn.heatmap
繪製出來,讓分類表現一目了然。
訓練歷史可視化
最後,plot_training_history
函數使用 matplotlib.pyplot
繪製了訓練和驗證的損失 (Loss) 和 F1-Score 曲線。這些曲線圖是診斷模型訓練狀態的重要工具,可以幫助我們判斷模型是否過度擬合或欠擬合。
透過以上步驟,我們不僅成功訓練了一個基於 BERT 的中文文本分類模型,更建立了一套完整的、包含資料前處理、訓練優化和結果評估的實戰流程。
👉 下一篇我們來分析一下模型跑出來的結果以及如何評估模型的指標!