40 条正、40 条负的情感语料,同用 bigram 特征:朴素贝叶斯测试集从 0.700 升到 0.833; 手写单隐层网络最好也只到 0.667,10 条样本时只有 0.500——正好是瞎猜。
上一节讲表示,这一节讲做法。 同样一份数据、同样一套特征,换模型换出完全不同的结果,这件事值得单独看一节。
一、两条路的区别不在模型,在「谁定特征」
传统路子:人定特征(这里是字符 bigram 计数),模型只学权重。 深度路子:也用人定的输入(还是 bigram),但中间加隐层,让模型自己组合。 注意这个 Demo 里两条路用的是同一套特征。所以差别不在特征,在模型有没有能力「自己造中间表示」。 很多人以为传统和深度的差别是「有没有神经网络」,其实更准的说法是特征是谁找的。 真端到端连特征都不用人定,直接喂原始字符。
二、结果:老办法赢了
训练 10 条时:朴素贝叶斯测试 0.700,网络 0.500。 加到 50 条:朴素贝叶斯 0.833,网络 0.667。 两个模型的训练集都是 1.000——也就是说它们都把这几十条背下来了。区别在背完之后还能不能应付没见过的。 网络一直卡在 0.500 附近,就是「全判一类」的成绩:测试集正负各半,蒙一类正好一半。 结论很直白:这个数据量上,网络连门都没摸到。
三、为什么网络会输
算一下参数量:26 维输入配 12 个隐单元,加偏置和输出层,一共 337 个参数,而样本只有 10 条。 参数比样本多 30 多倍。 这种情况下,网络完全可以靠死记硬背把训练集打满,而它对没见过的输入没有任何泛化能力。 朴素贝叶斯呢?它假设各维独立,把问题砍成了一堆「某个 bigram 出现几次」的独立计数。 假设很强,但在小数据上正好当正则用。 所以不是「深度不如传统」,是「这个数据量配这个模型不划算」。 样本上万、特征上百万的时候,结论会翻过来。
四、什么时候该换哪条路
三条判断标准,按顺序问: 1. 样本有多少。几百条以内,先上传统方法,它便宜、能解释、不容易崩。 2. 特征是现成的吗。表格类数据特征现成,树模型往往就够了; 图像、语音、原始文本没有现成特征,才需要深度模型自己学。 3. 要不要解释。风控、医疗、审核这类场景,能说清「为什么判成这样」比多两个点准确率重要。 三条里有一条指向传统,就别急着上网络。反过来,三条都指向深度,也别硬用传统凑。
五、动手 Demo:同一份语料,朴素贝叶斯与单隐层网络对照
造 80 条情感短句(40 正、40 负,负面里一半是「很 + 负面词」、一半是「不 + 正面词」); 固定 30 条做测试集,剩下 50 条按 10/20/30/50 逐档做训练集; 每档都建 bigram 词表,跑朴素贝叶斯和 12 隐单元的手写网络,打出训练集与测试集准确率。
p1 = X[y == 1].sum(0) + 1.0 # 拉普拉斯平滑
l1 = np.log(p1 / p1.sum())
h = np.tanh(X @ W1 + b1) # 12 个隐单元
p = sigmoid(h @ W2 + b2)
W1 -= lr * (X.T @ ((p - y) * (1 - h * h) @ W2.T))
实跑输出:
--------------------------------------------------------------------
传统与深度:同一份情感任务,两套做法
--------------------------------------------------------------------
语料条数 80(正 40 / 负 40)
训练条数 词表维 NB 训练 NB 测试 网络 训练 网络 测试
------------------------------------------------------------
10 26 1.000 0.700 1.000 0.500
20 36 1.000 0.767 1.000 0.500
30 43 1.000 0.767 1.000 0.500
50 56 1.000 0.833 1.000 0.667
两个模型的训练集都是 1.000,说明它们都把这几十条背了下来。区别在测试集:NB 从 0.700 一路升到 0.833,网络从 0.500 走到 0.667。
测试集正负各半,所以全判一类的准确率正好 0.500——网络在 10 条样本上就停在这个数,说明它连门都没摸到。
原因不是网络不行,是样本太少:26 维输入配 12 个隐单元,参数 337 个,样本只有 10 条。
网络参数量 337 个
对应训练样本 10 条
训练集那一列两个模型全是 1.000,这本身是个警告:在这份数据上,训练集准确率完全不能用来选模型。 测试集那一列才是有效信息:朴素贝叶斯 0.700→0.833 稳步上升,网络 0.500→0.667 一直贴着瞎猜线。 网络没有调参调好不是主要原因。主要原因是 337 个参数对 10 条样本,怎么调都躲不开过拟合。 这份语料是我按模板造的,句式高度重复,所以两个模型都能到 1.000。 真实语料没这么整齐,训练集准确率会低一些,但结论方向一样。
30 秒实验
- 把隐层从 12 个减到 3 个,重跑,看网络测试集能不能追上朴素贝叶斯。
- 把训练轮数从 400 改成 50,看网络是变好还是变差。
- 想一想:为什么参数比样本多的时候,模型一定会背答案?
常见误区
- 「深度一定比传统强」——小数据上传统方法经常赢,而且更稳。
- 「训练集 100% 说明模型好」——只说明它背下来了。
- 「准确率低就调参」——先看参数量和样本量的比例。
自测三问(点开对答案)
1. 传统方法和深度方法最本质的差别是什么? —— 特征是谁找的:传统靠人定,深度让模型自己组合出中间表示。 2. 为什么网络在 10 条样本时只有 0.500? —— 337 个参数对 10 条样本,学不到可泛化的东西,只能全判一类,正好一半。 3. 朴素贝叶斯为什么在小数据上反而稳? —— 它假设各维独立,把问题砍成独立计数,强假设起了正则作用。路线比完了,下一节换个角度:NLP 的任务其实只有两大类——理解和生成。
- ☐ (本节完,下一节 6.1.4 自然语言处理的两大核心任务:理解与生成)