1.数学原理:
a.线性模型
线性假设是指目标可以表示为特征的加权和,如同式子 的形式,使用矩阵点积进行简洁表示:
对于特征集合,即由一组batch_size大小的抽样组成的集合,常常写作:
注意,对于本章来说,所有均为预测值,在后续的计算中,需要优化的参数为W,b两个参数,这是对线性模型来说的,后续优化的时候的各类优化方法,都是讲W,b优化进入一个评价度最好的参数中去。
b.损失函数
损失函数是一个重要的评价指标,用于表示与实际值的拟合程度,对于简单的线性模型,一般采用平方误差即可,如下:
这个是为了便于求导后系数没那么多,上面这个式子是对单个的预测值与实际值的损失,实际上在一轮计算时候,是需要计算所有的损失的平均值,比如我这有一组输出共计N个y,那么其总的平均损失为
在训练模型的时候,需要找的是平均损失最小的和。
c.解析解
如果讲损失函数看作由x向量之和和y向量之差合成的第三个向量的模,那么很容易发现,在y向量的垂直投影刚好是x向量的加权和之时,就是损失函数最小的时候,这时候得到的解析解为:
这个方法用于存在解析解的时候,但是很多时候不存在解析解,那还是用其他方法
d.minibatch stochastic gradient descent
小批量随机梯度下降法是一种常用的方法,对于小批量随机梯度下降法,我们需要如下参数:
对于w,b的更新如下面式子所示“
注意一个问题,如果被优化的对象较为简单,整个定义域上仅有一个最优值,那这个方法就十分甚至九分的好用,如果有局部最优该怎么办。
2.实现步骤
3.原理实现
导入需要使用的包
"""
学习线性神经网络的
"""
import math
import time
import numpy as np
import torch
from d2l import torch as d2l
import random
生成需要被线性拟合的样本
def synthetic_data(w,b,num_example):
"""y=w.T*x+b+噪声,用这个功能获取input"""
x=torch.normal(0,1,(num_example,len(w)))
#print(x)
"""正态分布函数,0是期望,1是均值"""
y=torch.matmul(x,w)+b
#print(y.shape)
y+=torch.normal(0,0.01,y.shape)
"""这里加个噪声"""
return x,y
"""这玩意是行转列""
true_w=torch.tensor([2,-3.4])
true_b=4.2
feature,labels=synthetic_data(true_w,true_b,1000)
初始化参数模型
"""初始化模型参数"""
w=torch.normal(0,0.01,size=(2,1),requires_grad=True)
b=torch.zeros(1,requires_grad=True)
"""这是需要被计算的w,b的随机初始值"""
"""初始化参数"""
lr=0.03 #学习率
num_epochs=3 #代码周期
net =linreg
loss=loss
定义net,线性回归就是一个简单的模拟神经元,输入加权后得到一个输出
def linreg(x,w,b):
"""定义线性回归模型"""
return torch.matmul(x,w)+b
loss函数:
def loss(y_hat,y):
"""define loss function"""
return (y_hat-y)**2/2
获取每次进行计算的小批量
def data_item(batch_size,feature,labels):
"""minibatch stochastis gradient descent
随机小批量梯度下降法中需要挑选一部分样本"""
num_example=len(feature)
indices=list(range(num_example))
"""获取一个0,1,2,3,4,5,6****的玩意"""
random.shuffle(indices)
"""打乱,注意shuffle只能打乱列表,对于numpy类型的要使用permutation"""
for i in range(0,num_example,batch_size):
# print(i)
batch_indices=torch.tensor(indices[i:min(i+batch_size,num_example)])
yield feature[batch_indices],labels[batch_indices]
"""注意yield的用法,这是生成一个迭代器,当需要的时候进行计算,相当于return,不过要一个一个弹出
可以用next进行弹出,弹出所有的输出后终止"""
"""用于执行多次输出的return""
梯度下降算法
def sgd(params,lr,batch_size):
"""输入的params为[w,b],lr为学习率,batch_size为一次计算中的样本数"""
"""定义stochastic gradient descent"""
with torch.no_grad():
"""with下面为不调用求导的方法,节省算力"""
for param in params:#所有的wb按照梯度进行下降
param -= lr*param.grad/batch_size#[w,b]-grad([w,b])
param.grad.zero_()
训练:
"""开始训练"""
for epoch in range(num_epochs):
"""训练epoch轮"""
for x, y in data_item(batch, feature, labels):
"""每次随机获取十个样本"""
#print(x)
#print(y)
#print("-------------")
l=loss(net(x,w,b),y)
l.sum().backward()#计算了损失函数的梯度
"""反向传播msgd"""
sgd([w,b],lr,batch)
"""输入w,b,学习率,"""
#zz+=1
"""注意下面的都是with里面,with在epoch循环里面"""
with torch.no_grad():
"""如果require_grad打开,会消耗很多资源,这个with下所有的require_grad都将为0"""
train_l=loss(net(feature,w,b),labels)
print(w,b)
print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')
print(w,b)
4.调包实现
需要的包:
import torch
from d2l import torch as d2l
from torch.utils import data
from torch import nn
定义初始数据集,和原理实现是一样的
"""定义初始数据集参数来源"""
true_w=torch.tensor([2,-3.4])
true_b=4.2
features,labels=d2l.synthetic_data(true_w,true_b,1000)
pytorch的数据迭代器
def load_array(data_arrays,batch_size,is_train=True):
"""构造一个小批量的pytorch数据迭代器"""
dataset=data.TensorDataset(*data_arrays)
return data.DataLoader(dataset,batch_size,shuffle=is_train)
"""==============================================================="""
batch_size=10
data_iter=load_array((features,labels),batch_size)
定义net
batch_size=10
data_iter=load_array((features,labels),batch_size
初始化参数模型:
"""初始化参数模型"""
net[0].weight.data.normal_(0,0.01)
net[0].bias.data.fill_(0
定义损失函数和优化方法
loss=nn.MSELoss()
trainer = torch.optim.SGD(net.parameters(), lr=0.03)
"""定义优化方法"""
开始迭代优化:
num_epochs = 3
for epoch in range(num_epochs):
for X, y in data_iter:
l = loss(net(X) ,y)
trainer.zero_grad()
"""梯度清零"""
l.backward()
"""反向传播进行梯度优化"""
trainer.step()
"""更新参数,十分重要"""
l = loss(net(features), labels)
print(f'epoch {epoch + 1}, loss {l:f}')
输出:
w = net[0].weight.data
print('w的估计误差:', true_w - w.reshape(true_w.shape))
b = net[0].bias.data
print('b的估计误差:', true_b - b)