IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    CS229局部线性回归review和实现

    chenxia发表于 2023-05-31 10:40:36
    love 0

    在学习Torch之际,正好结合沐神的《动手学深度学习》和CS229中的局部线性回归讲义实践一下!终于跑通了第一个属于自己的代码!!

    0x01 什么是线性回归?

    在之前的CS229中,线性回归(Linear regression)作为机器学习的Hello world,让我们了解到学习模型(supervised learning algorithm)会包括几个部分:

    1. 数据集(dataset)
    2. 假设(hypothesis)
    3. 损失函数(loss function)
    4. 优化方法(optimization method)

    详细可见 cs229-01线性模型

    0x02 什么是局部线性回归?

    也就是给梯度一个权重

    LSR的描述

    LSR图片示例

    0x03 从零开始的代码实现

    在了解算法的基础上,如何使用代码构建出来是另外一个方面。两者可以是互补的!
    参照Tensorflow2.0 八股文的描述,我们将深度学习网络构建的过程也可以分为几个典型的步骤:

    1. 构建dataset
    2. 根据dataset生成不同的dataloader,方便后续批量梯度下降(batch gradient descent)
    3. 建立Model(根据hypothesis)
    4. 选择损失函数 loss function
    5. 优化器选择
    6. 超参数的设置 lr、epoch、batchsize
    7. 学习过程,批量梯度下降
    8. 评价指标,对于regression的分析常见的包括MSE、MAPE等等

    3.1 定义数据集

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import torch
    import matplotlib.pyplot as plt
    def gen_data(w,b,num_examples):
    """生成y=Xw+b的噪声"""
    # dtype=float
    X = torch.normal(0,1,(num_examples,len(w)),dtype=float)
    y = torch.matmul(X,w)
    y += torch.normal(0,0.01,y.shape,dtype=float)
    # reshape的意义在于将vector变成为matrix,vector应该是N,而matrix是N*1
    return X,y.reshape((-1,1))
    true_w=torch.tensor([2,-3.4],dtype=float)
    true_b=4.2
    features,labels=gen_data(true_w,true_b,1000)
    plt.scatter(features[:,1],labels,1)

    数据集可视化

    3.2 定义数据迭代

    基于Python原生生成的迭代器虽然可以连续的获取不同的小批量,但是执行效率很低,因为此****要求将所有数据加载到内存中,并执行大量的随机内存访问****,所以通常深度学习框架会内置迭代器,用于处理存储在文件中的数据和数据流提供的数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import random
    def data_iter(batch_size,features,labels):
    num_examples = len(features)
    indices = list(range(num_examples))
    # 样本随机读取,没有特定的顺序
    random.shuffle(indices)
    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]

    # batchsize=10
    # for X,y in data_iter(batch_size=batchsize,features=features,labels=labels):
    # '''仅作为测试使用'''
    # print(X,'\n',y)
    # break

    3.3 定义模型

    同时也能够返回对应参数的parameters的size,这里和教科书不一样,我们使用class的方式来建立新的模型。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class network:
    def __init__(self) -> None:
    self.w=torch.normal(0,0.01,size=(2,1),requires_grad=True,dtype=float)
    self.b=torch.zeros(1,requires_grad=True,dtype=float)

    def predict(self,X):
    return torch.matmul(X,self.w)+self.b

    def parameters(self):
    '''返回对应参数的size'''
    return [self.w,self.b]
    model=network()

    3.4 定义损失函数

    Local loss是局部损失函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def get_weight(X,features):
    '''权重分析'''
    diff = X.unsqueeze(-2).unsqueeze(-2)- features.unsqueeze(-2)
    w = torch.exp(-diff**2/0.000002).squeeze(-2).sum(axis=(1,2))
    return w
    def square_loss(y_hat,y):
    return (y_hat-y.reshape(y_hat.shape))**2/2
    # y_hat=model.predict(X)
    # res=square_loss(y_hat,y)
    # res.mean()
    def local_loss(y_hat,y,X):
    new_w=get_weight(X,features)
    return new_w.reshape(shape=(-1,1))*(y_hat-y.reshape(y_hat.shape))**2/2

    3.5 定义优化算法

    在计算机求解优化算法的过程中,我们可以先想一下我们需要什么东西?

    按照梯度下降的方式来进行神经网络的优化过程中,必然需要知道parameters的size,之后是对参数更新之后的长度learning rate,依旧每次下降的batch-size

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def sgd(params,lr,batchsize):
    '''小批量随机梯度下降'''
    # model.eval() 和 with torch.node_grad()区别是什么
    # model.eval()主要用于model的validation过程中,通知dropout和batchnorm层在train
    # val模式之间切换
    # with torch.no_grad()主要是停止autograd模块的工作,起到加速和节省显存的作用
    with torch.no_grad(): #??这是做什么的
    for param in params:
    param -= lr*param.grad/batchsize
    param.grad.zero_()

    3.6 定义超参数

    1
    2
    3
    4
    5
    lr = 0.05
    batchsize=10
    num_epoches = 4
    net = network()
    loss = square_loss

    3.7 开始训练

    1
    2
    3
    4
    5
    6
    7
    8
    9
    for epoch in range(num_epoches):
    for X,y in data_iter(batch_size=batchsize,features=features,labels=labels):
    # l = loss(net.predict(X),y)
    l = local_loss(net.predict(X),y,X)
    l.sum().backward()
    sgd(net.parameters(),lr,batchsize)
    with torch.no_grad():
    train_l=loss(net.predict(features),labels).mean()
    print(train_l)

    3.8 评估模型

    1
    print(net.w)

    模型结果

    0x04 几个注意的点

    1. 数据dtype最好设置float
    2. 注意vector和matrix甚至tensor之间的区别
    3. 在weight计算中的维度的变化来保证broadcasting
    4. with torch.no_grad( )和model.eval( )的区别
    5. 令人惊喜的torch的broadcasting的功能!!


沪ICP备19023445号-2号
友情链接