[从0开始深度学习] 线性神经网络1
线性回归
25.10.13
一.线性回归基础框架:
-
数据预处理
-
定义loss函数
-
定义优化器
-
训练 model.train() 需要记录梯度
4.1 前向传播计算loss
4.2 梯度清零 optimizer. zero_grad()
4.3 反向传播计算梯度 loss. backward()
4.4 更新参数 optimizer. step()
4.5评估 model.eval() 不需要记录梯度,计算total_loss,print
二.线性回归手敲代码实现:
import torch
from torch import nn
from torch.utils import data
'''
利用包来实现linear regression
'''
## 定义工具函数
def synthetic_data(w,b,num_samples,input_dim):
X = torch.normal(0,1, size=(num_samples,input_dim))
y = torch.matmul(X , w) + b
y += torch.normal(0,0.01,y.shape)
return X, y.reshape((-1,1))
## 生成数据集
input_dim = 2
output_dim = 1
true_w = torch.tensor([-2.0,4.0])##float才能有梯度,整数没有!!!
true_b = 4.2
num_samples = 1000
features, labels = synthetic_data(true_w,true_b,num_samples,input_dim)
## 读取数据集
def load_arry(data_arrays,batch_size,is_train=True):
dataset = data. TensorDataset(*data_arrays)#调用TensorDataset的API,把数据和标签打包成数据集,相当于创建了一个 (特征, 标签) 的配对集合
return data.DataLoader(dataset,batch_size,shuffle=is_train)#调用DataLoader的API,划分批次,并打乱顺序
batch_size = 5
num_epochs = 10
data_iter = load_arry((features,labels),batch_size,is_train=True)
## 定义模型
model = nn.Sequential(nn.Linear(input_dim,output_dim))#Sequential相当于装这些layers的容器,这里只有一层,其实也可以没有
##初始化模型参数,初始化网络的第一层net[0],使用weight.data,bias.data来访问参数
model[0].weight.data.normal_(0,0.01) # w = torch.normal(mean,std,size)---w.normal_(mean,std,size)
model[0].bias.data.fill_(0)# b = torch.tensor([0.0],requires_grad=True)这里一定是0.0,整数不能计算梯度 or b = torch.zeros(1, requires_grad=True)
## 训练: 1.选loss 2.选优化器 3.前向传播计算loss 4. 清零梯度 5.反向传播计算梯度 6.更新参数
# 6.一个epoch循环结束,计算总loss,观察是否下降
#定义损失函数
criterion = nn.MSELoss()
#定义优化算法自动处理梯度(小梯度下降也就是SGD)更新参数用来
optimizer = torch.optim.SGD(model.parameters(),lr = 0.01)
'''
训练阶段,记录计算图是为了反向传播的时候,顺着反方向计算梯度
梯度清理,清掉的是梯度值,而非计算图,
也就是说反向传播的时候要顺着计算图,重新计算梯度,然后根据新的梯度,来更新参数
'''
for epoch in range (num_epochs):
for X,y in data_iter:
#训练阶段
model.train()
loss = criterion(model(X),y) # 1. 前向传播计算loss,要记录计算图
optimizer.zero_grad() # 2. 梯度清零 zero_grad()
loss.backward() # 3. 反向传播 backward()
optimizer.step() # 4. 更新参数 step()
#评估阶段
model.eval()
with torch.no_grad():
total_loss = criterion(model(features),labels)
print(f'epoch:{epoch+1}, loss:{total_loss.item():.6f}')
三.理解总结:
1. 训练阶段为什么要梯度清零
训练阶段,记录计算图是为了反向传播的时候,顺着反方向计算梯度
梯度清理,清掉的是梯度值,而非计算图,也就是说反向传播的时候要顺着计算图,重新计算梯度,然后根据新的梯度,来更新参数;
而评估阶段,为了节省内存,不需要记录梯度
2. model.train()和model.eval()
训练时:model.train() - 让Dropout、BatchNorm正常工作;评估/推理时:model.eval() - 获得稳定、可重复的结果,只是这里还未涉及
# 可复现实验设置:随机种子与CuDNN确定性
SEED = 2025
random.seed(SEED)
np.random.seed(SEED)
torch.manual_seed(SEED)
3. Pytorch(torch.) 中的常见包熟记功能
data包提供了数据处理工具,data. TensorDataset 将特征和标签一一配对;
nn有大量神经网络层和常见损失函数:nn.Sequential, nn.MSELoss
torch 中直接包含优化器: torch. optim.Adam
4.如果将小批量的平均损失替换为小批量总损失,需要如何更改学习率?
我们说,反向传播过后要更新参数,也就是
这里η=lr, 优化器默认为平均损失。
如果替换为总损失 , 那么lr变为 lr/batch_size。
5. 常见损失函数
a) 回归损失
nn.MSELoss() # 均方误差
nn.L1Loss() # 平均绝对误差
nn.SmoothL1Loss() # 平滑L1损失(Huber损失)
nn.HuberLoss() # Huber损失
b) 分类损失
nn.CrossEntropyLoss() # 交叉熵损失(多分类)
nn.BCELoss() # 二分类交叉熵
nn.BCEWithLogitsLoss() # 带sigmoid的二分类交叉熵
nn.NLLLoss() # 负对数似然损失
c) 其他损失
nn.KLDivLoss() # KL散度
nn.MarginRankingLoss() # 排序损失
nn.TripletMarginLoss() # 三元组损失
nn.CosineEmbeddingLoss() # 余弦嵌入损失
参考内容:
1.https://zh-v2.d2l.ai/chapter_linear-networks/linear-regression-concise.html
更多推荐
所有评论(0)