线性回归
- [1] 线性回归输出是⼀个连续值,因此适⽤于回归问题。回归问题在实际中很常⻅,如预测房屋价格、⽓温、销售额等连续值的问题。与回归问题不同,分类问题中模型的最终输出是⼀个离散值。我们所说的图像分类、垃圾邮件识别、疾病检测等输出为离散值的问题都属于分类问题的范畴。softmax回归则适⽤于分类问题。
- [2] 由于线性回归和softmax回归都是单层神经⽹络,它们涉及的概念和技术同样适⽤于⼤多数的深度学习模型。⾸先以线性回归为例,介绍⼤多数深度学习模型的基本要素和表示⽅法。
1.线性回归的基本要素
1.1 模型定义
1.2 模型训练
接下来我们需要通过数据来寻找特定的模型参数值,使模型在数据上的误差尽可能⼩。这个过程叫作模型训练(model training)。下⾯我们介绍模型训练所涉及的3个要素。
- 训练数据
- 损失函数
- 优化算法
1.3 模型预测
2.线性回归的表示方法
2.1 神经网络图
2.2 矢量计算表达式
在模型训练或预测时,我们常常会同时处理多个数据样本并⽤到⽮量计算。在介绍线性回归的⽮量计算表达式之前,让我们先考虑对两个向量相加的两种⽅法。
先定义两个1000维的向量
import torch
from time import time
a=torch.ones(1000)
b=torch.ones(1000)
向量相加的一种方式是将两个向量按照元素逐一相加
start=time()
c=torch.zeros(1000)
for i in range(1000):
c[i]=a[i] + b[i]
print(time() - start)
***output***
0.02039504051208496
向量相加的另⼀种⽅法是,将这两个向量直接做⽮量加法。
start=time()
d=a+b
print(time()-start)
***output***
0.0008330345153808594
结果很明显,后者⽐前者更省时。因此,我们应该尽可能采⽤⽮量计算,以提升计算效率。
对3个房屋样本预测价格的⽮量计算表达式为 其中的加法运算使⽤了⼴播机制(可参考:广播机制)。例如
a=torch.ones(3)
b=10
print(a+b)
***output***
tensor([11.,11.,11.])
3. 线性回归的从零开始实现
# time:20220810
# writer:yohn
#Pytorch实现线性回归
from decimal import Decimal
import matplotlib
import torch
from matplotlib import pyplot as plt
import numpy as np
import random
#1.构造一个简单的人工训练数据集
num_inputs = 2 #输入特征个数
num_examples = 1000 #训练数据集样本数
true_w = [2, -3.4] #线性回归模型真实权重
true_b = 4.2 #偏差
features = torch.from_numpy(np.random.normal(0, 1, (num_examples,num_inputs)))
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b
labels += torch.from_numpy(np.random.normal(0, 0.01,size=labels.size()))
print(features[0], labels[0])
#tensor([ 0.5589, -0.2146], dtype=torch.float64) tensor(6.0320, dtype=torch.float64)
plt.scatter(features[:, 1].numpy(), labels.numpy(), 1) #显示样本数据
# plt.title("data")
# plt.show()
#2.读取数据
def data_iter(batch_size, features, labels):
num_examples = len(features)
indices = list(range(num_examples))
random.shuffle(indices) # 样本的读取顺序是随机的
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 #读取第一个小批量数据并打印,形状特征为(10,2)
for X, y in data_iter(batch_size, features, labels):
print(X, y)
break
#3.初始化模型参数,将权重初始化为均值为0,标准差为0.01的正态随机数,偏差初始化为0
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_()
b.requires_grad_()
#4.定义模型,用mm做矩阵乘法
def linreg(X, w, b): # 本函数已保存在d2lzh_pytorch包中⽅便以后使⽤
#X.to(torch.float32) #数据类型转换失败
X_=X.float()
#print(X_.type())
return torch.mm(X_, w) + b
#5.定义损失函数
def squared_loss(y_hat, y): # 本函数已保存在d2lzh_pytorch包中⽅便以后使⽤
# 注意这⾥返回的是向量, 另外, pytorch⾥的MSELoss并没有除以 2
return (y_hat - y.view(y_hat.size())) ** 2 / 2
#6.定义优化算法,sgd实现了小批量随机梯度下降法,通过不断迭代模型参数来优化损失函数
#这里自动求梯度模块计算得来的梯度是一个批量样本的梯度和
def sgd(params,lr,batch_size):
for param in params:
param.data-=lr*param.grad/batch_size
#7.训练模型
# 在训练中,我们将多次迭代模型参数。在每次迭代中,我们根据当前读取的⼩批量数据样本(特征 X 和
# 标签 y ),通过调⽤反向函数 backward 计算⼩批量随机梯度,并调⽤优化算法 sgd 迭代模型参数。
# 由于我们之前设批量⼤⼩ batch_size 为10,每个⼩批量的损失 l 的形状为(10, 1)。回忆⼀下⾃动求
# 梯度⼀节。由于变量 l 并不是⼀个标量,所以我们可以调⽤ .sum() 将其求和得到⼀个标量,再运
# ⾏ l.backward() 得到该变量有关模型参数的梯度。注意在每次更新完参数后不要忘了将参数的梯度清零。
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.backward() # ⼩批量的损失对模型参数求梯度
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()))
output:
PS F:\Pytorch> f:; cd 'f:\Pytorch'; & 'D:\program\Anaconda3\envs\Opencv\python.exe' 'c:\Users\Administrator\.vscode\extensions\ms-python.python-2022.12.1\pythonFiles\lib\python\debugpy\adapter/../..\debugpy\launcher' '60042' '--' 'f:\Pytorch\test_LinearRegression.py'
tensor([-0.7717, -0.7120], dtype=torch.float64) tensor(5.0800, dtype=torch.float64)
tensor([[-0.5386, 0.5189],
[ 0.1192, 0.2583],
[ 1.5698, 0.1282],
[ 0.2097, 0.1574],
[ 0.3357, -1.2421],
[-1.2881, 0.9988],
[ 1.1337, 0.7982],
[ 0.0722, -1.5144],
[-0.7096, 0.0702],
[ 0.4494, -0.3630]], dtype=torch.float64) tensor([ 1.3563, 3.5482, 6.9283, 4.0891, 9.0797, -1.7926, 3.7620, 9.4906,
2.5574, 6.3390], dtype=torch.float64)
epoch 1, loss 0.026653
epoch 2, loss 0.000089
epoch 3, loss 0.000048
PS F:\Pytorch>