一、参考资料
深度学习之concatenate和elementwise操作(一)
深度学习之concatenate和elementwise操作(二)
二、element-wise
相关介绍
1. 对应关系vs对应元素
如果两个元素在两个tensor内占据相同的位置,则认为这个两个元素是对应的,该对应关系由元素的索引确定。
> t1 = torch.tensor([ [1,2], [3,4] ], dtype=torch.float32)
> t2 = torch.tensor([ [9,8], [7,6] ], dtype=torch.float32)
# Example of the first axis
> print(t1[0])
tensor([1., 2.])
# Example of the second axis
> print(t1[0][0])
tensor(1.)
# t1中的1元素,对应t2中的9
> t1[0][0] tensor(1.)
> t2[0][0] tensor(9.)
2. element-wise
的概念
elementwise
操作是指两个相同形状(shape)的张量(tensor),在对应元素上进行逐位运算。
element-wise
操作相同形状的张量,即张量必须具有相同数量的元素才能执行 element-wise 操作。- 所有的算数运算,加、减、乘、除都是
element-wise
运算,我们通常看到的张量运算是使用标量值的算数运算。
以下术语都是指 element-wise
:
Element-wise
Component-wise
Point-wise
3. element-wise add
3.1 算数运算符
利用 +、-、*、/
算数运算符,进行算数运算。
> t1 = torch.tensor([ [1,2], [3,4] ], dtype=torch.float32)
> t2 = torch.tensor([ [9,8], [7,6] ], dtype=torch.float32)
> t1 + t2
tensor([[10., 10.],
[10., 10.]])
> print(t1 + 2)
tensor([[3., 4.],
[5., 6.]])
> print(t1 - 2)
tensor([[-1., 0.],
[ 1., 2.]])
> print(t1 * 2)
tensor([[2., 4.],
[6., 8.]])
> print(t1 / 2)
tensor([[0.5000, 1.0000],
[1.5000, 2.0000]])
3.2 内置方法
利用张量内置的方法,进行算数运算。
> t1 = torch.tensor([ [1,2], [3,4] ], dtype=torch.float32)
> t2 = torch.tensor([ [9,8], [7,6] ], dtype=torch.float32)
> print(t1.add(2))
tensor([[3., 4.],
[5., 6.]])
> print(t1.sub(2))
tensor([[-1., 0.],
[ 1., 2.]])
> print(t1.mul(2))
tensor([[2., 4.],
[6., 8.]])
> print(t1.div(2))
tensor([[0.5000, 1.0000],
[1.5000, 2.0000]])
4. Dot Product
[ a 1 a 2 ⋮ a n − 1 a n ] ⋅ [ b 1 b 2 ⋮ b n − 1 b n ] = [ a 1 b 1 a 2 b 2 ⋮ a n − 1 b n − 1 a n b n ] = a 1 b 1 + a 2 b 2 + ⋯ + a n − 1 b n − 1 + a n b n \left[\begin{array}{c}a_1\\a_2\\\vdots\\a_{n-1}\\a_n\end{array}\right]\cdot\left[\begin{array}{c}b_1\\b_2\\\vdots\\b_{n-1}\\b_n\end{array}\right] = \begin{bmatrix}a_{1} b_{1}\\a_{2} b_{2}\\\vdots\\a_{n-1} b_{n-1}\\a_{n} b_{n}\end{bmatrix} = \mathbf{a}_{1}\mathbf{b}_{1}+\mathbf{a}_{2}\mathbf{b}_{2}+\cdots+\mathbf{a}_{n-1}\mathbf{b}_{n-1}+\mathbf{a}_{n}\mathbf{b}_{n} a1a2⋮an−1an ⋅ b1b2⋮bn−1bn = a1b1a2b2⋮an−1bn−1anbn =a1b1+a2b2+⋯+an−1bn−1+anbn
简化使用求和公式:
a ⋅ b = ∑ i = 1 n a i b i \mathbf{a}\cdot\mathbf{b}=\sum_{i=1}^{n}\mathbf{a}_{i}\mathbf{b}_{i} a⋅b=i=1∑naibi
import numpy as np
np1 = np.array([4, 6])
np2 = np.array([[-3], [7]])
print(np.dot(np1, np2)
## [30]
# 4*-3 + 6*7 = 42*12 = 30
5. element-wise product
element-wise product
实际上是两个相同形状的张量进行逐元素相乘。
import numpy as np
np1 = np.array([4, 6])
np2 = np.array([-3, 7])
print(np2 * np1)
# [-12 42]
import numpy as np
np1 = np.array([4, 6])
print(np1 * 3)
# [12 18]
三、broadcasting
广播机制
1. 引言
如果标量值2是0阶张量,意味着它没有形状,张量 t1 是一个形状为 2x2 的2阶张量。如下所示:
> a = 2
> t1 = torch.tensor([ [1,2], [3,4] ], dtype=torch.float32)
由于 element-wise
只能操作相同形状的张量,为了解决两个张量形状不一致的问题,引入了 broadcasting
广播机制,使得两个不同形状的张量可以进行算数运算。
2. broadcasting
广播机制
将低阶张量通过 broadcasting
广播机制进行变换,以匹配高阶张量的形状,从而能够进行 element-wise
操作。broadcasting
广播是一个比基本 element-wise
操作更先进的话题。
> np.broadcast_to(2, t1.shape)
array([[2, 2],
[2, 2]])
将标量值2转换成一个2阶张量,该张量的形状与t1一样,形状匹配和 element-wise
方面的规则有了相同的形状。
> t1 + 2
tensor([[3., 4.],
[5., 6.]])
实际上的操作:
> t1 + torch.tensor(
np.broadcast_to(2, t1.shape)
,dtype=torch.float32
)
tensor([[3., 4.],
[5., 6.]])
3. 复杂的例子
t1 = torch.tensor([
[1,1],
[1,1]
], dtype=torch.float32)
t2 = torch.tensor([2,4], dtype=torch.float32)
# t1 + t2 ???????
> t1.shape
torch.Size([2, 2])
> t2.shape
torch.Size([2])
使用numpy包的 broadcast_to()
函数检查 broadcast
转换。
> np.broadcast_to(t2.numpy(), t1.shape)
array([[2., 4.],
[2., 4.]], dtype=float32)
> t1 + t2
tensor([[3., 5.],
[3., 5.]])
broadcasting之后,这两个张量之间的加法运算是相同形状张量之间的 element-wise
运算。
四、concatenation operation
1. concatenation operation
的概念
concatenation operation
是两个张量之间的拼接。
import numpy as np
a = np.array([[1, 2], [3, 4]])
print(a.shape)
b = np.array([[5, 6]])
print(b.shape)
np.concatenate((a, b))
c= np.concatenate((a, b))
print(c)
print(c.shape)
# 输出
Out[1]: (2, 2)
Out[2]: (1, 2)
Out[3]:
array([[1, 2],
[3, 4],
[5, 6]])
Out[4]: (3, 2)
2. feature map的几种连接形式
2.1 concatenate
concatenate方式:先卷积,再拼接。先对每个通道进行卷积,然后合并通道。
concatenate方式是通道数的合并,描述图像本身的特征数(通道数)增加,而每一特征下的信息没有增加。
Z c o n c a t = ∑ i = 1 c X i ∗ K i + ∑ i = 1 c Y i ∗ K i + c Z_{\mathrm{concat}}=\sum_{i=1}^cX_i*K_i+\sum_{i=1}^cY_i*K_{i+c} Zconcat=i=1∑cXi∗Ki+i=1∑cYi∗Ki+c
2.2 element-wise add
add方式:先相加,再卷积。先将对应的特征图进行相加,然后卷积。对应通道的特征图语义信息类似,对应的特征图共享一个卷积核。
add方式使得描述图像的每一维度下的特征信息量增多,但描述图像的维度本身并没有增加,显然对最终的图像分类是有意义的。
Z a d d = ∑ i = 1 c ( X i + Y i ) ∗ K i = ∑ i = 1 c X i ∗ K i + ∑ i = 1 c Y i ∗ K i \begin{aligned}Z_{add}=\sum_{i=1}^c\left(X_i+Y_i\right)*K_i=\sum_{i=1}^cX_i*K_i+\sum_{i=1}^cY_i*K_i\end{aligned} Zadd=i=1∑c(Xi+Yi)∗Ki=i=1∑cXi∗Ki+i=1∑cYi∗Ki
2.3 总结
-
通过add操作会得到新的特征,这个新的特征可以反映原始特征的一些特性,但是原始特征的一些信息也会由于add方式造成损失;concatenate是将原始特征直接拼接,让网络去学习应该如何融合特征,这个过程中信息不会损失。
-
concat的计算量较大,在明确原始特征的关系的情况下,使用add操作融合可以节省计算代价。