下面的解释出自上面的链接

对于两路输入来说,如果是通道数相同且后面带卷积的话,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。如果您有任何疑问,请随时问我。