作者: fchollet
创建日期: 2023/06/25
最后修改日期: 2023/06/25
描述: 在 PyTorch 中编写低级别的训练和评估循环。
import os
# 本指南只能使用 torch 后端运行。
os.environ["KERAS_BACKEND"] = "torch"
import torch
import keras
import numpy as np
Keras 提供了默认的训练和评估循环,fit()
和 evaluate()
。
它们的用法在指南 使用内置方法的训练与评估 中有介绍。
如果您想在利用 fit()
的便利性的同时自定义模型的学习算法
(例如,使用 fit()
训练 GAN),您可以继承 Model
类并
实现自己的 train_step()
方法,该方法在 fit()
期间会被反复调用。
现在,如果您想对训练和评估进行非常低级的控制,您应该从头编写自己的训练和评估循环。这就是本指南的内容。
要编写自定义训练循环,我们需要以下成分:
keras.optimizers
优化器,
或者使用来自 torch.optim
的本地 PyTorch 优化器。keras.losses
的损失,
或者使用来自 torch.nn
的本地 PyTorch 损失。tf.data.Dataset
,
PyTorch 的 DataLoader
,Python 生成器等等。让我们将它们排列好。我们将在每种情况下使用本地 torch 对象 – 当然,Keras 模型除外。
首先,让我们获取模型和 MNIST 数据集:
# 我们考虑一个简单的 MNIST 模型
def get_model():
inputs = keras.Input(shape=(784,), name="digits")
x1 = keras.layers.Dense(64, activation="relu")(inputs)
x2 = keras.layers.Dense(64, activation="relu")(x1)
outputs = keras.layers.Dense(10, name="predictions")(x2)
model = keras.Model(inputs=inputs, outputs=outputs)
return model
# 创建并加载 MNIST 数据集并放入 torch DataLoader
# 准备训练数据集。
batch_size = 32
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train = np.reshape(x_train, (-1, 784)).astype("float32")
x_test = np.reshape(x_test, (-1, 784)).astype("float32")
y_train = keras.utils.to_categorical(y_train)
y_test = keras.utils.to_categorical(y_test)
# 保留 10,000 个样本用于验证。
x_val = x_train[-10000:]
y_val = y_train[-10000:]
x_train = x_train[:-10000]
y_train = y_train[:-10000]
# 创建 torch 数据集
train_dataset = torch.utils.data.TensorDataset(
torch.from_numpy(x_train), torch.from_numpy(y_train)
)
val_dataset = torch.utils.data.TensorDataset(
torch.from_numpy(x_val), torch.from_numpy(y_val)
)
# 为数据集创建 DataLoader
train_dataloader = torch.utils.data.DataLoader(
train_dataset, batch_size=batch_size, shuffle=True
)
val_dataloader = torch.utils.data.DataLoader(
val_dataset, batch_size=batch_size, shuffle=False
)
接下来,这是我们的 PyTorch 优化器和损失函数:
# 实例化一个 torch 优化器
model = get_model()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
# 实例化一个 torch 损失函数
loss_fn = torch.nn.CrossEntropyLoss()
让我们使用自定义训练循环通过小批量梯度训练我们的模型。
在损失张量上调用 loss.backward()
会触发反向传播。
完成后,您的优化器会神奇地知道每个变量的梯度
并可以更新其变量,通过调用 optimizer.step()
完成。
张量、变量、优化器通过隐藏的全局状态相互连接。
此外,别忘了在 loss.backward()
之前调用 model.zero_grad()
,否则您将无法
获得变量的正确梯度。
以下是我们的训练循环,逐步进行:
for
循环以遍历纪元for
循环以遍历数据集,按批处理loss.backward()
以epochs = 3
for epoch in range(epochs):
for step, (inputs, targets) in enumerate(train_dataloader):
# 正向传播
logits = model(inputs)
loss = loss_fn(logits, targets)
# 反向传播
model.zero_grad()
loss.backward()
# 优化器变量更新
optimizer.step()
# 每100个批次记录一次日志。
if step % 100 == 0:
print(
f"训练损失(每批次)在步骤 {step}: {loss.detach().numpy():.4f}"
)
print(f"迄今为止看到: {(step + 1) * batch_size} 个样本")
训练损失(对于1个批次)在步骤0: 110.9115
已查看: 32个样本
训练损失(对于1个批次)在步骤100: 2.9493
已查看: 3232个样本
训练损失(对于1个批次)在步骤200: 2.7383
已查看: 6432个样本
训练损失(对于1个批次)在步骤300: 1.6616
已查看: 9632个样本
训练损失(对于1个批次)在步骤400: 1.5927
已查看: 12832个样本
训练损失(对于1个批次)在步骤500: 1.0992
已查看: 16032个样本
训练损失(对于1个批次)在步骤600: 0.5425
已查看: 19232个样本
训练损失(对于1个批次)在步骤700: 0.3308
已查看: 22432个样本
训练损失(对于1个批次)在步骤800: 0.8231
已查看: 25632个样本
训练损失(对于1个批次)在步骤900: 0.5570
已查看: 28832个样本
训练损失(对于1个批次)在步骤1000: 0.6321
已查看: 32032个样本
训练损失(对于1个批次)在步骤1100: 0.4962
已查看: 35232个样本
训练损失(对于1个批次)在步骤1200: 1.0833
已查看: 38432个样本
训练损失(对于1个批次)在步骤1300: 1.3607
已查看: 41632个样本
训练损失(对于1个批次)在步骤1400: 1.1250
已查看: 44832个样本
训练损失(对于1个批次)在步骤1500: 1.2562
已查看: 48032个样本
训练损失(对于1个批次)在步骤0: 0.5181
已查看: 32个样本
训练损失(对于1个批次)在步骤100: 0.3939
已查看: 3232个样本
训练损失(对于1个批次)在步骤200: 0.3406
已查看: 6432个样本
训练损失(对于1个批次)在步骤300: 0.1122
已查看: 9632个样本
训练损失(对于1个批次)在步骤400: 0.2015
已查看: 12832个样本
训练损失(对于1个批次)在步骤500: 0.1184
已查看: 16032个样本
训练损失(对于1个批次)在步骤600: 1.0702
已查看: 19232个样本
训练损失(对于1个批次)在步骤700: 0.4062
已查看: 22432个样本
训练损失(对于1个批次)在步骤800: 0.4570
已查看: 25632个样本
训练损失(对于1个批次)在步骤900: 1.2490
已查看: 28832个样本
训练损失(对于1个批次)在步骤1000: 0.0714
已查看: 32032个样本
训练损失(对于1个批次)在步骤1100: 0.3677
已查看: 35232个样本
训练损失(对于1个批次)在步骤1200: 0.8291
已查看: 38432个样本
训练损失(对于1个批次)在步骤1300: 0.8320
已查看: 41632个样本
训练损失(对于1个批次)在步骤1400: 0.1179
已查看: 44832个样本
训练损失(对于1个批次)在步骤1500: 0.5390
已查看: 48032个样本
训练损失(对于1个批次)在步骤0: 0.1309
已查看: 32个样本
训练损失(对于1个批次)在步骤100: 0.4061
已查看: 3232个样本
训练损失(对于1个批次)在步骤200: 0.2734
已查看: 6432个样本
训练损失(对于1个批次)在步骤300: 0.2972
已查看: 9632个样本
训练损失(对于1个批次)在步骤400: 0.4282
已查看: 12832个样本
训练损失(对于1个批次)在步骤500: 0.3504
已查看: 16032个样本
训练损失(对于1个批次)在步骤600: 0.3556
已查看: 19232个样本
训练损失(对于1个批次)在步骤700: 0.7834
已查看: 22432个样本
训练损失(对于1个批次)在步骤800: 0.2522
已查看: 25632个样本
训练损失(对于1个批次)在步骤900: 0.2056
已查看: 28832个样本
训练损失(对于1个批次)在步骤1000: 0.3259
已查看: 32032个样本
训练损失(对于1个批次)在步骤1100: 0.5215
已查看: 35232个样本
训练损失(对于1个批次)在步骤1200: 0.8051
已查看: 38432个样本
训练损失(对于1个批次)在步骤1300: 0.4423
已查看: 41632个样本
训练损失(对于1个批次)在步骤1400: 0.0473
已查看: 44832个样本
训练损失(对于1个批次)在步骤1500: 0.1419
已查看: 48032个样本
作为替代,让我们看看使用Keras优化器和Keras损失函数时循环的样子。
重要区别:
v.value.grad
来获取变量的梯度,调用在每个可训练变量上。optimizer.apply()
来更新变量,这必须在 torch.no_grad()
范围内调用。另外一个大陷阱: 尽管所有的NumPy/TensorFlow/JAX/Keras API以及Python unittest
API都使用参数顺序约定 fn(y_true, y_pred)
(参考值在前,预测值在后),PyTorch 实际上为其损失使用 fn(y_pred, y_true)
。因此,请确保反转 logits
和 targets
的顺序。
model = get_model()
optimizer = keras.optimizers.Adam(learning_rate=1e-3)
loss_fn = keras.losses.CategoricalCrossentropy(from_logits=True)
for epoch in range(epochs):
print(f"\nStart of epoch {epoch}")
for step, (inputs, targets) in enumerate(train_dataloader):
# 前向传播
logits = model(inputs)
loss = loss_fn(targets, logits)
# 反向传播
model.zero_grad()
trainable_weights = [v for v in model.trainable_weights]
# 调用 torch.Tensor.backward() 来计算权重的梯度
loss.backward()
gradients = [v.value.grad for v in trainable_weights]
# 更新权重
with torch.no_grad():
optimizer.apply(gradients, trainable_weights)
# 每100个批次记录一次日志。
if step % 100 == 0:
print(
f"Training loss (for 1 batch) at step {step}: {loss.detach().numpy():.4f}"
)
print(f"Seen so far: {(step + 1) * batch_size} samples")
开始第 0 轮
步骤 0 的训练损失(1 批次):98.9569
目前已看到:32 个样本
步骤 100 的训练损失(1 批次):5.3304
目前已看到:3232 个样本
步骤 200 的训练损失(1 批次):0.3246
目前已看到:6432 个样本
步骤 300 的训练损失(1 批次):1.6745
目前已看到:9632 个样本
步骤 400 的训练损失(1 批次):1.0936
目前已看到:12832 个样本
步骤 500 的训练损失(1 批次):1.4159
目前已看到:16032 个样本
步骤 600 的训练损失(1 批次):0.2796
目前已看到:19232 个样本
步骤 700 的训练损失(1 批次):2.3532
目前已看到:22432 个样本
步骤 800 的训练损失(1 批次):0.7533
目前已看到:25632 个样本
步骤 900 的训练损失(1 批次):1.0432
目前已看到:28832 个样本
步骤 1000 的训练损失(1 批次):0.3959
目前已看到:32032 个样本
步骤 1100 的训练损失(1 批次):0.4722
目前已看到:35232 个样本
步骤 1200 的训练损失(1 批次):0.3851
目前已看到:38432 个样本
步骤 1300 的训练损失(1 批次):0.8599
目前已看到:41632 个样本
步骤 1400 的训练损失(1 批次):0.1237
目前已看到:44832 个样本
步骤 1500 的训练损失(1 批次):0.4919
目前已看到:48032 个样本
开始第 1 轮
步骤 0 的训练损失(1 批次):0.8972
目前已看到:32 个样本
步骤 100 的训练损失(1 批次):0.5844
目前已看到:3232 个样本
步骤 200 的训练损失(1 批次):0.1285
目前已看到:6432 个样本
步骤 300 的训练损失(1 批次):0.0671
目前已看到:9632 个样本
步骤 400 的训练损失(1 批次):0.4296
目前已看到:12832 个样本
步骤 500 的训练损失(1 批次):0.1483
目前已看到:16032 个样本
步骤 600 的训练损失(1 批次):0.0230
目前已看到:19232 个样本
步骤 700 的训练损失(1 批次):0.1368
目前已看到:22432 个样本
步骤 800 的训练损失(1 批次):0.1531
目前已看到:25632 个样本
步骤 900 的训练损失(1 批次):0.0472
目前已看到:28832 个样本
步骤 1000 的训练损失(1 批次):0.2343
目前已看到:32032 个样本
步骤 1100 的训练损失(1 批次):0.4449
目前已看到:35232 个样本
步骤 1200 的训练损失(1 批次):0.3942
目前已看到:38432 个样本
步骤 1300 的训练损失(1 批次):0.3236
目前已看到:41632 个样本
步骤 1400 的训练损失(1 批次):0.0717
目前已看到:44832 个样本
步骤 1500 的训练损失(1 批次):0.9288
目前已看到:48032 个样本
开始第 2 轮
步骤 0 的训练损失(1 批次):0.9393
目前已看到:32 个样本
步骤 100 的训练损失(1 批次):0.2383
目前已看到:3232 个样本
步骤 200 的训练损失(1 批次):0.1116
目前已看到:6432 个样本
步骤 300 的训练损失(1 批次):0.6736
目前已看到:9632 个样本
步骤 400 的训练损失(1 扁次):0.6713
目前已看到:12832 个样本
步骤 500 的训练损失(1 批次):0.3394
目前已看到:16032 个样本
步骤 600 的训练损失(1 批次):0.2385
目前已看到:19232 个样本
步骤 700 的训练损失(1 批次):0.4248
目前已看到:22432 个样本
步骤 800 的训练损失(1 批次):0.0200
目前已看到:25632 个样本
步骤 900 的训练损失(1 批次):0.1259
目前已看到:28832 个样本
步骤 1000 的训练损失(1 批次):0.7566
目前已看到:32032 个样本
步骤 1100 的训练损失(1 批次):0.0594
目前已看到:35232 个样本
步骤 1200 的训练损失(1 批次):0.2821
目前已看到:38432 个样本
步骤 1300 的训练损失(1 批次):0.2088
目前已看到:41632 个样本
步骤 1400 的训练损失(1 批次):0.5654
目前已看到:44832 个样本
步骤 1500 的训练损失(1 批次):0.0512
目前已看到:48032 个样本
让我们在这个基本训练循环中添加指标监控。
你可以在从头编写的这样的训练循环中轻松重用内置的 Keras 指标(或你编写的自定义指标)。流程如下:
metric.update_state()
metric.result()
metric.reset_state()
(通常在一个轮次结束时)让我们利用这些知识在每个轮次结束时计算训练和验证数据的 CategoricalAccuracy
:
# 获取一个新的模型
model = get_model()
# 实例化一个优化器以训练模型。
optimizer = keras.optimizers.Adam(learning_rate=1e-3)
# 实例化一个损失函数。
loss_fn = keras.losses.CategoricalCrossentropy(from_logits=True)
# 准备指标。
train_acc_metric = keras.metrics.CategoricalAccuracy()
val_acc_metric = keras.metrics.CategoricalAccuracy()
这是我们的训练和评估循环: for epoch in range(epochs): print(f"\nStart of epoch {epoch}") for step, (inputs, targets) in enumerate(train_dataloader): # 前向传播 logits = model(inputs) loss = loss_fn(targets, logits)
# 后向传播
model.zero_grad()
trainable_weights = [v for v in model.trainable_weights]
# 对损失调用 torch.Tensor.backward() 以计算权重的梯度。
loss.backward()
gradients = [v.value.grad for v in trainable_weights]
# 更新权重
with torch.no_grad():
optimizer.apply(gradients, trainable_weights)
# 更新训练指标。
train_acc_metric.update_state(targets, logits)
# 每100个批次记录一次。
if step % 100 == 0:
print(
f"Training loss (for 1 batch) at step {step}: {loss.detach().numpy():.4f}"
)
print(f"Seen so far: {(step + 1) * batch_size} samples")
# 在每个纪元结束时显示指标。
train_acc = train_acc_metric.result()
print(f"Training acc over epoch: {float(train_acc):.4f}")
# 在每个纪元结束时重置训练指标
train_acc_metric.reset_state()
# 在每个纪元结束时运行验证循环。
for x_batch_val, y_batch_val in val_dataloader:
val_logits = model(x_batch_val, training=False)
# 更新验证指标
val_acc_metric.update_state(y_batch_val, val_logits)
val_acc = val_acc_metric.result()
val_acc_metric.reset_state()
print(f"Validation acc: {float(val_acc):.4f}")
第0个纪元开始
步骤0的训练损失(1个批次):59.2206
目前看到:32个样本
步骤100的训练损失(1个批次):8.9801
目前看到:3232个样本
步骤200的训练损失(1个批次):5.2990
目前看到:6432个样本
步骤300的训练损失(1个批次):3.6978
目前看到:9632个样本
步骤400的训练损失(1个批次):1.9965
目前看到:12832个样本
步骤500的训练损失(1个批次):2.1896
目前看到:16032个样本
步骤600的训练损失(1个批次):1.2416
目前看到:19232个样本
步骤700的训练损失(1个批次):0.9403
目前看到:22432个样本
步骤800的训练损失(1个批次):0.1838
目前看到:25632个样本
步骤900的训练损失(1个批次):0.5884
目前看到:28832个样本
步骤1000的训练损失(1个批次):0.7836
目前看到:32032个样本
步骤1100的训练损失(1个批次):0.7015
目前看到:35232个样本
步骤1200的训练损失(1个批次):0.3335
目前看到:38432个样本
步骤1300的训练损失(1个批次):0.2763
目前看到:41632个样本
步骤1400的训练损失(1个批次):0.4787
目前看到:44832个样本
步骤1500的训练损失(1个批次):0.2562
目前看到:48032个样本
整个纪元的训练准确率:0.8411
验证准确率:0.8963
第1个纪元开始
步骤0的训练损失(1个批次):0.3417
目前看到:32个样本
步骤100的训练损失(1个批次):1.1465
目前看到:3232个样本
步骤200的训练损失(1个批次):0.7274
目前看到:6432个样本
步骤300的训练损失(1个批次):0.1273
目前看到:9632个样本
步骤400的训练损失(1个批次):0.6500
目前看到:12832个样本
步骤500的训练损失(1个批次):0.2008
目前看到:16032个样本
步骤600的训练损失(1个批次):0.7483
目前看到:19232个样本
步骤700的训练损失(1个批次):0.5821
目前看到:22432个样本
步骤800的训练损失(1个批次):0.5696
目前看到:25632个样本
步骤900的训练损失(1个批次):0.3112
目前看到:28832个样本
步骤1000的训练损失(1个批次):0.1761
目前看到:32032个样本
步骤1100的训练损失(1个批次):0.1811
目前看到:35232个样本
步骤1200的训练损失(1个批次):0.2736
目前看到:38432个样本
步骤1300的训练损失(1个批次):0.3848
目前看到:41632个样本
步骤1400的训练损失(1个批次):0.4627
目前看到:44832个样本
步骤1500的训练损失(1个批次):0.3934
目前看到:48032个样本
整个纪元的训练准确率:0.9053
验证准确率:0.9221
第2个纪元开始
步骤0的训练损失(1个批次):0.5743
目前看到:32个样本
步骤100的训练损失(1个批次):0.4448
目前看到:3232个样本
步骤200的训练损失(1个批次):0.9880
目前看到:6432个样本
步骤300的训练损失(1个批次):0.2268
目前看到:9632个样本
步骤400的训练损失(1个批次):0.5607
目前看到:12832个样本
步骤500的训练损失(1个批次):0.1178
目前看到:16032个样本
步骤600的训练损失(1个批次):0.4305
目前看到:19232个样本
步骤700的训练损失(1个批次):0.1712
目前看到:22432个样本
步骤800的训练损失(1个批次):0.3109
目前看到:25632个样本
步骤900的训练损失(1个批次):0.1548
目前看到:28832个样本
步骤1000的训练损失(1个批次):0.1090
目前看到:32032个样本
步骤1100的训练损失(1个批次):0.5169
目前看到:35232个样本
步骤1200的训练损失(1个批次):0.3791
目前看到:38432个样本
步骤1300的训练损失(1个批次):0.6963
目前看到:41632个样本
步骤1400的训练损失(1个批次):0.6204
目前看到:44832个样本
步骤1500的训练损失(1个批次):0.1111
目前看到:48032个样本
整个纪元的训练准确率:0.9216
验证准确率:0.9356
层和模型通过调用 self.add_loss(value)
的层递归地跟踪在前向传递过程中创建的任何损失。
在前向传递结束时,通过属性 model.losses
可以获取到结果标量损失值的列表。
如果你想使用这些损失组件,你应该将它们相加并在训练步骤中将它们添加到主要损失中。
考虑这个层,它创建了一个活动正则化损失:
class ActivityRegularizationLayer(keras.layers.Layer):
def call(self, inputs):
self.add_loss(1e-2 * torch.sum(inputs)) # 添加正则化损失
return inputs
让我们构建一个使用它的非常简单的模型:
inputs = keras.Input(shape=(784,), name="digits")
x = keras.layers.Dense(64, activation="relu")(inputs)
# 将活动正则化插入为一层
x = ActivityRegularizationLayer()(x)
x = keras.layers.Dense(64, activation="relu")(x)
outputs = keras.layers.Dense(10, name="predictions")(x)
model = keras.Model(inputs=inputs, outputs=outputs)
Here's what our training loop should look like now:
# 获取一个全新的模型
model = get_model()
# 实例化一个优化器来训练模型。
optimizer = keras.optimizers.Adam(learning_rate=1e-3)
# 实例化一个损失函数。
loss_fn = keras.losses.CategoricalCrossentropy(from_logits=True)
# 准备指标。
train_acc_metric = keras.metrics.CategoricalAccuracy()
val_acc_metric = keras.metrics.CategoricalAccuracy()
for epoch in range(epochs):
print(f"\n开始第 {epoch} 轮")
for step, (inputs, targets) in enumerate(train_dataloader):
# 前向传播
logits = model(inputs)
loss = loss_fn(targets, logits)
if model.losses:
loss = loss + torch.sum(*model.losses)
# 后向传播
model.zero_grad()
trainable_weights = [v for v in model.trainable_weights]
# 计算损失的梯度
# 对于权重。
loss.backward()
gradients = [v.value.grad for v in trainable_weights]
# 更新权重
with torch.no_grad():
optimizer.apply(gradients, trainable_weights)
# 更新训练指标。
train_acc_metric.update_state(targets, logits)
# 每 100 批次记录一次。
if step % 100 == 0:
print(
f"第 {step} 步的训练损失(对于 1 批次):{loss.detach().numpy():.4f}"
)
print(f"至今已见:{(step + 1) * batch_size} 个样本")
# 在每轮结束时显示指标。
train_acc = train_acc_metric.result()
print(f"整轮训练准确率:{float(train_acc):.4f}")
# 在每轮结束时重置训练指标
train_acc_metric.reset_state()
# 在每轮结束时运行验证循环。
for x_batch_val, y_batch_val in val_dataloader:
val_logits = model(x_batch_val, training=False)
# 更新验证指标
val_acc_metric.update_state(y_batch_val, val_logits)
val_acc = val_acc_metric.result()
val_acc_metric.reset_state()
print(f"验证准确率:{float(val_acc):.4f}")
开始第 0 轮
第 0 步的训练损失(对于 1 批次):138.7979
至今已见:32 个样本
第 100 步的训练损失(对于 1 批次):4.4268
至今已见:3232 个样本
第 200 步的训练损失(对于 1 批次):1.0779
至今已见:6432 个样本
第 300 步的训练损失(对于 1 批次):1.7229
至今已见:9632 个样本
第 400 步的训练损失(对于 1 批次):0.5801
至今已见:12832 个样本
第 500 步的训练损失(对于 1 批次):0.4298
至今已见:16032 个样本
第 600 步的训练损失(对于 1 批次):0.4717
至今已见:19232 个样本
第 700 步的训练损失(对于 1 批次):1.3369
至今已见:22432 个样本
第 800 步的训练损失(对于 1 批次):1.3239
至今已见:25632 个样本
第 900 步的训练损失(对于 1 批次):0.5972
至今已见:28832 个样本
第 1000 步的训练损失(对于 1 批次):0.1983
至今已见:32032 个样本
第 1100 步的训练损失(对于 1 批次):0.5228
至今已见:35232 个样本
第 1200 步的训练损失(对于 1 批次):1.0025
至今已见:38432 个样本
第 1300 步的训练损失(对于 1 批次):0.3424
至今已见:41632 个样本
第 1400 步的训练损失(对于 1 批次):0.5196
至今已见:44832 个样本
第 1500 步的训练损失(对于 1 批次):0.4287
至今已见:48032 个样本
整轮训练准确率:0.8089
验证准确率:0.8947
开始第 1 轮
第 0 步的训练损失(对于 1 批次):0.2903
至今已见:32 个样本
第 100 步的训练损失(对于 1 批次):0.4118
至今已见:3232 个样本
第 200 步的训练损失(对于 1 批次):0.6533
至今已见:6432 个样本
第 300 步的训练损失(对于 1 批次):0.0402
至今已见:9632 个样本
第 400 步的训练损失(对于 1 批次):0.3638
至今已见:12832 个样本
第 500 步的训练损失(对于 1 批次):0.3313
至今已见:16032 个样本
第 600 步的训练损失(对于 1 批次):0.5119
至今已见:19232 个样本
第 700 步的训练损失(对于 1 批次):0.1628
至今已见:22432 个样本
第 800 步的训练损失(对于 1 批次):0.4793
至今已见:25632 个样本
第 900 步的训练损失(对于 1 批次):0.2726
至今已见:28832 个样本
第 1000 步的训练损失(对于 1 批次):0.5721
至今已见:32032 个样本
第 1100 步的训练损失(对于 1 批次):0.5783
至今已见:35232 个样本
第 1200 步的训练损失(对于 1 批次):0.2533
至今已见:38432 个样本
第 1300 步的训练损失(对于 1 批次):0.2218
至今已见:41632 个样本
第 1400 步的训练损失(对于 1 批次):0.1232
至今已见:44832 个样本
第 1500 步的训练损失(对于 1 批次):0.6805
至今已见:48032 个样本
整轮训练准确率:0.8970
验证准确率:0.9097
开始第2个周期
第0步的训练损失(1个批次): 0.4553
到目前为止:32个样本
第100步的训练损失(1个批次): 0.3975
到目前为止:3232个样本
第200步的训练损失(1个批次): 1.2382
到目前为止:6432个样本
第300步的训练损失(1个批次): 0.0927
到目前为止:9632个样本
第400步的训练损失(1个批次): 0.3530
到目前为止:12832个样本
第500步的训练损失(1个批次): 0.3842
到目前为止:16032个样本
第600步的训练损失(1个批次): 0.6423
到目前为止:19232个样本
第700步的训练损失(1个批次): 0.1751
到目前为止:22432个样本
第800步的训练损失(1个批次): 0.4769
到目前为止:25632个样本
第900步的训练损失(1个批次): 0.1854
到目前为止:28832个样本
第1000步的训练损失(1个批次): 0.3130
到目前为止:32032个样本
第1100步的训练损失(1个批次): 0.1633
到目前为止:35232个样本
第1200步的训练损失(1个批次): 0.1446
到目前为止:38432个样本
第1300步的训练损失(1个批次): 0.4661
到目前为止:41632个样本
第1400步的训练损失(1个批次): 0.9977
到目前为止:44832个样本
第1500步的训练损失(1个批次): 0.3392
到目前为止:48032个样本
整个周期的训练准确率: 0.9182
验证准确率: 0.9200