持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
通过前面几篇博客,初步了解了pytorch的使用方式,我个人认为pytorch的学习门槛相较于tensorflow较低,因为pytorch帮助用户建立了更完善的生产环境,很多操作都属于规则是套用,不需要用户写非常繁琐的代码就可以得到想要的结果。
通过对网络结构进行的代码实现和原理的解释,相比对于整个网络模型有了一个初步的认知,并没有想象中的如此复杂,因此借此,本博客详细的讲述一下在模型的学习过程,也就是我们所谓的训练,这内部到底执行了什么过程们可以让我们从输入的数据得到我们预期的一个输出。
从下面一张图说起,
输入,便是我们从训练集读取的每个批次的图像,这个学习过程,就是一个参数估计的过程,在网络初次训练的时候,每个参数的权重我们一般是根据经验随机初始化,虽然是一个随机的初始化,但是参数的选择也非常重要,选择一个好的参数可以帮助模型快速的收敛。
看到图中改变权重以减少误差所指向的位置,这个便是参数的计算过程,通过我们初始化的参数,网络会经过卷积、池化以及残差连接等过程产生一个输出,这个输出便是在给定当前权重(参数)的情况下得到的输出,将这个输出与ground truth进行比较,这个比较也同样存在文章,比较的方式有很多种类,不过不用担心pytorch中都已经集成了相关的函数,我们可以直接将两者作为输入得到一个输出,这个输出就是两者之间的损失,通俗的讲,也就是两者之间的差异。
然后,反向传播会将这个损失进行回传,通过一次迭代后,会根据我们事先设置好的学习率和动量来改变我们初始化的参数值,使其进行新一轮的计算,当经过很多次的迭代之后,在整个数据集中的loss值达到最小,或者是不再变化,相较于之前,那么此时训练就结束了,也就是所谓的最小化损失函数。
通过上述一个又一个的循环(前向传播再反向传播)最终得到一系列新的参数值,这些得到的参数值也就是我们所谓的权重,它可以使得网络在该数据集中得到一个较好的预测。
`for epoch in range(5):
running_loss = 0.0
for step,data in enumerate(train_loader,start=0):
inputs,labels = data
# 清除梯度
optimizer.zero_grad()
outputs = net(inputs.to(device))
loss = loss_function(outputs,labels.to(device))
loss.backward()
optimizer.step()
running_loss += loss.item()
if step % 500 == 499:
with torch.no_grad():
outputs = net(val_image.to(device))
predict_y = torch.max(outputs,dim=1)[1]
accuracy = (predict_y == val_label.to(device)).sum().item()/val_label.size(0)
print('[%d %5d] train_loss: %.3f test_accuracy:%.3f' % (epoch+1,step+1,
running_loss/500,accuracy))
Loss.append(running_loss)
running_loss = 0.0
`
这就是很明显的一个训练过程,首先需要读取数据集的中的数据,拆分为训练数据与标签,这个没什么需要注意的。然后就是将梯度归零,这样做的好处就是可以加速训练,避免干扰。
对于 loss = loss_function(outputs,labels.to(device)),就是计算损失,计算完成损失之后就是将得到的损失进行反向传播,这一点pytorch都帮我们封装好了,我们可以直接调用backward函数,最后就是对优化器进行更新,优化器这一点前面的代码中也有出现,这里也不再进行叙述,后面的博客中会有专门讲优化器的一个。
对于整个的结果,在每500步时打印一下当前的准确率,其结果如下,其实上述的训练过程与前面博客中使用的网络结构是相同的,都是使用了LeNet,网络结构相对较为简单,容易上手学习。
看到这里,对于整个网络的训练过程也有了详细的了解,对于深度学习也就没有了那么神秘的面纱。