TensorFlow发布「eager」模式,更易操作!

图:pixabay


原文来源:Google Brain

作者:Asim Shankar 、 Wolff Dobson

「雷克世界」编译:嗯~阿童木呀


今天,我们在TensorFlow中引入了Eager Execution。Eager Execution是一个命令式、运行定义式的接口,其中,操作一旦从Python中调用便立刻得以执行。这样TensorFlow的入门使用就变得相对简单,并可以使研究和开发过程更为直观。


使用Eager Execution的益处包括以下几点:


•具有面对即时运行错误的快速调试和Python工具的集成。


•支持使用易用的Python控制流的动态模型。


•大力支持自定义的、高阶梯度。


•适用几乎所有可用的TensorFlow操作。


现在,eager可作为一个实验性特征,所以我们正在寻求来自社区的反馈意见,以指导我们的研究方向。


为了更好地理解这一点,我们可以看一些相关代码,这就非常具有技术性了,而且如果熟悉TensorFlow的话也将会有所帮助。


使用Eager Execution


一旦你启用Eager Execution,操作将立即得以执行,并将其值返回给Python,而不需要调用Session.run()。例如,将两个矩阵相乘,代码为:


importtensorflow as tf

importtensorflow.contrib.eager as tfe

tfe.enable_eager_execution()

x = [[2.]]

m = tf.matmul(x, x)


使用print或Python调试器来检查中间结果其实是很简单的。


print(m)

# The 1x1 matrix [[4.]]


可以使用Python控制流来构建动态模型。下面是使用TensorFlow算术运算构建考拉兹猜想(Collatz conjecture)的一个示例:


a = tf.constant(12)

counter = 0

while not tf.equal(a, 1):

iftf.equal(a % 2, 0):

a = a / 2

else:

a = 3 * a + 1

print(a)


其中,tf.constant(12)张量对象的使用可以促进将所有的数学运算提升到张量运算中,因此所有返回值都将是张量。


梯度


大多数TensorFlow用户都对自动微分法(automatic differentiation)感兴趣。因为在每个调用期间可能会出现不同的操作,所以我们将所有的前向操作记录到一个磁带上,然后在计算梯度时回放。一旦我们计算好梯度之后,就可以将磁带丢弃。


如果你对autograd包非常熟悉的话,那就很简单了,因为API与它是很相似的。例如:


def square(x):

returntf.multiply(x, x)

grad = tfe.gradients_function(square)

print(square(3.)) # [9.]

print(grad(3.)) # [6.]


gradients_function调用使用Python函数square()作为参数,并返回一个Python可调用的函数,用以计算函数square()相对于其输入的偏导数。所以,为了得到输入为3.0时的square()的导数,调用grad(3.0),即结果为6。


可以使用相同的gradients_function调用以得到square的二阶导数:


gradgrad = tfe.gradients_function(lambda x: gra

d(x)[0])

print(gradgrad(3.)) # [2.]


正如我们所说,控制流可以导致不同的操作得以运行,正如在这个例子中显示的那样:


def abs(x):

return x if x > 0. else -x

grad = tfe.gradients_function(abs)

print(grad(2.0)) # [1.]

print(grad(-2.0)) # [-1.]


自定义梯度


用户可能希望为操作或函数自定义梯度。如果从多方面考虑的话,这可能会是有益的,包括为一系列操作提供一个更有效或数值更稳定的梯度。


下面是一个示例,说明了自定义梯度的使用。我们先看看函数log(1 + ex),它通常出现在交叉熵和对数似然值(log likelihoods)的计算中。


def log1pexp(x):

return tf.log(1 + tf.exp(x))

grad_log1pexp = tfe.gradients_function(log1pexp

)

# The gradient computation works fine at x = 0.

print(grad_log1pexp(0.))

# [0.5]

# However it returns a `nan` at x = 100 due to

numerical instability.

print(grad_log1pexp(100.))

# [nan]


我们可以使用上述函数的自定义梯度来分析简化梯度表达式。需要注意的是,下面的梯度函数实现是如何重用在正向传递期间得以计算的表达式(tf.exp(x))的,通过避免冗余计算使得梯度计算更加高效。


@tfe.custom_gradient

def log1pexp(x):

e = tf.exp(x)

def grad(dy):

returndy * (1 - 1 / (1 + e))

return tf.log(1 + e), grad

grad_log1pexp = tfe.gradients_function(log1pexp

)

# Gradient at x = 0 works as before.

print(grad_log1pexp(0.))

# [0.5]

# And now gradient computation at x=100 works a

s well.

print(grad_log1pexp(100.))

# [1.0]


构建模型


模型可以在类中进行组织。下面是一个模型类,它创建一个(简单的)双层网络,可以对标准的MNIST手写数字进行分类。


classMNISTModel(tfe.Network):

def __init__(self):

super(MNISTModel, self).__init__()

self.layer1 = self.track_layer(tf.layers.Dens

e(units=10))

self.layer2 = self.track_layer(tf.layers.Dens

e(units=10))

def call(self, input):

"""Actually runs the model."""

result = self.layer1(input)

result = self.layer2(result)

return result


我们建议在tf.layers中使用类(而不是函数),因为它们创建并包含了模型参数(变量)。变量的生命周期是与层对象的生命周期绑定在一起的,因此要确保对其进行追踪。


为什么要使用tfe.Network?网络就是层的容器,也就是tf.layer.Layer本身,使得Network对象能够嵌入到其他Network对象中。它还包含帮助检查、保存和恢复的实用程序。


即使不对模型进行训练,我们也可以强制调用它并检查输出结果:


# 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)


请注意,我们不需要任何占位符或会话(sessions)。在我们第一次将输入传递进去时,层参数的大小就已经得以设置。


为了能够对任何模型进行训练,我们定义了一个损失函数进行优化、计算梯度,并使用优化器来更新变量。首先,定义一个损失函数:


defloss_function(model, x, y):

y_ = model(x)

returntf.nn.softmax_cross_entropy_with_logits

(labels=y, logits=y_)


然后,训练的循环过程如下:


optimizer = tf.train.GradientDescentOptimizer(l

earning_rate=0.001)

for (x, y) in tfe.Iterator(dataset):

grads = tfe.implicit_gradients(loss_function)

(model, x, y)

optimizer.apply_gradients(grads)


对于在其计算过程中使用的所有TensorFlow变量,implicit_gradients()将计算loss_function的导数。


我们可以将计算移动到GPU上,就像我们一直使用TensorFlow所做的那样:


withtf.device("/gpu:0"):

for (x, y) in tfe.Iterator(dataset):

optimizer.minimize(lambda: loss_function(mo

del, x, y))


(注意:我们正在减少存储损失,并直接调用optimizer.minimize,当然,你也可以使用上面提到的apply_gradients()方法,它们是等效的。)


使用具有graph的eager


Eager Execution使开发和调试过程更加具有互动性,但是涉及在分布式训练、性能优化和生产部署方面,TensorFlow graphs具有很多优势。


启用Eager Execution时,执行操作的相同代码将构建一个描述Eager Execution未启动时的计算图。要将模型转换为图,只需在新的Python会话中运行相同的代码即可,其中,Eager Execution还没有得以启用,正如在MNIST示例中所看到的那样。可以从检查点保存和恢复模型变量的值,从而使我们能够更容易地在eager(命令式)和graph(声明式)之间移动编程。通过这种方式,启用Eager Execution编程的模型可以轻松导出以进行生产部署。


在不久的将来,我们将提供实用程序,以便选择性地将模型的部分转换为图。通过这种方式,你可以将计算的各个部分(例如一个自定义RNN单位的内部)融合在一起,以便实现高性能,还可以保持Eager Execution的灵活性和易读性。


代码如何更改?


对于当前的TensorFlow用户来说,使用Eager Execution应该是很直观、容易的。只有少数专门针对eager 的API可能会有些难度。大多数现有的API和操作需要与已启动的eager一起运行。下面是一些注意事项:


•与TensorFlow一样,我们的建议是,如果你还没有从队列切换到使用tf.data进行输入处理,那你该将其提上日程了。它更容易使用,且通常较快。更多详情,可点击链接查阅:博客文章(https://developers.googleblog.com/2017/09/introducing-tensorflow-datasets.html),相关资料文档(https://www.tensorflow.org/programmers_guide/datasets)。


•使用面向对象层,如tf.layer.Conv2D()或Keras层;它们可以对变量进行显式存储。


•对于大多数模型来说,你可以编写一些代码,以便它们在执行Eager Execution和图形构建时都可以使用。当然也有一些例外,例如使用Python控制流基于输入来改变计算的动态模型。


•一旦你调用了tfe.enable_eager_execution(),它就不能关闭。要获取图行为,请启动一个新的Python会话。


入门和未来


这只是一个预览版,所以你可能会碰到一些不足之处。入门须知:


•安装TensorFlow的nightly版本:https://github.com/tensorflow/tensorflow#installation


•查看README文件(包括已知问题):https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/eager/README.md


•在Eager Execution的用户指南中获取详细的说明:https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/eager/python/g3doc/guide.md


•查看GitHub中的有关Eager示例:https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/eager/python/examples


•查阅变更日志:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/eager/README.md#changelog


回复「转载」获得授权,微信搜索「ROBO_AI」关注公众号


中国人工智能产业创新联盟于2017年6月21日成立,超200家成员共推AI发展,相关动态:

中新网:中国人工智能产业创新联盟成立

ChinaDaily:China forms 1st AI alliance

证券时报:中国人工智能产业创新联盟成立 启动四大工程搭建产业生态“梁柱”

工信部网站:中国人工智能产业创新联盟与贵阳市政府、英特尔签署战略合作备忘录


点击下图加入联盟


下载中国人工智能产业创新联盟入盟申请表


关注“雷克世界”后不要忘记置顶

我们还在搜狐新闻、雷克世界官网、腾讯新闻、网易新闻、一点资讯、天天快报、今日头条、雪球财经……

↓↓↓点击阅读原文查看中国人工智能产业创新联盟手册

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值