使用 tf.keras 功能 API 时如何在 tensorflow/keras 中使用 for 循环?
how to use for loop in tensorflow/keras when using tf.keras functional API?
我想用 for 循环修改 CuDNNGRU 输出。但是,由于 tf.GradientTape 图形模式,我似乎无法这样做。如何修改 Functional API 中的 CuDNNGRU?我知道通常我们可以对函数 API 和 tf.keras.backend.* 函数执行一些矩阵操作,例如 K.backend.batch_dot 等。但是,我必须做一些复杂的操作,例如 triple for loop 或更多等等,如果有人知道怎么做,请帮助!
.....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
顺便说一下,我目前正在尝试使用以下代码修改 GRU 输出。
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 return [time,features] 而不是 [batch,time,features],如果可以的话,我可以用 tf.py_function 建立一个图层。但是好像不行,HELP!!!!
更新
我已经能够通过嵌套 tf.map_fn 实现操作。虽然它需要适当考虑传递给tf.map_fn的内容(多个输入必须是多个输出中的return)。希望这可以帮助其他人
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)
对于任何想要将其应用于 tensor
中的每个 i
的任意操作,您可以只使用 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)
我想用 for 循环修改 CuDNNGRU 输出。但是,由于 tf.GradientTape 图形模式,我似乎无法这样做。如何修改 Functional API 中的 CuDNNGRU?我知道通常我们可以对函数 API 和 tf.keras.backend.* 函数执行一些矩阵操作,例如 K.backend.batch_dot 等。但是,我必须做一些复杂的操作,例如 triple for loop 或更多等等,如果有人知道怎么做,请帮助!
.....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
顺便说一下,我目前正在尝试使用以下代码修改 GRU 输出。
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 return [time,features] 而不是 [batch,time,features],如果可以的话,我可以用 tf.py_function 建立一个图层。但是好像不行,HELP!!!!
更新
我已经能够通过嵌套 tf.map_fn 实现操作。虽然它需要适当考虑传递给tf.map_fn的内容(多个输入必须是多个输出中的return)。希望这可以帮助其他人
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)
对于任何想要将其应用于 tensor
中的每个 i
的任意操作,您可以只使用 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)