как использовать цикл for в tensorflow/keras при использовании функционального API tf.keras?

Я хочу изменить вывод CuDNNGRU с помощью цикла for. Однако, похоже, я не могу этого сделать из-за режима графика tf.GradientTape. Как я могу изменить CuDNNGRU в функциональном API? Я знаю, что обычно мы можем выполнять некоторые матричные операции в функциональном API с помощью функций tf.keras.backend.*, таких как K.backend.batch_dot и т. д. Однако мне приходится выполнять некоторые сложные операции, такие как тройной цикл for или более и т. д., Если кто-то знает, как это сделать, пожалуйста, помогите!

.....source code
x = L.Lambda(lambda fm: tf.squeeze(fm, axis=1))(x)
gru_1 = CuDNNGRU(512, return_sequences=True, name='gru1')(x)
gru_1b = CuDNNGRU(512, return_sequences=True, go_backwards=True,name='gru1_b')(x)
for i in gru_1:
    .....apply some function to gru_1 outputs

Кстати, в настоящее время я пытаюсь изменить выходные данные ГРУ с помощью приведенного ниже кода.

def attention(inputs):
    transpose_input = tf.transpose(inputs,perm=[0,2,1])
    atten_w = K.backend.batch_dot(inputs,transpose_input)
    atten_w = tf.linalg.set_diag(atten_w,tf.zeros(tf.shape(atten_w)[0:-1],dtype=tf.float32))
    atten_w = tf.nn.softmax(atten_w,axis=1)
    atten_v = tf.py_function(calculate_atten,inp=[inputs,atten_w],Tout=[tf.float32])
    atten_v = tf.convert_to_tensor(atten_v)
    atten_v.set_shape(self.input_shapex)


def calculate_atten(data,atten_w):
    input_vector = data.numpy()
    atten_vectors = atten_w.numpy()
    all_batch = []
    for index,one_batch in enumerate(input_vector):
        tmp_w = atten_vectors[index]
        all_vector = []
        for j,vector in enumerate(one_batch):
            tmp = np.zeros(input_vector.shape[2])
            for w in tmp_w[j]:
                tmp += vector*w
            all_vector.append(tmp)
        all_batch.append(all_vector)
    return all_batch

Однако в приведенном выше коде функция tf.py_function возвращает [время, функции] вместо [пакет, время, функции], если это можно сделать, я могу использовать tf.py_function для создания слоя. Но похоже не может, ПОМОГИТЕ!!!!

Обновлять

Мне удалось выполнить операции с вложенным tf.map_fn. Хотя нужно хорошо подумать, что передать в tf.map_fn (несколько входов должны быть возвращены в несколько выходов). Надеюсь, это может помочь другим

def attn_transformation(inputs):
    inputs_transpose = tf.transpose(inputs)
    atten_w = tf.tensordot(inputs,inputs_transpose,axes=1)
    def transform(data):
        multiply_data = data[0]*data[1][...,tf.newaxis]
        return [multiply_data,data[1]]
    data = tf.map_fn(lambda x:transform(x),elems=([inputs,atten_w]))
    data = tf.reduce_sum(data[0],axis=1)
    return data

gru_1 = CuDNNGRU(512, return_sequences=True, name='gru1')(x)
gru_1b = CuDNNGRU(512, return_sequences=True, go_backwards=True,name='gru1_b')(x)
atten_vf = L.Lambda(lambda x: tf.map_fn(attn_transformation,x))(gru_1)

person luvwinnie    schedule 20.06.2019    source источник


Ответы (1)


Для любой произвольной операции, где вы хотите применить ее к каждому i в tensor, вы можете просто использовать tf.map_fn()

Так, например, мы можем сделать что-то вроде:

inp = Input(shape=(2,3))
gru = CuDNNGRU(512, return_sequences=True)(inp)

def dummy_operation_to_be_applied(row):
  return row + 1

out = Lambda(lambda x: tf.map_fn(dummy_operation_to_be_applied, x))(gru)

ОБНОВИТЬ:

Обратите внимание, что мы также можем вложить tf.map_fn() для отображения операций в более низких измерениях.

Например:

def nested_op(x):
  return tf.reduce_max(x) + x

def dummy_operation_to_be_applied(row):
  return tf.map_fn(nested_op, row)

out = Lambda(lambda x: tf.map_fn(dummy_operation_to_be_applied, x))(gru)
person Stewart_R    schedule 20.06.2019
comment
Спасибо за ответ, для простой задачи это можно сделать с помощью приведенного выше кода, однако то, что я действительно хочу сделать, это что-то вроде цикла для строки. Я пробовал это, но он показывает эту ошибку. TypeError: вы пытаетесь использовать поток управления Python на слое, который не был объявлен динамическим. Передайте dynamic=True конструктору класса. Обнаружена ошибка: тензорные объекты являются итерируемыми, только если включено активное выполнение. Чтобы перебрать этот тензор, используйте tf.map_fn. - person luvwinnie; 20.06.2019
comment
Вы можете просто вложить их. Снова используйте tf.map_fn внутри операции - person Stewart_R; 20.06.2019
comment
@Leow Я обновил ответ примером вложенных вызовов tf.map_fn - person Stewart_R; 20.06.2019
comment
Спасибо за ответ! Я смог выполнить свои операции, однако это довольно хлопотно, когда я использую tf.map_fn, который имеет несколько входов, но один вход. tf.map_fn должен иметь ту же форму, что и ввод. - person luvwinnie; 20.06.2019