代码示例 / 计算机视觉 / FixRes: 修复训练-测试分辨率不一致

FixRes: 修复训练-测试分辨率不一致

作者: Sayak Paul
创建日期: 2021/10/08
最后修改: 2021/10/10
描述: 缓解训练集和测试集之间的分辨率不一致。

在Colab中查看 GitHub源代码


介绍

在训练和测试视觉模型时,使用相同的输入图像分辨率是一种常见做法。然而,正如Touvron等人的研究所证明的,这种做法会导致次优性能。数据增强是深度神经网络训练过程中的一个不可或缺的部分。对于视觉模型,我们通常在训练期间使用随机裁剪,而在推理期间使用中心裁剪。这在训练和推理期间引入了物体大小的差异。正如Touvron等人所示,如果我们能修复这种差异,就可以显著提升模型性能。

在这个例子中,我们实现了由Touvron等人提出的FixRes技术,以修复这种差异。


导入

import keras
from keras import layers
import tensorflow as tf  # 仅用于图像处理和管道

import tensorflow_datasets as tfds

tfds.disable_progress_bar()

import matplotlib.pyplot as plt

加载tf_flowers数据集

train_dataset, val_dataset = tfds.load(
    "tf_flowers", split=["train[:90%]", "train[90%:]"], as_supervised=True
)

num_train = train_dataset.cardinality()
num_val = val_dataset.cardinality()
print(f"训练示例的数量: {num_train}")
print(f"验证示例的数量: {num_val}")
训练示例的数量: 3303
验证示例的数量: 367

数据预处理工具

我们创建三个数据集:

  1. 一个分辨率较小的数据集 - 128x128。
  2. 两个分辨率较大的数据集 - 224x224。

我们将对较大分辨率的数据集应用不同的数据增强变换。

FixRes的思路是先在较小分辨率数据集上训练模型,然后在较大分辨率数据集上微调。这个简单而有效的方案带来了显著的性能提升。有关结果,请参阅原始论文

# 参考: https://github.com/facebookresearch/FixRes/blob/main/transforms_v2.py.

batch_size = 32
auto = tf.data.AUTOTUNE
smaller_size = 128
bigger_size = 224

size_for_resizing = int((bigger_size / smaller_size) * bigger_size)
central_crop_layer = layers.CenterCrop(bigger_size, bigger_size)


def preprocess_initial(train, image_size):
    """初步预处理函数,用于在较小分辨率上训练。

    对于训练,进行随机水平翻转 -> 随机裁剪。
    对于验证,只进行缩放。
    不使用颜色抖动。
    """

    def _pp(image, label, train):
        if train:
            channels = image.shape[-1]
            begin, size, _ = tf.image.sample_distorted_bounding_box(
                tf.shape(image),
                tf.zeros([0, 0, 4], tf.float32),
                area_range=(0.05, 1.0),
                min_object_covered=0,
                use_image_if_no_bounding_boxes=True,
            )
            image = tf.slice(image, begin, size)

            image.set_shape([None, None, channels])
            image = tf.image.resize(image, [image_size, image_size])
            image = tf.image.random_flip_left_right(image)
        else:
            image = tf.image.resize(image, [image_size, image_size])

        return image, label

    return _pp


def preprocess_finetune(image, label, train):
    """用于在较高分辨率上微调的预处理函数。

    对于训练,缩放到更大的分辨率以保持比例 ->
        随机水平翻转 -> 中心裁剪。
    对于验证,以相同方式处理,不进行水平翻转。
    不使用颜色抖动。
    """
    image = tf.image.resize(image, [size_for_resizing, size_for_resizing])
    if train:
        image = tf.image.random_flip_left_right(image)
    image = central_crop_layer(image[None, ...])[0]

    return image, label


def make_dataset(
    dataset: tf.data.Dataset,
    train: bool,
    image_size: int = smaller_size,
    fixres: bool = True,
    num_parallel_calls=auto,
):
    if image_size not in [smaller_size, bigger_size]:
        raise ValueError(f"{image_size} 分辨率不被支持。")

    # 确定我们正在使用的预处理函数。
    if image_size == smaller_size:
        preprocess_func = preprocess_initial(train, image_size)
    elif not fixres and image_size == bigger_size:
        preprocess_func = preprocess_initial(train, image_size)
    else:
        preprocess_func = preprocess_finetune

    dataset = dataset.map(
        lambda x, y: preprocess_func(x, y, train),
        num_parallel_calls=num_parallel_calls,
    )
    dataset = dataset.batch(batch_size)

    if train:
        dataset = dataset.shuffle(batch_size * 10)

    return dataset.prefetch(num_parallel_calls)

Notice how the augmentation transforms vary for the kind of dataset we are preparing.


准备数据集

initial_train_dataset = make_dataset(train_dataset, train=True, image_size=smaller_size)
initial_val_dataset = make_dataset(val_dataset, train=False, image_size=smaller_size)

finetune_train_dataset = make_dataset(train_dataset, train=True, image_size=bigger_size)
finetune_val_dataset = make_dataset(val_dataset, train=False, image_size=bigger_size)

vanilla_train_dataset = make_dataset(
    train_dataset, train=True, image_size=bigger_size, fixres=False
)
vanilla_val_dataset = make_dataset(
    val_dataset, train=False, image_size=bigger_size, fixres=False
)

可视化数据集

def visualize_dataset(batch_images):
    plt.figure(figsize=(10, 10))
    for n in range(25):
        ax = plt.subplot(5, 5, n + 1)
        plt.imshow(batch_images[n].numpy().astype("int"))
        plt.axis("off")
    plt.show()

    print(f"Batch shape: {batch_images.shape}.")


# 更小的分辨率。
initial_sample_images, _ = next(iter(initial_train_dataset))
visualize_dataset(initial_sample_images)

# 更大的分辨率,仅用于微调。
finetune_sample_images, _ = next(iter(finetune_train_dataset))
visualize_dataset(finetune_sample_images)

# 更大的分辨率,采用与更小分辨率数据集相同的增强变换。
vanilla_sample_images, _ = next(iter(vanilla_train_dataset))
visualize_dataset(vanilla_sample_images)

png

批次形状: (32, 128, 128, 3)。

png

批次形状: (32, 224, 224, 3)。

png

批次形状: (32, 224, 224, 3)。

模型训练工具

我们训练多个变体的 ResNet50V2 (He et al.):

  1. 在较小分辨率数据集上 (128x128)。将从头开始训练。
  2. 然后在较大分辨率 (224x224) 数据集上微调模型。
  3. 在较大分辨率数据集上从头开始训练另一个 ResNet50V2。

作为提醒,较大分辨率数据集在增强变换方面有所不同。

def get_training_model(num_classes=5):
    inputs = layers.Input((None, None, 3))
    resnet_base = keras.applications.ResNet50V2(
        include_top=False, weights=None, pooling="avg"
    )
    resnet_base.trainable = True

    x = layers.Rescaling(scale=1.0 / 127.5, offset=-1)(inputs)
    x = resnet_base(x)
    outputs = layers.Dense(num_classes, activation="softmax")(x)
    return keras.Model(inputs, outputs)


def train_and_evaluate(
    model,
    train_ds,
    val_ds,
    epochs,
    learning_rate=1e-3,
    use_early_stopping=False,
):
    optimizer = keras.optimizers.Adam(learning_rate=learning_rate)
    model.compile(
        optimizer=optimizer,
        loss="sparse_categorical_crossentropy",
        metrics=["accuracy"],
    )

    if use_early_stopping:
        es_callback = keras.callbacks.EarlyStopping(patience=5)
        callbacks = [es_callback]
    else:
        callbacks = None

    model.fit(
        train_ds,
        validation_data=val_ds,
        epochs=epochs,
        callbacks=callbacks,
    )

    _, accuracy = model.evaluate(val_ds)
    print(f"验证集上的 Top-1 准确率: {accuracy*100:.2f}%.")
    return model

实验 1: 在 128x128 上训练,然后在 224x224 上微调

epochs = 30

smaller_res_model = get_training_model()
smaller_res_model = train_and_evaluate(
    smaller_res_model, initial_train_dataset, initial_val_dataset, epochs
)
Epoch 1/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 56s 299ms/step - 准确率: 0.4146 - 损失: 1.7349 - 验证准确率: 0.2234 - 验证损失: 2.0703
Epoch 2/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.5062 - 损失: 1.2458 - 验证准确率: 0.3896 - 验证损失: 1.5800
Epoch 3/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.5262 - 损失: 1.1733 - 验证准确率: 0.5940 - 验证损失: 1.0160
Epoch 4/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 37ms/step - 准确率: 0.5740 - 损失: 1.1021 - 验证准确率: 0.5967 - 验证损失: 1.6164
Epoch 5/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.6160 - 损失: 1.0289 - 验证准确率: 0.5313 - 验证损失: 1.2465
Epoch 6/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.6137 - 损失: 1.0286 - 验证准确率: 0.6431 - 验证损失: 0.8564
Epoch 7/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.6237 - 损失: 0.9760 - 验证准确率: 0.6240 - 验证损失: 1.0114
Epoch 8/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.6029 - 损失: 0.9994 - 验证准确率: 0.5804 - 验证损失: 1.0331
Epoch 9/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.6419 - 损失: 0.9555 - 验证准确率: 0.6403 - 验证损失: 0.8417
Epoch 10/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.6513 - 损失: 0.9333 - 验证准确率: 0.6376 - 验证损失: 1.0658
Epoch 11/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.6316 - 损失: 0.9637 - 验证准确率: 0.5913 - 验证损失: 1.5650
Epoch 12/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.6542 - 损失: 0.9047 - 验证准确率: 0.6458 - 验证损失: 0.9613
Epoch 13/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.6551 - 损失: 0.8946 - 验证准确率: 0.6866 - 验证损失: 0.8427
Epoch 14/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.6617 - 损失: 0.8848 - 验证准确率: 0.7003 - 验证损失: 0.9339
Epoch 15/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.6455 - 损失: 0.9293 - 验证准确率: 0.6757 - 验证损失: 0.9453
Epoch 16/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.6821 - 损失: 0.8481 - 验证准确率: 0.7466 - 验证损失: 0.7237
Epoch 17/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.6750 - 损失: 0.8449 - 验证准确率: 0.5967 - 验证损失: 1.5579
Epoch 18/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 37ms/step - 准确率: 0.6765 - 损失: 0.8605 - 验证准确率: 0.6921 - 验证损失: 0.8136
Epoch 19/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.6969 - 损失: 0.8140 - 验证准确率: 0.6131 - 验证损失: 1.0785
Epoch 20/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.6831 - 损失: 0.8257 - 验证准确率: 0.7221 - 验证损失: 0.7480
Epoch 21/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.6988 - 损失: 0.8008 - 验证准确率: 0.7193 - 验证损失: 0.7953
Epoch 22/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.7172 - 损失: 0.7578 - 验证准确率: 0.6730 - 验证损失: 1.1628
Epoch 23/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.6935 - 损失: 0.8126 - 验证准确率: 0.7357 - 验证损失: 0.6565
Epoch 24/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.7149 - 损失: 0.7568 - 验证准确率: 0.7439 - 验证损失: 0.8830
Epoch 25/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.7151 - 损失: 0.7510 - 验证准确率: 0.7248 - 验证损失: 0.7459
Epoch 26/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.7133 - 损失: 0.7838 - 验证准确率: 0.7084 - 验证损失: 0.7140
Epoch 27/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.7314 - 损失: 0.7386 - 验证准确率: 0.6730 - 验证损失: 1.5988
Epoch 28/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.7259 - 损失: 0.7417 - 验证准确率: 0.7275 - 验证损失: 0.7255
Epoch 29/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.7006 - 损失: 0.7863 - 验证准确率: 0.6621 - 验证损失: 1.5714
Epoch 30/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 4s 36ms/step - 准确率: 0.7115 - 损失: 0.7498 - 验证准确率: 0.7548 - 验证损失: 0.7067
 12/12 ━━━━━━━━━━━━━━━━━━━━ 0s 14ms/step - 准确率: 0.7207 - 损失: 0.8735
验证集上的Top-1准确率: 75.48%.

冻结所有层,除了最后的批归一化层

为了微调,我们只训练两个层:

我们解冻最后的批归一化层,以补偿全局平均池化层之前激活统计的变化。如 论文中所示,解冻最后的批归一化层就足够了。

有关在 Keras 中微调模型的综合指南,请参考 本教程

for layer in smaller_res_model.layers[2].layers:
    layer.trainable = False

smaller_res_model.layers[2].get_layer("post_bn").trainable = True

epochs = 10

# 在微调期间使用较低的学习率。
bigger_res_model = train_and_evaluate(
    smaller_res_model,
    finetune_train_dataset,
    finetune_val_dataset,
    epochs,
    learning_rate=1e-4,
)
第 1 轮/10 轮
 104/104 ━━━━━━━━━━━━━━━━━━━━ 26s 158ms/step - 准确率: 0.6890 - 损失: 0.8791 - 验证准确率: 0.7548 - 验证损失: 0.7801
第 2 轮/10 轮
 104/104 ━━━━━━━━━━━━━━━━━━━━ 6s 34ms/step - 准确率: 0.7372 - 损失: 0.8209 - 验证准确率: 0.7466 - 验证损失: 0.7866
第 3 轮/10 轮
 104/104 ━━━━━━━━━━━━━━━━━━━━ 6s 34ms/step - 准确率: 0.7532 - 损失: 0.7925 - 验证准确率: 0.7520 - 验证损失: 0.7779
第 4 轮/10 轮
 104/104 ━━━━━━━━━━━━━━━━━━━━ 6s 34ms/step - 准确率: 0.7417 - 损失: 0.7833 - 验证准确率: 0.7439 - 验证损失: 0.7625
第 5 轮/10 轮
 104/104 ━━━━━━━━━━━━━━━━━━━━ 6s 34ms/step - 准确率: 0.7508 - 损失: 0.7624 - 验证准确率: 0.7439 - 验证损失: 0.7449
第 6 轮/10 轮
 104/104 ━━━━━━━━━━━━━━━━━━━━ 6s 34ms/step - 准确率: 0.7542 - 损失: 0.7406 - 验证准确率: 0.7493 - 验证损失: 0.7220
第 7 轮/10 轮
 104/104 ━━━━━━━━━━━━━━━━━━━━ 6s 34ms/step - 准确率: 0.7471 - 损失: 0.7716 - 验证准确率: 0.7520 - 验证损失: 0.7111
第 8 轮/10 轮
 104/104 ━━━━━━━━━━━━━━━━━━━━ 6s 35ms/step - 准确率: 0.7580 - 损失: 0.7082 - 验证准确率: 0.7548 - 验证损失: 0.6939
第 9 轮/10 轮
 104/104 ━━━━━━━━━━━━━━━━━━━━ 6s 34ms/step - 准确率: 0.7571 - 损失: 0.7121 - 验证准确率: 0.7520 - 验证损失: 0.6915
第 10 轮/10 轮
 104/104 ━━━━━━━━━━━━━━━━━━━━ 6s 34ms/step - 准确率: 0.7482 - 损失: 0.7285 - 验证准确率: 0.7520 - 验证损失: 0.6830
 12/12 ━━━━━━━━━━━━━━━━━━━━ 0s 34ms/step - 准确率: 0.7296 - 损失: 0.7253
验证集上的 Top-1 准确率: 75.20%。

实验 2:从头开始在 224x224 分辨率上训练模型

现在,我们在更大分辨率的数据集上从头开始训练另一个模型。请回忆一下, 该数据集中使用的增强变换与之前不同。

epochs = 30

vanilla_bigger_res_model = get_training_model()
vanilla_bigger_res_model = train_and_evaluate(
    vanilla_bigger_res_model, vanilla_train_dataset, vanilla_val_dataset, epochs
)
Epoch 1/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 58s 318ms/step - 准确率: 0.4148 - 损失: 1.6685 - 验证准确率: 0.2807 - 验证损失: 1.5614
Epoch 2/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.5137 - 损失: 1.2569 - 验证准确率: 0.3324 - 验证损失: 1.4950
Epoch 3/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.5582 - 损失: 1.1617 - 验证准确率: 0.5395 - 验证损失: 1.0945
Epoch 4/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.5559 - 损失: 1.1420 - 验证准确率: 0.5123 - 验证损失: 1.5154
Epoch 5/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.6036 - 损失: 1.0731 - 验证准确率: 0.4823 - 验证损失: 1.2676
Epoch 6/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.5376 - 损失: 1.1810 - 验证准确率: 0.4496 - 验证损失: 3.5370
Epoch 7/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.6216 - 损失: 0.9956 - 验证准确率: 0.5804 - 验证损失: 1.0637
Epoch 8/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.6209 - 损失: 0.9915 - 验证准确率: 0.5613 - 验证损失: 1.1856
Epoch 9/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.6229 - 损失: 0.9657 - 验证准确率: 0.6076 - 验证损失: 1.0131
Epoch 10/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.6322 - 损失: 0.9654 - 验证准确率: 0.6022 - 验证损失: 1.1179
Epoch 11/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.6223 - 损失: 0.9634 - 验证准确率: 0.6458 - 验证损失: 0.8731
Epoch 12/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.6414 - 损失: 0.9838 - 验证准确率: 0.6975 - 验证损失: 0.8202
Epoch 13/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.6635 - 损失: 0.8912 - 验证准确率: 0.6730 - 验证损失: 0.8018
Epoch 14/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.6571 - 损失: 0.8915 - 验证准确率: 0.5640 - 验证损失: 1.2489
Epoch 15/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.6725 - 损失: 0.8788 - 验证准确率: 0.6240 - 验证损失: 1.0039
Epoch 16/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.6776 - 损失: 0.8630 - 验证准确率: 0.6322 - 验证损失: 1.0803
Epoch 17/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.6728 - 损失: 0.8673 - 验证准确率: 0.7330 - 验证损失: 0.7256
Epoch 18/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 85ms/step - 准确率: 0.6969 - 损失: 0.8069 - 验证准确率: 0.7275 - 验证损失: 0.8264
Epoch 19/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 85ms/step - 准确率: 0.6891 - 损失: 0.8271 - 验证准确率: 0.6594 - 验证损失: 0.9932
Epoch 20/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 85ms/step - 准确率: 0.6678 - 损失: 0.8630 - 验证准确率: 0.7221 - 验证损失: 0.7238
Epoch 21/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.6980 - 损失: 0.7991 - 验证准确率: 0.6267 - 验证损失: 0.8916
Epoch 22/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 85ms/step - 准确率: 0.7187 - 损失: 0.7546 - 验证准确率: 0.7466 - 验证损失: 0.6844
Epoch 23/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 85ms/step - 准确率: 0.7210 - 损失: 0.7491 - 验证准确率: 0.6676 - 验证损失: 1.1051
Epoch 24/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.6930 - 损失: 0.7762 - 验证准确率: 0.7493 - 验证损失: 0.6720
Epoch 25/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.7192 - 损失: 0.7706 - 验证准确率: 0.7357 - 验证损失: 0.7281
Epoch 26/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.7227 - 损失: 0.7339 - 验证准确率: 0.7602 - 验证损失: 0.6618
Epoch 27/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.7108 - 损失: 0.7641 - 验证准确率: 0.7057 - 验证损失: 0.8372
Epoch 28/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.7186 - 损失: 0.7644 - 验证准确率: 0.7657 - 验证损失: 0.5906
Epoch 29/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.7166 - 损失: 0.7394 - 验证准确率: 0.7820 - 验证损失: 0.6294
Epoch 30/30
 104/104 ━━━━━━━━━━━━━━━━━━━━ 10s 84ms/step - 准确率: 0.7122 - 损失: 0.7655 - 验证准确率: 0.7139 - 验证损失: 0.8012
 12/12 ━━━━━━━━━━━━━━━━━━━━ 0s 33ms/step - 准确率: 0.6797 - 损失: 0.8819
在验证集上的 Top-1 准确率: 71.39%。

从上面的单元格中我们可以看出,FixRes 提供了更好的性能。FixRes 的另一个优点是改善了总训练时间并减少了 GPU 内存使用。FixRes 是与模型无关的,您可以在任何图像分类模型上使用它来潜在提高性能。

您可以在 这里 找到更多结果,这些结果是通过运行相同的代码并使用不同的随机种子收集的。