深度学习—从入门到放弃(二)简单线性神经网络
1.基本结构
就像昨日说的,咱们构建深度学习网络一般适用于数据大,处理难度也大的任务,因而关于网络的结构需要有一个非常深入的了解。这儿以一个分类猫狗的线性神经网络分类器作为比如: 1.方针函数 幻想一下,假如是想要一个能够分类出猫和狗的网络,咱们的终究目的是什么?应该是使用最短的时刻,最好的办法来完成任务。具象的来说就是在崎岖的山上找一条最优的下山途径。在神经网络中就是指最大极限降低丢失函数的途径。
2.学习规矩 能够继续联想刚刚的下山途径,咱们的方针函数是怎么最优下山,而学习规矩则是咱们该怎么下山,换言之也就是咱们怎么经过不断的学习和迭代取得最优途径,最优模型参数。 3.网络架构 什么是神经网络?就好像它的字面意思,是由一层层神经元构成的网络结构,因而咱们怎么规划神经元间的衔接以及网络层数都会对结果产生影响。咱们今天的大标题叫简单线性神经网络,也就是说层和层之间是以线性关系衔接。 4.初始化 又回到咱们的下山问题,下山的方针(方针函数)和怎么下山(学习规矩)都找到了,那么还有一个问题,咱们该从哪里动身,而这就是初始化。起点决议成败,一个好的起点会让咱们节省许多力气。 5.环境 既然是分类问题,那么必定要给咱们的网络一些实例去学习,但关于深度学习网络巨大数据量的需求,咱们又该怎么办呢?假如我说有这么一个开放数据集,里面有成千上万的图片数据,且都是预处理好了的,是不是处理了一大难题!在猫狗分类的问题里咱们选用了IMAGENET里的图片数据。 有了一个基本的认知之后咱们再来引入一个简单线性神经网络,能够看到这个神经网络是多层结构的,每一层都有自己的权重w,而咱们之前所说的“下山”就是找到丢失函数最小的最优参数w,
2.梯度下降
因为大多数学习算法的方针是最小化风险(也称为本钱或丢失)函数,因而优化通常是大多数机器学习算法的核心!梯度下降算法及其变体(例如随机梯度下降)是用于深度学习的最强大和最盛行的优化办法之一。
2.1梯度向量
这儿有关梯度向量大家只需要有这么一个了解就够了:梯度向量总是指向局部丢失函数增大的方向,能够这么了解:下山进程中假如跟着梯度向量的方向走就可能会变成怎么更好攀爬顶峰而不是下山。为了处理这个问题,咱们在之后引入负的梯度向量的概念。
2.2梯度下降算法
这儿就用到了上一节提到的负梯度向量的概念,而这儿的学习率能够了解为咱们下山进程中每迈一步的步长,经过不断的迭代更新(核算丢失函数相关于可学习参数(即权重)的梯度),神经网络中的权重终究回来咱们想要的“下山最优解”
2.3核算图和反向传达
关于梯度下降算法的结构分析后咱们不难发现:随着变量和嵌套函数数量的增加,梯度的推导将变得十分困难(梯度向量的核算需要对函数微分),这违反了咱们设置梯度下降的初衷—不只没有找到最优参数还会加大核算担负。 这儿咱们以一个嵌套函数为例: 咱们能够构建一个所谓的核算图(如下所示),将原始函数分解为更小、更易于了解的表达式。 咱们将上图称为前向传达,经过前向传达后的函数变得十分简练。随后咱们从前向传达末端动身逐步向前微分,这个进程为反向传达。 经过将核算分解为对中间变量的简单操作,咱们能够使用链式法则来核算任何梯度。
3.PyTorch 梯度下降
AutoGrad 是 PyTorch 的自动微分引擎。在Pytorch里梯度下降也是从前向传达开端的,当咱们声明变量和操作时,PyTorch 会跟踪一切指令,并在咱们调用.backward(),即反向传达时构建核算图。PyTorch 每次迭代或更改图时都会重建核算图。 总结来说Pytorch梯度下降分为以下几个步骤:
1.重置梯度 2.核算图前向传达 3.核算丢失函数 4.核算图反向传达,核算丢失函数相关于可学习参数(即权重)的梯度 5.梯度下降
# Reset all gradients to zero
sgd_optimizer.zero_grad()
# Forward pass (Compute the output of the model on the features (inputs))
prediction = wide_net(inputs)
# Compute the loss
loss = loss_function(prediction, targets)
print(f'Loss: {loss.item()}')
# Perform backpropagation to build the graph and compute the gradients
loss.backward()
# Optimizer takes a tiny step in the steepest direction (negative of gradient)
# and "updates" the weights and biases of the network
sgd_optimizer.step()
4.nn.Moudle
PyTorch 为咱们供给了现成的神经网络构建块,例如层(例如线性、循环等)、不同的激活和丢失函数等等,都打包在torch.nn模块中. 关于练习,咱们需要知道三点: 1.模型参数 模型参数是指模型的一切可学习参数,可经过调用.parameters()模型访问。 2.丢失函数 梯度下降的优化目标 3.优化器 PyTorch 为咱们供给了许多优化办法(不同版本的梯度下降)。优化器保存模型的当前状况,并经过调用该step()办法,将根据核算出的梯度更新参数
4.1 界说一个简单的神经网络
## A Wide neural network with a single hidden layer
class WideNet(nn.Module):
def __init__(self):
"""Initializing the WideNet"""
n_cells = 512
super().__init__()
self.layers = nn.Sequential(
nn.Linear(1, n_cells),
nn.Tanh(),
nn.Linear(n_cells, 1),
)
def forward(self, x):
"""Forward pass
Args:
x (torch.Tensor): 2D tensor of features
Returns:
torch.Tensor: model predictions
"""
return self.layers(x)
# Create a mse loss function
loss_function = nn.MSELoss()
# Stochstic Gradient Descent optimizer (you will learn about momentum soon)
lr = 0.003 # learning rate
#这儿使用了随机梯度下降中的momentum办法
sgd_optimizer = torch.optim.SGD(wide_net.parameters(), lr=lr, momentum=0.9)
网络结构为:
WideNet( (layers): Sequential( (0): Linear(in_features=1, out_features=512, bias=True) (1): Tanh() (2): Linear(in_features=512, out_features=1, bias=True) ) )
4.2 练习网络
def train(features, labels, model, loss_fun, optimizer, n_epochs):
"""Training function
Args:
features (torch.Tensor): features (input) with shape torch.Size([n_samples, 1])
labels (torch.Tensor): labels (targets) with shape torch.Size([n_samples, 1])
model (torch nn.Module): the neural network
loss_fun (function): loss function
optimizer(function): optimizer
n_epochs (int): number of training iterations
Returns:
list: record (evolution) of training losses
"""
loss_record = [] # keeping recods of loss
### 梯度下降
for i in range(n_epochs):
optimizer.zero_grad() # set gradients to 0
predictions = model(features) # Compute model prediction (output)
loss = loss_fun(predictions, labels) # Compute the loss
loss.backward() # Compute gradients (backward pass)
optimizer.step() # update parameters (optimizer takes a step)
loss_record.append(loss.item())
return loss_record
set_seed(seed=2021)
epochs = 1847 # Cauchy, Exercices d'analyse et de physique mathematique (1847)
losses = train(inputs, targets, wide_net, loss_function, sgd_optimizer, epochs)
with plt.xkcd():
ex3_plot(wide_net, inputs, targets, epochs, losses)
对应一开端深度学习网络的五大成分,咱们能够这么了解:
1.方针函数–MSE丢失 loss_function = nn.MSELoss() 2.学习规矩–随机梯度下降和momentum办法 sgd_optimizer = torch.optim.SGD(wide_net.parameters(), lr=lr, momentum=0.9) 3.网络结构–512个神经元,1个躲藏层,1个Tanh激活层 def init(self): n_cells = 512 super().init() self.layers = nn.Sequential( nn.Linear(1, n_cells), nn.Tanh(), nn.Linear(n_cells, 1), ) 4.初始化–随机 5.环境
5.超参数
5.1 网络深度
在了解”深度“这个概念前,咱们先来看看神经网络的结构:输入层,躲藏层,输出层。因而深度在这儿指的就是躲藏层的数量,躲藏层数量越多,网络深度越大。
那么让咱们来看看深度在练习神经网络时带来的应战。幻想一个具有 50 个躲藏层且每层只有一个神经元的单输入单输出线性网络。网络的输出很简单核算: 假如一切权重的初始值为wi=2wi=2, y(p)=250≈1.12561015y(p)=2^{50}≈1.125610^{15},这时候的猜测值趋近于无限大,此时这种状况称为梯度爆破。 假如一切权重的初始值为wi=0.5wi=0.5, y(p)=0.550≈8.8810−16y(p)=0.5^{50}≈8.8810^{-16},这时候的猜测值趋近于无限小,此时这种状况称为梯度消失。 因而为了有用的避免这两种状况发生,咱们需要了解深度关于网络练习带来的影响: 不难看出,浅层网络的学习是一个按部就班的进程,而关于深层网络而言它的学习进程更像sigmoid函数,即经过一定时刻的学习后忽然掌握数据集的某些特征,这两种学习方式是天壤之别的。
5.2 学习率
学习率是大多数优化算法的常见超参数。咱们能够把学习率想成梯度下降进程中每一步的步长。 1.学习率过小 学习率过小将会导致丢失函数收敛过慢,即梯度下降迈步太小,花费很长时刻都不能走到丢失函数最小的最优参数的位置 2.学习率过大 学习率过大会导致梯度下降时越过丢失函数最小值,造成丢失函数的动摇 上图为适合学习率下的神经网络丢失随练习时刻的变化
5.3 深度,学习率的相互影响
一般来说,深度越深的网络需要的是更小的学习率,能够幻想成它的处理进程更为复杂,因而也就更需要小心翼翼的走好每一步。而浅层神经网络则正好相反,它能够承受较大学习率带来的影响。
5.4 初始化
详见之前说到的梯度爆破和梯度消失。