¿Cómo puedo usar una neural network pre-entrenada con imágenes en escala de grises?

Tengo un conjunto de datos que contiene imágenes en escala de grises y quiero entrenar a una CNN de vanguardia sobre ellas. Me gustaría mucho afinar un modelo pre-entrenado (como los de aquí ).

El problema es que casi todos los modelos para los que puedo encontrar los pesos han sido entrenados en el conjunto de datos de ImageNet, que contiene imágenes RGB.

No puedo usar uno de esos modelos porque su capa de entrada espera un lote de formas (batch_size, height, width, 3) o (64, 224, 224, 3) en mi caso, pero mis lotes de imágenes son (64, 224, 224) .

¿Hay alguna manera de que pueda usar uno de esos modelos? Pensé en dejar caer la capa de entrada después de haber cargado los pesos y agregar los míos (como hacemos con las capas superiores). ¿Es este enfoque correcto?

La architecture del modelo no se puede cambiar porque los pesos se han entrenado para una configuración de entrada específica. Reemplazar la primera capa con la suya prácticamente inutilizaría el rest de los pesos.

– Edición: elaboración sugerida por Prune–
Las CNN se crean de manera que a medida que se profundizan, pueden extraer características de alto nivel derivadas de las características de nivel inferior que extrajeron las capas anteriores. Al eliminar las capas iniciales de una CNN, está destruyendo esa jerarquía de entidades porque las capas subsiguientes no recibirán las características que se supone que deben recibir como entrada. En su caso, la segunda capa ha sido entrenada para esperar las características de la primera capa. Al reemplazar su primera capa con pesos aleatorios, básicamente está desechando cualquier entrenamiento que se haya realizado en las capas subsiguientes, ya que deberían ser reentrenados. Dudo que puedan retener cualquiera de los conocimientos aprendidos durante la capacitación inicial.
— fin de edición —

Sin embargo, hay una forma fácil de hacer que su modelo funcione con imágenes en escala de grises. Solo necesitas hacer que la imagen parezca RGB. La forma más sencilla de hacerlo es repetir la matriz de imágenes 3 veces en una nueva dimensión. Debido a que tendrá la misma imagen en los 3 canales, el rendimiento del modelo debería ser el mismo que en las imágenes RGB.

En numpy esto se puede hacer fácilmente así:

 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) 

La forma en que funciona es que primero crea una nueva dimensión (para colocar los canales) y luego repite la matriz existente 3 veces en esta nueva dimensión.

También estoy bastante seguro de que ImageDataGenerator de keras puede cargar imágenes en escala de grises como RGB.

¿por qué no tratar de convertir una imagen en escala de grises a una imagen RGB?

 tf.image.grayscale_to_rgb( images, name=None ) 

Convertir las imágenes en escala de grises a RGB de acuerdo con la respuesta actualmente aceptada es un enfoque de este problema, pero no es el más eficiente. Con toda seguridad, puede modificar los pesos de la primera capa convolucional del modelo y lograr el objective establecido. El modelo modificado funcionará fuera de la caja (con una precisión reducida) y se podrá ajustar con precisión. La modificación de los pesos de la primera capa no inutiliza el rest de los pesos como lo sugieren otros.

Para hacer esto, tendrá que agregar algún código donde se carguen los pesos pre-entrenados. En el marco de su elección, debe descubrir cómo tomar el peso de la primera capa convolucional en su red y modificarlos antes de asignarlos a su modelo de 1 canal. La modificación requerida es sumr el tensor de peso sobre la dimensión de los canales de entrada. La forma en que se organiza el tensor de pesos varía de un marco a otro. El valor predeterminado de PyTorch es [out_channels, in_channels, kernel_height, kernel_width]. En Tensorflow creo que es [kernel_height, kernel_width, in_channels, out_channels].

Usando PyTorch como ejemplo, en un modelo ResNet50 de Torchvision ( https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py ), la forma de los pesos para conv1 es [64, 3 , 7, 7]. La sum de la dimensión 1 da como resultado un tensor de forma [64, 1, 7, 7]. En la parte inferior, he incluido un fragmento de código que funcionaría con los modelos ResNet en Torchvision, asumiendo que se agregó un argumento (inchans) para especificar un número diferente de canales de entrada para el modelo.

Para probar que esto funciona, hice tres ejecuciones de validación de ImageNet en ResNet50 con pesas pre-entrenadas. Hay una ligera diferencia en los números para la ejecución 2 y 3, pero es mínima y debe ser irrelevante una vez que se haya finalizado.

  1. ResNet50 sin modificar con imágenes RGB: Prec @ 1: 75.6, Prec @ 5: 92.8
  2. Imágenes ResNet50 sin modificar con escala de grises de 3 canales: Prec @ 1: 64.6, Prec @ 5: 86.4
  3. Imágenes de 1-chan ResNet50 con 1-chan en escala de grises: 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 

Cuando agrega la Resnet al modelo, debe ingresar input_shape en la definición de Resnet como

 model = ResNet50(include_top=True,input_shape=(256,256,1))