国王的机器》带你了解麻省理工学院的深度学习入门课程
深度学习并不是和机器学习并列的一个科目,而且用神经网络模型来处理机器学习里的有监督学习、无监督学习和强化学习这些子类 (注意这些红蓝绿颜色对应的名词),如下图所示 (我书中还多提到了「深度半监督学习」和「深度迁移学习」):
回到该课程,它的主要内容有
- 深度学习简介 (Introduction to DL)
- 深度序列建模 (Deep Sequence Modeling)
- 深度计算机视觉 (DL in CV)
- 深度生成模型 (Deep Generative Models)
- 深度强化学习 (DRL)
- 局限和前沿 (Limitations and Frontiers)
下面我给大家总结下每节课中最精华的部分,如要了解更多细节,下载本文给的课件材料并访问外国网站去看 Youtube 的视屏。
1
深度学习简介
为什么要学深度学习?可以自动学到特征 (而不想传统机器学习要手工生成特征)!以人脸识别应用来说,卷积神经网络可以自动学到
- 低层特征比如线、边等
- 中层特征比如眼睛、鼻子、耳朵等
- 高级特征就是不同的人脸
感知机 (perceptron) 是神经网络的极简形式,从输入到输出需要以下三个过程:
- 加总每个输入 (input) 和权重 (weight) 的乘积
- 加上偏置 (bias)
- 用转换函数 (transfer function) 得到输出 (output)
多加一个隐藏层 (hidden layer),单输出变成多输出,那么感知机就变成单层 (single layer) 神经网络了。多层 (multiple layer) 神经网络 (这里没画出来) 就是不断增加隐藏层。
计算出输出有什么用?当然要和真实标签 (true label) 比较,两者差异就叫做损失,专业术语是经验损失 (empirical loss)。上面计算的是单个数据的损失,全部加总再求平均得到总体损失 (total loss)。
我看了很多关于对损失 (loss),代价 (cost),误差 (error) 函数的解释,最喜欢用的惯例还是:
- 当描述单数据的误差时,用「损失函数」字眼
- 当描述多数据的误差时,用「代价函数」字眼
- 不想区分时,就用「误差函数」字眼
根据实际问题,损失主要可分为两类
- 回归问题的均方误差 (mean-square-error, MSE)
- 分类问题的交叉熵 (cross-entropy, CE)
定义完损失之后,当然要最小化它,核心方法 (当然还有很多变种) 就是梯度下降法 (gradient descent, GD)。而该方法的核心当然就是算出梯度,即误差函数 J 对所有参数 W 的偏导数。
计算梯度有笨方法 (耗时) 和聪明方法 (省时),而反向传播 (backpropgation) 就是后者。说白了就是张量版的链式法则,充分利用已经算好的偏导数来计算新的偏导数。要深刻了解反向传播可参考我的帖子「人工神经网络之正反向传播」。
现实中神经网络的损失函数非常吓人,用单纯 (vanilla) 的梯度下降很难找到最优解。有几个自适应学习率 (adaptive learning rate) 的算法技巧可以克服这个困难:
- Momentum
- RMSProp
- Adagrad
- Adadelta
- Adam
业界现在用的最多的是 Adam。
有了好的算法,我们发现在梯度下降 (GD) 中,更新一次参数需要在所有数据上做计算。深度学习中的数据有的上百万,这样做需要算力太惊人了。
换一个思路,用所有数据太慢,那么用单个数据,这种方法叫做随机梯度下降 (stochastic gradient descent, SGD),好处是快,坏处是不稳定。
把两者综合下,既不用所有数据,又不用单一数据,用一批数据怎么样?这种方法叫做小批量梯度下降 (mini-batch gradient descent, MBGD),每个 batch 里面的数据个数就是图中的 B。MBGD 在速度和稳定度综合来看比 GD 和 SGD 要好。
过拟合是机器学习 (深度学习) 中永远的问题,两个方法来减少过拟合:
- Dropout (实在没找到合适的翻译)
- 提前终止 (early stopping)
Dropout 的思路是每次随机的断开某些神经元之间的连接,目的是想让剩余的少量神经元能更好地合作,希望能提高神经网络的推广能力 (generalization)。
提前终止这种方法很直观,在训练过程中观察训练误差和验证误差 (上图里说测试误差,我觉得不对),当验证误差随着训练次数增加而增大时,可以提前终止训练。
2
深度序列建模
序列型数据最典型的是语言 (audio) 和文字 (text),当然还有金融里面的时间序列 (time series)。本节以文字举例,通常问题是给几个单词让你预测下一个单词是什么。比如
我生在中国,现定居美国,说一口流利的____
一个好的模型应该预测在空白处应填的词是「中文」。
循环神经网络 (recurrent neural network, RNN) 天生就适用于对序列型数据建模。其实 RNN 根据输入和输出个数可分为五类,如下图 (来自 Andrej Karpathy)。因此本课 RNN 的分类不是很齐全。
图右是一个 RNN 单元 (绿色矩形),输入 x(t) 进,输出 y(t) 出,更关键的是隐变量 h(t) 进进出出,以一种循环的方式。在时点 t 时
- 新隐变量 h(t) 是旧隐变量 h(t-1) 和输入 x(t) 的函数,外面再套个 tanh,参数为 Whh 和 Wxh
- 输出 y(t) 是 h(t) 的一个线性转换,参数为 Why
这些参数 Whh, Wxh, Why 在不同时点上是共享的。
本图将 RNN 单元展开 (unroll),在每个模块中生成 y(t), 沿着时间维度上加总得到损失 L。当然这只是对单个数据而言,对多个数据还要在样本维度上再加总一次。
由于 RNN 里面参数沿着时间轴是共享的,那么在每个时点的损失都和 Whh, Wxh, Why 有关,根据链式法则推出的反向传播也沿着时间轴反向进行。
之后写到 RNN 时,我会详细推导「沿着时间的反向传播」(backpropogation through time, BPTT),比全连接神经网络的反向传播还要简单些,有兴趣的读者可以先看看我写的「张量求导和计算图」先预预热。
但是普通的 RNN 有个问题,就是没有长期的记忆。继续用刚才的例子
我生在中国,现定居美国,说一口流利的____
RNN 在填词时已经忘了前面距离很远的「中国」,而关注位置很近的「美国」,因此填的是「英文」而不是「中文」。
RNN 有这样的问题是在 BPTT 时梯度消失 (vanishing gradient) 了,可能连续相乘的偏导都很小,乘完梯度最后几乎为零。
新参数 = 旧参数 - 学习率×梯度
梯度等于零那还更新个什么参数?RNN 当然学不到东西了。有三个技巧可缓解梯度消失的问题:
- 用 ReLU 激活函数
- 用单位矩阵来初始化权重
- 用「门控单元」来代替普通 RNN 单元
第三个技巧提到的有门控单元 (gated cell) 的 RNN 有两种:
- 门控循环单元 (Gated Recurrent Unit, GRU)
- 长短期记忆 (Long Short Term Memory, LSTM)
我们主要讲更为流行的后者,LSTM。它主要由四个小部分组成,下面四图来对其一一解释。
第一步:决定丢弃什么信息,这个操作由一个「忘记门」来完成。该层读取当前输入 x(t) 和前神经元信息 h(t-1),通过 sigmoid 函数 σ ,得到 f(t) 来决定丢弃的信息,输出结果为
- 1 表示完全保留
- 0 表示完全舍弃
在语言模型的例子中,通过此步可以忘记句子之前主要的性别代名词。
第二步:是确定所存放的新信息,分两步进行:
- sigmoid 函数作为「输入门」,决定要更新的值 i(t)
- tanh 函数来创建一个新的候选值 ~C(t) 加入到状态中
在语言模型的例子中,通过此步可以将新主语的性别替代旧主语的性别。
第三步:更新细胞状态,将 C(t-1) 更新为 C(t),分两步进行:
- 把旧状态 C(t-1) 与丢弃值 f(t) 相乘,丢弃掉确定需要丢弃的信息
- 接着加上 i(t) ⊗ ~C(t) 得到新的候选值
在语言模型的例子中,此步根据主语性别来丢弃旧信息并添加新信息。
第四步:确定输出,分两步进行:
- 用 sigmoid 函数来确定细胞状态的哪个部分将输出出去,得到 o(t)
- 再用 tanh 函数处理新状态 C(t) 并和 o(t) 相乘,仅会输出我们确定输出的那部分
在语言模型的例子中,比如输出判断是一个动词,那么需要根据主语代词是单数还是复数,确定动词的词形。
LSTM 更新状态 C(t) 时都是通过点乘 (而不是矩阵乘法),因此避免了梯度消失的问题。
RNN 的三大应用:
- 音乐生成:输入是一堆音符,输出是下一个音符
- 情感分类:输入是一句评价,输出是「好\坏」类别
- 机器翻译:输入是一国语言,输出是另一国语言
最后机器翻译用到了 encoder+decoder 是很常见的,更先进的还会带上注意力机制 (attention mechanism) 变成 Transformer 模型,想想 ELMo, ULMFiT, GPT, BERT ... 它们现在几乎把 RNN 在自然语言处理的位置取代了,但我们还是要从最基本的 RNN 开始学不是吗?
3
深度计算机视觉
计算机视觉 (computer vision, CV) 里面处理最常见的数据类型是图片,图片是非结构化类数据,但每个像素其实就是 0 到 255 之间的一个数,因此
- 一张黑白图片就是一个 2 维数组
- 一张彩色图片就是一个 3 维数组
在 CV 分类任务中,我们用神经网络将「多维数组」的输入转换成「一维概率向量」的输出,哪个类别的概率值最大就分为那类。
把这个蓝色球想成人眼,当我们看图片时目光锁定在某个红色框上。
那要看完整幅图,必须要一帧帧扫过去啊,伴随的操作就是红色框一点点在移动。
之前说了图片就是多维数组,将 0 到 255 值标准化成 0 到 1,像素 0 代表黑色,像素 1 代表白色,那么再看看这个滤器 (filter) 是不是代表是个白色 X 的样子。把滤器放在图片上一步步扫,每步就算出一个卷积值,那么
- 该值越大,扫的部分越像白色 X
- 该值越小,扫的部分越不像白色 X
卷积值计算也非常简单,就是滤器和被扫的所有数字点乘再加总,用上图举例
1×1 + 1×0 + 1×1
+ 1×0 + 1×1 + 0×0
+ 1×1 + 0×0 + 0×1 = 4
白色 X 只是一种滤器,你还可以想出黑色 X、黑色或白色竖线、黑色或白色横线等等的滤器。这些滤器可以帮助检测出图片中的线和边。
卷积神经网络 (convolutional neural network, CNN) 是由四个元素组成的:
- 卷积层 (convolutional layer)
- 非线性转换函数 (non-linear activation)
- 池化层 (pooling layer)
- 全连接层 (fully-connected layer)
通常元素 1-2-3 是相连的,CNN 中可能有好几个,而元素 4 是放在 CNN 最后若干层。
卷积层做的事就是用滤器扫过照片求卷积,每个滤器的参数在扫过整个照片的过程中是共享的。类比 RNN 的参数沿时间维度共享,CNN 的参数是沿空间维度共享。
非线性转换函数放在卷积层后面,这个和全连接神经网络一样,不停的做非线性转换,常见函数是 ReLU。
池化层主要是将图片变小并保存着最显著的特征。池化层分最大池化 (max pooling) 和平均池化 (average pooling),上图是前者,操作也非常简单,把过滤到的所有数取个最大值保存下来。
「卷积层 + ReLU + 池化层」做的事就是提取特征,从低层特征到高层特征。
特征提取好后可以做很多事情,比如最常见的是「图像分类」,显然用全连接层来做这件事。
除了「图像分类」,CNN 还可以用提取好的特征做以下三件事:
- 语义分割 (semantic segmentation)
- 对象检测 (object detection)
- 看图说话 (image captioning)
三个实例:
- 语义分割:从图像中分割出对象区域,并识别出示猫
- 对象检测:用方框找出两只猫、一只狗和一只鸭子。
- 看图说话:根据图片信息生成「猫在草丛中」
语义分割主要用卷积层下采样 (downsample) 和上采样 (upsampling),流行的模型如 SegNet。
对象检测把定位和分类可以迭代起来,最终在一张图片汇总对多个对象进行检测和分类,流行的模型如 R-CNN 和 YOLO。
看图说话将图信息转换成文字,用 CNN 来处理图片,用 RNN 来生成文字。谷歌的这篇论文『Show and Tell: A Neural Image Caption Generator』了解一下。
4
深度生成模型
机器学习两大类:
- 有监督学习:数据 = (x, y),任务有分类、回归、对象检测、语义分割等。
- 无监督学习:数据 = x,任务有聚类、降维。
本节讲的是深度无监督学习。
生成模型有两类:可以估计样本的概率分布密度,也可以直接对样本分布建模。
生成模型也可以叫做隐变量模型 (latent variable model),旗下两个有名的深度生成模型是
- 变分自编码器 (variational autoencoders, VAE)
- 生成对抗网络 (generative adversarial networks, GAN)
在统计里,隐变量是不可观测的随机变量,我们通常通过可观测变量的样本对隐变量作出推断。在上图中
- 那些法杖是隐变量,那些坐在墙边的奴隶看不到
- 那些法杖的影子是可观测变量,奴隶只能看到它们
奴隶只能靠影子来推测实物 (隐变量) 的样子。
要理解变分自编码器 (VAE),首先需要了解自编码器 (autoencoder)。
自编码器是输出值等于输入值的神经网络,它没用到任何标签 (标签就是输入),因此是无监督学习下面的模型。它的核心理念分两步
- 觉得输入的特征维度太高,压缩成低维度表征,编码器 (encoder) 干的事
- 如果低维度表征够好,那么应该能重构出输入,解码器 (decoder) 干的事
损失函数定义成本身 x 和重构出来的 x 之间的误差。
自编码器只能将编码向量通过解码器映射到相应的输入。它当然不能用于生成具有可变性的相似图像。d上图中 2,自编码器只能生成和原来一样枯燥的 2,不能生成摆手弄姿的 2,不能生成旋转自如的 2。
这些事变分自编码器 (VAE) 做的到。为了实现这一点,VAE 需要学习训练数据的概率分布,因此可以把 VAE 看成是在自编码器基础上加点「概率的料」,而做法就是在隐变量随机抽样,根据其均值向量 μ 和标准差向量 σ。
VAE 的损失由两部分组成,重构损失 (和自编码器里的一样) 加上正则项。正则项定义为
D(pΦ(z|x) || p(z))
其中
- pΦ(z|x) 是隐变量后验分布,通过编码器计算得到 (Φ 是编码网络的参数)
- p(z) 是隐变量先验分布,通常用标准正态分布表示
- D(p || q) 是 KL 散度,度量两个概率分布 p 和 q 之间的差异
在 VAE,由于 z 是随机变量,直接反向传播是行不通的。这是可以重新参数化,把 z 看成 Φ, x 和 ε 的函数,其中 ε 是标准正态随机变量。
由图右可知,现在用反向传播来求 ∂z/∂Φ 和 ∂z/∂x 是可以的,虽然求 ∂z/∂ε 行不通,但是在实操上我们根本不需要这个偏导数。
GAN and the variations that are now being proposed is the most interesting idea in the last 10 years in ML, in my opinion. -- Yann Lecun
GAN 不像 VAE 使用任何显式的密度估计,相反,它是基于博弈论 (game theory)的方法,目的是在两个网络,生成器 (generator) 和判别器 (discriminator) 之间的纳什均衡 (Nash equilibrium)。如上图所示:
- 生成器将杂讯输进数据里想要骗过辨别器
- 判别器从假数据中找出真数据
这样你来我往你追我赶的对抗中,生成器和判别器都越来越牛,生成器造假越来越炉火纯青,判别器打假越来越火眼金睛。直到判别器识别不出来真假的时候,生成器已经练成,可以造出高质量的假货了。
训练 GAN 就是一个 minimax 的游戏,定义
- D 表示判别器
- G 表示生成器
- z 代表杂讯,概率分布 p(z)
- x 是输入,概率分布 pdata
- θd 是判别网络的参数
- θg 是生成网络的参数
minimax 里面的目标函数比较复杂,以后再写 GAN 的帖子是再细说。粗略来说,将目标函数里 G 固定再求 max 就表示 pG 和 pdata 之间的差异,然后在找一个最好的 G 让这个最大值最小,即生成数据和真实数据的分布最小。
训练完后,丢弃判别器 (有点过河拆桥),保留生成器来生成数据了。
5
深度强化模型
机器学习三大类:
- 有监督学习:数据 = (x, y)
- 无监督学习:数据 = x
- 强化学习:数据 = (x, grade)
本节讲的是深度强化学习。
强化学习是在行动中学习,和有监督学习不同,它不需要输入和标签,而需要环境(environment) 对智能体 (agent) 在不同状态 (state) 下行为 (action) 的评价。环境、智能体、状态和行为就是强化学习的四大元素。
评价通常用回报表示,正回报就是奖励,负回报就是惩罚。为了体现回报的时间价值 (time value),我们会用一个小于 1 的折现因子对其打折。
动作值函数 Q 对于智能体而言,就好比人类的价值评判,它能根据智能体所处的状态 s 以及做相应动作 a 可以得到一个行为价值评分 (即总折现奖励的期望值),使智能体依据它的大小去选择实际采取的行动。
智能体要实现自主决策,必然会存在一个策略函数,定义为 π,它是状态 s 到行动 a 的函数,即 π(s) = a。在给定某个状态 s 时,智能体会采用最优行动 a*,而对应也是最优策略 π*(s)。
根据包不包含价值函数和策略可将 (深度) 强化学习两大类:
- 基于价值 (value-based) 学习,神经网络输出是 Q(s, a)
- 基于策略 (policy-based) 学习,神经网络输出是 π(s|a)
对于传统的强化学习,思路是通过计算最优值函数,从而求得最优策略 π*。而 DQN 是通过一些 CNN, RNN 和 FCNN,加上经验回放的技巧,将强化学习的问题转换成有监督学习问题 (见图底这个预测 Q 值和目标 Q 值之间的损失)。
上一幅图的 DQN 是通过 Q 来间接推出最优策略,而本图中 DQN 是直接推出最优策略。既然已经有了基于值函数的方法,为何还需要有直接求最优策略的方法呢?因为更简单,而且最优策略本质就是个策略函数。
直接求策略函数的好处是可以减少对大量无关数据的储存,而且对于连续的动作空间,基于价值函数的方法也不适用。
没听懂。我没有什么 RL 基础,大牛们可以讲讲。
6
深度学习局限和前沿
讲师极简方式总结了这门课教了什么:从数据到决策!
- 数据包括信号、图像、文字等非结构性 (unstructured) 数据
- 决策包括预测 (有监督学习)、检测 (无监督学习) 和行动 (深度学习)
考虑图一的有趣实验,我们知道这四个图分别是狗、香蕉、狗和树,但是我们非要用丢骰子的方法重新定义类,比如 3 对应的是香蕉,5 对应的是狗,1 对应的是树。
这样完全将现实世界的物体类别打乱,但是放进神经网络训练,发现训练准确率还是 100%,但是测试准确率随着上述随机丢筛子的随机性的增强而降低 (见图二绿色逐渐变低的条形图)。神经网络的推广能力 (generalization) 越来越弱。
如果说差推广能力产生深度神经网络局限是正常的,那么这个对抗样本产生的局限性有点匪夷所思。
上图两边的小图用人眼看几乎分别不出差别,都是庙,但是在左图加了扰动以后,右图居然被神经网络分类为鸵鸟!
有人专门研究怎样生成对抗样本,图二提供了思路,而这思路是类比图一得来的。
- 图一:改变参数 θ (固定输入 x 和输出 y) 来减小误差
- 图二:改变输出 x (固定参数 θ 和输出 y) 来增大误差
增大误差不就是增大机器误分类率么?那么改变后的 x 不就是对抗样本了么?
列举一些神经网络的局限:
- 需要大量数据
- 需要大量算力
- 容易被对抗样本愚弄
- 容易受算法偏差影响
- 对不确定性的表示能力弱
- 难解释进而难信任
- 优化时需要注意大量细节
- 需要领域知识来设计或微调网络结构
前沿之一:贝叶斯神经网络
考虑一个二分类狗和猫的神经网络,它输出永远是概率 P(狗) 和 P(猫)。但当在测试数据集中遇到马的图像时,理想情况下应该预测它既不是狗也不是猫,即 P(狗) = P(猫) = 50%,但是,由于输出层的 softmax 函数会调整一个类输出概率分数并最大化一个类,从而导致一个类概率过大。 这是点估计 (point-estimate) 神经网络的主要问题之一,而这就是为什么需要贝叶斯 (Baysian) 神经网络,即为输出增添的不确定性 (uncertainty)。
一言以蔽之,点估计神经网络的参数是一个点,而贝叶斯神经网络的参数是一个分布,如下图所示。
前沿之二:自动学习
自动学习 (AutoML) 是机器学习的未来。它目标就是使用自动化的数据驱动方式来做出上述的决策。用户只要提供数据,自动机器学习系统自动的决定最佳的方案。领域专家不再需要苦恼于学习各种机器学习的算法。
自动学习大大降低的机器学习的门槛,也和强人工智能或通用人工智能 (Artificial General Intelligence) 沾了些边。