Я определяю пользовательский слой встраивания слов keras, который использует как cnn, так и rnn, я изменил код из GRU, чтобы использовать GRUCell и некоторые собственные веса для фильтров CNN.Важно, что весовые коэффициенты фильтра определяются в методе построения для уровня, а весовые коэффициенты GRUCell определяются путем вызова метода построения соты.По какой-то причине это приводит к тому, что веса только для одного из них регистрируются, в зависимости от того, наследую ли я от RNN или Layer.Если я наследую от RNN, он регистрирует веса только для RNN, а если я наследую от уровня, он регистрирует веса только для CNN.Под регистром я подразумеваю, когда я использую слой и проверяю количество параметров, они соответствуют только тем для CNN и RNN соответственно.Я предполагаю, что другие наборы весов не обучаются, поскольку обучение не работает.Я хотел бы получить некоторые идеи о том, что не так с моим кодом, нужно ли мне определять веса для RNN внутри метода сборки для слоя?
from keras.layers.recurrent import RNN, GRUCell
import keras.backend as K
class cnn_lstm_layer(RNN):
def __init__(self, num_vocab, embed_dim, units=10):
self.num_vocab = num_vocab
self.embed_dim = embed_dim
self.units = units
cell = GRUCell(units)
super().__init__(cell)
def build(self, input_shape):
f2_count = 3
f3_count = 4
f4_count = 5
self.embeddings = self.add_weight(
shape=[self.num_vocab, self.embed_dim],
initializer='glorot_uniform',
name='char_embeddings')
self.kernel2 = self.add_weight(
shape=[2, self.embed_dim, 1, f2_count],
initializer='glorot_uniform',
name='f2')
self.kernel3 = self.add_weight(
shape=[3, self.embed_dim, 1, f3_count],
initializer='glorot_uniform',
name='f3')
self.kernel4 = self.add_weight(
shape=[4, self.embed_dim, 1, f4_count],
initializer='glorot_uniform',
name='f4')
self.conv_output_len = f2_count + f3_count + f4_count
step_input_shape = [None, self.conv_output_len]
self.cell.build(step_input_shape)
self.built = True
def call(self, inputs):
'''
uses the following reshaping trick
/10158700/raspredelennye-po-vremeni-svertochnye-sloi-v-tenzornom-potoke
'''
inputs = K.cast(inputs, tf.int32)
encoded = K.gather(self.embeddings, inputs)
# encoded = K.print_tensor(encoded, message = 'encoded: ')
# encoded = K.tf.Print(encoded, data = [encoded],message='encoded: ',summarize = 1000)
encoded = K.expand_dims(encoded, -1)
input_shape = K.int_shape(encoded)
_, s_words, s_char, s_embed_dim, _ = input_shape
encoded = K.reshape(encoded, (-1, s_char, s_embed_dim, 1))
paddings2 = [[0, 0], [1, 0], [0, 0], [0, 0]]
paddings3 = [[0, 0], [2, 0], [0, 0], [0, 0]]
paddings4 = [[0, 0], [3, 0], [0, 0], [0, 0]]
c2 = K.conv2d(tf.pad(encoded, paddings2),
self.kernel2,
data_format='channels_last',
padding='valid') # shape = (?,19,1,3)
c3 = K.conv2d(tf.pad(encoded, paddings3),
self.kernel3,
data_format='channels_last',
padding='valid')
c4 = K.conv2d(tf.pad(encoded, paddings4),
self.kernel4,
data_format='channels_last',
padding='valid')
c = K.concatenate([c2, c3, c4], axis=3) # shape = (?,19,1,12)
c = K.squeeze(c, 2) # shape = (?,19,12)
initial_state = self.get_initial_state(c)
last_output, outputs, states = K.rnn(self.cell.call,
c,
initial_state)
output = last_output
output = K.reshape(output,(-1,s_words,self.units))
return output
def get_initial_state(self, inputs):
# build an all-zero tensor of shape (samples, output_dim)
initial_state = K.zeros_like(inputs) # (samples, timesteps, input_dim)
initial_state = K.sum(initial_state, axis=(1, 2)) # (samples,)
initial_state = K.expand_dims(initial_state) # (samples, 1)
if hasattr(self.cell.state_size, '__len__'):
return [K.tile(initial_state, [1, dim])
for dim in self.cell.state_size]
else:
return [K.tile(initial_state, [1, self.cell.state_size])]
def compute_output_shape(self, input_shape):
batch_size, s_words, s_char = input_shape
output_shape = (batch_size, s_words,self.units)
return output_shape