Keras. Сиамская сеть и потеря триплета

#python #tensorflow #keras #computer-vision #loss-function

#python #тензорный поток #keras #компьютерное зрение #функция потери

Вопрос:

Я хочу построить сеть, которая должна иметь возможность проверять изображения (например, человеческие лица). Насколько я понимаю, лучшим решением для этого является сиамская сеть с потерей триплета. Я не нашел готовых реализаций, поэтому решил создать свою собственную.

Но у меня есть вопрос о Keras. Например, вот структура сети:

структура сети

И код примерно такой:

 embedding = Sequential([
  Flatten(),
  Dense(1024, activation='relu'),
  Dense(64),
  Lambda(lambda x: K.l2_normalize(x, axis=-1))
])

input_a = Input(shape=shape, name='anchor')
input_p = Input(shape=shape, name='positive')
input_n = Input(shape=shape, name='negative')

emb_a = embedding(input_a)
emb_p = embedding(input_p)
emb_n = embedding(input_n)

out = Concatenate()([emb_a, emb_p, emp_n])

model = Model([input_a, input_p, input_n], out)

model.compile(optimizer='adam', loss=<triplet_loss>)
  

Я определил только одну модель встраивания. Означает ли это, что после начала обучения модели веса будут одинаковыми для каждого ввода?

Если это так, как я могу извлечь веса вложения из model ?

Комментарии:

1. в вашем случае вы можете использовать прямое встраивание.predict(X) для извлечения встраивания

Ответ №1:

Да, в функции потери триплета веса должны быть общими для всех трех сетей, т. Е. Привязка, положительная и отрицательная. В Tensorflow 1.x для достижения разделения веса вы можете использовать reuse=True в tf.layers .

Но в Tensorflow 2.x с тех пор, как tf.layers был перенесен в tf.keras.layers и reuse функциональность была удалена. Для достижения разделения веса вы можете написать пользовательский слой, который берет родительский слой и повторно использует его веса.

Ниже приведен пример, чтобы сделать то же самое.

 class SharedConv(tf.keras.layers.Layer):
    def __init__(
        self,
        filters,
        kernel_size,
        strides=None,
        padding=None,
        dilation_rates=None,
        activation=None,
        use_bias=True,
        **kwargs
    ):
        self.filters = filters
        self.kernel_size = kernel_size
        self.strides = strides
        self.padding = padding
        self.dilation_rates = dilation_rates
        self.activation = activation
        self.use_bias = use_bias
        super().__init__(*args, **kwargs)

   def build(self, input_shape):
       self.conv = Conv2D(
           self.filters,
           self.kernel_size,
           padding=self.padding,
           dilation_rate=self.dilation_rates[0]
       )
       self.net1 = Activation(self.activation)
       self.net2 = Activation(self.activation)

   def call(self, inputs, **kwargs):
       x1 = self.conv(inputs)
       x1 = self.act1(x1)
       x2 = tf.nn.conv2d(
                inputs,
                self.conv.weights[0], 
                padding=self.padding,
                strides=self.strides,
                dilations=self.dilation_rates[1]
              )
        if self.use_bias:
            x2 = x2   self.conv.weights[1]
        x2 = self.act2(x2)
        return x1, x2
  

Ответ №2:

Я отвечу о том, как извлечь вложения (ссылка из моего поста на Github):

Моя обученная сиамская модель выглядела так: siamese_model.summary()

изображение

Обратите внимание, что моя недавно переопределенная модель в основном такая же, как выделенная желтым

Затем я переопределил свою модель, которую хотел использовать для извлечения вложений (это должна быть та же модель, которую вы определили, за исключением того, что теперь у нее не будет таких множественных входов, как siamese), которая выглядела следующим образом:

siamese_embeddings_model = build_siamese_model(input_shape)

siamese_embeddings_model .summary()

изображение

Затем я просто извлек веса из моей обученной сиамской модели и установил их в свою новую модель

embeddings_weights = siamese_model.layers[-3].get_weights()

siamese_embeddings_model.set_weights(embeddings_weights )

Затем вы можете предоставить новое изображение для извлечения вложений из новой модели

vector = siamese.predict(image)

len(vector[0]) он напечатает 150 из-за моего тонкого плотного слоя (который является выходным вектором)