¿Cómo puedo usar una red neuronal preentrenada con imágenes en escala de grises?

12 minutos de lectura

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?

  • 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.

¿Como puedo usar una red neuronal preentrenada con imagenes en
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.

  • apilar imágenes de 1 canal es fácil de hacer, pero la pregunta no es cómo hacer una imagen de 3 canales, es si puede usar un modelo previamente entrenado para la clasificación cuando sus imágenes originales son de 1 canal, y creo que la respuesta es probablemente no

    – kevinkayaks

    24 ago. 18 a las 0:46


  • Esto es más o menos el defecto enfoque cuando se trata de imágenes en escala de grises. Lo he hecho un par de veces y funciona bien, incluso es la configuración predeterminada en ImageDataGenerator de Keras para cargar la imagen en escala de grises repetida 3 veces. Piense en ello como una transformación RGB inversa -> escala de grises (donde gris = (R + B + G) / 3).

    – Djib2011

    24 ago. 18 a las 0:50

  • Esto muestra cómo hacer el segundo intento que sugerí; no responde a la pregunta original. ¿Resultará esto en un ajuste fino válido en la entrada de escala de grises?

    – Ciruela pasa

    24 ago. 18 en 0:51

  • El primer párrafo de su respuesta es la parte directa: ¿puede elaborar eso para convencer a OP?

    – Ciruela pasa

    24 ago. 18 a las 0:52

  • “Reemplazar la primera capa con la tuya haría que el resto de los pesos fueran inútiles”. – ¿Está usted seguro de eso? Un experimento para verificar esto sería entrenar una red neuronal, por ejemplo, en ImageNet y ver cuánto tiempo “típicamente” necesita para llegar a cierta precisión. Luego, reinicie la capa de entrada y vea cuánto tiempo se tarda en volver a esa precisión. Estoy convencido de que llevaría mucho menos tiempo con la red inicializada.

    – Martín Tomas

    26 ago. 18 en 09:04


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.

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

  • ¡Suena genial! Así que esto funciona porque r*w0+g*w1+b*w2 es equivalente a r*(w0+w1+w2) Cuándo r = g = b (escala de grises)?

    – Jeppe

    12 abr.

  • Entonces, esto parece exactamente lo que me interesa, sin embargo, no está claro si obtendremos una velocidad de procesamiento 3 veces mayor. Tengo una imagen RGB en la que el canal verde es mucho mejor que otros, y esperaba que usar solo el verde fuera mucho más rápido. ¿Puede aclarar cuáles fueron los tiempos para esto y si el objetivo de este enfoque es realmente acelerar el entrenamiento y la predicción? ¡Muchas gracias!

    – Gato

    22 dic. 2020 a las 13:09

  • @Cat puede observar una aceleración del minimapa, pero no cerca de 3x porque esta es solo una capa, y el resto de la red permanece igual.

    – leoll2

    24 feb. 21 en 12:16

1641748671 936 ¿Como puedo usar una red neuronal preentrenada con imagenes en
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)


  • ValueError: You are trying to load a weight file containing 13 layers into a model with 14 layers. ¿Alguna idea de cómo evitar esto?

    – Madara

    17 mayo 21 en 07:56


  • @Madara ¿Puedes compartir más detalles? También verifique si está incluyendo la capa final o no.

    – mmrbulbul

    17 mayo 21 en 09:15

  • # input_shape = (64,64,1) input_tensor = Input(shape=image_shape) model_input = Conv2D(filters = 3, kernel_size=3, padding='same', name="input_conv")(input_tensor) Ahora importo el modelo VGG16 vgg16 = VGG16(include_top=False, weights='imagenet',input_tensor=model_input) Luego trato de agregar una capa Conv. X = Conv2D(channels, kernel_size=3, padding='same')(vgg16.output) X = Activation('tanh')(X) Y el modelo final: model = Model(inputs = input_tensor, outputs = X)

    – Madara

    17 mayo 21 en 09:33


  • Solo divide la línea vgg16 = VGG16(include_top=False, weights='imagenet',input_tensor=model_input) en vgg16 = VGG16(include_top=False, weights='imagenet') vgg16 = vgg16(model_input) Debería estar funcionando.

    – mmrbulbul

    17 mayo 21 en 09:49


¿Por qué no intentar convertir una imagen en escala de grises en una imagen RGB?

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

1641748671 372 ¿Como puedo usar una red neuronal preentrenada con imagenes en
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)

  • Si bien este código puede resolver la pregunta, incluir una explicación de cómo y por qué esto resuelve el problema realmente ayudaría a mejorar la calidad de su publicación y probablemente resulte en más votos a favor. Recuerda que estás respondiendo la pregunta para lectores en el futuro, no solo para la persona que pregunta ahora. Edite su respuesta para agregar explicaciones y dar una indicación de las limitaciones y suposiciones que se aplican. Vea más detalles sobre cómo responder en este enlace: stackoverflow.com/help/how-to-answer

    – Usama Abdulrehman

    05 jul.

función de pila de profundidad de numpy, np.dstack((img, img, img)) es una forma natural de hacerlo.

  • Si bien este código puede resolver la pregunta, incluir una explicación de cómo y por qué esto resuelve el problema realmente ayudaría a mejorar la calidad de su publicación y probablemente resulte en más votos a favor. Recuerda que estás respondiendo la pregunta para lectores en el futuro, no solo para la persona que pregunta ahora. Edite su respuesta para agregar explicaciones y dar una indicación de las limitaciones y suposiciones que se aplican. Vea más detalles sobre cómo responder en este enlace: stackoverflow.com/help/how-to-answer

    – Usama Abdulrehman

    05 jul.

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,...)

.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad