用手机怎样制作网站,衡阳网站优化外包价格,中国建设人才专业服务网,美食门户类网站模版一 多层感知机
最简单的深度网络称为多层感知机。多层感知机由 多层神经元 组成#xff0c;每一层与它的上一层相连#xff0c;从中接收输入#xff1b;同时每一层也与它的下一层相连#xff0c;影响当前层的神经元。
softmax 实现了 如何处理数据#xff0c;如何将 输出…一 多层感知机
最简单的深度网络称为多层感知机。多层感知机由 多层神经元 组成每一层与它的上一层相连从中接收输入同时每一层也与它的下一层相连影响当前层的神经元。
softmax 实现了 如何处理数据如何将 输出转换为有效的概率分布并应用适当的 损失函数根据 模型参数最小化损失。
线性意味着单调假设任何特征的增大都会导致模型输出的增大如果对应的权重为正或者导致模 型输出的减小如果对应的权重为负。
在网络中加入隐藏层我们可以通过 在网络中加入一个或多个隐藏层来克服线性模型的限制使其能处理更普遍的函数关系类型。 要做到这一点最简单的方法是 将许多全连接层堆叠在一起。每一层都输出到上面的层直到生成最后的输出。我们可以把前L−1层看作表示把最后一层看作线性预测器。这种架构通常称为多层感知机multilayer perceptron通常缩写为 MLP。下面我们以图的方式描述了多层感知机。
下面是一个单隐藏层的多层感知机具有5个隐藏单元 这个多层感知机有4个输入3个输出其隐藏层包含5个隐藏单元。输入层不涉及任何计算因此使用此网络 产生输出 只需要实现隐藏层和输出层的计算。因此这个多层感知机中的 层数为2。注意这两个层都是全连 接的。每个输入都会影响隐藏层中的每个神经元而隐藏层中的每个神经元又会影响输出层中的每个神经元。
线性模型公式 不加激活函数参数可能会组到一起 加上激活函数 σ 后公式 为了发挥多层架构的潜力我们还需要一个额外的关键要素在仿射变换之后对每个隐藏单元应用非线性的 激活函数activation functionσ。激活函数的输出例如σ(·)被称为活性值activations。一般来说 有了激活函数就不可能再将我们的多层感知机退化成线性模型。 由于X中的每一行对应于小批量中的一个样本出于记号习惯的考量我们定义非线性函数σ也以按行的方 式作用于其输入即一次计算一个样本。
但是 应用于隐藏层的激活函数通常不仅按行操作也按元素操作。这意味着在计算每一层的线性部分之 后我们可以 计算每个活性值而不需要查看其他隐藏单元所取的值。对于大多数激活函数都是这样。 为了构建更通用的多层感知机我们可以继续堆叠这样的隐藏层一层叠一层从而产生更有表达能力的模型。
而且虽然一个单隐层网络能学习任何函数但并不意味着我们应该尝试使用单隐藏层网络来解决所有问题。 事实上通过 使用更深而不是更广的网络我们可以更容易地逼近许多函数。 二 激活函数
激活函数activation function通过 计算加权和 并 加上偏置 来确定神经元是否应该被激活它们将输入信号 转换为输出的可微运算。大多数激活函数都是非线性的。
%matplotlib inline
import torch
from d2l import torch as d2l
2.1 ReLU函数
最受欢迎的激活函数是修正线性单元Rectified linear unitReLU因为它实现简单同时在各种预测任务 中表现良好。ReLU提供了一种非常简单的非线性变换。给定元素xReLU函数被定义为该元素与0的最大值ReLU函数通过将相应的活性值设为0仅保留正元素并丢弃所有负元素。 x torch.arange(-8.0, 8.0, 1, requires_gradTrue)
print(x)
y torch.relu(x)
d2l.plot(x.detach(), y.detach(), x, relu(x), figsize(5, 2.5))# tensor([-8., -7., -6., -5., -4., -3., -2., -1., 0., 1., 2., 3., 4., 5.,
# 6., 7.], requires_gradTrue) 当输入为负时ReLU函数的导数为0而当输入为正时ReLU函数的导数为1。注意当输入值精确等于0时 ReLU函数不可导。在此时我们默认使用左侧的导数即当输入为0时导数为0。
2.1.1 反向传播后查看X的梯度
y.backward(torch.ones_like(x), retain_graphTrue)
d2l.plot(x.detach(), x.grad, x, grad of relu, figsize(5, 2.5)) 使用ReLU的原因是它求导表现得特别好要么让参数消失要么让参数通过。这使得优化表现得更好并 且 ReLU 减轻了困扰以往神经网络的梯度消失问题。 2.2 sigmoid 函数
对于一个定义域在R中的输入sigmoid函数将输入变换为区间(0, 1) 上的输出。 sigmoid函数是一个自然的选择因为它是一个 平滑的、可微 的阈值单元近似。当我们想要将输出视作二元分类问题的概率时sigmoid仍然被广泛用作 输出单元上的激活函数sigmoid可以视为softmax的特例。sigmoid在隐藏层中已经较少使用它在大部分时候被更简单、 更容易训练的ReLU 所取代。
y torch.sigmoid(x)
d2l.plot(x.detach(), y.detach(), x, sigmoid(x), figsize(5, 2.5)) sigmoid函数的导数图像如下所示。注意当输入为0时sigmoid函数的导数达到最大值0.25而输入在任一 方向上越远离0点时导数越接近0。
x.grad.data.zero_()
y.backward(torch.ones_like(x), retain_graphTrue)
d2l.plot(x.detach(), x.grad, x, grad of sigmoid, figsize(5, 2.5)) 2.3 tanh函数
与sigmoid函数类似tanh(双曲正切)函数 也能将其输入压缩转换到区间(‐1, 1)上。 下面我们绘制tanh函数。注意当输入在0附近时tanh函数接近线性变换。函数的形状类似于sigmoid函数 不同的是tanh函数 关于 坐标系原点中心对称。
y torch.tanh(x)
d2l.plot(x.detach(), y.detach(), x, tanh(x), figsize(5, 2.5)) tanh函数的导数图像如下所示。当输入接近0时tanh函数的导数接近最大值1。与我们在sigmoid函数图像 中看到的类似输入在任一方向上越远离0点导数越接近0。 多层感知机在输出层和输入层之间 增加一个或多个全连接隐藏层并 通过激活函数转换隐藏层的输出。常用的激活函数包括 ReLU函数、sigmoid函数和 tanh函数。 三 多层感知机从零开始实现
3.1 导入数据
Fashion‐MNIST中的每个图像由 28 × 28 784个灰度像素值组成。所有图像共分为10个类别。
import torch
from torch import nn
from d2l import torch as d2lbatch_size 256
train_iter, test_iter d2l.load_data_fashion_mnist(batch_size)
len(train_iter), len(test_iter)# (235, 40)
3.2 初始化模型参数
Fashion‐MNIST中的每个图像由 28 × 28 784个灰度像素值组成。所有图像共分为10个类别。忽 略像素之间的空间结构我们可以将每个图像视为具有784个输入特征和10个类的简单分类数据集。首先我 们将实现一个具有单隐藏层的多层感知机它包含256个隐藏单元。注意我们可以将这两个变量都视为超参 数。通常我们选择2的若干次幂作为层的宽度。因为内存在硬件中的分配和寻址方式这么做往往可以在计 算上更高效。
num_inputs, num_outputs, num_hiddens 784, 10, 256W1 nn.Parameter(torch.randn(num_inputs, num_hiddens, requires_gradTrue) * 0.01)
b1 nn.Parameter(torch.zeros(num_hiddens, requires_gradTrue))W2 nn.Parameter(torch.randn(num_hiddens, num_outputs, requires_gradTrue) * 0.01)
b2 nn.Parameter(torch.zeros(num_outputs, requires_gradTrue))params [W1, b1, W2, b2]
params 3.3 激活函数
使用 relu 函数
def relu(x):a torch.zeros_like(x)return torch.max(x, a)
3.4 定义模型
因为我们忽略了空间结构所以我们使用 reshape将每个二维图像转换为一个长度为num_inputs的向量。
def net(x):x x.reshape((-1, num_inputs))h relu(xW1 b1)return (hW2 b2)
3.5 定义损失函数
因此在这里我们直接使用高级API中的内置函数来 计 算softmax和交叉熵损失。
loss nn.CrossEntropyLoss(reductionnone)
3.6 执行训练
num_epochs, lr 10, 0.1
updater torch.optim.SGD(params, lrlr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, updater) 3.7 执行预测
d2l.predict_ch3(net, test_iter) 四 直接调包实现 MLP
与softmax回归的简洁实现 相比唯一的区别是我们 添加了2个全连接层之前我们只添加了1个全 连接层。第一层是隐藏层它包含128个隐藏单元并使用了ReLU激活函数。第二层是输出层。 隐藏层单元个数可以改保证两个全连接层输出和输入的层数要一致
net nn.Sequential(nn.Flatten(),nn.Linear(784, 128),nn.ReLU(),nn.Linear(128, 10))def init_weights(m):if type(m) nn.Linear:nn.init.normal_(m.weight, std0.01)
net.apply(init_weights)# Sequential(
# (0): Flatten(start_dim1, end_dim-1)
# (1): Linear(in_features784, out_features128, biasTrue)
# (2): ReLU()
# (3): Linear(in_features128, out_features10, biasTrue)
# )
batch_size, lr, num_epochs 256, 0.1, 10
loss nn.CrossEntropyLoss(reductionnone)
trainer torch.optim.SGD(net.parameters(), lrlr)
train_iter, test_iter d2l.load_data_fashion_mnist(batch_size)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer) 4.1 模型拟合相关知识
将模型在 训练数据上拟合的比在潜在分布中更接近的现象称为过拟合overfitting用于对抗过拟合的技术 称为 正则化regularization。
我们需要了解训练误差和泛化误差。训练误差training error是指模型在训 练数据集上计算得到的误差。泛化误差generalization error是指模型应用在 同样从原始样本的分布中 抽取的无限多数据样本时模型误差的期望。
为了评估模型将我们的数据分成三份除了训练和测试数据集之外还增加一个 验证数据集val‐ idation dataset也叫验证集validation set。
训练误差和验证误差都很严重但它们之间仅有一点差距。如果模型不能降低训练误差这可能意味着模型过于简单即 表达能力不足无法捕获试图学习的模式。此外由于我们的训练和验证误差之间的泛化误差很小我们有 理由相信可以 用一个更复杂的模型 降低训练误差。这种现象被称为欠拟合underfitting。验证集可以用于模型选择但不能过于随意地使用它。
另一方面当我们的训练误差明显低于验证误差时要小心这表明严重的 过拟合overfitting。最终我们 通常更关心验证误差而不是训练误差和验证误差之间的差距。
另一个重要因素是数据集的大小。训练数据集中的样本越少我们就越有可能过拟合。随着 训练数据量的增加泛化误差通常会减小。
我们应该选择一个复杂度适当的模型避免使用数量不足的训练样本。
我们总是可以通过去收集更多的 训练数据来缓解过拟合。但这可能成本很高耗时颇多或者完全超出我们的控制因而在短期内不可能做 到。假设我们已经拥有尽可能多的高质量数据我们便可以将重点放在 正则化技术 上。 4.2 正则化相关
1 权重衰减weight decay是最广泛使用的正则化的技术之一它通常也被 称为 L2正则化。
2 暂退法在前向传播过程中计算每一内部层的同时注入噪声这已经成为 训练神经网络的常用技术。这种方法之所以被称为暂退法因为我们从表面上看是在训练过程中丢弃drop out一些神经元。在整个训练过程的每一次迭代中标准暂退法包括在计算下一层之前 将当前层中的一些节 点置零。
当我们将暂退法应用到隐藏层以p的概率 将隐藏单元置为零时结果可以看作一个只包含原始神经元子集的网络。比如在 图4.6.1中删除了h2和h5 因此输出的计算不再依赖于h2或h5并且它们各自的梯度在执行反向传播时也会消失。这样输出层的计算 不能过度依赖于h1, . . . , h5的任何一个元素。 暂退法在前向传播过程中计算每一内部层的同时丢弃一些神经元。暂退法可以避免过拟合它通常与控制权重向量的维数和大小结合使用的。•暂退法仅在训练期间使用。 五 前向传播、反向传播和计算图
前向传播forward propagation或forward pass指的是按顺序从输入层到输出层计算和存储神经网 络中每层的结果。 反向传播backward propagation或backpropagation指的是计算神经网络参数梯度的方法。
该方 法根据微积分中的链式规则按相反的顺序从输出层到输入层遍历网络。
在训练神经网络时前向传播和反向传播相互依赖。对于前向传播我们沿着依赖的方向遍历计算图并计算 其路径上的所有变量。然后将这些用于反向传播其中计算顺序与计算图的相反。一方面在前向传播期间计算正则项取决于 模型参数W(1)和 W(2)的当前值。它 们是由优化算法根据最近迭代的反向传播给出的。另一方面反向传播期间参数的梯度计算取决于 由前向传播给出的隐藏变量h的当前值。
因此在训练神经网络时在初始化模型参数后我们交替使用前向传播和反向传播利用反向传播给出的 梯度来更新模型参数。注意反向传播重复利用前向传播中存储的中间值以避免重复计算。带来的影响之 一是我们 需要保留中间值直到反向传播完成。这也是 训练比单纯的预测需要更多的内存显存的原因之 一。此外这些中间值的大小与网络层的数量和批量的大小大致成正比。因此使用更大的批量来训练更深 层次的网络更容易导致内存不足out of memory错误。
前向传播在神经网络定义的计算图中按顺序计算和存储中间变量它的顺序是从输入层到输出层。反向传播按相反的顺序从输出层到输入层计算和存储神经网络的中间变量和参数的梯度。在训练深度学习模型时前向传播和反向传播是相互依赖的。训练比预测需要更多的内存。 5.1 参数初始化
初始化方案的选择在神经网络学习中起着举足轻重的作用它对保持数值稳定性至关重要。此外 这些初始化方案的选择可以与非线性激活函数的选择有趣的结合在一起。我们选择哪个函数以及如何初始化 参数可以决定优化算法收敛的速度有多快。糟糕选择可能会导致我们在训练时遇到梯度爆炸或梯度消失。
神经网络设计中的另一个问题是 其参数化所固有的对称性。
默认初始化我们使用正态分布来初始化权重值。如果我们不指定初始化方法框架将 使用默认的随机初始化方法对于中等难度的问题这种方法通常很有效。
需要用启发式的初始化方法来确保初始梯度既不太大也不太小ReLU激活函数缓解了梯度消失问题这样可以加速收敛。随机初始化是保证在进行优化前打破对称性的关键。
Xavier初始化Xavier初始化从均值为零方差 的高斯分布中采样权重。Xavier初始化表明对于每一层输出的方差不受输入数量的影响任何梯度的方差不受输出数量的影 响。