TensorFlow 2.0 整合了 Eager Execution 的简易性和 TensorFlow 1.0 的强大功能。这种整合的核心是 tf.function,方便您将 Python 语法子集转换为便携的高性能 TensorFlow 图形。
AutoGraph 是 tf.function 的一项出色新功能,让您可以使用自然的 Python 语法编写图形代码。如需可以与 AutoGraph 搭配使用的 Python 功能列表,请参阅 AutoGraph 功能和限制。如需有关 tf.function 的更多详细信息,请参阅 RFC TensorFlow 2.0:函数,而非会话。如需有关 AutoGraph 的更多详细信息,请参阅 tf.autograph。
注:AutoGraph 功能和限制 链接
https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/autograph/LIMITATIONS.md
RFC TensorFlow 2.0:函数,而非会话 链接
https://github.com/tensorflow/community/blob/master/rfcs/20180918-functions-not-sessions-20.md
本教程将向您介绍 tf.function 和 AutoGraph 的基本功能。
设置
导入 TensorFlow 2.0 Preview Nightly 并启用 TensorFlow 2.0 模式:
from __future__ import absolute_import, division, print_function, unicode_literals
import numpy as np
!pip install -q tensorflow==2.0.0-alpha0
import tensorflow as tf
安装临时补丁程序以启用一些额外的 TensorFlow 2.0 升级。我们很快会移除此程序。
from tensorflow.python.ops import control_flow_util
control_flow_util.ENABLE_CONTROL_FLOW_V2 = True
tf.function 装饰器
使用 tf.function 注释函数时,您仍可像调用任何其他函数一样调用该函数。不过,系统会将其编译成图形,这可为您带来以下好处:加快执行速度、在 GPU 或 TPU 上运行,或导出至 SavedModel。
@tf.function
def simple_nn_layer(x, y):
return tf.nn.relu(tf.matmul(x, y))
x = tf.random.uniform((3, 3))
y = tf.random.uniform((3, 3))
simple_nn_layer(x, y)
array([[0.29528466, 0.70377195, 0.581679 ],
[0.0462185 , 0.38763517, 0.50960624],
[0.30035543, 1.0594532 , 0.91603595]], dtype=float32)>
如果我们检查注释结果,就会发现这是一个特殊的可调用函数,能够处理与 TensorFlow 运行时的所有交互。
simple_nn_layer
如果您的代码使用多个函数,则您无需对全部函数进行注释,因为从已注释函数调用的任何函数也将以图形模式运行。
def linear_layer(x):
return 2 * x + 1
@tf.function
def deep_net(x):
return tf.nn.relu(linear_layer(x))
deep_net(tf.constant((1, 2, 3)))
使用 Python 控制流
在 tf.function 中使用依赖数据的控制流时,您可以使用 Python 控制流语句,AutoGraph 会将其转换为相应的 TensorFlow 操作。例如,如果 if 语句依赖 Tensor,则这些语句将会转换为 tf.cond()。
在下方示例中,x 是 Tensor,但 if 语句按预期运行:
@tf.function
def square_if_positive(x):
if x > 0:
x = x * x
else:
x = 0
return x
print('square_if_positive(2) = {}'.format(square_if_positive(tf.constant(2))))
print('square_if_positive(-2) = {}'.format(square_if_positive(tf.constant(-2))))
square_if_positive(2) = 4
square_if_positive(-2) = 0
请注意:上方示例使用带有标量值的简单条件句。批处理通常用于实际代码。
AutoGraph 支持常见的 Python 语句,例如 while、for、if、break、continue 和 return,并支持嵌套。这意味着您可以在 while 和 if 语句的条件下使用 Tensor 表达式,或在 for 循环中迭代 Tensor。
@tf.function
def sum_even(items):
s = 0
for c in items:
if c % 2 > 0:
continue
s += c
return s
sum_even(tf.constant([10, 12, 15, 20]))
AutoGraph 还为高级用户提供低级 API。例如,我们可以使用 AutoGraph 查看所生成的代码。
print(tf.autograph.to_code(sum_even.python_function, experimental_optional_features=None))
from __future__ import print_function
def tf__sum_even(items):
do_return = False
retval_ = None
s = 0
def loop_body(loop_vars, s_2):
c = loop_vars
continue_ = False
cond = c % 2 > 0
def if_true():
continue_ = True
return continue_
def if_false():
return continue_
continue_ = ag__.if_stmt(cond, if_true, if_false)
cond_1 = ag__.not_(continue_)
def if_true_1():
s_1, = s_2,
s_1 += c
return s_1
def if_false_1():
return s_2
s_2 = ag__.if_stmt(cond_1, if_true_1, if_false_1)
return s_2,
s, = ag__.for_stmt(items, None, loop_body, (s,))
do_return = True
retval_ = s
return retval_
tf__sum_even.autograph_info__ = {}
下面是一个更复杂的控制流示例:
@tf.function
def fizzbuzz(n):
msg = tf.constant('')
for i in tf.range(n):
if tf.equal(i % 3, 0):
msg += 'Fizz'
elif tf.equal(i % 5, 0):
msg += 'Buzz'
else:
msg += tf.as_string(i)
msg += '\n'
return msg
print(fizzbuzz(tf.constant(15)).numpy().decode())
Fizz
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
Keras 和 AutoGraph
您也可以使用采用对象方法的 tf.function。例如,通常您可以通过注释模型的 call 函数来装饰您的自定义 Keras 模型。如需了解详细信息,请参阅 tf.keras。
class CustomModel(tf.keras.models.Model):
@tf.function
def call(self, input_data):
if tf.reduce_mean(input_data) > 0:
return input_data
else:
return input_data // 2
model = CustomModel()
model(tf.constant([-2, -4]))
副作用
与在 Eager 模式下一样,您可以使用带有副作用的操作,例如通常位于 tf.function 中的 tf.assign 或 tf.print,且 tf.function 会插入必要的控制依赖项以确保这些操作按顺序执行。
v = tf.Variable(5)
@tf.function
def find_next_odd():
v.assign(v + 1)
if tf.equal(v % 2, 0):
v.assign(v + 1)
find_next_odd()
v
示例:训练简单模型
您还可以使用 AutoGraph 在 TensorFlow 中移动更多计算。例如,训练循环只是控制流,因此实际上您可以将其引入 TensorFlow。
下载数据
def prepare_mnist_features_and_labels(x, y):
x = tf.cast(x, tf.float32) / 255.0
y = tf.cast(y, tf.int64)
return x, y
def mnist_dataset():
(x, y), _ = tf.keras.datasets.mnist.load_data()
ds = tf.data.Dataset.from_tensor_slices((x, y))
ds = ds.map(prepare_mnist_features_and_labels)
ds = ds.take(20000).shuffle(20000).batch(100)
return ds
train_dataset = mnist_dataset()
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step
定义模型
model = tf.keras.Sequential((
tf.keras.layers.Reshape(target_shape=(28 * 28,), input_shape=(28, 28)),
tf.keras.layers.Dense(100, activation='relu'),
tf.keras.layers.Dense(100, activation='relu'),
tf.keras.layers.Dense(10)))
model.build()
optimizer = tf.keras.optimizers.Adam()
定义训练循环
compute_loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
compute_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()
def train_one_step(model, optimizer, x, y):
with tf.GradientTape() as tape:
logits = model(x)
loss = compute_loss(y, logits)
grads = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(grads, model.trainable_variables))
compute_accuracy(y, logits)
return loss
@tf.function
def train(model, optimizer):
train_ds = mnist_dataset()
step = 0
loss = 0.0
accuracy = 0.0
for x, y in train_ds:
step += 1
loss = train_one_step(model, optimizer, x, y)
if tf.equal(step % 10, 0):
tf.print('Step', step, ': loss', loss, '; accuracy', compute_accuracy.result())
return step, loss, accuracy
step, loss, accuracy = train(model, optimizer)
print('Final step', step, ': loss', loss, '; accuracy', compute_accuracy.result())
Step 10 : loss 1.84492886 ; accuracy 0.37
Step 20 : loss 1.07085669 ; accuracy 0.5415
Step 30 : loss 0.771448374 ; accuracy 0.613333344
Step 40 : loss 0.608694196 ; accuracy 0.67225
Step 50 : loss 0.508914351 ; accuracy 0.7084
Step 60 : loss 0.347155064 ; accuracy 0.7365
Step 70 : loss 0.374278426 ; accuracy 0.757142842
Step 80 : loss 0.457216293 ; accuracy 0.774375
Step 90 : loss 0.366965473 ; accuracy 0.787222207
Step 100 : loss 0.398182064 ; accuracy 0.7985
Step 110 : loss 0.210726 ; accuracy 0.808181822
Step 120 : loss 0.41397053 ; accuracy 0.817166686
Step 130 : loss 0.246230051 ; accuracy 0.824538469
Step 140 : loss 0.270531863 ; accuracy 0.831071436
Step 150 : loss 0.260166764 ; accuracy 0.835933328
Step 160 : loss 0.161626607 ; accuracy 0.841375
Step 170 : loss 0.101895899 ; accuracy 0.845647037
Step 180 : loss 0.365272254 ; accuracy 0.85
Step 190 : loss 0.363062441 ; accuracy 0.853421032
Step 200 : loss 0.238487661 ; accuracy 0.85685
Final step tf.Tensor(200, shape=(), dtype=int32) : loss tf.Tensor(0.23848766, shape=(), dtype=float32) ; accuracy tf.Tensor(0.85685, shape=(), dtype=float32)
批处理
在实际应用中,批处理对性能至关重要。转换为 AutoGraph 的最佳代码是在批处理层面决定控制流的代码。如果在单个示例层面作决定,请尝试使用批处理 API 维持性能。
例如,如果您在 Python 中有以下代码:
def square_if_positive(x):
return [i ** 2 if i > 0 else i for i in x]
square_if_positive(range(-5, 5))
[-5, -4, -3, -2, -1, 0, 1, 4, 9, 16]
您可能想在 TensorFlow 中将其编写成如下形式(而这种方法有效!):
@tf.function
def square_if_positive_naive(x):
result = tf.TensorArray(tf.int32, size=x.shape[0])
for i in tf.range(x.shape[0]):
if x[i] > 0:
result = result.write(i, x[i] ** 2)
else:
result = result.write(i, x[i])
return result.stack()
square_if_positive_naive(tf.range(-5, 5))
但在这种情况下,结果是您可编写如下代码:
def square_if_positive_vectorized(x):
return tf.where(x > 0, x ** 2, x)
square_if_positive_vectorized(tf.range(-5, 5))
更多 AI 相关阅读:
TensorFlow Lite 对象检测
标贝科技:TensorFlow 框架提升语音合成效果
使用 TensorFlow Model Analysis 提升模型质量