数据增强是一种在训练用于计算机视觉问题的神经网络模型时,常用于提高性能和减少泛化误差的技术。
图像数据增强技术也可以在模型做出预测时应用,以允许模型对测试数据集中每个图像的多个不同版本做出预测。对增强图像的预测可以进行平均,这可以带来更好的预测性能。
在本教程中,您将了解测试时增强(Test-Time Augmentation,TTA),以提高图像分类任务模型的性能。
完成本教程后,您将了解:
- 测试时增强是在进行预测时应用通常在训练期间使用的数据增强技术。
- 如何在 Keras 中从头开始实现测试时增强。
- 如何使用测试时增强来提高卷积神经网络模型在标准图像分类任务上的性能。
通过我的新书《深度学习计算机视觉》启动您的项目,其中包括分步教程和所有示例的 Python 源代码文件。
让我们开始吧。

如何使用测试时增强来提高图像分类模型的性能
照片作者:daveynin,保留部分权利。
教程概述
本教程分为五个部分;它们是:
- 测试时增强
- Keras 中的测试时增强
- 数据集和基线模型
- 测试时增强示例
- 如何调整测试时增强配置
测试时增强
数据增强是一种通常在模型训练期间使用的技术,它通过训练数据集中样本的修改副本扩展训练集。
数据增强通常对图像数据进行,通过一些图像操作技术(例如缩放、翻转、平移等)创建训练数据集中图像的副本。
人工扩展的训练数据集可以产生一个更熟练的模型,因为深度学习模型的性能通常随着训练数据集的大小而继续扩展。此外,训练数据集中图像的修改或增强版本有助于模型以对其位置、光照等不变的方式提取和学习特征。
测试时增强,简称 TTA,是数据增强在测试数据集上的应用。
具体来说,它涉及为测试集中的每个图像创建多个增强副本,让模型为每个副本做出预测,然后返回这些预测的集成。
选择增强是为了给模型提供正确分类给定图像的最佳机会,并且模型必须对其进行预测的图像副本数量通常很少,例如小于 10 或 20。
通常,会执行一次简单的测试时增强,例如平移、裁剪或图像翻转。
在他们 2015 年在 ILSVRC 数据集上取得当时最先进成果的论文《用于大规模图像识别的非常深卷积网络》中,作者使用了水平翻转测试时增强。
我们还通过水平翻转图像来增强测试集;原始图像和翻转图像的 softmax 类后验概率进行平均以获得图像的最终分数。
同样,在他们 2015 年关于 Inception 架构的论文《重新思考计算机视觉的 Inception 架构》中,Google 的作者使用了裁剪测试时增强,他们将其称为多裁剪评估。
想通过深度学习实现计算机视觉成果吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
Keras 中的测试时增强
Keras 深度学习库不原生提供测试时增强,但可以轻松实现。
ImageDataGenerator 类可用于配置测试时增强的选择。例如,以下数据生成器配置用于水平翻转图像数据增强。
1 2 |
# 配置图像数据增强 datagen = ImageDataGenerator(horizontal_flip=True) |
然后可以将增强应用于测试数据集中每个样本。
首先,可以将单个图像的维度从 [行][列][通道] 扩展到 [样本][行][列][通道],其中样本数为一,表示单个图像。这将图像的数组转换为包含一个图像的样本数组。
1 2 |
# 将图像转换为数据集 samples = expand_dims(image, 0) |
接下来,可以为样本创建一个迭代器,批大小可用于指定要生成的增强图像的数量,例如 10。
1 2 |
# 准备迭代器 it = datagen.flow(samples, batch_size=10) |
然后可以将迭代器传递给模型的 predict_generator() 函数以进行预测。具体来说,将生成 10 个增强图像的批次,模型将对每个图像进行预测。
1 2 |
# 对每个增强图像进行预测 yhats = model.predict_generator(it, steps=10, verbose=0) |
最后,可以进行集成预测。已经对每个图像进行了预测,并且每个预测都包含图像属于每个类别的概率,在图像多类分类的情况下。
可以使用软投票进行集成预测,其中每个类别的概率在预测中求和,并通过计算求和预测的argmax()来做出类别预测,返回最大求和概率的索引或类别编号。
1 2 3 4 |
# 对预测求和 summed = numpy.sum(yhats, axis=0) # 对类别求argmax return argmax(summed) |
我们可以将这些元素组合成一个函数,该函数将接收配置好的数据生成器、已拟合的模型和单个图像,并使用测试时增强返回类别预测(整数)。
1 2 3 4 5 6 7 8 9 10 11 12 |
# 使用测试时增强进行预测 def tta_prediction(datagen, model, image, n_examples): # 将图像转换为数据集 samples = expand_dims(image, 0) # 准备迭代器 it = datagen.flow(samples, batch_size=n_examples) # 对每个增强图像进行预测 yhats = model.predict_generator(it, steps=n_examples, verbose=0) # 对预测求和 summed = numpy.sum(yhats, axis=0) # 跨类求 argmax return argmax(summed) |
现在我们知道如何在 Keras 中使用测试时增强进行预测,接下来我们通过一个示例来演示这种方法。
数据集和基线模型
我们可以使用标准计算机视觉数据集和卷积神经网络来演示测试时增强。
在此之前,我们必须选择一个数据集和一个基线模型。
我们将使用 CIFAR-10 数据集,它包含 60,000 张 32×32 像素的彩色照片,分为 10 个类别,如青蛙、鸟、猫、船等。CIFAR-10 是一个广为人知的数据集,广泛用于机器学习领域计算机视觉算法的基准测试。该问题已“解决”。在该问题上,深度学习卷积神经网络在测试数据集上分类准确率超过 96% 或 97%,达到了最佳性能。
我们还将使用一个卷积神经网络(CNN)模型,它能够在该问题上取得良好(优于随机)但并非最先进的成果。这将足以展示测试时增强所能带来的性能提升。
通过调用 cifar10.load_data() 函数,可以轻松地通过 Keras API 加载 CIFAR-10 数据集,该函数返回一个元组,其中包含训练和测试数据集,并分为输入(图像)和输出(类标签)组件。
1 2 |
# 加载数据集 (trainX, trainY), (testX, testY) = load_data() |
在建模之前,将像素值从 0-255 范围标准化到 0-1 范围是一个好习惯。这确保了输入值小且接近零,反过来意味着模型的权重将保持较小,从而导致更快更好的学习。
1 2 3 |
# 归一化像素值 trainX = trainX.astype('float32') / 255 testX = testX.astype('float32') / 255 |
类标签是整数,在建模之前必须转换为独热编码。
这可以通过使用 Keras 实用函数 to_categorical() 实现。
1 2 3 |
# 独热编码目标值 trainY = to_categorical(trainY) testY = to_categorical(testY) |
我们现在准备为这个多类分类问题定义一个模型。
该模型有一个卷积层,包含 32 个滤波器,3×3 内核,使用整流线性激活函数,"相同"填充使输出与输入大小相同,并使用 He 权重初始化。这之后是一个批量归一化层和一个最大池化层。
此模式重复,包含一个卷积层、批量归一化层和最大池化层,尽管滤波器数量增加到 64。然后输出被展平,然后由一个全连接层解释,最后提供给输出层进行预测。
1 2 3 4 5 6 7 8 9 10 11 12 |
# 定义模型 model = Sequential() model.add(Conv2D(32, (3, 3), activation='relu', padding='same', kernel_initializer='he_uniform', input_shape=(32, 32, 3))) model.add(BatchNormalization()) model.add(MaxPooling2D((2, 2))) model.add(Conv2D(64, (3, 3), activation='relu', padding='same', kernel_initializer='he_uniform')) model.add(BatchNormalization()) model.add(MaxPooling2D((2, 2))) model.add(Flatten()) model.add(Dense(128, activation='relu', kernel_initializer='he_uniform')) model.add(BatchNormalization()) model.add(Dense(10, activation='softmax')) |
使用随机梯度下降的 Adam 变体来寻找模型权重。
使用分类交叉熵损失函数,这是多类分类所必需的,并在训练期间监控分类准确率。
1 2 |
# 编译模型 model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) |
模型经过三个训练周期,使用 128 张图像的大批量大小进行拟合。
1 2 |
# 拟合模型 model.fit(trainX, trainY, epochs=3, batch_size=128) |
一旦拟合完成,模型就会在测试数据集上进行评估。
1 2 3 |
# 评估模型 _, acc = model.evaluate(testX, testY, verbose=0) print(acc) |
完整的示例列于下方,可在几分钟内在 CPU 上轻松运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# cifar10 问题的基线 cnn 模型 from keras.datasets.cifar10 import load_data from keras.utils import to_categorical from keras.models import Sequential 从 keras.layers 导入 Conv2D 从 keras.layers 导入 MaxPooling2D from keras.layers import Dense from keras.layers import Flatten from keras.layers import BatchNormalization # 加载数据集 (trainX, trainY), (testX, testY) = load_data() # 归一化像素值 trainX = trainX.astype('float32') / 255 testX = testX.astype('float32') / 255 # 独热编码目标值 trainY = to_categorical(trainY) testY = to_categorical(testY) # 定义模型 model = Sequential() model.add(Conv2D(32, (3, 3), activation='relu', padding='same', kernel_initializer='he_uniform', input_shape=(32, 32, 3))) model.add(BatchNormalization()) model.add(MaxPooling2D((2, 2))) model.add(Conv2D(64, (3, 3), activation='relu', padding='same', kernel_initializer='he_uniform')) model.add(BatchNormalization()) model.add(MaxPooling2D((2, 2))) model.add(Flatten()) model.add(Dense(128, activation='relu', kernel_initializer='he_uniform')) model.add(BatchNormalization()) model.add(Dense(10, activation='softmax')) # 编译模型 model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) # 拟合模型 history = model.fit(trainX, trainY, epochs=3, batch_size=128) # 评估模型 _, acc = model.evaluate(testX, testY, verbose=0) print(acc) |
运行示例表明模型能够很好且快速地学习问题。
测试集准确率达到约 66%,这还不错,但并不出色。所选的模型配置已经开始过拟合,可以受益于正则化和进一步的调整。尽管如此,这为演示测试时增强提供了一个很好的起点。
1 2 3 4 5 6 7 |
Epoch 1/3 50000/50000 [==============================] - 64s 1ms/step - loss: 1.2135 - acc: 0.5766 Epoch 2/3 50000/50000 [==============================] - 63s 1ms/step - loss: 0.8498 - acc: 0.7035 Epoch 3/3 50000/50000 [==============================] - 63s 1ms/step - loss: 0.6799 - acc: 0.7632 0.6679 |
神经网络是随机算法,同一个模型在相同数据上多次拟合可能会找到不同的权重集,从而每次性能也不同。
为了平滑模型性能的估计,我们可以修改示例,多次重新运行模型的拟合和评估,并报告测试数据集上分数分布的均值和标准差。
首先,我们可以定义一个名为 load_dataset() 的函数,它将加载 CIFAR-10 数据集并准备好进行建模。
1 2 3 4 5 6 7 8 9 10 11 |
# 加载并返回准备好建模的 cifar10 数据集 def load_dataset(): # 加载数据集 (trainX, trainY), (testX, testY) = load_data() # 归一化像素值 trainX = trainX.astype('float32') / 255 testX = testX.astype('float32') / 255 # 独热编码目标值 trainY = to_categorical(trainY) testY = to_categorical(testY) return trainX, trainY, testX, testY |
接下来,我们可以定义一个名为 define_model() 的函数,它将定义一个用于 CIFAR-10 数据集的模型,准备进行拟合和评估。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# 为 cifar10 数据集定义 cnn 模型 def define_model(): # 定义模型 model = Sequential() model.add(Conv2D(32, (3, 3), activation='relu', padding='same', kernel_initializer='he_uniform', input_shape=(32, 32, 3))) model.add(BatchNormalization()) model.add(MaxPooling2D((2, 2))) model.add(Conv2D(64, (3, 3), activation='relu', padding='same', kernel_initializer='he_uniform')) model.add(BatchNormalization()) model.add(MaxPooling2D((2, 2))) model.add(Flatten()) model.add(Dense(128, activation='relu', kernel_initializer='he_uniform')) model.add(BatchNormalization()) model.add(Dense(10, activation='softmax')) # 编译模型 model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) return model |
接下来,定义了一个 evaluate_model() 函数,它将在训练数据集上拟合定义的模型,然后在测试数据集上评估它,返回运行的估计分类准确率。
1 2 3 4 5 6 7 |
# 拟合和评估已定义的模型 def evaluate_model(model, trainX, trainY, testX, testY): # 拟合模型 model.fit(trainX, trainY, epochs=3, batch_size=128, verbose=0) # 评估模型 _, acc = model.evaluate(testX, testY, verbose=0) return acc |
接下来,我们可以定义一个具有新行为的函数,以重复定义、拟合和评估一个新模型,并返回准确率分数的分布。
下面的 repeated_evaluation() 函数实现了这一点,它接收数据集并使用默认的 10 次重复评估。
1 2 3 4 5 6 7 8 9 10 11 12 |
# 重复评估模型,返回分数分布 def repeated_evaluation(trainX, trainY, testX, testY, repeats=10): scores = list() for _ in range(repeats): # 定义模型 model = define_model() # 拟合和评估模型 accuracy = evaluate_model(model, trainX, trainY, testX, testY) # 存储分数 scores.append(accuracy) print('> %.3f' % accuracy) return scores |
最后,我们可以调用 load_dataset() 函数来准备数据集,然后调用 repeated_evaluation() 来获取准确率分数分布,该分布可以通过报告均值和标准差来总结。
1 2 3 4 5 6 |
# 加载数据集 trainX, trainY, testX, testY = load_dataset() # 评估模型 scores = repeated_evaluation(trainX, trainY, testX, testY) # 总结结果 print('Accuracy: %.3f (%.3f)' % (mean(scores), std(scores))) |
将所有这些结合起来,下面列出了在 MNIST 数据集上重复评估 CNN 模型的完整代码示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# cifar10 问题的基线 cnn 模型,重复评估 from numpy import mean from numpy import std from keras.datasets.cifar10 import load_data from keras.utils import to_categorical from keras.models import Sequential 从 keras.layers 导入 Conv2D 从 keras.layers 导入 MaxPooling2D from keras.layers import Dense from keras.layers import Flatten from keras.layers import BatchNormalization # 加载并返回准备好建模的 cifar10 数据集 def load_dataset(): # 加载数据集 (trainX, trainY), (testX, testY) = load_data() # 归一化像素值 trainX = trainX.astype('float32') / 255 testX = testX.astype('float32') / 255 # 独热编码目标值 trainY = to_categorical(trainY) testY = to_categorical(testY) return trainX, trainY, testX, testY # 为 cifar10 数据集定义 cnn 模型 def define_model(): # 定义模型 model = Sequential() model.add(Conv2D(32, (3, 3), activation='relu', padding='same', kernel_initializer='he_uniform', input_shape=(32, 32, 3))) model.add(BatchNormalization()) model.add(MaxPooling2D((2, 2))) model.add(Conv2D(64, (3, 3), activation='relu', padding='same', kernel_initializer='he_uniform')) model.add(BatchNormalization()) model.add(MaxPooling2D((2, 2))) model.add(Flatten()) model.add(Dense(128, activation='relu', kernel_initializer='he_uniform')) model.add(BatchNormalization()) model.add(Dense(10, activation='softmax')) # 编译模型 model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) return model # 拟合和评估已定义的模型 def evaluate_model(model, trainX, trainY, testX, testY): # 拟合模型 model.fit(trainX, trainY, epochs=3, batch_size=128, verbose=0) # 评估模型 _, acc = model.evaluate(testX, testY, verbose=0) return acc # 重复评估模型,返回分数分布 def repeated_evaluation(trainX, trainY, testX, testY, repeats=10): scores = list() for _ in range(repeats): # 定义模型 model = define_model() # 拟合和评估模型 accuracy = evaluate_model(model, trainX, trainY, testX, testY) # 存储分数 scores.append(accuracy) print('> %.3f' % accuracy) 返回 分数 # 加载数据集 trainX, trainY, testX, testY = load_dataset() # 评估模型 scores = repeated_evaluation(trainX, trainY, testX, testY) # 总结结果 print('Accuracy: %.3f (%.3f)' % (mean(scores), std(scores))) |
在现代 CPU 硬件上运行该示例可能需要一些时间,而在 GPU 硬件上会快得多。
报告了每次重复评估的模型准确性,并报告了最终的平均模型性能。
在这种情况下,我们可以看到所选模型配置的平均准确度约为 68%,这与单次模型运行的估计值接近。
1 2 3 4 5 6 7 8 9 10 11 |
> 0.690 > 0.662 > 0.698 > 0.681 > 0.686 > 0.680 > 0.697 > 0.696 > 0.689 > 0.679 准确度:0.686 (0.010) |
现在我们已经为一个标准数据集开发了一个基线模型,接下来让我们更新示例以使用测试时增强。
测试时增强示例
现在我们可以更新我们对 CIFAR-10 上的 CNN 模型的重复评估,以使用测试时增强。
上面关于如何在 Keras 中实现测试时增强的部分中开发的 tta_prediction() 函数可以直接使用。
1 2 3 4 5 6 7 8 9 10 11 12 |
# 使用测试时增强进行预测 def tta_prediction(datagen, model, image, n_examples): # 将图像转换为数据集 samples = expand_dims(image, 0) # 准备迭代器 it = datagen.flow(samples, batch_size=n_examples) # 对每个增强图像进行预测 yhats = model.predict_generator(it, steps=n_examples, verbose=0) # 对预测求和 summed = numpy.sum(yhats, axis=0) # 跨类求 argmax return argmax(summed) |
我们可以开发一个函数来驱动测试时增强,通过定义 ImageDataGenerator 配置并为测试数据集中的每个图像调用 tta_prediction()。
考虑哪些图像增强类型可能有助于在 CIFAR-10 数据集上拟合的模型是很重要的。对照片进行微小修改的增强可能很有用。这可能包括缩放、平移和水平翻转等增强。
在此示例中,我们只使用水平翻转。
1 2 |
# 配置图像数据增强 datagen = ImageDataGenerator(horizontal_flip=True) |
我们将配置图像生成器以创建七张照片,从中将对测试集中每个示例的平均预测进行。
下面的 tta_evaluate_model() 函数配置 ImageDataGenerator,然后枚举测试数据集,为测试数据集中的每个图像进行类标签预测。然后通过比较预测的类标签与测试数据集中的类标签来计算准确率。这需要我们使用 argmax() 反转 load_dataset() 中执行的独热编码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# 使用测试时增强评估数据集上的模型 def tta_evaluate_model(model, testX, testY): # 配置图像数据增强 datagen = ImageDataGenerator(horizontal_flip=True) # 定义每个测试集图像要生成的增强图像数量 n_examples_per_image = 7 yhats = list() for i in range(len(testX)): # 进行增强预测 yhat = tta_prediction(datagen, model, testX[i], n_examples_per_image) # 存储以供评估 yhats.append(yhat) # 计算准确率 testY_labels = argmax(testY, axis=1) acc = accuracy_score(testY_labels, yhats) return acc |
然后可以更新 evaluate_model() 函数以调用 tta_evaluate_model() 来获取模型准确率分数。
1 2 3 4 5 6 7 |
# 拟合和评估已定义的模型 def evaluate_model(model, trainX, trainY, testX, testY): # 拟合模型 model.fit(trainX, trainY, epochs=3, batch_size=128, verbose=0) # 使用 tta 评估模型 acc = tta_evaluate_model(model, testX, testY) return acc |
将所有这些结合起来,下面列出了 CIFAR-10 与测试时增强的 CNN 重复评估的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# 带有测试时增强的 cifar10 问题的 cnn 模型 import numpy from numpy import argmax from numpy import mean from numpy import std from numpy import expand_dims from sklearn.metrics import accuracy_score from keras.datasets.cifar10 import load_data from keras.utils import to_categorical from keras.preprocessing.image import ImageDataGenerator from keras.models import Sequential 从 keras.layers 导入 Conv2D 从 keras.layers 导入 MaxPooling2D from keras.layers import Dense from keras.layers import Flatten from keras.layers import BatchNormalization # 加载并返回准备好建模的 cifar10 数据集 def load_dataset(): # 加载数据集 (trainX, trainY), (testX, testY) = load_data() # 归一化像素值 trainX = trainX.astype('float32') / 255 testX = testX.astype('float32') / 255 # 独热编码目标值 trainY = to_categorical(trainY) testY = to_categorical(testY) return trainX, trainY, testX, testY # 为 cifar10 数据集定义 cnn 模型 def define_model(): # 定义模型 model = Sequential() model.add(Conv2D(32, (3, 3), activation='relu', padding='same', kernel_initializer='he_uniform', input_shape=(32, 32, 3))) model.add(BatchNormalization()) model.add(MaxPooling2D((2, 2))) model.add(Conv2D(64, (3, 3), activation='relu', padding='same', kernel_initializer='he_uniform')) model.add(BatchNormalization()) model.add(MaxPooling2D((2, 2))) model.add(Flatten()) model.add(Dense(128, activation='relu', kernel_initializer='he_uniform')) model.add(BatchNormalization()) model.add(Dense(10, activation='softmax')) # 编译模型 model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) return model # 使用测试时增强进行预测 def tta_prediction(datagen, model, image, n_examples): # 将图像转换为数据集 samples = expand_dims(image, 0) # 准备迭代器 it = datagen.flow(samples, batch_size=n_examples) # 对每个增强图像进行预测 yhats = model.predict_generator(it, steps=n_examples, verbose=0) # 对预测求和 summed = numpy.sum(yhats, axis=0) # 跨类求 argmax return argmax(summed) # 使用测试时增强评估数据集上的模型 def tta_evaluate_model(model, testX, testY): # 配置图像数据增强 datagen = ImageDataGenerator(horizontal_flip=True) # 定义每个测试集图像要生成的增强图像数量 n_examples_per_image = 7 yhats = list() for i in range(len(testX)): # 进行增强预测 yhat = tta_prediction(datagen, model, testX[i], n_examples_per_image) # 存储以供评估 yhats.append(yhat) # 计算准确率 testY_labels = argmax(testY, axis=1) acc = accuracy_score(testY_labels, yhats) return acc # 拟合和评估已定义的模型 def evaluate_model(model, trainX, trainY, testX, testY): # 拟合模型 model.fit(trainX, trainY, epochs=3, batch_size=128, verbose=0) # 使用 tta 评估模型 acc = tta_evaluate_model(model, testX, testY) return acc # 重复评估模型,返回分数分布 def repeated_evaluation(trainX, trainY, testX, testY, repeats=10): scores = list() for _ in range(repeats): # 定义模型 model = define_model() # 拟合和评估模型 accuracy = evaluate_model(model, trainX, trainY, testX, testY) # 存储分数 scores.append(accuracy) print('> %.3f' % accuracy) 返回 分数 # 加载数据集 trainX, trainY, testX, testY = load_dataset() # 评估模型 scores = repeated_evaluation(trainX, trainY, testX, testY) # 总结结果 print('Accuracy: %.3f (%.3f)' % (mean(scores), std(scores))) |
鉴于重复评估和用于评估每个模型的较慢手动测试时增强,运行该示例可能需要一些时间。
在这种情况下,我们可以看到性能适度提升,从不使用测试时增强的测试集上的约 68.6% 提高到使用测试时增强的测试集上的约 69.8% 准确率。
1 2 3 4 5 6 7 8 9 10 11 |
> 0.719 > 0.716 > 0.709 > 0.694 > 0.690 > 0.694 > 0.680 > 0.676 > 0.702 > 0.704 准确度:0.698 (0.013) |
如何调整测试时增强配置
选择能够最大程度提升模型性能的增强配置可能具有挑战性。
不仅有许多增强方法可供选择以及每种方法的配置选项,而且在单个配置选项集上拟合和评估模型可能需要很长时间,即使在快速 GPU 上拟合也是如此。
相反,我建议拟合模型一次并将其保存到文件中。例如:
1 2 |
# 保存模型 model.save('model.h5') |
然后从单独的文件加载模型,并在小验证数据集或测试集的小子集上评估不同的测试时增强方案。
例如:
1 2 3 4 5 6 |
... # 加载模型 model = load_model('model.h5') # 评估模型 datagen = ImageDataGenerator(...) ... |
一旦您找到了一组能够最大程度提升性能的增强选项,您就可以在整个测试集上评估模型,或者像上面那样尝试重复评估实验。
测试时增强配置不仅包括 ImageDataGenerator 的选项,还包括从每个测试集示例中生成平均预测的图像数量。
我使用这种方法在上一节中选择了测试时增强,发现七个示例比三个或五个效果更好,并且随机缩放和随机平移似乎降低了模型准确性。
请记住,如果您还在训练数据集上使用图像数据增强,并且该增强使用了涉及计算数据集统计信息(例如,您调用 datagen.fit())的像素缩放类型,那么在测试时增强期间也必须使用相同的统计信息和像素缩放技术。
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
API
文章
总结
在本教程中,您学习了如何使用测试时增强来提高图像分类任务模型的性能。
具体来说,你学到了:
- 测试时增强是在进行预测时应用通常在训练期间使用的数据增强技术。
- 如何在 Keras 中从头开始实现测试时增强。
- 如何使用测试时增强来提高卷积神经网络模型在标准图像分类任务上的性能。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
你好。我叫 sang-min。
我看到了你的文章,写得很好。
我想尝试在目标检测中使用 TTA(测试时增强),但效果不佳。
在我看来,TTA 的关键是平均模型结果分数。
但是,目标检测需要提取边界框,所以我不确定如何平均这些框。
如果您有好的解决方案,请给我建议。
谢谢!!!
很好的问题。
也许可以查阅文献,了解在目标检测中使用 TTA 的好方法?
我有一个多类别不平衡问题,有 3 个类别,每个类别只有一个实例,另外 3 个类别,每个类别有两个实例等等。多数类别有 84 个实例。预处理后,数据集中的实例从 339 个减少到 309 个。
无论我尝试什么方法,都无法获得良好的性能。我尝试了 RandomOverSampling,但它并没有给我带来良好的性能。我无法使用 SMOTE 或任何其他与 SMOTE 相关的技术,因为我有许多样本很少的类别,并且它们都会报错。我尝试了层次分类和许多其他算法,但它们似乎在多数类别上表现得相当好,但对少数类别根本不起作用。我获得的总体性能是测试集上的 0.40 f1 分数,模型似乎过度拟合很多。
我发现了一个使用贝叶斯网络生成器创建的数据集,它创建了类似于原始数据集的人工数据。这个人工数据集的属性分布看起来与原始数据集非常相似。
顺便问一下,这个问题与原发性肿瘤分类有关,在这种情况下,我是否可以从这个人工数据集中抽取样本并将其与我的原始数据集结合用于训练、测试或开发?
如果这可行,将人工实例与我的原始数据集结合的正确方法是什么?
谢谢
San
如果它能在你的测试工具上产生更好的结果,并且你的测试工具是健壮的,那就去做吧。
嗨,您编写的 TTA 代码如何导致模型本身的更好训练?模型只在 model.fit() 步骤中进行训练,而其他步骤只是在数据的不同增强上评估模型。您可以解释一下吗?
在某些情况下(某些模型/某些数据集),TTA 会在相同数据集上多次尝试进行预测,这可以带来更好的性能。
模型可以从不同的角度观察输入。
先生,测试时增强也适用于数值数据集吗?请提供一个示例。
它可以是。
我有一篇关于这个主题的教程即将推出。敬请期待!
谢谢您的教程。
不过我只是在寻找代码的生成器部分,但上面提供的代码无法从一张图像中生成 10 个增强样本。图像数据生成器函数只对样本循环一次,并创建一个批大小为 1 的批次(无论我们设置的 batch_size 和 steps 变量是什么)。因此,我不得不将生成器放入一个循环中,并对其求和以获得“summed”变量。
您可以根据需要更改代码以循环多次。
嘿,我如何将此应用于图像增强任务?我有重建的图像和真实图像。使用 MSE 损失和 Adam 优化器,采用 UNET 架构。我想在处理新数据集时执行 TTA。
嗨,Harsha…测试时增强(TTA)是机器学习中常用的一种技术,通过对输入数据应用各种变换并平均预测来提高模型在推理期间的性能。这有助于减少过拟合并提高模型的鲁棒性。以下是如何在 Python 中应用测试时增强:
1. **准备您的模型**:首先,确保您有一个已训练好的模型可以进行推理。这可能是一个使用 TensorFlow、PyTorch 或 scikit-learn 等库训练的神经网络模型。
2. **定义增强变换**:定义一组要应用于测试数据的增强变换。这些变换可以包括旋转、翻转、缩放、裁剪或颜色抖动等技术。
3. **在推理期间执行 TTA**:在推理期间,将每个增强变换应用于输入数据,并使用您的模型进行预测。然后,平均预测以获得最终输出。
这是一个使用
imgaug
库进行图像增强并将 TTA 应用于图像分类的 Python 代码示例:python
import numpy as np
import imgaug.augmenters as iaa
# 定义你的模型
# 示例
# from keras.models import load_model
# model = load_model('path_to_your_model.h5')
# 定义增强变换
augmentation = iaa.Sequential([
iaa.Fliplr(0.5), # 水平翻转 50% 的图像
iaa.Affine(rotate=(-20, 20)), # 将图像旋转 -20 到 +20 度
iaa.GaussianBlur(sigma=(0, 3.0)) # 应用高斯模糊,sigma 在 0 到 3.0 之间
])
def predict_with_tta(model, images, n_augmentations=5)
all_predictions = []
for _ in range(n_augmentations)
augmented_images = augmentation(images=images)
predictions = model.predict(augmented_images)
all_predictions.append(predictions)
# 平均预测
avg_predictions = np.mean(all_predictions, axis=0)
return avg_predictions
# 示例用法:
# images = load_test_images()
# predictions = predict_with_tta(model, images)
# print(predictions)
在此示例中:
– 我们使用
imgaug
库来定义一组增强变换。–
predict_with_tta
函数接受训练好的模型、输入图像和要应用的增强次数。它将增强变换应用于输入图像,使用模型对每个增强版本进行预测,并平均预测结果。您可以根据您的具体用例和数据特征调整增强技术和参数。此外,请确保根据您的模型和数据的特定要求和 API 调整代码。