Tengo un conjunto de datos que contiene imágenes en escala de grises y quiero entrenar una CNN de última generación con ellas. Me gustaría mucho afinar un modelo pre-entrenado (como los que 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 forma (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 soltar la capa de entrada después de haber cargado los pesos y agregar los míos propios (como hacemos con las capas superiores). ¿Es correcto este enfoque?

Djib2011
La arquitectura del modelo. no puede cambiarse porque los pesos se han entrenado para una configuración de entrada específica. Reemplazar la primera capa con la tuya prácticamente inutilizaría el resto de los pesos.
— Editar: elaboración sugerida por Prune–
Las CNN están diseñadas para que, a medida que profundizan, puedan 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 funciones porque las capas posteriores no recibirán las funciones que se supone que deben recibir como entrada. En su caso, la segunda capa ha sido entrenada para suponer las características de la primera capa. Al reemplazar su primera capa con pesos aleatorios, básicamente está descartando cualquier entrenamiento que se haya realizado en las capas posteriores, ya que tendrían que volver a entrenarse. Dudo que pudieran retener alguno de los conocimientos aprendidos durante la formación inicial.
— fin de edición —
Sin embargo, hay una manera fácil de hacer que su modelo funcione con imágenes en escala de grises. Solo necesitas hacer la imagen para aparecer ser RGB. La forma más fácil de hacerlo es repetir la matriz de imágenes 3 veces en una nueva dimensión. porque tendrás la misma imagen en los 3 canales, el rendimiento del modelo debería ser el mismo que en las imágenes RGB.
En entumecido 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 esto 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 keras’ Generador de datos de imagen puede cargar imágenes en escala de grises como RGB.
Convertir imágenes en escala de grises a RGB según la respuesta actualmente aceptada es un enfoque para este problema, pero no el más eficiente. Sin duda, puede modificar los pesos de la primera capa convolucional del modelo y lograr el objetivo establecido. El modelo modificado funcionará de inmediato (con precisión reducida) y se podrá ajustar con precisión. Modificar los pesos de la primera capa no inutiliza el resto de los pesos como sugieren otros.
Para hacer esto, deberá agregar un código donde se cargan los pesos preentrenados. En el marco de su elección, debe descubrir cómo tomar los pesos de la primera capa convolucional en su red y modificarlos antes de asignarlos a su modelo de 1 canal. La modificación requerida es sumar 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]. Sumar sobre 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 (pulgadas) para especificar un número diferente de canales de entrada para el modelo.
Para probar que esto funciona, realicé tres ejecuciones de validación de ImageNet en ResNet50 con pesos previamente entrenados. Hay una ligera diferencia en los números para las ejecuciones 2 y 3, pero es mínima y debería ser irrelevante una vez ajustada.
- ResNet50 sin modificar con imágenes RGB: Prec @ 1: 75.6, Prec @ 5: 92.8
- ResNet50 sin modificar con imágenes en escala de grises de 3 canales: Prec @ 1: 64.6, Prec @ 5: 86.4
- ResNet50 de 1 canal modificado con imágenes en escala de grises de 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

bulbo
Una forma sencilla de hacer esto es agregar una capa de convolución antes del modelo base y luego enviar la salida al modelo base. Como esto:
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)
¿Por qué no intentar convertir una imagen en escala de grises en una imagen RGB?
tf.image.grayscale_to_rgb(
images,
name=None
)

nielsschneider
Dejar caer la capa de entrada no funcionará. Esto hará que todas las capas siguientes sufran.
Lo que puede hacer es concatenar 3 imágenes en blanco y negro para expandir su dimensión de color.
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)
función de pila de profundidad de numpy, np.dstack((img, img, img)) es una forma natural de hacerlo.
Enfrenté el mismo problema mientras trabajaba con VGG16 junto con imágenes en escala de grises. Resolví este problema de la siguiente manera:
Digamos que nuestras imágenes de entrenamiento están en train_gray_images
, cada fila contiene las intensidades de imagen en escala de grises desenrolladas. Entonces, si lo pasamos directamente a la función de ajuste, creará un error ya que la función de ajuste espera un canal 3 (RGB)
conjunto de datos de imagen en lugar de conjunto de datos en escala de grises. Entonces, antes de pasar a la función de ajuste, haga lo siguiente:
crear un maniquí RGB
conjunto de datos de imagen como el conjunto de datos de escala de grises con la misma forma (aquí dummy_RGB_image
). La única diferencia es que aquí estamos usando el número del canal 3.
dummy_RGB_images = np.ndarray(shape=(train_gray_images.shape[0], train_gray_images.shape[1], train_gray_images.shape[2], 3), dtype= np.uint8)
Por lo tanto, simplemente copie el conjunto de datos completo 3 veces en cada uno de los canales de “dummy_RGB_images”. (Aquí las dimensiones son [no_of_examples, height, width, channel])
dummy_RGB_images[:, :, :, 0] = train_gray_images[:, :, :, 0]
dummy_RGB_images[:, :, :, 1] = train_gray_images[:, :, :, 0]
dummy_RGB_images[:, :, :, 2] = train_gray_images[:, :, :, 0]
Finalmente pasar el dummy_RGB_images
en lugar del conjunto de datos de escala de grises, como:
model.fit(dummy_RGB_images,...)
.
Puede intentar eliminar la capa de entrada y agregar la suya propia. Entonces puedes intentar entrenar solo esa capa. Si no ve que la pérdida disminuye con todas las demás capas bloqueadas, no funcionará para usted de esta manera.
– kevinkayaks
24 ago. 18 en 0:37
no preguntes nosotros si este enfoque es correcto: ¡pregúntele a la computadora! ¡Intentalo! Otro enfoque es triplicar los vectores de entrada: alimentar los valores de escala de grises a las tres capas de color.
– Ciruela pasa
24 ago. 18 en 0:37
Mi sensación personal es que esto no va a funcionar para ti. Estas redes de clasificación definitivamente usan interrelaciones entre colores para clasificar objetos, y esta información está profundamente arraigada en los pesos de las capas intermedias.
– kevinkayaks
24 ago. 18 en 0:42
@Prune El entrenamiento de estos modelos puede llevar días, agradecería un poco de información si alguien ha encontrado este problema antes…
– Jcart
24 ago. 18 a las 0:43
Como mencionaron otros, es factible apilar 3 matrices idénticas en escala de grises como entrada, pero exploraría esto como una oportunidad para implementar más aumento de datos: aplicar filtros de imagen a la imagen original en escala de grises y asignarlos aleatoriamente a los 3 canales.
– ohailolcat
10 oct.