下面的解释出自上面的链接
对于两路输入来说,如果是通道数相同且后面带卷积的话,add等价于concat之后对应通道共享同一个卷积核。下面具体用式子解释一下。由于每个输出通道的卷积核是独立的,我们可以只看单个通道的输出。假设两路输入的通道分别为X1, X2, …, Xc和Y1, Y2, …, Yc。那么concat的单个输出通道为(*表示卷积):
Z _ { \text {concat} } = \sum _ { i = 1 } ^ { c } X _ { i } * K _ { i } + \sum _ { i = 1 } ^ { c } Y _ { i } * K _ { i + c }
Z
concat
=
i
=
1
∑
c
X
i
∗
K
i
+
i
=
1
∑
c
Y
i
∗
K
i
+
c
而add的单个输出通道为:
Z _ { a d d } = \sum _ { i = 1 } ^ { c } \left( X _ { i } + Y _ { i } \right) * K _ { i } = \sum _ { i = 1 } ^ { c } X _ { i } * K _ { i } + \sum _ { i = 1 } ^ { c } Y _ { i } * K _ { i }
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
因此add相当于加了一种prior,当两路输入可以具有“对应通道的特征图语义类似”(可能不太严谨)的性质的时候,可以用add来替代concat,这样更节省参数和计算量(concat是add的2倍)。FPN[1]里的金字塔,是
希望把分辨率最小但语义最强的特征图增加分辨率,从性质上是可以用add的
。如果用concat,因为分辨率小的特征通道数更多,计算量是一笔不少的开销
Resnet是做值的叠加,通道数是不变的,DenseNet是做通道的合并。你可以这么理解,add是描述图像的特征下的信息量增多了,但是描述图像的维度本身并没有增加,只是每一维下的信息量在增加,这显然是对最终的图像的分类是有益的。而concatenate是通道数的合并,也就是说描述图像本身的特征增加了,而每一特征下的信息是没有增加。
Hengkai Guo的回答 - 知乎 https://www.zhihu.com/question/306213462/answer/562776112下面的解释出自上面的链接对于两路输入来说,如果是通道数相同且后面带卷积的话,add等价于concat之后对应通道共享同一个卷积核。下面具体用式子解释一下。由于每个输出通道的卷积核是独立的,我们可以只看单个通道的输出。假设两路输入的通道分别...
原文链接:https://blog.csdn.net/xys430381_1/article/details/88355956
一、如何
理解
concat
和
add
的
方式
融合
特征
在各个网络模型
中
,ResNet,FPN等采用的element-wise
add
来
融合
特征
,而DenseNet等则采用
concat
来
融合
特征
。那
add
与
concat
形式有什么不同呢?事实上两者都可以
理解
为整合
特征
图信息。只不过
concat
比较直观,而
add
理解
起来比较生涩。
从图
中
可以发现,
concat
是通道数的增加;
add
是特
在各个网络模型
中
,ResNet,FPN等采用的element-wise
add
来
融合
特征
,而DenseNet等则采用
concat
来
融合
特征
。那
add
与
concat
形式有什么不同呢?事实上两者都可以
理解
为整合
特征
图信息。只不过
concat
比较直观,而
add
理解
起来比较生涩。
https://blog.csdn.net/LoseInVain/article/details/88363776
CVPR2018上关于目标检测(object detection)的论文比去年要多很多,而且大部分都有亮点。从其
中
挑了几篇非常有意思的文章,特来分享。
1、cascaded RCNN
论文:Cascade R-CNN Delving into High Quality Object Detection
论文链接:https://arxiv.org/abs/1712.00726
代码链接:h...
如何
理解
concat
和
add
的
方式
融合
特征
在各个网络模型
中
,ResNet,FPN等采用的element-wise
add
来
融合
特征
,而DenseNet等则采用
concat
来
融合
特征
。那
add
与
concat
形式有什么不同呢?事实上两者都可以
理解
为整合
特征
图信息。只不过
concat
比较直观,而
add
理解
起来比较生涩。
从图
中
可以发现,
concat
是通道数的增加;
add
是
特征
图相加,通道数不变...
1. 如何
理解
concat
和
add
:
实际上
add
与
concat
都可以
理解
为用于整合
特征
图信息,ResNet/FPN等网络结构逐元素做值的叠加而通道数是不变的,采用的
add
方式
来
融合
特征
;而DenseNet等网络结构则做通道的合并,采用
concat
方式
来
融合
特征
。
concat
方式
经常用于将
特征
联合、多个卷积
特征
提取框架提取的
特征
融合
或者是将输出层的信息进行
融合
;而
add
层更像是信息之间的叠加。
可以
理解
为,
add
方式
在...
pandas作者Wes McKinney 在【PYTHON FOR DATA ANALYSIS】
中
对pandas的方方面面都有了一个权威简明的入门级的介绍,但在实际使用过程
中
,我发现书
中
的内容还只是冰山一角。今天就pandas官网
中
关于数据合并和重述的章节做个人性质的总结。
文
中
代码块主要有pandas官网教程提供。
在深度学习
中
,经常会存在需要
特征
融合
的地方[1],而最基本的
融合
方法无非是:(1) 按点逐位相加(point-wise
add
ition) 和 (2) 进行向量拼接(
concat
enate)。这两种
方式
有着异同,也有着关联,接下来进行简单讨论。
∇\nabla∇联系
方式
:
e-mail: FesianXu@163.com
QQ: 973926198
github: https://githu...
class ConvLSTM(nn.Module):
def __init__(self, input_size, hidden_size, kernel_size):
super(ConvLSTM, self).__init__()
self.input_size = input_size
self.hidden_size = hidden_size
self.kernel_size = kernel_size
self.p
add
ing = kernel_size // 2
self.conv = nn.Conv2d(in_channels=self.input_size + self.hidden_size,
out_channels=4 * self.hidden_size,
kernel_size=self.kernel_size,
p
add
ing=self.p
add
ing)
def forward(self, input_tensor, cur_state):
h_cur, c_cur = cur_state
combined = torch.cat([input_tensor, h_cur], dim=1)
combined_conv = self.conv(combined)
cc_i, cc_f, cc_o, cc_g = torch.split(combined_conv, self.hidden_size, dim=1)
i = torch.sigmoid(cc_i)
f = torch.sigmoid(cc_f)
o = torch.sigmoid(cc_o)
g = torch.tanh(cc_g)
c_next = f * c_cur + i * g
h_next = o * torch.tanh(c_next)
return h_next, c_next
class UNet(nn.Module):
def __init__(self, in_channels, out_channels):
super(UNet, self).__init__()
self.conv1 = nn.Conv2d(in_channels, 64, kernel_size=3, p
add
ing=1)
self.conv2 = nn.Conv2d(64, 128, kernel_size=3, p
add
ing=1)
self.conv3 = nn.Conv2d(128, 256, kernel_size=3, p
add
ing=1)
self.conv4 = nn.Conv2d(256, 512, kernel_size=3, p
add
ing=1)
self.conv5 = nn.Conv2d(512, 1024, kernel_size=3, p
add
ing=1)
self.upconv6 = nn.ConvTranspose2d(1024, 512, kernel_size=2, stride=2)
self.conv6 = nn.Conv2d(1024, 512, kernel_size=3, p
add
ing=1)
self.upconv7 = nn.ConvTranspose2d(512, 256, kernel_size=2, stride=2)
self.conv7 = nn.Conv2d(512, 256, kernel_size=3, p
add
ing=1)
self.upconv8 = nn.ConvTranspose2d(256, 128, kernel_size=2, stride=2)
self.conv8 = nn.Conv2d(256, 128, kernel_size=3, p
add
ing=1)
self.upconv9 = nn.ConvTranspose2d(128, 64, kernel_size=2, stride=2)
self.conv9 = nn.Conv2d(128, 64, kernel_size=3, p
add
ing=1)
self.conv10 = nn.Conv2d(64, out_channels, kernel_size=1)
def forward(self, x):
conv1 = F.relu(self.conv1(x))
conv2 = F.relu(self.conv2(F.max_pool2d(conv1, 2)))
conv3 = F.relu(self.conv3(F.max_pool2d(conv2, 2)))
conv4 = F.relu(self.conv4(F.max_pool2d(conv3, 2)))
conv5 = F.relu(self.conv5(F.max_pool2d(conv4, 2)))
upconv6 = self.upconv6(conv5)
concat
6 = torch.cat([upconv6, conv4], dim=1)
conv6 = F.relu(self.conv6(
concat
6))
upconv7 = self.upconv7(conv6)
concat
7 = torch.cat([upconv7, conv3], dim=1)
conv7 = F.relu(self.conv7(
concat
7))
upconv8 = self.upconv8(conv7)
concat
8 = torch.cat([upconv8, conv2], dim=1)
conv8 = F.relu(self.conv8(
concat
8))
upconv9 = self.upconv9(conv8)
concat
9 = torch.cat([upconv9, conv1], dim=1)
conv9 = F.relu(self.conv9(
concat
9))
out = self.conv10(conv9)
return out
# Replace UNet's
Concat
operation with ConvLSTM
class ConvLSTMUNet(nn.Module):
def __init__(self, in_channels, out_channels, hidden_size, kernel_size):
super(ConvLSTMUNet, self).__init__()
self.unet = UNet(in_channels, out_channels)
self.convlstm = ConvLSTM(out_channels, hidden_size, kernel_size)
def forward(self, x, cur_state):
unet_out = self.unet(x)
lstm_out, lstm_state = self.convlstm(unet_out, cur_state)
return lstm_out, lstm_state
这个代码将UNet的
Concat
操作替换为ConvLSTM。如果您有任何疑问,请随时问我。