Решение линейной системы в Керасе - несовместимые формы - PullRequest
0 голосов
/ 18 октября 2019

Резюме: я реализую пользовательский RNN, в котором повторяемость внутренних состояний определяется решением линейной системы уравнений. Тот факт, что Keras хранит состояния внутренних слоев в форме (None, n_units), несовместим с его собственным решателем линейной алгебры.

Справочная информация: Keras сохраняет активации предыдущего слоя в форме (None, n_units). Это делает так, чтобы рекурсия в моей RNN, определяемая решением системы вида

LHS_matrix * h_new = RHS,

, имела вектор RHS с формой (None, n_units). LHS - это матрица с формой (n_units, n_units), конечно. Попытка использовать tf.linalg.solve() для решения системных сбоев с ошибкой «Несовместимые формы: [100,1] против [32,1]» - 100 - это количество единиц в моем слое, я понятия не имею, откуда взялись 32(и на данный момент я даже не хочу знать).

Я смог «решить» проблему путем транспонирования вектора RHS перед решением системы, получив таким образом h_new с формой (n_units, None),и затем перенести результат обратно в формат Кераса. Тем не менее, это решение на самом деле не элегантно, и мне не нравится тратить ресурсы на два дорогих ненужных транспонирования.

Есть ли лучший способ?

Ниже приведен минимальный пример кодав моей камере

class TestCell(Layer):

    def __init__(self, units, **kwargs):
        super(TestCell, self).__init__(**kwargs) # get standard initialisation, then overwrite what we need
        self.units = units
        self.state_size = units
        self.output_size = units


    def build(self, input_shape):
        # here we define the weights.
        self.kernel = self.add_weight(name="V", shape=(input_shape[-1], self.output_size), initializer='uniform', trainable=True)
        self.recurrent_kernel = self.add_weight(name="A", shape=(self.units, self.units), initializer='uniform', trainable=True)
        self.bias = self.add_weight(name="b", shape=(self.units,), initializer='uniform', trainable=True)

        self.built = True


    def call(self, inputs, states):
        h_prev = states[0] # previous activation of the layer
        A = self.recurrent_kernel
        A = A - tf.transpose(A)
        Vx = K.dot(inputs, self.kernel) # V*x
        Vxb = Vx + self.bias # V*x+b
        Iden = tf.eye(self.units) # identity matrix

        LHS_matrix = Iden - A
        RHS = K.dot(h_prev, Iden + A) + Vxb

        RHS = tf.transpose(RHS) # <----------------- 
        h_new = tf.linalg.solve(LHS_matrix, RHS)
        h_new = tf.transpose(h_new) # <----------------

        return h_new, [h_new]
...