【轩说Pytorch】线性回归

写在前面的话

笔者在学习过程中,总结了一些不成熟的经验。建议在学习【轩说Pytorch】,【轩说AI】前,学好几门必修的前置内容:

  1. 高等数学
  2. 线性代数
  3. 概率论与数理统计
  4. 吴恩达深度学习课程

前置内容指的是,系统学习过,可能会遗忘,但是大体上不对后续造成影响,一旦需要深挖理论,随时回去看视频课来补充一遍。

线性回归

最简单的神经网络

神经元的含义如下


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-no1lBPTZ-1677730110803)(./线性回归.assets/image-20230302092550314.png)]

Input layer:
X = [ x 1 , x 2 , x 3 ] T X=[x_1,x_2,x_3]^T X=[x1,x2,x3]T
Hidden layer:
W = [ w 1 , w 2 , w 3 ] T z = W T ⋅ X + b = w 1 x 1 + w 2 x 2 + w 3 x 3 + b a = σ ( z ) W=[w_1,w_2,w_3]^T\\ z=W^T\cdot X+b=w_1x_1+w_2x_2+w_3x_3+b\\ a=\sigma(z) W=[w1,w2,w3]Tz=WTX+b=w1x1+w2x2+w3x3+ba=σ(z)
Output layer:
y ^ = a \hat y=a y^=a
在线性回归问题中,激活函数 σ \sigma σ被省略,在Logistic回归中, σ \sigma σ不能被省略

代码

  1. 生成数据

    给定w和b,生成一些数据点 ( x , y ) (x,y) (x,y),数据点满足在 y = w ⋅ x + b y=w\cdot x+b y=wx+b的基础上的一些扰动。目的是将这些数据点 ( x , y ) (x,y) (x,y)送入回归模型后,可以让网络找出正确的w和b(正确拟合出线性关系)。

    def synthetic_data(w,b,num_examples):
            X=torch.normal(mean=0,std=1,size=(num_examples,len(w)))#X:(1000,2)
            y=torch.matmul(X,w)+b#y:matmul((1000,2)*(2))=matmul((1000,2)*(2,1))=(1000,1)=(1000)
            y+=torch.normal(0,0.01,y.shape)#y:(1000)
            return X,y.reshape((-1,1))#X:(1000,2),y(1000,1)
    true_w=torch.tensor([2,-3.4])#这里的w的维度(2)和(2,1),喂给函数的效果是一样的
    true_b=4.2
    features,labels=synthetic_data(true_w,true_b,1000)
    print(features.shape)
    print(labels.shape)
    """
    torch.Size([1000, 2])
    torch.Size([1000, 1])
    """
    
  2. 展示数据

    plt.scatter(features[:,1].detach().numpy(),labels.detach().numpy(),1)
    

  3. 手动生成mini batch

    #小批量-取batch
    def data_iter(batch_size,features,labels):
        num_examples=len(features)#1000
        indices=list(range(num_examples))#[0,1,2,3,...999]
        random.shuffle(indices)#[2,4,99,1,35,...]
        for i in range(0,num_examples,batch_size):
            batch_indices=torch.tensor(indices[i:min(i+batch_size,num_examples)])
            yield features[batch_indices],labels[batch_indices]
    batch_size=10
    next(data_iter(batch_size,features,labels))
    """
    (tensor([[ 0.3100, -1.1480],
             [ 0.9326,  1.7840],
             [ 0.7479, -0.4284],
             [ 0.8382,  2.6512],
             [-0.5357,  0.2354],
             [-0.3393, -1.1224],
             [-0.6993, -1.2861],
             [ 0.0155,  0.9641],
             [-1.1654,  0.7413],
             [ 0.4319,  3.0528]]),
     tensor([[ 8.7037e+00],
             [-7.1615e-03],
             [ 7.1457e+00],
             [-3.1387e+00],
             [ 2.3467e+00],
             [ 7.3261e+00],
             [ 7.1850e+00],
             [ 9.3840e-01],
             [-6.4830e-01],
             [-5.3213e+00]]))
    
    """
    
  4. 初始化参数w和b

    w=torch.normal(0,0.01,size=(2,1),requires_grad=True)
    b=torch.zeros(1,requires_grad=True)
    print(w)
    print(b)
    """
    tensor([[-0.0134],
            [-0.0072]], requires_grad=True)
    tensor([0.], requires_grad=True)
    """
    
  5. 构建线性回归模型(最简单的神经网络),得到输出的y_hat值

    def linreg(X,w,b):#X:(bs,n),w:(n,1),b:(1)
        return torch.matmul(X,w)+b #这里的"+b"用到了broadcast机制
    #定义模型
    
  6. 计算均方损失,用输出的y_hat和真实的label:y做L2损失

    def squared_loss(y_hat,y):
        return (y_hat-y.reshape(y_hat.shape))**2/2
    
  7. 梯度下降,params为模型中的参数,本例中为[w,b]

    #梯度下降法
    def sgd(params,lr):
        with torch.no_grad():#固定梯度。
            for param in params:
                param-=lr*param.grad
                param.grad.zero_()
    
  8. 训练网络

    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):
            y_hat=net(X,w,b)#y_hat:(bs)
            l=loss(y_hat,y)
            l.mean().backward()
            sgd([w,b],lr)
        with torch.no_grad():
            train_l=loss(net(features,w,b),labels)
            print(f'epoch{epoch+1},loss{float(train_l.mean()):f}')
    """
    epoch1,loss0.029799
    epoch2,loss0.000096
    epoch3,loss0.000049
    """
    
  9. 查看网络收敛后的w和b和真值的差距

    print(true_w-w.reshape(true_w.shape))
    print(true_b-b)
    """
    tensor([ 6.5148e-04, -4.6253e-05], grad_fn=<SubBackward0>)
    tensor([0.0003], grad_fn=<RsubBackward1>)
    """
    

可见,可以用单个神经元完成线性回归问题。

简化代码

  1. 导包

    import torch
    from torch.utils import data
    
  2. 用torch.utils.data.TensorDataset(X,Y)来生成数据集,把tensor X(1000,2)和tensor Y(1000,1)一对一地变成 [ ( T ( x 1 ) , T ( y 1 ) ) , ( T ( x 2 ) , T ( y 2 ) ) , ( T ( x 3 ) , T ( y 3 ) ) . . . . . ( T ( x 1000 ) , T ( y 1000 ) ) ] [(T(x_1),T(y_1)),(T(x_2),T(y_2)),(T(x_3),T(y_3)).....(T(x_{1000}),T(y_{1000}))] [(T(x1),T(y1)),(T(x2),T(y2)),(T(x3),T(y3)).....(T(x1000),T(y1000))]相当于一个男女结对的过程

    true_w=torch.tensor([2,-3.4])
    true_b=4.2
    def synthetic_data(w,b,num_examples):
            X=torch.normal(mean=0,std=1,size=(num_examples,len(w)))#X:(1000,2)
            y=torch.matmul(X,w)+b#y:matmul((1000,2)*(2))=matmul((1000,2)*(2,1))=(1000,1)=(1000)
            y+=torch.normal(0,0.01,y.shape)#y:(1000)
            return X,y.reshape((-1,1))#X:(1000,2),y(1000,1)
    data_X,data_Y=synthetic_data(true_w,true_b,1000)#(X,Y)
    dataset=data.TensorDataset(data_X,data_Y)
    #dataset:[(x_1,y_1),(x_2,y_2),(x_3,y_3),(x_4,y_4).....(x_1000,y_1000)]
    

    dataset[0]:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uWYNgspG-1677742599025)(./线性回归.assets/image-20230302152149386.png)]

  3. 调用torch.utils.data.Dataloader(dataset)来产生数据迭代器 [ [ T ( x 1 , x 4 , x 6 , x 199 , x 43 ) , T ( y 1 , y 4 , y 6 , y 199 , y 43 ) ] , [ T ( x . . . . ) , T ( y . . . . ) ] . . . . . . ] [[T(x1,x4,x6,x199,x43),T(y1,y4,y6,y199,y43)],[T(x....),T(y....)]......] [[T(x1,x4,x6,x199,x43),T(y1,y4,y6,y199,y43)],[T(x....),T(y....)]......],相当于把dataset的各个(tensor(x),tensor(y))张量对 按照batchsize大小,随机组合选取出一组组的 [ T e n s o r ( X g r o u p A ) , T e n s o r ( Y g r o u p B ) ] [Tensor(X_{groupA}),Tensor(Y_{groupB})] [Tensor(XgroupA),Tensor(YgroupB)]相当于男女结对之后,入住楼房的过程 。并且需要注意的是,dataloader是迭代器,不像dataset支持下标随机访问,必须通过迭代的方式访问“下一batch”。

    batch_size=10
    data_loader=data.DataLoader(dataset,batch_size,shuffle=True)
    

    next(iter(data_loader)):

  4. 用API产生model

    from torch import nn
    net =nn.Sequential(nn.Linear(2,1))
    
  5. 初始化模型参数

    net[0].weight.data.normal_(0,0.01)
    net[0].bias.data.fill_(0)
    

    pytorch中.weight.data与.weight

    .weight.data:得到的是一个Tensor的张量(向量),不可训练的类型
    .weight:得到的是一个parameter的变量,可以计算梯度的

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KyYmLBe2-1677742599026)(./线性回归.assets/c678adbbed6c49f89bc5c970147c5a30.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aEsaCtcl-1677742599027)(./线性回归.assets/ffea8769c1ec4bdb94f561ee0c435eeb.png)]

  6. 定义均方损失: L ( X , Y ) = 1 n Σ ( X i − Y i ) 2 L(X,Y)=\frac{1}{n}\Sigma(X_i-Y_i)^2 L(X,Y)=n1Σ(XiYi)2

    loss=nn.MSELoss()
    
  7. 定义梯度下降优化器

    trainer=torch.optim.SGD(net.parameters(),lr=0.03)
    
  8. 训练网络

num_epochs=3
for epoch in range(num_epochs):
    for X,y  in data_loader:
        y_hat=net(X)
        l=loss(y_hat,y)
        trainer.zero_grad()
        l.backward()
        trainer.step()
    l=loss(net(data_X),data_y)
    print(f'epoch {epoch+1},loss {l:f}')

  1. 查看网络参数

    print(list(net.parameters()))
    

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值