目录
本文主要整理自TensorFlow的官方英文文档。以及参考了两个博客,分别是:博主骑着蜗牛向前跑的tf.pad函数功能介绍和博主caicaiatnbu的[TensorFlow 学习笔记-08]tf.pad函数源码解析 侵删。
tf.pad()函数主要是对张量在各个维度上进行填充
函数原型:
def pad(tensor, paddings, mode="CONSTANT", name=None,constant_value=0):
函数参数:
- tensor是待填充的张量,int32
- paddings指出要给tensor的哪个维度进行填充,以及填充多少,要注意的是paddings的rank必须和tensor的rank相同
- mode指填充方式,"CONSTANT"表示用常数进行填充(默认为0,在需要的情况下可以用constant_value赋值),REFLECT", or "SYMMETRIC"
- name就是这个节点的名字了
- constant_value=0
二维填充示例:
下面看一个例子:
import tensorflow as tf
input= tf.constant([[1, 2, 3], [4, 5, 6]])
paddings = tf.constant([[1, 1,], [2, 2]])
# 'constant_values' is 0.
# rank of 't' is 2. 也就是矩阵的秩
input1=tf.pad(input, paddings, "CONSTANT")
input2=tf.pad(input, paddings, "CONSTANT",constant_values=8)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print("input:\n" ,sess.run(input))
print("input1:\n",sess.run(input1))
print("input2:\n",sess.run(input2))
#print(sess.run(input2))
'''
input:
[[1 2 3]
[4 5 6]]
input1:
[[0 0 0 0 0 0 0]
[0 0 1 2 3 0 0]
[0 0 4 5 6 0 0]
[0 0 0 0 0 0 0]]
input2:
[[8 8 8 8 8 8 8]
[8 8 1 2 3 8 8]
[8 8 4 5 6 8 8]
[8 8 8 8 8 8 8]]
'''
结合上图,我们对pad进行一个梳理:
- tensor的维度是n,则pad就有n行,因为pad的每一行负责对tensor的某一个维度进行填充.
- 在二维中,pad的第一行对tensor的行进行填充,[1, 1]中的第一个元素表示在tensor上面填充1行,第二个元素表示在tensor下面填充1行.
- 在二维中,pad的第二行对tensor的列进行填充,[2, 2]中的第一个元素表示在tensor左边填充2列,第二个元素表示在tensor右边填充2列.
- 在二维中我们想对tensor的周围填充什么常数,只需要用constant_value指定即可。
下面我们再看一个例子,来体会"CONSTANT", "REFLECT"和"METRIC"三种填充方式的异同
import tensorflow as tf
input= tf.constant([[1, 2, 3], [4, 5, 6]])
paddings = tf.constant([[1, 1,], [2, 2]])
# 'constant_values' is 0.
# rank of 't' is 2.
input1=tf.pad(input, paddings, "CONSTANT")
input2=tf.pad(input, paddings, "REFLECT")
#REFLECT模式,首先要定好边缘(可理解为对称轴),按边缘翻(边缘不复制)
input3=tf.pad(input, paddings, "SYMMETRIC")
#SYMMETRIC模式,别是把边缘(也就是对称轴)也复制了,从对称轴开始复制
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print("input1:\n" ,sess.run(input1))
print("input2:\n",sess.run(input2))
print("input3:\n",sess.run(input3))
'''
input1:
[[0 0 0 0 0 0 0]
[0 0 1 2 3 0 0]
[0 0 4 5 6 0 0]
[0 0 0 0 0 0 0]]
input2:
[[6 5 4 5 6 5 4]
[3 2 1 2 3 2 1]
[6 5 4 5 6 5 4]
[3 2 1 2 3 2 1]]
input3:
[[2 1 1 2 3 3 2]
[2 1 1 2 3 3 2]
[5 4 4 5 6 6 5]
[5 4 4 5 6 6 5]]
'''
很明显,"CONSTANT"是以一个固定的常数来填充;"REFLECT"是把边缘翻折填充,边缘不复制;SYMMETRIC"也是把边缘部分翻折填充,但是要复制边缘。
三维填充示例:
以上都是填充二维的tensor的例子,接下来我们来看一下三维的tensor(张量)的填充:
import tensorflow as tf
input= tf.Variable(tf.ones([2,3,4]))
paddings = tf.constant([[0,0],[1, 1,], [2, 2]])
paddings2=tf.constant([[1, 1], [0, 0], [0, 0]])
input1=tf.pad(input, paddings, "CONSTANT")
input2=tf.pad(input, paddings2, "CONSTANT")
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print("input:\n" ,sess.run(input))
print("input1:\n",sess.run(input1))
print("input2:\n" ,sess.run(input2))
'''
input:
[[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]
[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]]
第一个paddings的为[[0,0],[1, 1,], [2, 2]]:第一个维度不填充,
第二个维度上上面填充一行下面填充一行,第三个维度左右分别填充两行。填充后大小为[2,5,8]。
input1:
[[[0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 1. 1. 1. 1. 0. 0.]
[0. 0. 1. 1. 1. 1. 0. 0.]
[0. 0. 1. 1. 1. 1. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0.]]
[[0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 1. 1. 1. 1. 0. 0.]
[0. 0. 1. 1. 1. 1. 0. 0.]
[0. 0. 1. 1. 1. 1. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0.]]]
为了再次验证,我们把第二个paddings设为[[1, 1], [0, 0], [0, 0]]。
可以看到得出的结果input2只在第一个维度进行了填充。填充后tinput2大小为[4,3,4].
input2:
[[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]
[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]]
'''
首先,我们看一下,paddings的shape由要填充的tensor来定。shape为[n,2],n是tensor的rank(秩),此处为3.
首先我们创建了一个张量,且张量的维度为[2,3,4]。
第一个paddings的为[[0,0],[1, 1,], [2, 2]]:第一个维度不填充,第二个维度上上面填充一行下面填充一行,第三个维度左右分别填充两行。填充后大小为[2,5,8]。
为了再次验证,我们把第二个paddings设为[[1, 1], [0, 0], [0, 0]]。可以看到得出的结果input2只在第一个维度进行了填充。填充后tinput2大小为[4,3,4].
官网解释及总结:
下面我们再看官网API给的函数的解释。我们上面的所有示例均符合下面的公式。
The padded size of each dimension D of the output is:(被填充后张量的每个维度输出大小)
`paddings[D, 0] + tensor.dim_size(D) + paddings[D, 1]`。 #理解不了也没关系。
当填充模式为边缘翻折的两种情况时,对于paddings的大小也有一定的限制。最基本的原则是:对于要填充的tensor,我们至少要先有这些元素,然后才能对这些元素进行复制,并填充。
def pad(tensor, paddings, mode="CONSTANT", name=None, constant_values=0): # pylint: disable=invalid-name
"""Pads a tensor.
This operation pads a `tensor` according to the `paddings` you specify.
`paddings` is an integer tensor with shape `[n, 2]`, where n is the rank of
`tensor`. For each dimension D of `input`, `paddings[D, 0]` indicates how
many values to add before the contents of `tensor` in that dimension, and
`paddings[D, 1]` indicates how many values to add after the contents of
`tensor` in that dimension. If `mode` is "REFLECT" then both `paddings[D, 0]`
and `paddings[D, 1]` must be no greater than `tensor.dim_size(D) - 1`. If
`mode` is "SYMMETRIC" then both `paddings[D, 0]` and `paddings[D, 1]` must be
no greater than `tensor.dim_size(D)`.
The padded size of each dimension D of the output is:
`paddings[D, 0] + tensor.dim_size(D) + paddings[D, 1]`
For example:
```python
t = tf.constant([[1, 2, 3], [4, 5, 6]])
paddings = tf.constant([[1, 1,], [2, 2]])
# 'constant_values' is 0.
# rank of 't' is 2.
tf.pad(t, paddings, "CONSTANT") # [[0, 0, 0, 0, 0, 0, 0],
# [0, 0, 1, 2, 3, 0, 0],
# [0, 0, 4, 5, 6, 0, 0],
# [0, 0, 0, 0, 0, 0, 0]]
tf.pad(t, paddings, "REFLECT") # [[6, 5, 4, 5, 6, 5, 4],
# [3, 2, 1, 2, 3, 2, 1],
# [6, 5, 4, 5, 6, 5, 4],
# [3, 2, 1, 2, 3, 2, 1]]
tf.pad(t, paddings, "SYMMETRIC") # [[2, 1, 1, 2, 3, 3, 2],
# [2, 1, 1, 2, 3, 3, 2],
# [5, 4, 4, 5, 6, 6, 5],
# [5, 4, 4, 5, 6, 6, 5]]
```
Args:
tensor: A `Tensor`.
paddings: A `Tensor` of type `int32`.
mode: One of "CONSTANT", "REFLECT", or "SYMMETRIC" (case-insensitive)
name: A name for the operation (optional).
constant_values: In "CONSTANT" mode, the scalar pad value to use. Must be
same type as `tensor`.
Returns:
A `Tensor`. Has the same type as `tensor`.
Raises:
ValueError: When mode is not one of "CONSTANT", "REFLECT", or "SYMMETRIC".
"""