7线性回归
用真实值和预测值的差平方均值
线性回归是对n维输入的加权,外加偏差
使用平方损失来衡量预测值和真实值的差异
线性回归有显示解,可以看做是单层神经网络
8基础优化方法
梯度下降
梯度是使函数值增加最快的方向,负梯度就是使函数值下降最快的方向
等高线图w0的位置是函数值最大的地方,越向内函数值越小
选择学习率不能太小(梯度计算次数过多)也不能太大(会错过需要达到的梯度)
由于每一次计算梯度都需要对整个数据集处理,花费时间较长,因此可以随机采样b个样本来近似损失,b是批量大小。
选择批量大小
9线性回归从零开始实现
创建一个训练样本
def synthetic_data(w,b,num_examples):
X = torch.normal(0,1,(num_examples,len(w)))
#生成一个服从标准正态分布(均值为0,标准差为1)的随机张量X,形状为(num_examples, len(w)),即每一行都是一个样本,每一列都是一个特征。
y = torch.matmul(X,w)+b
#通过torch.matmul(X, w)计算线性模型的预测结果,并将偏差项b加到预测结果中,得到真实的目标值(标签)y
y += torch.normal(0,0.01,y.shape)#生成一个服从均值为0、标准差为0.01的正态分布的张量,随机噪音
return X,y.reshape((-1,1))#-1是让y的行匹配X的行
true_w = torch.tensor([2,-3.4])
#其中第一个元素对应第一个特征的权重,第二个元素对应第二个特征的权重
true_b = 4.2
features, labels = synthetic_data(true_w,true_b,1000)
#这些参数分别表示真实的权重、偏差和生成的数据样本数量
定义一个函数用来接收批量大小,特征矩阵和标签向量作为输入,生成大小为batch_size的批量
def data_iter(batch_size,features,labels):
num_examples = len(features)
indices = list(range(num_examples))
random.shuffle(indices)
#随机打乱列表indices
for i in range(0,num_examples,batch_size):
batch_indices = torch.tensor(
indices[i:min(i+batch_size,num_examples)])
#min(i+batch_size, num_examples) 是批次的结束索引。其中,i+batch_size 表示批次的结束位置,
# 但如果超过了总样本数量 num_examples,则取 num_examples 作为结束位置
yield features[batch_indices],labels[batch_indices]
#使用 yield 关键字生成一个迭代器对象意味着函数会返回一个迭代器,通过迭代器可以逐个地获取函数生成的值,而不是一次性返回所有值。
#在这段代码中,yield 表示每次迭代会生成一个包含当前批次的输入特征矩阵和目标值的元组。
batch_size = 10
for X,y in data_iter(batch_size,features,labels):
print(X,'\n',y)
break
定义初始化模型参数
w = torch.normal(0,0.01,size=(2,1),requires_grad=True)
#torch.normal 函数用于从指定的正态分布中随机采样张量的值。这里的正态分布具有均值 0 和标准差 0.01
#requires_grad=True 表示张量的梯度将会被计算和保留,这样可以在模型训练时进行梯度更新。
b = torch.zeros(1,requires_grad=True)
定义线性模型
def linreg(X,w,b):
'''线性回归模型'''
return torch.matmul(X,w)+b
定义损失函数
def squared_loss(y_hat,y):
'''均方损失'''
return(y_hat-y.reshape(y_hat.shape))**2/2
#y.reshape(y_hat.shape) 将目标值 y 重塑(reshape)为与预测值 y_hat 相同的形状。
定义参数优化函数
def sgd(params,lr,batch_size):
#参数w,b,xuexilv,批量
'''小批量随机梯度下降'''
with torch.no_grad():
#在计算梯度时不需要计算梯度,禁止梯度跟踪
for param in params:
param -= lr*param.grad / batch_size
#根据梯度下降算法的更新规则,更新每个参数的值
param.grad.zero_()
#梯度是累积的,需要在每次更新之后将梯度清零,否则梯度会持续累积。
一个完整的训练过程
for epoch in range(num_epochs):
for X,y in data_iter(batch_size,features,labels):
l = loss(net(X,w,b),y)#算真实值和预测值的偏差
l.sum().backward()
#希望使用整个批量的损失值来计算梯度和更新模型参数,而不是逐个样本地计算梯度和更新参数
#.backward() 方法来执行自动求导和反向传播操作
sgd([w,b],lr,batch_size)
with torch.no_grad():
train_1 = loss(net(features,w,b),labels)
print(f'epoch{epoch+1},loss{float(train_1.mean()):f}')
'''epoch1,loss0.054659
epoch2,loss0.000247
epoch3,loss0.000051'''
1.内部的 for 循环用于遍历训练数据集的小批量样本,并计算每个小批量样本的损失(偏差)。这些损失值被用于执行反向传播和参数更新,以优化模型的参数。
而在 for 循环外部的这部分代码:
train_1 = loss(net(features, w, b), labels)
print(f'epoch {epoch+1}, loss {float(train_1.mean()):f}')
是用于在每个训练轮次结束后,计算整个训练集上的平均损失,并将其输出到控制台。
2. f‘’是为了保证打印出浮点数
10线性回归的简洁实现
创建一个训练样本
def synthetic_data(w,b,num_examples):
X = torch.normal(0,1,(num_examples,len(w)))
#生成一个服从标准正态分布(均值为0,标准差为1)的随机张量X,形状为(num_examples, len(w)),即每一行都是一个样本,每一列都是一个特征。
y = torch.matmul(X,w)+b
#通过torch.matmul(X, w)计算线性模型的预测结果,并将偏差项b加到预测结果中,得到真实的目标值(标签)y
y += torch.normal(0,0.01,y.shape)#生成一个服从均值为0、标准差为0.01的正态分布的张量,随机噪音
return X,y.reshape((-1,1))#-1是让y的行匹配X的行
true_w = torch.tensor([2,-3.4])
#其中第一个元素对应第一个特征的权重,第二个元素对应第二个特征的权重
true_b = 4.2
features, labels = synthetic_data(true_w,true_b,1000)
#这些参数分别表示真实的权重、偏差和生成的数据样本数量
调用框架中现有的API来读取数据
'''调用框架中现有的API来读取数据'''
def load_array(data_arrays,batch_size,is_train=True):
dataset = data.TensorDataset(*data_arrays)
#创建了一个 TensorDataset 对象,该对象接受一个或多个张量作为输入,并将它们封装为一个数据集
return data.DataLoader(dataset,batch_size,shuffle=is_train)
#创建了一个数据加载器对象 DataLoader,它接受一个数据集对象 batch_size 指定了每个小批量样本的大小,
# shuffle=is_train 表示在训练模式下是否打乱数据顺序。
batch_size = 10
data_iter = load_array((features,labels),batch_size)
next(iter(data_iter))
#将数据加载器 data_iter 转换为一个迭代器对象,并使用 next() 函数获取迭代器的下一个元素。
模型定义及初始化w,b
'''模型定义'''
net = nn.Sequential(nn.Linear(2,1))
#线性层输入特征维度为 2,输出特征维度为 1 的权重矩阵和偏置向量。
'''初始化模型参数'''
net[0].weight.data.normal_(0,0.01)
#weight就是w,用均值为 0,标准差为 0.01 的正态分布进行初始化,替换原来的w
net[0].bias.data.fill_(0)
#用0来替换b的值
计算均方误差使用的是MSELoss类
'''损失'''
loss = nn.MSELoss()
实例化sgd优化
'''实例化sgd'''
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()
#这行代码执行参数更新。它使用优化器 trainer 来更新模型的参数,通过优化算法(如梯度下降)来最小化损失函数。
l = loss(net(features),labels)
print(f'epoch{epoch+1},loss{1:f}')