Entrenamiento de imagen basado en parche y combinar su probabilidad de una imagen

En primer lugar, he implementado un simple VGG16 red para clasificación de imágenes.

model = keras.applications.vgg16.VGG16(include_top = False,
                weights = None,
                input_shape = (32,32,3),
                pooling = 'max',
                classes = 10)

Cuya forma de entrada es 32 x 32. Ahora, estoy tratando de implementar un patch-based neural network. La idea principal es, desde la imagen de entrada, extraer 4 parche de imagen como esta imagen,

enter image description here

y entrenar la imagen de parche extraída(resizing to 32 x 32 como es la forma de entrada de nuestro modelo) finalmente, combinar sus cuatro probabilidades de salida y encontrar el resultado de salida final (Using normalizing & argmax). Así,

enter image description here

¿Cómo puedo hacer eso?

Gracias por su ayuda.

Nota:

Supongo que usando lambda layer puede ser posible.

Mi simple implementación de clasificación VGG es aquí en Colab.

Pregunta hecha hace 3 años, 5 meses, 0 días - Por geekglitcher


3 Respuestas:

  • Usé el conjunto de datos MNIST para conseguir cada imagen como 4 parches con tf.image.extract_patches, que posteriormente se pasan como un lote:

    import tensorflow as tf
    from tensorflow import keras as K
    from tensorflow.keras.layers import Conv2D, Flatten, Dense, MaxPooling2D, Dropout
    from tensorflow import nn as nn
    from functools import partial
    import matplotlib.pyplot as plt
    
    (xtrain, ytrain), (xtest, ytest) = tf.keras.datasets.mnist.load_data()
    
    train = tf.data.Dataset.from_tensor_slices((xtrain, ytrain))
    test = tf.data.Dataset.from_tensor_slices((xtest, ytest))
    
    patch_s = 18
    stride = xtrain.shape[1] - patch_s
    
    get_patches = lambda x, y: (tf.reshape(
        tf.image.extract_patches(
            images=tf.expand_dims(x[..., None], 0),
            sizes=[1, patch_s, patch_s, 1],
            strides=[1, stride, stride, 1],
            rates=[1, 1, 1, 1],
            padding='VALID'), (4, patch_s, patch_s, 1)), y)
    
    train = train.map(get_patches)
    test = test.map(get_patches)
    
    fig = plt.figure()
    plt.subplots_adjust(wspace=.1, hspace=.2)
    images, labels = next(iter(train))
    for index, image in enumerate(images):
        ax = plt.subplot(2, 2, index + 1)
        ax.set_xticks([])
        ax.set_yticks([])
        ax.imshow(image)
    plt.show()
    

    enter image description here

    Entonces, en el circuito de entrenamiento, me estoy perdiendo por cada uno de estos 4 productos:

    def compute_loss(model, x, y, training):
      out = model(x=x, training=training)
      repeated_y = tf.repeat(tf.expand_dims(y, 0), repeats=4, axis=0)
      loss = loss_object(y_true=repeated_y, y_pred=out, from_logits=True)
      loss = tf.reduce_mean(loss, axis=0)
      return loss
    

    Entonces estoy reduciendo la media del eje 0 para fusionar todas las probabilidades juntas. Aquí está el código completo de funcionamiento:

    import tensorflow as tf
    from tensorflow import keras as K
    from tensorflow.keras.layers import Conv2D, Flatten, Dense, MaxPooling2D, Dropout
    from tensorflow import nn as nn
    from functools import partial
    import matplotlib.pyplot as plt
    
    (xtrain, ytrain), (xtest, ytest) = tf.keras.datasets.mnist.load_data()
    
    train = tf.data.Dataset.from_tensor_slices((xtrain, ytrain))
    test = tf.data.Dataset.from_tensor_slices((xtest, ytest))
    
    patch_s = 18
    stride = xtrain.shape[1] - patch_s
    
    get_patches = lambda x, y: (tf.reshape(
        tf.image.extract_patches(
            images=tf.expand_dims(x[..., None], 0),
            sizes=[1, patch_s, patch_s, 1],
            strides=[1, stride, stride, 1],
            rates=[1, 1, 1, 1],
            padding='VALID'), (4, patch_s, patch_s, 1)), y)
    
    train = train.map(get_patches)
    test = test.map(get_patches)
    
    fig = plt.figure()
    plt.subplots_adjust(wspace=.1, hspace=.2)
    images, labels = next(iter(train))
    for index, image in enumerate(images):
        ax = plt.subplot(2, 2, index + 1)
        ax.set_xticks([])
        ax.set_yticks([])
        ax.imshow(image)
    plt.show()
    
    def prepare(inputs, targets):
        inputs = tf.divide(x=inputs, y=255)
        targets = tf.one_hot(indices=targets, depth=10)
        return inputs, targets
    
    train = train.take(10_000).map(prepare)
    test = test.take(10_00).map(prepare)
    
    class MyCNN(K.Model):
        def __init__(self):
            super(MyCNN, self).__init__()
            Conv = partial(Conv2D, kernel_size=(3, 3), activation=nn.relu)
            MaxPool = partial(MaxPooling2D, pool_size=(2, 2))
    
            self.conv1 = Conv(filters=16)
            self.maxp1 = MaxPool()
            self.conv2 = Conv(filters=32)
            self.maxp2 = MaxPool()
            self.conv3 = Conv(filters=64)
            self.maxp3 = MaxPool()
            self.flatt = Flatten()
            self.dens1 = Dense(64, activation=nn.relu)
            self.drop1 = Dropout(.5)
            self.dens2 = Dense(10, activation=nn.softmax)
    
        def call(self, inputs, training=None, **kwargs):
            x = self.conv1(inputs)
            x = self.maxp1(x)
            x = self.conv2(x)
            x = self.maxp2(x)
            x = self.conv3(x)
            x = self.maxp3(x)
            x = self.flatt(x)
            x = self.dens1(x)
            x = self.drop1(x)
            x = self.dens2(x)
            return x
    
    model = MyCNN()
    
    loss_object = tf.losses.categorical_crossentropy
    
    def compute_loss(model, x, y, training):
      out = model(inputs=x, training=training)
      repeated_y = tf.repeat(tf.expand_dims(y, 0), repeats=4, axis=0)
      loss = loss_object(y_true=repeated_y, y_pred=out, from_logits=True)
      loss = tf.reduce_mean(loss, axis=0)
      return loss
    
    def get_grad(model, x, y):
        with tf.GradientTape() as tape:
            loss = compute_loss(model, x, y, training=False)
        return loss, tape.gradient(loss, model.trainable_variables)
    
    optimizer = tf.optimizers.Adam()
    
    verbose = "Epoch {:2d}" \
              " Loss: {:.3f} Acc: {:.3%} TLoss: {:.3f} TAcc: {:.3%}"
    
    for epoch in range(1, 10 + 1):
        train_loss = tf.metrics.Mean()
        train_acc = tf.metrics.CategoricalAccuracy()
        test_loss = tf.metrics.Mean()
        test_acc = tf.metrics.CategoricalAccuracy()
    
        for x, y in train:
            loss_value, grads = get_grad(model, x, y)
            optimizer.apply_gradients(zip(grads, model.trainable_variables))
            train_loss.update_state(loss_value)
            train_acc.update_state(y, model(x, training=True))
    
        for x, y in test:
            loss_value, _ = get_grad(model, x, y)
            test_loss.update_state(loss_value)
            test_acc.update_state(y, model(x, training=False))
    
        print(verbose.format(epoch,
                             train_loss.result(),
                             train_acc.result(),
                             test_loss.result(),
                             test_acc.result()))
    

    Alerta de spoiler: con parches tan pequeños, no hace bien. Hacer parches más grandes que 18/28 para un mejor rendimiento.

    Respondida el Dec 16, 2020 a las 19:42 - por cyberscribe

    Votos positivos: 0 | Votos negativos: 0

  • Para implementar un enfoque de entrenamiento de imagen basado en parche y combinar sus probabilidades de una imagen, puedes seguir los siguientes pasos utilizando una capa Lambda en Keras.

    • Dividir la imagen de entrada en 4 parches de imagen de tamaño 32x32 cada uno.
    • Alimentar cada parche de imagen a una copia de tu red neuronal VGG16 pre-entrenada.
    • Obtener las probabilidades de salida de cada copia de la red para cada parche.
    • Combinar las probabilidades de salida de los 4 parches y encontrar el resultado final.

    Aquí te dejo un ejemplo de cómo podrías implementarlo:

    python
    from tensorflow.keras.models import Model
    from tensorflow.keras.layers import Input, Lambda, concatenate
    
    

    Definir la forma de entrada para la imagen completa

    input_full = Input(shape=(128, 128, 3))

    Dividir la imagen en 4 parches de tamaño 32x32 cada uno

    patch1 = Lambda(lambda x: x[:, :32, :32, :])(input_full) patch2 = Lambda(lambda x: x[:, :32, 96:, :])(input_full) patch3 = Lambda(lambda x: x[:, 96:, :32, :])(input_full) patch4 = Lambda(lambda x: x[:, 96:, 96:, :])(input_full)

    Crear copias de la red VGG16 para cada parche

    model_patch1 = Model(inputs=input_full, outputs=model(patch1)) model_patch2 = Model(inputs=input_full, outputs=model(patch2)) model_patch3 = Model(inputs=input_full, outputs=model(patch3)) model_patch4 = Model(inputs=input_full, outputs=model(patch4))

    Obtener las probabilidades de salida para cada parche

    preds_patch1 = model_patch1.predict(input_full) preds_patch2 = model_patch2.predict(input_full) preds_patch3 = model_patch3.predict(input_full) preds_patch4 = model_patch4.predict(input_full)

    Combinar las probabilidades de salida de los 4 parches

    combined_preds = concatenate([preds_patch1, preds_patch2, preds_patch3, preds_patch4])

    Normalizar y obtener la clase predicha final

    final_output = keras.layers.Lambda(lambda x: keras.backend.mean(keras.backend.softmax(x), axis=0))(combined_preds)

    Crear el modelo final

    model_final = Model(inputs=input_full, outputs=final_output)

    Este código te permite dividir la imagen de entrada en 4 parches, pasar cada parche a una copia de tu modelo VGG16, obtener las probabilidades de salida para cada parche, combinar las probabilidades de salida de los 4 parches y obtener la clase predicha final después de normalizar. Puedes ajustar los detalles según tus necesidades y requisitos específicos.

    Espero que esta respuesta te sea de ayuda. ¡Déjame saber si tienes alguna otra pregunta!

    Respondida el Dec 17, 2020 a las 19:39 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Aquí tienes un enfoque paso a paso para implementar una red neuronal basada en parches para la clasificación de imágenes utilizando Keras:

    1. Extracción de parches

    Define una función que tome una imagen como entrada y la divida en parches superpuestos. Por ejemplo, puedes utilizar una ventana deslizante de 32x32 con un desplazamiento de 16 píxeles.

    2. Redimensionamiento y normalización

    Redimensiona cada parche a 32x32 píxeles para que coincida con la forma de entrada de tu modelo VGG16. Aplica normalización, como restar la media y dividir por la desviación estándar, a cada parche.

    3. Creación de un modelo de red neuronal basado en parches

    Crea cuatro copias del modelo VGG16 preentrenado, una para cada parche. Utiliza la capa Lambda de Keras para paralelizar la entrada de los parches en los cuatro modelos.

    4. Combinación de probabilidades

    Después de que los cuatro modelos hayan procesado los parches, utiliza otra capa Lambda para combinar sus probabilidades. Puedes utilizar la media, la suma o cualquier otra función de agregación para combinar las probabilidades.

    5. Capa de salida

    Aplica una capa de activación softmax a la capa de combinación para obtener las probabilidades finales de clase. Utiliza la función argmax para encontrar la clase predicha.

    Código de ejemplo:

    python
    import keras
    from keras.applications.vgg16 import VGG16
    from keras.layers import Input, Lambda, Dense, Flatten
    from keras.models import Model
    
    

    Función de extracción de parches

    def extract_patches(image): patches = [] for i in range(0, image.shape[0], 16): for j in range(0, image.shape[1], 16): patch = image[i:i+32, j:j+32] patches.append(patch) return patches

    Función de combinación de probabilidades

    def combine_probabilities(probabilities): return keras.backend.mean(probabilities, axis=0)

    Modelo original VGG16

    base_model = VGG16(include_top=False, weights=None, input_shape=(32, 32, 3), pooling='max', classes=10)

    Extracción de parches

    input_image = Input(shape=(32, 32, 3)) patches = Lambda(extract_patches)(input_image)

    Procesamiento de parches

    processed_patches = [] for i in range(4): processed_patches.append(base_model(patches[i]))

    Combinación de probabilidades

    combined_probabilities = Lambda(combine_probabilities)(processed_patches)

    Capa de salida

    output = Dense(10, activation='softmax')(combined_probabilities)

    Creación del modelo

    model = Model(input_image, output)

    Nota:

    Puedes ajustar el tamaño de la ventana deslizante y el desplazamiento según tus necesidades. También puedes experimentar con diferentes funciones de agregación para combinar las probabilidades.

    Respondida el Dec 17, 2020 a las 19:46 - por Gemini

    Votos positivos: 0 | Votos negativos: 0