记录pytorch用于深度学习的学习过程。
线性回归和softmax回归都是单层神经网络,用于解决回归问题。
y ^ = x 1 w 1 + x 2 w 2 + b \hat y = x_1w_1 + x_2w_2 + b y^=x1w1+x2w2+b
L = 1 n ∑ 1 2 ( y ^ ( i ) − y ( i ) ) 2 L = \frac 1 n\sum\frac 1 2(\hat y^{(i)} - y^{(i)})^2 L=n1∑21(y^(i)−y(i))2
解析解analytical solution:误差最小化问题的解可以直接用公式表达出来。
数值解numerical solution:只能通过优化算法有限次迭代模型参数来尽可能降低损失函数的值。
小批量梯度下降法mini-batch
经过训练后,得到w1 w2 b。
y ^ = x 1 w 1 + x 2 w 2 + b \hat y = x_1w_1 + x_2w_2 + b y^=x1w1+x2w2+b
进行预测。
矢量计算比循环计算,快了1到2个数量级。所以尽可能用向量来计算。
y ^ = χ ω + b \hat y = \chi\omega + b y^=χω+b
相应的梯度下降迭代公式、损失函数均写成矢量。
import torch
from IPython import display
import matplotlib.pyplot as plt
import numpy as np
import random
num_inputs = 2 # 特征数
num_examples = 1000 # 样本数
true_w = [2, -3.4] # 真实权重w
true_b = 4.2 # 真实偏差b
features = torch.randn(num_examples, num_inputs, # 生成随机样本
dtype=torch.float32)
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.float32)
# 第一个样本:特征、标签
print(features[0], labels[0])
def use_svg_display():
# 用矢量图显示
display.set_matplotlib_formats('svg')
def set_figsize(figsize=(3.5, 2.5)):
use_svg_display()
# 设置图的尺寸
plt.rcParams['figure.figsize'] = figsize
set_figsize() # 设置好显示效果
plt.scatter(features[:, 1].numpy(), labels.numpy(), 1)
plt.show()
import torch
from IPython import display
import matplotlib.pyplot as plt
import numpy as np
import random
num_inputs = 2 # 特征数
num_examples = 1000 # 样本数
true_w = [2, -3.4] # 真实权重w
true_b = 4.2 # 真实偏差b
features = torch.randn(num_examples, num_inputs, # 生成随机样本 num_examples * num_inputs
dtype=torch.float32)
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.float32)
# 第一个样本:特征、标签
print(features[0], labels[0])
# def use_svg_display():
# # 用矢量图显示
# display.set_matplotlib_formats('svg')
#
#
# def set_figsize(figsize=(3.5, 2.5)):
# use_svg_display()
# # 设置图的尺寸
# plt.rcParams['figure.figsize'] = figsize
#
# set_figsize() # 设置好显示效果
# plt.scatter(features[:, 1].numpy(), labels.numpy(), 1)
# plt.show()
def data_iter(batch_size, features, labels):
'''
:param batch_size: 批量大小
:param features: 样本集合
:param labels: 标签
:return:
'''
num_examples = len(features)
indices = list(range(num_examples))
random.shuffle(indices) # 随机打乱list
for i in range(0, num_examples, batch_size):
j = torch.LongTensor(indices[i: min(i + batch_size, num_examples)]) # 最后一次可能不足一个batch
yield features.index_select(0, j), labels.index_select(0, j)
batch_size = 10
# for X, y in data_iter(batch_size, features, labels):
# print(X, y)
# break
w = torch.tensor(np.random.normal(0, 0.01, (num_inputs, 1)), dtype=torch.float32)
b = torch.zeros(1, dtype=torch.float32)
w.requires_grad_(requires_grad=True)
b.requires_grad_(requires_grad=True)
# 定义模型
def linreg(X, w, b):
return torch.mm(X, w) + b
# 定义损失函数
def squared_loss(y_hat, y):
# 注意这里返回的是向量, 另外, pytorch里的MSELoss并没有除以 2
return (y_hat - y.view(y_hat.size())) ** 2 / 2
# 定义优化算法:小批量随机梯度下降
def sgd(params, lr, batch_size):
'''
:param params: 权重参数
:param lr: 学习率
:param batch_size: 批量大小
:return:
'''
for param in params:
param.data -= lr * param.grad / batch_size # 注意这里更改param时用的param.data
lr = 0.03 # 学习率
num_epochs = 3 # 迭代周期个数
net = linreg # 网络模型
loss = squared_loss # 损失函数
for epoch in range(num_epochs): # 训练模型一共需要num_epochs个迭代周期
# 在每一个迭代周期中,会使用训练数据集中所有样本一次(假设样本数能够被批量大小整除)
# X和y分别是小批量样本的特征和标签
for X, y in data_iter(batch_size, features, labels):
l = loss(net(X, w, b), y).sum() # l是有关小批量X和y的损失
# l是向量,需要先sum()成标量再计算梯度
l.backward() # 小批量的损失对模型参数求梯度
# 计算得到的梯度在w.grad、b.grad中
sgd([w, b], lr, batch_size) # 使用小批量随机梯度下降迭代模型参数
# 不要忘了梯度清零
w.grad.data.zero_()
b.grad.data.zero_()
# 一轮迭代完成/训练完一轮全部样本
train_l = loss(net(features, w, b), labels)
print('epoch %d, loss %f' % (epoch + 1, train_l.mean().item()))
torch.utils.data
模块提供了有关数据处理的工具
torch.nn
模块定义了大量神经网络的层
torch.nn.init
模块定义了各种初始化方法
torch.optim
模块提供了很多常用的优化算法。
import torch
from IPython import display
import matplotlib.pyplot as plt
import numpy as np
import random
import torch.utils.data as Data
from torch import nn
from torch.nn import init
import torch.optim as optim
# 1、生成数据集
num_inputs = 2 # 特征数
num_examples = 1000 # 样本数
true_w = [2, -3.4] # 真实权重w
true_b = 4.2 # 真实偏差b
features = torch.randn(num_examples, num_inputs, # 生成随机样本 num_examples * num_inputs
dtype=torch.float32)
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.float32)
# 2、读取数据
batch_size = 10
# 将训练数据的特征和标签组合
dataset = Data.TensorDataset(features, labels)
# 随机读取小批量
data_iter = Data.DataLoader(dataset, batch_size, shuffle=True) # shuffle打乱样本顺序
# 3、定义模型
class LinearNet(nn.Module):
def __init__(self, n_feature):
super(LinearNet, self).__init__()
self.linear = nn.Linear(n_feature, 1)
# forward 定义前向传播
def forward(self, x):
y = self.linear(x)
return y
net = LinearNet(num_inputs)
# print(net) # 使用print可以打印出网络的结构
# 4、初始化参数模型
init.normal_(net.linear.weight, mean=0, std=0.01) # 正态分布
init.constant_(net.linear.bias, val=0) # 0
# 5、定义损失函数
loss = nn.MSELoss()
# 6、定义优化函数
optimizer = optim.SGD(net.parameters(), lr=0.03) # 梯度下降法 学习率0.03
# optimizer = optim.SGD([
# # 如果对某个参数不指定学习率,就使用最外层的默认学习率
# {'params': net.subnet1.parameters()}, # lr=0.03
# {'params': net.subnet2.parameters(), 'lr': 0.01}
# ], lr=0.03)
# print(optimizer)
# 7、训练模型
num_epochs = 3 # 迭代轮数
for epoch in range(1, num_epochs + 1):
for X, y in data_iter:
output = net(X)
l = loss(output, y.view(-1, 1))
optimizer.zero_grad() # 梯度清零,等价于net.zero_grad()
l.backward()
optimizer.step()
print('epoch %d, loss: %f' % (epoch, l.item()))
print()
dense = net.linear
print(true_w, dense.weight)
print(true_b, dense.bias)