Считать с Керасом - PullRequest
0 голосов
/ 21 марта 2020

Что я пытаюсь сделать

В настоящее время я делаю очень простой LSTM от последовательности к последовательности, используя Keras с небольшим поворотом, более ранние предсказания в последовательности должны засчитываться против потери меньше, чем позже из них. Я пытаюсь сделать это путем подсчета порядкового номера и умножения на квадрат root этого числа. (Я хочу сделать это, потому что это значение представляет относительный коэффициент неопределенности в процессе Пуассона, основанный на количестве собранных выборок. Моя сеть собирает данные и пытается оценить инвариантное значение на основе собранных данных.)

Как я пытаюсь это сделать

Я реализовал как пользовательскую функцию потерь, так и пользовательский слой.

Функция потерь:

def loss_function(y_true, y_pred):
    # extract_output essentially concatenates the first three regression outputs of y
    # into a list representing an [x, y, z] vector, and returns it along with the rest as a tuple
    r, e, n = extract_output(y_true)
    r_h, e_h, n_h = extract_output(y_pred)

    # Hyperperameters
    dir_loss_weight = 10
    dist_loss_weight = 1
    energy_loss_weight = 3

    norm_r = sqrt(dot(r, r))
    norm_r_h = sqrt(dot(r_h, r_h))

    dir_loss = mean_squared_error(r/norm_r, r_h/norm_r_h)
    dist_loss = mean_squared_error(norm_r, norm_r_h)
    energy_loss = mean_squared_error(e, e_h)

    return sqrt(n) * (dir_loss_weight * dir_loss + dist_lost_weight * dist_loss + energy_loss_weight * energy_loss)

Пользовательский слой:

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

    def build(self, input_shape):
        self.sequence_number = 0
        pass

    def call(self, x):
        self.sequence_number += 1
        return [self.sequence_number]

    def compute_output_shape(self, input_shape):
        return (1,)

Затем я добавил вход в качестве конкатенации к обычному выводу:

seq_num = CounterLayer()(inputs)
outputs = concatenate([out, seq_num])

Что не так

Моя ошибка:

Traceback (most recent call last):
  File "lstm.py", line 119, in <module>
    main()
  File "lstm.py", line 115, in main
    model = create_model()
  File "lstm.py", line 74, in create_model
    seq_num = CounterLayer()(inputs)
  File "/usr/lib/python3.7/site-packages/keras/engine/base_layer.py", line 497, in __call__
    arguments=user_kwargs)
  File "/usr/lib/python3.7/site-packages/keras/engine/base_layer.py", line 565, in _add_inbound_node
    output_tensors[i]._keras_shape = output_shapes[i]
AttributeError: 'int' object has no attribute '_keras_shape'

Я предполагаю, что у меня неправильная форма. Но я не знаю как. Кто-нибудь знает, неправильно ли я поступаю? Что я должен сделать, чтобы это произошло?

Дальнейшие приключения

Согласно комментарию @Mohammad Jafar Mashhadi, мое возвращение call должно было быть заключено в keras.backend.variable; однако, согласно его связанному ответу, мой подход не будет работать, потому что call не вызывается несколько раз, как я изначально предполагал, что это было.

Как я могу получить счетчик для RNN?

Для ясности, если RNN с заданным входом xi выдает yi, я пытаюсь получить i как часть моего вывода.

x1 -> RNN -> (y1, 1)
    h1 |
       v
x2 -> RNN -> (y2, 2)
    h2 |
       v
x3 -> RNN -> (y3, 3)
    h3 |
       v
x4 -> RNN -> (y4, 4)

Ответы [ 2 ]

1 голос
/ 23 марта 2020

Ошибка говорит о том, что inputs в строке seq_num = CounterLayer()(inputs) является целым числом.

Вы не можете передавать целые числа в качестве входных данных для слоев. Вы должны передать тезоры керас, и только тензоры керас.


Во-вторых, это не сработает, потому что Keras работает в стиле графика * stati c. call в слое ничего не вычисляет, он только строит график пустых тензоров. При передаче данных им будут обновляться только тензоры, а целочисленные значения - нет. Когда вы говорите self.sequence_number += 1, он будет вызываться только при построении модели, он не будет вызываться снова и снова.


Нам нужны подробности

Мы не сможем понять, что происходит, если вы не предоставите нам достаточно информации, например:

  • модель
  • сводка
  • ваши входные данные фигур
  • целевые данные фигур
  • пользовательские функции
  • et c.

Если приведенная ниже интерпретация верна, то очень важно знать форму вывода модели в сводке и формы целевых данных при ее передаче в соответствие.


Предложено решение

Если я понял то, что вы описали, вы хотите иметь последовательность увеличивающихся целых чисел наряду с временными шагами ваших последовательностей, поэтому эти числа используются в вашей функции потерь.

Если эта интерпретация верна, вам не нужно постоянно обновлять числа, вам просто нужно создать тензор диапазона и все.

Итак, внутри вашей потери (которую я не делаю ' Я не понимаю, если вы не предоставите нам пользовательские функции) вы должны создать этот тензор:

def custom_loss(y_true, y_pred):
    #use this if you defined your model with static sequence length - input_shape =(length, features)    
    length = K.int_shape(y_pred)[1]

    #use this if you defined your model with dynamic sequence length - input_shape = (None, features)
    length = K.shape(y_pred)[1]

    #this is the sequence vector:
    seq = tf.range(1, length+1)

    #you can get the root with 
    sec = K.sqrt(seq)

    #you reshape to match the shape of the loss, which is probably (batch, length)
    sec = K.reshape(sec, (1,-1)) #shape (1, lenght)

    #compute your loss normally, taking care to reduce the last axis and keep the two first
    loss = ..... #shape (batch, length)

    #multiply the weights by the loss
    return loss * sec

Вы должны работать как весь тензор! Вы не можете интерпретировать это как шаг за шагом. Вы должны делать все, сохраняя первое и второе измерения в своей потере.

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

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

Идея состоит в том, чтобы расширить вектор метки с помощью дополнительной функции, а затем снова разделить их внутри функции потерь.

# y_true_plus_timesteps has shape [n_training_instances, 2]

def custom_loss(y_true_plus_timesteps, y_pred):

    # labels stored in the first column
    y_true = y_true_plus_timesteps[:, 0]


    time_steps = y_true_plus_timesteps[:, 1]

    return K.mean(K.square(y_pred - y_true), axis=-1) +  your loss function

# note that labels are fed into the model with time steps 
model.fit(X, np.append(Y_true, time_steps, axis =1), batch_size = batch_size, epochs=90, shuffle=True, verbose=1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...