Tensorflow的Eager Execution是一种命令编程环境,操作会返回具体的值。
要启动Eager Execution,请将tf.enable_eager_execution()添加到程序或控制台回话的开头。
启用Eager Execution会改变TensorFlow操作的行为方式,现在他们会立即评估并将值返回给Python。tf.Tensor对象会引用具体值,而不是指向计算图中的节点的符号句柄。由于不需要构建稍后在会话中运行的计算图,因此使用print()或调试程序很容易检查结果。评估、输出和检查张量值不会中断计算梯度的流程。
tf.Tensor与numpy ndarray可以互相转换。
动态控制流:
在执行模型时,主机语言的所有功能都可用。
构建模型
将TensorFlow与Eager与Eager Execution结合使用时,可以编写自己的层或使用在tf.keras.layers程序包中提供的层。
虽然可以使用任何Python对象表示层,但TensorFlow提供了便利的基类tf.karas.layers.Layer。可以通过他实现自己的层:
class MysimpleLayer(tf.keras.layers.Layer): def __init__(self,output_units): super(MysimpleLayer,self).__init__() self.output_units=output_units def build(self,input_shape): #权重形状 self.kernel=self.add_variable("kernel",[input_shape[-1],self.output_units]) def call(self,input): #输出 return tf.matmul(input,self.kernel)
最好使用tf.keras.layers.Dense层(而不是上面的MysimpleLayer),它具有其功能的超集(它可以添加偏差)。
将层组合成模型时,可以使用tf.keras.Sequential表示层线性堆叠的模型。他非常适合基本模型:
model=tf.keras.Sequential([tf.keras.layer.Dense(10,input_shape=(784,)), tf.keras.layers.Dense(10)])#必须指明第一层的形状
或者,通过继承tf.keras.Model将模型整理为类。这是一个本身也是层的层容器,允许tf.keras.Model对象包含其他tf.keras.Model对象。
class MniSTModel(tf.keras.Model): def __init__(self): super(MniSTModel,self).__init__() self.dese1=tf.keras.layers.Dense(units=10) self.dense2=tf.keras.layers.Dense(units=10) def call(self,input): result=self.dense1(input) result=self.dense2(result) result=self.dense2(result)#复用dense2权重 return result model=MniSTModel()
计算梯度
自动微分对于实现机器学习算法(例如神经网络的反向传播)来说很有用。在Eager Execution期间,使用tf.GradientTape跟踪操作以便稍后计算梯度。
tf.GradientTape是一种选择性功能,可在不跟踪时提供最佳性能。由于在每次调用期间都可能发生不同的操作,因此所有的前向传播都会记录到“磁带"中。要计算梯度,反向播放磁带,然后放弃。特定的tf.gradientTape只能计算一个梯度;随后的调用会抛出运行时错误。
w=tf.Variable([[1.0]]) with tf.GradientTape() as tape: loss=w*w grad=tape.gradient(loss,w) print(grad)#=>tf.Tensor([[2.]],shape=(1,1),dtype=float32)
训练模型
以下实例将创建一个多层模型,该模型会对标准MNIST手写数组进行分类。它演示了在Eager Execution环境中构建可训练图的优化器和层API。
#下载mnist数据集 (mnist_images,mnist_labels),_=tf.keras.datasets.mnist.load_data() dataset=tf.data.Dataset.from_tensor_silices((tf.cast(mnist_images[...,tf.newaxis]/255,tf.float32),tf.cast(mnist_labels,tf.int64))) dataset=dataset.shuffle(1000).batch(32) #构建模型 mnist_model=tf.keras.Sequential([tf.keras.layers.Conv2D(16,[3,3],activation='relu'), tf.keras.layers.Conv2D(16,[3,3],activation='relu'), tf.keras.layers.GlobalAveragePooling2D(), tf.keras.layers.Dense(10) ])
即使没有训练,也可以在Eager Execution中调用模型并检查输出:
for images,labels in dataset.take(1): print('logits:",mnist_model(images[0:1]).numpy())
虽然keras模型具有内置训练循环(使用fit方法),但有时需要更多自定义设置。 下面是一个用eager实现的训练循环示例:
optimizer=tf.train.AdamOptimizer() loss_history=[] for (batch,(images,labels)) in enumerate(dataset.take(400)): if batch %80==0: print() print('.',end=' ') with tf.GradientTape() as tape: logits=mnist_model(images,training=True) loss_value=tf.losses.sparse_sorftmax_cross_entropy(labels,logits) loss_history.append(loss_value.numpy()) grads=tape.gradient(loss_value,mnist_model.variables) optimizer.apply_gradients(zip(grads,mnist_model.variables),global_step=tf.train.get_or_create_global_step()) import matplotlib.pyplot as plt plt.plot(loss_history) plt.xlabel('Batch #') plt.ylabel('loss [entropy]') Text(0,0.5,'loss [entropy]')
变量和优化器
tf.Variable对象会储存在训练期间访问的可变tf.Tensor值,以更加轻松地实现自动微分。模型的参数可作为变量封装在类中。
通过将tf.Variable与tf.GradientTape结合使用可以更好的封装模型参数。例如,上面的自动微分示例可以重写为:
class Model(tf.keras.Model): def __init__(self): super(Model,self).__init__() self.W=tf.Variable(5.,name='weight') self.B=tf.Variable(10.,name='bias') def call(self,inputs): return inputs*self.W+self.B #创建小型数据集 NUM_EXAMPLES=2000 training_inputs=tf.random_normal([NUM_EXAMPLES]) noise=tf.random_normal([NUM_EXAMPLES]) training_outputs=training_inputs*3+2+noise #损失函数 def loss(model,inputs,targets): error=model(inputs)-targets return tf.reduce_mean(tf.square(error)) def grad(model,inputs,targets): with tf.GradientTape() as tape: loss_value=loss(model,inputs,targets) return tape.gradient(loss_value,[model.W,model.B]) #1.建立model实例 2.计算损失函数对W、B的微分 3.更新参数 model=Model() optimizer=tf.train.GradientDescentOptimizer(learning_rate=0.01) print('Initial loss:{:.3f}'.format(loss(model,training_inputs,training_outputs))) #训练xunhuan for i in range(300): grads=grad(model,training_inputs,training_outputs) optimizer.apply_gradients(zip(grads,[model.W,model.B]),global_step=tf.train.get_or_create_global_step()) if i%20==0: print('Loss at step {:03d}:{:.3f}'.format(i,loss(model,training_inputs,training_outputs))) print('Final loss:{:.3f}'.format(loss(model,training_inputs,training_outputs))) print('W={},B={}'.format(model.W.numpy(),model.B.numpy()))