tensorflow2.x的autograph

使用autograph需要注意的地方

  1. 使用tf自带的函数,而不是原始的Python函数。

因为python中的函数仅仅会在跟踪执行函数以创建静态图的阶段使用,普通python函数无法嵌入到静态图中,所以在计算图构建好之后再次调用的时候,这些python函数并没有被计算,使用python函数会导致被装饰器装饰前(eager执行)和被装饰器修饰后(静态图执行)的输出不一致。

例如:
被@tf.function修饰过的函数利用np生成随机数每一次都是一样的,而使用tf就是不一样的。

import tensorflow as tf
import numpy as np

# 在tf.function中用input_signature限定输入张量的签名类型:shape和dtype
@tf.function(input_signature=[tf.TensorSpec(shape=[], dtype=tf.float32)])
def np_random():
    a = np.random.randn(3, 3)
    tf.print(a)


@tf.function
def tf_random():
    b = tf.random.normal((3, 3))
    tf.print(b)

# 被修饰过的np随机数每一次都是一样的
np_random()
np_random()
# 被修饰过的tf随机数每一次不一样
tf_random()
tf_random()

输出:

array([[-0.15504732,  1.55624863,  0.05300533],
       [ 0.31764741, -0.74893782, -1.09177159],
       [ 0.99932818,  0.45183048,  0.52071062]])
array([[-0.15504732,  1.55624863,  0.05300533],
       [ 0.31764741, -0.74893782, -1.09177159],
       [ 0.99932818,  0.45183048,  0.52071062]])
[[-0.477426946 0.0352273062 1.25906813]
 [-1.60776 -0.919097424 0.199720368]
 [-0.819047332 -0.321983 -1.48350918]]
[[0.992117703 -0.778428 0.158320323]
 [1.04978251 -0.56633848 -0.407015771]
 [1.45319021 0.473201066 0.672261238]]
  1. 避免在@tf.function修饰的函数内部定义tf.Variable

如果函数内部定义了tf.Variable,那么在eager执行的时候,这种创建变量的行为在每次函数调用的时候都会发生,但是在静态图执行的时候,这种创建变量的行为只会发生在第一步跟踪python代码逻辑创建计算图时。这会导致修饰前后输出结果不一致

如:
在函数内部定义tf.Variable然后报错

# 在修饰外部创建
x = tf.Variable(1.0, dtype=tf.float32)
@tf.function
def out():
    x.assign_add(1.0)
    tf.print(x)

out()
out()

@tf.function
def inside():
    a = tf.Variable(1.0, dtype=tf.float32)
    a.assign_add(1.0)
    tf.print(a)

# 报错
# inside()
# inside()
  1. 被@tf.function修饰的函数不可修改该函数外部的python列表或者字典等结构类型变量

静态计算图是被编译成c++代码在tensorflow内核中执行的,python中的列表和字典等数据结构变量时无法嵌入到计算图中的,他们仅仅能够在创建计算图的时候被读取,在执行计算图的时候无法修改Python中的列表和字典这样的数据结构变量的"""

lyst = []
@tf.function
def append_list(x):
    lyst.append(x)
    tf.print(lyst)

append_list(tf.constant(4.3))
append_list(tf.constant(2.3))
print(lyst)

输出:

[<tf.Tensor 'x:0' shape=() dtype=float32>]
[4.3]
[2.3]

autograph的工作机制

工作机制:

  1. 创建计算图
  2. 执行计算图

第一次输入两个参数都为str的数据

@tf.function(autograph=True)
def add(a, b):
    for i in tf.range(4):
        tf.print(i)
    c = a + b
    print('finish')
    return c

# 第一次输入:
add(tf.constant('hello'), tf.constant('world'))

输出:

finish
0
1
2
3

当再次使用相同的输入参数类型调用这个被@tf.function装饰的函数的时,只会发生一件事情,那就是执行上面步骤的第二步,执行计算图。所以没有看见打印’finish‘的结果

add(tf.constant('td'), tf.constant('new_world'))

输出:

0
1
2
3

当使用不同的类型参数作为输入的时候,会重新创建一个计算图,由于参数的类型发生了变化,已经创建的计算图不能再次使用

add(tf.constant(3.4), tf.constant(4.4))

输出:

finish
0
1
2
3

当输入的不是tensor类型的时候,每一次都会重新创建计算图,所以建议调用@tf.function的时候传入tensor类型的数据。例如

add('td', 'new_world')

输出:

finish
0
1
2
3

猜你喜欢

转载自blog.csdn.net/weixin_43141320/article/details/107119385