目錄
緣起
接續上一篇文章,一開始為了寫 LLM cybersecurity 的作業又不想花 credit,於是我用免費版 google colab 來完成。1成為 credit 富翁後再來用用 glow.ai 上的設備,體驗大幅上升。這篇文章便來記錄我在免費 google colab 跟 glow.ai 上的流程跟心得。
免費 google colab 的執行流程
資料集介紹 & 目標
資料集:kaggle 上的 Phishing Email Detection 資料集,裡面只有兩個欄位。
Email Text: 含信件標題與內文
Email Type: 兩種類別(Safe Email / Phishing Email)
資料集共 18650 筆資料。我們的目標是使用微調 LoRA 技術,讓離線 LLM 可以成功分類釣魚信件。
執行步驟(Google colab 版)
記得要開 GPU
啟動 LLaMA Factory
- 開啟新的 google colab 裝取所需環境套件
# 1. 下載 Llama-Factory
!git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git
%cd LLaMA-Factory
# 2. 安裝依賴環境
!pip install -e ".[torch,metrics]"
!pip install --no-deps unsloth # 推薦安裝 unsloth 加速
!pip install bitsandbytes>=0.39.0 # 為了設定 Quantization bit 用- 打開 google colab 的終端機輸入
llamafactory-cli webui --share - 回到 notebook 介面,新的 cell 輸入
from google.colab.output import eval_js
print("請點擊下方網址進入 Llama-Factory 介面:")
print(eval_js("google.colab.kernel.proxyPort(7860)"))這段程式會強制 Colab 將它內部的 7860 port(也就是 Llama-Factory 跑起來的地方)映射到一個可以點擊的外部網址。
資料前處理 & 上傳到 LLaMA Factory 可以看到的地方
- 使用 kaggle 上的資料集下載檔後,再輸入以下
import pandas as pd
import json
import os
# 1. 讀取 Kaggle 資料集 (請確保路徑正確,此例檔名是 phishing_emails.csv)
csv_file = os.path.join(path, "Phishing_Email.csv")
df = pd.read_csv(csv_file)
# 2. 轉換為 Llama-Factory 格式 (這裡假設欄位名稱,請根據你的 CSV 調整)
# 假設 "Email Text" 是內容,"Label" 是標籤
formatted_data = []
for _, row in df.iterrows():
formatted_data.append({
"instruction": "判斷這封郵件是否為釣魚郵件:",
"input": str(row["Email Text"]),
"output": str(row["Email Type"])
})
# 3. 儲存到 Llama-Factory 的 data 資料夾
save_path = "/content/LLaMA-Factory/data/phishing_data.json"
with open(save_path, "w", encoding="utf-8") as f:
json.dump(formatted_data, f, indent=2, ensure_ascii=False)
print(f"資料集已轉換並儲存至: {save_path}")這會將資料從 .csv 轉成 .json,並且處理成 LLaMA Factory 可接受格式。
LLaMA Factory 訓練設定

模型 : Qwen2.5-7B-Instruct ,因為只是辨認是否為釣魚信件(2 種可能),不必用非常大的模型應該就能處理
Fine-tuning method : lora
Quantization bit : 4,這個參數可以將模型壓縮到原來的\(\frac{1}{4}\)
Cutoff length: 512,主要避免內存爆掉,其次是觀察釣魚信件的特徵,關鍵通常都藏在 1-2 句話中
Learning rate: 5e-5
Epochs: 2.0 ,有足夠樣本數的情況下可以不用這麼多次
Batch size: 1,避免內存爆掉
Gradient accumulation: 32,影響 GPU 每次處理的資料
使用免費版 google colab 最需要注意內存爆掉的問題,因此設定要盡量設小,模型也要選小一點。未來如果還有需要用免費板 colab 訓練,以上設定也可以參考。2
執行結果
Loss 訓練圖

這裡 x 軸的 Step 計算方式為
\[\text{Total Steps} = \frac{\text{資料總數} \times \text{Epochs}}{\text{Total Batch Size}}\]
主要變化
11.54 (Epoch 0.01,186 筆)
7.24 (Epoch 0.02,371 筆)
3.60 (Epoch 0.03,457 筆)
2.29(Epoch 0.04,752 筆)
1.6 (Epoch 0.05,927 筆)
最後怕觸發免費 colab 的使用限制而提早停止,最終訓練到的資料共 927 筆,耗時約 2 小時,好久:(。
信件測試:
到 Chat 區載入 checkpoint path(相當於執行結果模型),進行測試

安全信件測試

釣魚信件測試

以 chat 區的結果來說全對,但當時沒用數據看結果,可惜了TT 但如果看訓練圖,會發現其實還有不小的改進空間。
在 Glows.ai 上的執行流程
這次使用的機器是 NVIDIA GeForce RTX 4090,可以用 HTTP 連線了!
資料集介紹 & 目標
資料集:Kaggle 上的 Finance News Sentiments 資料集,裡面也是有兩個欄位。
News Text: 金融新聞內容(包含標題與一段內文)
Sentiment Label: 三種類別(Positive / Negative / Neutral),用於表示新聞對市場情緒的影響
共 32,569 筆,一樣使用微調 LoRA 技術,讓離線 LLM 可以成功分類新聞情緒。
執行步驟(Glows.ai 版)
開啟 HTTP port 連線
導入資料集、對資料做前處理
這一步與 google colab 類似,快速快過
!pip install kagglehub[pandas-datasets]import kagglehub
path = kagglehub.dataset_download(
"antobenedetti/finance-news-sentiments"
)
print(path)
import os
print(os.listdir(path))確定檔名後測試能不能導入
import pandas as pd
csv_path = path + "/dataset.csv"
df = pd.read_csv(csv_path)
df.head()確定 OK 後調整資料集成 LLaMA Factory 可接受格式
import pandas as pd
import json
import os
# 1. 讀取 Kaggle 資料集 (請確保路徑正確)
csv_file = os.path.join(path, "dataset.csv")
df = pd.read_csv(csv_file)
# 2. 轉換為 Llama-Factory 格式 (這裡假設欄位名稱,請根據你的 CSV 調整)
formatted_data = []
for _, row in df.iterrows():
formatted_data.append({
"instruction": "判斷這則財經新聞的情緒:",
"input": str(row["text"]),
"output": str(row["sentiment"])
})
# 3. 儲存到 Llama-Factory 的 data 資料夾
save_path = "/LLaMA-Factory/data/news_data.json"
with open(save_path, "w", encoding="utf-8") as f:
json.dump(formatted_data, f, indent=2, ensure_ascii=False)
print(f"資料集已轉換並儲存至: {save_path}")- 調整
LLaMA-Factory\data裡的dataset_infon.json
{
"news_data": {
"file_name": "news_data.json",
"formatting": "alpaca",
"columns": {
"prompt": "instruction",
"query": "input",
"response": "output"
}
},
在 LLaMA Factory 訓練
打開 LLaMA Factory 的 HTTP Port,輸入剛剛建立好的 dataset 後即可開始訓練,最終訓練設定如下:
Model: Qwen2.5-7B-Instruct
learning rate: 2e-4
Epochs: 1
Maximum gradient norm: 1
Max samples: 100000
Compute type: fp16 (重要,選錯可能會跑不動)
cutoff length: 256
batch: 16
Gradient accumulation: 4
速度: 2$$4=8
val_size: 0.2
LR scheduler: cosine
因為現在資源比較多,設定可以奢侈一點~這個設定只花沒幾分鐘就練好了,讚。
訓練結果

看起來不錯,至少比在 Colab 上的情況要好很多。
再來看看 perdition
setting
cutoff: 256
Max samples: 100000
Batch size: 16
Maximum new tokens: 8
Top-p: 0.7
Temperature: 0.95
評估 result:
{ “predict_bleu-4”: 0.6883751680324095, “predict_model_preparation_time”: 0.0022, “predict_rouge-1”: 0.7306242519105055, “predict_rouge-2”: 0.0, “predict_rouge-l”: 0.7260624436055612, “predict_runtime”: 266.5178, “predict_samples_per_second”: 122.255, “predict_steps_per_second”: 7.643 }
AI 附的快速簡單看法
| 指標 | 本質 |
|---|---|
| BLEU-4 | 1~4-gram precision + brevity penalty |
| ROUGE-1 | unigram recall |
| ROUGE-2 | bigram recall |
| ROUGE-L | LCS-based F1 |
- BLEU:偏「寫得像不像原句(precision)」,越高越好。
- ROUGE:偏「有沒有講到重點(recall)」,越高越好。
- ROUGE-L:更偏「句子結構是否一致」
BLEU-4(predict_bleu-4)
BLEU 是 precision-based n-gram overlap 與 brevity penalty的結合,基本公式
\[BLEU = BP \cdot \exp\left(\sum_{n=1}^{4} w_n \log p_n\right)\]
- \(p_n\):n-gram precision
- \(w_n\):權重(通常 \(w_n = 1/4\))
- BP:brevity penalty(避免生成太短的懲罰項)
其中
n-gram precision (\(p_n\)) 為
\[p_n = \frac{\sum \text{clip(count of n-gram)}}{\sum \text{count of n-gram in candidate}}\]
Brevity Penalty (BP) 為
\[ BP = \begin{cases} 1 & c > r \\ e^{(1 - r/c)} & c \le r \end{cases} \]
- \(c\):生成句長度
- \(r\):參考句長度
ROUGE-N(ROUGE-1 / ROUGE-2)
ROUGE 是 recall-oriented overlap的意思,公式
- ROUGE-N recall(核心公式)
\[ROUGE\text{-}N = \frac{\sum \text{overlap n-grams}}{\sum \text{n-grams in reference}}\]
- ROUGE-N precision
\[ P = \frac{\text{overlap n-grams}}{\text{n-grams in candidate}} \]
- ROUGE-N F1(最常用)
\[F1 = \frac{2PR}{P + R}\]
特例
ROUGE-1
- n=1(unigram)
ROUGE-2
- n=2(bigram)
ROUGE-L(最長共同子序列 LCS)
- LCS 定義
\[ LCS = \text{longest common subsequence} \]
- Recall
\[R_{LCS} = \frac{LCS(ref, cand)}{|ref|}\]
- Precision
\[P_{LCS} = \frac{LCS(ref, cand)}{|cand|}\]
- ROUGE-L F1
\[ROUGE\text{-}L = \frac{(1 + \beta^2) P R}{R + \beta^2 P}\]
- 通常 \(\beta = 1\)
所以簡化版:
\[ROUGE\text{-}L = \frac{2PR}{P + R}\]
ROUGE-W(加權 LCS)
(有些 toolkit 會用)
\[ ROUGE\text{-}W = \frac{(1 + \beta^2) W_{LCS}}{...} \]
- 強化「連續匹配片段」
ROUGE-S(skip-bigram)
就是允許跳詞的 bigram:
\[ ROUGE\text{-}S = \frac{\text{skip bigram overlap}}{\text{reference skip bigrams}} \]
ROUGE-SU(skip-bigram + unigram)
\[ ROUGE\text{-}SU = ROUGE\text{-}S + ROUGE\text{-}1 \]
整體看起來是還可以的結果。
總結
微調有個缺點是耗時較長,需求配備也較高,用免費版的 Colab 幾乎很難做出有用的結果TT,相較之下有花$$的 glow.ai 就好多了!
原理部分,LoRA 微調的原理跟從頭訓練機器學習模型的過程頗為類似,只是除了跑的時候要注意訓練情況、跟數值結果外,實際跑一次也滿重要的。