Bootstrap

《昇思25天学习打卡营第7天|模型训练》

 1.数据预处理

  •  
    • 批量化:
      • dataset.batch(batch_size):将数据分批,每批 batch_size 个样本。
    • 应用变换:
      • dataset.map(image_transforms, 'image'):对图像应用上述 image_transforms 变换。
      • dataset.map(label_transform, 'label'):对标签应用 label_transform 变换。
    • 加载数据集:
      • MnistDataset(path):从指定路径加载MNIST数据集。
    • 定义标签变换:
      • transforms.TypeCast(mindspore.int32):将标签转换为 mindspore.int32 类型。
    • 定义图像变换:
      • vision.Rescale(1.0 / 255.0, 0):将像素值从0-255缩放到0-1。
      • vision.Normalize(mean=(0.1307,), std=(0.3081,)):对图像进行归一化,减去均值,除以标准差。
      • vision.HWC2CHW():将图像从HWC(高度、宽度、通道)格式转换为CHW(通道、高度、宽度)格式,这是MindSpore模型所需的输入格式。
    • datapipe 函数:是核心函数,用于构建数据处理管道,包括以下步骤:
    • 使用下载好的数据集对数据进行预处理包括:图像/标签变换、批量化等常见的数据处理步骤。
    • 2.定义网络模型

      • __init__(self): 构造函数,初始化网络层。
      • self.flatten = nn.Flatten(): 创建一个Flatten层,将输入图像展平为一维向量。
      • self.dense_relu_sequential = nn.SequentialCell(...): 创建一个SequentialCell容器,按顺序包含以下层:
        • nn.Dense(28*28, 512): 全连接层,输入维度是 28x28 (MNIST图像尺寸),输出维度是 512。
        • nn.ReLU(): ReLU激活函数。
        • nn.Dense(512, 512): 全连接层,输入维度和输出维度都是 512。
        • nn.ReLU(): ReLU激活函数。
        • nn.Dense(512, 10): 全连接层,输入维度是 512,输出维度是 10 (MNIST的类别数)。
      • construct(self, x): 定义模型的前向传播过程。
      • x = self.flatten(x): 将输入图像展平。
      • logits = self.dense_relu_sequential(x): 将展平后的图像输入到SequentialCell中,得到模型的输出 logits(未经softmax处理的分类分数)。
      • return logits: 返回模型的输出。
    • 3. 定义超参、损失函数和优化器

      • epochs = 3

        batch_size = 64
        learning_rate = 1e-2
        loss_fn = nn.CrossEntropyLoss()
        optimizer = nn.SGD(model.trainable_params(), learning_rate=learning_rate)

      • 超参
        • 超参(Hyperparameters)是可以调整的参数,可以控制模型训练优化的过程,不同的超参数值可能会影响模型训练和收敛速度。
        • 训练轮次(epoch):训练时遍历数据集的次数。
        • 批次大小(batch size):数据集进行分批读取训练,设定每个批次数据的大小。batch size过小,花费时间多,同时梯度震荡严重,不利于收敛;batch size过大,不同batch的梯度方向没有任何变化,容易陷入局部极小值,因此需要选择合适的batch size,可以有效提高模型精度、全局收敛。
        • 学习率(learning rate):如果学习率偏小,会导致收敛的速度变慢,如果学习率偏大,则可能会导致训练不收敛等不可预测的结果。梯度下降法被广泛应用在最小化模型误差的参数优化算法上。梯度下降法通过多次迭代,并在每一步中最小化损失函数来预估模型的参数。学习率就是在迭代过程中,会控制模型的学习进度。
      • 损失函数
        • 损失函数(loss function)用于评估模型的预测值(logits)和目标值(targets)之间的误差。训练模型时,随机初始化的神经网络模型开始时会预测出错误的结果。损失函数会评估预测结果与目标值的相异程度,模型训练的目标即为降低损失函数求得的误差。
      • 优化器
        • 模型优化(Optimization)是在每个训练步骤中调整模型参数以减少模型误差的过程。MindSpore提供多种优化算法的实现,称之为优化器(Optimizer)。优化器内部定义了模型的参数优化过程(即梯度如何更新至模型参数),所有优化逻辑都封装在优化器对象中。在这里,我们使用SGD(Stochastic Gradient Descent)优化器。
    • 4.训练与评估

      • 设置了超参、损失函数和优化器后,我们就可以循环输入数据来训练模型。一次数据集的完整迭代循环称为一轮(epoch)。每轮执行训练时包括两个步骤:

        训练:迭代训练数据集,并尝试收敛到最佳参数。验证/测试:迭代测试数据集,以检查模型性能是否提升。

      • 使用函数式自动微分,需先定义正向函数forward_fn,使用value_and_grad获得微分函数grad_fn。然后,我们将微分函数和优化器的执行封装为train_step函数,接下来循环迭代数据集进行训练即可
      • 定义前向传播函数 (forward_fn)
        • 接受 data(输入数据)和 label(标签)作为输入。
        • 将数据传入模型 (model(data)) 得到输出 logits
        • 使用损失函数 (loss_fn) 计算 logitslabel 之间的损失 loss
        • 返回 losslogits

      • 获取梯度函数 (grad_fn)

        • mindspore.value_and_grad(forward_fn, None, optimizer.parameters, has_aux=True)
          • forward_fn: 前向传播函数。
          • None: 不计算任何参数的梯度,因为我们只关注优化器的参数。
          • optimizer.parameters: 要计算梯度的参数列表,通常是模型的参数。
          • has_aux=True: 表示 forward_fn 返回多个值(这里是 losslogits)。
          • 返回一个函数 grad_fn,它接受 datalabel,返回 (loss, logits) 和对应参数的梯度。

      • 定义单步训练函数 (train_step)

        • 接受 datalabel
        • 调用 grad_fn(data, label) 获取 (loss, logits) 和梯度 grads
        • 使用优化器 (optimizer) 更新模型参数。
        • 返回 loss

      • 定义训练循环 (train_loop)

        • 接受 model(模型)和 dataset(数据集)。
        • size = dataset.get_dataset_size(): 获取数据集大小。
        • model.set_train(): 将模型设置为训练模式。
      • 遍历数据集:
        • for batch, (data, label) in enumerate(dataset.create_tuple_iterator()):
          • 获取当前批次的 datalabel
        • loss = train_step(data, label): 执行单步训练。
        • 打印训练进度(每100个批次打印一次)。
      • 定义测试循环函数 (test_loop)
        • 接受 model(模型)、dataset(数据集)和 loss_fn(损失函数)作为输入。
        • num_batches = dataset.get_dataset_size(): 获取测试集中的批次数。
        • model.set_train(False): 将模型设置为评估模式(关闭 Dropout 等)。
        • 初始化 total(样本总数)、test_loss(总损失)和 correct(正确预测数)为0。
      • 遍历数据集:
        • for data, label in dataset.create_tuple_iterator(): 获取每个批次的 datalabel
        • pred = model(data): 模型对数据进行预测。
        • total += len(data): 累加样本总数。
        • test_loss += loss_fn(pred, label).asnumpy(): 累加损失值。
        • correct += (pred.argmax(1) == label).asnumpy().sum(): 累加正确预测数。
          • pred.argmax(1): 获取预测结果中概率最大的类别索引。
          • (pred.argmax(1) == label): 判断预测是否正确。
          • .asnumpy().sum(): 转换为NumPy数组并求和。
        • test_loss /= num_batches: 计算平均损失。
        • correct /= total: 计算准确率。
        • 打印测试结果:准确率和平均损失。
      • 定义损失函数和优化器
        • loss_fn = nn.CrossEntropyLoss(): 使用交叉熵损失函数,适用于多分类问题。
        • optimizer = nn.SGD(model.trainable_params(), learning_rate=learning_rate): 使用随机梯度下降(SGD)优化器,传入模型的可训练参数和学习率。
      • 训练和测试循环
        • for t in range(epochs): 迭代指定的轮数(epochs)。
          • 打印当前轮数。
          • train_loop(model, train_dataset): 调用之前的 train_loop 函数进行训练。
          • test_loop(model, test_dataset, loss_fn): 调用 test_loop 函数进行测试。
        • 打印 "Done!"。
;