La precisión del tren CNN mejora durante el entrenamiento, pero la precisión de la prueba se mantiene alrededor del 40%

Así que en los últimos meses he estado aprendiendo mucho sobre redes neuronales con Tensorflow y Keras, así que quería intentar hacer un modelo para el conjunto de datos CIFAR10 (código a continuación).

Sin embargo, durante el proceso de entrenamiento, la precisión mejora (de aproximadamente el 35% después de 1 época al 60-65% después de 5 épocas), pero el val_acc se mantiene igual o aumenta solo un poco. Aquí están los resultados impresos:

Epoch 1/5 50000/50000 [==============================] - 454s 9ms/step - loss: 1.7761 - acc: 0.3584 - val_loss: 8.6776 - val_acc: 0.4489 Epoch 2/5 50000/50000 [==============================] - 452s 9ms/step - loss: 1.3670 - acc: 0.5131 - val_loss: 8.9749 - val_acc: 0.4365 Epoch 3/5 50000/50000 [==============================] - 451s 9ms/step - loss: 1.2089 - acc: 0.5721 - val_loss: 7.7254 - val_acc: 0.5118 Epoch 4/5 50000/50000 [==============================] - 452s 9ms/step - loss: 1.1140 - acc: 0.6080 - val_loss: 7.9587 - val_acc: 0.4997 Epoch 5/5 50000/50000 [==============================] - 452s 9ms/step - loss: 1.0306 - acc: 0.6385 - val_loss: 7.4351 - val_acc: 0.5321 10000/10000 [==============================] - 27s 3ms/step loss: 7.435152648162842 accuracy: 0.5321 

He buscado en Internet y creo que mi modelo está sobre ajustado, por lo que he intentado eliminar algunas capas, agregar más capas eliminadas y reducir la cantidad de filtros, pero ninguno mostró ninguna mejora.

Lo más extraño es que hace un tiempo hice un modelo muy similar, basado en algunos tutoriales, que tenía una precisión final del 80% después de 8 épocas. (Perdí ese archivo sin embargo)

Aquí está el código de mi modelo:

 model = Sequential() model.add(Conv2D(filters=256, kernel_size=(3, 3), activation='relu', data_format='channels_last', input_shape=(32, 32, 3))) model.add(MaxPooling2D((2, 2))) model.add(Conv2D(filters=128, kernel_size=(2, 2), activation='relu')) model.add(MaxPooling2D((2, 2))) model.add(Flatten()) model.add(Dense(1024, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(10, activation='softmax')) model.compile(optimizer=adam(), loss=categorical_crossentropy, metrics=['accuracy']) model.fit(train_images, train_labels, batch_size=1000, epochs=5, verbose=1, validation_data=(test_images, test_labels)) loss, accuracy = model.evaluate(test_images, test_labels) print('loss: ', loss, '\naccuracy: ', accuracy) 

train_images y test_images son numpy arrays de tamaño (50000,32,32,3) y (10000,32,32,3) y train_labels y test_labels son numpy arrays de tamaño (50000,10) y (10000,10) .

Mi pregunta: ¿qué causa esto y qué puedo hacer al respecto?

Editar después de la respuesta de Maxim:

Cambié el modelo a esto:

 model = Sequential() model.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu', kernel_initializer='he_normal', # better for relu based networks input_shape=(32, 32, 3))) model.add(MaxPooling2D((2, 2))) model.add(Conv2D(filters=256, kernel_size=(3, 3), activation='relu', kernel_initializer='he_normal')) model.add(MaxPooling2D((2, 2))) model.add(Flatten()) model.add(Dense(512, activation='relu')) model.add(Dropout(0.3)) model.add(Dense(10, activation='softmax')) 

y la salida es ahora esto:

 Epoch 1/10 50000/50000 [==============================] - 326s 7ms/step - loss: 1.4916 - acc: 0.4809 - val_loss: 7.7175 - val_acc: 0.5134 Epoch 2/10 50000/50000 [==============================] - 338s 7ms/step - loss: 1.0622 - acc: 0.6265 - val_loss: 6.9945 - val_acc: 0.5588 Epoch 3/10 50000/50000 [==============================] - 326s 7ms/step - loss: 0.8957 - acc: 0.6892 - val_loss: 6.6270 - val_acc: 0.5833 Epoch 4/10 50000/50000 [==============================] - 324s 6ms/step - loss: 0.7813 - acc: 0.7271 - val_loss: 5.5790 - val_acc: 0.6474 Epoch 5/10 50000/50000 [==============================] - 327s 7ms/step - loss: 0.6690 - acc: 0.7668 - val_loss: 5.7479 - val_acc: 0.6358 Epoch 6/10 50000/50000 [==============================] - 320s 6ms/step - loss: 0.5671 - acc: 0.8031 - val_loss: 5.8720 - val_acc: 0.6302 Epoch 7/10 50000/50000 [==============================] - 328s 7ms/step - loss: 0.4865 - acc: 0.8319 - val_loss: 5.6320 - val_acc: 0.6451 Epoch 8/10 50000/50000 [==============================] - 320s 6ms/step - loss: 0.3995 - acc: 0.8611 - val_loss: 5.3879 - val_acc: 0.6615 Epoch 9/10 50000/50000 [==============================] - 320s 6ms/step - loss: 0.3337 - acc: 0.8837 - val_loss: 5.6874 - val_acc: 0.6432 Epoch 10/10 50000/50000 [==============================] - 320s 6ms/step - loss: 0.2806 - acc: 0.9033 - val_loss: 5.7424 - val_acc: 0.6399 10000/10000 [==============================] - 19s 2ms/step loss: 5.74234927444458 accuracy: 0.6399 

Parece que vuelvo a ajustarme demasiado, aunque cambié el modelo con la ayuda que he recibido hasta ahora … ¿Alguna explicación o consejo?

Las imágenes de entrada son (32,32,3) matrices numpy normalizadas a (0,1)

No ha incluido cómo prepara los datos, aquí hay una adición que hizo que esta red aprendiera mucho mejor:

 x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255 

Si realiza la normalización de datos de esa manera, entonces su red está bien: alcanza una precisión de prueba de ~ 65-70% después de 5 épocas, lo que es un buen resultado. Tenga en cuenta que 5 épocas son solo el comienzo, se necesitarían entre 30 y 50 épocas para aprender bien los datos y mostrar un resultado cercano al estado de la técnica.

A continuación se presentan algunas mejoras menores que noté y que pueden obtener puntos de rendimiento adicionales:

  • Dado que está utilizando una red basada en ReLu, el inicializador he_normal es mejor que glorot_uniform (que es un valor predeterminado en Conv2D).
  • Es extraño disminuir la cantidad de filtros a medida que profundiza en la red. Debes hacer lo contrario. Cambié 256 -> 64 y 128 -> 256 y la precisión mejoró.
  • He disminuido la deserción ligeramente 0.5 -> 0.4 .
  • El tamaño de núcleo 3x3 es más común que 2x2 . Creo que deberías intentarlo también para la segunda capa de conv. De hecho, puedes jugar con todos los parámetros para encontrar la mejor combinación.

Aquí está el código final:

 (x_train, y_train), (x_test, y_test) = cifar10.load_data() print('x_train shape:', x_train.shape) print(x_train.shape[0], 'train samples') print(x_test.shape[0], 'test samples') y_train = to_categorical(y_train, 10) y_test = to_categorical(y_test, 10) model = Sequential() model.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu', kernel_initializer='he_normal', input_shape=(32, 32, 3))) model.add(MaxPooling2D((2, 2))) model.add(Conv2D(filters=256, kernel_size=(2, 2), kernel_initializer='he_normal', activation='relu')) model.add(MaxPooling2D((2, 2))) model.add(Flatten()) model.add(Dense(1024, activation='relu')) model.add(Dropout(0.4)) model.add(Dense(10, activation='softmax')) model.compile(optimizer=adam(), loss=categorical_crossentropy, metrics=['accuracy']) x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255 model.fit(x_train, y_train, batch_size=500, epochs=5, verbose=1, validation_data=(x_test, y_test)) loss, accuracy = model.evaluate(x_test, y_test) print('loss: ', loss, '\naccuracy: ', accuracy) 

El resultado después de 5 épocas:

 loss: 0.822134458447 accuracy: 0.7126 

Por cierto, podría interesarle comparar su enfoque con keras ejemplo CIFAR-10 conv net .