Dynamic ReLU(ECCV'20):一種根據輸入自適應動態調節的啟用函式
Dynamic ReLU(ECCV'20):一種根據輸入自適應動態調節的啟用函式
Mark 十月的清晨和你都值得期待 KevinCK 、 王晉東不在家 等導讀:ReLU是深度神經網路中常用的啟用函式。到目前為止,ReLU及其推廣(非引數或引數)都是靜態的,對所有的輸入樣本執行相同的操作。在本文中,作者提出了Dynamic ReLU啟用函式(DY-ReLU),它的引數依賴於所有輸入。其關鍵在於DY-ReLU將全域性上下文編碼為函式,並相應地調整分段線性啟用函式。與靜態模型相比,DY-ReLU的額外計算開銷可以忽略不計,但其表現能力顯著提高,特別是對於輕量神經網路。僅僅通過簡單地在MobileNetV2上使用DY-ReLU ,ImageNet分類的最高精度就可以從72.0%提高到76.2%,而計算量只增加了5%.
- 論文地址:https://arxiv.org/abs/2003.10027
- 論文程式碼:https://github.com/Islanna/DynamicReLU(閱讀原文)
1.Motivation
ReLU是深度學習中很重要的里程碑,簡單但強大,能夠極大地提升神經網路的效能,比如ResNet, MobileNet and ShuffleNet。目前也有很多ReLU的改進版,比如Leaky ReLU和 PReLU,而這些改進版和原版的最終引數都是固定的。所以論文想到,是否能夠根據輸入特徵來調整ReLU的引數。
本文提出的DY-ReLU它是一個引數依賴於輸入的動態分段線性函式。DY-ReLU既不增加網路的深度,也不增加網路的寬度,但可以有效地增加模型能力.
ReLU:分段函式的都依賴於輸入
2.方法
定義ReLU函式為y=max(x, 0), x為輸入值,那麼y=max(x,0). 我們可以寫成更加一般的形式y=max(ax+b),對應ReLU
y=max(ax+b),
s.t., a=1, b=0, when x > 0
a=0, b=0, when x<=0
這篇論文是對a, b進行了進一步的擴充套件, y=max{a1x+b1, a2x+b2}(畫外音:可以新增更多的函式 akx+bk,不過太多複雜度就上去了,reviewer應該會吐槽,作者這裡用了兩個, 我這裡就直接寫成了a1,a2, b1, b2與原文稍有不同)。
這裡把a, b看做是一個關於輸入x的一個函式,怎麼關聯呢?簡單粗暴的方式先對x平均,然後通過matrix transformation得到對應的引數個數就行,根據不同的情況,需要的引數量不一樣,具體這裡作者介紹了三種:
(1)如果每一個entry都apply一樣的DYReLU, 也就是圖1上面的小方塊都是長得一樣的分段函式,那麼我們只需要用四個引數{a1,a2,b1,b2},
圖2 每一個channel上面的分段函式一樣(2)如果是每一個channel apply不同的函式,圖2中的channel-wise,每一個channel是一樣的引數, 就需要4*C個引數。
第1個feature map:
{a11,a12,b11,b12}
第2個feature map:
{a21,a22,b21,b22}
第3個feature map:
{a31,a32,b31,b32}
....
第C個feature map:
{aC1,aC2,bC1,bC2}
圖3每一個元素上apply不一樣的啟用函式(3)如果更凶殘一些,每一個通道的每一個entry都不一樣,也就是spatial-wise和channel-wise,那就需要4C*H*W個引數了。(畫外音:如果每一層都加入這樣的一個操作,引數量還小嗎?)。
在related work中,作者list出了相關的文獻,並做了一下總結和對比,如下表所示:
後續作者在ImageNet,COCO上使用MobileNetV2做了一系列的實驗,感興趣的同學,可以瞭解一下實驗performance。這裡我思考了一下,如果在節點分類的任務上加上這樣的操作,也就是對於每一個節點的N維特徵進行average,再加上linear操作等得到4或者4C個引數值,用於max{a1x+b, a2x+b}, 這個操作倒是像是一種attention. Attention關注了node feature哪個維度的重要度以及與當前維度的相關度, 具體效果怎麼樣,感興趣的同學做完實驗可以與我聯絡,我們一起交流一下~. 下面是作者post的程式碼,在下方加上小編寫的main函式,可以執行一下看每一層對應的輸出,深入理解本文的內容,當然也可以改寫成節點分類,圖分類等等任務上。
import torch
import torch.nn as nn
class DyReLU(nn.Module):
def __init__(self, channels, reduction=4, k=2, conv_type='2d'):
super(DyReLU, self).__init__()
self.channels = channels
self.k = k
self.conv_type = conv_type
assert self.conv_type in ['1d', '2d']
self.fc1 = nn.Linear(channels, channels // reduction)
self.relu = nn.ReLU(inplace=True)
self.fc2 = nn.Linear(channels // reduction, 2*k)
self.sigmoid = nn.Sigmoid()
self.register_buffer('lambdas', torch.Tensor([1.]*k + [0.5]*k).float())
self.register_buffer('init_v', torch.Tensor([1.] + [0.]*(2*k - 1)).float())
def get_relu_coefs(self, x):
theta = torch.mean(x, axis=-1)
if self.conv_type == '2d':
theta = torch.mean(theta, axis=-1)
theta = self.fc1(theta)
theta = self.relu(theta)
theta = self.fc2(theta)
theta = 2 * self.sigmoid(theta) - 1
return theta
def forward(self, x):
raise NotImplementedError
class DyReLUA(DyReLU):
def __init__(self, channels, reduction=4, k=2, conv_type='2d'):
super(DyReLUA, self).__init__(channels, reduction, k, conv_type)
self.fc2 = nn.Linear(channels // reduction, 2*k)
def forward(self, x):
assert x.shape[1] == self.channels
theta = self.get_relu_coefs(x)
relu_coefs = theta.view(-1, 2*self.k) * self.lambdas + self.init_v
# BxCxL -> LxCxBx1
x_perm = x.transpose(0, -1).unsqueeze(-1)
output = x_perm * relu_coefs[:, :self.k] + relu_coefs[:, self.k:]
# LxCxBx2 -> BxCxL
result = torch.max(output, dim=-1)[0].transpose(0, -1)
return result
class DyReLUB(DyReLU):
def __init__(self, channels, reduction=4, k=2, conv_type='2d'):
super(DyReLUB, self).__init__(channels, reduction, k, conv_type)
self.fc2 = nn.Linear(channels // reduction, 2*k*channels)
def forward(self, x):
assert x.shape[1] == self.channels
theta = self.get_relu_coefs(x)
relu_coefs = theta.view(-1, self.channels, 2*self.k) * self.lambdas + self.init_v
if self.conv_type == '1d':
# BxCxL -> LxBxCx1
x_perm = x.permute(2, 0, 1).unsqueeze(-1)
output = x_perm * relu_coefs[:, :, :self.k] + relu_coefs[:, :, self.k:]
# LxBxCx2 -> BxCxL
result = torch.max(output, dim=-1)[0].permute(1, 2, 0)
elif self.conv_type == '2d':
# BxCxHxW -> HxWxBxCx1
x_perm = x.permute(2, 3, 0, 1).unsqueeze(-1)
output = x_perm * relu_coefs[:, :, :self.k] + relu_coefs[:, :, self.k:]
# HxWxBxCx2 -> BxCxHxW
result = torch.max(output, dim=-1)[0].permute(2, 3, 0, 1)
return result
if __name__ == '__main__':
x = torch.randn(1, 50, 100)
model = DyReLUA(channels=50, conv_type='1d')
y = model(x)
最後:圖網路相關論文裡面的theorem滿天飛,突然回頭看看ECCV的論文,總感覺少點什麼.
釋出於 09-12 深度學習(Deep Learning) 圖神經網路(GNN) 圖卷積神經網路 (GCN)文章被以下專欄收錄
圖網路學習與PyTorch 不定時更新圖網路學習筆記推薦閱讀
注意力機制+ReLU啟用函式=自適應引數化ReLU
雲程萬里南航提出ATAC:啟用函式和注意力機制的統一
CVer圖神經網路的新基準Benchmarking Graph Neural Networks
Mark圖卷積網路(GCN)入門詳解
圖卷積網路(GCN)入門詳解什麼是GCNGCN 概述模型定義數學推導Graph Laplacianref圖神經網路領域算是一個比較新的領域,有非常多的探索潛力,所以我也一直想著要入門。其中圖卷積網路就非常…
Don.hub4 條評論
寫下你的評論...-
foolbird09-13
這年頭relu改進還可以發頂會的嗎。。
- 一隻滑行的蝸牛09-14 有沒有線下試過,效果咋樣