Changelog
前言
最近在知乎上刷到一個很有意思的提問Qwen3-0.6B這種小模型有什么實際意義和用途。查看了所有回答,有人提到小尺寸模型在邊緣設備場景中的優勢(低延遲)、也有人提出小模型只是為了開放給其他研究者驗證scaling law
(Qwen2.5
系列豐富的模型尺寸為開源社區驗證方法有效性提供了基礎)、還有人說4B、7B的Few-Shot
效果就已經很好了甚至直接調用更大的LLM
也能很好的解決問題。讓我比較感興趣的是有大佬提出小模型在向量搜索、命名實體識別(NER)和文本分類領域中很能打,而另一個被拿來對比的就是Bert
模型。在中文文本分類中,若對TextCNN
、FastText
效果不滿意,可能會嘗試Bert
系列及其變種(RoBerta
等)。但以中文語料為主的類Encoder-Only
架構模型其實并不多(近期發布的ModernBERT
,也是以英文和Code語料為主),中文文本分類還是大量使用bert-base-chinese
為基礎模型進行微調,而距Bert
發布已經過去了6年。Decoder-Only
架構的LLM
能在文本分類中擊敗參數量更小的Bert
嗎?所以我準備做一個實驗來驗證一下。
不想看實驗細節的,可以直接看最后的結論 和實驗局限性 部分。
實驗設置
模型 參數量 訓練方式 google-bert/bert-base-cased 0.1B 添加線性層,輸出維度為分類數 Qwen/Qwen3-0.6B 0.6B 構造Prompt,SFT
數據集配置:fancyzhx/ag_news,分類數為4,分別為World(0)、Sports(1)、Business(2)、Sci/Tech(3)。訓練樣本數120000,測試樣本數7600,樣本數量絕對均衡。數據集展示:
{ "text" : "New iPad released Just like every other September, this one is no different. Apple is planning to release a bigger, heavier, fatter iPad that..." "label" : 3
}
選擇該數據集是在Paper with code
的Text Classification
類中看到的榜單,并且該數據集元素基本上不超過510個token(以Bert Tokenizer
計算)。因為Bert的最大輸入長度是510個token
,超過會進行截斷,保留前510個token
,所以為了進行公平的比較,盡量避免截斷。 因為是多分類任務,我們以模型在測試集上的F1指標為標準,F1值越高,模型效果越好。
Bert訓練細節
Bert
的訓練比較簡單,將文本使用Tokenizer
轉換成input_ids
后,使用Trainer
進行正常訓練即可。訓練參數(若未單獨指出,則代表使用Trainer
默認值):
參數名稱 值 lr_scheduler_type(學習率衰減策略) cosine learning_rate(學習率) 1.0e-5 per_device_train_batch_size(訓練batch_size) 64 gradient_accumulation_steps(梯度累積) 1 per_device_eval_batch_size(驗證batch_size) 256 num_train_epochs(epoch) 3 weight_decay 1e-6 eval_steps(驗證頻率) 0.05
Step Training Loss Validation Loss Accuracy Precision Recall F1 282 0.274700 0.263394 0.909737 0.910311 0.909737 0.909676 564 0.207800 0.222230 0.922237 0.922701 0.922237 0.922246 846 0.199600 0.204222 0.931579 0.932552 0.931579 0.931510 1128 0.215600 0.191824 0.934605 0.935274 0.934605 0.934737 1410 0.190500 0.192846 0.932763 0.934421 0.932763 0.932937 1692 0.193300 0.180665 0.937895 0.938941 0.937895 0.937849 1974 0.143000 0.180497 0.940526 0.940945 0.940526 0.940636 2256 0.141500 0.177630 0.941711 0.941988 0.941711 0.941644 2538 0.147100 0.173602 0.943947 0.944022 0.943947 0.943908 2820 0.131600 0.176895 0.940658 0.941790 0.940658 0.940683 3102 0.152800 0.170928 0.945000 0.945140 0.945000 0.944925 3384 0.140000 0.169215 0.944474 0.944766 0.944474 0.944399 3666 0.149900 0.168865 0.944474 0.944538 0.944474 0.944483 3948 0.112000 0.172459 0.946184 0.946142 0.946184 0.946159 4230 0.124000 0.172826 0.945000 0.945254 0.945000 0.944924 4512 0.122300 0.171583 0.944737 0.944925 0.944737 0.944708 4794 0.104400 0.171969 0.944868 0.945059 0.944868 0.944854 5076 0.117500 0.171504 0.945395 0.945502 0.945395 0.945363 5358 0.099800 0.171761 0.945263 0.945510 0.945263 0.945232
Qwen3訓練細節
使用Qwen3
訓練文本分類模型有2種方法。第1種是修改模型架構,將模型最后一層替換為輸出維度為分類數的線性層。第2種是構造Prompt
,以選擇題的方式創建問答對,然后進行SFT
訓練。
線性層分類
與微調Bert類似,將文本使用Tokenizer
轉換成input_ids
后,使用Trainer
進行正常訓練。訓練參數(若未單獨指出,則代表使用Trainer
默認值):
參數名稱 值 lr_scheduler_type(學習率衰減策略) cosine learning_rate(學習率) 1.0e-5 per_device_train_batch_size(訓練batch_size) 8 gradient_accumulation_steps(梯度累積) 8 per_device_eval_batch_size(驗證batch_size) 16 num_train_epochs(epoch) 1 weight_decay 1.0e-6 eval_steps(驗證頻率) 0.05
Step Training Loss Validation Loss Accuracy Precision Recall F1 94 0.281800 0.243619 0.918158 0.918180 0.918158 0.917893 188 0.224100 0.220015 0.924211 0.925216 0.924211 0.924289 282 0.197700 0.236405 0.919211 0.920127 0.919211 0.919257 376 0.182800 0.243235 0.920132 0.925368 0.920132 0.919136 470 0.191500 0.207864 0.928289 0.929563 0.928289 0.928304 564 0.208400 0.192414 0.935658 0.935668 0.935658 0.935647 658 0.201900 0.191506 0.938553 0.938695 0.938553 0.938607 752 0.191900 0.179849 0.937500 0.937417 0.937500 0.937378 846 0.156100 0.177319 0.938684 0.938983 0.938684 0.938653 940 0.159900 0.177048 0.938289 0.939433 0.938289 0.938175 1034 0.159100 0.172280 0.943553 0.943725 0.943553 0.943455 1128 0.117000 0.168742 0.943026 0.942911 0.943026 0.942949 1222 0.151500 0.164628 0.943421 0.944371 0.943421 0.943503 1316 0.143600 0.158676 0.945921 0.946856 0.945921 0.945965 1410 0.183200 0.154356 0.946184 0.946708 0.946184 0.946221 1504 0.159400 0.153549 0.947763 0.947847 0.947763 0.947771 1598 0.147100 0.152530 0.948553 0.948609 0.948553 0.948539 1692 0.161400 0.151299 0.949079 0.949216 0.949079 0.949029 1786 0.150500 0.151270 0.948421 0.948572 0.948421 0.948363
可以看到使用線性層分類的Qwen3-0.6B在測試集上最好結果是:0.949
SFT分類
我們先基于數據集寫一個選擇題形式的Prompt,Prompt模板為:
prompt = """Please read the following news article and determine its category from the options below.Article:
{news_article}Question: What is the most appropriate category for this news article?
A. World
B. Sports
C. Business
D. Science/TechnologyAnswer:/no_think""" answer = "<think>\n\n</think>\n\n{answer_text}"
news_article
為新聞文本,answer_text
表示標簽。先測試一下Qwen3-0.6B在測試集上思考和非思考模式下的zero-shot
能力(準確率
)。為獲得穩定的結果,非思考模式使用手動拼接選項計算ppl,ppl最低的選項為模型答案。思考模式取<think>...</think>
后的第一個選項。結果如下:
模型 思考 非思考 Qwen3-0.6B 0.7997 0.7898
訓練框架使用LLama Factory
,Prompt
模板與上文一致。 因為Qwen3
為混合推理模型,所以對非推理問答對要在模板最后加上/no_think
標識符(以避免失去推理能力),并且回答要在前面加上<think>\n\n</think>\n\n
。 按照LLama Factory SFT訓練數據的格式要求組織數據,如:
{ 'instruction' : "Please read the following news article and determine its category from the options below.\n\nArticle:\nWall St. Bears Claw Back Into the Black (Reuters) Reuters - Short-sellers, Wall Street's dwindling\\band of ultra-cynics, are seeing green again.\n\nQuestion: What is the most appropriate category for this news article?\nA. World\nB. Sports\nC. Business\nD. Science/Technology\n\nAnswer:/no_think" , 'output' : '<think>\n\n</think>\n\nC'
}
model_name_or_path : model/Qwen3- 0.6B
stage : sft
do_train : true
finetuning_type : full
dataset : agnews_train
template : qwen3
cutoff_len : 512 overwrite_cache : true
preprocessing_num_workers : 8
output_dir : Qwen3- 0.6B- Agnews
save_strategy : steps
logging_strategy : steps
logging_steps : 0.01
save_steps : 0.2
plot_loss : true
report_to : tensorboard
overwrite_output_dir : true
per_device_train_batch_size : 12
gradient_accumulation_steps : 8
learning_rate : 1.2e-5
warmup_ratio : 0.01
num_train_epochs : 1
lr_scheduler_type : cosine
bf16 : true
因為Bert
在訓練2個epoch
后就出現了嚴重的過擬合,所以對Qwen3
模型,只訓練1個epoch
,每0.2個epoch
保存一個檢查點。 訓練過程中模型對測試集的指標變化(訓練結束后加載檢查點對測試集進行推理,注意!為保證推理結果穩定,我們選擇選項ppl低的作為預測結果 ):
Step Training Loss Accuracy Precision Recall F1 250 0.026 0.912 0.917 0.912 0.912 500 0.027 0.924 0.924 0.924 0.924 750 0.022 0.937 0.937 0.937 0.937 1000 0.022 0.941 0.941 0.941 0.941 1250 0.023 0.940 0.940 0.940 0.940
可以看到Qwen3-0.6B
模型Loss
在一開始就急速下降,然后開始抖動的緩慢下降,如下圖(縱軸范圍調整0.05~0.015)。在測試集上最好結果是:0.941。
Bert和Qwen3-0.6B訓練耗時
模型 Epoch 訓練耗時 推理耗時 總耗時 Bert 3 35 min - 0.58 h Qwen3-0.6B(線性層分類) 1 52 min - 0.86 h Qwen3-0.6B(SFT分類) 1 62 min 30 min 1.5 h
Bert和Qwen3-0.6B RPS測試
為測試Bert
和Qwen3-0.6B
是否滿足實時業務場景,對微調后的Bert
和Qwen3-0.6B
進行RPS
測試,GPU
為RTX 3090
(24G):
模型 推理引擎 最大輸出Token數 RPS Bert HF - 60.3 Qwen3-0.6B(SFT分類) HF 8 13.2 Qwen3-0.6B(SFT分類) VLLM 8 27.1 Qwen3-0.6B(線性層分類) HF - 38.1
結論
在Ag_new
數據集上,各模型效果:Qwen3-0.6B
(線性層分類)> Bert
> Qwen3-0.6B
(SFT分類)> Qwen3-0.6B
(Think Zero-Shot)> Qwen3-0.6B
(No Think Zero-Shot)。 各模型訓練推理耗時: Qwen3-0.6B
(SFT分類)> Bert
> Qwen3-0.6B
(線性層分類)。 各模型RPS
:Bert
> Qwen3-0.6B
(線性層分類) > Qwen3-0.6B
(SFT分類)。 Think
模式下的Qwen3-0.6B
比No Think
模式下的Qwen3-0.6B
準確率僅高出1%,推理時間比No Think
慢20倍(HF推理引擎,Batch
推理)。在訓練Qwen3-0.6B
(線性層分類)時,Loss
在前期有點抖動,或許微調一下學習率預熱比率會對最終結果有微弱正向效果。
實驗局限性
未實驗在Think
模式下Qwen3-0.6B
的效果(使用GRPO
直接訓練0.6B
的模型估計是不太行的,可能還是先使用較大的模型蒸餾出Think
數據,然后再進行SFT
。或者先拿出一部分數據做SFT
,然后再進行GRPO
訓練(冷啟動))。 未考慮到長序列文本如token
數(以Bert Tokenizer
為標準)超過1024
的文本。 也許因為AgNews
分類任務比較簡單,其實不管是Bert
還是Qwen3-0.6B
在F1
超過0.94
的情況下,都是可用的狀態。Bert
(F1:0.945)和Qwen3-0.6B
線性層分類(F1:0.949)的差距并不明顯。如果大家有更好的開源數據集可以用于測試,也歡迎提出。 未測試兩模型在中文文本分類任務中的表現。
來源:https://zhuanlan.zhihu.com/p/1906768058745349565?share_code=KPTadtlbij0m&utm_psn=1907715099319312567