有哪些计算图?
- 静态计算图
静态计算则意味着程序在编译执行时将先生成神经网络的结构,然后再执行相应操作。从理论上讲,静态计算这样的机制允许编译器进行更大程度的优化,但是这也意味着你所期望的程序与编译器实际执行之间存在着更多的代沟。这也意味着,代码中的错误将更加难以发现(比如,如果计算图的结构出现问题,你可能只有在代码执行到相应操作的时候才能发现它) - 动态计算图
动态计算意味着程序将按照我们编写命令的顺序进行执行。这种机制将使得调试更加容易,并且也使得我们将大脑中的想法转化为实际代码变得更加容易。 - AutoGraph
TensorFlow 2.0主要使用的是动态计算图和Autograph。而Autograph机制可以将动态图转换成静态计算图,兼收执行效率和编码效率之利。在TensorFlow 2.X中通过@tf.function实现的。
AutoGraph使用规范
- 被@tf.function修饰的函数应尽量使用TensorFlow中的函数而不是Python中的其他函数。
- 避免在@tf.function修饰的函数内部定义tf.Variable.
- 被@tf.function修饰的函数不可修改该函数外部的Python列表或字典等结构类型变量
当我们使用@tf.function装饰一个函数的时候,后面到底发生了什么呢?
1.第一件事情是创建计算图。
2.第二件事情是执行计算图。
AutoGraph使用案例
Autograph的编码规范时提到构建Autograph时应该避免在@tf.function修饰的函数内部定义tf.Variable.但是如果在函数外部定义tf.Variable的话,又会显得这个函数有外部变量依赖,封装不够完美。一种简单的思路是定义一个类,并将相关的tf.Variable创建放在类的初始化方法中。而将函数的逻辑放在其他方法中。
1.利用tf.Module的子类化将其封装一下
class DemoModule(tf.Module):
def __init__(self,init_value = tf.constant(0.0),name=None):
super(DemoModule, self).__init__(name=name)
with self.name_scope: #相当于with tf.name_scope("demo_module")
self.x = tf.Variable(init_value,dtype = tf.float32,trainable=True)
@tf.function(input_signature=[tf.TensorSpec(shape = [], dtype = tf.float32)])
def addprint(self,a):
with self.name_scope:
self.x.assign_add(a)
tf.print(self.x)
return(self.x)
2.子类化模型转化静态图模型
import tensorflow as tf
import numpy as np
class myModel(tf.keras.Model):
def __init__(self,number_classes=10):
super(myModel,self).__init__(name='my_model')
self.num_classes=number_classes
self.dense_1=tf.keras.layers.Dense(32,activation='relu')
self.dense_2=tf.keras.layers.Dense(64,activation='relu')
self.dense_3=tf.keras.layers.Dense(number_classes)
@tf.function(input_signature=[tf.TensorSpec([None,32],dtype=tf.float32)])
def call(self,inputs):
x=self.dense_1(inputs)
x=self.dense_2(x)
x=self.dense_3(x)
return x
model=myModel(10)
model.compile(
optimizer=tf.keras.optimizers.Adam(0.01),
loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True),
mitrics=['accuracy']
)
x=np.random.random((1000,32))
y=np.random.random((1000,10))
model.fit(x,y,batch_size=32,epochs=5)
注意:
如果传入的常量,或者numpy,python的变化而非tensor,autograph都是先构建模型,然后遍历模型,如果传入的是tensor数据类型发生变化,也会重新创建静态图,再执行静态图。