Pytorch深度学习【四】

优化方法

  • 梯度下降—当一个模型没有显示解
    • 挑选一个初始值 w 0 w_0 w0
    • 重复迭代参数 t = 1 , 2 , 3 t = 1,2,3 t=1,2,3
      w t = w t − 1 − η ∂ ℓ ∂ w t − 1 w_t = w_{t-1}-\eta\frac{\partial\ell}{\partial w_{t-1}} wt=wt1ηwt1
      • 沿梯度方向将增加损失函数值
      • − ∂ ℓ ∂ w t − 1 -\frac{\partial\ell}{\partial w_{t-1}} wt1就是该点处下降最快的方向即为负梯度
      • η \eta η学习率:步长的超参数—在负梯度上下降的长度
        • 学习率太小—计算次数太多—占用计算资源—可能陷入局部最优解
        • 学习率太大—在最优点容易引发震荡,不易于稳定
  • 小批量随机梯度下降
    • 在整个训练集上算梯度太贵
      • 一个深度神经网络模型可能需要很久进行计算
    • 我们可以随机采样b个样本 i 1 , i 2 , … , i b i_1,i_2,\dots,i_b i1,i2,,ib来近似损失
      1 b ∑ i ∈ I b ℓ ( x i , y i , w ) \frac{1}{b}\sum_{i\in I_b}\ell(x_i,y_i,w) b1iIb(xi,yi,w)
    • batch是批量大小,另一个重要的超参数
      • batch太小—计算量太小,不适合并行来最大利用计算资源
      • batch内存消耗增加
    • 总结
      • 梯度下降通过不断沿着反梯度方向更新参数求解—自动求导可以解决
      • 小批量随机梯度下降是深度学习默认的求解算法
      • 两个重要的超参数时批量大小和学习率

pytorch实现线性模型

  • pytorch原始实现线性回归
    • 导入基本包
      !pip install d2l
      %matplotlib inline # 可以在Ipython编译器里直接使用,功能是可以内嵌绘图,并且可以省略掉plt.show()这一步。
      import matplotlib # 画图
      import matplotlib.pyplot as plt
      import random
      import torch
      !pip install matplotlib_inline
      from d2l import torch as d2l
      
    • 构造人工数据集
      • 使用线性模型参数 w = [ 2 , − 3 , 4 ] T w = [2,-3,4]^T w=[2,3,4]T b = 4.2 b = 4.2 b=4.2和噪声项 ϵ \epsilon ϵ生成数据集及其标签:
        y = X w + b + ϵ y = Xw + b + \epsilon y=Xw+b+ϵ
      def synthetic_data(w, b, num_examples):
          """ 生成 y = Xw + b + 噪声 """
          X = torch.normal(0, 1, (num_examples, len(w))) 
          # 生成输入均值为0方差为1的随机数---样本个数为num_examples---列数就是w的长度
          y = torch.matmul(X, w) + b # 生成y
          y += torch.normal(0, 0.01, y.shape) # 生成和y一样的噪音加入
          return X, y.reshape((-1, 1)) # 把y做成一个列向量返回
      true_w = torch.tensor([2, -3.4])
      true_b = 4.2
      features, labels = synthetic_data(true_w, true_b, 1000)
      print(features)
      print(labels)
      plt.scatter(features[:,1].detach().numpy(),labels.detach().numpy(),1) # 画出x和y线性关系
      
    • 定义一个data_iter函数,该函数接受批量大小、特征矩阵和标签向量作为输入,生成大小为batch_size的小批量
      def data_iter(batch_size, features, labels):
      num_examples = len(features) # 有多少个样本
      indices = list(range(num_examples)) # range---生成0-num_examples-1个元素的list
      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] 
          # yield相当于return---调用继续执行,每次调用执行一次且是从上次开始执行
      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 # matmul是矩阵乘向量
    
    • 定义损失函数
      def squared_loss(y_hat, y):
          """均方损失"""
          return (y_hat - y.reshape(y_hat.shape))**2 / 2
    
    • 定义优化算法
      def sgd(params, lr, batch_size): # params---所有参数 lr---学习率 batch_size---批量大小
          """小批量随机梯度下降"""
          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, features, labels):
          l = loss(net(X, w, b), y)
          l.sum().backward()
          sgd([w, b], lr, batch_size) # 使用参数的梯度更新参数
        with torch.no_grad():
          train_l = loss(net(features, w, b), labels)
          print(f'epoch{epoch + 1}, loss {float(train_l.mean()):f}')
      print(f'w的估计误差:{true_w - w.reshape(true_w.shape)}')
      print(f'b的估计误差:{true_b - b}')
      # 使用了 f-strings(也称为格式化字符串文字)这种新式字符串格式化方法。f-strings 由字符 'f' 和一个大括号构成,大括号内可以包含任意的 Python 表达式。
    
  • pytorch简洁实现线性回归模型
    • 包含前期工具包
    !pip install d2l==0.14
    import numpy as py
    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)
    
    • 迭代器
      # 利用pytorch构造的迭代器
    def load_arry(data_arrays, batch_size, is_train=True):
      dataset = data.TensorDataset(*data_arrays) 
      return data.DataLoader(dataset, batch_size, shuffle=is_train)
    batch_size = 10
    data_iter = load_arry((features, labels), batch_size)
    next(iter(data_iter))
    '''
    data_arrays:包含每个样本数据的张量的元组。例如,如果有一个数据集有两个特征(例如“年龄”和“收入”)和一个标签(例如“信用评分”),则 data_arrays 将是一个包含三个张量的元组,其中第一个张量包含所有样本的年龄,第二个张量包含所有样本的收入,第三个张量包含所有样本的信用评分。
    batch_size:每个批次的样本数。例如,如果 batch_size 为 10,则 DataLoader 对象返回的每个批次将包含 10 个样本。
    is_train:布尔值,指示数据是用于训练(True)还是评估(False)。如果 is_train 为 True,则在将数据分成批次之前将对数据进行洗牌。如果 is_train 为 False,则不会对数据进行洗牌,而是按原样返回
    load_arry 函数通过传入数据张量作为参数来创建 TensorDataset 对象。 TensorDataset 类是将多个张量组合成单个数据集对象的数据集类。 它允许您使用整数索引访问每个张量中的数据。然后,该函数通过传入 TensorDataset 对象和批量大小来创建 DataLoader 对象。 DataLoader 类是一个 PyTorch 实用程序,它提供了一种以小批量迭代数据集的便捷方式。 它负责为您打乱数据并将其分成批次。最后,next(iter(data_iter)) 调用从 DataLoader 对象中获取下一批数据。 iter() 函数返回一个迭代器对象,允许您迭代 DataLoader 的元素。 next() 函数从迭代器中检索下一个元素。 在这种情况下,下一个元素是一批示例,表示为张量元组。 批次中的示例数等于指定的批次大小。
    '''
    
    • 使用框架预先定义好的层
    from torch import nn
    net = nn.Sequential(nn.Linear(2, 1))
    # 输入维度为2输出维度为1 Linear是线性层 Sequential其实就是顺序构建神经网络
    
    • 初始化模型参数
    net[0].weight.data.normal_(0, 0.01) # w进行随机分配在正太分布区间内
    net[0].bias.data.fill_(0) # b直接设置为0
    
    • 训练过程
    num_epochs = 3
    for epoch in range(num_epochs):
      for X, y in data_iter:
        l = loss(net(X), y)
        trainer.zero_grad() # 优化器梯度清零
        l.backward()
        trainer.step() # 模型更新
      l = loss(net(features), labels)
      print(f'epoch {epoch + 1}, loss {l : f}')
      # loss {l : f} 是一个字符串格式说明符,用于指定l变量的值在打印时应如何格式化。f表示l应格式化为浮点数。
    
  • 本节一些有意义的思考问题
    • 损失为什么要求平均
      • 可以理解为损失求平均类似于归一化处理,方便学习率的正常调节
    • batchsize越小其实收敛反而越好
    • 随机梯度下降的随机—是指抽样随机
    • 牛顿法和梯度下降两种算法问题

你可能感兴趣的:(深度学习,pytorch,python)