Pytorch框架下的深度学习------3(线性回归原理及实现)

本文介绍了线性回归问题的基本概念,包括如何通过调整权重和偏置找到最优直线,以及如何使用平方差损失函数和随机梯度下降法进行模型训练。通过Python的PyTorch库,演示了数据集生成、模型构建、损失函数定义和优化过程。
摘要由CSDN通过智能技术生成
#线性回归问题的通俗理解是:从一个数据集中,这个数据集包含一个问题的特征和标签。通过选取合适的直线,使得由这些特征对应的标签大致处在这条直线上。
#找到这条直线的过程就是解这个线性回归问题。
#那又该怎样找到这条直线呢?
#我们设标签为y^,特征为X(由特征构成的向量),每个特征所占的权重为W(由权重构成的向量,因为每个特征影响标签的程度不同),偏置b(增强表达能力)
#y = W*X+b
#其中,特征的值都是确定的,所以变量就是W和b,也就是说,我们要通过调整权重和偏置来找到这条直线
#那又该根据怎样的规则区调整W和b呢?
#我们定义一个损失函数,描述的是标签y^与y之间的差距。回归问题中最常用的是平方差函数1/2(y^-y)^2
#但是我们不能只取一个标签和预测值的损失值,这样是无法将损失这一概念涵盖到整个数据集
#于是我们取数据集中所有标签的损失之和再除以数据个数LOSS=1/n 【(0,n)求和(1/2(y^-y)^2)】这样就可以把损失的概念涵盖到全局
#既然损失函数描述的是预测值和标签之间的差距,那么我们应该减少这个差距才能得到更好的预测
#所以我们就可以根据LOSS和W,b的关系,通过调整W,b来使得LOSS达到最小值
#我们求出LOSS关于W,b的梯度grad(LOSS)=(dW,db)
#梯度描述的是自变量使得因变量变化最快的方向,如果梯度为正就上升最快,为负就下降最快
#我们为了让LOSS变小,应该加对应变量梯度的负数W^ = W - 1/n*d(LOSS)/d(W)
#但我们一般情况下加上学习率p来控制更新权重 W^ = W - (p/n)*d(LOSS)/d(W)
#除此之外,由于每次更新W或b都得遍历一次数据集,这会大大拖慢运行速度,所以一般情况下,我们分批训练,即一次取B个数据
#那么LOSS^就是取B个数据的平方茶和再出B,W^ = W - (p/B)*d(LOSS^)/d(W)
#每次都取B个数据来更新参数,遍历一次数据集称为一个epoch,可以自己设定更新到什么时候为止
import torch
import random
import d2l
# #制作数据集,该数据集包含了1000个特征向量和标签
# def synthetic_data(w,b,num_examples):
#     X = torch.normal(0,1,(num_examples,len(w)))#这里的列必须和权重的维度相等,也就是说每行数据都有两个特征(现实情况下,应该根据特征数量确定权重维度,但我们这里只是作为演示)
#     y = torch.matmul(X,w) + b
#     #在标签中加入噪声,假设该噪声服从均值为0,方差为0.01的正态分布
#     y +=torch.normal(0,0.01,y.shape)
#     return X,y.reshape(-1,1)
#
# #设真实权重为(后续需要通过网络调整到的真实权重)
# true_w = torch.tensor([2,-3.4])
# #设真实偏置为(后续需要通过网络调整到的真实偏置)
# true_b = 4.2
# features,labels = synthetic_data(true_w,true_b,1000)
# #可以发现,我们生成了1000个特征向量,每行特征数量为2以及1000个对应的标签
# print("fetatures:",features[0],"\nlabel:",labels[0])
#
# #读取数据集
# #定义一个函数data_iter()作用是批量化读取数据集,因为我们之前提到过,每次更新W,b时采用小批数据进行更新,可以加快运行速度
# def data_iter(batch_size,features,labels):
#     num_examples = len(features)#获取到特征的长度,注意这里的长度指的是有多少组。我们设置的特征是一组两个特征
#     indices = list(range(num_examples))#创建一个列表,列表长度为num_examples(【0,1,2,3,4....】)
#     random.shuffle(indices)#将该列表打乱(【4,0,1,3,2,....】)
#     for i in range(0,num_examples,batch_size):#步长为batch_size的循环,遍历整个列表
#         batch_indices = torch.tensor(
#                     indices[i:min(i+batch_size,num_examples)])#一次从个indices中截取batch_size个数,索引特征和标签
#         yield features[batch_indices],labels[batch_indices]#获取对应的特征和标签
#
# #主要的思想就是,建立一个和特征组数大小相同的列表,作为后期索引的下标。为了加强随机性,把这个列表打乱
#
# batch_size = 10
# for X,y in data_iter(batch_size,features,labels):
#     print(X, '\n', y)
#
# #初始化参数模型
# w = torch.normal(0,0.0,size=(2,1),requires_grad=True)
# b = torch.zeros(1,requires_grad=True)
#
# #定义模型
# def linreg(X,w,b):   #@save
#     return torch.matmul(X,w) + b
#
# #定义损失函数
# #在总述中提到,我们必须有一个衡量网络是否训练好的标准,由损失函数决定,这里采用均方函数
# def squared_loss(y_hat,y):
#     return (y_hat - y.reshape(y_hat.shape))**2 / 2#注意,此处计算的均方误差只是一个数据的误差,不是batch的
#
# #小批量随机梯度下降
# #之前提到,我们必须要使得损失函数尽可能小,我们唯二能控制的变量就是W,b。所以我们通过计算LOSS对于W,b的梯度来控制W,b从而使得LOSS减小
# #我们使用随机梯度下降的方法
# def sgd(params,lr,batch_size):       #@save
#     with torch.no_grad():
#         for param in params:
#             param -= lr * param.grad / batch_size
#             param.grad.zero_()#这里必须要将之前计算的梯度置零,不然会一直累加
#
# #训练
# lr = 0.03
# num_epochs = 3#遍历三次数据集
# net = linreg
# loss = squared_loss
# 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()
#         sgd([w,b],lr,batch_size)
#     with torch.no_grad():#ptyorch默认会自己计算梯度,而我们实际上自己手动敲了梯度更新代码,所以这里禁止pytorch进行梯度跟踪
#         train_l = loss(net(features,w,b),labels)
#         print(f'epoch{epoch+1},loss{ float(train_l.mean()):.8f}')

#########################################################################################
#实际上pytorch框架有很多API可以帮助我们完成线性回归的模型,所以结下俩我们调用API完成简单的线性回归模型构建#
from torch.utils import data
from d2l import torch as d2l
#生成数据集
true_w = torch.tensor([2,-3.4])
true_b = 4.2
#使用synthetic_data()函数,通过输入真实权重,偏置,数据个数可以自动生成数据集
features,labels = d2l.synthetic_data(true_w,true_b,1000)

#读取数据集
def load_array(data_arrays,batch_size,is_train=True): #@save
    dataset = data.TensorDataset(*data_arrays)#TensorDataset将接收到的数据封装成pytorch数据集
    return data.DataLoader(dataset,batch_size,shuffle=is_train)#DataLoader用于批量加载数据,shuffle决定是否随机抽取

batch_size = 10
data_iter = load_array((features,labels),batch_size)
print(next(iter(data_iter)))#iter()是一个迭代器,一次只访问一组(这里对网络没有实际效果,只是打印出来做展示)例如
#my_list = [1, 2, 3, 4, 5]
# # 将列表转换为迭代器
# my_iterator = iter(my_list)
# # 使用迭代器逐个访问元素
# print(next(my_iterator))  # 输出:1
# print(next(my_iterator))  # 输出:2
# print(next(my_iterator))  # 输出:3
# print(next(my_iterator))  # 输出:4
# print(next(my_iterator))  # 输出:5

#定义模型
from torch import nn
#Sequential()是将多个层连接在一起这里虽然只有一层,但是后期会有很都层,这里做一个铺垫
#Linear()全链接层,传两个参数:1.输入层的形状(特征有两个)2.输出层的形状(输出有一个)
net = nn.Sequential(nn.Linear(2,1))

#初始化模型参数
#net[0]访问net的第一层参数,通过normal,fill来初始化weight和bias(权重和偏置)
net[0].weight.data.normal_(0,0.01)
net[0].bias.data.fill_(0)

#定义损失函数
#直接调用库,调取均方误差
loss = nn.MSELoss()

#定义优化算法
#在optim模块使用SGD(随机梯度下降法),需要传两个参数,一是(w,b)而是学习率lr。可以通过net.parameters()直接访问网络参数
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}')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值