如何使用带有灰度图像的预先训练的神经网络?

Jca*_*art 12 python machine-learning deep-learning keras tensorflow

我有一个包含灰度图像的数据集,我想在它们上训练一个最先进的CNN.我非常想调整一个预先训练好的模型(就像这里的模型一样).

问题在于我几乎所有可以找到权重的模型都在ImageNet数据集上进行了训练,该数据集包含RGB图像.

我不能使用其中一个模型,因为他们的输入层需要一批形状(batch_size, height, width, 3)(64, 224, 224, 3)在我的情况下,但我的图像批次是(64, 224, 224).

有什么方法可以使用其中一种型号吗?我已经考虑过在加载权重并添加自己的权重后丢弃输入层(就像我们为顶层做的那样).这种方法是否正确?

Dji*_*011 17

无法更改模型的体系结构,因为权重已针对特定输入配置进行了训练.用你自己替换第一层几乎会使其余的权重变得无用.

- 编辑:Prune建议的详细说明 - 建立
CNN以便随着它们的深入,它们可以提取从前一层提取的较低级别特征派生的高级特征.通过删除CNN的初始层,您正在破坏该功能层次结构,因为后续层将不会接收它们应该作为其输入的功能.在您的情况下,第二层已经过训练,可以期待第一层的特征.通过用随机权重替换你的第一层,你实际上丢弃了对后续层进行的任何训练,因为它们需要重新训练.我怀疑他们可以保留在初始培训期间学到的任何知识.
---结束编辑---

但是,有一种简单的方法可以让您的模型使用灰度图像.您只需要使图像看起来像RGB.最简单的方法是在新维度上重复图像阵列3次.因为您将在所有3个通道上拥有相同的图像,所以模型的性能应与RGB图像上的相同.

numpy中,这可以很容易地完成:

print(grayscale_batch.shape)  # (64, 224, 224)
rgb_batch = np.repeat(grayscale_batch[..., np.newaxis], 3, -1)
print(rgb_batch.shape)  # (64, 224, 224, 3)
Run Code Online (Sandbox Code Playgroud)

这种方式的工作方式是首先创建一个新维度(放置通道),然后在这个新维度上重复现有数组3次.

我也很确定keras的ImageDataGenerator可以将灰度图像加载为RGB.

  • 这几乎是处理灰度图像时的*默认* 方法。我已经做过几次了,效果很好,它甚至是 keras 的 ImageDataGenerator 中的默认设置,用于加载重复 3 次的灰度图像。将其视为反向 RGB -> 灰度变换(其中 Gray=(R+B+G)/3)。 (3认同)
  • 堆叠1通道图像很容易做到,但问题不是如何使图像成为3通道,而是当他的原始图像是1通道时,他是否可以使用预训练模型进行分类,我认为答案可能是否定的 (2认同)
  • "用你自己替换第一层几乎会使其余的重量无用." - 你确定吗?检查这一点的实验将是训练神经网络,例如在ImageNet上,并查看"通常"需要多长时间才能达到一定的准确度.然后重新初始化输入图层,看看再次达到该精度需要多长时间.我确信使用初始化网络需要花费更少的时间. (2认同)

mmr*_*bul 12

一个简单的方法是在基础模型之前添加一个卷积层,然后将输出馈送到基础模型。像这样:

from keras.models import Model
from keras.layers import Input 

resnet = Resnet50(weights='imagenet',include_top= 'TRUE') 

input_tensor = Input(shape=(IMG_SIZE,IMG_SIZE,1) )
x = Conv2D(3,(3,3),padding='same')(input_tensor)    # x has a dimension of (IMG_SIZE,IMG_SIZE,3)
out = resnet (x) 

model = Model(inputs=input_tensor,outputs=out)


Run Code Online (Sandbox Code Playgroud)


小智 9

根据当前接受的答案将灰度图像转换为RGB是解决此问题的一种方法,但不是最有效的方法。您当然可以修改模型的第一个卷积层的权重并达到指定的目标。修改后的模型将立即可用(精度降低)并且是可调的。修改第一层的权重不会像其他人所建议的那样使其余权重无用。

为此,您必须在加载预训练权重的位置添加一些代码。在您选择的框架中,您需要弄清楚如何在分配给您的1通道模型之前掌握网络中第一卷积层的权重并进行修改。所需的修改是对输入通道的尺寸上的权重张量求和。权重张量的组织方式因框架而异。PyTorch的默认值为[out_channels,in_channels,kernel_height,kernel_width]。在Tensorflow中,我相信它是[kernel_height,kernel_width,in_channels,out_channels]。

以PyTorch为例,在Torchvision的ResNet50模型(https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py)中,conv1的权重形状为[64,3 ,7,7]。对维度1求和得出张量形状[64、1、7、7]。在底部,我提供了一个代码片段,该代码片段可与Torchvision中的ResNet模型一起使用,假定已添加一个参数(inchans)为该模型指定了不同数量的输入通道。

为了证明这项工作,我在ResNet50上使用预先训练的权重进行了3次ImageNet验证。运行2和3的数字略有不同,但是这是最小的,一旦进行微调就应该无关紧要。

  1. 带有RGB图像的未修改ResNet50:Prec @ 1:75.6,Prec @ 5:92.8
  2. 带有3通道灰度图像的未修改ResNet50:Prec @ 1:64.6,Prec @ 5:86.4
  3. 带有1-chan灰度图像的修改后的1-chan ResNet50:Prec @ 1:63.8,Prec @ 5:86.1
def _load_pretrained(model, url, inchans=3):
    state_dict = model_zoo.load_url(url)
    if inchans == 1:
        conv1_weight = state_dict['conv1.weight']
        state_dict['conv1.weight'] = conv1_weight.sum(dim=1, keepdim=True)
    elif inchans != 3:
        assert False, "Invalid number of inchans for pretrained weights"
    model.load_state_dict(state_dict)

def resnet50(pretrained=False, inchans=3):
    """Constructs a ResNet-50 model.
    Args:
        pretrained (bool): If True, returns a model pre-trained on ImageNet
    """
    model = ResNet(Bottleneck, [3, 4, 6, 3], inchans=inchans)
    if pretrained:
        _load_pretrained(model, model_urls['resnet50'], inchans=inchans)
    return model
Run Code Online (Sandbox Code Playgroud)

  • 听起来超级酷!所以这是有效的,因为当 `r = g = b`(灰度)时,`r*w0+g*w1+b*w2` 等价于 `r*(w0+w1+w2)`? (5认同)
  • 这个答案与公认的答案相矛盾。如果这个答案是正确的(我认为是),它应该被标记为已接受的答案。否则,人们在阅读已接受的答案后会被误导。 (2认同)

Hu *_*ixi 6

为什么不尝试将灰度图像转换为 RGB 图像?

tf.image.grayscale_to_rgb(
    images,
    name=None
)
Run Code Online (Sandbox Code Playgroud)


Nie*_*und 6

删除输入层是行不通的。这将导致所有后续层都受到影响。

您可以做的是将 3 个黑白图像连接在一起以扩展您的色彩维度。

img_input = tf.keras.layers.Input(shape=(img_size_target, img_size_target,1))
img_conc = tf.keras.layers.Concatenate()([img_input, img_input, img_input])    

model = ResNet50(include_top=True, weights='imagenet', input_tensor=img_conc)
Run Code Online (Sandbox Code Playgroud)

  • 虽然此代码可以解决问题,但包括解释如何以及为何解决问题将真正有助于提高帖子的质量,并可能会带来更多的赞成票。请记住,您是在为将来的读者回答问题,而不仅仅是现在提问的人。请编辑您的答案以添加解释并说明适用的限制和假设。有关如何回答的更多详细信息,请访问此链接:https://stackoverflow.com/help/how-to-answer (3认同)