• pytorch基础学习(3)


    1. inplace=True在原对象基础上修改,可以节省内存:
      x = F.relu(x, inplace=True)
    2. 继承nn.Module来定义自己的网络层级结构:网络中的参数不再暴露给用户,也不用去考虑参数初始化的问题。
    3. 区分nn.ReLU和F.relu:这两个是典型的PyTorch的两种API:前者是一个类,类风格的API一般都在torch.nn下,而且以大写字母开头;后者是一个函数,函数很多都在torch.nn.functional下面,全小写字母。
    4. 使用GPU设备
      device = torch.device('cuda:0')
    5. 训练集,测试集,验证集:
      1. 训练集:拿到以后要划分成训练集和验证集,只用训练集来训练,验证集用来以一定的频率对模型的performance做验证,也就是用来防止over-fitting的,在训练过程中可以得到验证集的Loss或者acc.的曲线,在曲线上就能大致判断发生over-fitting的点,选取在这个点之前的模型的参数作为学习到的参数,能让模型有较好的泛化能力。
      2. 测试集:
        1. 一般都是客户用来验收模型的,是拿不到的,在一些比赛里就是用来计算选手模型的score的集合。
        2. 即便拿不到测试集,如果总是能知道样本在测试集上的performance,那么如果用这个performance来调整模型,实际上这时的测试集起到的就是验证集的作用了,这是不对的,让测试集失去意义了,这样训练出的模型根本不知道用哪些样本来判断模型的泛化能力如何了,因此一些比赛总是有提交限制的,就是尽量在避免这种手段刷榜。
    6. 使用正则化项:
      1. ​​​​​​​在训练前设置优化器参数:
        optimizer = optim.SGD(net.parameters(), lr=learning_rate, weight_decay=0.01)
      2. 正则化项目是用来克服over-fitting的,如果网络本身就没有发生over-fitting,那么设置了正则化项势必会导致网络的表达能力不足,引起网络的performance变差。
      3. 使用1L1正则化项,即对所有参数绝对值求和再乘以一个系数:
        1. # 为Loss添加L1正则化项
        2. L1_reg = 0
        3. for param in net.parameters():
        4.     L1_reg += torch.sum(torch.abs(param))
        5.    loss += 0.001 * L1_reg  # lambda=0.001
        注:使用L1正则化项时如果指定和使用L2正则化项时相同的λ = 0.01 发生under-fitting,似乎如果要用L1正则化的话要把其系数设置的小一点,所以这里用了0.001。
    7. 某些优化器(如Adam)内置了momentum,所以没有这个参数,对多数优化器直接设置就可以了,传进去的参数是β的取值。其取值越大则考虑之前的更新方向的程度就越大,取值为0时即相当于没有惯性:
      optimizer = optim.SGD(net.parameters(), lr=learning_rate, momentum=0.78)
    8. 学习率
      1. 在使用梯度更新参数时,学习率如果选取太小的话,学习过程会很慢;’如果学习率选取太大,那么很可能会出现来回抖动的情况,这时最终的模型可能很难收敛,而且看起来和"梯度弥散"的情况也很像
      2. 选取合适的固定的学习率是很难的, 可以在训练的一开始选取比较大的学习率加快训练过程,然后逐渐让其衰减到比较小的值,最终让模型收敛。
      3.  ReduceLROnPlateau
        1. 这个类即用来监控某个量,当其在训练过程中多次没有发生下降(或上升,取决于mode参数)时,就减少学习率。
        2. 首先,在定义优化器时:
          1. from torch.optim.lr_scheduler import ReduceLROnPlateau
          2. optimizer = ......
          3. # 传入优化器让学习率受其管理,当连续200次没有减少loss时就会减少学习率(乘以0.7)
          4. scheduler = ReduceLROnPlateau(optimizer, mode="min", patience=200, factor=0.7)
        3. 在每次训练时,改用这个scheduler来执行.step()方法,并传入要监控的量,这里即是传入计算出的loss:
          1. optimizer.step()
          2. # 传入要监控的量,每调用一次step就会监控一次loss
          3. # 前面定义时的mode="min"即是监控量没有减少时触发减小lr的操作的
          4. scheduler.step(loss)
      4. StepLR
        1. 是固定的每执行step_size个.step()方法,就把学习率乘以gamma即可。
        2. 定义优化器时:
          1. from torch.optim.lr_scheduler import StepLR
          2. optimizer = ......
          3. # 每跑800个step就把学习率乘以0.9
          4. scheduler = StepLR(optimizer, step_size=800, gamma=0.9)
        3. 训练时(注意不用传监控量进去了):
          1. optimizer.step()
          2. scheduler.step()
    9. Early Stop
      1. 如果一直训练,训练集上的性能可以一直上升,但验证集上的性能在经过某个点之后就可能开始下降,这时就是模型出现了over-fitting,提前停止就是用来克服over-fitting的。
      2. 但是没训练完怎么知道哪个点是最大值点呢?可以用经验来判断,比如当连续多个epoch上的验证集Acc.在下降时就停止训练。
    10. dropout使用
      1. 在PyTorch中直接在要加的有连接的相邻两层之间插入Dropout层:nn.Dropout(0.5)
      2. 在train时,模型使用前指明模式:
        1. # 指明使用"训练用"的网络模式,这里的目的是开启使用Dropout
        2. net.train()
        3. logits = net(data)
        4. loss = ......
      3. 在validation或者test时,模型使用前指明模式:
        1. # 在验证集上需要把Dropout去掉,只在训练的时候使用!这里是切换一下模式
        2. net.eval()
        3. logits = net(data)
        4. test_loss += ......
      4. 注意,PyTorch中torch.nn.Dropout()传入的参数是断开的概率,而TensorFlow中tf.nn.dropout()传入的参数是保持连接的概率,即1-断开的概率。
    11. Stochastic Gradient Descent:
      1. 随机梯度下降没有用Random这个词,因为它不是完全的随机,而是服从一定的分布的,只是具有随机性在里面。
      2. Stochastic的意思是从x到y的映射:x → y  给定一个x xx并不能确定地知道输出y,而是服从一定的概率分布。与之对应的是Deterministic这个词,它表示从x xx到y yy的映射是确定的:y=f(x)
      3. SGD是从训练集中随机选出一个比较小的batch(16/32/64/128…甚至可能只有一个样本)出来,在这个小的样本集上用梯度的均值做梯度下降更新参数。而传统的梯度下降则是每次都要考虑在整个训练集上所有样本的梯度。
      4. 使用SGD的原因是训练集样本可能非常多,一方面显存不够把所有样本读进来,另一方面对所有样本计算梯度速度可能太慢了。所以在实际用的时候都不用原始的GD,而是用SGD来做的:
        1. from torch import optim
        2. # ......
        3. optimizer = optim.SGD(net.parameters(), lr=learning_rate, momentum=0.78)
    12. 不属于pytorch的一些笔记(命名空间软件包):
      1. 命名空间软件包是对相关的包或模块进行分组的一种方法,通常是一个被忽略的功能,它对于在较大的项目中构建打包生态系统非常有用。
      2. 如果你的应用组件的开发、打包和版本化都是独立的,但仍然希望从同一个命名空间访问它们,那么命名空间包特别有用,它有利于明确每个包所属的组织或项目。
      3. 命名空间软件包指第三方库可修改,一个正常的第三方库的话,他一般只是可读模式,但是使用命名空间软件包这个方式,可以实现对第三方库进行修改。
        1. pip install -e:以可编辑的模式安装项目
        2. pip install -e .的直接执行对象是当前文件下面的 setup.py 。
        3. setup.py 内包含了执行命令,也就是 安装依赖 和将 命名空间软件 重新安装到包管理器中。
        4. pip install -v:输出更详细的信息

  • 相关阅读:
    【Pandas数据分析5】数据清洗
    Spring Boot 各版本的支持时间
    【图论——第八讲】Kruskal算法求最小生成树问题
    介绍一下浏览器的缓存(Expires, Cache-Control等)
    Unity 一些常用特性收集
    基于 Java 解释一下硬编码和非硬编码?
    Vue3+ts -01
    Redis怎么保证数据不丢失
    ConcurrentDictionary<T,V> 的这两个操作不是原子性的
    数据库事务
  • 原文地址:https://blog.csdn.net/weixin_45647721/article/details/128163182