这里总结了李宏毅老师的机器学习的课程。首先我们将会了解到机器学习的概念,但是课程的主要观点将会聚焦到Deep Learning。进行了解之后我们会学习到监督学习( supervised learning )的相关网络,还有自监督学习(self- supervised learning)的相关知识,包括生成对抗网络(GAN),BERT,Tansformer等。后面还会讲到强化学习(Reinforcement learning)、可解释化的AI、模型攻击(model attack)、领域自适应(domain adaption)、模型压缩(network compression)、机器终身学习(long-life learning )和元学习(meata learning)
(一)机器学习或者是深度学习的介绍
(1)什么是机器学习ML?
寻找一个函数,解决一个问题。
(2)是什么样的函数呢?
- Regression(回归): the function outputs a scalar.也就是一个回归问题,它可以预测一个数值。例如预测PM2.5
- Classification(分类):given the computer some options or classes, the function outputs the correct one. 例如:邮件是否为垃圾邮件?阿尔法go的预测问题。
- Structured learning(结构的学习):create something with structure(image, document)让机器学会一个结构化问题。例如写邮件,写新闻,画画,编曲等
(3)寻找函数的步骤是怎么样的呢?
第一步:设计一个带有未知参数的函数
第二步:定义一个Loss函数
- loss函数的输出证明了函数的好坏
- 常用的损失函数有平方差,绝对值差,交叉熵等(所谓交叉熵,就是说明两个分布之间的差距(距离))
第三步:不断优化更新函数
- 优化的意思是找出合适的参数(w,b)
- 随机选取参数、梯度下降、更新参数
- 目的是让loss最小,也就是让函数越来越好
这里有一个小知识点,局部最优解往往不是神经网络常遇到的问题。
(4)如何让网络解决非线性问题?
线性的神经网络能解决的问题往往是有限的,例如只能解决简单的回归问题,和二分类的问题。但是像 XOR 异或问题却无法解决。然而我们遇到的问题大多数是非线性的。
那么我们如何让神经网络变成非线性的呢?
这就是我们经常提到的激活函数了。
我们都知道常用的是sigmoid, tanh,relu。
那我们为什么激活函数不是线性的呢?当我们把线性函数带进去的时候会发现,神经网络仍是线性的。所以激活函数都是非线性的。
关于激活函数的内容可参考:
【1】https://zhuanlan.zhihu.com/p/260970955
【2】https://www.jianshu.com/p/1dfe5e05a75c
【3】https://zhuanlan.zhihu.com/p/61616349
【4】https://www.jianshu.com/p/aad9deccbc27
(5)什么是深度学习DL?
深度学习和是在机器学习的基础上,将神经网络不断地堆叠,让网络变得像一条深深得通道。这便是深度学习。
- 发展历史
i. 1958: perception (linear model)
ii. 1969: perceptron has limitation
iii. 1980s: multi-layer perveptron
Do not have any significant difference from DNN today.
iv. 1986: backpropagation (反向传播)
Usually more than 3hidden layers is not helpful
v. 1989:1 hidden layer is “good enough”, why deep?
vi. 2006: RBM initialization ( breakthrough )
vii. 2009: GPU
viii. 2011: start to be used in speech recognition
ix. 2012 win ILVRC image competition
(6)为什么神经网络是一个Fat network,而是一个Deep network?
理论上来说神经网络就是一个巨型的函数,将输入输进去,通过计算就能得出结果。与其把神经网络做的那么深入,为何不直接把神经网络设置成一个只有一层的有很多参数的网络呢?
因为通过实践发现,深层的网络往往能学习到时间或者空间上的更深层次的信息,这是单层神经网络无法学习得到的。
(二) 机器学习任务的攻略
这里需要解决的问题是在我们训练神经网络的时候,会遇到很多的问题使得神经网络的训练效果并不好。这里是具体分析其原因。
(1)损失值很大
这种情况出现主要是两个原因:
- (1)模型太小
这里有可能是模型的容量太小,也就是说模型不够复杂所导致的loss无法收敛。需要做的是 - (2)优化器优化问题
例如可能会进入到一个非常平坦的地方,让梯度无法更新。
如何区分这两种情况呢?
构建深的model,但是loss更加大了,那就是优化器的问题所在了,如果loss变小了,那就是网络不够复杂的问题。
(2)损失值很小,但是在测试集上表现不好。
这里极有可能是过拟合( overfitting)了。也就是说神经网络的模型足够复杂,直接把训练集里面的样本直接记下来了。但是遇到新的问题就不会解决了。
解决方案:
- (1)扩充数据集,不推荐说是自己去扩充数据集,但是可以使用一些数据增强技术data augmentation 例如:平移、反转、截取等
- (2)减少参数[设计一个更小的模型,dropout,权重衰退],或者共享参数[Resnet等]
参考:
【1】https://www.jianshu.com/p/995516301b0a
【2】https://www.jianshu.com/p/2155e59d14a4
【3】https://www.jianshu.com/p/ad00cf171353
(3)如何加速loss收敛?
使用更好的优化器,例如Adam等,也可以通过设置learning rate,加速其学习的步伐。还可以使用batch,批量训练。
(4)神经网络收敛不起来怎么办?
极有可能是遇到了局部最优解和鞍点,他俩的共同特征就是导数为0,也就使得梯度卡住了,这样的点叫做:critical point。其实实际训练中local minima 是不常见的,我们往往卡在鞍点(saddle point)。通常是通过计算H的值,就能判断是什么情况:
(5)学习率(learning rate)始终用一个值好吗?
答案肯定是否定的,learning rate的大小需要随着训练不断变化。例如,loss function一开始的坡度很大,我们要使用学习率控制跨步小一点,别直接飞出天际。当坡度非常小的时候,我们要给它一点步伐,别卡住了。这便能够一定程度上解决critical point的问题。
我们通常遇到的问题就是,训练着,结果loss卡住不下降了,难道真的是遇到critical point了嘛?在实际情况中上面说的critical point往往不是问题。它能通过好的优化器很大程度上解决。
那么都有怎么样的解决方案呢?
- SGD:随机梯度下降,学习率固定
- SGD with momentum:动量,也就是加入前面梯度的影响。就像是惯性一样。可以直接冲过平坦的地方,学习率固定
- Adagrad:让学习率不在震荡,斜率大的地方,分母大,从而学习率小,步子小。但学习率随着时间越来越小,会让收敛减速。
- RMSProp:Adagrad是考虑前面所有的梯度对后面造成的影响,RMSProp,更注重的是前一次的梯度影响,类似于momentum。但后期容易在小范围内产生震荡,原因是可能会导致分母过小。
- Adam = RMSProp + momentum
(6)数据集怎么划分的?
我们通常将总数居分成三份:训练集,验证集,测试集。我们分别用不同的网络对training set进行训练,在验证集上选出最优秀的那一个,那样的话就比较科学。
当遇到数据集不够的时候可以使用K折交叉验证。
可参考:
【1】https://www.jianshu.com/p/2155e59d14a4
【2】https://www.jianshu.com/p/26b57b25c56d
(三)卷积神经网络 CNN
卷积神经网络主要处理的是图片相关的问题,例如图片分类,如图片分割等。最大的特点是,将权重变成了卷积核这样的形式。卷积核 == 权重矩阵。
可以将其看作是一种特殊的全连接层的网络。其原理是利用一个个的卷积核扫描去探测图片中的重要特征信息。卷积核的个数决定了该层输出的通道数。
(1)通常将卷积核设置成3*3,足够吗?
虽然一个33的卷积核看起来很小,但是当网络变深的时候,33的区域可能映射到前面的区域是很大的。例如,第一层的时候我们确实检测的范围是3x3,但是在第二个卷积层中,其实3x3的格子在原来的图片中对应的是5x5。
(2)CNN无法很好的解决缩放旋转,裁剪等问题。
可以通过增加一层:special transformer layer
通过矩阵乘法,将图片旋转,缩放,平移。但是有一个缺点是无法进行梯度下降。
(3)常见的CNN模型
VGG、GoogLeNet、ResNet、ResNet各种变种、DenseNet等
GoogLeNet文章中提出优化模型有两种途径:提高深度或是宽度。但是这两种方法都存在局限性:1.参数太多,容易过拟合,若训练数据集有限;2.网络越大计算复杂度越大,难以应用;3.网络越深,梯度越往后穿越容易消失,难以优化模型。
GoogLeNet正是围绕着这两个思路提出的,其通过构建密集的块结构——Inception(如下图)来近似最优的稀疏结构,从而达到提高性能而又不大量增加计算量的目的。
ResNet解决模型深,易造成梯度消失,继续训练时,很难再更新参数,很难学到特征
可参考:
【1】https://blog.csdn.net/lianghe77/article/details/104486543
【2】https://blog.csdn.net/wangzi11111111/article/details/88945699
(四)注意力机制(self-attention)
注意力机制主要解决的是多输入的问题,例如句子的翻译,每个句子的长度并不是固定的,那么该怎么样操作使得神经网络能够接收,序列信息。
(1)输入数目和输出数目相同(N to N)
我们认为序列内部是有相关性的,例如I LOVE YOU。主语和谓语之间是有联系的。再比如说,30号上午,北京到天津的航班。这里面的地面也是有联系的。所以主要问题变成了,如何确定这种相关系数?
注意力机制提出了三个注意力的系数:q、k、v
I: input, O:ouput, Q={q1,q2,...qn}, K={k1,k2...kn}, V={v1,v2...vn}
进阶版的注意力机制:multi-head self-attention,多head,就是用多个wq矩阵wk,wv矩阵。理解一下就是说,有不同的关系和理解。
在语音辨识中可能一句语音非常长,如使用self-attention的话输入就会及其大,我们或许不需要看到很远的距离,我们只系要看临近之间的关系。
self-attention 和CNN的关系:
- CNN是简单版的自注意力机制
可参考:
【1】https://www.csdn.net/tags/NtTacgxsMTAxODMtYmxvZwO0O0OO0O0O.html
自注意力机制和RNN的比较:
自注意力机制还可以用在图神经网络中:
(五)RNN 循环神经网络
解决的也是输入输出不确定的应用场景。与self-attention不同,他不是一次性输出N个结果,而是每次输入一个x,输出一个y。
有一个中间结果会被保存下来,一起作为下一层的输入。
演化出了Elman NN和Jordan NN,其不同点仅在于a的取值。其他结构基本没有变化。还有一种双向的RNN叫做:Bidirectional RNN,他设计了正反两个神经网络,共同输出一个结果。其解释为,能够将整个序列了解的更好。
(1)LSTM (long short-term memory)长短期记忆网络
这个网络是一种特殊的RNN。不难发现RNN希望神经网络能够记住一些内容,但是根据RNN网络结构可以发现,它只对上一个输入有考虑。而且关于存储逻辑设计的不是很合理。LSTM重新设计了关于memory的设计。
LSTM设计了三个门来控制,存储单元的存储与否以及怎么样存储,将这三个们封装成一个special Neuron, 已拥有四个输入和一个输出。下面是他的结构:
他的核心结构是长这样的,其具体是怎么运行的呢?
每一个输入不仅是考虑x,还会考虑记忆和上一个单词的输出。也可以堆叠出多层的LSTM神经网络。
可参考:
【1】https://www.freesion.com/article/68911223173/
(六)transformer 变形金刚
依然致力于解决seq to seq的问题。多用于文本和自然语言的处理。例如语音翻译,多label分类,目标检测等
transformer的整体结构可分为encoder 和 decoder两个部分,这两个部分都是前面所说的self-attention机制的一个堆叠。
(1)encoder
inputs输入过后有一个positional encoding,就是为了确保位置信息。然后输入到多head的自注意力机制里面,与上面说到的self-attention不同,他多了一个Feed Forward,是一个两层的全连接,第一层的激活函数为ReLU,第二层不适用激活函数。
还有一个区别是多了一个add&norm
,这是类似于ResNet的一个残差的设计。
(2)decoder
decoder的输入与以往的神经网络不一样,他不是一次性将答案输给他,而是第一次输入START,机器预测出“机”。然后把预测出来的“S+机”作为输入,预测出下一个字“器”一直这样执行下去。但是我们也不难看出缺点,有可能就会一步错,步步错。
Masked Multi-Head Attention的结构和Multi-Head Attention的结构是一样的,只是输入时被掩盖的数据。
Encoder 的 Multi-Head Attention 的结构和 Decoder 的 Multi-Head Attention 的结构也是一样的,只是 Decoder 的 Multi-Head Attention 的输入来自两部分,K,V 矩阵来自Encoder的输出,Q 矩阵来自 Masked Multi-Head Attention 的输出。
可参考:
【1】https://blog.csdn.net/qq_48314528/article/details/122160800
【2】https://www.jianshu.com/p/6ced23376003
【3】https://zhuanlan.zhihu.com/p/403433120
李宏毅老师还介绍了很多transformer的变种,那就已经听不懂了。
(3)各式各样的attention
前面说过self-attention会将序列长度为N 的输入输出为一个N*N的矩阵。但是我们的输入极有可能是一个非常非常长的向量,这样的话,这个输出的矩阵将会是非常大的,如果在用多个head的话,那计算量又将翻倍。这里讲述了一些方法加速训练。
第一种方式:Local Attention / Truncated Attention / Global Attention。就是说,可能我并不需要看到整个句子之间的关系,我可以选择性的去跳过一些计算点。或者说,不同的head,我们关注的点有不一样。
第二种方法叫做:Clustering(分类归并)。先把sequence的原始向量们计算出的query和key拿出来, 进行聚类, 把比较近的分类在一起, 比较远的则分别属于不同的clustering.然后在计算attention matrix的时候, 只有在query和key被归类到同一个clustering种类里才会去计算他们的attention, 否则直接设置为0.这样就可以加快attention matrix的计算.
但是即使是clustering也是基于人类的理解来判断的.
第三种:利用线性代数的方法,加速运算。
计算结果一样,计算量不一样。
可参考:
【1】https://blog.csdn.net/q1347688324/article/details/123778585