ResNet50 模型总是预测 1 类

Posted

技术标签:

【中文标题】ResNet50 模型总是预测 1 类【英文标题】:ResNet50 Model Always Predicts 1 Class 【发布时间】:2022-01-05 07:52:36 【问题描述】:

我正在研究 ResNet50 模型来预测胸部 X 光片中是否存在新冠病毒/非新冠病毒。但是,我的模型目前只预测类标签 1……我尝试了 3 种不同的优化器,2 种不同的损失函数,多次将学习率从 1e-6 更改为 0.5,并更改了类标签上的权重……

有人知道问题可能是什么吗?为什么它总是预测类别标签 1?

代码如下:

# import data
# train_ds = tf.keras.utils.image_dataset_from_directory(
train_ds = tf.keras.preprocessing.image_dataset_from_directory(
    DATASET_PATH+"Covid/",
    labels="inferred",
    batch_size=64,
    image_size=(256, 256),
    shuffle=True,
    seed=COVID_SEED,
    validation_split=0.2, 
    subset="training",
)

val_ds = tf.keras.preprocessing.image_dataset_from_directory(
    DATASET_PATH+"Covid/",
    labels="inferred",
    batch_size=64,
    image_size=(256, 256),
    shuffle=True,
    seed=COVID_SEED,
    validation_split=0.2, 
    subset="validation",
)

# split data
train_X = list()
train_y = list()
test_X = list()
test_y = list()

for image_batch_train, labels_batch_train in train_ds:
  for index in range(0, len(image_batch_train)):
    train_X.append(image_batch_train[index])
    train_y.append(labels_batch_train[index])

for image_batch, labels_batch in val_ds:
  for index in range(0, len(image_batch)):
    test_X.append(image_batch[index])
    test_y.append(labels_batch[index])

Conv_Base = ResNet50(weights=None, input_shape=(256, 256, 3), classes=2)

# The Convolutional Base of the Pre-Trained Model will be added as a Layer in this Model

for layer in Conv_Base.layers[:-8]:
    layer.trainable = False

model = Sequential()
model.add(Conv_Base)
model.add(Flatten())
model.add(Dense(units = 1024, activation = 'relu'))
model.add(Dropout(0.5))
model.add(Dense(units = 1, activation = 'sigmoid'))

model.summary()

opt = Adadelta(learning_rate=0.3)
model.compile(optimizer = opt, loss = 'BinaryCrossentropy', metrics = ['accuracy'])
# try to add class weights to make it predict 0, since we currently only predict class label 1
class_weight = 0: 50.,
                1: 1.

r=model.fit(x = train_ds, validation_data = val_ds, epochs = COVID_EPOCHS, class_weight=class_weight)

#print the class labels of prediction

predictions = model.predict(val_ds)
predictions = np.ndarray.flatten(predictions)
predictions = np.where(predictions < 0, 0, 1) # Convert to 0 and 1.

np.set_printoptions(threshold=np.inf)
print(predictions)

【问题讨论】:

您可以将 weights=None 更改为 weights="imagenet" 并重试吗?此外,您能否确认您的训练和测试数据以类似的方式进行了归一化(在这两种情况下输入是否都缩放为 [0, 1]?另外,您能否预测训练集的类别以获取更多信息?model.predict (train_ds) 你能在 ResNet50() 中使用 include_top=False 代替 classes=2。 为什么它总是预测类别标签 1? 检查您编写的 np.where() 声明。您将正值四舍五入为 1。此语句没有意义,因为 sigmoid 输出范围为 [0, 1]。 @Frightera 我明白了,这是一个错误,谢谢您的纠正。但是,我仍然有同样的问题,即始终获得相同的验证准确度,看来我总是在预测同一个类。 @GaussianPrior 我玩了你的建议一段时间,规范化解决了这个问题。将权重更改为“imagenet”不会编译,因为我相信它需要 10000 个类。非常感谢! 【参考方案1】:

干得好!我也会在这里留下答案,因为我认为除了规范化之外你还需要做更多的事情。

当权重为无时(请参阅here),resnet 权重是随机的。您正在使用大型卷积特征提取器(Resnet 的第一层),但该提取器没有经过任何训练。您可能会获得不错的性能,因为成功的 Dense 层会补偿这种随机初始化,但很可能这不是您的目标。请记住,您的 resnet 权重不可训练,因此特征提取永远不会改变。

我建议使用 imagenet 权重的原因是因为您正在处理图像,因此可以合理地假设您的卷积特征提取器需要提取重要的图像特征,例如颜色、形状、边缘等。事实上,imagenet resnet 是在大约 1000 个类上训练是无关紧要的,因为你在它到达输出层之前将其切断,这是发生类数瓶颈的地方。我会追求 weights = 'imagenet' 的东西。

【讨论】:

以上是关于ResNet50 模型总是预测 1 类的主要内容,如果未能解决你的问题,请参考以下文章

当使用 OpenCV 完成图像加载和调整大小时,Resnet50 会产生不同的预测

知识蒸馏IRG算法实战:使用ResNet50蒸馏ResNet18

yolotv5和resnet152模型预测

图像分类案例 ResNet50 鸟类图像4分类,附Pytorch完整代码

在 ResNet50 或任何深度学习模型中处理多个输入(图像、文本)数据

模型推理寒武纪 MLU resnet50 量化及离线推理流程