我正在使用Keras和TensorFlow对通过平铺成256x256图块的航拍图像进行分类。该模型将训练数据(即构成研究区域的256×256图像瓦片)分成70%的训练数据和30%的验证数据。使用顺序模型,然后使用图像数据生成器。最后,使用拟合生成器将模型拟合到数据。然后将模型保存为h5
格式,以用于预测不同研究区域中其他图像的类。
当我使用70%/ 30%训练/验证分割运行模型时,验证图像的预测效果很好,精度越来越高,每个时期的损失也在逐渐减少。另外,当我通过将概率阵列连接到表示图块边界的矢量多边形来可视化预测(即概率阵列)时,分类结果看起来非常好。
我的问题是,当我使用保存的h5
模型对新图像进行预测时 - 结果是无意义的,并且对于每个图块看起来是随机的。就像概率数组被随机混洗一样,当我将结果连接到矢量图像边界图块时,结果看起来完全是随机的。我该如何解决这个问题?
以下是用于训练模型的代码的相关部分:
base_model = applications.VGG16(weights='imagenet', include_top=False, input_shape=(img_rows, img_cols, img_channel))
add_model = Sequential()
add_model.add(Flatten(input_shape=base_model.output_shape[1:]))
add_model.add(Dense(256, activation='relu'))
add_model.add(Dense(n_classes, activation='sigmoid')) # n classes
model = Model(inputs=base_model.input, outputs=add_model(base_model.output))
model.compile(loss='binary_crossentropy', optimizer=optimizers.SGD(lr=1e-4, momentum=0.9),
metrics=['accuracy'])
######################
batch_size = 32
epochs = 50
print('Running the image data generator...')
train_datagen = ImageDataGenerator(
rotation_range=30,
width_shift_range=0.1,
height_shift_range=0.1,
horizontal_flip=True)
train_datagen.fit(x_train)
print('Fitting the model...')
history = model.fit_generator(
train_datagen.flow(x_train, y_train, batch_size=batch_size),
steps_per_epoch=x_train.shape[0] // batch_size,
epochs=epochs,
#validation_data=(x_valid, y_valid),
#callbacks=[ModelCheckpoint(model_checkpoint, monitor='val_acc', save_best_only=True)]
)
######################
## Predict
#print('Predicting...')
#p_valid = model.predict(x_valid, batch_size=128)
## Write predictions to csv
#print('Saving predictions to CSV...')
#df = pd.DataFrame(p_valid)
#df['image'] = split + 1 + df.index
#df.to_csv(out_csv, index=False, header=False)
"""
Save model, including these details:
-the architecture of the model, allowing to re-create the model
-the weights of the model
-the training configuration (loss, optimizer)
-the state of the optimizer, allowing to resume training exactly where you left off.
"""
print("Saving model")
model.save("/vgg16-model-50epochs.h5")
print('Processing complete.')
以下脚本使用上面保存的模型对来自不同研究区域的测试图像进行预测。注意,在上面的最终训练中没有70/30的训练/验证分割 - 我只是使用100%的牌来训练模型,然后我在下面的脚本中保存并重复使用:
import glob, os, time
import cv2
import numpy as np
import pandas as pd
from keras.models import load_model
#from keras.models import model_from_json
# Path to the input tiles which will be used to predict classes
inws = '/image-directory-for-another-study-area'
tiles = glob.glob(os.path.join(inws, '*.tif'))
# h5 file from trained model
in_h5 = "/vgg16-model-50epochs.h5"
# Output model predictions in csv format
out_csv = '/new-predictions.csv'
# Read images and convert to numpy array
x_test = np.array([cv2.imread(tile) for tile in tiles], np.float16) / 255.
print('Loading existing model...')
loaded_model = load_model(in_h5)
print("Predicting on image tiles...")
predictions = loaded_model.predict(x_test, batch_size=128)
# Save to csv
df = pd.DataFrame(predictions)
df['image'] = df.index + 1
df.to_csv(out_csv, index=False, header=False)
print("Predictions saved to disk: {0}".format(out_csv))
答案 0 :(得分:8)
我非常怀疑这是由于预处理不匹配造成的,即您对x_train
和x_test
应用了不同的预处理。
由于您没有显示x_train
是如何获得的,因此我无法为您验证。但是,众所周知,预训练的VGG16
模型使用caffe
- 就像规范化(参见preprocess_input
)一样,它通过减去通道方式来均衡输入图像。请注意,这与您测试图像所做的不同,
x_test = np.array([tile中瓷砖的[cv2.imread(tile)],np.float16)/ 255。
相反,您需要在keras VGG16示例中执行某些操作
#Extract features with VGG16
from keras.applications.vgg16 import VGG16
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input
import numpy as np
model = VGG16(weights='imagenet', include_top=False)
img_path = 'elephant.jpg'
img = image.load_img(img_path, target_size=(224, 224))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x) <---- use this function to preprocess your image
features = model.predict(x)
答案 1 :(得分:3)
在第二个脚本中,glob
的使用会创建一个无序的tiff文件列表。要使这种方法起作用,您需要一个可以与有序预测相关联的tiff文件的有序列表(例如[00001.tif, 00002.tif, ... 1234.tif]
)。 sorted()
函数可用于执行排序。
tiles = sorted(glob.glob(os.path.join(inws, '*.tif')))