我在KTH数据集上训练一个CNN模型,用于检测6类人类动作。
数据处理
- 数据集包含599个视频,每个动作由25个不同的人完成,包含99到100个视频。我将数据分为300个视频用于训练,98个视频用于验证,200个视频用于测试集。
- 我将分辨率降低到50×50像素,以免在处理时内存不足。
- 我从每个视频的中间提取了200帧。
- 我将像素值从0-255归一化到0,1范围内。
- 最后,我对类别标签进行了独热编码。
模型架构
这是我的模型架构。
以下是神经网络层的代码。
model = Sequential()model.add(Conv3D(filters=64, kernel_size=(3, 3, 3), strides=(1, 1, 1), padding='valid', activation='relu', input_shape=X_train.shape[1:]))model.add(MaxPooling3D(pool_size=2, strides=(2, 2, 2), padding='same'))model.add(Conv3D(filters=128, kernel_size=(3, 3, 3), strides=(1, 1, 1), padding='valid', activation='relu'))model.add(MaxPooling3D(pool_size=2, strides=(2, 2, 2), padding='same'))model.add(Conv3D(filters=256, kernel_size=(3, 3, 3), strides=(1, 1, 1), padding='valid', activation='relu'))model.add(Conv3D(filters=256, kernel_size=(3, 3, 3), strides=(1, 1, 1), padding='valid', activation='relu'))model.add(MaxPooling3D(pool_size=2, strides=(2, 2, 2), padding='same'))model.add(Conv3D(filters=512, kernel_size=(3, 3, 3), strides=(1, 1, 1), padding='valid', activation='relu'))model.add(Dense(4096, activation='relu'))model.add(Dense(4096, activation='relu'))#model.add(Dropout(0.5))model.add(Flatten())model.add(Dense(6, activation='softmax'))model.summary()
训练
我的问题是训练和验证的准确率都没有变化,从第一轮开始就基本处于冻结状态。这是训练步骤。这是前6个epoch,这是最后6个epoch。损失函数看起来像这样。训练损失非常高,验证损失没有变化。训练过程看起来像这样。
我很困惑,模型是欠拟合还是过拟合?我该如何解决这个问题?dropout会有所帮助吗?因为我假设在视频上无法进行数据增强?
非常感谢任何建议。
回答:
您使用的是0-1值的帧,并且使用了relu激活函数。在死亡relu问题中,模型会冻结并且完全不学习,因为relu会得到0或权重乘以输入的最大值(如果没有添加偏置)。为了确保模型正常工作,您可以尝试以下两种方法,尽管我不能保证您会得到好的准确率,但可以尝试这些方法来避免死亡relu问题:
使用leaky relu,alpha值设为大于等于0.2。不要归一化帧,而是转换为灰度以减少过多的训练。不要从中间取200帧,而是将所有视频分成等量的帧块,从每个块中取2到3个连续的帧。还可以尝试添加更多的全连接层,因为它们有助于分类。
我曾经处理过几乎相同的问题,我的做法是将帧合并后使用Conv2D。例如,如果您有10个大小为64x64x3的帧,而不是使用Conv3D,我对640x64x3的数据集使用了Conv2D,最终在16个类别的视频上达到了86%的准确率。