简书翻译原文

卷积层

卷积操作是使用一个二维的卷积核在一个批处理的图片上进行不断扫描。具体操作是将一个卷积核在每张图片上按照一个合适的尺寸在每个通道上面进行扫描。为了达到好的卷积效率,需要在不同的通道和不同的卷积核之间进行权衡。

三个卷积函数

  • conv2d: 任意的卷积核,能同时在不同的通道上面进行卷积操作。
  • depthwise_conv2d: 卷积核能相互独立的在自己的通道上面进行卷积操作。
  • separable_conv2d: 在纵深卷积 depthwise filter 之后进行逐点卷积 separable filter。

卷积步长:

strides ,比如 strides = [1, 1, 1, 1] 表示卷积核对每个像素点进行卷积,即在二维屏幕上面,两个轴方向的步长都是1。strides = [1, 2, 2, 1] 表示卷积核对每隔一个像素点进行卷积,即在二维屏幕上面,两个轴方向的步长都是2。

输出shape:

  • padding = 'SAME': 向下取舍,仅适用于全尺寸操作,即输入数据维度和输出数据维度相同。
  • padding = 'VALID: 向上取舍,适用于部分窗口,即输入数据维度和输出数据维度不同,输出维度如下。
shape(output) = [batch,
(in_height - filter_height + 1) / strides[1],
(in_width - filter_width + 1) / strides[2],
...]

conv2d

tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)

输入参数:

  • 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 相同。

解释:这个函数的作用是对一个四维的输入数据 input 和四维的卷积核 filter 进行操作,然后对输入数据进行一个二维的卷积操作,最后得到卷积之后的结果。

给定的输入张量的维度是 [batch, in_height, in_width, in_channels] ,卷积核张量的维度是 [filter_height, filter_width, in_channels, out_channels] ,具体卷积操作如下:

  • 将卷积核的维度转换成一个二维的矩阵形状 [filter_height * filter_width * in_channels, output_channels]
  • 对于每个批处理的图片,我们将输入张量转换成一个临时的数据维度 [batch, out_height, out_width, filter_height * filter_width * in_channels]
  • 对于每个批处理的图片,我们右乘以卷积核,得到最后的输出结果。

更加具体的表示细节为:

output[b, i, j, k] = sum_{di, dj, q} 
  input[b, strides[1] * i + di, strides[2] * j + dj, q] * filter[di, dj, q, k]
 

注意,必须有 strides[0] = strides[3] = 1。在大部分处理过程中,卷积核的水平移动步数和垂直移动步数是相同的,strides = [1, stride, stride, 1]

depthwise_conv2d

tf.nn.depthwise_conv2d(input, filter, strides, padding, name=None)

输入参数:

  • 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

更加具体公式如下:

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]

使用例子:

#!/usr/bin/env python
# -*- coding: utf-8 -*- 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.initialize_all_variables()
sess.run(init)
print sess.run(y)
print sess.run(tf.shape(y))

separable_conv2d

tf.nn.separable_conv2d(input, depthwise_filter, pointwise_filter, strides, padding, name=None)

输入参数:

  • input: 一个Tensor。数据维度是四维 [batch, in_height, in_width, in_channels]
  • depthwise_filter: 一个Tensor。数据维度是四维 [filter_height, filter_width, in_channels, channel_multiplier]。其中,in_channels 的卷积深度等于input的in_channels。
  • 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 ,那么将报错。

解释:这个函数的作用是利用几个分离的卷积核去做卷积,可以参考这个解释

比如下图中,常规卷积和分离卷积的区别:

首先使用一个二维的卷积核,在每个通道上,以深度 channel_multiplier 进行卷积。也就是先使用 depthwise_conv2d ,将 ID 的通道数映射到 ID * DM 的通道数上面,之后从 ID * DM 的通道数映射到 OD 的通道数上面,这也就是又进行了一次常规卷积

具体公式如下:

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]

使用例子:

#!/usr/bin/env python
# -*- coding: utf-8 -*- 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) # 输入通道等于input的通道
pointwise_filter = tf.Variable( np.random.rand(1, 1, 15, 20), dtype = np.float32) # 卷积核两项必须是1
# 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.initialize_all_variables()
sess.run(init)
print sess.run(y)
print sess.run(tf.shape(y))

池化层

最大汇聚效果优于平均汇聚

池化操作是利用一个矩阵窗口在输入张量上进行扫描,并且将每个矩阵窗口中的值通过取最大值,平均值或者XXXX来减少元素个数。每个池化操作的矩阵窗口大小是由 ksize 来指定的,并且根据步长参数 strides 来决定移动步长。比如,如果 strides 中的值都是1,那么每个矩阵窗口都将被使用。如果 strides 中的值都是2,那么每一维度上的矩阵窗口都是每隔一个被使用。以此类推。

输出数据维度是:

shape(output) = (shape(value) - ksize + 1) / strides

  • padding = 'SAME': 向下取舍,仅适用于全尺寸操作,即输入数据维度和输出数据维度相同。
  • padding = 'VALID: 向上取舍,适用于部分窗口,即输入数据维度和输出数据维度不同,输出维度如上。

avg_pool

tf.nn.avg_pool(value, ksize, strides, padding, name=None)

解释:这个函数的作用是计算池化区域中元素的平均值。

输入参数:

  • value: 一个四维的Tensor。数据维度是 [batch, height, width, channels]。数据类型是float32float64qint8quint8qint32
  • ksize: 一个长度不小于4的整型数组。每一位上面的值对应于输入数据张量中每一维的窗口对应值。
  • strides: 一个长度不小于4的整型数组。该参数指定滑动窗口在输入数据张量每一维上面的步长。
  • padding: 一个字符串,取值为 SAME 或者 VALID
  • name: (可选)为这个操作取一个名字。

输出参数:

  • 一个Tensor,数据类型和value相同。

max_pool

tf.nn.max_pool(value, ksize, strides, padding, name=None)解释:这个函数的作用是计算池化区域中元素的最大值。

输入参数:

  • value: 一个四维的Tensor。数据维度是 [batch, height, width, channels]。数据类型是float32float64qint8quint8qint32
  • ksize: 一个长度不小于4的整型数组。每一位上面的值对应于输入数据张量中每一维的窗口对应值。
  • strides: 一个长度不小于4的整型数组。该参数指定滑动窗口在输入数据张量每一维上面的步长。
  • padding: 一个字符串,取值为 SAME 或者 VALID
  • name: (可选)为这个操作取一个名字。

输出参数:

  • 一个Tensor,数据类型和value相同。

激活函数

在神经网络中,我们有很多的非线性函数来作为激活函数,比如连续的平滑非线性函数(sigmoidtanhsoftplus),连续但不平滑的非线性函数(relurelu6relu_x)和随机正则化函数(dropout)。

所有的激活函数都是单独应用在每个元素上面的,并且输出张量的维度和输入张量的维

分类:

平滑非线性(sigmoid,tanh,elu,softplus,softsign)

连续但不是处处可导(relu,relu6,crelu,relu_x)

随机正则化(dropout)

relu

tf.nn.relu(features, name = None)

解释:这个函数的作用是计算激活函数relu,即max(features, 0)

输入参数:

  • features: 一个Tensor。数据类型必须是:float32float64int32int64uint8int16int8
  • name: (可选)为这个操作取一个名字。

输出参数:

  • 一个Tensor,数据类型和features相同。

relu6

tf.nn.relu6(features, name = None)

解释:这个函数的作用是计算激活函数relu6,即min(max(features, 0), 6)

输入参数:

  • features: 一个Tensor。数据类型必须是:floatdoubleint32int64uint8int16或者int8
  • name: (可选)为这个操作取一个名字。

输出参数:

  • 一个Tensor,数据类型和features相同。

crelu

tf.nn.crelu(features, name = None)

解释:这个函数会倍增通道,一个是relu,一个是relu关于y轴对称的形状。

输入参数:

  • features: 一个Tensor。数据类型必须是:float32float64int32int64uint8int16int8
  • name: (可选)为这个操作取一个名字。

输出参数:

  • 一个Tensor,数据类型和features相同,通道加倍。

elu

tf.nn.elu(features, name = None)

解释:x小于0时,y = a*(exp(x)-1),x大于0时同relu。

  • features: 一个Tensor。数据类型必须是:float32float64int32int64uint8int16int8
  • name: (可选)为这个操作取一个名字。

输出参数:

  • 一个Tensor,数据类型和features相同。

softplus

tf.nn.softplus(features, name = None)

解释:这个函数的作用是计算激活函数softplus,即log( exp( features ) + 1)

输入参数:

  • features: 一个Tensor。数据类型必须是:float32float64int32int64uint8int16或者int8
  • name: (可选)为这个操作取一个名字。

输出参数:

  • 一个Tensor,数据类型和features相同。

softsign

tf.nn.softsign(features, name = None)

解释:这个函数的作用是计算激活函数softsign,即features / (abs(features) + 1)

输入参数:

  • features: 一个Tensor。数据类型必须是:float32float64int32int64uint8int16或者int8
  • name: (可选)为这个操作取一个名字。

输出参数:

  • 一个Tensor,数据类型和features相同。

sigmoid

tf.sigmoid(x, name = None)

解释:这个函数的作用是计算 x 的 sigmoid 函数。具体计算公式为 y = 1 / (1 + exp(-x))

输入参数:

  • x: 一个Tensor。数据类型必须是floatdoubleint32complex64int64或者qint32
  • name: (可选)为这个操作取一个名字。

输出参数:

  • 一个Tensor,如果 x.dtype != qint32 ,那么返回的数据类型和x相同,否则返回的数据类型是 quint8

sigmoid输出恒大于零,相当于加了偏置分量。

tanh

tf.tanh(x, name = None)

解释:这个函数的作用是计算 x 的 tanh 函数。具体计算公式为 ( exp(x) - exp(-x) ) / ( exp(x) + exp(-x) )

  • x: 一个Tensor。数据类型必须是floatdoubleint32complex64int64或者qint32
  • name: (可选)为这个操作取一个名字。

输出参数:

  • 一个Tensor,如果 x.dtype != qint32 ,那么返回的数据类型和x相同,否则返回的数据类型是 quint8

[-2,2]之间tanh最敏感

[-8,-2]之间tanh不敏感

dropout

tf.nn.dropout(x, keep_prob, noise_shape = None, seed = None, name = None)

解释:这个函数的作用是计算神经网络层的dropout

一个神经元将以概率keep_prob决定是否放电,如果不放电,那么该神经元的输出将是0,如果该神经元放电,那么该神经元的输出值将被放大到原来的1/keep_prob。这里的放大操作是为了保持神经元输出总个数不变。比如,神经元的值为[1, 2]keep_prob的值是0.5,并且是第一个神经元是放电的,第二个神经元不放电,那么神经元输出的结果是[2, 0],也就是相当于,第一个神经元被当做了1/keep_prob个输出,即2个。这样保证了总和2个神经元保持不变。

默认情况下,每个神经元是否放电是相互独立的。但是,如果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]区间,那么会提示错误。

bias_add

tf.nn.bias_add(value, bias, name = None)

解释:这个函数的作用是将偏差项 bias 加到 value 上面。

这个操作你可以看做是 tf.add 的一个特例,其中 bias 必须是一维的。该API支持广播形式,因此 value 可以有任何维度。但是,该API又不像 tf.add 可以让 bias 的维度和 value 的最后一维不同,tf.nn.bias_add中bias的维度和value最后一维必须相同。

输入参数:

  • value: 一个Tensor。数据类型必须是floatdoubleint64int32uint8int16int8或者complex64
  • bias: 一个一维的Tensor,数据维度和 value 的最后一维相同。数据类型必须和value相同。
  • name: (可选)为这个操作取一个名字。

输出参数:

  • 一个Tensor,数据类型和value相同。

范例:

#!/usr/bin/env python
# -*- coding: utf-8 -*- 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))

『TensorFlow』网络操作API_上的更多相关文章

  1. 『TensorFlow』网络操作API_下

    一.优化器基类介绍 标注一点,优化器中的学习率可以是tensor,这意味着它可以feed, learning_rate: A Tensor or a floating point value. 正常使 ...

  2. 『TensorFlow』网络操作API_中_损失函数及分类器

    一.误差值 度量两个张量或者一个张量和零之间的损失误差,这个可用于在一个回归任务或者用于正则的目的(权重衰减). l2_loss tf.nn.l2_loss(t, name=None) 解释:这个函数 ...

  3. 『TensorFlow』读书笔记_Inception_V3_上

    1.网络背景 自2012年Alexnet提出以来,图像分类.目标检测等一系列领域都被卷积神经网络CNN统治着.接下来的时间里,人们不断设计新的深度学习网络模型来获得更好的训练效果.一般而言,许多网络结 ...

  4. 『TensorFlow』专题汇总

    TensorFlow:官方文档 TensorFlow:项目地址 本篇列出文章对于全零新手不太合适,可以尝试TensorFlow入门系列博客,搭配其他资料进行学习. Keras使用tf.Session训 ...

  5. 『TensorFlow』梯度优化相关

    tf.trainable_variables可以得到整个模型中所有trainable=True的Variable,也是自由处理梯度的基础 基础梯度操作方法: tf.gradients 用来计算导数.该 ...

  6. 『TensorFlow』模型保存和载入方法汇总

    『TensorFlow』第七弹_保存&载入会话_霸王回马 一.TensorFlow常规模型加载方法 保存模型 tf.train.Saver()类,.save(sess, ckpt文件目录)方法 ...

  7. 『TensorFlow』分布式训练_其三_多机分布式

    本节中的代码大量使用『TensorFlow』分布式训练_其一_逻辑梳理中介绍的概念,是成熟的多机分布式训练样例 一.基本概念 Cluster.Job.task概念:三者可以简单的看成是层次关系,tas ...

  8. 『TensorFlow』滑动平均

    滑动平均会为目标变量维护一个影子变量,影子变量不影响原变量的更新维护,但是在测试或者实际预测过程中(非训练时),使用影子变量代替原变量. 1.滑动平均求解对象初始化 ema = tf.train.Ex ...

  9. 『TensorFlow』读书笔记_降噪自编码器

    『TensorFlow』降噪自编码器设计  之前学习过的代码,又敲了一遍,新的收获也还是有的,因为这次注释写的比较详尽,所以再次记录一下,具体的相关知识查阅之前写的文章即可(见上面链接). # Aut ...

随机推荐

  1. Emmet.vim 教程

    Emmet.vim 教程 May 5, 2012 目录 1 下载 Emmet.vim 2 安装 Emmet.vim 3 使用 Emmet.vim 4 余话 Emmet 项目原先叫 Zen Coding ...

  2. React-Router4.x中文文档

    以下为翻译的中文API(水平有限,凑合看,欢迎纠正补充~) <BrowserRouter> 使用HTML5历史记录API(pushState,replaceState和popstate事件 ...

  3. eclipse web module版本问题:Cannot change version of project facet Dynamic Web Module to 2.5.

    Description    Resource    Path    Location    TypeCannot change version of project facet Dynamic We ...

  4. Spark生态以及原理

    spark 生态及运行原理 Spark 特点 运行速度快 => Spark拥有DAG执行引擎,支持在内存中对数据进行迭代计算.官方提供的数据表明,如果数据由磁盘读取,速度是Hadoop MapR ...

  5. Unable to register MBean [HikariDataSource (HikariPool-0)] with key 'dataSou rce'; nested exception is javax.management.InstanceAlreadyExistsException: com.z axxer.hikari:name=dataSource,type=HikariDa

    今天启动项目看到已经启动起来,但是看到控制台有红色,没注意是什么问题,具体在细看下,发现是一个Tomcat中发布了两个实例. 解决办法:去发布路径下,全部删掉或者删掉不用的即可.

  6. C#-----类FileStream的使用

    1.枚举类FileMode 指定操作系统打开文件的方式 CreateNew  指定操作系统应创建一个新的文件 Create  指定操作系统应创建一个新的文件. 如果该文件已存在,则会覆盖它 Open  ...

  7. 记账本微信小程序开发四

    学习添加组件 集成日期组件 添加组件 需要在main.js文件中,声明一个data值date与wxml中的{{date}}绑定关联,然后在onLoad中初始化字符串格式的日期值, 处理日期组件点击确认 ...

  8. Electron把网页打包成桌面应用并进行源码加密

    前言 最近想把自己用html+css+js做的网页界面打包成桌面应用,网上一搜,发现Electron是一个不错的选择,试了试,发现效果真的不错.这里记录一下打包过程以作记录,便于自己以后查看学习. 一 ...

  9. Django框架---- 信号

    Django中的信号及其用法 Django中提供了"信号调度",用于在框架执行操作时解耦. 一些动作发生的时候,系统会根据信号定义的函数执行相应的操作 Django中内置的sign ...

  10. 20190409Liunx中计划任务及压缩归档week2_day1

    计划任务介绍 我们可以通过一些设置.来让电脑定时提醒我们该做什么事了.或者我们提前设置好,告诉电脑你几点做什么几点做什么,这种我们就叫它定时任务.而遇到一些需要执行的事情或任务.我们也可以通过命令来告 ...