如何将灰度图像输入VGG等预训练神经网络模型?
问题解答
1. 灰度图读取后为3通道的原因
cv2.imread()默认使用cv2.IMREAD_COLOR参数读取图像,无论原图是否为单通道灰度图,都会自动转换为3通道BGR格式(三个通道的像素值完全相同),所以你输出的形状是(227,227,3)。如果需要读取单通道灰度图,需要指定参数:
img = cv2.imread("图像路径", cv2.IMREAD_GRAYSCALE)
读取后的形状为(高, 宽),如果需要适配VGG16的3通道输入要求,可以将单通道复制到三个通道:
img = np.stack([img, img, img], axis=-1)
2. 模型准确率仅50%的核心问题排查
你的准确率相当于随机猜测,本质是模型没有学到有效特征,优先排查以下代码错误:
输入预处理错误
VGG16预训练权重是在RGB格式的ImageNet数据集上训练的,而cv2.imread()默认读取的是BGR格式图像,你没有做通道转换,导致预训练权重完全无法提取有效特征。此外你直接将像素值除以255的归一化方式不符合VGG16的预训练要求,应该使用官方提供的预处理函数:from tensorflow.keras.applications.vgg16 import preprocess_input # 读取图像后先转RGB img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 再用官方预处理函数处理,会自动做均值归一化 img = preprocess_input(img)模型结构冗余错误
你在VGG16前额外添加了一层随机初始化的3通道卷积层,这层会完全破坏预训练VGG16学到的特征分布,属于完全多余的结构,直接删除即可。训练策略错误
你没有冻结VGG16的预训练权重,随机初始化的分类头会在训练初期打乱预训练的通用特征,尤其是医疗数据集样本量普遍偏小的情况下,很容易出现训不动的问题。正确的迁移学习流程是:- 先冻结VGG16的所有层,只训练你添加的分类头,训练10-15轮
- 解冻VGG16的顶层3-5层,调低学习率至1e-5级别再微调10-20轮
对应修改后的模型定义参考:
def build_model(): vgg16_model = VGG16(weights = 'imagenet', include_top = False, input_shape=(224,224,3)) # 先冻结VGG所有层 vgg16_model.trainable = False model = Sequential() # 直接接入VGG,删除之前的随机卷积层 model.add(vgg16_model) model.add(GlobalAveragePooling2D()) model.add(BatchNormalization()) model.add(Dropout(0.5)) model.add(Dense(units = 512, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(units = 1, activation='sigmoid')) # 初始训练用稍大的学习率 model.compile(optimizer = Adam(learning_rate=1e-4), loss = 'binary_crossentropy', metrics = ['accuracy']) return model数据集排查
以上代码问题修复后如果准确率仍然偏低,再排查数据集:- 正负样本比例是否均衡
- 标注是否存在错误
- 样本量是否足够,不足的话可以添加随机旋转、翻转、裁剪等数据增强操作
内容的提问来源于stack exchange,提问作者UserInNeed
相关产品推荐
相关产品推荐

