3.3 线性回归的简洁实现
1 3.3 线性回归的简洁实现 2 import torch 3 from torch import nn 4 import numpy as np 5 torch.manual_seed(1) 6 7 print(torch.__version__) 8 torch.set_default_tensor_type('torch.FloatTensor') 9 10 # 1 生成数据集 11 num_inputs = 2 # 输入个数(特征数) 12 num_examples = 1000 # 训练数据集样本数 13 true_w = [2, -3.4] # 真实权重 14 true_b = 4.2 # 偏差 15 16 # features:训练数据特征;labels:标签 17 features = torch.tensor(np.random.normal(0, 1, (num_examples, num_inputs)), dtype= torch.float) 18 labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b # y = Xw + b + e 19 labels += torch.tensor(np.random.normal(0, 0.01, size=labels.size()), dtype=torch.float) 20 21 # Passage 2 读取数据 22 import torch.utils.data as Data 23 24 batch_size = 10 25 26 # 将训练数据的特征和标签组合 27 dataset = Data.TensorDataset(features, labels) 28 29 # 把dataset放入DataLoader,随机读取小批量 30 data_iter = Data.DataLoader( 31 dataset=dataset, # torch TensorDataset format 32 batch_size=batch_size, # mini batch size 33 shuffle=True, # 要不要打乱数据 (打乱比较好) 34 # num_workers=Passage 2, # 多线程来读数据 35 ) 36 37 # 读取并打印第一个小批量数据样本 38 for X, y in data_iter: 39 print(X, '\n', y) 40 break 41 42 # Passage 3 定义模型 43 # 导入torch.nn模块(neural networks,神经网络) 44 # nn的核心数据结构为Module,抽象概念,既可以表示神经网络中的某个层,也可以表示一个包含很多层的神经网络 45 # 常见做法:继承nn.Module,撰写自己的网络/层 46 # 一个nn.Module实例应该包含一些层以及返回输出的向前传播方法 47 class LinearNet(nn.Module): 48 def __init__(self, n_feature): 49 super(LinearNet, self).__init__() 50 self.linear = nn.Linear(n_feature, 1) 51 # forward 定义向前传播 52 def forward(self, x): 53 y = self.linear(x) 54 return y 55 56 net = LinearNet(num_inputs) 57 print(net) # 打印出网络的结构 58 59 # nn.Sequential 60 # Sequential是一个有序的容器,网络层将按照传入Sequential的顺序依次被添加到计算图中 61 # 写法一: 62 net = nn.Sequential( 63 nn.Linear(num_inputs, 1) 64 # 此处还可以传入其他层 65 ) 66 67 # 写法二: 68 net = nn.Sequential() 69 net.add_module('linear', nn.Linear(num_inputs, 1)) 70 # net.add_module...... 71 72 # 写法三: 73 from collections import OrderedDict 74 net = nn.Sequential(OrderedDict([ 75 ('linear', nn.Linear(num_inputs, 1)) 76 #...... 77 ])) 78 79 print(net) 80 print(net[0]) 81 82 # 通过net.parameters()来查看模型所有的可学习参数,将返回一个生成器 83 for param in net.parameters(): 84 print(param) 85 86 # 作为一个单层神经网络,线性回归输出层中的神经元和输入层中各个输入完全连接;因此,线性回归的输出层又叫全连接层 87 # 注意:torch.nn仅支持输入一个batch的样本不支持单个样本输入,如果只有单个样本,可使用input.unsqueeze(0)来添加一维 88 89 # 4 初始化模型参数,例如线性回归中的权重和偏差 90 # 通过init.normal_将权重参数每个元素初始化为随机采样于均值为0,标注差为0.01的正态分布,偏差会初始化为零 91 from torch.nn import init 92 93 init.normal_(net[0].weight, mean=0, std=0.01) 94 init.constant_(net[0].bias, val=0.0) 95 # 可以直接修改bias的data: net[0].bias.data.fill_(0) 96 97 for param in net.parameters(): 98 print(param) 99 100 # 5 定义损失函数 101 # 损失函数可看作是一种特殊的层 102 loss = nn.MSELoss() # 使用均方误差 103 104 # 6 定义优化算法 105 # torch.optim模块提供了很多常用的优化算法,例如:SGD,Adam和RMSProp等 106 # 创建一个用于优化net所有参数的优化器实例,并指定学习率为0.03的小批量随机梯度下降(SGD)为优化算法 107 import torch.optim as optim 108 109 optimizer = optim.SGD(net.parameters(), lr=0.03) 110 print(optimizer) 111 112 # 还可以为不同子网络设置不同的学习率,在finetune时经常用到 113 # optimizer = optim.SGD([ 114 # # 如果对某个参数不指定学习率,就使用最外层的默认学习率 115 # {'params': net.subnet1.parameters()}, # lr=0.01 116 # {'params': net.subnet2.parameters(), 'lr': 0.01} 117 # ], lr=0.03) 118 119 # 调整学习率 120 # 法一:修改optimizer.param.groups中对应的学习率 121 # 法二(推荐):新建优化器,由于optimizer十分轻量级,构建开销很小,故而可以构建新的optimizer 122 # 但是后者对于使用动量的优化器(如Adam),会丢失动等状态信息,可能会造成损失函数的收敛出现震荡等情况 123 # for param_group in optimizer.param_groups: 124 # param_group['lr'] *= 0.1 # 学习率为之前的0.1倍 125 126 # 7 训练模型 127 num_epochs = 3 128 for epoch in range(1, num_epochs + 1): 129 for X, y in data_iter: 130 output = net(X) 131 l = loss(output, y.view(-1, 1)) 132 optimizer.zero_grad() # 梯度清零,等价于net.zero_grad() 133 l.backward() 134 optimizer.step() 135 print('epoch %d, loss: %f' % (epoch, l.item())) 136 137 dense = net[0] 138 print(true_w, dense.weight.data) 139 print(true_b, dense.bias.data)