TL;DR 在即将发布(本文章写于 2018-01-06)的 TenserFlow v1.5 中,TensorFlow将会引入一个重要的 User-friendly 特性:Eager Execution. 本文章将展示 Eager Execution 引入的一些新的特性。

安装 TensorFlow 对应的版本

因为 TensorFlow 正式版(写作时间 2018-01-06,此时的正式版本为1.4.1)中还不包含此功能,因此我们需要安装 TensorFlow nightly build 版本。

pip install tf-nightly  # or tf-nightly-gpu if you have GPU

特性探索

Eager execution

在开启这个模式后,TensorFlow 将会立即执行操作,返回结果给 Python,而不需要使用 Session.run(), 例如:

import tensorflow as tf
import tensorflow.contrib.eager as tfe

tfe.enable_eager_execution()

x = [[2]]
m = tf.matmul(x, x)

print(m)

点击这里 launch binder ,在线运行这个例子

你会得到如下显示:

tf.Tensor([[4]], shape=(1, 1), dtype=int32)

Dynamic models

在不具备动态模型的能力前,TensorFlow 中的每一个 operator 都需要明确定声明和定义。在具备的了动态模型能力之后,TensorFlow 具备了从操作中推导操作数类型的能力,让复杂的动态模型容易实现,例如:

import tensorflow as tf
import tensorflow.contrib.eager as tfe

tfe.enable_eager_execution()

a = tf.constant(12)
counter = 0
while not tf.equal(a, 1):
  if tf.equal(a % 2, 0):
    a = a / 2
  else:
    a = 3 * a + 1
  print(a)

点击这里 launch binder ,在线运行这个例子

如果没有启用 Eager Execution 会显示如下错误:

Using a tf.Tensor as a Python bool is not allowed.

原因是在 while not tf.equal(a, 1) 处,如果没有启动 Eager Execution 那么返回的结果是 tf.Tensor 对象,因为还不知道具体的值所以不能转换成bool类型。

Gradients

得益于 Eager Execution 立即执行的特性,Gradients 也可以立即得到,而不用等到运行时才能知道,例子如下:

import tensorflow as tf
import tensorflow.contrib.eager as tfe

tfe.enable_eager_execution()

def square(x):
  return tf.multiply(x, x)

grad = tfe.gradients_function(square)

print(square(3.))    # 输出 [9.]
print(grad(3.))      # 输出 [6.]

点击这里 launch binder ,在线运行这个例子

输入的具体情况如下:

tf.Tensor(9.0, shape=(), dtype=float32)
[<tf.Tensor: id=11, shape=(), dtype=float32, numpy=6.0>]

Building models

官方推荐应该使用 Python 的 class 来组织模型结构而不是 function。Eager Execution 带有的 tfe.Network 就是设计用来作为模型的父类的,继承这个类之后就支持网络的套嵌,下面这段代码是官方推荐的简易 MNIST 模型的参考:

class MNISTModel(tfe.Network):
  def __init__(self):
    super(MNISTModel, self).__init__()
    self.layer1 = self.track_layer(tf.layers.Dense(units=10))
    self.layer2 = self.track_layer(tf.layers.Dense(units=10))
  def call(self, input):
    """Actually runs the model."""
    result = self.layer1(input)
    result = self.layer2(result)
    return result

即使没有训练,我们也能够立即调用它并观察输出:

# Let's make up a blank input image
model = MNISTModel()
batch = tf.zeros([1, 1, 784])
print(batch.shape)
# (1, 1, 784)
result = model(batch)
print(result)
# tf.Tensor([[[ 0.  0., ...., 0.]]], shape=(1, 1, 10), dtype=float32)

这里并不需要使用 placeholders 或者 sessions。当我们第一输入时,模型的参数会被设定好。

为了训练任何模型,我们都需要 loss function,calculate gradients 和 optimizer 去优化参数。 loss function

def loss_function(model, x, y):
    y_ = model(x)
    return tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=y_)

calculate gradients & optimizer

optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)
for (x, y) in tfe.Iterator(dataset):
    grads = tfe.implicit_gradients(loss_function)(model, x, y)
    optimizer.apply_gradients(grads)

点击这里 launch binder ,在线运行这个例子

其他特性

还有其他特性,如:

  • get the second derivative
  • derivative under control flow
  • Custom Gradients

这里就不再介绍,感兴趣的可以参考官方文档或者本文的参考文档。

参考文档