Автоматическое кодирование Keras с распределением веса на сетевом уровне - PullRequest
0 голосов
/ 11 июля 2020

Я пытаюсь построить автоматический кодировщик релейной сети в keras. Основная идея состоит в том, что уровни кодирования имеют зашумленные и чистые версии, а уровни декодирования передают функции из соответствующих зашумленных слоев кодирования и имеют потери восстановления с чистыми уровнями кодирования. Я предпринял попытку, но не знаю, как проверить, правильно ли я ее настроил. У меня также есть несколько c вопросов по моей реализации. Вот сокращенная версия моего автоэнкодера с меньшим количеством слоев:

from tensorflow.keras.layers import Layer
from tensorflow.keras.layers import BatchNormalization
from tensorflow.keras.layers import Conv2D
from tensorflow.keras.layers import Conv2DTranspose
from tensorflow.keras.layers import LeakyReLU
from tensorflow.keras.layers import UpSampling2D
from tensorflow.keras.layers import GaussianNoise
from tensorflow.keras.layers import Input
from tensorflow.keras.layers import Flatten
from tensorflow.keras.models import Model
import tensorflow as tf


class Combine(Layer):
    def __init__(self, **kwargs):
        super(Combine, self).__init__()

    def build(self, input_shape):
        input_shape = input_shape[0][1:]
        self.w_vertical = self.add_weight(
            shape=(input_shape),
            initializer="Ones",
            trainable=True,
            name="vertical"
        )
        self.w_lateral = self.add_weight(
            shape=(input_shape),
            initializer="Zeros",
            trainable=True,
            name="lateral"
        )        
        self.w_product = self.add_weight(
            shape=(input_shape),
            initializer="Zeros",
            trainable=True,
            name="product"
        )        
        self.b = self.add_weight(
            shape=(input_shape), 
            initializer="Zeros", 
            trainable=True,
            name="bias"
        )

    def call(self, inputs):
        vertical = tf.math.multiply(inputs[0], self.w_vertical)
        lateral = tf.math.multiply(inputs[1], self.w_lateral)
        product_inner = tf.math.multiply(inputs[0], inputs[1])
        product = tf.math.multiply(product_inner, self.w_product)
        combined = self.b+vertical+lateral+product
        square_diff = tf.math.squared_difference(combined,inputs[2])
        mse = tf.math.reduce_mean(square_diff)
        self.add_loss(0.2*mse)
        return combined

def build_autoencoder(width=8, height=8, depth=3,filter_number=10, filter_size=3):
    # initialize the input shape to be "channels last" along with
    # the channels dimension itself

    inputShape = (height, width, depth)
    chanDim = -1
    noise_std = 0.1   
    # define the input to the encoder
    inputs = Input(shape=inputShape)
    # create shared layers
    l1_conv = Conv2D(filter_number, filter_size, strides=2, padding="same")
    l1_batch = BatchNormalization(axis=chanDim)   
    l1_nonlin = LeakyReLU(alpha=0.2)
    #clean layer 1
    clean_l1_conv = l1_conv(inputs)
    clean_l1_batch = l1_batch(clean_l1_conv)    
    clean_l1_nonlin = l1_nonlin(clean_l1_batch)
    # noisy layer 1
    noisy_image = GaussianNoise(noise_std)(inputs)
    noisy_l1_conv = l1_conv(noisy_image)
    noisy_l1_batch = l1_batch(noisy_l1_conv)
    noisy_l1_batch = GaussianNoise(noise_std)(noisy_l1_batch)
    noisy_l1_nonlin = l1_nonlin(noisy_l1_batch)   
    
    l2_conv = Conv2D(filter_number, filter_size, strides=2, padding="same")
    l2_batch = BatchNormalization(axis=chanDim)   
    l2_nonlin = LeakyReLU(alpha=0.2)
    #clean layer 2
    clean_l2_conv = l2_conv(clean_l1_nonlin)
    clean_l2_batch = l2_batch(clean_l2_conv)    
    clean_l2_nonlin = l2_nonlin(clean_l2_batch)
    # noisy layer 2
    noisy_l2_conv = l2_conv(noisy_l1_nonlin)
    noisy_l2_batch = l2_batch(noisy_l2_conv)
    noisy_l2_batch = GaussianNoise(noise_std)(noisy_l2_batch)
    noisy_l2_nonlin = l2_nonlin(noisy_l2_batch)   
       
    latent = Flatten()(clean_l2_nonlin)    

    dec_l2 = UpSampling2D(size=2, interpolation="nearest")(noisy_l2_nonlin)
    dec_l2 = Conv2DTranspose(filter_number, filter_size, strides=1, padding="same")(dec_l2)
    dec_l2 = BatchNormalization(axis=chanDim)(dec_l2)
    dec_l2 = LeakyReLU(alpha=0.2)(dec_l2)
        
    dec_l1 = Combine()([dec_l2, noisy_l1_nonlin, clean_l1_nonlin])
    dec_l1 = UpSampling2D(size=2, interpolation="nearest")(dec_l1)
    dec_l1 = Conv2DTranspose(filter_number, filter_size, strides=1, padding="same")(dec_l1)
    dec_l1 = BatchNormalization(axis=chanDim)(dec_l1)
    
    outputs = Conv2DTranspose(depth, filter_size, activation="sigmoid", padding="same")(dec_l1)
    
    autoencoder = Model(inputs, outputs, name="autoencoder")
   
    # return a 3-tuple of the encoder, decoder, and autoencoder
    return autoencoder

autoencoder = build_autoencoder()
autoencoder.compile(loss="mse", optimizer="Adam", metrics=['accuracy'])
autoencoder.summary()

Когда я запускаю свой фрагмент кода выше, я получаю следующее резюме: введите описание изображения здесь

Вопросы:

Разделяют ли мои шумные и чистые слои conv2d веса? (Что и является моим намерением)

Как объединяются потери, которые я добавляю в слой Combine с потерями на выходе, добавленными в compile()?

Как мне получить доступ к скрытому слою, который не отображается в сводке? Я хочу, чтобы результат последнего «чистого» слоя использовался для последующей задачи.

...