测试集的精确度达到了66%,这是可以接受的,但不是很好。所选择的模型配置已经开始过度拟合,可以从正则化和进一步调优的使用中受益。然而,这为演示测试时增强提供了一个很好的起点。
Epoch1/350000/50000 [==============================] -64s1ms/step-loss: 1.2135-acc: 0.5766Epoch2/350000/50000 [==============================] -63s1ms/step-loss: 0.8498-acc: 0.7035Epoch3/350000/50000 [==============================] -63s1ms/step-loss: 0.6799-acc: 0.76320.6679
神经网络是一种随机算法,相同的模型在相同的数据上多次拟合可能会找到不同的权值集,反过来,每次都有不同的性能。
为了平衡模型性能的估计,我们可以更改示例,多次重新运行模型的拟合和评估,并报告测试数据集上得分分布的平均值和标准偏差。
首先,我们可以定义一个名为load_dataset()的函数,它将加载CIFAR-10数据集并为建模做好准备。
#loadandreturnthecifar10datasetreadyformodelingdefload_dataset(): #loaddataset (trainX, trainY), (testX, testY) =load_data() #normalizepixelvaluestrainX=trainX.astype('float32') /255testX=testX.astype('float32') /255#onehotencodetargetvaluestrainY=to_categorical(trainY) testY=to_categorical(testY) returntrainX, trainY, testX, testY
接下来,我们可以定义一个名为define_model()的函数,它将为CIFAR-10数据集定义一个模型,准备好适合它并进行计算。
#definethecnnmodelforthecifar10datasetdefdefine_model(): #definemodelmodel=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')) #compilemodelmodel.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) returnmodel
接下来,定义一个evaluate_model()函数,它将在训练数据集上适合定义的模型,然后在测试数据集上评估它,返回运行的估计分类精度。
#fitandevaluateadefinedmodeldefevaluate_model(model, trainX, trainY, testX, testY): #fitmodelmodel.fit(trainX, trainY, epochs=3, batch_size=128, verbose=0) #evaluatemodel_, acc=model.evaluate(testX, testY, verbose=0) returnacc
接下来,我们可以定义一个新的函数来重复定义、拟合和评估一个新模型,并返回精度分数的分布。
下面的repeated_evaluation()函数实现了这一点,获取数据集并使用默认的10个重复求值。
#repeatedlyevaluatemodel, returndistributionofscoresdefrepeated_evaluation(trainX, trainY, testX, testY, repeats=10): scores=list() for_inrange(repeats): #definemodelmodel=define_model() #fitandevaluatemodelaccuracy=evaluate_model(model, trainX, trainY, testX, testY) #storescorescores.append(accuracy) print('> %.3f'%accuracy) returnscores
最后,我们可以调用load_dataset()函数来准备数据集,然后再调用repeated_evaluation()来获得精度得分的分布,可以通过报告平均值和标准偏差来汇总。
#loaddatasettrainX, trainY, testX, testY=load_dataset() #evaluatemodelscores=repeated_evaluation(trainX, trainY, testX, testY) #summarizeresultprint('Accuracy: %.3f (%.3f)'% (mean(scores), std(scores)))
将所有这些结合在一起,下面列出了在cifar10数据集上重复评估CNN模型的完整代码示例。
#baselinecnnmodelforthecifar10problem, repeatedevaluationfromnumpyimportmeanfromnumpyimportstdfromkeras.datasets.cifar10importload_datafromkeras.utilsimportto_categoricalfromkeras.modelsimportSequentialfromkeras.layersimportConv2Dfromkeras.layersimportMaxPooling2Dfromkeras.layersimportDensefromkeras.layersimportFlattenfromkeras.layersimportBatchNormalization#loadandreturnthecifar10datasetreadyformodelingdefload_dataset(): #loaddataset (trainX, trainY), (testX, testY) =load_data() #normalizepixelvaluestrainX=trainX.astype('float32') /255testX=testX.astype('float32') /255#onehotencodetargetvaluestrainY=to_categorical(trainY) testY=to_categorical(testY) returntrainX, trainY, testX, testY#definethecnnmodelforthecifar10datasetdefdefine_model(): #definemodelmodel=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')) #compilemodelmodel.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) returnmodel#fitandevaluateadefinedmodeldefevaluate_model(model, trainX, trainY, testX, testY): #fitmodelmodel.fit(trainX, trainY, epochs=3, batch_size=128, verbose=0) #evaluatemodel_, acc=model.evaluate(testX, testY, verbose=0) returnacc#repeatedlyevaluatemodel, returndistributionofscoresdefrepeated_evaluation(trainX, trainY, testX, testY, repeats=10): scores=list() for_inrange(repeats): #definemodelmodel=define_model() #fitandevaluatemodelaccuracy=evaluate_model(model, trainX, trainY, testX, testY) #storescorescores.append(accuracy) print('> %.3f'%accuracy) returnscores#loaddatasettrainX, trainY, testX, testY=load_dataset() #evaluatemodelscores=repeated_evaluation(trainX, trainY, testX, testY) #summarizeresultprint('Accuracy: %.3f (%.3f)'% (mean(scores), std(scores)))
在CPU硬件上运行这个例子可能需要一些时间,但在GPU硬件上运行速度更快。
对每次重复评价报告模型的准确性,并报告最终的平均模型性能。
在这种情况下,我们可以看到选择的模型配置的平均精度约为68%,这接近于单个模型运行时的估计。
>0.690>0.662>0.698>0.681>0.686>0.680>0.697>0.696>0.689>0.679Accuracy: 0.686 (0.010)
现在我们已经为一个标准数据集开发了一个基线模型,让我们看看如何使用TTA扩展这个示例。
TTA的例子
我们现在可以更新CIFAR-10上CNN模型的重复评估,以使用测试时间增强。
上面关于如何在Keras中TTA的一节中开发的tta_predict()函数可以直接使用。
#makeapredictionusingtest-timeaugmentationdeftta_prediction(datagen, model, image, n_examples): #convertimageintodatasetsamples=expand_dims(image, 0) #prepareiteratorit=datagen.flow(samples, batch_size=n_examples) #makepredictionsforeachaugmentedimageyhats=model.predict_generator(it, steps=n_examples, verbose=0) #sumacrosspredictionssummed=numpy.sum(yhats, axis=0) #argmaxacrossclassesreturnargmax(summed)
我们可以通过定义ImageDataGenerator配置并为测试数据集中的每个图像调用tta_prediction()来开发一个TTA的函数。
重要的是要考虑可能使模型适合CIFAR-10数据集的图像增强类型。对照片进行微小修改的增强可能是有用的。这可能包括缩放、移动和水平翻转等增强功能。
在本例中,我们将只使用水平翻转。
#configureimagedataaugmentationdatagen=ImageDataGenerator(horizontal_flip=True)
我们将配置图像生成器来创建7张照片,从这些照片可以对测试集中每个示例进行平均预测。
下面的tta_evaluate_model()函数配置ImageDataGenerator,然后枚举测试数据集,为测试数据集中的每个图像制作一个类标签预测。然后,通过将预测的类标签与测试数据集中的类标签进行比较来计算精度。这需要我们通过使用argmax()逆转load_dataset()中执行的一个热编码。
#evaluateamodelonadatasetusingtest-timeaugmentationdeftta_evaluate_model(model, testX, testY): #configureimagedataaugmentationdatagen=ImageDataGenerator(horizontal_flip=True) #definethenumberofaugmentedimagestogeneratepertestsetimagen_examples_per_image=7yhats=list() foriinrange(len(testX)): #makeaugmentedpredictionyhat=tta_prediction(datagen, model, testX[i], n_examples_per_image) #storeforevaluationyhats.append(yhat) #calculateaccuracytestY_labels=argmax(testY, axis=1) acc=accuracy_score(testY_labels, yhats) returnacc