Tensorflow2.0中function(是1.0版本的Graph的推荐替代)的相关知识介绍

这篇具有很好参考价值的文章主要介绍了Tensorflow2.0中function(是1.0版本的Graph的推荐替代)的相关知识介绍。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在 Tensorflow无人车使用移动端的SSD(单发多框检测)来识别物体及Graph的认识 中我们对Graph这个计算图有了一定的了解,也知道了它具备的优点:性能做了提升,可以并行处理以及由于它是一种数据结构,可以在非Python环境中进行交互。

我们先来看下自己的tensorflow的版本: 

print(tf.__version__) # 2.11.0 

目前基本上都是2.0以上,不过这个Session的用法在tensorflow2.0版本之后就没有了,所以大家在上一篇文章看到的是我使用的兼容1.0版本的用法:tf.compat.v1.Session(graph=g1)
如果是直接去调用的话:tf.compat.v1.Session(graph=g1) 就会报下面这样的错误:

AttributeError: module 'tensorflow' has no attribute 'Session'

于是到了2.0版本之后,我们使用function来代替Graph! 

1、tf.function声明

 我们具体来看下,2.0及以上版本中的tf.function是如何使用的。

import tensorflow as tf

# 常规函数
def f(x, w, b):
    y = tf.matmul(x, w) # 矩阵乘法就是dot点积运算
    return y + b

tf_f = tf.function(f)

print(type(f),type(tf_f))
# <class 'function'>
# <class 'tensorflow.python.eager.polymorphic_function.polymorphic_function.Function'>

 可以看到这里的tf.function和平时定义的def的这个函数类型是不一样,def的类型就是function,而tf.function(函数名)得到的类型是
tensorflow.python.eager.polymorphic_function.polymorphic_function.Function

eager:渴望的,急切的,这里就是一种即时模型的意思,polymorphic:意思来看是,多形态的,多态的。 

函数定义好了之后,我们来看下是如何调用并计算的

c1 = tf.constant([[1.0, 2.0]])
c2 = tf.constant([[2.0], [3.0]])
c3 = tf.constant(4.0)

f_value = f(c1, c2, c3).numpy()
tf_value = tf_f(c1, c2, c3).numpy()
print(f_value,tf_value)#[[12.]] [[12.]]

得到的结果是一样的,那我们引入这个tf.function的作用是什么呢?接着往下看

2、@tf.function装饰器

上面我们可以看到 tf.function 的类型,虽然也是函数,但跟常规函数还是有很大区别,因为我们的目的是能够代替Graph,而使用计算图的目的又是为了性能的提升,所以应该知道这个函数所要表达的意思了吧,在这里我们可以使用 @tf.function 装饰器,就可以让这种即时执行模式的控制流转换成计算图的方式了。

其中matmulMatrixMultiple的缩写,矩阵乘法的意思,也就是在numpy中的dot点积运算的用法(行乘以列的和)
实际上,这个tf.function可能封装多个tf.graph,所以这两种不同的函数表达,在性能和部署上存在很大的不同。

import tensorflow as tf

def inner_function(x, w, b):
    x = tf.matmul(x, w)
    return x + b

# 使用装饰器来定义函数
@tf.function
def outer_function(x):
    w = tf.constant([[2.0], [3.0]])
    b = tf.constant(4.0)
    return inner_function(x, w, b)

# 创建一个Graph计算图,里面包含inner_function和outer_function
r1 = outer_function(tf.constant([[1.0, 2.0]])).numpy()
r2 = outer_function(tf.constant([[1.0, 2.0],[3.0, 4.0],[5.0, 6.0]])).numpy()
print(r1)
print(r2)

'''
[[12.]]

[[12.]
 [22.]
 [32.]]
'''

这里使用了一个@tf.function装饰器来声明这个函数为多态函数,我们来打印看下它的具体特征:

print(outer_function.pretty_printed_concrete_signatures())
'''
outer_function(x)
  Args:
    x: float32 Tensor, shape=(1, 2)
  Returns:
    float32 Tensor, shape=(1, 1)

outer_function(x)
  Args:
    x: float32 Tensor, shape=(3, 2)
  Returns:
    float32 Tensor, shape=(3, 1)
'''

我使用了两种形状的输入,这里也对应出现两种形式的计算图。这种多态的作用是可以用来提升性能,因为可以判断输入的类型(以及形状),如果是一样的形状,同类型的就不需要新建计算图,我们接着来看下

r3 = outer_function(tf.constant([[11.0, 22.0],[3.0, 4.0],[5.0, 6.0]])).numpy()
print(outer_function.pretty_printed_concrete_signatures())

'''
outer_function(x)
  Args:
    x: float32 Tensor, shape=(1, 2)
  Returns:
    float32 Tensor, shape=(1, 1)

outer_function(x)
  Args:
    x: float32 Tensor, shape=(3, 2)
  Returns:
    float32 Tensor, shape=(3, 1)
'''

可以看到结果是一样的,对于这样的输入,因为r3跟r2的类型形状是一样的,所以r3可以使用r2的,那么从另一角度可以理解为缓存,当数据类型或形状不一致的时候才会创建新的计算图。

r4 = outer_function([[11.0, 22.0],[3.0, 4.0],[5.0, 6.0]]).numpy()
print(outer_function.pretty_printed_concrete_signatures())

'''
outer_function(x)
  Args:
    x: float32 Tensor, shape=(1, 2)
  Returns:
    float32 Tensor, shape=(1, 1)

outer_function(x)
  Args:
    x: float32 Tensor, shape=(3, 2)
  Returns:
    float32 Tensor, shape=(3, 1)

outer_function(x=[[11.0, 22.0], [3.0, 4.0], [5.0, 6.0]])
  Returns:
    float32 Tensor, shape=(3, 1)
'''

这里的r4虽然输出是跟r3一样,不过这里的输入类型不一致,所以还是会新建一个。

3、tf.autograph

现在我们又回到最开始的tf.function,它的本质其实是对原函数做了转换,函数体做了新的变化处理。依然是上面的示例,我们查看下它的本质:

import tensorflow as tf

# 常规函数
def f(x, w, b):
    y = tf.matmul(x, w) # 矩阵乘法就是dot点积运算
    return y + b

tf_f = tf.function(f)
w = tf.constant([[2.0], [3.0]])
b = tf.constant(4.0)
print(tf_f(tf.constant([[1.0, 2.0]]),w,b).numpy()) # [[12.]]
print(tf.autograph.to_code(f))
'''
def tf__f(x, w, b):
    with ag__.FunctionScope('f', 'fscope', ag__.ConversionOptions(recursive=True, user_requested=True, optional_features=(), internal_convert_user_code=True)) as fscope:
        do_return = False
        retval_ = ag__.UndefinedReturnValue()
        y = ag__.converted_call(ag__.ld(tf).matmul, (ag__.ld(x), ag__.ld(w)), None, fscope)
        try:
            do_return = True
            retval_ = (ag__.ld(y) + ag__.ld(b))
        except:
            do_return = False
            raise
        return fscope.ret(retval_, do_return)
'''

可以看到这里是将原函数 转成 tf__f 函数,其函数体是做了另外的处理,里面结构也是很类似的。我们打印 tf__f 这个graph计算图的详情看下:

print(tf_f.get_concrete_function(tf.constant([[1.0, 2.0]]),w,b).graph.as_graph_def())

'''
node {
  name: "x"
  op: "Placeholder"
  attr {
    key: "_user_specified_name"
    value {
      s: "x"
    }
  }
  attr {
    key: "dtype"
    value {
      type: DT_FLOAT
    }
  }
  attr {
    key: "shape"
    value {
      shape {
        dim {
          size: 1
        }
        dim {
          size: 2
        }
      }
    }
  }
}
node {
  name: "w"
  op: "Placeholder"
  attr {
    key: "_user_specified_name"
    value {
      s: "w"
    }
  }
  attr {
    key: "dtype"
    value {
      type: DT_FLOAT
    }
  }
  attr {
    key: "shape"
    value {
      shape {
        dim {
          size: 2
        }
        dim {
          size: 1
        }
      }
    }
  }
}
node {
  name: "b"
  op: "Placeholder"
  attr {
    key: "_user_specified_name"
    value {
      s: "b"
    }
  }
  attr {
    key: "dtype"
    value {
      type: DT_FLOAT
    }
  }
  attr {
    key: "shape"
    value {
      shape {
      }
    }
  }
}
node {
  name: "MatMul"
  op: "MatMul"
  input: "x"
  input: "w"
  attr {
    key: "T"
    value {
      type: DT_FLOAT
    }
  }
  attr {
    key: "transpose_a"
    value {
      b: false
    }
  }
  attr {
    key: "transpose_b"
    value {
      b: false
    }
  }
}
node {
  name: "add"
  op: "AddV2"
  input: "MatMul"
  input: "b"
  attr {
    key: "T"
    value {
      type: DT_FLOAT
    }
  }
}
node {
  name: "Identity"
  op: "Identity"
  input: "add"
  attr {
    key: "T"
    value {
      type: DT_FLOAT
    }
  }
}
versions {
  producer: 1286
}
'''

可以看到每个节点里面是名称、属性、类型、操作等详细的说明,这也印证了最开始说的这个Graph计算图是一种数据结构,数据类型是
<class 'tensorflow.core.framework.graph_pb2.GraphDef'>

4、追踪

graph里的Tracing也是其一个特性,这里的print不在追踪范围内,所以虽然调用了三次,结果只输出一次!

import tensorflow as tf
#tf.config.run_functions_eagerly(False)
@tf.function
def mse(y_true, y_pred):
    print("计算均方误差")
    tf.print("均方误差")
    sq_diff = tf.pow(y_true - y_pred, 2)
    return tf.reduce_mean(sq_diff)
  
tf.config.run_functions_eagerly(False)

y_true = tf.random.uniform([5], maxval=10, dtype=tf.int32)
y_pred = tf.random.uniform([5], maxval=10, dtype=tf.int32)

print(y_true,y_pred)
mse_r = mse(y_true, y_pred)
mse_r = mse(y_true, y_pred)
mse_r = mse(y_true, y_pred)

print(mse_r.numpy())
'''
tf.Tensor([8 0 6 3 9], shape=(5,), dtype=int32) tf.Tensor([9 5 9 3 9], shape=(5,), dtype=int32)
计算均方误差
均方误差
均方误差
均方误差
7
'''

其中的tf.print是可以追踪的,所以每次的调用都会输出。

5、非严格执行

tf.graph计算图只关心需要的操作,其余的不会关心,就算是错误的情况也不处理。

def t(x):
    tf.gather(x, [3])
    return x

try:
    print(t(tf.constant([0.0])))
except tf.errors.InvalidArgumentError as e:
    print(f'{type(e).__name__}: {e}')

gather用法: 

help(tf.gather)
gather_v2(params, indices, validate_indices=None, axis=None, batch_dims=0, name=None)


params = tf.constant(['p0', 'p1', 'p2', 'p3', 'p4', 'p5'])
params[3].numpy() # b'p3'
indices = [2, 0, 2, 5]
tf.gather(params, indices).numpy() #array([b'p2', b'p0', b'p2', b'p5'], dtype=object)

这里的tf.gather调用,我们可以很明显知道,在输入是[0]的情况,[3]索引的数据是不存在的,所以会报错:

InvalidArgumentError: {{function_node __wrapped__GatherV2_device_/job:localhost/replica:0/task:0/device:CPU:0}} indices[0] = 3 is not in [0, 1) [Op:GatherV2]

而当我们使用@tf.function装饰器来装饰这个函数的时候,会发现即便有错误也不会执行。 

@tf.function
def t(x):
    tf.gather(x, [3])
    return x

print(t(tf.constant([0.0])))#tf.Tensor([0.], shape=(1,), dtype=float32)

这也再次说明了计算图只关心流程图,里面的具体计算不会去验证。其中tf.gather的用法就是在指定维度抽取数据,这个用法在很多情况使用起来特别有用,我们再来看一个示例:文章来源地址https://www.toymoban.com/news/detail-610224.html

import tensorflow as tf
a = tf.range(8)
a = tf.reshape(a, [4,2])
print(a)
print(tf.gather(a, [3,1,0], axis=0))
'''
tf.Tensor(
[[0 1]
 [2 3]
 [4 5]
 [6 7]], shape=(4, 2), dtype=int32)
tf.Tensor(
[[6 7]
 [2 3]
 [0 1]], shape=(3, 2), dtype=int32)
'''

到了这里,关于Tensorflow2.0中function(是1.0版本的Graph的推荐替代)的相关知识介绍的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Tensorflow2.0笔记 - 创建tensor

            tensor创建可以基于numpy,list或者tensorflow本身的API。         笔记直接上代码:   notebook运行结果截图:  

    2024年01月21日
    浏览(31)
  • TensorFlow2.0教程1-Eager

    2023年11月06日
    浏览(30)
  • Tensorflow2.0笔记 - 修改形状和维度

            本次笔记主要使用reshape,transpose,expand_dim,和squeeze对tensor的形状和维度进行操作。         运行结果:  

    2024年01月16日
    浏览(27)
  • Tensorflow2——Eager模式简介以及运用

    TensorFlow的eager执行模式是一个重要的编程环境,它能立即评估运算,而无须构建图:运算会实时返回值,而不是构建一个计算图后再运行。这使得使用TensorFlow和调试模型更简单,并且可以减少很多样板代码。 eager执行模式对研究和实验来说是一个灵活的机器学习平台,有下列

    2024年02月11日
    浏览(42)
  • Tensorflow2.0笔记 - Broadcasting和Tile

            关于broadcasting的介绍,参考这篇文章。         https://blog.csdn.net/python_LC_nohtyp/article/details/104097417         运行结果

    2024年01月20日
    浏览(25)
  • 深入浅出TensorFlow2函数——tf.exp

    分类目录:《深入浅出TensorFlow2函数》总目录 相关文章: · 深入浅出TensorFlow2函数——tf.exp · 深入浅出TensorFlow2函数——tf.math.exp · 深入浅出Pytorch函数——torch.exp · 深入浅出PaddlePaddle函数——paddle.exp 按元素计算 x x x 的指数 y = e x y=e^x y = e x 。 语法 参数 x :[ tf.Tensor ] 必须

    2024年02月12日
    浏览(23)
  • 深入浅出TensorFlow2函数——tf.rank

    分类目录:《深入浅出TensorFlow2函数》总目录 语法 参数 input : tf.Tensor 或 tf.SparseTensor name :[可选] 操作的名称 返回值 张量 input 的维度,是一个 int32 类型的张量 实例 输入: 输出: 函数实现

    2024年02月12日
    浏览(32)
  • 深入浅出TensorFlow2函数——tf.reshape

    分类目录:《深入浅出TensorFlow2函数》总目录 语法 参数 返回值 返回一个新的形状为 shape 的 tf.Tensor 且具有与 tensor 以同样的顺序和相同的值。 实例 输入: 如果 shape 的一个参数为是 -1 ,则计算该维度的大小,使总大小保持不变。特别是,若 shape 为 [-1] ,则将 tensor 展平为一

    2024年02月11日
    浏览(48)
  • 深入浅出TensorFlow2函数——tf.Tensor

    分类目录:《深入浅出TensorFlow2函数》总目录 相关文章: · 深入浅出TensorFlow2函数——tf.Tensor · 深入浅出Pytorch函数——torch.Tensor · 深入浅出PaddlePaddle函数——paddle.Tensor 一个 tf.Tensor 表示一个多维数组。在编写TensorFlow程序时,被操作和传递的主要对象就是 tf.Tensor 。 tf.Tens

    2024年02月17日
    浏览(29)
  • Tensorflow2.0笔记 - tensor的合并和分割

            主要记录concat,stack,unstack和split相关操作的作用         运行结果:

    2024年01月23日
    浏览(24)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包