- UPDATED:2023 年 1 月 27 日,本文登上 ATA 头条。(注:ATA 全称 Alibaba Technology Associate,是阿里集团最大的技术社区)
- UPDATED:2023 年 2 月 2 日,本文在 ATA 获得鲁肃点赞。(注:鲁肃,本名程立,是阿里合伙人、阿里集团上一任 CTO)
大家好!我是麦克船长,目前就职于阿里巴巴集团,任总监/资深综合运营专家,先后负责过淘宝行业产品团队、天天特卖、大聚划算运营中心。网名一直用「麦克船长」,中科大计算机本科毕业后先是做的音视频流媒体技术、分布式系统等等,干过 Full Stack,后来创业在技术、产品、运营、营销、供应链等等方面多年后来到阿里,在淘系带过不同业务的产品、运营团队。文本来自我的个人博客:
MikeCaptain - 麦克船长的技术、产品与商业博客
,梳理了自己在春节期间对 NLP 基础模型的技术演变学习笔记记录,写就于大年初一在香港过春节时。本文包含 3 个章节:
- 第一章,主要介绍 Transformer 出现之前的几个主流语言模型
,包括 N 元文法(n-gram)、多层感知器(MLP)、卷积神经网络(CNN)、循环神经网络(RNN)。其中 CNN 主要应用领域在计算机视觉,因此没有更详细展开。其他模型也未面面俱到,主要考虑还是一个领域学习者的角度来了解和应用,而非研究。 - 第二章,是本文的核心
,先介绍了注意力机制(Attention Mechanism),然后基于第一章对此前几大语言模型了解后,我们能更好地理解 Transformer 为什么会带来革命性的影响。 - 第三章,是一个 Transformer 的实现版本
,基于 Tensorflow。
春节期间,除了本文,我还梳理了一篇关于「大型语言模型(LLM)在 Transformer 之后的演化综述」和一篇关于「LLM 引领生产力革命,带来的未来几年科技脉搏把控」
,但没有时间整理排版,待日后有空再归拢后发出,这些权当是在春节期间消磨时间的技术爱好,因为是偏向学习的技术笔记,所以
非常欢迎大家批评、指正、交流
。
- 作者:钟超(麦克船长)
- 邮箱:zhongchao.ustc#gmail.com (#->@)
- 微信:sinosuperman(请注明「公司/机构、职位」便于我备注,谢谢)
- 时间:2023 年 1 月 22 日
前言
本文试图从技术角度搞清楚一个问题:
过去一年 AIGC 爆火、过去五年 NLP(自然语言处理)领域突飞猛进的缘起是什么?
这个问题被解答后,将还有两个问题,但暂时本文没有作答:1)如果认为通过图灵测试代表着 AGI(Artificial General Intelligence,通用人工智能)的话,当下 NLP,乃至 AGI 发展到什么程度了?2)未来一些年内,AGI 的发展路线可能会是怎样的?
利用春节时间,写了这么一篇数万字的长文笔记,希望共同爱好的朋友能读完多多指正。
1、我来阿里之后第一个新增爱好是「变形金刚模型」,第二个新增爱好是「变形金刚模型」
写了个这么冷的梗,其实想说的是,前者指的是著名 IP「变形金刚」相关的手办玩具模型,后者指的是这个引领革命的人工智能语言模型 Transformer。这两个爱好,都与目前从事的电商工作本职没有表面上的直接联系,权当爱好了。
2022 年「生成式 AI」应用取得了突飞猛进的发展,作为一个「古典互联网」从业者,深切地感到这一次 AI 技术可能会带来的颠覆式变革,这让我兴奋又焦虑。2022 年上半年,我从天天特卖业务负责人到大聚划算运营中心负责人,在去年相当长一段时间里在关注直播带货在营销平台的模式命题,一直在思考一个问题:直播电商的高效(更适合的商品演绎方式 + 私域权益 + 冲动购买等」vs. 直播电商的低效(直播分发无人货匹配 + 直播间内千人一面 + 货品状态未知 + 主播不可控等),能否推动一个保留直播的高效,同时解决直播的低效的模式呢?
这里面有大量的内容值得探讨,不过这不是麦克船长该系列文章的初衷,但这是我为什么开始非常关注 AI 的引子。直播电商的数字人技术基础,有动作捕捉、面部表情模拟、视觉渲染、直播话术生成、语音合成等等。依据第一性原理抽丝剥茧后,我发现尽管动作捕捉、视觉渲染等等很多技术仍有很大挑战,但是从商业视角看真正最影响用户心智的,是直播话术生成和演绎,除了头部主播,绝大多数直播带货在这方面都做的很糟糕,那么这里面就有巨大的「机器学习」生成内容超越非头部的大多数从业者的市场空间,而这完全依赖自然语言处理(NLP)。
这个问题就属于「生成式 AI」的范畴了,国外科技圈叫它「Gen-AI」,即 Generative AI,中国科技圈都叫它「AIGC」,即 AI Generated Content,与 UGC、PGC 相对应。Gen-AI 的叫法更关注主体,具体地说是「生成式 AI 模型」,它是个「内容引擎」。而中国的叫法更关注「内容应用」。
讲到 AIGC 这里,大家熟悉的 ChatGPT 就在 2022 年年底登场了。也是因为 ChatGPT 的破圈,带来了 AIGC 在国内科技圈的关注度暴涨。我从去年年中开始关注「文生图,text2image」领域的明星 Stable Diffusion 开源,进而关注到了 text2image 应用的爆发,包括 Disco Diffusion、MidJourney、DALL·E 2 等等,这些都源于 CV(计算机视觉)领域因为 Diffusion 模型发展带来的技术突破。
AI 生成图片确实非常惊人。我酷爱变形金刚模玩,进而对机甲类都非常喜欢,所以随手生成了几张图,这里贴一下大家看看,分钟级的创作速度。(注意:当下 AI 生成图片主要是基于 Diffusion 的应用发展,AI 生成文本的核心驱动才是 Transformer 模型,此处只是展示)
但是从第一性原理角度讲,生成图片的应用广度,远远小于生成文本。文本内容的本质是语言文字的理解与生成,人类历史有 600 万年,但是人类文明历史大概就 6000 年,文明的大发展出现在近 2000 多年的原因,主要来自 3500 多年前人类发明了文字。所以 AI 生成文本,意味着 AI 可以用人类熟悉的方式(语言文字)与人类高效协作,这必将引爆生产力革命。而这必将深入影响电商、内容、游戏、云计算、企业服务等众多领域。
2、掌握技术基础,是当下读懂 AI 脉搏的基本功,而这个脉搏将带动各行各业
一旦深入关注 AI、关注 NLP 领域,你就会发现当下仍然处于一个技术发展突破的阶段,不关注技术的情况下来聊 AI、聊 NLP、聊 AIGC,那就只能是一个「爱好者」,而无法深入与这个行业内的弄潮儿对话,更不要提参与其中了。所以这个春节,麦克船长回归了当年做技术时的初心,翻了一些材料,学习了 NLP 语言模型的关键技术,在此作为技术学习笔记,与大家分享。尽管担心班门弄斧,但是本着费曼老师提倡的输出学习法,我把自己学习梳理的内容抛出来,除了会更帮助到我自己,也能结交一些对此同样在关注的同学们,欢迎感兴趣的同学加我的微信(微信号 sinosuperman)在业余时间和我交流。
阅读本文,先对你过往的基础知识做了一些假设,如果你暂未了解,可能在阅读时遇到以下内容做一些简单地查询即可:
- Word Presentation:自然语言处理中的词表示法,主要涉及 embedding。
- 张量:需要一点基础,比如了解张量的形状、升降维度等。但不会涉及到复杂问题,对一阶张量(向量)、二阶张量(矩阵)的简单运算有数学基础即可。对三阶张量,大概能想象出其空间含义即可。语言模型里理解词之间的距离,是有其空间几何意义的。
- 技术框架:PyTorch 或 TensorFlow 框架。由于时间和篇幅关系,春节期间梳理这些时,对于框架基础,我主要是 Google 现用现查,询问 ChatGPT 以及在微信读书里直接搜索全文。
作为技术笔记难免有纰漏或理解错误,欢迎指正。文中自绘图片用的是 Graphviz,公式生成用的是 KaTeX,贴到 ATA 后难免有一些没有兼容的部分(发现的已做了 fix),望见谅。
第一章 · 2017 年之前的几个关键 NLP 语言模型
NLP 的技术基础方面,我认为主要是这两部分:词表示法(Word Presentation)、语言模型(Language Model)。对于词表示法,这里不做详细介绍,基本的思路就是把词表示为向量(一维张量),最基本的 One-Hot、Word2Vec、GloVe、fastText 等。这部分的技术演进也在不断前进,比如本文将要重点介绍的 Transformer 模型里,用到的词表示法是「引入上下文感知的词向量」。
语言模型从早期的 N 元文法(N-Gram,本文要介绍的),到神经网络被提出后最早期的感知器(Perceptron),再到后来席卷计算机视觉(CV)领域的卷积神经网络(CNN),然后出现考虑序列特征的循环神经网络(RNN,包括 Encoder-Decoder 模型),直到 2017 年横空出世的 Transformer,大概分这五个主要阶段。因为本文的重点是 Transformer,所以前面四个模型我会快速概览一下,然后介绍下最朴素的注意力(Attention)机制,基于此再详细介绍下 Transformer,并对一个完整的、精炼实现的代码实例进行精讲。
第 1 节 · N 元文法语言模型
1.1、马尔科夫假设(Markov Assumption)与 N 元文法语言模型(N-gram Language Model)
下一个词出现的概率只依赖于它前面 n-1 个词,这种假设被称为「马尔科夫假设(Markov Assumption」。N 元文法,也称为 N-1 阶马尔科夫链。
- 一元文法(1-gram),unigram,零阶马尔科夫链,不依赖前面任何词;
- 二元文法(2-gram),bigram,一阶马尔科夫链,只依赖于前 1 个词;
- 三元文法(3-gram),trigram,二阶马尔科夫链,只依赖于前 2 个词;
- ……
通过前 t-1 个词预测时刻 t 出现某词的概率,用最大似然估计:
P
(
w
t
∣
w
1
,
w
2
.
.
.
w
t
−
1
)
=
C
(
w
1
,
w
2
,
.
.
.
w
t
)
C
(
w
1
,
w
2
,
.
.
.
w
t
−
1
)
P(w_t | w_1,w_2…w_{t-1}) = \frac{C(w_1,w_2,…w_t)}{C(w_1,w_2,…w_{t-1})}
P
(
w
t
∣
w
1
,
w
2
…
w
t
−
1
)
=
C
(
w
1
,
w
2
,
…
w
t
−
1
)
C
(
w
1
,
w
2
,
…
w
t
)
进一步地,一组词(也就是一个句子)出现的概率就是:
P
(
w
1
,
w
2
,
.
.
.
w
t
)
=
P
(
w
t
∣
w
1
,
w
2
,
.
.
.
w
t
−
1
)
⋅
P
(
w
t
−
1
∣
w
1
,
w
2
,
.
.
.
w
t
−
2
)
⋅
.
.
.
⋅
P
(
w
1
)
=
∏
i
=
1
t
−
1
P
(
w
i
∣
w
1
:
i
−
1
)
\begin{aligned} P(w_1,w_2,…w_t) &= P(w_t | w_1,w_2,…w_{t-1}) \cdot P(w_{t-1} | w_1,w_2,…w_{t-2}) \cdot … \cdot P(w_1) \ &= \displaystyle\prod_{i=1}^{t-1}P(w_i | w_{1:i-1}) \end{aligned}
P
(
w
1
,
w
2
,
…
w
t
)
=
P
(
w
t
∣
w
1
,
w
2
,
…
w
t
−
1
)
⋅
P
(
w
t
−
1
∣
w
1
,
w
2
,
…
w
t
−
2
)
⋅
…
⋅
P
(
w
1
)
=
i
=
1
∏
t
−
1
P
(
w
i
∣
w
1
:
i
−
1
)
为了解决句头、尾逇概率计算问题,我们再引入两个标记 和 分别表示 beginning of sentence 和 end of sentence,所以
w
0
=
w_0 =
w
0
=
、
w
l
e
n
g
t
h
1
=
w_{length + 1} =
w
l
e
n
g
t
h
1
=
,其中 length 是词的数量。
具体地,比如对于 bigram,该模型表示如下:
P
(
w
1
,
w
2
,
.
.
.
w
t
)
=
∏
i
=
1
t
−
1
P
(
w
i
∣
w
i
−
1
)
P
(
w
t
∣
w
t
−
1
)
=
C
(
w
t
−
1
,
w
t
)
C
(
w
t
−
1
)
\begin{aligned} P(w_1,w_2,…w_t) &= \displaystyle\prod_{i=1}^{t-1}P(w_i | w_{i-1}) \ P(w_t | w_{t-1}) &= \frac{C(w_{t-1}, w_t)}{C(w_{t-1})} \end{aligned}
P
(
w
1
,
w
2
,
…
w
t
)
P
(
w
t
∣
w
t
−
1
)
=
i
=
1
∏
t
−
1
P
(
w
i
∣
w
i
−
1
)
=
C
(
w
t
−
1
)
C
(
w
t
−
1
,
w
t
)
- 如果有词出现次数为了 0,这一串乘出来就是 0 了,咋办?
- 因为基于马尔科夫假设,所以 N 固定窗口取值,对长距离词依赖的情况会表现很差。
- 如果把 N 值取很大来解决长距离词依赖,则会导致严重的数据稀疏(零频太多了),参数规模也会急速爆炸(高维张量计算)。
上面的第一个问题,我们引入平滑 / 回退 / 差值等方法来解决,而后面两个问题则是在神经网络模型出现后才更好解决的。
1.2、平滑(Smoothing)/ 折扣(Discounting)
虽然限定了窗口 n 大小降低了词概率为 0 的可能性,但当 n-gram 的 n 比较大的时候会有的未登录词问题(Out Of Vocabulary,OOV)。另一方面,训练数据很可能也不是 100% 完备覆盖实际中可能遇到的词的。所以为了避免 0 概率出现,就有了让零平滑过渡为非零的补丁式技术出现。
最简单的平滑技术,就是折扣法(Discounting)。这是一个非常容易想到的办法,就是把整体 100% 的概率腾出一小部分来,给这些零频词(也常把低频词一起考虑)。常见的平滑方法有:加 1 平滑、加 K 平滑、Good-Turing 平滑、Katz 平滑等。
1.2.1、加 1 平滑 / 拉普拉斯平滑(Add-One Discounting / Laplace Smoothing)
加 1 平滑,就是直接将所有词汇的出现次数都 +1,不止针对零频词、低频词。如果继续拿 bigram 举例来说,模型就会变成:
P
(
w
i
∣
w
i
−
1
)
=
C
(
w
i
−
1
,
w
i
)
1
∑
j
=
1
n
(
C
(
w
i
−
1
,
w
j
)
1
)
=
C
(
w
i
−
1
,
w
i
)
1
C
(
w
i
−
1
)
∣
V
∣
P(w_i | w_{i-1}) = \frac{C_(w_{i-1},w_i) + 1}{\displaystyle\sum_{j=1}^n(C_(w_{i-1},w_j) + 1)} = \frac{C(w_{i-1}, w_i) + 1}{C(w_{i-1}) + |\mathbb{V}|}
P
(
w
i
∣
w
i
−
1
)
=
j
=
1
∑
n
(
C
(
w
i
−
1
,
w
j
)
1
)
C
(
w
i
−
1
,
w
i
)
1
=
C
(
w
i
−
1
)
∣
V
∣
C
(
w
i
−
1
,
w
i
)
1
其中
N
N
N
表示所有词的词频之和,
∣
V
∣
|\mathbb{V}|
∣
V
∣
表示词汇表的大小。
如果当词汇表中的词,很多出现次数都很小,这样对每个词的词频都 +1,结果的偏差影响其实挺大的。换句话说,+1 对于低频词很多的场景,加的太多了,应该加一个更小的数( 1 < δ < 1)。所以有了下面的「δ 平滑」技术。
1.2.2、加 K 平滑 / δ 平滑(Add-K Discounting / Delta Smoothing)
把 +1 换成 δ,我们看下上面 bigram 模型应该变成上面样子:
P
(
w
i
∣
w
i
−
1
)
=
C
(
w
i
−
1
,
w
i
)
δ
∑
j
=
1
n
(
C
(
w
i
−
1
,
w
j
)
δ
)
=
C
(
w
i
−
1
,
w
i
)
δ
C
(
w
i
−
1
)
δ
∣
V
∣
P(w_i | w{i-1}) = \frac{C_(w_{i-1},w_i) + \delta}{\displaystyle\sum_{j=1}^n(C_(w_{i-1},w_j) + \delta)} = \frac{C(w_{i-1}, w_i) + \delta}{C(w_{i-1}) + \delta|\mathbb{V}|}
P
(
w
i
∣
w
i
−
1
)
=
j
=
1
∑
n
(
C
(
w
i
−
1
,
w
j
)
δ
)
C
(
w
i
−
1
,
w
i
)
δ
=
C
(
w
i
−
1
)
δ
∣
V
∣
C
(
w
i
−
1
,
w
i
)
δ
δ 是一个超参数,确定它的值需要用到困惑度(Perplexity,一般用缩写 PPL)。另外,有些文章里也会把这个方法叫做「加 K 平滑,Add-K Smoothing」。
1.2.3、困惑度(Perplexity)
对于指定的测试集,困惑度定义为测试集中每一个词概率的几何平均数的倒数,公式如下:
PPL
(
D
t
e
s
t
)
=
1
P
(
w
1
,
w
2
.
.
.
w
n
)
n
\operatorname{PPL}(\mathbb{D}_{test}) = \frac{1}{\sqrt[n]{P(w_1,w_2…w_n)}}
PPL
(
D
t
es
t
)
=
n
P
(
w
1
,
w
2
…
w
n
)
1
把
P
(
w
1
,
w
2
,
.
.
.
w
t
)
=
∏
i
=
1
t
−
1
P
(
w
i
∣
w
i
−
1
)
P(w_1,w_2,…w_t) = \displaystyle\prod_{i=1}^{t-1}P(w_i|w_{i-1})
P
(
w
1
,
w
2
,
…
w
t
)
=
i
=
1
∏
t
−
1
P
(
w
i
∣
w
i
−
1
)
带入上述公式,就得到了 PPL 的计算公式:
PPL
(
D
t
e
s
t
)
=
(
∏
i
=
1
n
P
(
w
i
∣
w
1
:
i
−
1
)
)
−
1
n
\operatorname{PPL}(\mathbb{D}_{test}) = (\displaystyle\prod_{i=1}nP(w_i|w_{1:i-1})){-\frac{1}{n}}
PPL
(
D
t
es
t
)
=
(
i
=
1
∏
n
P
(
w
i
∣
w
1
:
i
−
1
)
)
−
n
1
1.3、回退(Back-off)
在多元文法模型中,比如以 3-gram 为例,如果出现某些三元语法概率为零,则不使用零来表示概率,而回退到 2-gram,如下。
P
(
w
i
∣
w
i
−
2
w
i
−
1
)
=
{
P
(
w
i
∣
w
i
−
2
w
i
−
1
)
C
(
w
i
−
2
w
i
−
1
w
i
)
0
P
(
w
i
∣
w
i
−
1
)
C
(
w
i
−
2
w
i
−
1
w
i
)
=
0
a
n
d
C
(
w
i
−
1
w
i
)
0
P(w_i|w_{i-2}w_{i-1}) = \begin{cases} P(w_i|w_{i-2}w_{i-1}) & C(w_{i-2}w_{i-1}w_i) > 0 \ P(w_i|w_{i-1}) & C(w_{i-2}w_{i-1}w_i) = 0 \enspace and \enspace C(w_{i-1}w_i) > 0 \end{cases}
P
(
w
i
∣
w
i
−
2
w
i
−
1
)
=
{
P
(
w
i
∣
w
i
−
2
w
i
−
1
)
P
(
w
i
∣
w
i
−
1
)
C
(
w
i
−
2
w
i
−
1
w
i
)
0
C
(
w
i
−
2
w
i
−
1
w
i
)
=
0
an
d
C
(
w
i
−
1
w
i
)
0
1.4、差值(Interpolation)
N 元文法模型如果用回退法,则只考虑了 n-gram 概率为 0 时回退为 n-1 gram,那么自然要问:n-gram 不为零时,是不是也可以按一定权重来考虑 n-1 gram?于是有了插值法。以 3-gram 为例,把 2-gram、1-gram 都考虑进来:
P
(
w
i
∣
w
i
−
2
w
i
−
1
)
=
λ
1
P
(
w
i
∣
w
i
−
2
w
i
−
1
)
λ
2
P
(
w
i
∣
w
i
−
1
)
λ
3
P
(
w
i
)
P(w_i|w_{i-2}w_{i-1}) = \lambda_1 P(w_i|w_{i-2}w_{i-1}) + \lambda_2 P(w_i|w_{i-1}) + \lambda_3 P(w_i)
P
(
w
i
∣
w
i
−
2
w
i
−
1
)
=
λ
1
P
(
w
i
∣
w
i
−
2
w
i
−
1
)
λ
2
P
(
w
i
∣
w
i
−
1
)
λ
3
P
(
w
i
)
第 2 节 · 感知器(Perceptron)
N 元文法模型的显著问题,在「马尔科夫假设与 N 元文法语言模型」小节已经提到了。这些问题基本在神经网络模型中被解决,而要了解神经网络模型,就要从感知器(Perceptron)开始。1957 年感知机模型被提出,1959 年多层感知机(MLP)模型被提出。MLP 有时候也被称为 ANN,即 Artificial Neural Network,接下来我们来深入浅出地了解一下,并有一些动手的练习。
2.1、感知器(Perceptron):解决二元分类任务的前馈神经网络
x 是一个输入向量,w 是一个权重向量(对输入向量里的而每个值分配一个权重值所组成的向量)。举一个具体任务例子,比如如果这两个向量的内积超过某个值,则判断为 1,否则为 0,这其实就是一个分类任务。那么这个最终输出值可以如下表示:
y
=
{
1
(
ω
⋅
x
≥
0
)
0
(
ω
⋅
x
<
0
)
y = \begin{cases} 1 & (\omega \cdot x \geq 0) \ 0 & (\omega \cdot x \lt 0) \end{cases}
y
=
{
1
0
(
ω
⋅
x
≥
0
)
(
ω
⋅
x
<
0
)
这就是一个典型的感知器(Perceptron),一般用来解决分类问题。还可以再增加一个偏差项(bias),如下:
y
=
{
1
(
ω
⋅
x
b
≥
0
)
0
(
ω
⋅
x
b
<
0
)
y = \begin{cases} 1 & (\omega \cdot x + b \geq 0) \ 0 & (\omega \cdot x + b \lt 0) \end{cases}
y
=
{
1
0
(
ω
⋅
x
b
≥
0
)
(
ω
⋅
x
b
<
0
)
感知器其实就是一个前馈神经网络,由输入层、输出层组成,没有隐藏层。而且输出是一个二元函数,用于解决二元分类问题。
2.2、线性回归(Linear Regression):从离散值的感知器(解决类问题),到连续值的线性回归(解决回归问题)
一般来说,我们认为感知器的输出结果,是离散值。一般来说,我们认为离散值作为输出解决的问题,是分类问题;相应地,连续值解决的问题是回归(Regression)。比如对于上面的感知器,如果我们直接将
ω
⋅
x
b
\omega \cdot x + b
ω
⋅
x
b
作为输出值,则就变成了一个线性回归问题的模型了。
下面我们用 PyTorch 来实现一个线性回归的代码示例,首先我们要了解在 PyTorch 库里有一个非常常用的函数:
nn.Linear(in_features, out_features)
这个函数在创建时会自动初始化权值和偏置,并且可以通过调用它的
forward
函数来计算输入数据的线性变换。具体来说,当输入为
x
时,
forward
函数会计算
y
=
ω
⋅
x
b
y = \omega \cdot x + b
y
=
ω
⋅
x
b
,其中
W
W
W
和
b
b
b
分别是
nn.Linear
图层的权值和偏置。
我们来一个完整的代码示例:
import torch
import torch.nn as nn
# 定义模型
class LinearRegression(nn.Module):
def __init__(self, input_size, output_size):
super(LinearRegression, self).__init__()
self.linear = nn.Linear(input_size, output_size)
def forward(self, x):
return self.linear(x)
# 初始化模型
model = LinearRegression(input_size=1, output_size=1)
# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
# 创建输入特征 X 和标签 y
X = torch.Tensor([[1], [2], [3], [4]])
y = torch.Tensor([[2], [4], [6], [8]])
# 训练模型
for epoch in range(100):
# 前向传播,在本文 2.7 节有详细介绍
predictions = model(X)
loss = criterion(predictions, y)
# 反向传播,在本文 2.7 节有详细介绍
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 创建测试数据 X_test 和标签 y_test
X_test = torch.Tensor([[5], [6], [7], [8]])
y_test = torch.Tensor([[10], [12], [14], [16]])
# 测试模型
with torch.no_grad():
predictions = model(X_test)
loss = criterion(predictions, y_test)
print(f'Test loss: {loss:.4f}')
上述代码,一开始先创建一个
LinearRegression
线性回归模型的类,其中有一个
forward
前向传播函数,调用时其实就是计算一下输出值
y
。
主程序,一开始创建一个线性回归模型实例,然后定义一个用于评价模型效果的损失函数评价器,和用随机梯度下降(Stochastic Gradient Descent)作为优化器。
然后创建一个输入特征张量,和标签张量。用这组特征和标签进行训练,训练的过程就是根据
X
计算与测试
predictions
向量,再把它和
y
一起给评价器算出损失
loss
,然后进行反向传播(在本文 2.7 节有介绍)。注意反向传播的三行代码:
optimizer.zero_grad()
loss.backward()
optimizer.step()
如此训练 100 次(每一次都会黑盒化地更新模型的参数,一个
epoch
就是一次训练过程,有时也称为
iteration
或者
step
,不断根据
loss
训练优化模型参数。
然后我们创建了一组测试特征值张量
X_test
,和测试标签张量
y_test
,然后用它们测试模型性能,把测试特征得到的
predictions
与
y_test
共同传给评价器,得到
loss
。在这个例子中我们会得到如下结果:
Test loss: 0.0034
2.3、逻辑回归(Logistic Regression):没有值域约束的线性回归,到限定在一个范围内的逻辑回归(常用于分类问题)
可以看到线性回归问题,输出值是没有范围限定的。如果限定(limit)在特定的
(
0
,
L
)
(0, L)
(
0
,
L
)
范围内,则就叫做逻辑回归了。那么如何将一个线性回归变成逻辑回归呢?一般通过如下公式变换:
y
=
L
1
e
−
k
(
z
−
z
0
)
y = \frac{L}{1 + e^{-k(z-z_0)}}
y
=
1
e
−
k
(
z
−
z
0
)
L
这样原来的
z
∈
(
−
∞
,
∞
)
z \in (-\infty, +\infty)
z
∈
(
−
∞
,
∞
)
就被变换成了
y
∈
(
0
,
L
)
y \in (0, L)
y
∈
(
0
,
L
)
了。
- 激活函数
:这种把输出值限定在一个目标范围内的函数,被叫做
激活函数(Activation Function)
。 - 函数的陡峭程度
由
k
k
k
控制,越大越陡。
- 当
z
=
z
0
z = z_0
z
=
z
0
时,
y
=
L
2
y = \frac{L}{2}
y
=
2
L
。
下面给出一个基于 Python 的 scikit-learn 库的示例代码:
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# 这是 scikit-learn 库里的一个简单的数据集
iris = load_iris()
# 把 iris 数据集拆分成训练集和测试集两部分
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.25, random_state=42)
# 用 scikit-learn 库创建一个逻辑回归模型的实例
lr = LogisticRegression()
# 用上边 split 出来的训练集数据,训练 lr 模型实例
lr.fit(X_train, y_train)
# 用训练过的模型,拿测试集的输入数据做测试
predictions = lr.predict(X_test)
# 用测试集的数据验证精确性
accuracy = lr.score(X_test, predictions)
print(accuracy)
2.4、Sigmoid 回归(Sigmoid Regression):归一化的逻辑回归,一般用于二元分类任务
当
L
=
1
,
k
=
1
,
z
0
=
0
L = 1, k = 1, z_0 = 0
L
=
1
,
k
=
1
,
z
0
=
0
,此时的激活函数就是
S
i
g
m
o
i
d
Sigmoid
S
i
g
m
o
i
d
函数,也常表示为
σ
\sigma
σ
函数,如下:
y
=
1
1
e
−
z
y = \frac{1}{1 + e^{-z}}
y
=
1
e
−
z
1
Sigmoid 回归的值域,恰好在 (0, 1) 之间,所以常备作为用来归一化的激活函数。而一个线性回归模型,再用 sigmoid 函数归一化,这种也常被称为「Sigmoid 回归」。Sigmoid 这个单词的意思也就是 S 形,我们可以看下它的函数图像如下:
因为归一化,所以也可以把输出值理解为一个概率。比如我们面对一个二元分类问题,那么输出结果就对应属于这个类别的概率。
这样一个 sigmoid 模型可以表示为:
y
=
S
i
g
m
o
i
d
(
W
⋅
x
b
)
y = Sigmoid(W \cdot x + b)
y
=
S
i
g
m
o
i
d
(
W
⋅
x
b
)
另外
s
i
g
m
o
i
d
sigmoid
s
i
g
m
o
i
d
函数的导数(即梯度)是很好算的:
y
′
=
y
⋅
(
1
−
y
)
y’ = y \cdot (1-y)
y
′
=
y
⋅
(
1
−
y
)
。这非常方便用于「梯度下降算法」根据 loss 对模型参数进行优化。Sigmoid 回归,一般用于二元分类任务。那么对于超过二元的情况怎么办呢?这就引出了下面的 Softmax 回归。
2.5、Softmax 回归(Softmax Regression):从解决二元任务的 sigmoid,到解决多元分类任务的 Softmax
相对逻辑回归,Softmax 也称为多项逻辑回归。上面说 Sigmoid 一般用于解决二元分类问题,那么多元问题就要用 Softmax 回归了。我们来拿一个具体问题来解释,比如问题是对于任意输入的一个电商商品的图片,来判断这个图片所代表的的商品,属于哪个商品类目。假设我们一共有 100 个类目。那么一个图片比如说其所有像素值作为输入特征值,输出就是一个 100 维的向量
**z
z
z**
,输出向量中的每个值
z
i
z_i
z
i
表示属于相对应类目的概率
y
i
y_i
y
i
:
y
i</