【问题标题】:Selecting loss and metrics for Tensorflow model为 TensorFlow 模型选择损失和指标
【发布时间】:2021-08-23 04:48:34
【问题描述】:

我正在尝试使用预训练的 Xception 模型和新添加的分类器进行迁移学习。

这是模型:

base_model = keras.applications.Xception(
    weights="imagenet",
    input_shape=(224,224,3),
    include_top=False
)

我使用的数据集是 oxford_flowers102 直接取自 tensorflow 数据集。 This 是一个数据集页面。

我在选择某些参数时遇到了问题 - 要么训练准确度显示出可疑的低值,要么出现错误。

我需要帮助来指定这个参数,对于这个 (oxford_flowers102) 数据集:

  1. 为分类器新添加的密集层。我正在尝试: outputs = keras.layers.Dense(102, activation='softmax')(x) 我不确定是否应该在这里选择激活函数。
  2. 模型的损失函数。
  3. 指标。

我试过了:

model.compile(
    optimizer=keras.optimizers.Adam(),
    loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    metrics=[keras.metrics.Accuracy()],
)

不知道应该是SparseCategoricalCrossentropy还是CategoricalCrossentropy,那from_logits参数呢?

我也不确定应该选择metricskeras.metrics.Accuracy()还是keras.metrics.CategoricalAccuracy()

我确实缺乏一些理论知识,但现在我只需要这个工作。期待您的回答!

【问题讨论】:

    标签: tensorflow machine-learning keras deep-learning tensorflow2.0


    【解决方案1】:

    关于数据集:oxford_flowers102

    数据集分为训练集验证集测试集。训练集和验证集各包含每类 10 张图像(每个总共有 1020 张图像)。测试集由剩余的 6149 张图片组成(每类最少 20 张)。

    'test'        6,149
    'train'       1,020
    'validation'  1,020
    

    如果我们检查,我们会看到

    import tensorflow_datasets as tfds
    tfds.disable_progress_bar()
    
    data, ds_info = tfds.load('oxford_flowers102', 
                              with_info=True, as_supervised=True)
    train_ds, valid_ds, test_ds = data['train'], data['validation'], data['test']
    
    for i, data in enumerate(train_ds.take(3)):
      print(i+1, data[0].shape, data[1])
    1 (500, 667, 3) tf.Tensor(72, shape=(), dtype=int64)
    2 (500, 666, 3) tf.Tensor(84, shape=(), dtype=int64)
    3 (670, 500, 3) tf.Tensor(70, shape=(), dtype=int64)
    
    ds_info.features["label"].num_classes
    102
    

    因此,它有 102 个类别或类,并且目标带有一个具有不同形状输入的 整数

    澄清

    首先,如果你保留这个整数目标或标签,你应该使用sparse_categorical_accuracy来获得准确性,sparse_categorical_crossentropy作为损失函数。但是,如果您将整数标签转换为 one-hot 编码向量,那么您应该使用 categorical_accuracy 来获得准确性,并使用 categorical_crossentropy 来获得损失函数。由于这些数据集有整数标签,您可以选择sparse_categorical,也可以将标签转换为one-hot以便使用categorical

    第二,如果你将outputs = keras.layers.Dense(102, activation='softmax')(x)设置为最后一层,你会得到概率分数。但是如果你设置outputs = keras.layers.Dense(102)(x),那么你会得到logits。所以,如果你设置了activations='softmax',那么你就不应该使用from_logit = True。例如,在您上面的代码中,您应该执行以下操作(这里是 some theory 给您):

    ...
    (a)
    # Use softmax activation (no logits output)
    outputs = keras.layers.Dense(102, activation='softmax')(x)
    ...
    model.compile(
        optimizer=keras.optimizers.Adam(),
        loss=keras.losses.SparseCategoricalCrossentropy(from_logits=False),
        metrics=[keras.metrics.Accuracy()],
    )
    
    or,
    
    (b)
    # no activation, output will be logits
    outputs = keras.layers.Dense(102)(x)
    ...
    model.compile(
        optimizer=keras.optimizers.Adam(),
        loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
        metrics=[keras.metrics.Accuracy()],
    )
    

    第三使用字符串标识符metrics=['acc'] , optimizer='adam'。但是在您的情况下,当您提到损失函数时,您需要更加具体一些。因此,您应该选择keras.metrics.SparseCategoricalAccuracy()而不是keras.metrics.Accuracy()如果您的目标是整数keras.metrics.CategoricalAccuracy()如果您的目标是一次性编码向量

    代码示例

    这是一个端到端的示例。请注意,我将将整数标签转换为一次性编码向量(现在,这是我的偏好问题)。另外,我想要最后一层的概率(不是logits),这意味着from_logits = False。对于所有这些,我需要在训练中选择以下参数:

    # use softmax to get probabilities 
    outputs = keras.layers.Dense(102, 
                       activation='softmax')(x)
    
    # so no logits, set it false (FYI, by default it already false)
    loss = keras.losses.CategoricalCrossentropy(from_logits=False),
    
    # specify the metrics properly 
    metrics = keras.metrics.CategoricalAccuracy(),
    

    让我们完成整个代码。

    import tensorflow_datasets as tfds
    tfds.disable_progress_bar()
    
    data, ds_info = tfds.load('oxford_flowers102', 
                             with_info=True, as_supervised=True)
    train_ds, valid_ds, test_ds = data['train'], data['validation'], data['test']
    
    
    NUM_CLASSES = ds_info.features["label"].num_classes
    train_size =  len(data['train'])
    
    batch_size = 64
    img_size = 120 
    

    预处理和增强

    import tensorflow as tf 
    
    # pre-process functions 
    def normalize_resize(image, label):
        image = tf.cast(image, tf.float32)
        image = tf.divide(image, 255)
        image = tf.image.resize(image, (img_size, img_size))
        label = tf.one_hot(label , depth=NUM_CLASSES) # int to one-hot
        return image, label
    
    # augmentation 
    def augment(image, label):
        image = tf.image.random_flip_left_right(image)
        return image, label 
    
    
    train = train_ds.map(normalize_resize).cache().map(augment).shuffle(100).\
                              batch(batch_size).repeat()
    valid = valid_ds.map(normalize_resize).cache().batch(batch_size)
    test = test_ds.map(normalize_resize).cache().batch(batch_size)
    

    型号

    from tensorflow import keras 
    
    base_model = keras.applications.Xception(
        weights='imagenet',  
        input_shape=(img_size, img_size, 3),
        include_top=False)  
    
    base_model.trainable = False
    inputs = keras.Input(shape=(img_size, img_size, 3))
    x = base_model(inputs, training=False)
    x = keras.layers.GlobalAveragePooling2D()(x)
    outputs = keras.layers.Dense(NUM_CLASSES, activation='softmax')(x)
    model = keras.Model(inputs, outputs)
    

    好的,另外,这里我喜欢使用两个指标来计算 top-1top-3 准确度。

    model.compile(optimizer=keras.optimizers.Adam(),
                  loss=keras.losses.CategoricalCrossentropy(),
                  metrics=[
                           keras.metrics.TopKCategoricalAccuracy(k=3, name='acc_top3'),
                           keras.metrics.TopKCategoricalAccuracy(k=1, name='acc_top1')
                        ])
    model.fit(train, steps_per_epoch=train_size // batch_size,
              epochs=20, validation_data=valid, verbose=2)
    
    ...
    Epoch 19/20
    15/15 - 2s - loss: 0.2808 - acc_top3: 0.9979 - acc_top1: 0.9917 - 
    val_loss: 1.5025 - val_acc_top3: 0.8147 - val_acc_top1: 0.6186
    
    Epoch 20/20
    15/15 - 2s - loss: 0.2743 - acc_top3: 0.9990 - acc_top1: 0.9885 - 
    val_loss: 1.4948 - val_acc_top3: 0.8147 - val_acc_top1: 0.6255
    

    评估

    # evaluate on test set 
    model.evaluate(test, verbose=2)
    97/97 - 18s - loss: 1.6482 - acc_top3: 0.7733 - acc_top1: 0.5994
    [1.648208498954773, 0.7732964754104614, 0.5994470715522766]
    

    【讨论】:

    • 解释得很好!
    猜你喜欢
    • 2017-10-02
    • 1970-01-01
    • 2021-07-27
    • 2018-04-12
    • 2021-05-07
    • 2023-03-20
    • 2020-10-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多