目录
引言
1.2机器学习中的关键组件
1.3.1监督学习
2.预备知识
2.1数据操作
2.1.3.广播机制
2.1.4. 索引和切片
2.1.5. 节省内存
2.1.6. 转换为其他Python对象
2.2. 数据预处理
2.2.1. 读取数据集
2.2.2. 处理缺失值
2.2.3. 转换为张量格式
2.3. 线性代数
2.3.2. 向量
2.3.5. 张量算法的基本性质
2.3.6. 降维
3.线性神经网络
4.多层感知机
4.1多层感知机
4.1.1隐藏层
4.1.2激活函数
4.1.2.1ReLU函数
4.1.2.2. sigmoid函数
4.1.2.3. tanh函数
4.2. 多层感知机的从零开始实现
4.4. 模型选择、欠拟合和过拟合
4.4.1. 训练误差和泛化误差
4.4.2. 模型选择
4.4.3. 欠拟合还是过拟合?
4.5. 权重衰减
4.6. 暂退法(Dropout)
4.8. 数值稳定性和模型初始化
5. 深度学习计算
5.1. 层和块
5.2.参数管理
5.5. 读写文件
可以用来学习的数据(data);
如何转换数据的模型(model);
一个目标函数(objective function),用来量化模型的有效性;(比如损失函数)
调整模型参数以优化目标函数的算法(algorithm)。(如梯度下降)
首先,我们介绍n维数组,也称为张量(tensor)。 无论使用哪个深度学习框架,它的张量类(在MXNet中为ndarray, 在PyTorch和TensorFlow中为tensor)都与Numpy的ndarray类似。 但深度学习框架又比Numpy的ndarray多一些重要功能: 首先,GPU很好地支持加速计算,而NumPy仅支持CPU计算; 其次,张量类支持自动微分。 这些功能使得张量类更适合深度学习。
张量表示一个由数值组成的数组,这个数组可能有多个维度。 具有一个轴的张量对应数学上的向量(vector); 具有两个轴的张量对应数学上的矩阵(matrix); 具有两个轴以上的张量没有特殊的数学名称。
在某些情况下,即使形状不同,我们仍然可以通过调用 广播机制(broadcasting mechanism)来执行按元素操作。 这种机制的工作方式如下:
通过适当复制元素来扩展一个或两个数组,以便在转换之后,两个张量具有相同的形状;
对生成的数组执行按元素操作。
与任何Python数组一样:第一个元素的索引是0,最后一个元素索引是-1; 可以指定范围以包含第一个元素和最后一个之前的元素。
在一个轴的张量中,可以用[-1]选择最后一个元素,可以用[1,3]选择第二个和第三个元素。
两个轴的张量中访问元素:
①一个元素:[1,2]
②一行:[1,:]
③一列:[:,1]
④子区域:[1:3,1:] #第1到2行,第1到最后1列
⑤子区域:[::3,::2] #从第0行开始,每3行一跳,从第0列开始,每2列一跳。
可以使用X[:] = X + Y 或X += Y来减少操作的内存开销。
使用pandas预处理原始数据,并将原始数据转换为张量格式的步骤。
首先我们来创建一个人工数据集并存储到指定目录下的CSV文件。(CSV文件即为每一行为一个数据每一个列为一个特征:逗号分隔值)
要从创建的CSV文件中加载原始数据集,我们导入pandas包并调用read_csv函数。
NAN,(Not a Number),NAN项代表缺失值。为了处理缺失的数据,典型的方法包括插值法和删除法, 其中插值法用一个替代值弥补缺失值,而删除法则直接忽略缺失值。
由于“巷子类型”(“Alley”)列只接受两种类型的类别值“Pave”和“NaN”, pandas
可以自动将此列转换为两列“Alley_Pave”和“Alley_nan”。 巷子类型为“Pave”的行会将“Alley_Pave”的值设置为1,“Alley_nan”的值设置为0。 缺少巷子类型的行会将“Alley_Pave”和“Alley_nan”分别设置为0和1。
现在inputs和outputs中的所有条目都是数值类型,它们可以转换为张量格式。
列向量是向量的默认方向。
向量的长度通常称为向量的维度(dimension)。
向量或轴的维度被用来表示向量或轴的长度,即向量或轴的元素数量。 然而,张量的维度用来表示张量具有的轴数。
两个矩阵的按元素乘法称为Hadamard积(Hadamard product)。(A*B)
.sum() , .mean()函数可降维。
非降维求和:
有时在调用函数来计算总和或均值时保持轴数不变会很有用。
保持轴数不变之后,可以利用广播机制。
目标,或许是深度学习算法最重要的组成部分(除了数据),通常被表达为范数。
矩阵求导看收藏笔记
自动微分(automatic differentiation)来加快求导。 实际中,根据设计好的模型,系统会构建一个计算图(computational graph), 来跟踪计算是哪些数据通过哪些操作组合起来产生输出。 自动微分使系统能够随后反向传播梯度。 这里,反向传播(backpropagate)意味着跟踪整个计算图,填充关于每个参数的偏导数。
假设自变量x和因变量y之间的关系是线性的, 即y可以表示为x中元素的加权和,这里通常允许包含观测值的一些噪声。
给定一个数据集,我们的目标是寻找模型的权重w和偏置b,在开始寻找最好的模型参数(model parameters)w和b之前, 我们还需要两个东西:
(1)一种模型质量的度量方式; (2)一种能够更新模型以提高模型预测质量的方法。
在我们开始考虑如何用模型拟合(fit)数据之前,我们需要确定一个拟合程度的度量。 损失函数(loss function)能够量化目标的实际值与预测值之间的差距。
在损失平面上只有一个临界点,这个临界点对应于整个区域的损失极小点。 将损失关于w的导数设为0,得到解析解。但并不是所有的问题都存在解析解。 解析解可以进行很好的数学分析,但解析解对问题的限制很严格,导致它无法广泛应用在深度学习里。
即使在我们无法得到解析解的情况下,我们仍然可以有效地训练模型。梯度下降(gradient descent)的方法, 这种方法几乎可以优化所有深度学习模型。 它通过不断地在损失函数递减的方向上更新参数来降低误差。
小批量随机梯度下降(minibatch stochastic gradient descent)
|B|表示每个小批量中的样本数,这也称为批量大小(batch size)。 η表示学习率(learning rate)(步长的超参数)。 批量大小和学习率的值通常是手动预先指定,而不是通过模型训练得到的。 这些可以调整但不在训练过程中更新的参数称为超参数(hyperparameter)。
事实上,更难做到的是找到一组参数,这组参数能够在我们从未见过的数据上实现较低的损失, 这一挑战被称为泛化(generalization)。
对于线性回归,每个输入都与每个输出相连, 我们将这种变换称为全连接层(fully-connected layer)或称为稠密层(dense layer)。
通过从均值为0、标准差为0.01的正态分布中采样随机数来初始化权重, 并将偏置初始化为0。
w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
将模型的输入和参数同模型的输出关联起来。 回想一下,要计算线性模型的输出, 我们只需计算输入特征X和模型权重w的矩阵-向量乘法后加上偏置b。
广播机制: 当我们用一个向量加一个标量时,标量会被加到向量的每个分量上。
对于每一个小批量,我们会进行以下步骤:
通过调用net(X)
生成预测并计算损失l
(前向传播)。
通过进行反向传播来计算梯度。
通过调用优化器来更新模型参数。
独热编码(one-hot encoding)。 独热编码是一个向量,它的分量和类别一样多。 类别对应的分量设置为1,其他所有分量设置为0。
softmax函数能够将未规范化的预测变换为非负数并且总和为1,同时让模型保持 可导的性质。 为了完成这一目标,我们首先对每个未规范化的预测求幂,这样可以确保输出非负。 为了确保最终输出的概率值总和为1,我们再让每个求幂后的结果除以它们的总和。
交叉熵损失(cross-entropy loss)
原始数据集中的每个样本都是28×28的图像。 本节将展平每个图像,把它们看作长度为784的向量。 在后面的章节中,我们将讨论能够利用图像空间结构的特征, 但现在我们暂时只把每个像素位置看作一个特征。
在网络中加入一个或多个隐藏层来克服线性模型的限制, 使其能处理更普遍的函数关系类型。 要做到这一点,最简单的方法是将许多全连接层堆叠在一起。 我们可以把前L−1层看作表示,把最后一层看作线性预测器。 这种架构通常称为多层感知机(multilayer perceptron),通常缩写为MLP。
网络产生输出只需要实现隐藏层和输出层的计算。 因此,这个多层感知机中的层数为这两层数之和。 注意,这两个层都是全连接的。 每个输入都会影响隐藏层中的每个神经元, 而隐藏层中的每个神经元又会影响输出层中的每个神经元。
隐藏层的大小是超参数(隐藏层数、每层隐藏层的大小)
非线性激活函数:一般来说,有了激活函数,就不可能再将多层感知机退化成线性模型。
使用ReLU的原因是,它求导表现得特别好:要么让参数消失,要么让参数通过。 这使得优化表现得更好,并且ReLU减轻了困扰以往神经网络的梯度消失问题(稍后将详细介绍)。
初始化模型参数
激活函数
模型
损失函数
训练
将模型在训练数据上拟合的比在潜在分布中更接近的现象称为过拟合(overfitting), 用于对抗过拟合的技术称为正则化(regularization)。
训练误差(training error)是指, 模型在训练数据集上计算得到的误差。 泛化误差(generalization error)是指, 模型在新数据上的误差。
影响模型泛化的因素。
可调整参数的数量。当可调整参数的数量(有时称为自由度)很大时,模型往往更容易过拟合。
参数采用的值。当权重的取值范围较大时,模型可能更容易过拟合。
训练样本的数量。即使模型很简单,也很容易过拟合只包含一两个样本的数据集。而过拟合一个有数百万个样本的数据集则需要一个极其灵活的模型。
我们决不能依靠测试数据进行模型选择。 然而,我们也不能仅仅依靠训练数据来选择模型,因为我们无法估计训练数据的泛化误差。
K折交叉验证
模型复杂性
数据集大小
权重衰减(weight decay)是最广泛使用的正则化的技术之一, 它通常也被称为L2正则化。
权重衰退是一种常见的处理过拟合(模型复杂度过高)的方法。
要保证权重向量比较小, 最常用方法是将其范数作为惩罚项加到最小化损失的问题中。 将原来的训练目标最小化训练标签上的预测损失, 调整为最小化预测损失和惩罚项之和。
<1,在深度学习中通常叫权重衰退。
暂退法在前向传播过程中,计算每一内部层的同时丢弃一些神经元。暂退法可以避免过拟合,它通常与控制权重向量的维数和大小结合使用的。
将暂退法应用到隐藏层,以p的概率将隐藏单元置为零,在测试时不用暂退法。
矩阵乘法容易带来梯度爆炸和梯度消失的问题。梯度爆炸(gradient exploding)问题: 参数更新过大,破坏了模型的稳定收敛; 要么是梯度消失(gradient vanishing)问题: 参数更新过小,在每次更新时几乎不会移动,导致模型无法学习。
让训练更加稳定,合理的初始化权重和激活函数。Xavier 是一种常见的权重初始化方法。
块(block)可以描述单个层、由多个层组成的组件或整个模型本身。 使用块进行抽象的一个好处是可以将一些块组合成更大的组件, 这一过程通常是递归的。
从编程的角度来看,块由类(class)表示。 它的任何子类都必须定义一个将其输入转换为输出的前向传播函数, 并且必须存储任何必需的参数。 注意,有些块不需要任何参数。 最后,为了计算梯度,块必须具有反向传播函数。 在定义我们自己的块时,由于自动微分提供了一些后端实现,我们只需要考虑前向传播函数和必需的参数。
访问参数,用于调试、诊断和可视化;
参数初始化;
在不同模型组件间共享参数。
save
和load
函数可用于张量对象的文件读写。
我们可以通过参数字典保存和加载网络的全部参数。
空间不变性
1.平移不变性 2.局部性
卷积层对输入和卷积核权重进行互相关运算,并在添加标量偏置之后产生输出。所以,卷积层中的两个被训练的参数是卷积核权重和标量偏置。
在每次迭代中,我们比较Y
与卷积层输出的平方误差,然后计算梯度来更新卷积核。
随着我们应用许多连续卷积层,累积丢失的像素数就多了。 解决这个问题的简单方法即为填充(padding):在输入图像的边界填充元素(通常填充元素是0)。常用来使输出与输入具有相同的高和宽。
有时候为了高效计算或是缩减采样次数,卷积窗口可以跳过中间位置,每次滑动多个元素。我们将每次滑动元素的数量称为步幅(stride)。
当输入包含多个通道时,需要构造一个与输入数据具有相同输入通道数的卷积核。(多个二维)
多输入单输出:每个输入通道都有一个卷积核,结果是所有通道卷积结果的核。
到目前为止,不论有多少输入通道,我们还只有一个输出通道。我们可以有多个三维卷积核,每个核生成一个输出通道。
1×1卷积失去了卷积层的特有能力——在高度和宽度维度上,识别相邻元素间相互作用的能力。 其实1×1卷积的唯一计算发生在通道上。
使用1×1卷积核与3个输入通道和2个输出通道的互相关计算。 这里输入和输出具有相同的高度和宽度,输出中的每个元素都是从输入图像中同一位置的元素的线性组合。 我们可以将1×1卷积层看作在每个像素位置应用的全连接层,以Ci个输入值转换为Co个输出值。
池化(pooling)层,它具有双重目的:降低卷积层对位置的敏感性,同时降低对空间降采样表示的敏感性。
输出通道数与输入通道数相同。
总体来看,LeNet(LeNet-5)由两个部分组成:
卷积编码器:由两个卷积层组成;
全连接层密集块:由三个全连接层组成。
每个卷积块中的基本单元是一个卷积层、一个sigmoid激活函数和平均汇聚层。
AlexNet比相对较小的LeNet5要深得多。AlexNet由八层组成:五个卷积层、两个全连接隐藏层和一个全连接输出层。
AlexNet使用ReLU而不是sigmoid作为其激活函数。
AlexNet通过暂退法控制全连接层的模型复杂度,而LeNet只使用了权重衰减。
经典卷积神经网络的基本组成部分是下面的这个序列:
带填充以保持分辨率的卷积层;
非线性激活函数,如ReLU;
汇聚层,如最大汇聚层
一个VGG块与之类似,由一系列卷积层组成,后面再加上用于空间下采样的最大汇聚层。在最初的VGG论文中 ,作者使用了带有3×3卷积核、填充为1(保持高度和宽度)的卷积层,和带有2×2汇聚窗口、步幅为2(每个块后的分辨率减半)的最大汇聚层。
与AlexNet、LeNet一样,VGG网络可以分为两部分:第一部分主要由卷积层和汇聚层组成,第二部分由全连接层组成。
NiN块以一个普通卷积层开始,后面是两个1×1的卷积层。这两个1×1卷积层充当带有ReLU激活函数的逐像素全连接层。
NiN去除了容易造成过拟合的全连接层,将它们替换为全局平均汇聚层(即在所有位置上进行求和)。该汇聚层通道数量为所需的输出数量(例如,Fashion-MNIST的输出为10)。
移除全连接层可减少过拟合,同时显著减少NiN的参数。
Inception块由四条并行路径组成。 前三条路径使用窗口大小为1×1、3×3和5×5的卷积层,从不同空间大小中提取信息。 中间的两条路径在输入上执行1×1卷积,以减少通道数,从而降低模型的复杂性。 第四条路径使用3×3最大汇聚层,然后使用1×1卷积层来改变通道数。
这四条路径都使用合适的填充来使输入与输出的高和宽一致,最后我们将每条线路的输出在通道维度上连结,并构成Inception块的输出。在Inception块中,通常调整的超参数是每层输出通道数。
批量规范化应用于单个可选层(也可以应用到所有层),其原理如下:在每次训练迭代中,我们首先规范化输入,即通过减去其均值并除以其标准差,其中两者均基于当前小批量处理。 接下来,我们应用比例系数和比例偏移。 正是由于这个基于批量统计的标准化,才有了批量规范化的名称。
它可能通过在每个小批量里加入噪音来控制模型复杂度。因此没必要和丢弃法混合使用。
可以加速收敛速度。
对于全连接层,我们将批量规范化层置于全连接层中的仿射变换和激活函数之间。
对于卷积层,我们可以在卷积层之后和非线性激活函数之前应用批量规范化。
残差网络的核心思想是:每个附加层都应该更容易地包含原始函数作为其元素之一。
卷积、全连接、池化层都只考虑不刻意线索。
注意力机制则显示的考虑刻意线索。
在注意力机制的背景下,刻意线索被称为查询(query);
每个输入是一个值value和不刻意线索query的对。
给定任何查询,注意力机制通过注意力汇聚(attention pooling) 将选择引导至感官输入(sensory inputs,例如中间特征表示)。 在注意力机制中,这些感官输入被称为值(value)。 更通俗的解释,每个值都与一个键(key)配对, 这可以想象为感官输入的非自主提示。
非参数注意力汇聚
参数注意力汇聚(批量矩阵乘法)
加性注意力
缩放点积注意力
多GPU并行,常用切分方案为数据并行。
两种可以改进模型泛化的方法,即图像增广和微调,并将它们应用于图像分类。
可以以不同的方式裁剪图像,使感兴趣的对象出现在不同的位置,减少模型对于对象出现位置的依赖。 我们还可以调整亮度、颜色等因素来降低模型对颜色的敏感度。
应用迁移学习(transfer learning)将从源数据集学到的知识迁移到目标数据集。
微调包括以下四个步骤:
预训练神经网络模型。
创建一个新的神经网络模型,即目标模型。这将复制源模型上的所有模型设计及其参数(输出层除外)。我们还假设源模型的输出层与源数据集的标签密切相关;因此不在目标模型中使用该层。
向目标模型添加输出层,其输出数是目标数据集中的类别数。然后随机初始化该层的模型参数。
在目标数据集(如椅子数据集)上训练目标模型。输出层将从头开始进行训练,而所有其他层的参数将根据源模型的参数进行微调。
很多时候图像里有多个我们感兴趣的目标,我们不仅想知道它们的类别,还想得到它们在图像中的具体位置。