#python #tensorflow #keras #lstm
#python #tensorflow #keras #lstm
Вопрос:
Я пытаюсь преобразовать модель Keras (.h5 / json) с пользовательскими слоями в модель tensorflow (.pb) и использую следующий пользовательский слой LSTM.
class AttentionVLSTMCell(AbstractRNNCell):
def __init__(...):
super(AttentionVLSTMCell, self).__init__(**kwargs)
...
@property
def state_size(self):
return [self.timestep*self.att_input_dim, self.units]
def build(self, input_shape): # difinition of the weights
...
@tf.function
def _time_distributed_dense(self, x, w, b=None, dropout=None,
input_dim=None, output_dim=None,
timesteps=None, training=None):
if input_dim is None:
input_dim = K.shape(x)[2]
if timesteps is None:
timesteps = K.shape(x)[1]
if output_dim is None:
output_dim = K.shape(w)[1]
if dropout is not None and 0. < dropout < 1.:
# apply the same dropout pattern at every timestep
ones = K.ones_like(K.reshape(x[:, 0, :], (-1, input_dim)))
dropout_matrix = K.dropout(ones, dropout)
expanded_dropout_matrix = K.repeat(dropout_matrix, timesteps)
x = K.in_train_phase(x * expanded_dropout_matrix, x, training=training)
# collapse time dimension and batch dimension together
x = K.reshape(x, (-1, input_dim))
x = K.dot(x, w)
if b is not None:
x = K.bias_add(x, b)
# reshape to 3D tensor
if K.backend() == 'tensorflow':
x = K.reshape(x, K.stack([-1, timesteps, output_dim]))
x.set_shape([None, None, output_dim])
else:
x = K.reshape(x, (-1, timesteps, output_dim))
return x
def _compute_update_vertex(self, x, V_tm1, c):
"""Computes carry and output using split kernels."""
# x = W * track
x_i, x_f, x_c, x_o = x
V_tm1_i, V_tm1_f, V_tm1_c, V_tm1_o, V_tm1_o2, V_tm1_u, V_tm1_v = V_tm1
c_i, c_f, c_c, c_o = c
# i = x_i V_tm1_i * R_i
# = W_i * track V_tm1_i * R_i C_i * context
print(x_i)
print(V_tm1_i)
print(c_i)
i = self.recurrent_activation(
x_i
K.dot(V_tm1_i, self.recurrent_kernel[:, :self.units])
K.dot(c_i, self.context_kernel[:, :self.units]))
f = self.recurrent_activation(
x_f
K.dot(V_tm1_f, self.recurrent_kernel[:, self.units:self.units * 2])
K.dot(c_f, self.context_kernel[:, self.units:self.units * 2]))
c = self.activation(
x_c
K.dot(V_tm1_c, self.recurrent_kernel[:, self.units * 2:self.units * 3])
K.dot(c_c, self.context_kernel[:, self.units * 2:self.units * 3]))
# U = update vertex
U = f * V_tm1_u i * c
o = self.recurrent_activation(
x_o
K.dot(V_tm1_o, self.recurrent_kernel[:, self.units * 3:])
K.dot(c_o, self.context_kernel[:, self.units * 3:]))
h_temp = o * self.activation(V_tm1_o2)
# h size [self.units]
h = self.dense_activation(K.dot(h_temp, self.dense_kernel))
# h size [1] activated sigmoid
#the size of h is [units]
V = h * U (1-h) * V_tm1_v
return h, V
def call(self, inputs, states, training=None):
# store the whole sequence so we can "attend" to it at each timestep
att = states[0] # Attention input (track num, input dim)
self.x_seq = K.reshape(att, (-1, self.timestep, self.att_input_dim)) # Attention input (track num, input dim)
V_tm1 = states[1] # previous Vertex state (units)
# Additive Attention Bahdanau et al., 2015
# apply the a dense layer over the time dimension of the sequence
# do it here because it doesn't depend on any previous steps
# thefore we can save computation time:
self._uxpb = self._time_distributed_dense(self.x_seq,
self.attention_kernel_U,
b=self.attention_kernel_b,
input_dim=self.att_input_dim,
timesteps=self.timestep,
output_dim=self.units)
# repeat the input track to the length of the sequence (track num, feature dim))
_tt = K.repeat(inputs, self.timestep)
_Wxtt = K.dot(_tt, self.attention_kernel_W)
et = K.dot(activations.tanh(_Wxtt self._uxpb), K.expand_dims(self.attention_kernel_V))
"""
#Dot-Product Attention Luong et al., 2015 / Scaled Dot-Product Attention Vaswani 2017
self.x_seq /= np.sqrt(self.att_input_dim)
et = K.batch_dot(K.expand_dims(inputs), self.x_seq, axes=[1, 2])
et = K.reshape(et, (-1, self.timestep, 1))
"""
at = K.exp(et)
at_sum = K.sum(at, axis=1)
at_sum_repeated = K.repeat(at_sum, self.timestep)
at /= at_sum_repeated # attention weights ({batchsize}, track num, 1)
context = K.squeeze(K.batch_dot(at, self.x_seq, axes=1), axis=1)
if self.implementation == 1:
# input = track
inputs_i = inputs
inputs_f = inputs
inputs_c = inputs
inputs_o = inputs
# k = W
k_i, k_f, k_c, k_o = array_ops.split(
self.kernel, num_or_size_splits=4, axis=1)
x_i = K.dot(inputs_i, k_i)
x_f = K.dot(inputs_f, k_f)
x_c = K.dot(inputs_c, k_c)
x_o = K.dot(inputs_o, k_o)
if self.use_bias:
b_i, b_f, b_c, b_o = array_ops.split(
self.bias, num_or_size_splits=4, axis=0)
x_i = K.bias_add(x_i, b_i)
x_f = K.bias_add(x_f, b_f)
x_c = K.bias_add(x_c, b_c)
x_o = K.bias_add(x_o, b_o)
V_tm1_i = V_tm1
V_tm1_f = V_tm1
V_tm1_c = V_tm1
V_tm1_o = V_tm1
V_tm1_o2 = V_tm1
V_tm1_u = V_tm1
V_tm1_v = V_tm1
c_i = context
c_f = context
c_c = context
c_o = context
x = (x_i, x_f, x_c, x_o)
V_tm1 = (V_tm1_i, V_tm1_f, V_tm1_c, V_tm1_o, V_tm1_o2, V_tm1_u, V_tm1_v)
c = (c_i, c_f, c_c, c_o)
h, V = self._compute_update_vertex(x, V_tm1, c)
return [h, at], [att, V]
def get_config(self):
...
def get_initial_state(self, inputs=True, batch_size=True, dtype=None):
...
Я могу загрузить модель с пользовательскими слоями, а также могу использовать ее в tensorflow.keras.
Однако при попытке loaded_model.save(model_name, save_format="tf")
Traceback (most recent call last):
File "/home/usr7/s70087f/.local/lib/python3.6/site-packages/tensorflow_core/python/framework/ops.py", line 1619, in _create_c_op
c_op = c_api.TF_FinishOperation(op_desc)
tensorflow.python.framework.errors_impl.InvalidArgumentError: Shape must be rank 2 but is rank 1 for 'MatMul_7' (op: 'MatMul') with input shapes: [256], [256,256].
Существует проблема в V_tm1_i (вычисление для входного элемента LSTM с вниманием):
i = self.recurrent_activation(
x_i
K.dot(V_tm1_i, self.recurrent_kernel[:, :self.units])
K.dot(c_i, self.context_kernel[:, :self.units]))
Я знаю, что мы должны использовать тензор> = 2 ndims для ‘MatMul’, но на самом деле он имеет размер пакета.
Поэтому я хочу, чтобы это стало [None,256], [256,256]
.
Отображаются входные данные и скрытое состояние пользовательского слоя:
AttentionVLSTM
inputs
Tensor("model/Decoder_Attention_VLSTM/strided_slice_1:0", shape=(None, 256), dtype=float32)
states
(<tf.Tensor 'model/reshape/Reshape:0' shape=(None, 27136) dtype=float32>, <tf.Tensor 'model/Decoder_Activation_2/Relu:0' shape=(None, 256) dtype=float32>)
AttentionVLSTM
inputs
Tensor("TensorArrayV2Read/TensorListGetItem:0", shape=(None, 256), dtype=float32)
states
(<tf.Tensor 'Placeholder_3:0' shape=(None, 27136) dtype=float32>, <tf.Tensor 'Placeholder_4:0' shape=(None, 256) dtype=float32>)
AttentionVLSTM
inputs
Tensor("inputs:0", shape=(None, 256), dtype=float32)
states
(<tf.Tensor 'states:0' shape=(27136,) dtype=float32>, <tf.Tensor 'states_1:0' shape=(256,) dtype=float32>)
V_tm1 получается из скрытого состояния, а «Заполнитель_4: 0» — это правильная форма [None,256]
, но «states_1: 0» потерял размер пакетной оси [256,]
.
Другие пользовательские слои (кроме этого слоя) могут работать, и этот слой также работает в tensorflow.Keras.
Размер пакета = 32 (состояния: 0 и входные данные: 0 не выводятся)
AttentionVLSTM
inputs
Tensor("model/Decoder_Attention_VLSTM/strided_slice_1:0", shape=(32, 256), dtype=float32)
states
(<tf.Tensor 'model/reshape/Reshape:0' shape=(32, 27136) dtype=float32>, <tf.Tensor 'model/Decoder_Activation_2/Relu:0' shape=(32, 256) dtype=float32>)
AttentionVLSTM
inputs
Tensor("TensorArrayV2Read/TensorListGetItem:0", shape=(32, 256), dtype=float32)
states
(<tf.Tensor 'Placeholder_3:0' shape=(32, 27136) dtype=float32>, <tf.Tensor 'Placeholder_4:0' shape=(32, 256) dtype=float32>)
Ответ №1:
Я мог бы решить эту проблему. Причиной ошибки является определение начального состояния в конце этого пользовательского класса. В этом нет необходимости, поскольку начальное состояние уже было определено в «AbstractRNNCell».