1fcwqedwtnxl5uxv2bl5tbw.png

Antes de terminar esta publicación, que ya es larga, quería resaltar algunas de las otras características que incorporamos al modelo y brindar algunos ejemplos de códigos de capacitación para aquellos interesados ​​en desarrollar su propio modelo inpainting.

Abandono de Montecarlo

A diferencia de los métodos bayesianos tradicionales, no producimos directamente una estimación de incertidumbre basada físicamente utilizando una U-Net. Para tener una idea aproximada de la confianza y la estabilidad del modelo, decidimos introducir una caída en la capa de inferencia del modelo basada en el trabajo de Gal y Ghahramani, 2016, que nos permite generar una distribución de predicciones pintadas para cada caso de prueba. Estas distribuciones nos permiten producir intervalos de confianza para cada píxel pintado y refinar aún más nuestras estimaciones a regiones de las que el modelo tiene más certeza al pintar. Un ejemplo de esto se muestra a continuación en la Fig. 17.

Figura 18: Salidas de ejemplo de abandono de Monte Carlo (n = 50 iteraciones). Imagen del autor.

Normalmente utilizamos N=50 iteraciones por caso y, como podemos ver arriba, las áreas con mayor incertidumbre suelen ser los bordes y espacios de las nubes, ya que el modelo a menudo alucina al posicionar estas características.

Estadísticas de formación

La capacitación del modelo para este proyecto se completó en dos conjuntos de hardware, incluido un clúster informático de GPU basado en Linux en Microsoft Azure y una computadora de escritorio de alto rendimiento con Windows 11 (detalles adicionales del sistema en la Tabla 1). También se realizó un barrido extenso de hiperparámetros bayesianos en el transcurso de 2 días. Además, la normalización por lotes se aplica junto con la detención temprana (n=20), el abandono y la regularización L2 (regresión de cresta) para ayudar a mitigar el sobreajuste durante el proceso de capacitación. La caída de la tasa de aprendizaje también se aplica en dos épocas (450 y 475), lo que permite que el modelo se establezca más fácilmente en un mínimo de pérdida local cerca del final de la fase de entrenamiento. Todas las ejecuciones de entrenamiento y barridos de hiperparámetros se guardan en línea utilizando el Opción de almacenamiento en la nube de Weights & Biasespara monitorear las tasas de aprendizaje del modelo y la estabilidad a lo largo del tiempo.

Tabla 1: Detalles resumidos del hardware utilizado para el entrenamiento de modelos. Imagen del autor.

Código de ejemplo

Un enlace a GitHub está aquí: https://github.com/frasertheking/blindzone_inpainting

Sin embargo, quería brindar una descripción general de la implementación real de 3Net+ (con profundidad variable) en Tensorflow a continuación para aquellos interesados ​​en jugar con ella.

def conv_block(x, kernels, kernel_size=(3, 3), strides=(1, 1), padding='same', is_bn=True, is_relu=True, n=2, l2_reg=1e-4):
for _ in range(1, n+1):
x = k.layers.Conv2D(filters=kernels, kernel_size=kernel_size,
padding=padding, strides=strides,
kernel_regularizer=tf.keras.regularizers.l2(l2_reg),
kernel_initializer=k.initializers.he_normal(seed=42))(x)
if is_bn:
x = k.layers.BatchNormalization()(x)
if is_relu:
x = k.activations.relu(x)
return x

def unet3plus(input_shape, output_channels, config, depth=4, training=False, clm=False):

""" Prep """
interp = config['interpolation']
input_layer = k.layers.Input(shape=input_shape, name="input_layer")
xpre = preprocess(input_layer, output_channels)

""" Encoder """
encoders = []
for i in range(depth+1):
if i == 0:
e = conv_block(xpre, config['filters']*(2**i), kernel_size=(config['kernel_size'], config['kernel_size']), l2_reg=config['l2_reg'])
else:
e = k.layers.MaxPool2D(pool_size=(2, 2))(encoders[i-1])
e = k.layers.Dropout(config['dropout'])(e, training=True)
e = conv_block(e, config['filters']*(2**i), kernel_size=(config['kernel_size'], config['kernel_size']), l2_reg=config['l2_reg'])
encoders.append(e)

""" Middle """
cat_channels = config['filters']
cat_blocks = depth+1
upsample_channels = cat_blocks * cat_channels

""" Decoder """
decoders = []
for d in reversed(range(depth+1)):
if d == 0 :
continue
loc_dec = []
decoder_pos = len(decoders)
for e in range(len(encoders)):
if d > e+1:
e_d = k.layers.MaxPool2D(pool_size=(2**(d-e-1), 2**(d-e-1)))(encoders[e])
e_d = k.layers.Dropout(config['dropout'])(e_d, training=True)
e_d = conv_block(e_d, cat_channels, kernel_size=(config['kernel_size'], config['kernel_size']), n=1, l2_reg=config['l2_reg'])
elif d == e+1:
e_d = conv_block(encoders[e], cat_channels, kernel_size=(config['kernel_size'], config['kernel_size']), n=1, l2_reg=config['l2_reg'])
elif e+1 == len(encoders):
e_d = k.layers.UpSampling2D(size=(2**(e+1-d), 2**(e+1-d)), interpolation=interp)(encoders[e])
e_d = k.layers.Dropout(config['dropout'])(e_d, training=True)
e_d = conv_block(e_d, cat_channels, kernel_size=(config['kernel_size'], config['kernel_size']), n=1, l2_reg=config['l2_reg'])
else:
e_d = k.layers.UpSampling2D(size=(2**(e+1-d), 2**(e+1-d)), interpolation=interp)(decoders[decoder_pos-1])
e_d = k.layers.Dropout(config['dropout'])(e_d, training=True)
e_d = conv_block(e_d, cat_channels, kernel_size=(config['kernel_size'], config['kernel_size']), n=1, l2_reg=config['l2_reg'])
decoder_pos -= 1
loc_dec.append(e_d)
de = k.layers.concatenate(loc_dec)
de = conv_block(de, upsample_channels, kernel_size=(config['kernel_size'], config['kernel_size']), n=1, l2_reg=config['l2_reg'])
decoders.append(de)

""" Final """
d1 = decoders[len(decoders)-1]
d1 = conv_block(d1, output_channels, kernel_size=(config['kernel_size'], config['kernel_size']), n=1, is_bn=False, is_relu=False, l2_reg=config['l2_reg'])
outputs = [d1]

""" Deep Supervision """
if training:
for i in reversed(range(len(decoders))):
if i == 0:
e = conv_block(encoders[len(encoders)-1], output_channels, kernel_size=(config['kernel_size'], config['kernel_size']), n=1, is_bn=False, is_relu=False, l2_reg=config['l2_reg'])
e = k.layers.UpSampling2D(size=(2**(len(decoders)-i), 2**(len(decoders)-i)), interpolation=interp)(e)
outputs.append(e)
else:
d = conv_block(decoders[i - 1], output_channels, kernel_size=(config['kernel_size'], config['kernel_size']), n=1, is_bn=False, is_relu=False, l2_reg=config['l2_reg'])
d = k.layers.UpSampling2D(size=(2**(len(decoders)-i), 2**(len(decoders)-i)), interpolation=interp)(d)
outputs.append(d)

if training:
for i in range(len(outputs)):
if i == 0:
continue
d_e = outputs[i]
d_e = k.layers.concatenate([out1, out2, out3])
outputs[i] = merge_output(input_layer, k.activations.linear(d_e), output_channels)

return tf.keras.Model(inputs=input_layer, outputs=outputs, name='UNet3Plus')