基于Keras的CNN皮肤癌分类模型精度极低问题排查求助
问题分析与解决方案
首先,你的模型存在几个关键的结构与配置错误,这才是导致loss和精度恒定不变的核心原因,样本量不足是次要问题,先解决前者:
1. 输出层与激活函数完全不匹配
你要完成7分类任务,但最后一层的定义完全错误:
model.add(Dense(1)) model.add(Activation("softmax"))
- Softmax激活是用来输出多类别的概率分布的,它的输出维度必须等于你的类别总数(这里是7),这样才能对应每个类别的概率。
- 现在
Dense(1)只会输出一个数值,经过softmax后永远是1.0,模型根本无法区分不同类别,自然不会更新任何参数,训练状态也就完全停滞了。
修正代码:
model.add(Dense(7)) # 输出维度等于类别数7 model.add(Activation("softmax"))
2. 损失函数选择错误
你用了mean_squared_error作为损失函数,这是回归任务的常用损失,完全不适合多分类场景。由于你的标签是整数编码的dx_code,应该使用sparse_categorical_crossentropy;如果后续把标签转成one-hot编码,再换成categorical_crossentropy。
修正编译逻辑:
model.compile(loss="sparse_categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
3. 数据加载效率问题(非核心,但建议优化)
你的creating_training_data函数里,每读一张图片就遍历整个metadata表去匹配,不仅效率极低,还容易出现匹配遗漏。可以先把metadata转成字典映射,大幅提升加载速度:
# 先构建image_id到dx_code的映射字典 id_to_label = metadata.set_index('image_id')['dx_code'].to_dict() def creating_training_data(path): training_data = [] for img in os.listdir(path): try: img_id = img.split('.')[0] # 提取不带后缀的图片ID if img_id not in id_to_label: continue img_array = cv2.imread(os.path.join(path, img), cv2.IMREAD_GRAYSCALE) new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE)) training_data.append([new_array, id_to_label[img_id]]) except Exception as e: print(f"处理图片{img}时出错:{e}") return training_data
关于样本量的补充说明
436个训练样本做7分类确实偏少,尤其是HAM10000本身类别分布极不平衡(比如nv类占比超过70%),如果你的小类别只有几个样本,模型很难学到有效特征。如果修正模型后效果仍不理想,可以尝试:
- 逐步增加样本量:MacBook性能有限的话,可以先尝试2000-3000个样本,或者用
ImageDataGenerator做数据增强(翻转、旋转、缩放等),扩充数据多样性。 - 处理类别不平衡:在
model.fit中使用class_weight参数,给小类别更高的权重,让模型更关注这些样本。 - 迁移学习:用MobileNetV2、ResNet50这类轻量级预训练模型做特征提取,利用预训练的通用特征,在小样本下也能获得不错的效果。
先修正前三个核心错误,再观察模型训练状态是否改善。
内容的提问来源于stack exchange,提问作者OAK
相关产品推荐
相关产品推荐

