Classificação de imagem em larga escala com Keras - ajuste fino vgg16 -

Este artigo foi publicado há mais de um ano. As informações podem estar desatualizadas.
1. Introdução
Recentemente, comecei a aprender machine learning e a participar do Kaggle , o concurso para classificação de imagens.
Desta vez, resumirei como implementar o ajuste fino do vgg16 com a biblioteca python keras 1.
2 Sobre dados
O conjunto de dados é o seguinte.
Eu só havia experimentado um conjunto de dados como o MNIST que costumava ser visto nos tutoriais de ML, então senti que era um conjunto de dados muito grande.
- Classes: cerca de 15.000
- Tamanho dos dados de aprendizado: cerca de 1,2 milhão de arquivos de imagem. Mais de 300 GB
- Tamanho de cada arquivo de imagem: varia entre os arquivos. por exemplo. 1.600 \ * 1.200
- Dados de teste: cerca de 120.000 arquivos
3 Implementação
3.1 Aprender dados
Primeiro vou mostrar o código inteiro.
1from keras.preprocessing.image import ImageDataGenerator2from keras import optimizers3from keras.applications.vgg16 import VGG164from keras.layers import Dense, Dropout, Flatten, Input, BatchNormalization5from keras.models import Model, Sequential6from keras.callbacks import ModelCheckpoint7import numpy as np8 9train_data_dir = "/train/"10validation_data_dir = "/validation/"11 12train_datagen = ImageDataGenerator(rescale=1. / 255)13validation_datagen = ImageDataGenerator(rescale=1. / 255)14 15img_width, img_height = 200, 15016nb_train_samples = 91564917nb_validation_samples = 30209118epochs = 5019batch_size = 6420nb_category = 1495121 22train_generator = train_datagen.flow_from_directory(23 train_data_dir,24 target_size=(img_width, img_height),25 batch_size=batch_size,26 class_mode="categorical")27 28validation_generator = validation_datagen.flow_from_directory(29 validation_data_dir,30 target_size=(img_width, img_height),31 batch_size=batch_size,32 class_mode="categorical")33 34# define input_tensor35input_tensor = Input(shape=(img_width, img_height, 3))36 37vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)38 39top_model = Sequential()40top_model.add(Flatten(input_shape=vgg16.output_shape[1:]))41top_model.add(Dense(256, activation='relu', kernel_initializer='he_normal'))42top_model.add(BatchNormalization())43top_model.add(Dropout(0.5))44top_model.add(Dense(nb_category, activation='softmax'))45 46# Connect vgg16 and top_model47model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output))48 49# Fix layers50for layer in model.layers[:15]:51 layer.trainable = False52 53optimizer = optimizers.rmsprop(lr=5e-7, decay=5e-5)54model.compile(loss='categorical_crossentropy',55 optimizer=optimizer,56 metrics=['accuracy'])57 58checkpoint_cb = ModelCheckpoint("snapshot/{epoch:03d}-{val_acc:.5f}.hdf5", save_best_only=True)59 60model.fit_generator(61 train_generator,62 steps_per_epoch=nb_train_samples // batch_size,63 epochs=epochs,64 validation_data=validation_generator,65 validation_steps=nb_validation_samples // batch_size,66 callbacks=[checkpoint_cb])67 68# Save the model69model.save("model.h5")70 71model.summary()3.1.1 Aprenda com dados em grande escala
Na maioria dos tutoriais, podemos ver os dados carregados da seguinte maneira.
1(X_train, y_train), (X_test, y_test) = mnist.load_data()No entanto, não é possível carregar dados inteiros na memória quando você trata dados em grande escala como esse.
Em vez disso, você pode usar a função flow_from_directory para carregar dados 2.
Esta função processa os dados da imagem enquanto os expande em tempo real.
Primeiro você precisa criar o ImageDataGenerator .
1train_datagen = ImageDataGenerator(rescale=1. / 255)2validation_datagen = ImageDataGenerator(rescale=1. / 255)Essa classe executa a geração em lote de dados de imagem enquanto executa o pré-processamento. Desta vez, basta redimensionar. 1/255 é usado para normalizar o intervalo de valores RGB de 0-255 a 0-1.
Em seguida, leia os dados
1train_generator = train_datagen.flow_from_directory(2 train_data_dir,3 target_size=(img_width, img_height),4 batch_size=batch_size,5 class_mode="categorical")6 7validation_generator = validation_datagen.flow_from_directory(8 validation_data_dir,9 target_size=(img_width, img_height),10 batch_size=batch_size,11 class_mode="categorical")Como é uma classificação categórica, defina class_mode como categorical .
Neste momento, você deve ter cuidado com a estrutura da pasta. Como mostrado abaixo, você deve criar uma subpasta para cada classe que deseja classificar.
1data/2 train/3 classA/4 aaa.jpg5 bbb.jpg6 ...7 classB/8 ccc.jpg9 ddd.jpg10 ...11 12 validation/13 classA/14 eee.jpg15 fff.jpg16 ...17 classB/18 ggg.jpg19 hhh.jpg20 ...3.1.2 Usar modelo vgg16
Aprenda a usar o modelo VGG16 que pode ser usado com o Keras .
1# define input_tensor2input_tensor = Input(shape=(img_width, img_height, 3))3 4vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)5 6top_model = Sequential()7top_model.add(Flatten(input_shape=vgg16.output_shape[1:]))8top_model.add(Dense(256, activation='relu', kernel_initializer='he_normal'))9top_model.add(BatchNormalization())10top_model.add(Dropout(0.5))11top_model.add(Dense(nb_category, activation='softmax'))12 13# Connect vgg16 with top_model14model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output))15 16# Fix layers17for layer in model.layers[:15]:18 layer.trainable = False19 20optimizer = optimizers.rmsprop(lr=5e-7, decay=5e-5)21model.compile(loss='categorical_crossentropy',22 optimizer=optimizer,23 metrics=['accuracy'])24 25checkpoint_cb = ModelCheckpoint("snapshot/{epoch:03d}-{val_acc:.5f}.hdf5", save_best_only=True)26 27model.fit_generator(28 train_generator,29 steps_per_epoch=nb_train_samples // batch_size,30 epochs=epochs,31 validation_data=validation_generator,32 validation_steps=nb_validation_samples // batch_size,33 callbacks=[checkpoint_cb])Primeiro, use o modelo vgg16 padrão. Neste momento, o tamanho do conjunto de dados de entrada é especificado.
1input_tensor = Input(shape=(img_width, img_height, 3))2 3vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)Em seguida, anexe seu próprio modelo.
Observe que include_top no argumento acima deve ser definido como False para fins de ajuste fino.
1top_model = Sequential()2top_model.add(Flatten(input_shape=vgg16.output_shape[1:]))3top_model.add(Dense(256, activation='relu', kernel_initializer='he_normal'))4top_model.add(BatchNormalization())5top_model.add(Dropout(0.5))6top_model.add(Dense(nb_category, activation='softmax'))7 8# Connect vgg16 with top_model9model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output))Para ser sincero, não entendo completamente a função relu especificada aqui.
Portanto, não acho que o conteúdo desse modelo seja muito útil.
Em seguida, o peso é fixo. Se isso não for especificado, os pesos serão aprendidos novamente desde o início, mas desta vez serão corrigidos.
1for layer in model.layers[:15]:2 layer.trainable = FalseCompile o modelo. No momento, especifique o otimizador. Isso especifica qual algoritmo usar ao atualizar parâmetros.
1optimizer = optimizers.rmsprop(lr=5e-7, decay=5e-5)2model.compile(loss='categorical_crossentropy',3 optimizer=optimizer,4 metrics=['accuracy'])Finalmente aprendendo. Se ModelCheckpoint estiver definido em retornos de chamada, os resultados intermediários poderão ser salvos. Não é obrigatório.
1checkpoint_cb = ModelCheckpoint("snapshot/{epoch:03d}-{val_acc:.5f}.hdf5", save_best_only=True)2 3model.fit_generator(4 train_generator,5 steps_per_epoch=nb_train_samples // batch_size,6 epochs=epochs,7 validation_data=validation_generator,8 validation_steps=nb_validation_samples // batch_size,9 callbacks=[checkpoint_cb])3.2 Prever
1from keras.preprocessing.image import ImageDataGenerator2from keras import optimizers3from keras.applications.vgg16 import VGG164from keras.layers import Dense, Dropout, Flatten, Input, BatchNormalization5from keras.models import Model, Sequential, load_model6import pandas as pd7import numpy as np8import os9from pandas import DataFrame10 11test_data_dir = "/test/"12 13test_datagen = ImageDataGenerator(rescale=1. / 255)14 15img_width, img_height = 200, 15016nb_test_samples = 11547417batch_size = 118nb_category = 1495119 20test_generator = test_datagen.flow_from_directory(21 test_data_dir,22 target_size=(img_width, img_height),23 batch_size=batch_size,24 class_mode=None,25 shuffle=False)26 27model = load_model("model.h5")28 29pred = model.predict_generator(30 test_generator,31 steps=nb_test_samples,32 verbose=1)Não é muito diferente de aprender código. Da mesma forma, os dados são lidos com flow_from_directory , mas o ponto a ser observado é que as subpastas são necessárias mesmo para os dados de teste (= classes desconhecidas). Por exemplo, na configuração a seguir, ele não funcionará, a menos que você organize os dados em subpastas.
1data/2 test/3 sub/4 aaa.jpg5 bbb.jpg6 ...Como a classe é desconhecida, defina class_mode como None .
4 Resumo
- Entendeu como usar o vgg16 com o Keras.
- Carregue dados em grande escala com
flow_from_directory. - Observe que você também precisa de subpastas para previsão.




