Резюме: я реализую пользовательский 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]