线性回归的框架实现和非框架实现

这是看了李沐大神的动手深度学习,自己敲了一遍,直接上代码吧,注释已经写的很清楚了

用pytorch实现

import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l

"""生成数据集"""
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000)

def load_array(data_arrays,batch_size,is_train=True):
    """构造一个pytorch数据迭代器"""
    #data.TensorDataset可以将输入的两类数据一一对应,data_arrays前面有*是元组解包
    dataset = data.TensorDataset(*data_arrays)
    # DataLoader将数据重新排序,每次随机选batch_size个出来
    return data.DataLoader(dataset,batch_size,shuffle=is_train)

batch_size=10
data_iter = load_array((features,labels),batch_size)

next(iter(data_iter))  #转成python中的迭代器,通过next每次得到一个x和y

"""定义模型"""
from torch import nn
#Sequential相当于一个各种层的列表(list of layer),这里只有一个线性层
net = nn.Sequential(nn.Linear(2,1))

"""初始化模型参数"""
# net[0]访问到了线性层,再加上.weight访问到了详细层的权重,也就是w,再加.data访问到了w的值
# 再加.normal_就是要用均值为0,方差为0.01的正态分布值来初始化权重
net[0].weight.data.normal_(0,0.01)
#将线性层的偏差的值(也就是b的值)全部填充为0
net[0].bias.data.fill_(0)

"""使用均方误差"""
loss =nn.MSELoss()

"""实例化SGD实例"""
#net.parameters()包括所有的参数,包括w和b
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()  #首先将梯度清0
        l.backward()   #计算梯度
        trainer.step()  #进行模型更新
    l = loss(net(features), labels)  #计算所有的loss
    print(f'epoch {epoch + 1}, loss {l:.8f}')

不用pytorch

import torch
import random
def synthetic_data(w,b,num_examples):
    '''自己造一个数据集,生成y=Xw+b+噪声'''
    
    #生成num_examples个均值为0,方差为1的样本,每个样本的长度为w的长度
    X=torch.normal(0,1,(num_examples,len(w)))
    y=torch.matmul(X,w)+b   #计算出y
    y = y+torch.normal(0,0.01,y.shape)  #产生噪声
    return X,y.reshape((-1,1))  #将y转换成一列返回

true_w = torch.tensor([[2],[-3.4]])  # y=2*x1-3.4*x2+4.2
print(true_w.size())
true_b = 4.2
feature,labels = synthetic_data(true_w,true_b,1000)
feature
“”“
feature的结果
tensor([[ 2.1414, -1.1311],
        [ 1.6006, -0.3353],
        [ 1.5872,  1.7699],
        ...,
        [ 0.3235,  0.6810],
        [ 0.8720,  0.5016],
        [ 0.4405,  0.2278]])
”“”

%matplotlib inline
from d2l import torch as d2l
d2l.set_figsize()
#画图 可以看到feature的第零列和label呈正相关  这里的detach是要把他从计算图里面拿出来才能转为numpy
d2l.plt.scatter(feature[:,0].detach().numpy(),labels.detach().numpy(),1)
# 该函数接受批量大小,特征矩阵和向量标签作为输入,生成batch_size的小批量
def data_iter(batch_size,feature,labels):
    num_examples = len(feature)
    #将列表随机打乱, 读取样本时候是随机的,没有特定顺序
    indices = list(range(num_examples))  
    random.shuffle(indices)
    
    for i in range(0,num_examples,batch_size):
        #batch_indices是每次取的随机样本的范围,比如第1到第11个,第5到第15个这样
        batch_indices = torch.tensor(indices[i:min(i+batch_size,num_examples)])
        #yield是python中的构造器,会不断产生feature[batch_indices]和labels[batch_indices]
        yield feature[batch_indices],labels[batch_indices]
        
batch_size=10

for X,y in data_iter(batch_size,feature,labels):
    print(X,'\n',y)
    break


# 初始化w和b,均需要计算梯度,因此后面的参数为True
w = torch.normal(0,0.01,size=(2,1),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  #这里返回的是一个向量,没有求均值,也没有求和


def sgd(params,lr,batch_size):  #params是一个list,里面包含w和b
    """小批量随机梯度下降"""
    with torch.no_grad():
        for param in params:
            param -= lr*param.grad/batch_size    #在这里求了梯度的均值,和在均方损失里面求是一样的
            param.grad.zero_()   #梯度清0
            
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,feature,labels):
        #这里'l'的形状为batch_size*1的一个向量,因为loss函数返回的是一个向量
        l = loss(net(X,w,b),y)  #求出小批量的损失
        l.sum().backward()
        sgd([w,b],lr,batch_size)  #更新w和b
    #计算真实的loss
    with torch.no_grad():  #不需要计算梯度
        #feature是整个真实的数据,传入net中,计算和真实labels的损失,前面的X是随机的小批量样本
        train_loss = loss(net(feature,w,b),labels) 
        print(f'epoch {epoch + 1}, loss {float(train_loss.mean()):f}')

print(w)
print("w的估计误差:"+str(true_w-w.reshape(true_w.shape)))
print(b)
print("b的估计误差:"+str(true_b-b))

print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}')
print(f'b的估计误差: {true_b - b}')

补充

Python中的解包:https://zhuanlan.zhihu.com/p/351369448
小批量随机梯度下降
在整个训练集上求梯度太贵也太慢了,深度学习中往往需要花费数个小时,随机采取b个样本来近似看做整体的损失
线性回归的框架实现和非框架实现_第1张图片

b的大小是一个很重要的超参数,对应代码里面的batch_size

你可能感兴趣的:(深度学习,线性回归,pytorch,深度学习)