在以图搜图的过程中,需要以来模型提取特征,通过特征之间的欧式距离来找到相似的图形。
本次我们主要讲诉以图搜图模型创建的方法。
图片预处理方法,看这里: https://keras.io/zh/preprocessing/image/
本文主要参考了这位大神的文章, 传送门在此: InceptionV3进行fine-tuning
训练模型代码如下:
# 基本流程
#
import os
import sys
import glob
import argparse
import matplotlib.pyplot as plt
from keras.applications.inception_v3 import InceptionV3, preprocess_input
from keras.models import Model
from keras.layers import Dense, GlobalAveragePooling2D
from keras.preprocessing.image import ImageDataGenerator
from keras.optimizers import SGD
# 一、定义函数
IM_WIDTH, IM_HEIGHT = 299, 299 # inceptionV3 指定图片尺寸
FC_SIZE = 1024 # 全连接层的数量
# 二、数据处理
# 图片归类放在不同文件夹下
train_dir = 'E:/Project/Image/data/finetune/train' # 训练集数据
val_dir = 'E:/Project/Image/data/finetune/test' # 验证集数据
nb_epoch = 1
batch_size = 15
nb_classes = len(glob.glob(train_dir + "/*")) # 分类数
# 图片增强
# ImageDataGenerator 会自动根据路径下的文件夹创建标签,所以在代码中只看到输入的 x, 看不到 y
train_datagen = ImageDataGenerator(
preprocessing_function=preprocess_input,
rotation_range=30,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True
)
train_generator = train_datagen.flow_from_directory(
train_dir, target_size=(IM_WIDTH, IM_HEIGHT),batch_size=batch_size, class_mode='categorical'
)
validation_generator = train_datagen.flow_from_directory(
val_dir, target_size=(IM_WIDTH, IM_HEIGHT),batch_size=batch_size, class_mode='categorical'
)
# 三、使用 bottleneck finetune
# 去掉 模型最外层的全连接层,添加上自己的 全连接层
# 添加新层函数
def add_new_last_layer(base_model, nb_classes):
x = base_model.output
x = GlobalAveragePooling2D()(x) # 下采样
x = Dense(FC_SIZE, activation='relu')(x)
predict_bottle_feat = Dense(nb_classes, activation='softmax')(x)
model = Model(input=base_model.input, output=predict_bottle_feat)
return model
# 冻结 base_model 所有层
def setup_to_transfer_learn(model, base_model):
for layer in base_model.layers:
layer.trainable = False
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])
# 定义网络框架
base_model = InceptionV3(weights='imagenet', include_top=False)
model = add_new_last_layer(base_model, nb_classes)
setup_to_transfer_learn(model, base_model)
# 训练
# 模式一训练
steps = 20 # 可以自由定义,越大结果越精准,但过大容易过拟合
history_tl = model.fit_generator(
train_generator,
epochs=nb_epoch,
steps_per_epoch=steps,
validation_data=validation_generator,
validation_steps=steps,
class_weight='auto')
# 保存模型
model.save("my_inceptionV3.h5")
使用模型提取指定层的特征:
from keras.preprocessing import image
from keras_applications.inception_v3 import preprocess_input
from keras.models import Model, load_model
import numpy as np
target_size = (229, 229) #fixed size for InceptionV3 architecture
base_model = load_model(filepath="my_inceptionV3.h5")
# 需要提取那一层的特征,此处就写入指定层的名称
model = Model(input=base_model.input, output=base_model.get_layer('block4_pool').output)
img_path = "C:/Users/Administrator/Pictures/搜图/horse.jpg"
img = image.load_img(img_path, target_size=target_size)
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
block4_pool_features = model.predict(x)
使用模型进行预测:
from keras.preprocessing import image
from keras.models import load_model
import numpy as np
import json
from keras_applications.imagenet_utils import decode_predictions
def predict(model, img, target_size):
"""Run model prediction on image
Args:
model: keras model
img: PIL format image
target_size: (w,h) tuple
Returns:
list of predicted labels and their probabilities
"""
if img.size != target_size:
img = img.resize(target_size)
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
preds = model.predict(x) # 此处获取的为
return preds[0] # 返回 numpy array [classes, ]
def decode_predict(probalities_list):
with open("img_classes.json", 'r') as load_f:
load_dict = json.load(load_f)
index = probalities_list.index(max(probalities_list))
target_class = load_dict[str(index)]
return target_class
target_size = (229, 229) #fixed size for InceptionV3 architecture
model = load_model(filepath="my_inceptionV3.h5")
img = image.load_img("C:/Users/Administrator/Pictures/搜图/horse.jpg")
res_numpy = predict(model, img, target_size=target_size)
res_list = res_numpy.tolist()
target_class = decode_predict(res_list)
print(target_class)