动手学深度学习

Posted Coding With you.....

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动手学深度学习相关的知识,希望对你有一定的参考价值。

一预备知识(书中是MXNet中的NDArray类,电子中用的是Pytorch版)

1.Tensor

创建long型3*3的全为0的Tensor:import torch;x = torch.zeros(3, 3, dtype=torch.long)

view()可以改变Tensor的形状,eg:view(-1,4)可以将16变为4*4维度的。但这是共享数据的,reshape()是可以改变形状并且不共享数据的,但是此函数并不能保证返回的是其拷贝,所以不推荐使用。推荐先用clone创造一个副本然后再使用view。所以如果需要复制,请使用clone();如果需要相同的存储,请使用view()。reshape()的语义是它可能共享或可能不共享存储,并且您事先不知道。

2.广播机制

对于两个形状不同的Tensor做运算时,会触发广播机制:先将两个Tensor进行简单的复制使得Tensor形状相同,再进行运算。

3.Tensor和Numpy转换:使用numpy()Tensor转换成NumPy数组;使用from_numpy()将NumPy数组转换成Tensor,直接用torch.tensor()也可以。

4.自动求梯度:将Tensor的属性.requires_grad设置为True,通过链式法则调用.backward进行求梯度

二深度学习基础

1线性回归

线性回归输出是一个连续值,因此适用于回归问题。回归问题在实际中很常见,如预测房屋价格、气温、销售额等连续值的问题。与回归问题不同,分类问题中模型的最终输出是一个离散值。我们所说的图像分类、垃圾邮件识别、疾病检测等输出为离散值的问题都属于分类问题的范畴。softmax回归则适用于分类问题。

定义模型---模型训练(读取数据,损失函数计算误差,优化算法有限次迭代模型参数来尽可能降低损失函数的值)----模型预测(模型训练完成后,将训练好的模型参数保存,可以用来预测)

实现:输入个数---特征数,特征有几个就输入几个。

           torch.mm(X, w)等价于NDArray中nd.dot(X, w);

          模型训练中,由于pytorch的动态计算图,当我们使用loss.backward()和opimizer.step()进行梯度下降更新参数的时候,梯度并不会自动清零。所以每次获取1个batch的数据,计算1次梯度,然后梯度零,避免了梯度累加。

softmax更适合离散值的回归;同线性回归一样,也是一个单层神经网络。

既然分类问题需要得到离散的预测输出,一个简单的办法是将输出值oi当作预测类别是iii的置信度,并将值最大的输出所对应的类作为预测输出,即输出 argmaxioi\\underset{i}{\\arg\\max} o_iiargmax​oi​。例如,如果o1​,o2​,o3​分别为0.1,10,0.1,由于o2​最大,那么预测类别为2,其代表猫。

softmax是将所有类型的概率之和为1,概率最大的那一个为所属类别。result=softmax(w*x+b).

交叉熵能够衡量同一个随机变量中的两个不同概率分布的差异程度,最小化交叉熵损失函数等价于最大化训练数据集所有标签类别的联合预测概率。

 import d2lzh_pytorch as d2l

多层感知机:在单层神经网络的基础上引入了隐藏层,每个隐藏层的输出通过激活函数进行变换。多层感知机中的隐藏层和输出层都是全连接层。

                 激活函数:引入非线性变换,比如ReLU(rectified linear unit)函数提供了一个很简单的非线性变换;sigmoid函数可以将元素的值变换到0和1之间;tanh(双曲正切)函数可以将元素的值变换到-1和1之间;

训练误差(training error)和泛化误差(generalization error)。通俗来讲,前者指模型在训练数据集上表现出的误差,后者指模型在任意一个测试数据样本上表现出的误差的期望,并常常通过测试数据集上的误差来近似。

验证集:可以从给定的训练集中随机选取一小部分作为验证集,而将剩余部分作为真正的训练集,来进行模型选择。

过拟合与欠拟合:一类是模型无法得到较低的训练误差,模型的训练误差远小于它在测试数据集上的误差。影响因素有模型复杂度和训练数据集大小等。【如果模型的复杂度过低,很容易出现欠拟合;如果模型复杂度过高,很容易出现过拟合。应对欠拟合和过拟合的一个办法是针对数据集选择合适复杂度的模型;如果训练数据集中样本数过少,特别是比模型参数数量(按元素计)更少时,过拟合更容易发生。】

k折交叉验证:把原始训练数据集分割成K个不重合的子数据集,然后做K次模型训练和验证。每一次使用一个子数据集验证模型,并使用其他K−1个子数据集来训练模型。在这K次训练和验证中,每次用来验证模型的子数据集都不同。最后对这K次训练误差和验证误差分别求平均。

权重衰减等价于 L2范数正则化(regularization)。正则化通过为模型损失函数添加惩罚项使学出的模型参数值较小,是应对过拟合的常用手段。

深度学习模型常常使用丢弃法(dropout)来应对过拟合问题:给定一个概率,概率这部分变为0,1-概率部分变为原来2倍。

举个例子,假设输入和所有层的权重参数都是标量,如权重参数为0.2和5,多层感知机的第30层输出为输入X分别与0.2^30(衰减)和5^30(爆炸)的乘积。类似地,当层数较多时,梯度的计算也更容易出现衰减或爆炸。通常需要随机初始化神经网络的模型参数,如权重参数。

三深度学习计算

1.

四卷积神经网络

1.通常在卷积层中使用更加直观的互相关(cross-correlation)运算。在二维卷积层中,一个二维输入数组和一个二维核(kernel)数组通过互相关运算输出一个二维数组。

    互相关:从左到右,从上到下;卷积:从右至左,从下至上

2.池化(pooling)层,它的提出是为了缓解卷积层对位置的过度敏感性

池化层直接计算池化窗口内元素的最大值或者平均值。该运算也分别叫做最大池化或平均池化。

3.LeNet展示了通过梯度下降训练卷积神经网络可以达到手写数字识别在当时最先进的结果。LeNet分为卷积层块和全连接层块两个部分。

4.AlexNet跟LeNet结构类似,但使用了更多的卷积层和更大的参数空间来拟合大规模数据集ImageNet。它是浅层神经网络和深度神经网络的分界线。

5.VGG提出了可以通过重复使用简单的基础块来构建深度模型的思路。与AlexNet和LeNet一样,VGG网络由卷积层模块后接全连接层模块构成。卷积层模块串联数个vgg_block,其超参数由变量conv_arch定义。该变量指定了每个VGG块里卷积层个数和输入输出通道数。全连接模块则跟AlexNet中的一样。VGG块的组成规律是:连续使用数个相同的填充为1、窗口形状为3×33\\times 33×3的卷积层后接上一个步幅为2、窗口形状为2×22\\times 22×2的最大池化层。卷积层保持输入的高和宽不变,而池化层则对其减半。我们使用vgg_block函数来实现这个基础的VGG块,它可以指定卷积层的数量和输入输出通道数。

 

LeNet、AlexNet和VGG在设计上的共同之处是:先以由卷积层构成的模块充分抽取空间特征,再以由全连接层构成的模块来输出分类结果。其中,AlexNet和VGG对LeNet的改进主要在于如何对这两个模块加宽(增加通道数)和加深。

6.NiN使用卷积窗口形状分别为11×1111\\times 1111×11、5×55\\times 55×5和3×33\\times 33×3的卷积层,相应的输出通道数也与AlexNet中的一致。每个NiN块后接一个步幅为2、窗口形状为3×33\\times 33×3的最大池化层。除使用NiN块以外,NiN还有一个设计与AlexNet显著不同:NiN去掉了AlexNet最后的3个全连接层,取而代之地,NiN使用了输出通道数等于标签类别数的NiN块,然后使用全局平均池化层对每个通道中所有元素求平均并直接用于分类。这里的全局平均池化层即窗口形状等于输入空间维形状的平均池化层。NiN的这个设计的好处是可以显著减小模型参数尺寸,从而缓解过拟合。然而,该设计有时会造成获得有效模型的训练时间的增加。

  • NiN重复使用由卷积层和代替全连接层的1×11\\times 11×1卷积层构成的NiN块来构建深层网络。
  • NiN去除了容易造成过拟合的全连接输出层,而是将其替换成输出通道数等于标签类别数的NiN块和全局平均池化层。
  • NiN的以上设计思想影响了后面一系列卷积神经网络的设计。

7.GoogLeNet的网络结构

GoogLeNet中的基础卷积块叫作Inception块,Inception块里有4条并行的线路。前3条线路使用窗口大小分别是1×11\\times 11×1、3×33\\times 33×3和5×55\\times 55×5的卷积层来抽取不同空间尺寸下的信息,其中中间2个线路会对输入先做1×11\\times 11×1卷积来减少输入通道数,以降低模型复杂度。第四条线路则使用3×33\\times 33×3最大池化层,后接1×11\\times 11×1卷积层来改变通道数。4条线路都使用了合适的填充来使输入与输出的高和宽一致。最后我们将每条线路的输出在通道维上连结,并输入接下来的层中去。

Inception块中可以自定义的超参数是每个层的输出通道数,我们以此来控制模型复杂度。

8.批量归一化层置于全连接层中的仿射变换和激活函数之间。对卷积层来说,批量归一化发生在卷积计算之后、应用激活函数之前。如果卷积计算输出多个通道,我们需要对这些通道的输出分别做批量归一化,且每个通道都拥有独立的拉伸和偏移参数,并均为标量

9.ResNet的前两层跟之前介绍的GoogLeNet中的一样:在输出通道数为64、步幅为2的7×77\\times 77×7卷积层后接步幅为2的3×33\\times 33×3的最大池化层。不同之处在于ResNet每个卷积层后增加的批量归一化层。

10.DenseNet的主要构建模块是稠密块(dense block)和过渡层(transition layer)。前者定义了输入和输出是如何连结的,后者则用来控制通道数,使之不过大。

五循环神经网络

1.循环神经网络

  • 使用循环计算的网络即循环神经网络。
  • 循环神经网络的隐藏状态可以捕捉截至当前时间步的序列的历史信息。
  • 循环神经网络模型参数的数量不随时间步的增加而增长。
  • 可以基于字符级循环神经网络来创建语言模型。

2.时序数据采样:随机采样:每个样本是原始序列上随机截取的一段序列

                            相邻采样:可以用一个小批量最终时间步的隐藏状态来初始化下一个小批量的隐藏状态,从而使下一个小批量的输出也取决于当前小批量的输入,并如此循环下去。

3.循环神经网络中较容易出现梯度衰减或梯度爆炸。我们会在6.6节(通过时间反向传播)中解释原因。为了应对梯度爆炸,我们可以裁剪梯度(clip gradient)。

4.通常使用困惑度(perplexity)来评价语言模型的好坏。

  • 最佳情况下,模型总是把标签类别的概率预测为1,此时困惑度为1;
  • 最坏情况下,模型总是把标签类别的概率预测为0,此时困惑度为正无穷;
  • 基线情况下,模型总是预测所有类别的概率都相同,此时困惑度为类别个数。

5.门控循环单元(gated recurrent unit,GRU)是一种常用的门控循环神经网络。它引入了重置门(reset gate)和更新门(update gate)的概念,从而修改了循环神经网络中隐藏状态的计算方式。

作总结:

  • 门控循环神经网络可以更好地捕捉时间序列中时间步距离较大的依赖关系。
  • 门控循环单元引入了门的概念,从而修改了循环神经网络中隐藏状态的计算方式。它包括重置门、更新门、候选隐藏状态和隐藏状态。
  • 重置门有助于捕捉时间序列里短期的依赖关系。
  • 更新门有助于捕捉时间序列里长期的依赖关系。

6.LSTM 中引入了3个门,即输入门(input gate)、遗忘门(forget gate)和输出门(output gate),以及与隐藏状态形状相同的记忆细胞(某些文献把记忆细胞当成一种特殊的隐藏状态),从而记录额外的信息。---------------------记住需要长时间记忆的,忘记不重要的信息

  • 长短期记忆的隐藏层输出包括隐藏状态和记忆细胞。只有隐藏状态会传递到输出层。
  • 长短期记忆的输入门、遗忘门和输出门可以控制信息的流动。
  • 长短期记忆可以应对循环神经网络中的梯度衰减问题,并更好地捕捉时间序列中时间步距离较大的依赖关系。

同一个门控 就同时可以进行遗忘和选择记忆(LSTM则要使用多个门控)

GRU输入输出的结构与普通的RNN相似,其中的内部思想与LSTM相似。与LSTM相比,GRU内部少了一个”门控“,参数比LSTM少,但是却也能够达到与LSTM相当的功能。考虑到硬件的计算能力时间成本,因而很多时候我们也就会选择更加”实用“的GRU。

7.一个有隐藏层的深度循环神经网络,每个隐藏状态不断传递至当前层的下一时间步和当前时间步的下一层。

同多层感知机一样,隐藏层个数LLL和隐藏单元个数hhh都是超参数。此外,如果将隐藏状态的计算换成门控循环单元或者长短期记忆的计算,我们可以得到深度门控循环神经网络。

8.之前介绍的循环神经网络模型都是假设当前时间步是由前面的较早时间步的序列决定的,因此它们都将信息通过隐藏状态从前往后传递。有时候,当前时间步也可能由后面时间步决定。例如,当我们写下一个句子时,可能会根据句子后面的词来修改句子前面的用词。双向循环神经网络通过增加从后往前传递信息的隐藏层来更灵活地处理这类信息。

 

双向循环神经网络在每个时间步的隐藏状态同时取决于该时间步之前和之后的子序列(包括当前时间步的输入)。

 

六优化算法

1.命令式编程和符号式编程(命令式是直接运行,符号式是先不定义然后用的时候通过compile()来运行)

  • 命令式编程更方便。当我们在Python里使用命令式编程时,大部分代码编写起来都很直观。同时,命令式编程更容易调试。这是因为我们可以很方便地获取并打印所有的中间变量值,或者使用Python的调试工具。

  • 符号式编程更高效并更容易移植。一方面,在编译的时候系统容易做更多优化;另一方面,符号式编程可以将程序变成一个与Python无关的格式,从而可以使程序在非Python环境下运行,以避开Python解释器的性能问题。

七计算机视觉

1.图像增广(image augmentation)技术通过对训练图像做一系列随机改变,来产生相似但又不同的训练样本,从而扩大训练数据集的规模。

  • 图像增广基于现有训练数据生成随机图像从而应对过拟合。
  • 为了在预测时得到确定的结果,通常只将图像增广应用在训练样本上,而不在预测时使用含随机操作的图像增广。

 

 

 

 

线性回归和平方损失函数的房价预测;循环神经网络进行歌词创作

以上是关于动手学深度学习的主要内容,如果未能解决你的问题,请参考以下文章

小白学习之pytorch框架-动手学深度学习(begin)

BERT预训练 动手学深度学习v2

PyTorch版《动手学深度学习》开源了,最美DL书遇上最赞DL框架

分享《动手学深度学习(李沐等著)》PDF+源代码+《神经网络与深度学习(吴岸城)著》PDF

《动手学深度学习》(PyTorch版)

动手学深度学习:人工智能机器学习深度学习领域重磅教程图书