web-dev-qa-db-fra.com

Comment utiliser un réseau neuronal pré-formé avec des images en niveaux de gris?

J'ai un jeu de données contenant des images en niveaux de gris et je souhaite y former un CNN à la pointe de la technologie. J'aimerais beaucoup peaufiner un modèle pré-formé (comme ceux ici ).

Le problème est que presque tous les modèles pour lesquels je peux trouver les poids ont été formés sur le jeu de données ImageNet, qui contient des images RVB.

Je ne peux pas utiliser l'un de ces modèles car leur couche d'entrée attend un lot de forme (batch_size, height, width, 3) ou (64, 224, 224, 3) dans mon cas, mais mes lots d'images sont (64, 224, 224).

Existe-t-il un moyen d'utiliser l'un de ces modèles? J'ai pensé à supprimer la couche d'entrée après avoir chargé les poids et à ajouter les miens (comme nous le faisons pour les couches supérieures). Cette approche est-elle correcte?

3
Jcart

L'architecture du modèle ne peut pas être modifiée, car les poids ont été formés pour une configuration d'entrée spécifique. Remplacer la première couche par la vôtre rendrait le reste des poids inutile. 

- Edit: élaboration suggérée par Prune--
Les CNN sont construits de manière à pouvoir extraire des entités de haut niveau dérivées des entités de niveau inférieur extraites des couches précédentes à mesure qu’elles s’approfondissent. En supprimant les couches initiales d'un CNN, vous détruisez cette hiérarchie d'entités, car les couches suivantes ne recevront pas les entités auxquelles elles sont supposées appartenir. Dans votre cas, la deuxième couche a été formée pour attendre les caractéristiques de la première couche. En remplaçant votre première couche par des poids aléatoires, vous éliminez essentiellement toute formation effectuée sur les couches suivantes, car elles auraient besoin d'être recyclées. Je doute qu'ils puissent conserver les connaissances acquises lors de la formation initiale.
--- fin éditer ---

Il existe cependant un moyen simple de faire fonctionner votre modèle avec des images en niveaux de gris. Il vous suffit de faire en sorte que l’image apparaisse comme étant RVB. Le moyen le plus simple de procéder consiste à répéter le tableau d’images 3 fois sur une nouvelle dimension. Étant donné que vous aurez le même image sur les 3 canaux, les performances du modèle doivent être identiques à celles des images RVB.

Dans numpy _ ceci peut être facilement fait comme ceci:

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)

Cela fonctionne de la manière suivante: il crée d'abord une nouvelle dimension (pour placer les canaux), puis répète le tableau existant 3 fois sur cette nouvelle dimension.

Je suis également à peu près sûr que keras ' ImageDataGenerator peut charger des images en niveaux de gris au format RVB.

5
Djib2011

La conversion des images en niveaux de gris en RVB conformément à la réponse actuellement acceptée est une solution à ce problème, mais elle n’est pas la plus efficace. Vous pouvez très certainement modifier les poids de la première couche convolutionnelle du modèle et atteindre l'objectif défini. Le modèle modifié fonctionnera hors de la boîte (avec une précision réduite) et sera ajustable. La modification des poids de la première couche ne rend pas le reste des poids inutile comme suggéré par d’autres.

Pour ce faire, vous devrez ajouter du code là où les poids pré-entraînés sont chargés. Dans le cadre de votre choix, vous devez déterminer comment saisir les poids de la première couche de convolution de votre réseau et les modifier avant de les affecter à votre modèle à 1 canal. La modification requise consiste à additionner le tenseur de poids sur la dimension des canaux d'entrée. La manière dont le tenseur de poids est organisé varie d’un cadre à l’autre. La valeur par défaut de PyTorch est [out_channels, in_channels, kernel_height, kernel_width]. Dans Tensorflow, je pense que c’est [kernel_height, kernel_width, in_channels, out_channels].

En utilisant PyTorch comme exemple, dans un modèle ResNet50 de Torchvision ( https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py ), la forme des poids pour conv1 est [64, 3, 7, 7]. En sommant la dimension 1, on obtient un tenseur de forme [64, 1, 7, 7]. En bas, j'ai inclus un extrait de code qui fonctionnerait avec les modèles ResNet dans Torchvision en supposant qu'un argument (inchans) a été ajouté pour spécifier un nombre différent de canaux d'entrée pour le modèle.

Pour prouver que cela fonctionne, j'ai effectué trois essais de validation ImageNet sur ResNet 50 avec des poids pré-entraînés. Il y a une légère différence dans les nombres pour les séries 2 et 3, mais elle est minime et ne devrait pas être pertinente une fois ajustée.

  1. ResNet50 non modifié avec les images RVB: Prec @ 1: 75.6, Prec @ 5: 92.8
  2. ResNet50 non modifié avec des images en niveaux de gris à 3 canaux: Prec @ 1: 64.6, Prec @ 5: 86.4
  3. ResNet50 à 1 canal modifié avec images en niveaux de gris à 1 canal: 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
0
rwightman

pourquoi ne pas essayer de convertir une image en niveaux de gris en une image RVB?

tf.image.grayscale_to_rgb(
    images,
    name=None
)
0
Hu Xixi