TensorFlow入门
TensorFlow三个基础核心概念:计算图、Tensor、Session
一、计算图:
在TensorFlow中,计算图是一个有向图,用来描述计算节点以及计算节点之间的关系,所以在TensorFlow中我们存储一个值或者数组的时候,存的其实是这个值或者数组的计算图而不是其本身的数字。我们可以用写一个简单的例子来验证一下:
GPU版本
import tensorflow as tf
g=tf.Graph()
with g.device("/gpu:0"):
#c=lambda a,b:a+b
d=tf.constant([10,9,8,7])
e=tf.constant([1,2,3,4])
f_1=d+f
print(f_1.graph)
print(d.graph,e.graph)
sess=tf.Session()
print(sess.run(f_1))
CPU版
import tensorflow as tf
a=tf.constant([1,2,3,4],name=‘a’)
b=tf.constant([0,1,2,3],name=‘b’)
c=a+b
print(a.graph,b.graph)
print(c.graph)
sess=tf.Session()
print(sess.run©)
1、关于计算图的操作
1、新建计算图:g=tf.Graph(),但是不同计算图上的张量是不能共享的,这个是存在于变量
2、指定计算图的使用的device:with g.device("/gpu:0"):
3、设置默认计算图:with g.as_default:
4、在会话中可以指定使用的计算图:with tf.Session(graph=g1):
对于以上操作用代码说话,建议大家和我一起写,这样才会有比较大的体会和能够记住,
import tensorflow as tf
g1=tf.Graph()
with g1.as_default():
a=tf.constant([1,2,3],name=“a”)#用常量试试看
b=tf.get_variable(‘b’,initializer=tf.constant_initializer()(shape = [1]))#用变量试试看
g2=tf.Graph()
with g2.as_default():
a=tf.constant([2,3],name=“a”)#用常量试试看
b=tf.get_variable(‘b’,initializer=tf.constant_initializer()(shape = [3]))#用常量试试看
with tf.Session(graph=g2) as sess:
with g1.device("/cpu:0"):
tf.global_variables_initializer().run()
c=a+1
print(“常量的情况下”,sess.run©)
with tf.variable_scope("", reuse=True):
print(“变量情况下”,sess.run(tf.get_variable(“b”)))
with tf.Session(graph=g2) as sess:
with g2.device("/gpu:0"):
tf.global_variables_initializer().run()
c=a+1
print(“常量的情况下”,sess.run©)
with tf.variable_scope("", reuse=True):
print(“变量情况下”,sess.run(tf.get_variable(“b”)))
二、张量:
张量(tensor)可以简单理解为多维数组。其中零阶张量表示标量(scalar),也就是一个数;一阶张量为向量(vector),也就是一维数组;第n阶张量可以理解为一个n维数组。但是张量在Tensorflow中的实现并不是直接采用数组的形式,它只是对Tensorflow中运算结果的引用。在张量中并没有真正保存数字,它保存的是如何得到这些数字的计算过程。
import tensorflow as tf
a=tf.constant(2,name=‘a’)
b=tf.constant([0,1,2,3],name=‘b’)
c=a*b
print(a,b)
print©
sess=tf.Session()
print(sess.run©)
三、会话:
在TensorFlow中,计算图的计算过程都是在会话下进行的,同一个会话内的数据是可以共享的,会话结束计算的中间量就会消失。
在TensorFlow需要指定会话。
import tensorflow as tf
with tf.Session as sess:
print(sess.run(result))
sess=tf.Session()
with sess.as_default():
print(result.eval())
sess = tf.InteractiveSession()#会自动成为默认会话
四、tensorflow中的数据类型
数据类型 | Python 类型 | 描述 |
---|---|---|
DT_FLOAT | tf.float32 | 32 位浮点数. |
DT_DOUBLE | tf.float64 | 64 位浮点数 |
DT_INT64 | tf.int64 | 64 位有符号整型. |
DT_INT32 | tf.int32 | 32 位有符号整型. |
DT_INT16 | tf.int16 | 16 位有符号整型. |
DT_INT8 | tf.int8 | 8 位有符号整型. |
DT_UINT8 | tf.uint8 | 8 位无符号整型. |
DT_STRING | tf.string | 可变长度的字节数组.每一个张量元素都是一个字节数组 |
DT_BOOL | tf.bool | 布尔型. |
DT_COMPLEX64 | tf.complex64 | 由两个32位浮点数组成的复数:实数和虚数. |
DT_QINT32 | tf.qint32 | 用于量化Ops的32位有符号整型. |
DT_QINT8 | tf.qint8 | 用于量化Ops的8位有符号整型. |
DT_QUINT8 | tf.quint8 | 用于量化Ops的8位无符号整型. |
五、TensorFlow 基础API
我们这个课程的是将TensorFlow的高阶API,但是由于在我们的应用案例中不可能都是高阶API,还会涉及到一些常用必须的基础的API,我们在开始讲高阶API之前也先简单讲一下低阶的基础API.根据TensorFlow官网以及在日常的编程中的使用情况,我梳理了以下需要掌握的TensorFlow基础API:
tf.Graph():
tf.Graph.device():
tf.Graph.as_default():
tf.Session():
tf.Session.run():
tf.Session.as_default():
tf.InteractiveSession():
tf.constant():
tf.variable():
tf.get_variable():
tf.placeholder():
tf.agrmax
tf.train()
tf.nn()
前面我们在讲解计算图、张量、会话时有些基础的API已经讲解了,在这里我们就不重复讲。我们这里重点讲一下tf.train和tf.nn这两个非常重要的API.
(1)tf.nn
1、卷积函数
<1>tf.nn.convolution
tf.nn.convolution(input, filter, padding,strides=None, dilation_rate=None, name=None, data_format =None)
这个函数计算 N 维卷积的和
<2>tf.nn.conv2d
tf.nn.conv2d(input, filter, strides, padding,use_cudnn_on_gpu=None, data_format=None, name=None)
这个函数的作用是对一个四维的输入数据input 和四维的卷积核 filter 进行操作,然 后对输入数据进行一个二维的卷积操作,最后得到卷积之后的结果。
参数:
input:指需要做卷积的输入图像,要求是一个Tensor,具有[batch, in_height, in_width, in_channels]这样的shape,具体含义是[训练时一个batch的图片数量,图片高度,图片宽度,图像通道数],注意这是一个4维的Tensor,要求类型为float32和float64其中之一
filter : 相当于CNN中的卷积核,要求是一个Tensor,具有[filter_height, filter_width, in_channels, out_channels]这样的shape,具体含义是[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数],要求类型与参数input相同。另外,需要注意的是,第三维in_channels就是参数input的第四维。
**strides:**一个长度是4的一维整数类型数组,每一维度对应的是input中每一维的对应移动步数,比如,strides[1]对应input[1]的移动步数
**padding:**string类型的量,取值为SAME或者VALID
padding=‘SAME’:仅适用于全尺寸操作,即输入数据维度和输出数据维度相同
padding=‘VALID’:适用于部分窗口,即输入数据维度和输出数据维度不同
use_cudnn_on_gpu:bool类型,是否使用cudnn加速,默认为true
**name:**可选,为这个操作取一个名字
使用示例:
input_data = tf.Variable( np.random.rand(10,9,9,3), dtype = np.float32 )
filter_data = tf.Variable( np.random.rand(2, 2, 3, 2), dtype = np.float32)
y = tf.nn.conv2d(input_data, filter_data, strides = [1, 1, 1, 1], padding = ‘SAME’)
打印出 tf.shape(y)的结果是[10 9 9 2]
<3>tf.nn.depthwise_conv2d
tf.nn.depthwise_conv2d (input, filter, strides, padding, rate=None, name=None,data_format= None)
这个函数输入张量的数据维度是[batch, in_height,in_width, in_channels],卷积核的维度是 [filter_height, filter_width, in_channels, channel_multiplier],在通道 in_channels 上面的卷积深度是 1,depthwise_conv2d 函数将不同的卷积核独立地应用在 in_channels 的每个通道上(从通道 1 到通道 channel_multiplier),然后把所以的结果进行汇总。最后输出通道的总数是 in_channels * channel_multiplier。
使用示例:
input_data = tf.Variable( np.random.rand(10, 9, 9, 3), dtype = np.float32 )
filter_data = tf.Variable( np.random.rand(2, 2, 3, 5), dtype = np.float32)
y = tf.nn.depthwise_conv2d(input_data,filter_data,strides= [1, 1, 1, 1], padding = ‘SAME’)
这里打印出 tf.shape(y)的结果是[10 9 9 15]。
<4>tf.nn.separable_conv2d
tf.nn.separable_conv2d (input, depthwise_filter, pointwise_filter, strides, padding, rate=None, name=None, data_format=None)
此函数是利用几个分离的卷积核去做卷积。在这个API 中,将应用一个 二维的卷积核,在每个通道上,以深度 channel_multiplier 进行卷积。
特殊参数:
depthwise_filter: 一个张量。数据维度是四维[filter_height, filter_width, in_channels, channel_multiplier]。
其中,in_channels的卷积深度是1。
**pointwise_filter:**一个张量。数据维度是四维[1, 1, channel_multiplier * in_channels,out_channels]。
其中,pointwise_filter 是在 depthwise_filter 卷积之后的混合卷积。
使用示例:
input_data = tf.Variable( np.random.rand(10,9, 9, 3), dtype = np.float32 )
depthwise_filter = tf.Variable( np.random.rand(2, 2, 3, 5), dtype = np.float32)
pointwise_filter = tf.Variable( np.random.rand(1, 1, 15, 20), dtype = np.float32)
# out_channels >= channel_multiplier * in_channels
y = tf.nn.separable_conv2d(input_data, depthwise_filter, pointwise_filter,strides = [1, 1, 1, 1], padding = ‘SAME’)
这里打印出 tf.shape(y)的结果是[10 9 9 20]。
<5>tf.nn.atrous_conv2d
tf.nn.atrous_conv2d(value, filters,rate, padding, name=None)
计算 Atrous 卷积,又称孔卷 积或者扩张卷积。
使用示例:
input_data = tf.Variable( np.random.rand(1,5,5,1), dtype = np.float32 )
filters = tf.Variable( np.random.rand(3,3,1,1), dtype = np.float32)
y = tf.nn.atrous_conv2d(input_data, filters, 2, padding=‘SAME’)
这里打印出tf.shape(y)的结果是[1 5 5 1]。
<6>tf.nn.conv2d_transpose
tf.nn.conv2d_transpose(value,filter,output_shape,strides,padding=‘SAME’,data_format=‘NHWC’,name=None)
在解卷积网络(deconvolutional network)中有时称为“反卷积”,但实际上是 conv2d 的转置,而不是实际的反卷积。
特殊参数:
**output_shape:**一维的张量,表示反卷积运算后输出的形状
输出:和 value 一样维度的 Tensor
使用示例:
x = tf.random_normal(shape=[1,3,3,1])
kernel = tf.random_normal(shape=[2,2,3,1])
y = tf.nn.conv2d_transpose(x,kernel,output_shape=[1,5,5,3],strides=[1,2,2,1],padding=“SAME”)
这里打印出 tf.shape(y)的结果是[1 5 5 3]。
<7>tf.nn.conv1d
tf.nn.conv1d(value, filters, stride, padding,use_cudnn_on_gpu=None, data_format=None, name=None)
和二维卷积类似。这个函数是用来计算给定三维的输入和过滤器的情况下的一维卷 积。不同的是,它的输入是三维,如[batch, in_width, in_channels]。卷积核的维度也是三维,少 了一维 filter_height,如 [filter_width, in_channels, out_channels]。stride 是一个正整数,代表卷积 核向右移动每一步的长度。
<8>tf.nn.conv3d
tf.nn.conv3d(input, filter, strides, padding, name=None)
和二维卷积类似。这个函数用来计 算给定五维的输入和过滤器的情况下的三维卷积。和二维卷积相对比:
● input 的 shape 中多了一维 in_depth,形状为 Shape[batch, in_depth, in_height, in_width, in_channels];
● filter 的 shape 中多了一维 filter_depth,由 filter_depth, filter_height, filter_width 构成了卷 积核的大小;
● strides 中多 了一维, 变 为 [strides_batch, strides_depth, strides_height, strides_width, strides_channel],必须保证 strides[0] = strides[4] = 1。
<9>tf.nncon3d_transpose
tf.nn.conv3d_transpose(value, filter,output_shape, strides, padding=‘SAME’, name=None)
和二维反卷积类似
2、池化函数
<1>tf.nn.avg_pool
tf.nn.avg_pool(value, ksize, strides, padding,data_format=‘NHWC’, name=None)
这个函 数计算池化区域中元素的平均值。
参数:
**value:**一个四维的张量。数据维度是[batch, height, width, channels]
**ksize:**一个长度不小于 4 的整型数组。每一位上的值对应于输入数据张量中每一维的窗口对应值
**strides:**一个长度不小于 4 的整型数组。该参数指定滑动窗口在输入数据张量每一维上的步长
**padding:**一个字符串,取值为 SAME 或者 VALID
data_format: 'NHWC’代表输入张量维度的顺序,N 为个数,H 为高度,W 为宽度,C 为通道数(RGB 三
通道或者灰度单通道)
name(可选):为这个操作取一个名字
使用示例:
input_data = tf.Variable( np.random.rand(10,6,6,3), dtype = np.float32 )
filter_data = tf.Variable( np.random.rand(2, 2, 3, 10), dtype = np.float32)
y = tf.nn.conv2d(input_data, filter_data, strides = [1, 1, 1, 1], padding = ‘SAME’)
output = tf.nn.avg_pool(value = y, ksize = [1, 2, 2, 1], strides = [1, 1, 1, 1],padding =‘SAME’)
上述代码打印出 tf.shape(output)的结果是[10 6 6 10]。计算输出维度的方法是:shape(output)
=(shape(value) - ksize + 1) / strides。
<2>tf.nn.max_pool
tf.nn.max_pool(value, ksize, strides, padding,data_format=‘NHWC’, name=None)
这个函数是计算池化区域中元素的最大值。
参数:
**value:**需要池化的输入,一般池化层接在卷积层后面,所以输入通常是feature map,依然是[batch,height,width,channels]这样的shape
**ksize:**池化窗口的大小,取一个4维向量,一般是[1, height, width, 1],因为不想在batch和channels上做池化,所以这两个维度设为1
**strides:**和卷积类似,窗口在每一个维度上滑动的步长,一般也是[1, stride, stride, 1]
**padding:**和卷积类似,可以取‘VALID’和‘SAME’
使用示例:
input_data = tf.Variable( np.random.rand(10,6,6,3), dtype = np.float32 )
filter_data = tf.Variable( np.random.rand(2, 2, 3, 10), dtype = np.float32)
y = tf.nn.conv2d(input_data, filter_data, strides = [1, 1, 1, 1], padding = ‘SAME’)
output = tf.nn.max_pool(value = y, ksize = [1, 2, 2, 1], strides = [1, 1, 1, 1],padding =‘SAME’)
上述代码打印出 tf.shape(output)的结果是[10 6 6 10]。
<3>tf.nn.max_pool_with_argmax
tf.nn.max_pool_with_argmax(input, ksize,strides, padding, Targmax = None, name=None)
这个函数的作用是计算池化区域中元素的最大值和该最大值所在的位置。
在计算位置 argmax 的时候,我们将 input 铺平了进行计算,所以,如果 input = [b, y, x, c], 那么索引位置是(( b * height + y) * width +x) * channels + c。
**使用示例:**该函数只能在 GPU 下运行,在 CPU 下没有对应的函数实现
input_data = tf.Variable( np.random.rand(10,6,6,3), dtype = tf.float32 )
filter_data = tf.Variable( np.random.rand(2, 2, 3, 10), dtype = np.float32)
y = tf.nn.conv2d(input_data, filter_data, strides = [1, 1, 1, 1], padding = ‘SAME’)
output, argmax = tf.nn.max_pool_with_argmax(input = y, ksize = [1, 2, 2, 1],strides = [1, 1, 1, 1], padding = ‘SAME’)
返回结果是一个张量组成的元组(output, argmax),output 表示池化区域的最大值;argmax 的数据类型是 Targmax,维度是四维。
<4>tf.nn.avg_pool3d
三维下的平均池化
<5>tf.nn.max_pool3d
三维下的最大池化
<6>tf.nn.fractional_avg_pool
三维下的平均池化
<7>tf.nn.fractional_max_pool
三维下的最大池化
<8>tf.nn.pool
tf.nn.pool(input, window_shape, pooling_type,padding, dilation_rate=None, strides=None, name=None, data_format=None)
这个函数执行一个 N 维的池化操作。
3、激活函数
激活函数(activation function)运行时激活神经网络中某一部分神经元,将激活信息向后传入下一层的神经网络。神经网络之所以能解决非线性问题(如语音、图像识别),本质上就 是激活函数加入了非线性因素,弥补了线性模型的表达力,把“激活的神经元的特征”通过函数保留并映射到下一层。
注:
1、软饱和是指激活函数 h(x)在取值趋于无穷大时,它的一阶导数趋于 0。硬饱和是指当|x| > c 时,其中 c 为常数,f '(x)=0。relu 就是一类左侧硬饱和激活函数。
2、梯度消失是指在更新模型参数时采用链式求导法则反向求导,越往前梯度越小。最终的结果是到达一定深度后梯 度对模型的更新就没有任何贡献了。
3、激活函数的选择:当输入数据特征相差明显时,用 tanh 的效果会很好,且在循环过程中会不断扩大特征效果并显示出来。当特征相差不明显时,sigmoid 效果比较好。同时,用 sigmoid 和 tanh 作为激活函数时, 需要对输入进行规范化,否则激活后的值全部都进入平坦区,隐层的输出会全部趋同,丧失原有 的特征表达。而 relu 会好很多,有时可以不需要输入规范化来避免上述情况。 因此,现在大部分的卷积神经网络都采用 relu 作为激活函数。我估计大概有 85%~90%的神经网 络会采用 ReLU,10%~15%的神经网络会采用 tanh,尤其用在自然语言处理上。
<1>tf.nn.relu
tf.nn.relu(features,name=None)
这个函数的作用是计算激活函数relu,即f(x)=max (x,0),即将矩阵中每行的非最大值置0
![](C:\Users\Robin\Desktop\文档2\tensorflow相关\TensorFlow基础入门\relu and softplus.png)
如图,relu 在 x<0 时硬饱和。由于 x>0 时 导数为 1,所以,relu能够在 x>0时保持梯度不衰减,从 而缓解梯度消失问题,还能够更很地收敛,并提供了神经网络的稀疏表达能力。但是,随着训练的进行, 部分输入会落到硬饱和区,导致对应的权重无法更新, 称为“神经元死亡”。
使用示例:
a = tf.constant([-1.0, 2.0])
with tf.Session() as sess:
b = tf.nn.relu(a)
print sess.run(b)
<2>tf.nn.softplus
softplus可以看做是ReLU的平滑版本。定义为f(x)=log(1+exp(x)).
<3>tf.nn.relu6
tf.nn.relu6(features, name=None)
被定义为min(max(features, 0), 6)
<4>tf.nn.crelu
tf.nn.crelu(features, name=None)
<5>tf.nn.sigmoid
sigmoid 函数的优点在于,它的输出映射在(0,1)内,单调连续,非常适合用作输出层,并且 求导比较容易。但是,它也有缺点,因为软饱和性,一旦输入落入饱和区,f’(x)就会变得接近 于 0,很容易产生梯度消失。
使用示例:
a = tf.constant([[1.0, 2.0], [1.0, 2.0], [1.0, 2.0]])
sess = tf.Session()
print sess.run(tf.sigmoid(a))
<6>tf.nn.tanh
tanh 函数也具有软饱和性。因为它的输出以 0 为中心,收敛速度比 sigmoid 要很。但是仍 无法解决梯度消失的问题。
<7>tf.nn.elu
<8>tf.nn.bias_add
<9>tf.nn.softsign
<10>tf.nn.dropout
tf.nn.dropout(x, keep_prob, noise_shape, seed=None, name=None)
参数:
**x:**输入Tensor
**keep_prob:**float类型,每个元素被保留下来的概率
一个神经元将以概率 keep_prob 决定是否被抑制。如果被抑制,该神经元的输出就为0;如果不被抑制,那么该神经元的输出值将被放大到原来的1/keep_prob 倍。
**noise_shape:**一个1维的int32张量,代表了随机产生“保留/丢弃”标志的shape
在默认情况下,每个神经元是否被抑制是相互独立的。但是否被抑制也可以通过noise_shape 来 调节。当 noise_shape[i] == shape(x)[i]时,x 中的元素是相互独立的。如果 shape(x) =[k, l, m, n], x 中的维度的顺序分别为批、行、列和通道,如果 noise_shape = [k, 1, 1, n],那么每个批和通道 都是相互独立的,但是每行和每列的数据都是关联的,也就是说,要不都为 0,要不都还是原 来的值。
**seed:**整形变量,随机数种子
使用示例:
a = tf.constant([[-1.0, 2.0, 3.0, 4.0]])
with tf.Session() as sess:
b = tf.nn.dropout(a, 0.5, noise_shape = [1,4])
print sess.run(b)
b = tf.nn.dropout(a, 0.5, noise_shape = [1,1])
print sess.run(b)
**注:**dropout 在论文中最我被提出时是这么做的:在训练的时候用概率p 丢弃,然后在预测的时候,所有参数按比例缩 小,也就是乘以 p。
在各种深度学习框架(如Keras、TensorFlow)的实现中,都是用反向 ropout 来代替 dropout。 也就是这里所说的,在训练的时候一边 dropout,然后再按比例放大,也就是乘以 1/p,然后在预测的时候,不做 任务处理。
4、分类函数
<1>tf.nn.sigmoid_cross_entropy_with_logits
tf.nn.sigmoid_cross_entropy_with_logits(logits,targets, name=None):
输入:logits:[batch_size, num_classes],targets:[batch_size, size].
logits 用最后一层的输入即可
最后一层不需要进行 sigmoid 运算,此函数内部进行了 sigmoid 操作
输出:loss [batch_size, num_classes]
这个函数的输入要格外注意,如果采用此函数作为损失函数,在神经网络的最后一层不需 要进行 sigmoid 运算。
<2>tf.nn.softmax
tf.nn.softmax(logits,dim=-1, name=None)
计算 Softmax 激活,也就是 softmax = exp(logits) / reduce_sum(exp(logits), dim)。
<3>tf.nn.log_softmax
tf.nn.log_softmax(logits,dim=-1, name=None)
计算 log softmax 激活,也就是 logsoftmax = logits -log(reduce_sum(exp(logits), dim))
<4>tf.nn.softmax_cross_entropy_with_logits
tf.nn.softmax_cross_entropy_with_logits(_sentinel=None,labels=None, logits=None, dim=-1, name =None)
输入:logits and labels 均为[batch_size, num_classes]
输出: loss:[batch_size], 里面保存的是 batch 中每个样本的交叉熵
<5>tf.nn.sparse_softmax_cross_entropy_with_logits
tf.nn.sparse_softmax_cross_entropy_with_logits(logits,labels, name=None)
logits 是神经网络最后一层的结果
输入:logits: [batch_size, num_classes] labels: [batch_size],必须在[0, num_classes]
输出:loss [batch_size],里面保存是 batch 中每个样本的交叉熵
(2)tf.train
<1>tf.train
<2>tf.train.GradientDescentOptimizer
<3>tf.train.Saver
(3)tf.Variable\tf.get_variable:
1、图变量的初始化方法
对于一般的Python代码,变量的初始化就是变量的定义,向下面这样:
In [1]: x = 3
In [2]: y = 3 * 5
In [3]: y
Out[3]: 15
如果我们模仿上面的写法来进行TensorFlow编程,就会出现下面的”怪现象”:
In [1]: import tensorflow as tf
In [2]: x = tf.Variable(3, name=‘x’)
In [3]: y = x * 5
In [4]: print(y)
Tensor(“mul:0”, shape=(), dtype=int32)
y的值并不是我们预想中的15,而是一个莫名其妙的输出——”
In [1]: import tensorflow as tf
In [2]: x = tf.Variable(3, name=‘x’)
In [3]: y = x * 5
In [4]: sess = tf.InteractiveSession()
In [5]: sess.run(tf.global_variables_initializer())
In [6]: sess.run(y)
Out[6]: 15
在TensorFlow的世界里,变量的定义和初始化是分开的,所有关于图变量的赋值和计算都要通过tf.Session的run来进行。想要将所有图变量进行集体初始化时应该使用tf.global_variables_initializer。
2、两种定义图变量的方法
<1>tf.Variable
tf.Variable.init(initial_value, trainable=True, collections=None, validate_shape=True, name=None)
参数名称 参数类型 含义
initial_value 所有可以转换为Tensor的类型 变量的初始值
trainable bool 如果为True,会把它加入到GraphKeys.TRAINABLE_VARIABLES,才能对它使用Optimizer
collections list 指定该图变量的类型、默认为[GraphKeys.GLOBAL_VARIABLES]
validate_shape bool 如果为False,则不进行类型和维度检查
name string 变量的名称,如果没有指定则系统会自动分配一个唯一的值
虽然有一堆参数,但只有第一个参数initial_value是必需的,用法如下(assign函数用于给图变量赋值):
In [1]: import tensorflow as tf
In [2]: v = tf.Variable(3, name=‘v’)
In [3]: v2 = v.assign(5)
In [4]: sess = tf.InteractiveSession()
In [5]: sess.run(v.initializer)
In [6]: sess.run(v)
Out[6]: 3
In [7]: sess.run(v2)
Out[7]: 5
<2>tf.get_variable
tf.get_variable跟tf.Variable都可以用来定义图变量,但是前者的必需参数(即第一个参数)并不是图变量的初始值,而是图变量的名称。
In [1]: import tensorflow as tf
In [2]: init = tf.constant_initializer([5])
In [3]: x = tf.get_variable(‘x’, shape=[1], initializer=init)
In [4]: sess = tf.InteractiveSession()
In [5]: sess.run(x.initializer)
In [6]: sess.run(x)
Out[6]: array([ 5.], dtype=float32)
3、scope如何划分命名空间
一个深度学习模型的参数变量往往是成千上万的,不加上命名空间加以分组整理,将会成为可怕的灾难。TensorFlow的命名空间分为两种,tf.variable_scope和tf.name_scope。
下面示范使用tf.variable_scope把图变量划分为4组:
for i in range(4):
with tf.variable_scope(‘scope-{}’.format(i)):
for j in range(25):
v = tf.Variable(1, name=str(j))
可视化输出的结果如下:
下面让我们来分析tf.variable_scope和tf.name_scope的区别:
<1>tf.variable_scope
1、当使用tf.get_variable定义变量时,如果出现同名的情况将会引起报错
In [1]: import tensorflow as tf
In [2]: with tf.variable_scope(‘scope’):
…: v1 = tf.get_variable(‘var’, [1])
…: v2 = tf.get_variable(‘var’, [1])
ValueError: Variable scope/var already exists, disallowed. Did you mean to set reuse=True in VarScope? Originally defined at:
2、而对于tf.Variable来说,却可以定义“同名”变量
In [1]: import tensorflow as tf
In [2]: with tf.variable_scope(‘scope’):
…: v1 = tf.Variable(1, name=‘var’)
…: v2 = tf.Variable(2, name=‘var’)
…:
Out[3]: (‘scope/var:0’, ‘scope/var_1:0’)
但是把这些图变量的name属性打印出来,就可以发现它们的名称并不是一样的。
如果想使用tf.get_variable来定义另一个同名图变量,可以考虑加入新一层scope,比如:
In [1]: import tensorflow as tf
In [2]: with tf.variable_scope(‘scope1’):
…: v1 = tf.get_variable(‘var’, shape=[1])
…: with tf.variable_scope(‘scope2’):
…: v2 = tf.get_variable(‘var’, shape=[1])
…:
Out[3]: (‘scope1/var:0’, ‘scope1/scope2/var:0’)
<2>tf.name_scope
当tf.get_variable遇上tf.name_scope,它定义的变量的最终完整名称将不受这个tf.name_scope的影响,如下:
In [1]: import tensorflow as tf
In [2]: with tf.variable_scope(‘v_scope’):
…: with tf.name_scope(‘n_scope’):
…: x = tf.Variable([1], name=‘x’)
…: y = tf.get_variable(‘x’, shape=[1], dtype=tf.int32)
…: z = x + y
…:
In [3]: x.name, y.name, z.name
Out[3]: (‘v_scope/n_scope/x:0’, ‘v_scope/x:0’, ‘v_scope/n_scope/add:0’)
4、图变量的复用
想象一下,如果我们正在定义一个循环神经网络RNN,想复用上一层的参数以提高模型最终的表现效果,应该怎么做呢?
<1>做法一:
In [1]: import tensorflow as tf
In [2]: with tf.variable_scope(‘scope’):
…: v1 = tf.get_variable(‘var’, [1])
…: tf.get_variable_scope().reuse_variables()
…: v2 = tf.get_variable(‘var’, [1])
…:
Out[3]: (‘scope/var:0’, ‘scope/var:0’)
<2> 做法二:
In [1]: import tensorflow as tf
In [2]: with tf.variable_scope(‘scope’):
…: v1 = tf.get_variable(‘x’, [1])
…:
In [3]: with tf.variable_scope(‘scope’, reuse=True):
…: v2 = tf.get_variable(‘x’, [1])
…:
Out[4]: (‘scope/x:0’, ‘scope/x:0’)
5、图变量的种类
TensorFlow的图变量分为两类:local_variables和global_variables。
如果我们想定义一个不需要长期保存的临时图变量,可以向下面这样定义它:
with tf.name_scope(“increment”):
zero64 = tf.constant(0, dtype=tf.int64)
current = tf.Variable(zero64, name=“incr”, trainable=False, collections=[ops.GraphKeys.LOCAL_VARIABLES])
(4)tf.truncated_normal
tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
参数:
shape: 一维的张量,也是输出的张量。
mean: 正态分布的均值。
stddev: 正态分布的标准差。
dtype: 输出的类型。
seed: 一个整数,当设置之后,每次生成的随机数都一样。
name: 操作的名字。
从截断的正态分布中输出随机值。
生成的值服从具有指定平均值和标准偏差的正态分布,如果生成的值大于平均值两个标准偏差,则丢弃该值重新选择。
1、μ是正态分布的位置参数,描述正态分布的集中趋势位置。概率规律为取与μ邻近的值的概率大。正态分布以X=μ为对称轴,左右完全对称。正态分布的期望、均数、中位数、众数相同,均等于μ。
2、σ描述正态分布资料数据分布的离散程度,σ越大,数据分布越分散,σ越小,数据分布越集中。也称为是正态分布的形状参数,σ越大,曲线越扁平,反之,σ越小,曲线越瘦高。
3、在正态分布的曲线中,横轴区间(μ-σ,μ+σ)内的面积为68.268949%。 横轴区间(μ-2σ,μ+2σ)内的面积为95.449974%。 横轴区间(μ-3σ,μ+3σ)内的面积为99.730020%。
X落在(μ-3σ,μ+3σ)以外的概率小于千分之三,在实际问题中常认为相应的事件是不会发生的,基本上可以把区间(μ-3σ,μ+3σ)看作是随机变量X实际可能的取值区间,这称之为正态分布的“3σ”原则。
在tf.truncated_normal中如果x的取值在区间(μ-2σ,μ+2σ)之外则重新进行选择。这样保证了生成的值都在均值附近。
(5)tf.random_normal
tf.random_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
从正态分布中输出随机值
参数:
shape: 一维的张量,也是输出的张量。
mean: 正态分布的均值。
stddev: 正态分布的标准差。
dtype: 输出的类型。
seed: 一个整数,当设置之后,每次生成的随机数都一样。
name: 操作的名字。
(6)tf.cast
tf.cast(x, dtype, name=None)
tf.cast()函数的作用是执行 tensorflow 中张量数据类型转换,比如读入的图片如果是int8类型的,一般在要在训练前把图像的数据格式转换为float32。
参数:
**x:**待转换的数据(张量)
**dtype:**目标数据类型
**name:**可选参数,定义操作的名称
示例:
import tensorflow as tf
t1 = tf.Variable([1,2,3,4,5])
t2 = tf.cast(t1,dtype=tf.float32)
print ‘t1: {}’.format(t1)
print ‘t2: {}’.format(t2)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
sess.run(t2)
print t2.eval()
#print(sess.run(t2))
输出:
t1: <tf.Variable ‘Variable:0’ shape=(5,) dtype=int32_ref>
t2: Tensor(“Cast:0”, shape=(5,), dtype=float32)
[ 1. 2. 3. 4. 5.]
(7)tf.constant
tf.constant( value, dtype=None ,shape=None, name=‘Const’, verify_shape=False)
用来创建常量
**参数:**除了第一个value别的都不是必须的
value: 这个参数是必须的,可以是一个数值,也可以是一个列表。
1、 创建一个数值:tensor=tf.constant(1)
2、创建一个列表:tensor=tf.constant([1, 2])
为查看结果必须创建一个会话,并用取值函数eval()来查看创建的tensor的值:
sess=tf.Session()
with sess.as_default():
print(‘结果是:’, tensor.eval())
结果是:1 或者 结果是:[1 2]
dtype: 这个参数表示数据类型,一般可以是tf.float32,tf.float64等:
shape: 表示张量的形状,即维数以及每一维的大小。如果指定了第三个参数,
1、当第一个参数value是数字时, 张量的所有元素都会用该数字填充:
示例:
tensor=tf.constant(-1, shape=[2, 3])
sess=tf.Session()
with sess.as_default():
print(‘结果是:’, tensor.eval())
结果是: [[-1 -1 -1][-1 -1 -1]]
可以看到,输出结果是一个二维张量,第一维大小为2,第二维大小为3,全部用数字-1填充。
2、当第一个参数value是一个列表时,注意列表的长度必须小于等于第三个参数shape的大小(即各维
大小的乘积),否则会报错:
示例:
tensor=tf.constant([1, 2, 3, 4, 5, 6, 7], shape=[2, 3])
Traceback (most recent call last):
File “<pyshell#68>”, line 1, in
tensor=tf.constant([1, 2, 3, 4, 5, 6, 7], shape=[2, 3])
ValueError: Too many elements provided. Needed at most 6, but received 7
这是因为函数会生成一个shape大小的张量,然后用value这个列表中的值一一填充shape中的元素。这
里列表大小为7,而shape大小为2*3=6,无法正确填充,所以发生了错误。
而如果列表大小小于shape大小,则会用列表的最后一项元素填充剩余的张量元素:
示例:
tensor=tf.constant([1, 2], shape=[1, 4, 3])
sess=tf.Session()
with sess.as_default():
print(‘结果是:’, tensor.eval())
结果是: [[[1 2 2][2 2 2]2 2 2][2 2 2]]]
name: 为这个常量起名,主要是字符串就行
不输入内容时:
tensor=tf.constant([1, 2])
print(tensor)
Tensor(“Const_16:0”, shape=(2,), dtype=int32)
输入name时:
tensor=tf.constant([1, 2], name=“jiayu”)
print(tensor)
Tensor(“jiayu_1:0”, shape=(2,), dtype=int32)
verify_shape: 默认为False,如果修改为True的话表示检查value的形状与shape是否相符,如果不符会报错。
示例:
tensor=tf.constant([[1, 2, 3], [4, 5, 6]], shape=[2, 3], verify_shape=True)
以上代码value与shape都是两行三列,检查结果正确。而下面的代码会报错:
tensor=tf.constant([1, 2], shape=[3, 2], verify_shape=True)