前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >开刷Cs20之Tensorflow第二弹

开刷Cs20之Tensorflow第二弹

作者头像
公众号guangcity
发布2019-09-20 15:30:28
1.5K0
发布2019-09-20 15:30:28
举报
文章被收录于专栏:光城(guangcity)光城(guangcity)

开刷Cs20之Tensorflow第二弹

学习内容

Basic operations, constants, variables

Control dependencies

Data pipeline

TensorBoard

本节学习来源斯坦福大学cs20课程,有关自学与组队学习笔记,将会放于github仓库与本公众号发布,欢迎大家star与转发,收藏!

cs20是一门对于深度学习研究者学习Tensorflow的课程,今天学习了二节,非常有收获,并且陆续将内容写入jupytebook notebook中,有关这个源代码及仓库地址,大家可以点击阅读原文或者直接复制下面链接!

直通车: https://github.com/Light-City/Translating_documents

目录

第一个TensorFlow程序TensorBoard可视化如何运行可视化的图?可视化计算图Constants, Sequences, Variables, Ops常量特殊值填充张量常量作为序列随机生成的变量算法操作神奇的除法Tensorflow数据类型尽可能使用TF DType常数有什么问题?变量创建变量tf.constant 与 tf.Variable区别初始化变量Eval()tf.Variable.assign()assign_add() and assign_sub()每个会话都维护自己的变量副本控制依赖关系Placeholder快速提醒Placeholders为什么占位符?占位符使用?使用字典向占位符补充值Variable和placeholder有什么区别呢?Placeholders 是有效操作如果想要提供多个数据点怎么办?is_feedable给TF操作喂数据对测试非常有帮助,输入虚拟值以测试大图的部分什么是懒加载?

第一个TensorFlow程序

import tensorflow as tf
a = tf.constant(2)
b = tf.constant(3)
x = tf.add(a, b)
with tf.Session() as sess:
    print(sess.run(x))

输出:

5

上述运行会出现警告:Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA

# 如果你有一个GPU,你不应该关心AVX的支持,因为大多数昂贵的操作将被分派到一个GPU设备上(除非明确地设置)。
# 在这种情况下,您可以简单地忽略此警告: 

import os 
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
a = tf.constant(2)
b = tf.constant(3)
x = tf.add(a, b)
with tf.Session() as sess:
    print(sess.run(x))

输出:

5

TensorBoard可视化

定义计算图

a=tf.constant(2)
b=tf.constant(3)
x=tf.add(a,b)

在图形定义之后和运行会话之前创建摘要编写器

writer=tf.summary.FileWriter('./graphs',tf.get_default_graph())
with tf.Session() as sess:
    print(sess.run(x))
writer.close

输出:

5

输出:

<bound method FileWriter.close of <tensorflow.python.summary.writer.writer.FileWriter object at 0x7f0bbeb5d518>>

如何运行可视化的图?

1.如果您使用jupyter notebook进行Tensorboard代码编写,那么可以安装一个jupyer-tensorboard库,关于这个库的更多内容,请查阅:https://github.com/lspvic/jupyter_tensorboard 安装这个库:pip(3) install jupyter-tensorboard

重启Jupyter,勾选生成的event文件夹,会出现tensorboard,然后即可打开tensorboard,如果弹出浏览器阻止,开启允许即可!

当然你也可以通过jupyter直接运行后,通过命令端运行: tensorboard --logdir=./graphs/ --port 6066

2.如果您使用pycharm,那么就直接运行代码后,然后在命令端运行上述命令即可!

可视化计算图

import tensorflow as tf
a = tf.constant(2)
b = tf.constant(3)
x = tf.add(a, b)
writer = tf.summary.FileWriter('./graphs', tf.get_default_graph())
writer.close()

上述运行后,变量名是默认给的,const,const1,那如何修改呢?

直接给定变量一个name属性即可!

a = tf.constant(2, name='a')
b = tf.constant(3, name='b')
x = tf.add(a, b, name='add')
writer = tf.summary.FileWriter('./graphs', tf.get_default_graph())
with tf.Session() as sess:
    print(sess.run(x)) # >> 5

输出:

5

Constants, Sequences, Variables, Ops

常量

原型:

tf.constant(
    value,
    dtype=None,
    shape=None,
    name='Const',
    verify_shape=False
)
import tensorflow as tf
a = tf.constant([2,2],name='a')
b = tf.constant([[0,1],[2,3]],name='b')

类似于Numpy的广播机制

x = tf.multiply(a, b, name='mul')
with tf.Session() as sess:
    print(sess.run(x))

输出:

[[0 2]
 [4 6]]

特殊值填充张量

1.原型:

tf.zeros(shape, dtype=tf.float32, name=None)

创建一个shape的的张量,并且为每个元素设置为0

类似于numpy.zeros

tf.zeros([2,3],tf.int32)

输出:

<tf.Tensor 'zeros:0' shape=(2, 3) dtype=int32>

2.原型:

tf.zeros_like(input_tensor, dtype=None, name=None, optimize=True)

创建一个形状和类型的张量(除非指定了type)作为input_tensor,但所有元素都是零。

类似于numpy.zeros_like

如果输入张量是[[0, 1], [2, 3], [4, 5]],那么将会创建同shape,全为0的张量。即:[[0, 0], [0, 0], [0, 0]]

3.原型:

tf.ones(shape, dtype=tf.float32, name=None)
tf.ones_like(input_tensor, dtype=None, name=None, optimize=True)

分别类似于:numpy.onesnumpy.ones_like

4.原型:

tf.fill(dims, value, name=None) 

创建一个用标量值填充的张量

类似于:numpy.full

tf.fill([2, 3], 8) 

输出:

<tf.Tensor 'Fill:0' shape=(2, 3) dtype=int32>

常量作为序列

1.原型:

tf.lin_space(start, stop, num, name=None)
tf.lin_space(10.0, 13.0, 4) # [10. 11. 12. 13.]

输出:

<tf.Tensor 'LinSpace:0' shape=(4,) dtype=float32>

2.原型:

tf.range(start, limit=None, delta=1, dtype=None, name='range')

注意:这个不与numpy的序列相同,Tensor对象是不可迭代的,也就是不能有如下操作:

for _ in tf.range(4): # typeError
tf.range(3,18,3)# [3 6 9 12 15]

输出:

<tf.Tensor 'range:0' shape=(5,) dtype=int32>
tf.range(5) # [0 1 2 3 4]

输出:

<tf.Tensor 'range_1:0' shape=(5,) dtype=int32>

随机生成的变量

tf.random_normal
tf.truncated_normal
tf.random_uniform
tf.random_shuffle
tf.random_crop
tf.multinomial
tf.random_gamma

设置随机种子:

tf.set_random_seed(seed)

算法操作

tf.abs
tf.sqrt

等等

类似于numpy

神奇的除法

a = tf.constant([2, 2], name='a')
b = tf.constant([[0, 1], [2, 3]], name='b')
with tf.Session() as sess:
    print(sess.run(tf.div(b, a)))             
    print(sess.run(tf.divide(b, a)))         
    print(sess.run(tf.truediv(b, a)))         
    print(sess.run(tf.floordiv(b, a)))        
#     print(sess.run(tf.realdiv(b, a)))  # Error: only works for real values      
    print(sess.run(tf.truncatediv(b, a)))    
    print(sess.run(tf.floor_div(b, a)))      
[[0 0]
 [1 1]]
[[0.  0.5]
 [1.  1.5]]
[[0.  0.5]
 [1.  1.5]]
[[0 0]
 [1 1]]
[[0 0]
 [1 1]]
[[0 0]
 [1 1]]

Tensorflow数据类型

TensorFlow 采用 Python 原生类型: 布尔, 数值(int, float), 字符串

单个值将转换为0-d张量(或标量),值列表将转换为1-d张量(向量),值列表将转换为2-d 张量(矩阵)等。

t_0 = 19           # scalars are treated like 0-d 
tf.zeros_like(t_0) # 0               
tf.ones_like(t_0)  # 1            

输出:

<tf.Tensor 'ones_like:0' shape=() dtype=int32>
t_1 = [b"apple", b"peach", b"grape"]  # 1-d arrays are treated like 1-d tensors
tf.zeros_like(t_1) # [b'' b'' b'']
tf.ones_like(t_1)   # TypeError: Expected string, got 1 of 
t_2 = [[True, False, False],
  [False, False, True],
  [False, True, False]]     # 2-d arrays are treated like 2-d tensors
tf.zeros_like(t_2)      # 3x3 tensor, all elements are False
tf.ones_like(t_2)       # 3x3 tensor, all elements are True

输出:

<tf.Tensor 'ones_like_2:0' shape=(3, 3) dtype=bool>

Numpy与TensorFlow类型联系

1.部分类型一致 tf.int32==np.int32 2.可以传递numpy类型到TensorFlow操作

tf.ones([2,2],np.float32) # [[1.0 1.0], [1.0 1.0]]

3.对于tf.Session.run(fetches),如果传递的fetches是一个Tensor,输出将是一个 NumPy n维数组.

# 上述联系中第三个例子
import numpy as np
sess = tf.Session()
a = tf.zeros([2, 3], np.int32)
print(type(a))  
a = sess.run(a) #<<<< Avoid doing this. Use a_out = sess.run(a)
print(type(a))  
<class 'tensorflow.python.framework.ops.Tensor'>
<class 'numpy.ndarray'>

尽可能使用TF DType

1.Python原生类型:TensorFlow必须推断Python类型

使用Python类型来指定TensorFlow对象既快速又简单,并且对于原型设计思想非常有用。然而,这样做有一个重要的缺陷。 Python类型缺乏显式声明数据类型的能力,但TensorFlow的数据类型更具体。例如,所有整数都是相同的类型,但TensorFlow具有8位,16位,32位和64位整数。因此,如果您使用Python类型,TensorFlow必须推断您的意思是哪种数据类型。

2.NumPy阵列:NumPy不兼容GPU

将数据传递给TensorFlow时,可以将数据转换为适当的类型,但某些数据类型仍然可能难以正确声明,例如复数。因此,建议将手工定义的Tensor对象创建为NumPy数组。

常数有什么问题?

1.不是不变的

2.常量存储在图形定义中

# 打印出图表def
my_const = tf.constant([1.0, 2.0], name="my_const")
with tf.Session() as sess:
    print(sess.graph.as_graph_def())

图形定义存储在protobuf中(协议缓冲区,Google的语言中立,平台中立,可扩展的机制,用于序列化结构化数据 - 想想XML,但更小,更快,更简单。)

上述问题就使得当常量很大时加载图形很昂贵,仅对原始类型使用常量。

使用变量或读取器来获取需要更多内存的更多数据。

变量

创建变量

1.使用tf.Variable创建变量

s = tf.Variable(2,name='scalar')
m = tf.Variable([[0, 1], [2, 3]], name="matrix") 
W = tf.Variable(tf.zeros([784,10]))

2.使用tf.get_variable创建变量

s = tf.get_variable('scalar',initializer=tf.constant(2))
m = tf.get_variable('matrix',initializer=tf.constant([[0,1],[2,3]]))
W = tf.get_variable('big_matrix',shape=(784,10),initializer=tf.zeros_initializer())

tf.constant 与 tf.Variable区别

tf.constant 是一个操作

tf.Variable 是一个包含多个操作的类

tf.Variable holds several ops:

x = tf.Variable(...) 
x.initializer # init op
x.value() # read op
x.assign(...) # write op
x.assign_add(...) # and more
W = tf.get_variable("big_matrix", shape=(784, 10), initializer=tf.zeros_initializer())
with tf.Session() as sess:
    print(sess.run(W))   
# FailedPreconditionError: Attempting to use uninitialized value Variable

初始化变量

因此你必须初始化你变量,初始化是一个操作,你需要在一个session的上下文中去执行!

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

初始化变量的三种形式:

1.最简单的方式是一次初始化所有变量

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

2.只初始化一个变量子集

with tf.Session() as sess:
    sess.run(tf.variables_initializer([a, b]))

3.初始化单个变量

W = tf.Variable(tf.zeros([784,10]))
with tf.Session() as sess:
    sess.run(W.initializer)

Eval()

Eval()类似于sess.run(W)

# W is a random 700 x 100 variable object
W = tf.Variable(tf.truncated_normal([700, 10]))
with tf.Session() as sess:
    sess.run(W.initializer)
    print(W)
    print(sess.run(W))

输出:

<tf.Variable 'Variable_6:0' shape=(700, 10) dtype=float32_ref>
[[-0.5226208  -0.97566205 -0.42451558 ... -0.4133208  -0.50616413
  -0.832415  ]
 [-1.2517142  -1.5990031  -1.2126933  ... -0.60406566 -1.0643008
   1.8198049 ]
 [-0.12700588  1.453523   -0.32724586 ...  0.8391837  -0.21167135
   0.5361979 ]
 ...
 [ 1.1430322   0.30788425 -0.2411158  ... -0.1196197  -0.11606342
  -0.7137539 ]
 [ 1.7774947  -0.5762313  -1.0951449  ... -0.8084044  -0.16739914
   0.5140143 ]
 [-0.4849846   0.04498202 -0.06566923 ... -0.53475994 -0.5896073
  -0.8156376 ]]
# W is a random 700 x 100 variable object
W = tf.Variable(tf.truncated_normal([700, 10]))
with tf.Session() as sess:
    sess.run(W.initializer)
    print(W)
    print(W.eval())

输出:

<tf.Variable 'Variable_7:0' shape=(700, 10) dtype=float32_ref>
[[-0.8490288   0.16360298 -1.2199837  ...  0.68452436  0.41389784
   1.0369685 ]
 [ 0.83160686  0.23120853 -0.14505246 ... -0.68007827 -0.02268635
  -0.6440017 ]
 [-0.72545207  0.10048836  0.5861655  ... -0.50299203 -1.2190983
  -1.1676756 ]
 ...
 [ 0.12471761 -1.5892761  -0.06928917 ... -1.1436646  -1.3074825
   0.23211905]
 [-1.1235662   1.0567249  -0.40683436 ...  0.55470574  0.64190876
   1.1899426 ]
 [-0.02476467  0.05603853 -1.3414879  ...  1.119798   -0.5048172
  -0.47068778]]

tf.Variable.assign()

W = tf.Variable(10)
W.assign(100)
with tf.Session() as sess:
    sess.run(W.initializer)
    print(W.eval())
10

上述结果为什么是?

因为W.assign(100)创建了一个分配操作,这个操作需要在session中执行才会生效。

W = tf.Variable(10)
assign_op = W.assign(100)
with tf.Session() as sess:
    sess.run(W.initializer)
    sess.run(assign_op)
    print(W.eval())
100

您不需要初始化变量,因为assign_op会为您执行此操作。实际上,初始化op是赋值操作,它将变量的初始值赋给变量本身。

# create a variable whose original value is 2
my_var = tf.Variable(2, name="my_var") 

# assign a * 2 to a and call that op a_times_two
my_var_times_two = my_var.assign(2 * my_var)

with tf.Session() as sess:
    sess.run(my_var.initializer)
    print(my_var.eval())       # 2
    sess.run(my_var_times_two) # 4
    print(my_var.eval())
    sess.run(my_var_times_two) # 8
    print(my_var.eval())
    sess.run(my_var_times_two) # 16
    print(my_var.eval())

输出:

2
4
8
16

assign_add() and assign_sub()

my_var = tf.Variable(10)
with tf.Session() as sess:
    sess.run(my_var.initializer)
    # 增加了10
    sess.run(my_var.assign_add(10)) # 20
    print(my_var.eval())
    # 减少了2
    sess.run(my_var.assign_sub(2))  # 18
    print(my_var.eval())

输出:

20
18

assign_add()和assign_sub()无法为您初始化变量my_var,因为这些操作需要my_var的原始值

每个会话都维护自己的变量副本

可以看到在两个session内,同一个Variable对象的当前值互不干扰:

W = tf.Variable(10)

sess1 = tf.Session()
sess2 = tf.Session()

sess1.run(W.initializer)
sess2.run(W.initializer)

print(sess1.run(W.assign_add(10))) # >> 20
print(sess2.run(W.assign_sub(2))) # >> 8

print(sess1.run(W.assign_add(100))) # >> 120
print(sess2.run(W.assign_sub(50))) # >> -42

sess1.close()
sess2.close()

输出:

20
8
120
-42

控制依赖关系

tf.Graph.control_dependencies(control_inputs)
# defines which ops should be run first
# your graph g have 5 ops: a, b, c, d, e
g = tf.get_default_graph()
with g.control_dependencies([a, b, c]):
    # 'd' and 'e' will only run after 'a', 'b', and 'c' have executed.
    d = ...
    e = …

Placeholder

快速提醒

TF程序通常有两个阶段:

1.组装图表

2.使用会话在图中执行操作。

Placeholders

首先组装图形,而不知道计算所需的值

比喻:

在不知道x或y的值的情况下定义函数f(x,y)= 2 * x + y

x,y是实际值的占位符。

为什么占位符?

We, or our clients, can later supply their own data when they need to execute the computation.

我们或我们的客户可以在需要执行计算时提供自己的数据。

占位符使用?

占位符原型:

tf.placeholder(dtype, shape=None, name=None)
# 创建一个3个元素,类型为tf.float32的placeholder
a = tf.placeholder(tf.float32, shape=[3])

b = tf.constant([5, 5, 5], tf.float32)

# 像使用常量或变量一样使用占位符
c = a + b  # short for tf.add(a, b)

with tf.Session() as sess:
    print(sess.run(c))   # >> InvalidArgumentError: a doesn’t an actual value

使用字典向占位符补充值

# 创建一个3个元素,类型为tf.float32的placeholder
a = tf.placeholder(tf.float32, shape=[3])

b = tf.constant([5, 5, 5], tf.float32)

# 像使用常量或变量一样使用占位符
c = a + b  # short for tf.add(a, b)

with tf.Session() as sess:
    print(sess.run(c, feed_dict={a: [1, 2, 3]}))     # 张量a是key,而不是字符串'a'

# >> [6, 7, 8]

输出:

[6. 7. 8.]

怪癖:

shape = None表示任何形状的张量都将被接受为占位符的值。

shape = None很容易构造图形,但是用于调试的噩梦

shape = None也会破坏所有后续形状推断,这使得许多操作不起作用,因为它们期望某些等级。

Variable和placeholder有什么区别呢?

Variable是变量,可以在graph里不断的被修改,而placeholder不行。

Variable通常是需要学习的权重,而placeholder通常是训练数据。

Variable使用initializer初始化,而placeholder在run的时候通过fee_dict赋值。

换言之,Variable类比于函数内定义的变量,而placeholder相当于函数方法签名上的形参。

Placeholders 是有效操作

如果想要提供多个数据点怎么办?

# 比如下面的操作,通过一个循环,反复feed不同的数据:
with tf.Session() as sess:
    for a_value in list_of_values_for_a:
    print(sess.run(c, {a: a_value}))

这种做法不仅正确,而且很常见,机器学习算法中,定义一个训练op,然后不断feed不同的训练数据进行训练。虽然place_holder一直在传入,但里面的参数通过Variable一直在迭代。

is_feedable

事实上,feed_dict不仅可以feed的是placeholder,还可以feed任何可feed的tensor! placeholder只是一种方法表示必须被feed。

# 我们可以通过is_feedable判断是否可以被feed:
tf.Graph.is_feedable(tensor)

给TF操作喂数据

# create operations, tensors, etc (using the default graph)
a = tf.add(2, 5)
b = tf.multiply(a, 3)

with tf.Session() as sess:
    # compute the value of b given a is 15
    sess.run(b, feed_dict={a: 15}) # >> 45

对测试非常有帮助,输入虚拟值以测试大图的部分

当您有一个大图并且只想测试某些部分时,您可以提供虚拟值,因此TensorFlow不会浪费时间进行不必要的计算。

什么是懒加载?

懒创建/初始化对象直到它需要

1.正常加载例子

x = tf.Variable(10, name='x')
y = tf.Variable(20, name='y')
z = tf.add(x, y) # create the node before executing the graph

writer = tf.summary.FileWriter('./graphs/normal_loading', tf.get_default_graph())
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for _ in range(10):
        sess.run(z)
writer.close()
tf.get_default_graph().as_graph_def() 

输出:

...
node {
  name: "Add"
  op: "Add"
  input: "x/read"
  input: "y/read"
  attr {
    key: "T"
    value {
      type: DT_INT32
    }
  }
}
...

2.懒加载例子

x = tf.Variable(10, name='x')
y = tf.Variable(20, name='y')

writer = tf.summary.FileWriter('./graphs/normal_loading', tf.get_default_graph())
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for _ in range(10):
        sess.run(tf.add(x, y)) # someone decides to be clever to save one line of code
writer.close()
tf.get_default_graph().as_graph_def() 

输出:

node {
  name: "Add_1"
  op: "Add"
  input: "x_1/read"
  input: "y_1/read"
  attr {
    key: "T"
    value {
      type: DT_INT32
    }
  }
}
...
...
node {
  name: "Add_10"
  op: "Add"
  input: "x_1/read"
  input: "y_1/read"
  attr {
    key: "T"
    value {
      type: DT_INT32
    }
  }
}
...

两者都给出相同的z值,有什么问题?

第一种方式:节点“添加”添加一次到图表定义 第二种方式:节点“添加”向图表定义添加了10次或者你想要多次计算z

想象一下,你想要计算一个操作 数千甚至数百万!

你的图表变得臃肿,加载缓慢,传递昂贵。

我在GitHub上看到的最常见的TF非bug错误之一

解决办法:

  • 操作与计算/运行操作的单独定义
  • 使用Python属性确保函数在第一次调用时也会加载
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-02-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 光城 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 开刷Cs20之Tensorflow第二弹
  • 学习内容
  • 第一个TensorFlow程序
  • TensorBoard可视化
  • 如何运行可视化的图?
  • 可视化计算图
  • Constants, Sequences, Variables, Ops
    • 常量
      • 特殊值填充张量
        • 常量作为序列
          • 随机生成的变量
            • 算法操作
              • 神奇的除法
              • Tensorflow数据类型
              • 尽可能使用TF DType
              • 常数有什么问题?
              • 变量
                • 创建变量
                  • tf.constant 与 tf.Variable区别
                    • 初始化变量
                      • Eval()
                        • tf.Variable.assign()
                          • assign_add() and assign_sub()
                            • 每个会话都维护自己的变量副本
                              • 控制依赖关系
                              • Placeholder
                                • 快速提醒
                                  • Placeholders
                                    • 为什么占位符?
                                      • 占位符使用?
                                        • 使用字典向占位符补充值
                                          • Variable和placeholder有什么区别呢?
                                            • Placeholders 是有效操作
                                              • 如果想要提供多个数据点怎么办?
                                                • is_feedable
                                                  • 给TF操作喂数据
                                                    • 对测试非常有帮助,输入虚拟值以测试大图的部分
                                                      • 什么是懒加载?
                                                      领券
                                                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档