Лямбда-слой для выполнения, если затем в керас / тензор потока - PullRequest
0 голосов
/ 06 марта 2020

Я вырываю себе волосы этим.

Я задал вопрос здесь Если потом внутри нестандартного не обучаемого слоя керас , но у меня все еще есть трудности.

Я попробовал его решение, но оно не сработало - я решил опубликовать свой полный код вместе с его решением

У меня есть пользовательский слой Keras, который я хочу вернуть, указав c вывод из указанных c входов. Я не хочу, чтобы он был обучаемым.

Слой должен сделать следующее

if input = [1,0] then output = 1
if input = [0,1] then output = 0

Вот код лямбда-слоя для этого:

input_tensor = Input(shape=(n_hots,))


def custom_layer_1(tensor):
    if tensor == [1,0]:
        resp_1 = np.array([1,],dtype=np.int32)
        k_resp_1 = backend.variable(value=resp_1)
        return k_resp_1
    elif tensor == [0,1]:
        resp_0 = np.array([0,],dtype=np.int32)
        k_resp_0 = backend.variable(value=resp_0)
        return k_resp_0
    else:
        resp_e = np.array([-1,])
        k_resp_e = backend.variable(value=resp_e)
        return k_resp_e
    print(tensor.shape)

layer_one = keras.layers.Lambda(custom_layer_1,output_shape = (None,))(input_tensor)


_model = Model(inputs=input_tensor, outputs = layer_one)

Когда я соответствую своей модели, она всегда вычисляет -1, несмотря на входные данные.

Вот как выглядит модель:

Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 2)                 0         
_________________________________________________________________
lambda_1 (Lambda)            (None, None)              0         
=================================================================
Total params: 0
Trainable params: 0
Non-trainable params: 0

Вот полный код модели:

import numpy as np
from keras.models import Model
from keras import layers
from keras import Input
from keras import backend
import keras
from keras import models
import tensorflow as tf


# Generate the datasets:
n_obs = 1000

n_hots = 2

obs_mat = np.zeros((n_obs,n_hots),dtype=np.int32)

resp_mat = np.zeros((n_obs,1),dtype=np.int32)

# which position in the array should be "hot" ?
hot_locs = np.random.randint(n_hots, size=n_obs)

# set the bits:
for row,loc in zip(np.arange(n_obs),hot_locs):
    obs_mat[row,loc] = 1

for idx in np.arange(n_obs):
    if( (obs_mat[idx,:]==[1,0]).all() == True ):
        resp_mat[idx] = 1
    if( (obs_mat[idx,:]==[0,1]).all() == True ):
        resp_mat[idx] = 0

# test data:
test_suite = np.identity(n_hots)

# Build the network
input_tensor = Input(shape=(n_hots,))


def custom_layer_1(tensor):
    if tensor == [1,0]:
        resp_1 = np.array([1,],dtype=np.int32)
        k_resp_1 = backend.variable(value=resp_1)
        return k_resp_1
    elif tensor == [0,1]:
        resp_0 = np.array([0,],dtype=np.int32)
        k_resp_0 = backend.variable(value=resp_0)
        return k_resp_0
    else:
        resp_e = np.array([-1,])
        k_resp_e = backend.variable(value=resp_e)
        return k_resp_e
    print(tensor.shape)

layer_one = keras.layers.Lambda(custom_layer_1,output_shape = (None,))(input_tensor)


_model = Model(inputs=input_tensor, outputs = layer_one)

# compile
_model.compile(optimizer="adam",loss='mse')

#train (even thought there's nothing to train)
history_mdl = _model.fit(obs_mat,resp_mat,verbose=True,batch_size = 100,epochs = 10)

# test
_model.predict(test_suite)
# outputs: array([-1., -1.], dtype=float32)

test = np.array([1,0])
test = test.reshape(1,2)
_model.predict(test,verbose=True)
# outputs: -1

Это похоже на довольно простые вещи, почему не работает? Спасибо

1 Ответ

0 голосов
/ 06 марта 2020

Есть несколько причин:

  • Вы сравниваете двухмерный тензор (samples, hots) с одномерным тензором (hots).
  • Вы не учитывали размер партии ни в одном из результатов.
  • Возможно, вы не получите хороших результатов с простым if, в то время как tf является тензорной структурой.

Итак, предложение:

from keras import backend as K

def custom_layer(tensor):
    #comparison tensors with compatible shape 2D: (dummy_batch, hots)
    t10 = K.reshape(K.constant([1,0]), (1,2))
    t01 = K.reshape(K.constant([0,1]), (1,2))

    #comparison results - elementwise - shape (batch_size, 2)
    is_t10 = K.equal(tensor, t10)
    is_t01 = K.equal(tensor, t01)

    #comparison results - per sample - shape (batch_size,)
    is_t10 = K.all(is_t10, axis=-1)
    is_t01 = K.all(is_t01, axis=-1)

    #result options
    zeros = K.zeros_like(is_t10, dtype='float32') #shape (batch_size,)
    ones = K.ones_like(is_t10, dtype='float32')   #shape (batch_size,)
    negatives = -ones                             #shape (batch_size,)

    #selecting options
    result_01_or_else = K.switch(is_t01, zeros, negatives)
    result = K.switch(is_t10, ones, result_01_or_else)

    return result

Предупреждения :

  • этот слой не дифференцируем ( он возвращает константы) - вы не сможете обучить все, что находится перед этим слоем, и если вы попытаетесь, вы получите ошибку «Операция имеет None для градиента».
  • Входные данные tensor не могут быть выходами других слоев, поскольку требуется, чтобы они были точными или равными нулям.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...