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

⏱️3 min
Compartilhar:

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.

python
1from keras.preprocessing.image import ImageDataGenerator
2from keras import optimizers
3from keras.applications.vgg16 import VGG16
4from keras.layers import Dense, Dropout, Flatten, Input, BatchNormalization
5from keras.models import Model, Sequential
6from keras.callbacks import ModelCheckpoint
7import numpy as np
8
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, 150
16nb_train_samples = 915649
17nb_validation_samples = 302091
18epochs = 50
19batch_size = 64
20nb_category = 14951
21
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_tensor
35input_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_model
47model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output))
48
49# Fix layers
50for layer in model.layers[:15]:
51 layer.trainable = False
52
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 model
69model.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.

python
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 .

python
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

python
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.

javascript
1data/
2 train/
3 classA/
4 aaa.jpg
5 bbb.jpg
6 ...
7 classB/
8 ccc.jpg
9 ddd.jpg
10 ...
11
12 validation/
13 classA/
14 eee.jpg
15 fff.jpg
16 ...
17 classB/
18 ggg.jpg
19 hhh.jpg
20 ...

3.1.2 Usar modelo vgg16

Aprenda a usar o modelo VGG16 que pode ser usado com o Keras .

python
1# define input_tensor
2input_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_model
14model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output))
15
16# Fix layers
17for layer in model.layers[:15]:
18 layer.trainable = False
19
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.

python
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.

python
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_model
9model = 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.

python
1for layer in model.layers[:15]:
2 layer.trainable = False

Compile o modelo. No momento, especifique o otimizador. Isso especifica qual algoritmo usar ao atualizar parâmetros.

python
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.

python
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

python
1from keras.preprocessing.image import ImageDataGenerator
2from keras import optimizers
3from keras.applications.vgg16 import VGG16
4from keras.layers import Dense, Dropout, Flatten, Input, BatchNormalization
5from keras.models import Model, Sequential, load_model
6import pandas as pd
7import numpy as np
8import os
9from pandas import DataFrame
10
11test_data_dir = "/test/"
12
13test_datagen = ImageDataGenerator(rescale=1. / 255)
14
15img_width, img_height = 200, 150
16nb_test_samples = 115474
17batch_size = 1
18nb_category = 14951
19
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.

javascript
1data/
2 test/
3 sub/
4 aaa.jpg
5 bbb.jpg
6 ...

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.

5 Referência

Footnotes

  1. Keras Documentation

  2. Building powerful image classification models using very little data

Compartilhar:

Artigos relacionados

Aplicativo Android CI/CD com Flutter
Guides

Aplicativo Android CI/CD com Flutter

Aprenda a construir pipelines CI/CD para apps Android com Flutter. Baseado em GitHub Actions, sem usar fastlane.

mark241
Como localizar o aplicativo no Flutter
Guides

Como localizar o aplicativo no Flutter

Aprenda a localizar seu aplicativo Flutter usando arquivos arb. Este artigo é baseado no Flutter 2.0.1.

mark241