在b站看了一下沐神的视频以及看了一下他的动手深度学习系列)
学到了许多,将自己练习的一下代码放在这里,,和原版的区别应该就是多了一些注释吧。这里就不多加说明一些基本的理论,主要是放代码。
一,线性回归的从零开始实现
主要包括以下几步: 生成数据集 读取数据集 初始化模型参数 定义模型(假设函数) 定义损失函数 定义优化算法 训练
1 数据的生成和读取
#其实第一步应该是按照这些包的,但是这么简单的事情直接去看文档或者视频吧%matplotlib inlineimport randomimport torchfrom d2l import torch as d2l
#构造一个数据集,w[2,-3.4]T,b=4.2,噪声随机def synthetic_data(w,b,num_examples):"""生成y=Xw+b+噪声"""x=torch.normal(0,1,(num_examples,len(w)))#均值为0,方差为1的随机数,大小为n个样本,列数为len(w)y=torch.matmul(x,w)+b #matmul是pytorch的乘法y+=torch.normal(0,0.01,y.shape)return x,y.reshape((-1,1)) #返回一个列向量
true_w=torch.tensor([2,-3.4])true_b=4.2features,labels=synthetic_data(true_w,true_b,1000)
print('features',features[0],'\nlabels:',labels[0]) #查看一下第一行的数字

d2l.set_figsize()d2l.plt.scatter(features[:,(1)].detach().numpy(),labels.detach().numpy(),1);#绘图查看一下两者之间的关系,其中detach这个函数是将数字从计算图中取下来然后可以转换为numpy

##定义一个data_iter函数,该函数接收批量大小,特征矩阵,标签向量作为输入,生成batch_size大小批量def data_iter(batch_size,features,labels):num_examples=len(features)indices=list(range(num_examples))#从0到len(features)-1这么长的数字的一个列表random.shuffle(indices)#随机读取样本,不按照特定顺序,这一步直接是混淆了上一步的indices,如果直接查看random((shuffle)前后indices会发现两者的结果完全不同#print(indices)for i in range(0,num_examples,batch_size): #range(start, stop[, step])batch_indices=torch.tensor(indices[i:min(i+batch_size,num_examples)]) #生成一定长度的向量矩阵的索引位置,比如下面设置的10yield features[batch_indices],labels[batch_indices] #带yield的函数是一个生成器,#虽然和print或者return会很像,但是返回的是迭代对象,不会执行任何代码,data_iter也就变成了一个不会产生正常输出的对象,需要for循环或者使用next()#方法进行读取batch_size=10for x,y in data_iter(batch_size,features,labels):print(x,'\n',y)break
2,初始化模型,损失函数,优化算法,训练
# num_examples=len(features)# indices=list(range(num_examples))# random.shuffle(indices)#定义初始化模型函数w=torch.normal(0,0.01,size=(2,1),requires_grad=True) #均值为,方差为0.01的,2,1的矩阵b=torch.zeros(1,requires_grad=True) #初始值为0
# 定义模型def linreg(x,w,b):"""线性回归模型"""return torch.matmul(x,w)+b #toch.matmul是tensor的乘法
#定义损失函数def squared_loss(y_hat,y):"""均方损失"""return(y_hat-y.reshape(y_hat.shape))**2/2#因为y_hat的维度可能比较高,所以需要将y转换为和它一样的维度才能计算#这个是原本的计算公式
#定义优化算法def sgd(params,lr,batch_size):"""小批量随机梯度下降"""with torch.no_grad():for param in params: #修改参数列表中的参数,lr是学习率param-=lr*param.grad/batch_size #除以批量的大小,其实应该是在上面的loss那里除的,这样就可以计算每个样本的损失,但是这样是等价的param.grad.zero_() #将梯度设置为0,这样就只有新的参数而不是带有旧的梯度,在更新的时候新参数就和旧的梯度无关
#训练lr=0.03num_epochs=10net=linreg #模型,这里面指线性模型,以后可以修改loss=squared_lossfor epoch in range(num_epochs):for x,y in data_iter(batch_size,features,labels):l=loss(net(x,w,b),y) #计算x和y的小批量损失,,先看上面的定义的函数,也就是先做假设函数,然后再计算损失l.sum().backward()sgd([w,b],lr,batch_size) #使用参数的梯度来更新参数with torch.no_grad():train_l=loss(net(features,w,b),labels)print(f'epoch:{epoch+1},loss:{float(train_l.mean()):f}')
print(f'w的估计误差;{true_w-w.reshape(true_w.shape)}')print(f'b的估计误差;{true_b-b}')
二,线性回归的简洁实现
##线性回归的简洁实现,也就是使用框架import numpy as npimport torchfrom torch.utils import data #这里面会有一些处理数据的模块from d2l import torch as d2l
2.1 数据的获取
true_w=torch.tensor([2,-3.4])true_b=4.2num_examples=len(features)features,labels=d2l.synthetic_data(true_w,true_b,num_examples) #数据生成
#批量分割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) #Dataloader函数是随机调取batch_size=10data_iter=load_array((features,labels),batch_size)next(iter(data_iter))
#使用框架的预定义好的层from torch import nn #nn是指神经网络net=nn.Sequential(nn.Linear(2,1))#只需要指定输入的维度是多少,把一些层按照顺序放在一起(sequntial的意思)#初始化模型参数net[0].weight.data.normal_(0,0.1)#使用均值为0,方差为0.01的正太分布替换data的值net[0].bias.data.fill_(0)#设置偏差为0#相当于我们之前手动实现的w,b
#计算均方误差,使用的是MSELoss类,也被称为平方L2范数loss=nn.MSELoss()
#优化算法,SGD实例化trainer=torch.optim.SGD(net.parameters(),lr=0.02) #传入所有的参数以及学习率
num_epochs=5for epoch in range(num_epochs):for x,y in data_iter: #一次一次将总数据中的一部分拿出来l=loss(net(x),y) #首先计算损失函数,和之前不同的是模型自带参数,因此不需要进一步输入参数trainer.zero_grad() #优化器先去除掉梯度l.backward() #然后反向传播,也就是sumtrainer.step() #优化器对模型进行更新d=loss(net(features),labels) #搞完之后对模型进行误差评估print(f'epoch is {epoch+1},loss is {d:f}')
