Прогнозы тестовых данных дают случайные результаты при прогнозировании из сохраненной модели - PullRequest
0 голосов
/ 29 апреля 2018

Я классифицирую аэрофотоснимки, которые разбиты на плитки размером 256x256, используя Keras и TensorFlow. Модель разделяет обучающие данные (то есть фрагменты изображения 256x256, составляющие область исследования) на 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))

Ответы [ 2 ]

0 голосов
/ 06 мая 2018

Во втором сценарии использование glob создает список файлов TIFF, которые не упорядочены. Чтобы этот подход работал, вам нужен упорядоченный список файлов TIFF (например, [00001.tif, 00002.tif, ... 1234.tif]), которые могут быть связаны с упорядоченными прогнозами. Функцию sorted() можно использовать для упорядочения.

tiles = sorted(glob.glob(os.path.join(inws, '*.tif')))
0 голосов
/ 01 мая 2018

Я очень подозреваю, что это связано с несовпадающей предварительной обработкой, то есть вы применяете различную предварительную обработку для x_train и x_test.

Так как вы не показали, как получается x_train, я не могу проверить вас. Однако известно, что в модели с предварительной подготовкой VGG16 используется caffe -подобная нормализация (см. preprocess_input), которая нормализует входное изображение путем вычитания среднего значения по каналу. Обратите внимание, это отличается от того, что вы сделали для тестирования изображений,

x_test = np.array ([cv2.imread (плитка) для плитки в плитках], 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)
...