TensorFlow编程指南 Eager Execution.docx
《TensorFlow编程指南 Eager Execution.docx》由会员分享,可在线阅读,更多相关《TensorFlow编程指南 Eager Execution.docx(20页珍藏版)》请在冰豆网上搜索。
TensorFlow编程指南EagerExecution
EagerExecution
TensorFlow的EagerExecution是一种命令式编程环境,可立即评估操作,无需构建图:
操作会返回具体的值,而不是构建以后再运行的计算图。
这样能让您轻松地开始使用TensorFlow和调试模型,并且还减少了样板代码。
要遵循本指南,请在交互式 python 解释器中运行下面的代码示例。
EagerExecution是一个灵活的机器学习平台,用于研究和实验,可提供:
∙直观的界面-自然地组织代码结构并使用Python数据结构。
快速迭代小模型和小型数据集。
∙更轻松的调试功能-直接调用操作以检查正在运行的模型并测试更改。
使用标准Python调试工具进行即时错误报告。
∙自然控制流程-使用Python控制流程而不是图控制流程,简化了动态模型的规范。
EagerExecution支持大多数TensorFlow操作和GPU加速。
有关在EagerExecution中运行的示例集合,请参阅:
tensorflow/contrib/eager/python/examples。
注意:
如果启用EagerExecution,某些模型的开销可能会增加。
我们正在改进性能;如果发现问题,请报告错误,并分享您的基准测试结果。
设置和基本用法
升级到最新版本的TensorFlow:
$pipinstall--upgradetensorflow
要启动EagerExecution,请将 tf.enable_eager_execution() 添加到程序或控制台会话的开头。
不要将此操作添加到程序调用的其他模块。
from__future__importabsolute_import,division,print_function
importtensorflowastf
tf.enable_eager_execution()
现在您可以运行TensorFlow操作了,结果将立即返回:
tf.executing_eagerly() #=>True
x=[[2.]]
m=tf.matmul(x,x)
print("hello,{}".format(m)) #=>"hello,[[4.]]"
启用EagerExecution会改变TensorFlow操作的行为方式-现在它们会立即评估并将值返回给Python。
tf.Tensor 对象会引用具体值,而不是指向计算图中的节点的符号句柄。
由于不需要构建稍后在会话中运行的计算图,因此使用 print() 或调试程序很容易检查结果。
评估、输出和检查张量值不会中断计算梯度的流程。
EagerExecution适合与 NumPy 一起使用。
NumPy操作接受 tf.Tensor 参数。
TensorFlow 数学运算将Python对象和NumPy数组转换为 tf.Tensor 对象。
tf.Tensor.numpy 方法返回对象的值作为NumPy ndarray。
a=tf.constant([[1,2],
[3,4]])
print(a)
#=>tf.Tensor([[12]
# [34]],shape=(2,2),dtype=int32)
#Broadcastingsupport
b=tf.add(a,1)
print(b)
#=>tf.Tensor([[23]
# [45]],shape=(2,2),dtype=int32)
#Operatoroverloadingissupported
print(a*b)
#=>tf.Tensor([[2 6]
# [1220]],shape=(2,2),dtype=int32)
#UseNumPyvalues
importnumpyasnp
c=np.multiply(a,b)
print(c)
#=>[[2 6]
# [1220]]
#Obtainnumpyvaluefromatensor:
print(a.numpy())
#=>[[12]
# [34]]
tf.contrib.eager 模块包含可用于EagerExecution和GraphExecution环境的符号,对编写处理图的代码非常有用:
tfe=tf.contrib.eager
动态控制流
EagerExecution的一个主要好处是,在执行模型时,主机语言的所有功能都可用。
因此,编写 fizzbuzz 很容易(举例而言):
deffizzbuzz(max_num):
counter=tf.constant(0)
fornuminrange(max_num):
num=tf.constant(num)
ifint(num%3)==0andint(num%5)==0:
print('FizzBuzz')
elifint(num%3)==0:
print('Fizz')
elifint(num%5)==0:
print('Buzz')
else:
print(num)
counter+=1
returncounter
这段代码具有依赖于张量值的条件并在运行时输出这些值。
构建模型
许多机器学习模型通过组合层来表示。
在将TensorFlow与EagerExecution结合使用时,您可以编写自己的层或使用在 tf.keras.layers 程序包中提供的层。
虽然您可以使用任何Python对象表示层,但TensorFlow提供了便利的基类 tf.keras.layers.Layer。
您可以通过继承它实现自己的层:
classMySimpleLayer(tf.keras.layers.Layer):
def__init__(self,output_units):
self.output_units=output_units
defbuild(self,input):
#Thebuildmethodgetscalledthefirsttimeyourlayerisused.
#Creatingvariablesonbuild()allowsyoutomaketheirshapedepend
#ontheinputshapeandhenceremovetheneedfortheusertospecify
#fullshapes.Itispossibletocreatevariablesduring__init__()if
#youalreadyknowtheirfullshapes.
self.kernel=self.add_variable(
"kernel",[input.shape[-1],self.output_units])
defcall(self,input):
#Overridecall()insteadof__call__sowecanperformsomebookkeeping.
returntf.matmul(input,self.kernel)
请使用 tf.keras.layers.Dense 层(而不是上面的 MySimpleLayer),因为它具有其功能的超集(它也可以添加偏差)。
将层组合成模型时,可以使用 tf.keras.Sequential 表示由层线性堆叠的模型。
它非常适合用于基本模型:
model=tf.keras.Sequential([
tf.keras.layers.Dense(10,input_shape=(784,)), #mustdeclareinputshape
tf.keras.layers.Dense(10)
])
或者,通过继承 tf.keras.Model 将模型划分为不同类别。
这是一个本身也是层的层容器,允许 tf.keras.Model 对象包含其他 tf.keras.Model 对象。
classMNISTModel(tf.keras.Model):
def__init__(self):
super(MNISTModel,self).__init__()
self.dense1=tf.keras.layers.Dense(units=10)
self.dense2=tf.keras.layers.Dense(units=10)
defcall(self,input):
"""Runthemodel."""
result=self.dense1(input)
result=self.dense2(result)
result=self.dense2(result) #reusevariablesfromdense2layer
returnresult
model=MNISTModel()
因为第一次将输入传递给层时已经设置参数,所以不需要为 tf.keras.Model 类设置输入形状。
tf.keras.layers 类创建并包含自己的模型变量,这些变量与其层对象的生命周期相关联。
要共享层变量,请共享其对象。
Eager训练
计算梯度
自动微分对于实现机器学习算法(例如用于训练神经网络的反向传播)很有用。
在EagerExecution期间,请使用 tf.GradientTape 跟踪操作以便稍后计算梯度。
tf.GradientTape 是一种选择性功能,可在不跟踪时提供最佳性能。
由于在每次调用期间都可能发生不同的操作,因此所有前向传播操作都会记录到“磁带”中。
要计算梯度,请反向播放磁带,然后放弃。
特定的 tf.GradientTape 只能计算一个梯度;随后的调用会引发运行时错误。
w=tfe.Variable([[1.0]])
withtf.GradientTape()astape:
loss=w*w
grad=tape.gradient(loss,[w])
print(grad) #=>[tf.Tensor([[2.]],shape=(1,1),dtype=float32)]
下面是一个记录前向传播操作以训练简单模型的 tf.GradientTape 示例:
#Atoydatasetofpointsaround3*x+2
NUM_EXAMPLES=1000
training_inputs=tf.random_normal([NUM_EXAMPLES])
noise=tf.random_normal([NUM_EXAMPLES])
training_outputs=training_inputs*3+2+noise
defprediction(input,weight,bias):
returninput*weight+bias
#Alossfunctionusingmean-squarederror
defloss(weights,biases):
error=prediction(training_inputs,weights,biases)-training_outputs
returntf.reduce_mean(tf.square(error))
#Returnthederivativeoflosswithrespecttoweightandbias
defgrad(weights,biases):
withtf.GradientTape()astape:
loss_value=loss(weights,biases)
returntape.gradient(loss_value,[weights,biases])
train_steps=200
learning_rate=0.01
#StartwitharbitraryvaluesforWandBonthesamebatchofdata
W=tfe.Variable(5.)
B=tfe.Variable(10.)
print("Initialloss:
{:
.3f}".format(loss(W,B)))
foriinrange(train_steps):
dW,dB=grad(W,B)
W.assign_sub(dW*learning_rate)
B.assign_sub(dB*learning_rate)
ifi%20==0:
print("Lossatstep{:
03d}:
{:
.3f}".format(i,loss(W,B)))
print("Finalloss:
{:
.3f}".format(loss(W,B)))
print("W={},B={}".format(W.numpy(),B.numpy()))
输出(具体数字可能会有所不同):
Initialloss:
71.204
Lossatstep000:
68.333
Lossatstep020:
30.222
Lossatstep040:
13.691
Lossatstep060:
6.508
Lossatstep080:
3.382
Lossatstep100:
2.018
Lossatstep120:
1.422
Lossatstep140:
1.161
Lossatstep160:
1.046
Lossatstep180:
0.996
Finalloss:
0.974
W=3.01582956314,B=2.1191945076
重播 tf.GradientTape 以计算梯度并将梯度应用于训练循环中。
下面是来自 mnist_eager.py 示例的摘录:
dataset=tf.data.Dataset.from_tensor_slices((data.train.images,
data.train.labels))
...
for(batch,(images,labels))inenumerate(dataset):
...
withtf.GradientTape()astape:
logits=model(images,training=True)
loss_value=loss(logits,labels)
...
grads=tape.gradient(loss_value,model.variables)
optimizer.apply_gradients(zip(grads,model.variables),
global_step=tf.train.get_or_create_global_step())
以下示例将创建一个多层模型,该模型会对标准 MNIST手写数字进行分类。
它演示了在EagerExecution环境中构建可训练图的优化器和层API。
训练模型
即使没有训练,也可以在EagerExecution中调用模型并检查输出:
#Createatensorrepresentingablankimage
batch=tf.zeros([1,1,784])
print(batch.shape) #=>(1,1,784)
result=model(batch)
#=>tf.Tensor([[[0. 0.,...,0.]]],shape=(1,1,10),dtype=float32)
该示例使用了 TensorFlowMNIST示例中的 dataset.py模块,请将该文件下载到本地目录。
运行以下命令以将MNIST数据文件下载到工作目录并准备要进行训练的 tf.data.Dataset:
importdataset #downloaddataset.pyfile
dataset_train=dataset.train('./datasets').shuffle(60000).repeat(4).batch(32)
为了训练模型,请定义损失函数以进行优化,然后计算梯度。
使用优化器更新变量:
defloss(model,x,y):
prediction=model(x)
returntf.losses.sparse_softmax_cross_entropy(labels=y,logits=prediction)
defgrad(model,inputs,targets):
withtf.GradientTape()astape:
loss_value=loss(model,inputs,targets)
returntape.gradient(loss_value,model.variables)
optimizer=tf.train.GradientDescentOptimizer(learning_rate=0.001)
x,y=iter(dataset_train).next()
print("Initialloss:
{:
.3f}".format(loss(model,x,y)))
#Trainingloop
for(i,(x,y))inenumerate(dataset_train):
#Calculatederivativesoftheinputfunctionwithrespecttoitsparameters.
grads=grad(model,x,y)
#Applythegradienttothemodel
optimizer.apply_gradients(zip(grads,model.variables),
global_step=tf.train.get_or_create_global_step())
ifi%200==0:
print("Lossatstep{:
04d}:
{:
.3f}".format(i,loss(model,x,y)))
print("Finalloss:
{:
.3f}".format(loss(model,x,y)))
输出(具体数字可能会有所不同):
Initialloss:
2.674
Lossatstep0000:
2.593
Lossatstep0200:
2.143
Lossatstep0400:
2.009
Lossatstep0600:
2.103
Lossatstep0800:
1.621
Lossatstep1000:
1.695
...
Lossatstep6600:
0.602
Lossatstep6800:
0.557
Lossatstep7000:
0.499
Lossatstep7200:
0.744
Lossatstep7400:
0.681
Finalloss:
0.670
为了加速训练,可以将计算移至GPU:
withtf.device("/gpu:
0"):
for(i,(x,y))inenumerate(dataset_train):
#minimize()isequivalenttothegrad()andapply_gradients()calls.
optimizer.minimize(lambda:
loss(model,x,y),
global_step=tf.train.get_or_create_global_step())
变量和优化器
tfe.Variable 对象存储在训练期间访问的可变 tf.Tensor 值,以更加轻松地实现自动微分。
模型的参数可以作为变量封装在类中。
通过将 tfe.Variable 与 tf.GradientTape 结合使用可以更好地封装模型参数。
例如,上面的自动微分示例可以重写为:
classModel(tf.keras.Model):
def__init__(self):
super(Model,self).__init__()
self.W=tfe.Variable(5.,name='weight')
self.B=tfe.Variable(10.,name='bias')
defpredict(self,inputs):
returninputs*self.W+self.B
#Atoydatasetofpointsaround3*x+2
NUM_EXAMPLES=2000
training_inputs=tf.random_normal([NUM_EXAMPLES])
noise=tf.random_normal([NUM_EXAMPLES])
training_outputs=training_inputs*3+2+noise
#Thelossfunctiontobeoptimized
defloss(model,inputs,targets):
error=model.predict(inputs)-targets
returntf.reduce_mean(tf.square(err