Keras使用无增强ImageDataGenerator训练CNN不收敛怎么办
问题描述
我使用Keras API在Cifar10数据集上训练CNN模型,相关实现代码如下:
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data() conv_network = Input(shape=(32, 32, 3), name="img") x = Conv2D(filters=32, kernel_size=(3,3), strides=2, activation="relu")(conv_network) x = Conv2D(filters=64, kernel_size=(3,3), strides=2, activation="relu")(x) x = Conv2D(filters=128, kernel_size=(3,3), strides=2, activation="relu")(x) x = Flatten()(x) x = Dense(1024, activation='relu')(x) output = Dense(10, activation='softmax')(x) model = tf.keras.Model(conv_network, output, name="convolutional_network") model.compile(loss='sparse_categorical_crossentropy',optimizer='Adam', metrics=['accuracy'])
正常训练场景
最初直接传入原始数据训练模型,代码如下:
r = model.fit(x_train, y_train, epochs=25,validation_data=(x_test, y_test))
该方式下模型可正常训练,训练集准确率随训练轮次逐步提升,第10轮训练集准确率可达89.01%,日志内容如下:
Epoch 1/25 1563/1563 [==============================] - 7s 4ms/step - loss: 1.7196 - accuracy: 0.4259 - val_loss: 1.3780 - val_accuracy: 0.5105 Epoch 2/25 1563/1563 [==============================] - 6s 4ms/step - loss: 1.2711 - accuracy: 0.5519 - val_loss: 1.2598 - val_accuracy: 0.5600 Epoch 3/25 1563/1563 [==============================] - 7s 4ms/step - loss: 1.1004 - accuracy: 0.6137 - val_loss: 1.2390 - val_accuracy: 0.5776 Epoch 4/25 1563/1563 [==============================] - 7s 4ms/step - loss: 0.9520 - accuracy: 0.6678 - val_loss: 1.2774 - val_accuracy: 0.5767 Epoch 5/25 1563/1563 [==============================] - 7s 4ms/step - loss: 0.7858 - accuracy: 0.7257 - val_loss: 1.3226 - val_accuracy: 0.5921 Epoch 6/25 1563/1563 [==============================] - 6s 4ms/step - loss: 0.6334 - accuracy: 0.7791 - val_loss: 1.5789 - val_accuracy: 0.5586 Epoch 7/25 1563/1563 [==============================] - 6s 4ms/step - loss: 0.5178 - accuracy: 0.8227 - val_loss: 1.7296 - val_accuracy: 0.5730 Epoch 8/25 1563/1563 [==============================] - 6s 4ms/step - loss: 0.4163 - accuracy: 0.8589 - val_loss: 2.0499 - val_accuracy: 0.5682 Epoch 9/25 1563/1563 [==============================] - 6s 4ms/step - loss: 0.3794 - accuracy: 0.8739 - val_loss: 2.0991 - val_accuracy: 0.5820 Epoch 10/25 1563/1563 [==============================] - 7s 4ms/step - loss: 0.3453 - accuracy: 0.8901 - val_loss: 2.3261 - val_accuracy: 0.5697
异常训练场景
使用未配置任何数据增强逻辑的ImageDataGenerator生成数据流训练时,模型预测结果完全随机、无训练效果,训练代码如下:
datagen = ImageDataGenerator() model.fit(datagen.flow(x_train, y_train, batch_size=32), steps_per_epoch=50000 / 32, epochs=10)
对应的训练日志显示,损失值虽然持续下降,但准确率始终维持在10%左右的10分类随机猜测水平,无任何提升,日志内容如下:
Epoch 1/10 1562/1562 [==============================] - 7s 4ms/step - loss: 1.6822 - accuracy: 0.1010 Epoch 2/10 1562/1562 [==============================] - 7s 4ms/step - loss: 1.2881 - accuracy: 0.0982 Epoch 3/10 1562/1562 [==============================] - 7s 4ms/step - loss: 1.1302 - accuracy: 0.0987 Epoch 4/10 1562/1562 [==============================] - 7s 4ms/step - loss: 0.9817 - accuracy: 0.1001 Epoch 5/10 1562/1562 [==============================] - 7s 4ms/step - loss: 0.8215 - accuracy: 0.1011 Epoch 6/10 1562/1562 [==============================] - 7s 4ms/step - loss: 0.6760 - accuracy: 0.1000 Epoch 7/10 1562/1562 [==============================] - 7s 4ms/step - loss: 0.5445 - accuracy: 0.1005 Epoch 8/10 1562/1562 [==============================] - 7s 4ms/step - loss: 0.4660 - accuracy: 0.1006 Epoch 9/10 1562/1562 [==============================] - 7s 4ms/step - loss: 0.4048 - accuracy: 0.1002 Epoch 10/10 1562/1562 [==============================] - 7s 4ms/step - loss: 0.3641 - accuracy: 0.1006
问题原因与修正方法
核心错误是标签维度不匹配:
tf.keras.datasets.cifar10.load_data()返回的标签y_train、y_test是形状为(样本数, 1)的二维列向量,不是sparse_categorical_crossentropy损失期望的形状为(样本数,)的一维整数数组。- 直接向
model.fit()传入数组数据时,Keras内部会自动做维度适配,挤压多余的标签维度,因此训练可以正常进行。 - 但
ImageDataGenerator.flow()生成批次数据时,不会自动对标签做维度压缩,输出的批次标签形状为(batch_size, 1),不符合损失函数和准确率指标的输入要求,会触发错误的广播计算:你看到的损失下降只是数值计算的假象,准确率统计完全失效,模型根本没有在正确的监督信号下更新参数,因此准确率始终卡在随机猜测水平。
修正操作很简单,加载数据后手动压缩标签维度即可,建议同时做像素值归一化加快收敛:
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data() # 压缩标签维度为一维 y_train = y_train.squeeze() y_test = y_test.squeeze() # 归一化像素值到0-1区间 x_train = x_train / 255.0 x_test = x_test / 255.0
完成上述处理后,再用ImageDataGenerator生成数据流训练,模型就可以正常收敛。
内容的提问来源于stack exchange,提问作者matlamalice
相关产品推荐
相关产品推荐

