上篇文章,我们理解了我们程序的神经网络设计,这篇我们继续,把训练迭代过程分析一下,完成这两篇文章,下面问题,应该能回答了。
- 一张图片,如何被计算机读懂?
- pytorch 封装的网络,什么是卷积层,为什么要多层?层与层如何衔接?如何设计?
- 什么是池化?为什么要池化?
- 什么是全链接层?它有什么作用?
- 神经网络模型的前向传播?这个步骤的作用是什么?
- 什么梯度下降?梯度下降的价值?
- 什么是激活函数?为什么要用激活函数?
一、上篇完成网络设计后,神经网络如何训练,自优化的?
回到程序【如需解读,请参阅从0到1,AI我来了- (2)解读程序-从AI手写数字识别开始】
for epoch in range(num_epochs): running_loss = 0.0 correct = 0 total = 0 for images, labels in train_loader: optimizer.zero_grad() outputs = model(images) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() avg_loss = running_loss / len(train_loader) accuracy = 100 * correct / total # 记录到 TensorBoard writer.add_scalar('Loss/train', avg_loss, epoch) writer.add_scalar('Accuracy/train', accuracy, epoch) # 记录到列表 loss_values.append(avg_loss) accuracy_values.append(accuracy) print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {avg_loss:.4f}, Accuracy: {accuracy:.2f}%') writer.close()
这里做了10次训练,每次迭代训练会经过:
forward(前向传播)--》计算损失 --》backward(反向传播) --》更新权重
forward
前篇提到了,定义网络模型时,有个函数forword。
forward通常是指一个模型的前向传播过程,它的主要作用是计算输入数据通过网络时的输出,即这里的输入数据图片到输出数字概率的过程。
outputs = model(images)
程序中,这句代码,实际就是会调用SimpleCNN 的forward的方法,输入是图片,输出的是概率结果。
计算损失Loss
criterion = nn.CrossEntropyLoss()
...
loss = criterion(outputs, labels)
torch.nn
模块提供了多种常用的损失函数,这些损失函数可以用于不同类型的机器学习任务。附录一,有一些主要的损失函数,这里是个多分类问题,所以nn.CrossEntropyLoss 可以满足我们要求。
那CrossEntropyLoss 是如何计算损失的?
CrossEntropyLoss
结合了 softmax 函数和负对数似然损失(Negative Log Likelihood Loss)
大白话就是模型会跑出一些结果,比如[1.0,2.0,7.0],这里表示7.0的可能性最大,CrossEntropyLoss
会先把这些分数转化为概率,即把这些值变为0~1之间的值,且和为1。[1.0,2.0,7.0] 转化为[0.1,0.2,0.7]。
backward 反向传播
loss.backward()
非常关键的一行代码,简单理解就是,为了追求更小的损失,自动优化模型参数,不断迭代。
原理尝试解读一下,网上找了个图,解释一下:
损失函数L(w),随机指定权重,偏置(bias,随机标量),比如图中的W0哪个点,为了让损失更小(找到波谷),需要对w求导,即寻找W0点的切线。
如果切线斜率为负(如下图,w越大,Loss越小),说明应该增加w的值,也就是会自动根据学习率,更新w的值。
如果切线斜率为正(w越大,Loss 越大),说明梯度应该减少w的值。
更新权重
optimizer.step()
在计算出梯度后,我们需要根据这些梯度更新模型的参数。这里使用的优化器(optimizer)将会在调用 optimizer.step()
时生成参数的更新。
optimizer.step() 会更新哪些参数?
在调用 optimizer.step()
时,所有在优化器中注册的参数(即 model.parameters()
返回的那些)都会被更新。
参数类型,包括哪些?
在深度学习模型中,这些可学习的参数通常包括全连接层(nn.Linear
)的权重和偏置、卷积层(nn.Conv2d
)的权重和偏置、以及其他层的参数。
综上,那7个问题,应该能基本解答出来了,不往底层算法钻的话,能理解就行了。
下篇,我们我们来实践一个本地智能知识库,把常见的Agent、RAG,向量数据库分析分析。
附录:
一、分类任务
-
交叉熵损失 (Cross Entropy Loss):
torch.nn.CrossEntropyLoss
:用于多类分类问题torch.nn.BCEWithLogitsLoss
:用于二分类问题的 logits(未经过 sigmoid)和目标相结合的二元交叉熵损失。
-
负对数似然损失 (Negative Log Likelihood Loss):
torch.nn.NLLLoss
:配合在LogSoftmax
后使用,适用于多类分类。
-
KL 散度损失 (KL Divergence Loss):
torch.nn.KLDivLoss
:用于衡量两个概率分布之间的差异。
回归任务
-
均方误差损失 (Mean Squared Error Loss):
torch.nn.MSELoss
:适用于回归问题,计算预测值和目标值之间的均方差。
-
平均绝对误差损失 (Mean Absolute Error Loss):
torch.nn.L1Loss
:计算预测值和目标值之间的平均绝对差。
-
Huber 损失:
torch.nn.HuberLoss
:结合了均方误差和平均绝对误差的特点,对于目标值较大时更为稳健。
其他损失函数
-
对比损失 (Contrastive Loss):
- 自定义损失,一般用于 Siamese 网络。
-
Triplet Loss:
- 自定义损失,适用于需保持距离的学习(如人脸识别)。
-
Focal Loss:
- 自定义损失,用于处理类别不平衡问题。