神经网络模型
首先,我们知道pytorch的任何网络net
,都是torch.nn.Module
的子类,都算是module
,也就是模块。
model.apply(fn)
:
pytorch中的model.apply(fn)
会递归地将函数fn
应用到父模块的每个子模块submodule
,也包括model
这个父模块自身。isinstance
:
isinstance是一个函数。它用于检查一个对象是否属于指定的类或类型。
isinstance(object, classinfo)接受两个参数:
- object:要检查的对象。
- classinfo:可以是类、类型或由类或类型组成的元组。
如果object是classinfo的实例或子类的实例,则返回True;否则返回False。torch.nn.Module
设定模式:
函数train
和函数eval
的作用是将Module
及其SubModule
分别设置为training mode
和evaluation mode
。torch.optim.Optimizer
:
torch.optim.Optimizer的实例是指通过torch.optim模块创建的优化器对象。torch.optim模块提供了各种常用的优化器类,这些类都是torch.optim.Optimizer的子类。
...
for X, y in train_iter:
# 计算梯度并更新参数
y_hat = net(X)
l = loss(y_hat, y)
if isinstance(updater, torch.optim.Optimizer):
# torch.optim.Optimizer是用来优化模型权重的类
# 使用PyTorch内置的优化器和损失函数
updater.zero_grad() # 先清零梯度
# 求梯度
l.backward()
updater.step()
metric.add(
# 训练损失乘len(y)是因为,pytorch会自动对loss取均值
float(l) * len(y), accuracy(y_hat, y),
y.size().numel()
)
else:
# 使用定制的优化器和损失函数
# l是向量
l.sum().backward()
updater(X.shape[0])
metric.add(float(l.sum()), accuracy(y_hat, y), y.numel())
# 返回训练损失和训练精度
...
def updater(batch_size):
return d2l.sgd([W, b], lr, batch_size)
...
代码通过if isinstance(updater, torch.optim.Optimizer):
检查updater是否是torch.optim.Optimizer的实例,并分别设定操作。
在PyTorch中,可以使用torch.optim.SGD类来创建SGD优化器的实例。通过实例化torch.optim.SGD类并传入相应的参数,可以创建一个SGD优化器对象。然后,可以使用该对象的step()方法来更新模型的参数,该方法会根据梯度和学习率自动执行参数更新操作。
import torch
import torch.optim as optim
# 创建模型和损失函数
model = ...
loss_fn = ...
# 创建SGD优化器
learning_rate = 0.01
optimizer = optim.SGD(model.parameters(), lr=learning_rate)
# 在每个训练步骤中执行以下操作
optimizer.zero_grad() # 清零梯度
output = model(input)
loss = loss_fn(output, target)
loss.backward() # 计算梯度
optimizer.step() # 更新参数
在上述代码中,model.parameters()用于获取模型的参数。
nn.Sequential()
介绍
一个序列容器,用于搭建神经网络的模块被按照被传入构造器的顺序添加到nn.Sequential()容器中。利用nn.Sequential()搭建好模型架构。nn.Sequential()可以视为将多个模块封装成一个模块,用forward()
接收输入后,nn.Sequential()
按照内部模块顺序自动一次计算并输出结果。
nn.Sequential()和torch.nn.ModuleList的区别在于:torch.nn.ModuleList只是一个储存网络模块的list,其中的网络模块之间没有连接关系和顺序关系。而nn.Sequential()内的网络模块之间是按照添加的顺序级联的。
nn.Linear()
基本用法
用nn.Linear()
定义一个神经网络的线性层:
torch.nn.Linear(in_features, # 输入的神经元个数
out_features, # 输出神经元个数
bias=True # 是否包含偏置
)
Linear就是对输入执行了一次线性变换:
假设输入i个样本,样本特征数为n。定义线性层,我们输入特征值为n,即in_feature=n
我们想让下一层输出为o,所以out_feature=o
。
经过线性层后,我们最终得到了维矩阵,即输入i个样本,每个样本维度为n,输出i个样本,将每个样本扩展成了o维
nn.Flatten()
torch.nn.Flatten(start_dim=1, end_dim=- 1)
作用:将连续的维度范围展平为张量。 经常在nn.Sequential()中出现,一般写在某个神经网络模型之后,用于对神经网络模型的输出进行处理,得到tensor类型的数据。
torch.init.normal_(tensor,mean=,std=)
: mean表示均值,std表示正态分布标准差assert
:python中当表达式为真时,程序继续往下执行,只是判断,不做任何处理; 当表达式为假时,抛出AssertionError错误,并将 [参数] 输出
如果将W1和W2初始化为全0,会导致神经网络在训练过程中出现一种现象叫做"对称权重"(Symmetric Weights)问题。这意味着每个神经元在同一层的权重会保持相同的值,因为它们会收到相同的梯度更新。
初始化为全0会导致以下问题:
- 梯度消失:所有权重相同导致梯度更新也相同,神经网络在反向传播过程中可能无法学习到有意义的表示。
- 缺乏多样性:对于隐藏层神经元,如果它们的权重都相同,那么它们在计算过程中会学习到相同的特征,无法捕捉输入数据中的多样性。
为了避免这些问题,通常使用一种称为“权重初始化”(Weight Initialization)的方法来初始化权重。通过给网络的权重矩阵赋予随机的初始值(通常是很小的值),可以打破对称性,使得每个神经元在训练过程中能学习到不同的特征。权重初始化有很多种方法,比如使用正态分布、均匀分布或者特定的初始化策略(如Xavier初始化、He初始化等)。
参考资料: blog.csdn.net/zhaohongfei… blog.csdn.net/Just_do_mys… blog.csdn.net/gx19990824/… blog.csdn.net/weixin_2943…