• torch函数学习


    torch函数学习

    mask取值

    在这里插入图片描述

    如果取值的数组类型是bool则按照mask取值,如果是long,则按照数组中的标号取值
    注意,这里的mask取值会减少数组的纬度,只取mask数组中为1的数。
    如果mask是bool,则它与masked_select函数相同

    如果不行降低原始组维数,并修改对应为true的元素时,可用x.masked_scatter_(mask,re)

    运算

    最简单且最有用的操作是按元素(elementwise)运算。 它们将标准标量运算符应用于数组的每个元素。 对于将两个数组作为输入的函数,按元素运算将二元运算符应用于两个数组中的每对位置对应的元素
    c =a + b 是数组中每个元素位置运算,如果纬度不同,可以结合广播运算

    怎么判断维数

    在这里插入图片描述
    有几个’['就由几维

    初始化tensor

    x = torch.arange(12)
    torch.zeros((2, 3, 4))
    torch.ones((2, 3, 4))
    torch.randn(3, 4)
    torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
    
    • 1
    • 2
    • 3
    • 4
    • 5

    len 和 size的区别

    len()是最近一维的大小
    x.size是整个张量的维数
    在这里插入图片描述

    torch.normal

    生成随机数
    生成张量的数组
    维数比生成维数多1
    但是在用[]访问元素时
    [0]返回的是第0个张量
    而不是整个张量数组。

    索引和切片

    切片维数的判断

    features[:] = feature
    feature[1:2]

    feature[:1],feature[1]是有区别的 feature[:1]是第一行的张量数组[[x]],而feature[1]是第一行的张量[x]

    feature[:1]隐含的是[0,1)是一段,feature的维数等于feature[:1]的维数。feature[1]是feature中的第1个tensor,被拎出来的,因此feature[1]的维数是feature的维数减1.
    总结来讲,只要见到":"维数不减,见不到“:”维数减1
    如:
    在这里插入图片描述
    X[0:1]是取0这一段,X[0]是取0这个张量
    再如:取最后一列
    在这里插入图片描述
    再总结
    如何有效判断数据的维数变化:
    带":“号是在原始纬度上取维数,不带”:"是减掉该维数
    如上面的例子
    X是[3,2,2],
    X[0:1,:,1:2] 后 变成 [1,2,1]
    X[0,:,1] 后 变成 [2]

    "::"是什么

    双::表示的是跳n取一个数:

    >>> range(10)[::2]
    [0, 2, 4, 6, 8]
    
    • 1
    • 2

    跳2取数
    seq[start : end : step]

    >>> range(100)[5:18:2]
    [5, 7, 9, 11, 13, 15, 17]
    
    • 1
    • 2

    在5到8之间跳2取数。

    特殊例子 负数

    [-3:-1]是最后一个到倒数第三个前闭后开
    [::-1] 正1是从头到尾跳1取值,-1是从尾到头跳1取值。

    "…"符号

    有时候tensor张量的维数较大,我们只想动最后几维,一直使用::占空间,因此用省略号代替之前所有维数都保留。
    在这里插入图片描述

    自动求导

    在获得梯度前要调用backward()
    y.backward()
    x.grad
    
    • 1
    • 2

    在这里插入图片描述

    grad.zero_()清理之前累积计算的梯度
    # 在默认情况下,PyTorch会累积梯度,我们需要清除之前的值
    x.grad.zero_()
    y = x.sum()
    y.backward()
    x.grad
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    梯度是累加的,如果不清0则出现错误
    连续backward让梯度累加
    在这里插入图片描述
    计算新梯度前应grad.zero_()
    在这里插入图片描述

    grad can be implicitly created only for scalar outputs

    在这里插入图片描述
    向量的对向量的导数是矩阵,而pytorch仅支持计算标量的导数,通常用sum()将向量转化为标量再求导

    分离计算

    我们不行求某部分的导数时要对它进行标记
    我们不想计算y部分的导数,因此使用detach()
    在这里插入图片描述

    梯度震荡时的处理

    代码
    import torch
    import random
    from d2l import torch as d2l
    
    # 生成数据
    def synthetic_data(w,b,num_examples):
        ''' 生成Y=Xw+b + 噪声'''
        X = torch.normal(0,10,(num_examples,len(w)))
        Y = torch.matmul(X,w)+b
        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,num_examples=1000)
    print('features',features[0],"\nlable:",labels[0])
    a = ([1,2])
    b = ([1,2])
    d2l.set_figsize()
    d2l.plt.scatter(a,b,1)
    
    d2l.set_figsize()
    d2l.plt.scatter(features[:,1].detach().numpy(),labels.detach().numpy(),1)
    
    # 数据输入
    #print(features[:,1].detach().numpy().size)
    print(len(features))
    #a = torch.normal(0,10,(1,2))
    a = features[:]
    print(a)
    print(a.size())
    print(len(a))
    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]
    batch_size = 10
    for X,y in data_iter(batch_size,features,labels):
        print(X,"\n",y)
        break
    
    
    # 建立模型
    # 随机初始化
    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
    
    # 定义lossFuction
    def squared_loss(y_hat,y):
        return (y_hat-y.reshape(y_hat.shape))**2/2
    
    # 梯度下降求解
    def sgd(params, lr, batch_size):  #@save
        """小批量随机梯度下降"""
        with torch.no_grad():#有什么用
            for param in params:
                param -= lr * param.grad / batch_size
                param.grad.zero_()##
    def sgd1(params,lr,batch_size):
        with torch.no_grad():
            for param in params:
                param = param - lr*param.grad/batch_size
                param.grad.zero_()
    # 训练过程
    lr = 0.003
    num_epochs = 3
    net = linreg
    loss = squared_loss
    
    for epoch in range(0,num_epochs):
        # batch size
        for X,y in data_iter(batch_size,features,labels):
            # 建立映射
            #print(X.shape)
            l = loss(net(X,w,b),y)
            # 反向传播
            l.sum().backward()#backward() 之后 grad才会计算
            #print(w)
            #print(l.sum())
    
            # 参数更新
            sgd([w,b],lr,batch_size)
        with torch.no_grad():
            #lr /= 2
            #print(w)
            train_l = loss(net(features,w,b),labels)
            print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')
            
    
    # 调参
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    问题

    w的初值是0,当我生成数据的样本在0-1( X = torch.normal(0,1,(num_examples,len(w))))时 ,训练正常:
    在这里插入图片描述
    但当生成数据样本在0-10时,此时出现不收敛情况:
    在这里插入图片描述
    打印出批量的loss时发现:
    误差很大且在震荡
    在这里插入图片描述
    打印出批量的梯度时发现:
    很大且在震荡
    在这里插入图片描述
    出现了发散的情况。

    分析

    sgd梯度下降的梯度来自:
    d||L|| = L* x
    在这里插入图片描述
    可以看到梯度是loss L的倍数,如果初始迭代的L就比较大,导致梯度也比较大,偏离真值,使得下一次L更大,一直恶性循环导致发散结果。

    解决
    1. 不用sdg了
    2. 调整步长,当梯度下降时,如果出现震荡现象就是步长不合适,调小学习率lr,让loss刚开始很小,就可以防止发散。实验表明这种方法可以解决这一问题:
      调整学习率为0.003
      在这里插入图片描述
      调整为0.0003
      在这里插入图片描述
      动态调整,逐步提升学习率
      在这里插入图片描述
      在这里插入图片描述
      动态调整,逐步降低学习率
      在这里插入图片描述
      在这里插入图片描述
      虽然此时loss为4,4左右但w已经收敛到真值
      在这里插入图片描述
      可以看到当,样本噪声变大,(0-10)的正太分布要比(0-1)的样本的绝对噪声的幅值要大很多,收敛的loss也没有(0-1)大。
    启发

    1.当问题发散时,可以调整学习率,说明初始l太大,sgd方法虽然收敛快,但需要初始loss不要太大(初值要好)。
    2.问题的噪声越大,越复杂,收敛时(最小值)的能量就越大。

    神经网络训练(pytorch)

    要点:

    1. 前向传播(包括loss和net)
    2. 求梯度(自动)
    3. 优化方法(自动)
    num_epochs = 3
    #过程:
    #  计算Loss
    #  更新参数
    for epoch in range(num_epochs):
        for X,y in data_iter:
            l = loss(net(X),y)# 前向传播 (网络结构)-net,lossFunction
            trainer.zero_grad()# 
            l.backward()# sum可以省掉 #后向传播
            trainer.step()#更新梯度(优化方法)-优化方法
        l = loss(net(features),labels)
        print(f'epoch {epoch + 1}, loss: {l}')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    4.2 实现基于栈的表达式求值计算器(难度4/10)
    2023-09-07力扣每日一题
    C语言学习(十一)之字符输入/输出
    IDEA转换编码格式
    C和指针 第15章 输入/输出函数 15.6 打开流
    在互联网上少了这一步,你就别想着赚钱?
    【iOS开发】——Category底层原理、Extension、关联对象
    难以理解:摄像头APP,我测试好好的,发给别人就用不了
    Unity中location和rotation赋值和更改
    Oracle查看与修改隐藏参数
  • 原文地址:https://blog.csdn.net/fb_help/article/details/126780197