本文介绍了我遇到的一些TensorFlow的函数和类,记录了相关用法和自己的理解,一方面为了整理自己的思路,加深印象,另一方面也方便以后查阅。
构建卷积层
tf.nn.conv2d
tf.nn.conv2d(
input,
filter,
strides,
padding,
use_cudnn_on_gpu=True,
data_format=’NHWC’,
dilations=[1, 1, 1, 1],
name=None
)
- 最常见的卷积层构造方法。
- 参数解释:
- input:为输入卷积层的数据,用4维的tensor来表示,shape为[batch, in_height, in_width, in_channels],具体含义是[训练时一个batch的图片数量, 图片高度, 图片宽度, 图像通道数],注意这是一个4维的Tensor,要求类型为float32和float64其中之一;
- filter:表示卷积核,同样是4维的tensor,shape为[filter_height, filter_width, in_channels, out_channels],具体含义是[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数],ilter_height, filter_width也可以说是卷积核在input的对应维度上的window size;第三维in_channels,就是参数input的第四维;out_channels有两个含义,一是有多少个卷积核,二是最终输出图像的通道数(一个卷积核的计算结果对应一个输出通道的值);
- strides:表示卷积核在各个维度上的跨度,同样是4维tensor(各个维度的意义和input参数相同),
[1, 1, 1, 1]
表示卷积核一个一个像素移动着计算,[1, 2, 2, 1]
表示在in_height和in_width维度上每隔一个像素计算一次。 - padding:表示如何计算图像边缘的像素。只有两个可选值:
VALID
和SAME
,VALID
表示图像边缘一圈的像素不计算,SAME
表示将图像边缘进行扩充以计算所有图像内像素(通常用0填充)。详细内容可参见TensorFlow官方Neural Network教程。
- return:返回值为经过卷积计算的结果(也被成为feature map),shape为[batch, out_height, out_width, out_channels],其中
batch
和input的batch相同,后三个参数则由卷积核来决定。 - 如何计算:由卷积核在input图像上不断滑动,做卷积预算,最终得出输出的feature map,feature map的长宽要试输入图像、卷积核和padding方式共同决定。
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:池化窗口在各维度上的大小,一般是[1, height, width, 1],即保持batch和channel维度不变,只在height和width维度上做池话操作;
- strides:和卷积类似,窗口在每一个维度上滑动的步长,一般是[1, stride, stride, 1](保持batch和channel不变);
- padding:和卷积类似,可取’VALID’ 或者’SAME’;
- return:返回经过maxpool计算后的tensor,shape为[batch, height, width, channels]。
- 这个函数实现的是max_pool(最大池化操作),即在一个范围内的值中选最大值,作为卷积后二次提取的特征。
tf.train.Optimizer类
- 这个类是tensorflow中各种优化器的父类,作用:给定一个目标函数/损失函数,根据一定的算法(优化器算法),来不断计算、更新函数中的变量,以使得最终函数取得最小值,即达到优化目标。
- 下面介绍一些常用的函数API,虽然在各个优化器子类中会有一定变化,但大体还是一致的。
常用的优化类
- GradientDescentOptimizer:梯度下降优化器;
- AdamOptimizer:Adam优化器,一般直接用这个就行;
init
通常会在初始化时定义优化器的学习率/更新率,egoptimizer = tf.train.AdamOptimizer(1e-3)
。
compute_gradients
compute_gradients(
loss,
var_list=None,
gate_gradients=GATE_OP,
aggregation_method=None,
colocate_gradients_with_ops=False,
grad_loss=None
)
- 函数作用:计算loss函数中各变量的梯度。
- 参数解释:
- loss:损失函数,在tf中就是一个变量;
- var_list:需要计算梯度的变量列表,只有在这个列表中的变量才会计算梯度,默认是
TRAINABLE_VARIABLES
collection中的所有变量。那有人可能会问,TRAINABLE_VARIABLES
collection里那么多变量,岂不是会有很多多余的?是这样的,但因为有那些多余的变量都不再loss函数中,因此计算出来的梯度也是0,所以也不会有影响。 - gate_gradients:指定了计算操作可以并行化的程度,通常不管。
- return:A list of (gradient, variable) pairs,即返回一个梯度-变量对的列表,反应了每个变量所计算出的梯度。
apply_gradients
apply_gradients(
grads_and_vars,
global_step=None,
name=None
)
- 函数作用:用计算出来的梯度更新变量。
- 参数解释:
- grads_and_vars:List of (gradient, variable) pairs,即为
compute_gradients
函数的返回值。 - global_step:标记变量,记录已进行了多少次变量更新操作,每更新一次global_step会自动加1。
- 注:在一次apply_gradients中会进行多次变量更新操作(会一直优化变量直到达到了指定误差),因此需要一个变量来记录进行了多少次更新。
- grads_and_vars:List of (gradient, variable) pairs,即为
- return:返回op,执行该操作即进行优化更新操作。
minimize
minimize(
loss,
global_step=None,
var_list=None,
gate_gradients=GATE_OP,
aggregation_method=None,
colocate_gradients_with_ops=False,
name=None,
grad_loss=None
)
- 函数作用:该函数相当于compute_gradients和apply_gradients的封装(先进行compute_gradients再进行apply_gradients),直接就返回一个最小化的Operation操作,没有中间先得到梯度、再应用梯度这些步骤了,更为简便。
- return:返回op,执行该操作即进行优化更新操作。
如何使用Optimizer
直接调用
minimize
函数1
2
3
4
5opt = GradientDescentOptimizer(learning_rate=0.1)
opt_op = opt.minimize(loss)
# 执行优化操作
opt_op.run()如果想对梯度进行一些修改,或者想观察梯度的变化情况,则分开执行
compute_gradients
和apply_gradients
函数,中间可随意操作梯度,只要保证梯度以(gradient, variable) list
的形式传入即可。1
2
3
4
5
6
7
8
9
10
11
12opt = GradientDescentOptimizer(learning_rate=0.1)
# 计算梯度
grads_and_vars = opt.compute_gradients(loss)
# 对梯度进行操作
capped_grads_and_vars = [(MyCapper(gv[0]), gv[1]) for gv in grads_and_vars]
# 更新变量
opt_op = opt.apply_gradients(capped_grads_and_vars)
# 执行优化操作
opt_op.run()
注1:执行一次minimzie()/apply_gradients()
返回的op操作,就相当于更新一次神经网络各边的权值(即函数中指定的var_list
),明显只更新一次肯定不能使网络达到最优,因此就要多次调用op操作,而具体调用多少次呢?大多情况下没有明确的答案,要看何时loss函数收敛到一定范围就可以了。
注2:一般是一个mini-batch调用一次优化op,然后设置一个epoch次数(如300、500),使神经网络在全量数据集上优化更新一个较大的次数,就认为达到最优了。
注3:最终loss函数画出来应该是一个先下降再趋于平稳的曲线,说明模型确实学到东西了,且loss函数最终收敛了(至少达到了局部极小值)。如果画出来的曲线还在下降,说明更新次数不够,还应该继续训练。
模型、数据可视化
Protocal Buffer
- Protocol buffers 是谷歌推出一种数据序列化格式,通常以string字符串的形式实现,数据转化为protocal buffer后就可以存储到磁盘上并在需要时重新加载。
- protocol buffer是一种跨平台、跨语言的格式,可类比XML,但更为轻量化。
- tensoeflow中就使用protocal buffer格式来存储模型和数据。
TensorBoard
- TensorBoard主要作用是可视化,可以读取存储到磁盘上的Protocol Buffer格式的文件,并进行可视化展示,计算图、计算过程的变量变化都可进行可视化显示。
- TensorBoard官方文档
tf.summary函数
在tensorflow程序中主要使用tf.summary的各类方法将数据转化为protocol buffer格式并存储到磁盘上,具体介绍如下。
除了保存基本的变量外,还可保存文本(tf.summary.text
)、图像(tf.summary.image
)、音频(tf.summary.audio
)格式的文件,且都可以用tensorboard进行展示。
tf.summary.scalar
tf.summary.scalar(
name,
tensor,
collections=None,
family=None
)
- 函数作用:将标量转化为probuf格式,一般在画loss、accuary时会用到这个函数。
- 参数解释:
- name:将标量以什么名字进行保存,在tensorboard中就会使用这个名字来显示变量。type:string。
- tensor:待存储的tensor,注意tensor的shape必须为
()
,即tensor必须是标量(即就一个数)。 - 其他参数一般用不到。
- return:会返回一个string格式的tensor,存储probuf化的标量信息。
tf.summary.histogram
tf.summary.histogram(
name,
values,
collections=None,
family=None
)
- 函数作用:用于存储tensor,不同于scalar只能存储一个数,distribution任何shape都可以存,其用来记录tensor中各个元素的分布情况。
- 参数解释:
- name:tensorboard中显示的名字;
- values:待存储的的tensor值;
- renturn:会返回一个string格式的tensor,存储probuf化的tensor信息。
- 在tensorboard中有两种查看histogram信息的方法:HISTOGRAMS和DISTRIBUTIONS,前者以直方形式显示统计结果, 后者提供更为抽象的统计信息。
- HISTOGRAMS可理解为频数分布直方图的堆叠,有两种显示模式:OVERLAY和OFFSET,OVERLAY意为覆盖,即不同的线代表不同的时间/step。如果较晚的线与较早的线重合,就以覆盖方式画线,横轴:值,纵轴:数量;OFFSET则将先按时间/step的前后分开画,但横纵轴的含义不变,横轴:值,纵轴:数量。
- DISTRIBUTIONS可理解为多分位数折线图的堆叠,
- TensorBoard Histogram Dashboard文档
tf.summary.merge
tf.summary.merge(
inputs,
collections=None,
name=None
)
- 函数作用:用于管理多个summary,将多个protocol buffer的数据整合到一个protocol buffer中,所以每次就可以只计算总的probuf了。
- 参数解释:
- inputs:待合并的多个tensor,每个tensor都是包含protocol buffer的string类型;type:包含多个tensor的list;
- 其他参数不常用。
- return:返回一个string类型的tensor,存储整合后的protocol buffer(包含了inputs中的各个probuf)。
tf.summary.merge_all
tf.summary.merge_all(
key=tf.GraphKeys.SUMMARIES,
scope=None,
name=None
)
- 函数作用:用于管理所有的summary,将所有的protocol buffer整合到一个里,一次性计算所有的summary。
- 参数解释:
- key:指定了整合哪个范围内的summary,默认为
tf.GraphKeys.SUMMARIES
(就是所有的summary,summary默认都添加到这里)。 - scope:过滤掉不想整合的summary。
- 三个参数通常情况下都不指定。
- key:指定了整合哪个范围内的summary,默认为
- return:返回一个string类型的tensor,存储整合后的protocol buffer。
tf.summary.FileWriter类
- 将变量转化为protocol buffer形式后,就需要将其写到文件中了,提供的将probuf写到文件中的类为:
FileWriter
。 - tensorflow称存储probuf的文件为
event file
,就是存储计算过程中各种事件的文件的意思。 - event file采用的是异步更新机制(系统会在空闲的时候才更新文件),保证了对文件的操作不会拖慢模型训练速度。
构造函数
init(
logdir,
graph=None,
max_queue=10,
flush_secs=120,
graph_def=None,
filename_suffix=None,
session=None
)
logdir
参数:要将event file保存在哪个目录下;- 其他参数不用管。
tf.FileWriter.add_graph
add_graph(
graph,
global_step=None,
graph_def=None
)
- 函数作用:将graph存储到FileWriter对应的event file中。之后tensorboard读取event file就可以对计算图进行可视化展示。
- 参数解释:
- graph:待存储的计算图;
- global_step:计数变量,每次调用函数就+1;
- return:无返回值。与其他返回op的函数不同,执行这个函数后数据就直接被写到文件了。
- 通常不使用这个函数,而是直接将
sess.graph
传入FileWriter的构造函数中。
tf.FileWriter.add_summary
add_summary(
summary,
global_step=None
)
- 函数作用:将summary函数产生的protocol buffer数据存储到FileWriter对应的event file中。
- 参数解释:
- summary:待存储的summary protocol buffer;注意必须先
run()/eval()
才能生成probuf,之后才能传入函数,不然就只传了一个空tensor。 - global_step:计数变量,每次调用函数就+1;
- summary:待存储的summary protocol buffer;注意必须先
- return:无返回值,函数直接执行写入操作(实际是异步的)。
Tensor shape information:将tensor的shape反映到图中(通过边的粗细程度)
tf.FileWriter.flush()
- 将所有pending的数据立即写入文件。
- 因为add函数是异步执行的,所以调用函数后系统不会立即将数据写入文件。
使用tensorboard
1 | # 初始化一个存储文件 |
如何调用TensorBoard:
tensorboard --logdir=PATH
;省略形式:tensorboard --logdir .
,直接在当前目录下运行。
注:annaconda下需要先进入相应python环境,才可以使用tensorboard
命令。- 之后在
localhost: 6006
上即可访问。
tensorboard分析:
在tensorboard中会按照name scope将相关节点都聚集到一个父节点中,因此良好的name scope命名规则会很有利于模型可视化。- 关于
name_scope
和variable_scope
的区别:
name_scope:为了更好地管理变量的命名空间而提出的。比如在 tensorboard 中,因为引入了 name_scope, 我们的 Graph 看起来才井然有序。
variable_scope:大部分情况下是跟 tf.get_variable() 配合使用,来实现变量共享的功能。但tensorboard也会对同一variable_scope的变量进行聚集和整理。
- 关于
tensorboard中的标签页:
GRAPHS
:可视化图结构;
SCALARS
:存储标量,横坐标是STEP时就表示标量随训练步骤的变化情况;DISTRIBUTIONS
:可理解为多分位数折线图 的堆叠。横轴表示训练步数,纵轴表示权重值。而从上到下的折现分别表示权重分布的不同分位数:[maximum, 93%, 84%, 69%, 50%, 31%, 16%, 7%, minimum]HISTOGRAMS
:是DISTRIBUTIONS的另一种形式,一般选OFFSET形式展示。其中,横轴表示值,纵轴表示值对应元素的数量,每个切片显示一个直方图,切片按步数排列;旧的切片较深,新的切片颜色较浅.如图,可以看到在第393步时,以4.91为中心的bin中有161个元素.
- 可以在distribution和historgram中打印变量的梯度,看梯度最终是否趋于0(即在0附近集中),如果趋于0的话变量就收敛了。
- 注:标签中横轴的含义:STEP: 迭代步长;RELATIVE: 相对时间(小时,相对于起始点);WALL:也训练时间。
tf.nn.embedding_lookup
tf.nn.embedding_lookup(
params,
ids,
partition_strategy=’mod’,
name=None,
validate_indices=True,
max_norm=None
)
- 函数作用:根据序号查找tensor中的相应项。当
params
为一个tensor时,根据ids
返回查到的行;当params
是多个tensor所构成的list时,则根据分隔策略返回查到的各个tensor的行。 - 构成
params
的tensor通常为2维的,此时查到的是行;如果tensor是一维的,则是查找相应的项。 - 参数解释:
- params:待查找项的集合;type:单个tensor或多个tensor的list。
- ids:用来查找项的索引;type:整型list或tensor,1-D/mul-D都可。
- partition_strategy:分隔策略,指定了怎样由索引去查找对应项。type:”mod” 或 “div”。
只有在len(params) > 1
时才有用,即params是由多个tensor构成时才有用。
- return:返回一个tensor,表示查到的params的行。shape为ids的shape再加上所查到的行,即rank = ids_rank + 1。
- partition_strategy进一步解释:
- 默认为
mod
:按余数来分隔各个tensor,0~n-1分别表示第一个tensor到最后一个tensor的第一项,n~2n-1分别表示第一个tensor到最后一个tensor的第二项,以此类推; div
:按除数来分隔tensor,从前到后依次查找每个tensor中的元素。
example code:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42# params为单个tensor的情况
params = tf.constant([[10, 20, 30],[40, 50, 60]])
ids = tf.constant([0, 1, 1])
print(tf.nn.embedding_lookup(params,ids).eval())
# 输出
# [[10 20 30]
# [40 50 60]
# [40 50 60]]
# params为多个tensor的情况,需要指定分隔策略
params1 = tf.constant([[10, 20, 30],[40, 50, 60]])
params2 = tf.constant([[70, 80, 90],[100, 110, 120]])
ids = tf.constant([0, 1, 2, 3])
print(tf.nn.embedding_lookup([params1, params2],ids).eval())
# 输出
# [[ 10 20 30]
# [ 70 80 90]
# [ 40 50 60]
# [100 110 120]]
print(tf.nn.embedding_lookup([params1, params2],ids, partition_strategy='div').eval())
# div分隔策略下,输出为
# [[ 10 20 30]
# [ 40 50 60]
# [ 70 80 90]
# [100 110 120]]
# 若ids是多维的,查到的内容不变,则仅仅是将查找结果整理成相应的多维数组的形式而已。
params1 = tf.constant([[10, 20, 30],[40, 50, 60]])
params2 = tf.constant([[70, 80, 90],[100, 110, 120]])
ids = tf.constant([[0, 1], [2, 3]])
print(tf.nn.embedding_lookup([params1, params2],ids, partition_strategy='div').eval())
# 输出
# [[[ 10 20 30]
# [ 40 50 60]]
# [[ 70 80 90]
# [100 110 120]]]
- 默认为
如何构建词汇表
词汇表本质是一个word: id字典,用于将token词和对应的整数映射起来,即把每个词变成一个独立的整数,这样我们就可以通过相应的index来存储、操作token,节省存储空间、加快速度,也便于后期做词嵌入。
tensorflow有VocabularyProcessor
和tf.keras.preprocessing.text.Tokenizer
两种实现方法,下面分别介绍。
VocabularyProcessor类
- 这个类tensoflow官方已经不推荐使用了(替代手段为
tf.keras.preprocessing.text.Tokenizer
的相关API),但因为有时要阅读别人代码,所以还是简单总结下这个类的使用方法。 - 构造方法:tf.contrib.learn.preprocessing.VocabularyProcessor (max_document_length, min_frequency=0, vocabulary=None, tokenizer_fn=None)
max_document_length:文档的最大长度。如果文本的长度大于最大长度,那么它会被剪切,反之则用0填充;
min_frequency:词频的最小值,出现次数小于最小词频的词不会被收录到词汇表中;
vocabulary:CategoricalVocabulary对象,直接none就行;
tokenizer_fn:分词函数,直接none就行。 example code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17from tensorflow.contrib import learn
import numpy as np
max_document_length = 4
x_text =[
'i love you',
'me too'
]
vocab_processor = learn.preprocessing.VocabularyProcessor(max_document_length)
vocab_processor.fit(x_text) # 训练一个词汇表
print(next(vocab_processor.transform(['i me too'])).tolist()) # 输出index形式的文档
x = np.array(list(vocab_processor.transform(x_text)))
print(x)
# 输出
[1, 4, 5, 0]
[[1 2 3 0]
[4 5 0 0]]一些常用函数:
VocabularyProcessor.fit():训练词汇表,词汇表第0位默认为<UNK>
(”: 0”),用于标示不在词汇表中的词;
VocabularyProcessor.transform():根据词汇表将句子转化成相应的数字序列,并返回;
VocabularyProcessor.fit_transform():先训练一个词汇表,再返回训练集的数字序列;
VocabularyProcessor.vocabulary_.mapping[key]:根据key(即token词)取对应id;
VocabularyProcessor.vocabulary.mapping.get(key, default=None):根据key(即token词)取对应id,没取到返回的default参数值;
VocabularyProcessor.vocabulary._mapping.keys():返回所有keys;
tf.keras.preprocessing.text.Tokenizer类
1 | # Tokenizer |
更多见:文本预处理方法小记-知乎
关于collection
tf.add_to_collection
add_to_collection(
name,
value
)
- 函数作用:将某个变量添加到默认graph的某个collection中(是
tf.tf.get_default_graph().add_to_collection
的简写形式)。 - 参数解释:
- name:collection的名字,若collection不存在则自动创建一个并添加;
- value:要被添加的变量;
- return:无返回值。
其他函数
关于axis参数和dimension的理解
- 在Tensorflow和numpy的函数中,经常会有
axis
这个参数,这是一个和维度dimension息息相关的概念,下面来进行介绍。 - axis:中文意思为“轴”,本质是一个方向!表示在当前维度上数量增加的方向,与笛卡尔坐标系中的x轴和y轴表达是一个意思。
- axis是从0开始计数的,在一个矩阵/2D tensor中,axis0表示竖直方向,axis1表示水平方向。在更高维的张量中,axis0、axis1也是表示相同的方向。
- 但注意,在一维tensor(即数组/向量)中axis的表示有些不同,一维tensor只有一个axis,为axis0,且axis0的方向是水平的。原因在于:一维tensor本质应该是列向量,这样axis0方向就是竖直的了,与高维tensor统一;但因为人们的表示习惯,把一维tensor表示为行向量了,因此才会有axis0的差异。
- dimension:维度,本质和axis是一样的,也是指方向。但有两种上下文的理解:1、这个东西是几维几维的,是指这个东西有多少个“方向”来描述;2、这个东西的1维2维3维,是指第几个方向,即1维对应axis 0,2维对应axis 1,这样。
- 详细解释参照:NUMPY AXES EXPLAINED
tf.split
tf.split(
value,
num_or_size_splits,
axis=0,
num=None,
name=’split’
)
- 函数作用:将大tensor分割成几个小tensor
- 参数解释:
- value:输入数据,为tensor类型;
- num_or_size_splits:指定了两种分割策略。若输入的是一个整数n,则会在axis维度上平均分成n个小tensor;若输入的是一个tensor/list,则会按照指定的大小来分;
- axis:指定了要沿哪个维度来分,注意维度的计数从0开始。
- return:包含被分割的小tensor的list
- example code:
1
2
3
4
5
6
7
8
9
10
11value = tf.get_variable(name="value", shape=[5, 30])
# 平均分 & 沿维度1分
split0, split1, split2 = tf.split(value, num_or_size_splits=3, axis=1)
print(split0.shape) # [5, 10]
# 按指定的大小分 & 沿维度1分
split0, split1, split2 = tf.split(value, [4, 15, 11], 1)
print(split0.shape) # [5, 4]
print(split1.shape) # [5, 15]
print(split2.shape) # [5, 11]
tf.concat
tf.concat(
values,
axis,
name=’concat’
)
- 函数作用:将多个小tensor拼接为一个大tensor(沿着axis指定的维度)
- 参数解释:
- values:将要拼接的tensor集合;type:list of tensor。
- axis:在哪个维度上进行拼接;type:int;
- 返回值:一个拼接后的新tensor。
- 注:待拼接的各个tensor,除了axis维度,其他维度的长度必须相等。
tf.reshape
tf.reshape(
tensor,
shape,
name=None
)
- 函数作用:改变一个tensor的shape。
- 参数解释:
- tensor:原tensor。
- shape:要被改变成的shape;type:list;
- 返回值:reshaped tensor。
- 注1:shape中的某个维度可以指定为-1,表示该维度的长度由系统推断,最多只能指定一个维度为-1。如果shape就直接是
[-1]
,则会将原tensor平铺为1-Dtensor。 - 注2:要把元素都填充到新tensor的各个维度中,肯定要以一定的顺序读取原tensor中的元素,那按什么样的顺序进行读取呢?可以理解为深度优先,即先把一个元素所有的低维度子元素读完,再读下一个元素。填充时也是这个顺序。
tf.transpose
tf.transpose(
a,
perm=None,
name=’transpose’,
conjugate=False
)
- 函数作用:对矩阵进行转置。更本质来说是对tensor的维度顺序进行调整,如将第3维调整到第2维,第2维调到第1维等;
- 参数解释:
- a:待转置的tensor;
- perm:在新tensor中原先各维度的排列顺序,即指定如何转置tensor;type:list;默认为[n-1, …, 0],表示从后到前依次转置,即为2-D矩阵的转置方式。
- conjugate:用处不大,只在元素为复数时有用。
- return:转置后的新tensor。
- example code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26x = tf.constant([[1, 2, 3], [4, 5, 6]])
tf.transpose(x)
# [[1, 4]
# [2, 5]
# [3, 6]]
# Equivalently
tf.transpose(x, perm=[1, 0])
# [[1, 4]
# [2, 5]
# [3, 6]]
# 'perm' is more useful for n-dimensional tensors, for n > 2
x = tf.constant([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
# (2, 2, 3) shape转置为 (2, 3, 2) shape
tf.transpose(x, perm=[0, 2, 1])
# [[[1, 4],
# [2, 5],
# [3, 6]],
# [[7, 10],
# [8, 11],
# [9, 12]]]
tf.squeeze
tf.squeeze(
input,
axis=None,
name=None
)
- 函数作用:去除tensor中大小为1的维度(因为这些维度本身意义不大)。对应了函数名squeeze“挤压”。
- 参数解释:
- input:输入tensor
- axis:可以自己指定要去除具体哪一个大小为1的维度,list类型
- return:返回一个处理后的tensor
- example code
1
2
3
4
5
6# 't' is a tensor of shape [1, 2, 1, 3, 1, 1]
tf.shape(tf.squeeze(t)) # [2, 3]
# remove specific size 1 dimensions
# 't' is a tensor of shape [1, 2, 1, 3, 1, 1]
tf.shape(tf.squeeze(t, [2, 4])) # [1, 2, 3, 1]
tf.expand_dims
tf.expand_dims(
input,
axis=None,
name=None,
dim=None(deprecated)
)
- 函数作用:对tensor添加维度,添加的维度长度为1。常用来对tensor增加batch维。
- 参数解释:
- input:待操作的tensor;
- axis:指定在哪个位置添加维度,位置从0开始;
- dim:这是deprecated的参数,不推荐使用;
- return:改变后的tensor。
- example code
1
2
3
4
5
6
7
8
9# 't' is a tensor of shape [2]
tf.shape(tf.expand_dims(t, 0)) # [1, 2]
tf.shape(tf.expand_dims(t, 1)) # [2, 1]
tf.shape(tf.expand_dims(t, -1)) # [2, 1]
# 't2' is a tensor of shape [2, 3, 5]
tf.shape(tf.expand_dims(t2, 0)) # [1, 2, 3, 5]
tf.shape(tf.expand_dims(t2, 2)) # [2, 3, 1, 5]
tf.shape(tf.expand_dims(t2, 3)) # [2, 3, 5, 1]
tf.tile
tf.tile(
input,
multiples,
name=None
)
- 函数作用:通过多次复制一个tensor的方式构造新tensor。可以理解为用tf.concat拼接相同的tensor。
- 参数解释:
- input:将要被复制的tensor;
- multiple:指定input中各个维度将要被复制的次数;type:list,且长度必须和input的维度数相等。
- return:所构造的新tensor。
- example code
1
2
3
4
5
6
7
8
9
10
11
12
13
14with tf.Session():
x = tf.constant([[1, 2, 3], [4, 5, 6]])
y1 = tf.tile(x, [2, 1])
y2 = tf.tile(x, [1, 2])
print(y1.eval())
print(y2.eval())
# 输出:
# [[1 2 3]
# [4 5 6]
# [1 2 3]
# [4 5 6]]
# [[1 2 3 1 2 3]
# [4 5 6 4 5 6]]
tf.stack
tf.stack(
values,
axis=0,
name=’stack’
)
- 函数作用:将一个list内的多个tensor叠成一个(rank+1)的tensor,多的那一维就是tensor的数量。
- 与tf.concat的区别,stack可以用来叠加scalar,concat则多用来叠加tensor。
- 参数解释:
- values:list of tensor;
- axis:要叠到新tensor的哪个维度上,默认为0,即各个tensor以行的形式进行排列。
- return:返回新的tensor
- example code
1
2
3
4
5x = tf.constant([1, 4])
y = tf.constant([2, 5])
z = tf.constant([3, 6])
tf.stack([x, y, z]) # [[1, 4], [2, 5], [3, 6]] (Pack along first dim.)
tf.stack([x, y, z], axis=1) # [[1, 2, 3], [4, 5, 6]]
tf.math.zero_fraction
tf.math.zero_fraction(
value,
name=None
)
- Aliases:tf.nn.zero_fraction
- 函数作用:返回value中值为0的元素所占的比例。因为relu激活函数有时会大面积的将输入参数设为0,所以此函数可以有效衡量relu激活函数的有效性。
tf.gather()
tf.gather(
params,
indices,
validate_indices=None,
name=None,
axis=None,
batch_dims=0
)
- “切片函数”:默认从axis=0维切片(即获取axis=1~:的部分),然后将切的slice填到indices对应的元素中。
- 参数解释:
- params:待切片的tensor;
- indices:指定了第一维中要切哪些的下标
- example
1
2
3params = [[0, 1], [2, 3]]
indices = [[0, 0], [1, 1]]
output = [[[0, 1], [0, 1]], [[2, 3], [2, 3]]]
tf.gather_nd()
tf.gather_nd(
params,
indices,
name=None,
batch_dims=0
)
- 也是“切片函数”,和gather()的区别就是:并非从axis=0切片,而是根据indices[-1]维来切片,即按照indices中最后一维元素值来访问params的下标,取params中对应下标元素的slice,然后将切后的slice作为indices中的最后一维元素来填充。
- 参数解释:
- params:待切片的tensor;
- indices:最后一维指定的元素指定了如何访问下标(要切哪些下标)。
1
2
3params = [[0, 1], [2, 3]]
indices = [[0, 0], [1, 1]]
output = [0, 3]
tf.reduce_sum(input_tensor, axis)
- 将tensor中axis维的元素相加,相加后axis维就没了,tenosr的总rank数即减少1,因此叫reduce.
- 如果不指定axis,则tensor中所有元素相加,最后返回一个scalar。
tf.reduce_mean(input_tensor, axis)
- 和
reduce_sum
类似,唯一不同是sum是做加法,mean是做平均。
如何设置GPU的使用
- 通过
CUDA_VISIBLE_DEVICES
环境变量可以设置程序可以看到的GPU,因此也就只能使用相应的GPU。注:这种方法不仅会对tensorflow程序生效,对所有的程序都会生效。 - 两种设置方式:
- 在python程序中设置(推荐),
os.environ["CUDA_VISIBLE_DEVICES"] = "2, 3"
,后面的数是GPU的序号,可通过nvidia-smi
命令来查看。这种设置方法只对此python程序有效,推荐。 - 在命令行中设置,
export CUDA_VISIBLE_DEVICES = "2, 3"
。
- 在python程序中设置(推荐),
杂七杂八
- tensorflow中
*
实现为element-wise乘法,即tensor的对应项乘,要求左右两边tensor shape一致,因此乘出来的tensor shape也会一致。
Post Date: 2019-03-06
版权声明: 本文为原创文章,转载请注明出处