Tensorflow中的tensorflow.nn模块是TensorFlow用于深度学习计算的核心模块。
主要的API:
激活函数(Activation Functions)
操作 描述 tf.nn.relu(features, name=None) 整流函数:max(features, 0) tf.nn.relu6(features, name=None) 以6为阈值的整流函数:min(max(features, 0), 6) tf.nn.elu(features, name=None) elu函数,exp(features) - 1 if < 0,否则featuresExponential Linear Units (ELUs) tf.nn.softplus(features, name=None) 计算softplus:log(exp(features) + 1) tf.nn.dropout(x, keep_prob, noise_shape=None, seed=None, name=None) 计算dropout,keep_prob为keep概率, noise_shape为噪声的shape tf.nn.bias_add(value, bias, data_format=None, name=None) 对value加一偏置量 此函数为tf.add的特殊情况,bias仅为一维, 函数通过广播机制进行与value和, 数据格式可以与value不同,返回为与value相同格式 tf.sigmoid(x, name=None) y = 1 / (1 + exp(-x)) tf.tanh(x, name=None) tf.tanh(x, name=None) 卷积函数(Convolution)
操作 描述 tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, data_format=None, name=None) 在给定的4D input与 filter下计算2D卷积输入shape为 [batch, height, width, in_channels] tf.nn.conv3d(input, filter, strides, padding, name=None) 在给定的5D input与 filter下计算3D卷积输入shape为[batch, in_depth, in_height, in_width, in_channels] tf.nn.depthwise_conv2d(input, filter, strides, padding, name=None) 卷积核能相互独立的在自己的通道上面进行卷积操作。 tf.nn.separable_conv2d(input, depthwise_filter, pointwise_filter, strides, padding, name=None) 在纵深卷积 depthwise filter 之后进行逐点卷积 separable filter 注意,虽然这些操作被称之为“卷积”操作,但是严格的说,他们只是互相关,因为卷积核没有做一个逆向的卷积过程
池化函数(Pooling)
操作 描述 tf.nn.avg_pool(value, ksize, strides, padding, data_format=’NHWC’, name=None) 平均方式池化 tf.nn.max_pool(value, ksize, strides, padding, data_format=’NHWC’, name=None) 最大值方法池化 tf.nn.max_pool_with_argmax(input, ksize, strides,padding, Targmax=None, name=None) 返回一个二维元组(output,argmax),最大值pooling,返回最大值及其相应的索引 tf.nn.avg_pool3d(input, ksize, strides, padding, name=None) 3D平均值pooling tf.nn.max_pool3d(input, ksize, strides, padding, name=None) 3D最大值pooling 数据标准化(Normalization)
操作 描述 tf.nn.l2_normalize(x, dim, epsilon=1e-12, name=None) 对维度dim进行L2范式标准化output = x / sqrt(max(sum(x2), epsilon)) tf.nn.sufficient_statistics(x, axes, shift=None, keep_dims=False, name=None) 计算与均值和方差有关的完全统计量返回4维元组,元素个数,元素总和,元素的平方和,shift结果参见算法介绍 tf.nn.normalize_moments(counts, mean_ss, variance_ss, shift, name=None) 基于完全统计量计算均值和方差 tf.nn.moments(x, axes, shift=None, name=None, keep_dims=False) 直接计算均值与方差 tf.nn.local_response_normalization(input, depth_radius=None, bias=None, alpha=None, beta=None, name=None) 这个函数的作用是计算局部数据标准化。输入的数据 input 是一个四维的张量,但该张量被看做是一个一维的向量( input 的最后一维作为向量),向量中的每一个元素都是一个三维的数组(对应 input 的前三维)。向量的每一个元素都是独立的被标准化的。 损失函数(Losses)
操作 描述 tf.nn.l2_loss(t, name=None) output = sum(t ** 2) / 2 分类函数(Classification)
操作 描述 tf.nn.sigmoid_cross_entropy_with_logits(logits, targets, name=None)* 计算输入logits, targets的交叉熵 tf.nn.softmax(logits, name=None) 计算softmax softmax[i, j] = exp(logits[i, j]) / sum_j(exp(logits[i, j])) tf.nn.log_softmax(logits, name=None) logsoftmax[i, j] = logits[i, j] - log(sum(exp(logits[i]))) tf.nn.softmax_cross_entropy_with_logits(logits, labels, name=None) 计算logits和labels的softmax交叉熵logits, labels必须为相同的shape与数据类型 tf.nn.sparse_softmax_cross_entropy_with_logits(logits, labels, name=None) 计算logits和labels的softmax交叉熵 tf.nn.weighted_cross_entropy_with_logits(logits, targets, pos_weight, name=None) 与sigmoid_cross_entropy_with_logits()相似,但给正向样本损失加了权重pos_weight 符号嵌入(Embeddings)
操作 描述 tf.nn.embedding_lookup(params, ids, partition_strategy=’mod’, name=None, validate_indices=True) 根据索引ids查询embedding列表params中的tensor值, 如果len(params) > 1,id将会安照partition_strategy策略进行分割 1、如果partition_strategy为”mod”,id所分配到的位置为p = id % len(params)比如有13个ids,分为5个位置,那么分配方案为:[[0, 5, 10], [1, 6, 11], [2, 7, 12], [3, 8], [4, 9]] , 2、如果partition_strategy为”div”,那么分配方案为: [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10], [11, 12]] tf.nn.embedding_lookup_sparse(params, sp_ids, sp_weights, partition_strategy=’mod’, name=None, combiner=’mean’) 对给定的ids和权重查询embedding 1、sp_ids为一个N x M的稀疏tensor,N为batch大小,M为任意,数据类型int64, 2、sp_weights的shape与sp_ids的稀疏tensor权重,浮点类型,若为None,则权重为全’1’ 求值网络(Evaluation)
操作 描述 tf.nn.top_k(input, k=1, sorted=True, name=None) 返回前k大的值及其对应的索引 tf.nn.in_top_k(predictions, targets, k, name=None) 返回判断是否targets索引的predictions相应的值是否在在predictions前k个位置中,返回数据类型为bool类型,len与predictions同 监督候选采样网络(Candidate Sampling)
对于有巨大量的多分类与多标签模型,如果使用全连接softmax将会占用大量的时间与空间资源,所以采用候选采样方法仅使用一小部分类别与标签作为监督以加速训练扫描二维码关注公众号,回复: 3127632 查看本文章操作 描述 Sampled Loss Functions tf.nn.nce_loss(weights, biases, inputs, labels, num_sampled,num_classes, num_true=1, sampled_values=None,remove_accidental_hits=False, partition_strategy=’mod’,name=’nce_loss’) 返回noise-contrastive的训练损失结果 tf.nn.sampled_softmax_loss(weights, biases, inputs, labels, num_sampled, num_classes, num_true=1, sampled_values=None,remove_accidental_hits=True, partition_strategy=’mod’, name=’sampled_softmax_loss’) 返回sampled softmax的训练损失 参考- Jean et al., 2014第3部分 Candidate Samplers tf.nn.uniform_candidate_sampler(true_classes, num_true, num_sampled, unique, range_max, seed=None, name=None) 通过均匀分布的采样集合返回三元tuple 1、sampled_candidates 候选集合。 2、期望的true_classes个数,为浮点值 3、期望的sampled_candidates个数,为浮点值 tf.nn.log_uniform_candidate_sampler(true_classes, num_true,num_sampled, unique, range_max, seed=None, name=None) 通过log均匀分布的采样集合,返回三元tuple tf.nn.learned_unigram_candidate_sampler(true_classes, num_true, num_sampled, unique, range_max, seed=None, name=None) 根据在训练过程中学习到的分布状况进行采样 返回三元tuple tf.nn.fixed_unigram_candidate_sampler(true_classes, num_true,num_sampled, unique, range_max, vocab_file=”, distortion=1.0, num_reserved_ids=0, num_shards=1, shard=0, unigrams=(), seed=None, name=None) 基于所提供的基本分布进行采样 保存与恢复变量
操作 | 描述 |
---|---|
类tf.train.Saver(Saving and Restoring Variables) | |
tf.train.Saver.init(var_list=None, reshape=False, sharded=False, max_to_keep=5, keep_checkpoint_every_n_hours=10000.0, name=None, restore_sequentially=False,saver_def=None, builder=None) | 创建一个存储器Savervar_list定义需要存储和恢复的变量 |
tf.train.Saver.save(sess, save_path, global_step=None, latest_filename=None, meta_graph_suffix=’meta’,write_meta_graph=True) | 保存变量 |
tf.train.Saver.restore(sess, save_path) | tf.train.Saver.restore(sess, save_path) |
tf.train.Saver.last_checkpoints | 列出最近未删除的checkpoint 文件名 |
tf.train.Saver.set_last_checkpoints(last_checkpoints) | 设置checkpoint文件名列表 |
tf.train.Saver.set_last_checkpoints_with_time(last_checkpoints_with_time) | 设置checkpoint文件名列表和时间戳 |
- 循环神经网络(Recurrent Neural Networks)
操作 | 描述 |
---|---|
tf.nn.rnn(cell, inputs, initial_state=None, dtype=None, sequence_length=None, scope=None) | 基于RNNCell类的实例cell建立循环神经网络 |
tf.nn.dynamic_rnn(cell, inputs, sequence_length=None, initial_state=None, dtype=None, parallel_iterations=None, swap_memory=False, time_major=False, scope=None) | 基于RNNCell类的实例cell建立动态循环神经网络与一般rnn不同的是,该函数会根据输入动态展开返回(outputs,state) |
tf.nn.state_saving_rnn(cell, inputs, state_saver, state_name, sequence_length=None, scope=None) | 可储存调试状态的RNN网络 |
tf.nn.bidirectional_rnn(cell_fw, cell_bw, inputs,initial_state_fw=None, initial_state_bw=None, dtype=None,sequence_length=None, scope=None) | 双向RNN, 返回一个3元组tuple (outputs, output_state_fw, output_state_bw) |
-— tf.nn.rnn简要介绍—
cell: 一个RNNCell实例
inputs: 一个shape为[batch_size, input_size]的tensor
initial_state: 为RNN的state设定初值,可选
sequence_length:制定输入的每一个序列的长度,size为[batch_size],值范围为[0, T)的int型数据
其中T为输入数据序列的长度
@
@针对输入batch中序列长度不同,所设置的动态计算机制
@对于在时间t,和batch的b行,有
(output, state)(b, t) = ? (zeros(cell.output_size), states(b, sequence_length(b) - 1)) : cell(input(b, t), state(b, t - 1))
详细用法(举例说明):
激活函数
- tf.nn.relu ( features, name = None )
- 解释:这个函数的作用是计算激活函数 relu,即 max ( features, 0 )
- 输入参数:features: 一个Tensor。数据类型必须是:float32,float64,int3, int64,uint8,int16,int8,name: (可选)为这个操作取一个名字
- 输出参数:一个Tensor,数据类型和features相同
- 例子:
import tensorflow as tf
a = tf.constant([-2.0, -1.0, 2.0, 3.0])
with tf.Session() as sess:
b = tf.nn.relu(a)
print(sess.run(b))
## 输出: [0. 0. 2. 3.]
- tf.nn.relu6(features, name = None)
- 解释:这个函数的作用是计算激活函数relu6,即min(max(features, 0), 6)
- 输入参数:features: 一个Tensor。数据类型必须是:float,double,int32, int64,uint8,int16或者int8, name: (可选)为这个操作取一个名字
- 输出参数:一个Tensor,数据类型和features相同
- 例子:
import tensorflow as tf
a = tf.constant([-2.0, -1.0, 1.0, 5.0, 10.0])
with tf.Session() as sess:
b = tf.nn.relu6(a)
print(sess.run(b))
## 输出: [0. 0. 1. 5. 6.]
- tf.nn.softplus(features, name = None)
- 解释:这个函数的作用是计算激活函数softplus,即log( exp( features ) + 1)
- 输入参数:features: 一个Tensor。数据类型必须是:float32,float64,int32,int64,uint8,int16或者int8, name: (可选)为这个操作取一个名字。
- 输出参数:一个Tensor,数据类型和features相同
- 例子:
import tensorflow as tf
a = tf.constant([0.0, 1.0])
with tf.Session() as sess:
b = tf.nn.softplus(a)
print(sess.run(b))
## 输出: [ 0.69314718 1.31326163]
- tf.nn.dropout(x, keep_prob, noise_shape = None, seed = None, name = None)
- 解释:这个函数的作用是计算神经网络层的dropout,一个神经元将以概率keep_prob决定是否被激活,如果不被激活,那么该神经元的输出将是0,如果该神经元被激活,那么该神经元的输出值将被放大到原来的1/keep_prob倍。这里的放大操作是为了保持神经元输出总和不变。默认情况下,每个神经元是否被激活是相互独立的。但是,如果noise_shape被修改了,那么他对于变量x就是一个广播形式,而且当且仅当 noise_shape[i] == shape(x)[i] ,x中的元素是相互独立的。比如,如果 shape(x) = [k, l, m, n], noise_shape = [k, 1, 1, n] ,那么每个批和通道都是相互独立的,但是每行和每列的数据都是关联的,即要不都为0,要不都还是原来的值。
- 输入参数:
x: 一个Tensor。
keep_prob: 一个 Python 的 float 类型。表示元素是否放电的概率。
noise_shape: 一个一维的Tensor,数据类型是int32。代表元素是否独立的标志。
seed: 一个Python的整数类型。设置随机种子。
name: (可选)为这个操作取一个名字。 - 输出参数:一个Tensor,数据维度和x相同。
异常:输入异常: 如果 keep_prob 不是在 (0, 1]区间,那么会提示错误。 - 例子:
import tensorflow as tf
a = tf.constant([[-1.0, 2.0, 3.0, 4.0]])
with tf.Session() as sess:
b = tf.nn.dropout(a, 0.5)
print(sess.run(b))
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))
## 输出: [[-2. 0. 0. 8.]]
# [[-2. 4. 0. 0.]]
# [[-0. 0. 0. 0.]]
- tf.nn.bias_add(value, bias, name = None)
- 解释:这个函数的作用是将偏差项 bias 加到 value 上面。这个操作你可以看做是 tf.add 的一个特例,其中 bias 必须是一维的。该API支持广播形式,因此 value 可以有任何维度。但是,该API又不像 tf.add ,可以让 bias 的维度和 value 的最后一维不同。
- 输入参数:
value: 一个Tensor。数据类型必须是float,double,int64,int32,uint8,int16,int8或者complex64。
bias: 一个一维的Tensor,数据维度和 value 的最后一维相同。数据类型必须和value相同。
name: (可选)为这个操作取一个名字。 - 输出参数:一个Tensor,数据类型和value相同。
- 例子:
import tensorflow as tf
a = tf.constant([[1.0, 2.0],[1.0, 2.0],[1.0, 2.0]])
b = tf.constant([2.0,1.0])
c = tf.constant([1.0])
sess = tf.Session()
print(sess.run(tf.nn.bias_add(a, b)))
# 因为 a 最后一维的维度是 2 ,但是 c 的维度是 1,所以以下语句将发生错误
print(sess.run(tf.nn.bias_add(a, c)))
# 但是 tf.add() 可以正确运行
print(sess.run(tf.add(a, c)))
- tf.sigmoid(x, name = None)
- 解释:这个函数的作用是计算 x 的 sigmoid 函数。具体计算公式为 y = 1 / (1 + exp(-x))。
- 输入参数:
x: 一个Tensor。数据类型必须是float,double,int32,complex64,int64或者qint32。
name: (可选)为这个操作取一个名字。 - 输出参数:一个Tensor,如果 x.dtype != qint32 ,那么返回的数据类型和x相同,否则返回的数据类型是 quint8 。
- 例子:
import tensorflow as tf
a = tf.constant([[1.0, 2.0], [1.0, 2.0], [1.0, 2.0]])
sess = tf.Session()
print(sess.run(tf.sigmoid(a)))
## 输出: [[0.7310586 0.880797 ]
# [0.7310586 0.880797 ]
# [0.7310586 0.880797 ]]
- tf.tanh(x, name = None)
- 解释:这个函数的作用是计算 x 的 tanh 函数。具体计算公式为 ( exp(x) - exp(-x) ) / ( exp(x) + exp(-x) )。
- 输入参数:
x: 一个Tensor。数据类型必须是float,double,int32,complex64,int64或者qint32。
name: (可选)为这个操作取一个名字。 - 输出参数:一个Tensor,如果 x.dtype != qint32 ,那么返回的数据类型和x相同,否则返回的数据类型是 quint8 。
- 例子:
import tensorflow as tf
a = tf.constant([[1.0, 2.0],[1.0, 2.0],[1.0, 2.0]])
sess = tf.Session()
print(sess.run(tf.tanh(a)))
卷积层
卷积操作是使用一个二维的卷积核在一个批处理的图片上进行不断扫描。具体操作是将一个卷积核在每张图片上按照一个合适的尺寸在每个通道上面进行扫描。为了达到好的卷积效率,需要在不同的通道和不同的卷积核之间进行权衡。
conv2d: 任意的卷积核,能同时在不同的通道上面进行卷积操作。
depthwise_conv2d: 卷积核能相互独立的在自己的通道上面进行卷积操作。
separable_conv2d: 在纵深卷积 depthwise filter 之后进行逐点卷积 separable filter 。
注意,虽然这些操作被称之为“卷积”操作,但是严格的说,他们只是互相关,因为卷积核没有做一个逆向的卷积过程。
卷积核的卷积过程是按照 strides 参数来确定的,比如 strides = [1, 1, 1, 1] 表示卷积核对每个像素点进行卷积,即在二维屏幕上面,两个轴方向的步长都是1。strides = [1, 2, 2, 1] 表示卷积核对每隔一个像素点进行卷积,即在二维屏幕上面,两个轴方向的步长都是2。
如果我们先暂且不考虑通道这个因素,那么卷积操作的空间含义定义如下:如果输入数据是一个四维的 input ,数据维度是 [batch, in_height, in_width, …],卷积核也是一个四维的卷积核,数据维度是 [filter_height, filter_width, …] ,那么:
shape(output) = [batch,
(in_height - filter_height + 1) / strides[1],
(in_width - filter_width + 1) / strides[2],
…]
output[b, i, j, :] =
sum_{di, dj} input[b, strides[1] * i + di, strides[2] * j + dj, …] *
filter[di, dj, …]
因为,input 数据是一个四维的,每一个通道上面是一个向量 input[b, i, j, :] 。对于 conv2d ,这些向量将会被卷积核 filter[di, dj, :, :] 相乘而产生一个新的向量。对于 depthwise_conv_2d ,每个标量分量 input[b, i, j, k] 将在 k 个通道上面独立的被卷积核 filter[di, dj, k] 进行卷积操作,然后把所有得到的向量进行连接组合成一个新的向量。
对于输出数据的维度 shape(output),这取决于填充参数 padding 的设置:
padding = ‘SAME’: 向下取舍,仅适用于全尺寸操作,即输入数据维度和输出数据维度相同。
padding = ‘VALID: 向上取舍,适用于部分窗口,即输入数据维度和输出数据维度不同。
- .tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)
- 解释:这个函数的作用是对一个四维的输入数据 input 和四维的卷积核 filter 进行操作,然后对输入数据进行一个二维的卷积操作,最后得到卷积之后的结果。
- 输入参数:
input: 一个Tensor。数据类型必须是float32或者float64。
filter: 一个Tensor。数据类型必须是input相同。
strides: 一个长度是4的一维整数类型数组,每一维度对应的是 input 中每一维的对应移动步数,比如,strides[1] 对应 input[1] 的移动步数。
padding: 一个字符串,取值为 SAME 或者 VALID 。
use_cudnn_on_gpu: 一个可选布尔值,默认情况下是 True 。
name: (可选)为这个操作取一个名字。 - 输出参数:一个Tensor,数据类型是 input 相同
- 例子:
import numpy as np
import tensorflow as tf
input_data = tf.Variable( np.random.rand(10,6,6,3), dtype = np.float32 )
filter_data = tf.Variable( np.random.rand(2, 2, 3, 1), dtype = np.float32)
y = tf.nn.conv2d(input_data, filter_data, strides = [1, 1, 1, 1], padding = 'SAME')
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
print(sess.run(y))
print(sess.run(tf.shape(y)))
- tf.nn.depthwise_conv2d(input, filter, strides, padding, name=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 。
更加具体公式如下:
output[b, i, j, k * channel_multiplier + q] =
sum_{di, dj} input[b, strides[1] * i + di, strides[2] * j + dj, k] *
filter[di, dj, k, q]
注意,必须有 strides[0] = strides[3] = 1。在大部分处理过程中,卷积核的水平移动步数和垂直移动步数是相同的,即 strides = [1, stride, stride,1]。 - 输入参数:
input: 一个Tensor。数据维度是四维 [batch, in_height, in_width, in_channels]。
filter: 一个Tensor。数据维度是四维 [filter_height, filter_width, in_channels, channel_multiplier]。
strides: 一个长度是4的一维整数类型数组,每一维度对应的是 input 中每一维的对应移动步数,比如,strides[1] 对应 input[1] 的移动步数。
padding: 一个字符串,取值为 SAME 或者 VALID 。
use_cudnn_on_gpu: 一个可选布尔值,默认情况下是 True 。
name: (可选)为这个操作取一个名字。 - 输出参数:
一个四维的Tensor,数据维度为 [batch, out_height, out_width, in_channels * channel_multiplier]。 - 例子:
- 解释:这个函数也是一个卷积操作。给定一个输入张量,数据维度是 [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 。
import numpy as np
import tensorflow as tf
input_data = tf.Variable( np.random.rand(10, 6, 6, 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')
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
print(sess.run(y))
print(sess.run(tf.shape(y)))
- tf.nn.separable_conv2d(input, depthwise_filter, pointwise_filter, strides, padding, name=None)
- 解释:这个函数的作用是利用几个分离的卷积核去做卷积,可以参考这个解释 ( https://stackoverflow.com/questions/37092037/tensorflow-what-does-tf-nn-separable-conv2d-do )。这个卷积是为了避免卷积核在全通道的情况下进行卷积,这样非常浪费时间。使用这个API,你将应用一个二维的卷积核,在每个通道上,以深度 channel_multiplier 进行卷积。其实如上图 Separable Convolution 中,就是先利用 depthwise_filter ,将 ID 的通道数映射到 ID * DM 的通道数上面,之后从 ID * DM 的通道数映射到 OD 的通道数上面,这也就是上面说的深度 channel_multiplier 对应于 DM。
具体公式如下:
output[b, i, j, k] = sum_{di, dj, q, r]
input[b, strides[1] * i + di, strides[2] * j + dj, q] *
depthwise_filter[di, dj, q, r] *
pointwise_filter[0, 0, q * channel_multiplier + r, k]
strides 只是仅仅控制 depthwise convolution 的卷积步长,因为 pointwise convolution 的卷积步长是确定的 [1, 1, 1, 1] 。注意,必须有 strides[0] = strides[3] = 1。在大部分处理过程中,卷积核的水平移动步数和垂直移动步数是相同的,即 strides = [1, stride, stride, 1]。 - 输入参数:
input: 一个Tensor。数据维度是四维 [batch, in_height, in_width, in_channels]。
depthwise_filter: 一个Tensor。数据维度是四维 [filter_height, filter_width, in_channels, channel_multiplier]。其中,in_channels 的卷积深度是 1。
pointwise_filter: 一个Tensor。数据维度是四维 [1, 1, channel_multiplier * in_channels, out_channels]。其中,pointwise_filter 是在 depthwise_filter 卷积之后的混合卷积。
strides: 一个长度是4的一维整数类型数组,每一维度对应的是 input 中每一维的对应移动步数,比如,strides[1] 对应 input[1] 的移动步数。
padding: 一个字符串,取值为 SAME 或者 VALID 。
name: (可选)为这个操作取一个名字。 - 输出参数:
一个四维的Tensor,数据维度为 [batch, out_height, out_width, out_channels]。
异常:
数值异常: 如果 channel_multiplier * in_channels > out_channels ,那么将报错。
- 解释:这个函数的作用是利用几个分离的卷积核去做卷积,可以参考这个解释 ( https://stackoverflow.com/questions/37092037/tensorflow-what-does-tf-nn-separable-conv2d-do )。这个卷积是为了避免卷积核在全通道的情况下进行卷积,这样非常浪费时间。使用这个API,你将应用一个二维的卷积核,在每个通道上,以深度 channel_multiplier 进行卷积。其实如上图 Separable Convolution 中,就是先利用 depthwise_filter ,将 ID 的通道数映射到 ID * DM 的通道数上面,之后从 ID * DM 的通道数映射到 OD 的通道数上面,这也就是上面说的深度 channel_multiplier 对应于 DM。
import numpy as np
import tensorflow as tf
input_data = tf.Variable( np.random.rand(10, 6, 6, 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')
with tf.Session() as sess:
init = tf.tf.global_variables_initializer()
sess.run(init)
print(sess.run(y))
print(sess.run(tf.shape(y)))
池化层
池化操作是利用一个矩阵窗口在输入张量上进行扫描,并且将每个矩阵窗口中的值通过取最大值,平均值或者XXXX来减少元素个数。每个池化操作的矩阵窗口大小是由 ksize 来指定的,并且根据步长参数 strides 来决定移动步长。比如,如果 strides 中的值都是1,那么每个矩阵窗口都将被使用。如果 strides 中的值都是2,那么每一维度上的矩阵窗口都是每隔一个被使用。以此类推。
更具体的输出结果是:
output[i] = reduce( value[ strides * i: strides * i + ksize ] )
输出数据维度是:
shape(output) = (shape(value) - ksize + 1) / strides
其中,取舍方向取决于参数 padding :
padding = ‘SAME’: 向下取舍,仅适用于全尺寸操作,即输入数据维度和输出数据维度相同。
padding = ‘VALID: 向上取舍,适用于部分窗口,即输入数据维度和输出数据维度不同。
- tf.nn.avg_pool(value, ksize, strides, padding, name=None)
- 解释:这个函数的作用是计算池化区域中元素的平均值。
- 输入参数:
value: 一个四维的Tensor。数据维度是 [batch, height, width, channels]。数据类型是float32,float64,qint8,quint8,qint32。
ksize: 一个长度不小于4的整型数组。每一位上面的值对应于输入数据张量中每一维的窗口对应值。
strides: 一个长度不小于4的整型数组。该参数指定滑动窗口在输入数据张量每一维上面的步长。
padding: 一个字符串,取值为 SAME 或者 VALID 。
name: (可选)为这个操作取一个名字。 - 输出参数:
一个Tensor,数据类型和value相同。 - 例子:
import numpy as np
import tensorflow as tf
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')
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
print(sess.run(output))
print(sess.run(tf.shape(output)))
- tf.nn.max_pool(value, ksize, strides, padding, name=None)
- 解释:这个函数的作用是计算池化区域中元素的最大值。
- 输入参数:
value: 一个四维的Tensor。数据维度是 [batch, height, width, channels]。数据类型是float32,float64,qint8,quint8,qint32。
ksize: 一个长度不小于4的整型数组。每一位上面的值对应于输入数据张量中每一维的窗口对应值。
strides: 一个长度不小于4的整型数组。该参数指定滑动窗口在输入数据张量每一维上面的步长。
padding: 一个字符串,取值为 SAME 或者 VALID 。
name: (可选)为这个操作取一个名字。
- 输出参数:
一个Tensor,数据类型和value相同。 - 例子:
- 输出参数:
import numpy as np
import tensorflow as tf
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')
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
print(sess.run(output))
print(sess.run(tf.shape(output)))
- 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 。
- 输入参数:
input: 一个四维的Tensor。数据维度是 [batch, height, width, channels]。数据类型是float32。
ksize: 一个长度不小于4的整型数组。每一位上面的值对应于输入数据张量中每一维的窗口对应值。
strides: 一个长度不小于4的整型数组。该参数指定滑动窗口在输入数据张量每一维上面的步长。
padding: 一个字符串,取值为 SAME 或者 VALID 。
Targmax: 一个可选的数据类型: tf.int32或者tf.int64。默认情况下是 tf.int64 。
name: (可选)为这个操作取一个名字。 - 输出参数:
一个元祖张量 (output, argmax):
output: 一个Tensor,数据类型是float32。表示池化区域的最大值。
argmax: 一个Tensor,数据类型是Targmax。数据维度是四维的。 - 例子:
import numpy as np
import tensorflow as tf
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')
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
print(sess.run(output))
print(sess.run(tf.shape(output)))
标准化
标准化是能防止模型过拟合的好方法。特别是在大数据的情况下
- tf.nn.l2_normalize(x, dim, epsilon=1e-12, name=None)
- 解释:这个函数的作用是利用 L2 范数对指定维度 dim 进行标准化。比如,对于一个一维的张量,指定维度 dim = 0,那么计算结果为:
output = x / sqrt( max( sum( x ** 2 ) , epsilon ) )
假设 x 是多维度的,那么标准化只会独立的对维度 dim 进行,不会影响到别的维度。 - 输入参数:
x: 一个Tensor。
dim: 需要标准化的维度。
epsilon: 一个很小的值,确定标准化的下边界。如果 norm < sqrt(epsilon),那么我们将使用 sqrt(epsilon) 进行标准化。
name: (可选)为这个操作取一个名字。 - 输出参数:
一个 Tensor ,数据维度和 x 相同。 - 例子:
- 解释:这个函数的作用是利用 L2 范数对指定维度 dim 进行标准化。比如,对于一个一维的张量,指定维度 dim = 0,那么计算结果为:
import numpy as np
import tensorflow as tf
input_data = tf.Variable( np.random.rand(2, 3), dtype = tf.float32 )
output = tf.nn.l2_normalize(input_data, dim = 0)
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
print(sess.run(output))
print(sess.run(tf.shape(output)))
- tf.nn.local_response_normalization(input, depth_radius=None, bias=None, alpha=None, beta=None, name=None)
- 解释:这个函数的作用是计算局部数据标准化。
输入的数据 input 是一个四维的张量,但该张量被看做是一个一维的向量( input 的最后一维作为向量),向量中的每一个元素都是一个三维的数组(对应 input 的前三维)。向量的每一个元素都是独立的被标准化的。具体数学形式如下:
sqr_sum[a, b, c, d] =
sum(input[a, b, c, d - depth_radius : d + depth_radius + 1] ** 2)
output = input / (bias + alpha * sqr_sum ** beta)
如果你想更加了解这种标准化,可以参考这篇论文( http://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks )。 - 输入参数:
input: 一个Tensor。数据维度是四维的,数据类型是 float32 。
depth_radius: (可选)一个整型,默认情况下是 5 。
bias: (可选)一个浮点型,默认情况下是 1。一个偏移项,为了避免除0,一般情况下我们取正值。
alpha: (可选)一个浮点型,默认情况下是 1。一个比例因子,一般情况下我们取正值。
beta: (可选)一个浮点型,默认情况下是 0.5。一个指数。
name: (可选)为这个操作取一个名字。 - 输出参数:
一个 Tensor ,数据类型是 float32 。 - 例子:
- 解释:这个函数的作用是计算局部数据标准化。
import numpy as np
import tensorflow as tf
input_data = tf.Variable( np.random.rand(1, 2, 3, 4), dtype = tf.float32 )
output = tf.nn.local_response_normalization(input_data)
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
print(sess.run(input_data))
print(sess.run(output))
print(sess.run(tf.shape(output)))
- tf.nn.moments(x, axes, name=None)
- 解释:这个函数的作用是计算 x 的均值和方差。
沿着 axes 维度,计算 x 的均值和方差。如果 x 是一维的,并且 axes = [0] ,那么就是计算整个向量的均值和方差。
如果,我们取 axes = [0, 1, 2] (batch, height, width),那么我们就是计算卷积的全局标准化。如果只是计算批处理的标准化,那么我们取 axes = [0] (batch) 。 - 输入参数:
x: 一个Tensor。
axes: 一个整型的数组,确定计算均值和方差的维度 。
name: 为这个操作取个名字。 - 输出参数:
两个 Tensor ,分别是均值 mean 和方差 variance 。 - 例子:
- 解释:这个函数的作用是计算 x 的均值和方差。
import numpy as np
import tensorflow as tf
input_data = tf.Variable( np.random.rand(2, 3), dtype = tf.float32 )
mean, variance = tf.nn.moments(input_data, [0])
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
print(sess.run(input_data))
print(sess.run(mean))
print(sess.run(tf.shape(mean)))
损失函数
度量两个张量或者一个张量和零之间的损失误差
- tf.nn.l2_loss(t, name=None)
- 解释:这个函数的作用是利用 L2 范数来计算张量的误差值,但是没有开方并且只取 L2 范数的值的一半,具体如下:
output = sum(t ** 2) / 2 - 输入参数:
t: 一个Tensor。数据类型必须是一下之一:float32,float64,int64,int32,uint8,int16,int8,complex64,qint8,quint8,qint32。虽然一般情况下,数据维度是二维的。但是,数据维度可以取任意维度。
name: 为这个操作取个名字。 - 输出参数:
一个 Tensor ,数据类型和 t 相同,是一个标量。 - 例子:
- 解释:这个函数的作用是利用 L2 范数来计算张量的误差值,但是没有开方并且只取 L2 范数的值的一半,具体如下:
import numpy as np
import tensorflow as tf
input_data = tf.Variable( np.random.rand(2, 3), dtype = tf.float32 )
output = tf.nn.l2_loss(input_data)
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
print(sess.run(input_data))
print(sess.run(output))
print(sess.run(tf.shape(output)))
分类操作
Tensorflow提供了操作,能帮助你更好的进行分类操作。
- tf.nn.sigmoid_cross_entropy_with_logits(logits, targets, name=None)
- 解释:
这个函数的作用是计算 logits 经 sigmoid 函数激活之后的交叉熵
。对于一个不相互独立的离散分类任务,这个函数作用是去度量概率误差。比如,比如,在一张图片中,同时包含多个分类目标(大象和狗),那么就可以使用这个函数。为了描述简洁,我们规定 x = logits,z = targets,那么 Logistic 损失值为:
x - x * z + log( 1 + exp(-x) ), 为了确保计算稳定,避免溢出,真实的计算实现如下:
max(x, 0) - x * z + log(1 + exp(-abs(x)) ), logits 和 targets 必须有相同的数据类型和数据维度。 - 输入参数:
logits: 一个Tensor。数据类型是以下之一:float32或者float64。
targets: 一个Tensor。数据类型和数据维度都和 logits 相同。
name: 为这个操作取个名字。 - 输出参数:
一个 Tensor ,数据维度和 logits 相同。 - 例子:
- 解释:
import numpy as np
import tensorflow as tf
input_data = tf.Variable( np.random.rand(1,3), dtype = tf.float32 )
output = tf.nn.sigmoid_cross_entropy_with_logits(input_data, [[1.0,0.0,0.0]])
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
print(sess.run(input_data))
print(sess.run(output))
print(sess.run(tf.shape(output)))
- tf.nn.softmax(logits, name=None)
- 解释:这个函数的作用是计算 softmax 激活函数。
对于每个批 i 和 分类 j,我们可以得到:
softmax[i, j] = exp(logits[i, j]) / sum(exp(logits[i])) - 输入参数:
logits: 一个Tensor。数据类型是以下之一:float32或者float64。数据维度是二维 [batch_size, num_classes]。
name: 为这个操作取个名字。 - 输出参数:
一个 Tensor ,数据维度和数据类型都和 logits 相同。 - 例子:
- 解释:这个函数的作用是计算 softmax 激活函数。
import numpy as np
import tensorflow as tf
input_data = tf.Variable( [[0.2, 0.1, 0.9]] , dtype = tf.float32 )
output = tf.nn.softmax(input_data)
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
print(sess.run(input_data))
print(sess.run(output))
print(sess.run(tf.shape(output)))
- tf.nn.softmax_cross_entropy_with_logits(logits, labels, name=None)
- 解释:这个函数的作用是计算 logits 经 softmax 函数激活之后的交叉熵。
对于每个独立的分类任务,这个函数是去度量概率误差。比如,在 CIFAR-10 数据集上面,每张图片只有唯一一个分类标签:一张图可能是一只狗或者一辆卡车,但绝对不可能两者都在一张图中。(这也是和 tf.nn.sigmoid_cross_entropy_with_logits(logits, targets, name=None)这个API的区别)
注意:输入API的数据 logits 不能进行缩放,因为在这个API的执行中会进行 softmax 计算,如果 logits 进行了缩放,那么会影响计算正确率。不要调用这个API区计算 softmax 的值,因为这个API最终输出的结果并不是经过 softmax 函数的值。
logits 和 labels 必须有相同的数据维度 [batch_size, num_classes],和相同的数据类型 float32 或者 float - 输入参数:
logits: 一个没有缩放的对数张量。
labels: 每一行 labels[i] 必须是一个有效的概率分布值。
name: 为这个操作取个名字。 - 输出参数:
一个 Tensor ,数据维度是一维的,长度是 batch_size,数据类型都和 logits 相同。 - 例子:
- 解释:这个函数的作用是计算 logits 经 softmax 函数激活之后的交叉熵。
import numpy as np
import tensorflow as tf
input_data = tf.Variable( [[0.2, 0.1, 0.9]] , dtype = tf.float32 )
output = tf.nn.softmax_cross_entropy_with_logits(input_data, [[1,0,0]])
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
print(sess.run(input_data))
print(sess.run(output))
print(sess.run(tf.shape(output)))
嵌入层
Tensorflow 提供了从张量中嵌入查找的库。
- tf.nn.embedding_lookup(params, ids, name=None)
- 解释:这个函数的作用是查询 params 中索引是 ids 的值。
这个操作是 tf.gather() 的一个泛化,但它可以被并行计算处理,其中 params 被认为是一个大型的张量库,ids 中的值对应于各个分区。
如果 len(params) > 1,ids 中每个元素 id 对应于 params 中每个分区 p ,即 p = id % len(params)。那么,我们得到的每个切片是 params[p][id // len(params), …] 。
最后得到的切片结果被重新连接成一个稠密张量,最后返回的张量维度是 shape(ids) + shape(params)[1: ]。 - 输入参数:
params: 一个拥有相同数据维度和数据类型的张量。
ids: 一个张量,数据类型是 int32 。
name: 为这个操作取个名字。 - 输出参数:
一个 Tensor ,数据类型和 params 相同。
异常:
数值异常: 如果 params 是空的,那么会抛出这个异常。 - 例子:
- 解释:这个函数的作用是查询 params 中索引是 ids 的值。
import tensorflow as tf
import numpy as np
params = tf.constant(np.random.rand(3,4))
ids = tf.constant([0,2])
output = tf.nn.embedding_lookup(params, ids)
with tf.Session() as sess:
print('params: ', sess.run(params))
print('-------------------------------')
print('输出第0行和第2行: ', sess.run(output))
评估操作
评估操作对于测量神经网络的性能是有用的。 由于它们是不可微分的,所以它们通常只是被用在评估阶段
- tf.nn.top_k(input, k, name=None)
- 解释:这个函数的作用是返回 input 中每行最大的 k 个数,并且返回它们所在位置的索引。
value(i, j) 表示输入数据 input(i) 的第 j 大的元素。
indices(i, j) 给出对应元素的列索引,即 input(i, indices(i, j)) = values(i, j) 。如果遇到两个相等的元素,那么我们先取索引小的值。 - 输入参数:
input: 一个张量,数据类型必须是以下之一:float32、float64、int32、int64、uint8、int16、int8。数据维度是 batch_size 乘上 x 个类别。
k: 一个整型,必须 >= 1。在每行中,查找最大的 k 个值。
name: 为这个操作取个名字。 - 输出参数:
一个元组 Tensor ,数据元素是 (values, indices),具体如下:
values: 一个张量,数据类型和 input 相同。数据维度是 batch_size 乘上 k 个最大值。
indices: 一个张量,数据类型是 int32 。每个最大值在 input 中的索引位置。 - 例子:
- 解释:这个函数的作用是返回 input 中每行最大的 k 个数,并且返回它们所在位置的索引。
import tensorflow as tf
import numpy as np
input = tf.constant(np.random.rand(3,4))
k = 2
output = tf.nn.top_k(input, k)
with tf.Session() as sess:
print(sess.run(input))
print('--------------------')
print(sess.run(output))
- tf.nn.in_top_k(predictions, targets, k, name=None)
- 解释:这个函数的作用是返回一个布尔向量,说明目标值是否存在于预测值之中。
输出数据是一个 batch_size 长度的布尔向量,如果目标值存在于预测值之中,那么 out[i] = true。
注意:targets 是predictions中的索引位,并不是 predictions 中具体的值。 - 输入参数:
predictions: 一个张量,数据类型是 float32 。数据维度是 batch_size 乘上 x 个类别。
targets: 一个张量,数据类型是 int32 。一个长度是 batch_size 的向量,里面的元素是目标 class ID 。
k: 一个整型。在每行中,查找最大的 k 个值。
name: 为这个操作取个名字。 - 输出参数:
一个张量,数据类型是 bool 。判断是否预测正确。 - 例子:
- 解释:这个函数的作用是返回一个布尔向量,说明目标值是否存在于预测值之中。
import tensorflow as tf
import numpy as np
input = tf.constant(np.random.rand(3,4), tf.float32)
k = 2
output = tf.nn.in_top_k(input, [3,3,3], k)
with tf.Session() as sess:
print(sess.run(input))
print('--------------------')
print(sess.run(output))