error_of_linear_regression_pytorch

《Dive-into-DL-Pytorch》-线性回归的简单实现(linear regression pytorch)

11月3日开始学习深度学习,很多东西不太理解,对书中的代码尽量给出自己理解的注释,并进行分析

书中有两处直接运行会出现报错,也对其进行简单分析,因为刚学不久,所以很多地方的理解可能不是很正确

0.模型(Model)

设第一个特征 ( f e a t u r e ) 为 x 1 ,第二个特征为 x 2 ,真实标签 ( l a b e l ) 为 y : y ^ = ω 1 x 1 + ω 2 x 2 + b ω 1 和 ω 2 是权重 ( w e i g h t ) , b 是偏差 ( b i a s ) ,它们是线性回归模型的参数 ( p a r a m e t e r ) 。 y ^ 是线性回归对真实标签 y 的预测 设第一个特征(feature)为x_1,第二个特征为x_2,真实标签(label)为y:\\ \hat y = \omega_1x_1 + \omega_2x_2 + b \\ \omega_1和\omega_2是权重(weight),b是偏差(bias),它们是线性回归模型的参数(parameter)。\hat y是线性回归对真实标签y的预测 设第一个特征(feature)x1,第二个特征为x2,真实标签(label)yy^=ω1x1+ω2x2+bω1ω2是权重(weight)b是偏差(bias),它们是线性回归模型的参数(parameter)y^是线性回归对真实标签y的预测

1.导入库

import torch
import numpy as np
import random
from torch import nn

2.生成数据集

给定随机生成的批量样本特征 X ∈ R 1000 × 2 ,使用真实权重 ω = [ 2 , − 3.4 ] T 、偏差 b = 4.2 和一个随机噪声项 ϵ 来生成标签 y = X ω + b + ϵ 给定随机生成的批量样本特征\boldsymbol{X}\in\mathbb{R}^{1000\times2},使用真实权重 \boldsymbol{\omega} = [2, -3.4]^T、偏差b = 4.2和一个随机噪声项\epsilon来生成标签\\ \mathbf{y} = \boldsymbol{X}\boldsymbol{\omega} + b + \epsilon 给定随机生成的批量样本特征XR1000×2,使用真实权重ω=[2,3.4]T、偏差b=4.2和一个随机噪声项ϵ来生成标签y=Xω+b+ϵ

num_inputs = 2	# 训练数据的输入个数(特征数)
num_examples = 1000	# 训练数据的样本数
true_w = [2, -3.4]	# 真实权重(有两个特征,所以权重也有两个)
true_b = 4.2	# 真实偏差
features = torch.tensor(np.random.normal(0, 1, (num_examples, num_inputs)), dtype=torch.float)	# 采用正态分布随机生成每个样本的两个特征

labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b	# 通过特征和偏差计算真实标签
labels += torch.tensor(np.random.normal(0, 0.01, size=labels.size()), dtype=torch.float)	# 通过上面计算的标签全部为一个常数值,所以此处加入一个随机噪声项代表数据集中无意义的干扰
# 噪声项服从均值为0,标准差为0.01的正态分布

3.读取数据

# 导入pytorch提供的data包来读取数据
import torch.utils.data as Data

# 定义小批量样本的数量
batch_size = 10
# 将训练数据的特征与标签组合
dataset = Data.TensorDataset(features, labels)
# 将dataset导入dataloader
data_iter = Data.DataLoader(dataset, batch_size, shuffle=True)
	# 第一个参数为导入的数据集
    # 第二个参数为每次读取的样本个数
    # 第三个参数为是否打乱数据
    
# 打印第一个小批量的数据
for X, y in data_iter:
    print(X, y)
    break

4.定义模型

class LinearNet(nn.Module):	# 定义了一个继承自nn.Module的类LinearNet
    def __init__(self, n_feature):
        super(LinearNet, self).__init__()
        self.linear = nn.Linear(n_feature, 1)	# nn.Linear定义了一个神经网络的线性层
        										# n_feature是输入特征的个数
            									# 1是输出特征的个数
    # forward 定义前向传播
    def forward(self, x):	# 接受一个输入张量x,并通过线性层后返回输出张量y
        y = self.linear(x)
        return y
    
net = LinearNet(num_inputs)
print(net)  # 使用print可以打印出网络的结构
书中还给了使用nn.Sequential来搭建网络,Sequential是一个有序容器,网络层将按照传入Sequential时的顺序依次添加到计算图中:
# 写法一
net = nn.Sequential(
    nn.Linear(num_inputs, 1)
    # 此处还可以传入其他层
)

# 写法二
net = nn.Sequential()
net.add_module('linear', nn.Linear(num_inputs, 1))	# linear是该层的名字
# net.add_module ... 此处还可以传入其他层

# 写法三
from collections import OrderedDict
net = nn.Sequential(OrderedDict([
    ('linear', nn.Linear(num_inputs, 1))	# linear是该层的名字
    # ... 此处还可以传入其他层
]))

print(net)
print(net[0])	# 输出第一层网络,上面的三个写法都只创建了一层网络
通过net.patameters()可以查看模型所有可学习的参数:
for param in net.parameters():
    print(param)

5.初始化模型参数

此处是对net[0]的模型参数进行初始化,即定义模型中传入的第一层网络,事实上,上面的代码也只传入了一层网络

# 我们通过init.normal_将权重参数每个元素初始化为随机采样于均值为0,标准差为0.01的正态分布,偏差会初始化为0
from torch.nn import init

init.normal_(net[0].weight, mean=0, std=0.01)
init.constant_(net[0].bias, val=0.0)  # 也可以直接修改bias的data:net[0].bias.data.fill_(0)

6.定义损失函数

# 使用nn模块提供的均方差损失作为模型的损失函数
loss = nn.MSEloss

7.定义优化算法

# 使用torch.optim提供的SGD优化算法,并制定学习率为0.03
import torch.optim as optim

optimizer = optim.SGD(net.parameters(), lr=0.03)	# net.parameters()是需要学习的参数
print(optimizer)
当然,我们还可以对不同的网络层设定不同的学习率:
optimizer = optim.SGD([
    # 如果对某个参数不指定学习率,就是用最外层的默认学习率
    {'params': net.subnet1.parameters()}, # lr=0.03
    {'params': net.subnet2.parameters(), 'lr': 0.01}
], lr=0.03)

注意: 上面的代码写进notebook中运行会报错,错误原因为:AttributeError: ‘Sequential’ object has no attribute ‘subnet1’(属性错误:Sequential中没有sbunet1这个属性)。这里的subnet1subnet2是网络层的名字,在定义模型的代码中的linear是一样的(那个地方代码我也有注释),因为上面的代码没有定义名字是subnet1subnet2的网络层,所以此处报错。如果你想让代码跑起来,那将这一段代码注释掉就是正确的解决办法了。详细的原因解释在这里:AttributeError: ‘Sequential’ object has no attribute ‘subnet1’

如果不希望学习率是一个固定的常数,我们也可以使用下面的方法来调整学习率:
# 调整学习率
for param_group in optimizer.param_groups:
    param_group['lr'] *= 0.1    # 学习率为之前的0.1倍

思考: 这里为什么用了一个for循环?

当有多层网络的时候,就可以设定多个学习率,于是,可以用上面的方法对这些学习率进行修改了

8.训练模型

num_epochs = 3	# 训练模型的迭代周期次数
for epoch in range(1, num_epochs + 1):	# 这里我也不是很理解为什么用range(1, num_epochs+1),而不用										 # range(num_epochs)
    for X, y in data_iter:	# X为特征值,y为标签
        output = net(X)	# 将特征值X用net模型进行预测的到输出结果
        l = loss(output, y.view(-1, 1))	# 计算输出结果和标签的差异程度
        optimizer.zero_grad()	# 梯度清零
        l.backward()
        optimizer.step()
    print('epoch %d, loss: %f' % (epoch, l.item()))	# 输出每一个迭代周期的损失函数
# 输出真实参数和学到的参数,进行比较
dense = net[0]
print(true_w, dense.weight)
print(true_b, dense.bias)

9.两个错误

当时将所有的代码敲到notebook上之后运行时出现了两个错误:

  1. RuntimeError: Boolean value of Tensor with more than one value is ambiguous
  2. AttributeError: ‘Sequential’ object has no attribute ‘subnet1’

第二个错误已经分析过了,现在来分析第一个:

RuntimeError: Boolean value of Tensor with more than one value is ambiguous(运行时出错:Tensor的布尔值具有多个值有歧义),这个错误找了半天,最后是对着源码一行一行的看,发现定义损失函数的时候,忘记加后面的括号了,当时也成了这样loss = nn.MSEloss😭

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值