我想加载一个预训练模型并开始对图像进行测试。
我以为这会有效的代码如下:
from keras.applications.inception_v3 import InceptionV3from keras.preprocessing import imagefrom keras.models import Modelfrom keras.layers import Dense, GlobalAveragePooling2Dfrom keras import backend as Kbase_model = InceptionV3(weights='imagenet', include_top=False)from __future__ import absolute_import, division, print_functionimport tensorflow as tffrom tensorflow import kerasimport numpy as npimport matplotlib.pyplot as plt#Preprocessingfashion_mnist = keras.datasets.fashion_mnist(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']train_images = train_images / 255.0test_images = test_images / 255.0#Preprocessingtest_loss, test_acc = base_model.evaluate(test_images, test_labels)print('Test accuracy:', test_acc)
然而,它显示:“在训练/测试之前必须编译模型”
在https://keras.io/applications/查看InceptionV3时:他们似乎在导入模型后进行编译和拟合。为什么他们要这样做?
回答:
InceptionV3模型是在与Fashion MNIST非常不同的图像上训练的。你在教程中看到的是迁移学习的一个实例。大致来说,在迁移学习中,你可以将模型分成特征提取模块和分类模块。卷积层和池化层的目标是自动化特征提取,以便我们可以从原始图像像素生成一个理想的转换,产生一组代表性特征,这些特征很好地描述了图像。
然后这些图像被输入到分类模块,目标是利用这些特征进行实际的分类。这就是卷积和池化后附加的密集层的目标。还要注意,InceptionV3模型是在ImageNet图像上训练的,这些图像有1000个类别。为了成功地将ImageNet应用于Fashion MNIST数据集,你需要重新训练密集层,以便卷积和池化层可以利用从图像中提取的特征进行分类。因此,像你所做的那样设置include_top=False
,但你还需要附加一些密集层并重新训练它们。还要确保你指定最后一层有10个类,因为Fashion MNIST数据集是这样设置的。
然而,需要注意的是,InceptionV3接受299 x 299大小的图像,而Fashion MNIST接受28 x 28的图像。你需要调整图像大小,并在第三维度上人为地填充图像,使它们成为RGB图像。因为从28 x 28调整到299 x 299需要在两个维度上增加10倍的因子,将图像调整到这种分辨率可能在感知上不会很好。InceptionV3可以加载一个模型,你可以更改预期的输入图像大小。不幸的是,InceptionV3的最小图像大小是75 x 75,所以我们必须使用这个,然后调整到75 x 75。要调整图像大小,你可以使用Scikit-images的resize
方法来自skimage.transform
。另外,如果你计划使用InceptionV3,你需要像他们在训练前对网络所做的那样预处理输入图像。
因此:
from __future__ import absolute_import, division, print_functionfrom keras.applications.inception_v3 import InceptionV3from keras.preprocessing import imagefrom keras.applications.inception_v3 import preprocess_input # Newfrom keras.models import Modelfrom keras.layers import Dense, GlobalAveragePooling2Dfrom keras import backend as Kimport tensorflow as tffrom tensorflow import kerasimport numpy as npimport matplotlib.pyplot as pltbase_model = InceptionV3(weights='imagenet', include_top=False, input_shape=(75, 75, 3))# 现在添加一些密集层 - 我们也添加一个全局平均池化层作为一种更好的“扁平化”方式x = base_model.outputx = GlobalAveragePooling2D()(x)# 让我们添加一个全连接层x = Dense(1024, activation='relu')(x)# 以及一个softmax层 -- 10个类predictions = Dense(10, activation='softmax')(x)# 创建新模型model = Model(inputs=base_model.input, outputs=predictions)# 确保我们设置卷积层和池化层,使它们不可训练for layer in base_model.layers: layer.trainable = False#Preprocessingfashion_mnist = keras.datasets.fashion_mnist(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']train_images = train_images.astype(np.float) / 255.0 # Changetest_images = test_images.astype(np.float) / 255.0 # Change# 预处理图像from skimage.transform import resizetrain_images_preprocess = np.zeros((train_images.shape[0], 75, 75, 3), dtype=np.float32)for i, img in enumerate(train_images): img_resize = resize(img, (75, 75), anti_aliasing=True) img_resize = preprocess_input(img_resize).astype(np.float32) train_images_preprocess[i] = np.dstack([img_resize, img_resize, img_resize])del train_imagestest_images_preprocess = np.zeros((test_images.shape[0], 75, 75, 3), dtype=np.float32)for i, img in enumerate(test_images): img_resize = resize(img, (75, 75), anti_aliasing=True) img_resize = preprocess_input(img_resize).astype(np.float32) test_images_preprocess[i] = np.dstack([img_resize, img_resize, img_resize])del test_images# 编译模型model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])# 训练它model.fit(train_images_preprocess, train_labels, epochs=15)# 现在评估模型 - 注意我们评估的是新模型,而不是旧模型test_loss, test_acc = model.evaluate(test_images_preprocess, test_labels)print('Test accuracy:', test_acc)
请注意,我必须更改InceptionV3基础模型的预期输入形状,使其为75 x 75 x 3,其中3表示它期望的是彩色图像。另外,我必须在除以255之前将数据转换为浮点数,否则数据仍然是无符号8位整数,因此值只能是0或1,这将显著降低你的准确性。另外,我创建了新的数组来存储调整到75 x 75大小的RGB版本图像,这些图像不仅调整了大小,而且还使用了与InceptionV3在训练图像之前使用的相同方法进行预处理。还有一点需要提及的是,我们需要设置密集层之前的层,使它们不进行训练。我们希望使用这些层来为输入到密集层的图像提供特征描述符,以便进行分类。最后,请注意,训练和测试数据的标签是从0到9进行枚举的。因此,你需要的损失函数将是稀疏分类交叉熵,它被设计为接受单值标签。分类交叉熵损失函数期望使用独热编码。
我们最终编译模型,以便为训练做好准备,然后进行训练。最后,我们评估测试数据的准确性。当然,这需要一些调整,尤其是你想要的密集层数量和选择的训练轮数。
警告
调整图像大小和为它们创建新数组会花费一些时间,因为我们要分别循环处理60000张训练图像和10000张测试图像。你需要在这里耐心等待。为了节省内存,我删除了原始的训练和测试图像,以便为预处理图像腾出空间。
结束语
因为Fashion MNIST数据集的自由度远低于ImageNet,你可以使用比正常情况下更少的层来获得高准确度的模型。ImageNet数据库包含具有不同程度的扭曲、对象方向、位置和大小的图像。如果你构建了一个仅包含几个卷积和池化层,结合扁平化和几个密集层的模型,不仅训练时间会更短,而且你会得到一个性能不错的模型。