前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Tensorflow2——Eager模式简介以及运用

Tensorflow2——Eager模式简介以及运用

作者头像
Albert_xiong
发布2021-06-21 16:39:50
1K0
发布2021-06-21 16:39:50
举报
文章被收录于专栏:Mybatis学习Mybatis学习

Eager模式简介以及运用

1、什么是Eager模式?

使用过TensorFlow的大家都会知道, TF通过计算图将计算的定义和执行分隔开, 这是一种声明式(declaretive)的编程模型. 确实, 这种静态图的执行模式优点很多,但是在debug时确实非常不方便(类似于对编译好的C语言程序调用,此时是我们无法对其进行内部的调试), 因此有了Eager Execution, 这在TensorFlow v1.5首次引入. 引入的Eager Execution模式后, TensorFlow就拥有了类似于Pytorch一样动态图模型能力, 我们可以不必再等到see.run(*)才能看到执行结果, 可以方便在IDE随时调试代码,查看OPs执行结果. tf.keras封装的太好了 。不利于适用于自定义的循环与训练,添加自定义的循环 是一个命令式的编程环境,它使得我们可以立即评估操作产生的结果,而无需构建计算图。

图运算模式:把一系列的操作搭建好,然后再进行操作,某一步出现错误的话,很难排查,不利于自定义的动作 eager模式:做一步,就能看到结果,交互模式(命令行模式),增加了网络调试的灵活程度,在TensorFlow2的时候,默认的使用了eager模式

首先声明一个比较常见的问题: 至于为什么要导入除了第一行意外的另外几行,我在训练的时候遇到了一个问题,问题如下: “Failed to get convolution algorithm. This is probably because cuDNN failed to initialize” 网上大多数人说什么tf和cuDNN的版本不匹配啊啥的,最后发现可能是GPU内存不足造成的。需要在程序前加以下一段代码:————参考了这篇博客 “Failed to get convolution algorithm. This is probably because cuDNN failed to initialize”错误的解决办法.成功的解决了问题。意思是对GPU进行按需分配。主要原因是我的图像比较大,消耗GPU资源较多。但我的显卡(GTX1060TI)显存只有6GB,所以会出现这个错误。这个错误提示有很大的误导性,让人一直纠结CUDA和CuDNN的版本问题。

代码语言:javascript
复制
#先导入必要的库
import tensorflow as tf
#下面就是加入的部分
from tensorflow.compat.v1 import ConfigProto
from tensorflow.compat.v1 import InteractiveSession

config = ConfigProto()
config.gpu_options.allow_growth = True
session = InteractiveSession(config=config)

2、Eager模式下的基本运算

1)基本运算

代码语言:javascript
复制
x=[[2,]] #返回[[2]]
m=tf.matmul(x,x)  #两个X相乘  返回一个tensor  <tf.Tensor: shape=(1, 1), dtype=int32, numpy=array([[4]])>
m.numpy()   #将tensor转化为numpy数组 

#例如定义一个二维数组
a=tf.constant([[1,2],[3,4]])
a.numpy()   #array([[1, 2],[3, 4]])

c=tf.multiply(a,m)    
#  c返回值:<tf.Tensor: shape=(2, 2), dtype=int32, numpy=array([[ 4,  8],[12, 16]])>
# 再看一个例子
num=tf.convert_to_tensor(10)  #将numpy数字转化为tensor _——> <tf.Tensor: shape=(), dtype=int32, numpy=10>

2)当做python运算的时候,tensor自动的变成一个python对象去参与运算

代码语言:javascript
复制
for i in range(num.numpy()):
    i=tf.convert_to_tensor(i)
    if int(i%2)==0:  #当做int运算的时候,tensor自动的变成一个python对象
        print(str(i.numpy())+":even")
    else:
        print(str(i.numpy())+":odd")
#再例如
g=tf.convert_to_tensor(10)   #  ——>>>   <tf.Tensor: shape=(), dtype=int32, numpy=10>
float(g)   #——>  10.0

3)有关于变量的相关操作

记住下面的这几个API方法即可

代码语言:javascript
复制
v=tf.Variable(0.0)#创建一个变量

(v+1).numpy()  #对于这个变量,可以直接使用他的值 返回:1.0

v.assign(5)   #通过这个方法 直接改变变量的值   返回:<tf.Variable 'UnreadVariable' shape=() dtype=float32, numpy=5.0>

v.assign_add(1)  #增加变量的值  返回:<tf.Variable 'UnreadVariable' shape=() dtype=float32, numpy=6.0>

v.read_value()  #直接读取变量的值,读取出来的结果是一个tensor  返回:<tf.Tensor: shape=(), dtype=float32, numpy=6.0>

总结:可以看到在eager执行下,每个操作后的返回值是tf.Tensor,其包含具体值,不再像Graph模式下那样只是一个计算图节点的符号句柄。由于可以立即看到结果,这非常有助于程序debug。更进一步地,调用tf.Tensor.numpy()方法可以获得Tensor所对应的numpy数组。

3、如何自动求解微分

使用tape来记录我们的运算过程,进一步求解微分。不管对于变量还是常量的跟踪运算,都要求一种float的数据运算类型

1)对于变量情况:

代码语言:javascript
复制
w=tf.Variable([[1.0]])
with tf.GradientTape() as t:
    loss=w*w                    #来记录我们的运算,GradientTape()——>上下文管理器    自动的跟踪变量的运算,如果是个常量,那么就需要人工的去规定他,让这个磁带去跟踪常量的计算过程
grad=t.gradient(loss,w)   #t.gradient()这个方法:求解loss对w的微分 <tf.Tensor: shape=(1, 1), dtype=float32, numpy=array([[2.]], dtype=float32)>

2)对于常量来说:

代码语言:javascript
复制
v=tf.constant([[3.0]])
with tf.GradientTape() as t:
    t.watch(v)  #让t去跟踪常量的运算,因为v是一个常量
    loss=v*v  

dloss_dv=t.gradient(loss,v)
dloss_dv.numpy()   #——>>>  array([[6.]], dtype=float32)

3)对于多次微分:

注意:对于GradientTape()持有的资源,记录的这些运算,在调用了t.gradient() 这个方法之后会立即释放,在同一运算中,计算多个微分的话是不行的,如果要如此,需要在里面添加一个参数。具体如下:

代码语言:javascript
复制
v=tf.Variable([[3.0]])
with tf.GradientTape(persistent=True) as t:
    t.watch(v)  
    y=v*v  
    z=y*y
dy_dv=t.gradient(y,v)  #<tf.Tensor: shape=(1, 1), dtype=float32, numpy=array([[6.]], dtype=float32)>
dz_dv=t.gradient(z,v)  #<tf.Tensor: shape=(1, 1), dtype=float32, numpy=array([[108.]], dtype=float32)>

4、自定义训练

这次的自定义训练,参考数据集是手写数字mnist,模型也比较简单,主要是掌握具体的方法。

1)导入数据,创建Dataset

代码语言:javascript
复制
import tensorflow as tf
import matplotlib.pyplot as plt

(train_images,train_labels),_=tf.keras.datasets.mnist.load_data()  #下载数据
train_images=tf.expand_dims(train_images,-1)  #卷积神经网络图片输入的时候要求有通道数 扩张维度 等同于numpy的用法 np.expand_dims(img,-1)

#刚刚说过,自定义训练的时候,输入类型要求为float类型
train_images=tf.cast(train_images/255,tf.float32) #图片转为float类型
train_labels=tf.cast(train_labels,tf.int64)

#建立数据集
dataset=tf.data.Dataset.from_tensor_slices((train_images,train_labels))

dataset=dataset.shuffle(10000).batch(32)    #这里的dataset是一个可迭代的对象

2)创建模型

代码语言:javascript
复制
model=tf.keras.Sequential()
model.add(tf.keras.layers.Conv2D(16,(3,3),activation="relu",input_shape=(28,28,1)))#通道数为1的任意大小的图片都能够输入进来
model.add(tf.keras.layers.Conv2D(32,(3,3),activation="relu"))
model.add(tf.keras.layers.GlobalAveragePooling2D())
model.add(tf.keras.layers.Dense(10,activation="softmax"))

3)自定义训练

1、自定义训练的时候,我要先定义他的优化函数,在tf2里面,优化函数全部归到了optimizers里面。

代码语言:javascript
复制
optimizer=tf.keras.optimizers.Adam()

2、定义loss的函数,计算损失值,SparseCategoricalCrossentropy()是一个可调用的对象

代码语言:javascript
复制
loss_func=tf.keras.losses.SparseCategoricalCrossentropy()

————————————————————————————————— (可忽略)中间先来一个没有经过训练的情况,直接通过model调用:

代码语言:javascript
复制
features,labels=next(iter(dataset))  #iter(dataset) 将dataset迭代出来 next()取出下一个数据
predictions=model(features)   # TensorShape([32, 10])
tf.argmax(predictions,axis=1)
print(labels)

输出结果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

上面之所以不准,是因为没有经过训练

至于下面这两个代码,我查询了一下它的具体用法: features,labels=next(iter(dataset)) tf.argmax(predictions,axis=1) ///tf.argmax(predictions,axis=1) 这个函数的主要功能是返回最大值所在的坐标。主要用在分类的时候,如果只是简单的输出,只是对于每一类可能性的预测的输出,但是我要要的输出必须是确定的哪一类,所以需要确定里面的最大的值(也就是说最可能是哪一类)。 ///dataset是一个可迭对象,用iter对他进行迭代,然后用next方法取出列表里面的下一个数据 next(it,’-1’) 这个-1是默认值,从-1的下一个也就是0开始取,其实还是列表的第一个。

—————————————————————————————————

3、定义损失函数

代码语言:javascript
复制
#定义损失函数
def loss(model,x,y):
    y_=model(x)  #y_是预测的label   y是实际的label
    return loss_func(y,y_)

4、定义每一个批次的训练

代码语言:javascript
复制
#这是一个训练批次(batch)所需做的事情,怎么训练的?
def train_step(model,images,labels):
    #在这一步当中,要计算我们的损失值与可训练参数的梯度值,需要建立一个gradient tape
    with tf.GradientTape() as t:  #tf.GradientTape()跟踪运算——>loss_step的值对于可训练参数的变化,追踪损失函数
        loss_step=loss(model,images,labels)
    #计算loss值和可训练参数的梯度
    grads=t.gradient(loss_step,model.trainable_variables)  #model.trainable_variables()模型的可训练参数
    #怎么去优化呢?运用之前写好的optimizers,来改变我们的变量值,使得我们的梯度下降的最快
    optimizer.apply_gradients(zip(grads,model.trainable_variables))#通过这个优化器,对变量进行一定的修改

5、定义训练的函数

代码语言:javascript
复制
def train():
    for epoch in range(10): #对所有的数据训练10次
        #对dataset进行迭代
        for (batch,(images,label)) in enumerate(dataset):  #batch就是那个enumerate,给它加上了序号0/1/2/3...
            train_step(model,images,labels)   #进行一步训练>>>这里的images,labels就是从上一个语句中迭代出来的
        print("Epoch{}is finshed".format(epoch))

6、开始训练

代码语言:javascript
复制
train() 

—————————————— 总结:主要是了解Eager模式的下面的一些操作,最重要的是学会如何的自定义训练。分为哪几步? 定义优化器 定义损失函数 定义每一个批次的训练 定义训练函数 开始训练

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-05-13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Eager模式简介以及运用
  • 1、什么是Eager模式?
  • 2、Eager模式下的基本运算
    • 1)基本运算
      • 2)当做python运算的时候,tensor自动的变成一个python对象去参与运算
        • 3)有关于变量的相关操作
        • 3、如何自动求解微分
          • 1)对于变量情况:
            • 2)对于常量来说:
              • 3)对于多次微分:
              • 4、自定义训练
                • 1)导入数据,创建Dataset
                  • 2)创建模型
                    • 3)自定义训练
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档