當前位置:首頁 » 網路連接 » 殘差網路採用跳躍連接
擴展閱讀
手機網路不能共享文件夾 2025-09-26 23:43:13

殘差網路採用跳躍連接

發布時間: 2022-10-08 04:07:17

Ⅰ Resnet | Block的進化史——未完待續

https://arxiv.org/pdf/1512.03385.pdf

如上述圖片所示,Resnet通過提出shortcut連接,解決了深度學習網路在訓練過程中隨著網路層數越來越多而導致的網路退化問題。這種shortcut的連接有兩種形式,一種是完全的等價連接shortcut,另一種作為降采樣block的shortcut,使得add操作可以在同等維度上進行降采樣shortcut。另外考慮到耗時問題,為了減低更深的resnet網路的耗時,作者提出了一種Bottleneck結構,通過1*1卷積降低作用於3*3卷積的通道數,從而降低計算量和耗時。
對於shortcut的連接有點有兩種我比較認可的解釋:
1:跳躍連接實現了學習的靈活性,使得網路在訓練的過程中可以自由的選擇「更多進行卷積與非線性變換」還是「更多的傾向於什麼都不做」,或者是兩者結合。
2:跳躍連接使得網路剛開始訓練時,由於恆等連接shortcut的存在使得網路從物理上變得更淺,網路訓練更加容易。

https://arxiv.org/pdf/1603.05027.pdf
希望在訓練的過程中,不論是前向還是反向階段,信號可以直接從一個單元傳遞到其他任意一個單元,這種方式要比原始的Resnetblcok的性能更要好。

BN_after_addition:BNrelu的結果放在了恆等信號傳遞的路上,導致優化困難,阻礙了信息的傳遞。
ReLU_before_addition:將Relu放在信號傳遞的輸出部分,導致最終的輸出為非負值,這將限制網路特徵的表達范圍。
它的BN和ReLU全都放置在權重層的前面。
ReLU-only Pre-activation:ReLU層沒有和BN層直連在一起,因此無法共享BN層帶來的訓練優勢。
Pre-activation:這個方法最好。

https://arxiv.org/abs/2004.04989

1:提出了一種基於分段的殘差學習網路結構,該方法為信息在網路各層間的傳播提供了更好的途徑,從而簡化了學習過程。
2.更具原始的block和Pre-activation block存在的問題,作者提出了如下拓撲結構,該結構是一種分段的組織結構,細節為:
(1)把網路結構分為三個部分,四個主要stage和一個啟動和結束階段。
(2)四個主要階段中每個stage都可以包含若干個Blocks,stage1,2,3,4分別有Block的個數為(3,4,6,3)。
(3)每個stage又分為三個部分,一個開始Block,若干個中間Block。比如以resnet50的情況下,有[1,2,4,1]對應stage的中間block。start,middle,end三種blcok的設計如圖所示。

Ⅱ 什麼是skip connection

skip connection 就是一種跳躍式傳遞。在ResNet中引入了一種叫resial network殘差網路結構,其和普通的CNN的區別在於從輸入源直接向輸出源多連接了一條傳遞線,這是一種identity mapping,也就是所謂的恆等映射,用來進行殘差計算。這叫是shortcut connection,也叫skip connection。其效果是為了防止網路層數增加而導致的梯度彌散問題與退化問題。

Ⅲ 自學圍棋的AlphaGo Zero,你也可以造一個

  • 01

    遙想當年,AlphaGo的Master版本,在完勝柯潔九段之後不久,就被後輩AlphaGo Zero(簡稱狗零) 擊潰了。

    從一隻完全不懂圍棋的AI,到打敗Master,狗零隻用了21天。

    而且,它不需要用人類知識來喂養,成為頂尖棋手全靠自學。

    如果能培育這樣一隻AI,即便自己不會下棋,也可以很驕傲吧。

    於是,來自巴黎的少年Dylan Djian (簡稱小笛) ,就照著狗零的論文去實現了一下。

    他給自己的AI棋手起名SuperGo,也提供了代碼(傳送門見文底) 。

    除此之外,還有教程——

    一個身子兩個頭

    智能體分成三個部分:

    一是特徵提取器(Feature Extractor) ,二是策略網路(Policy Network) ,三是價值網路(Value Network) 。

    於是,狗零也被親切地稱為“雙頭怪”。特徵提取器是身子,其他兩個網路是腦子。

    特徵提取器

    特徵提取模型,是個殘差網路 (ResNet) ,就是給普通CNN加上了跳層連接 (Skip Connection) , 讓梯度的傳播更加通暢。

    跳躍的樣子,寫成代碼就是:

    1classBasicBlock(nn.Mole):

    2 """

    3 Basic resial block with 2 convolutions and a skip connection

    4 before the last ReLU activation.

    5 """

    6

    7def__init__(self, inplanes, planes, stride=1, downsample=None):

    8 super(BasicBlock, self).__init__()

    9

    10 self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=3,

    11 stride=stride, padding=1, bias=False)

    12 self.bn1 = nn.BatchNorm2d(planes)

    13

    14 self.conv2 = nn.Conv2d(planes, planes, kernel_size=3,

    15 stride=stride, padding=1, bias=False)

    16 self.bn2 = nn.BatchNorm2d(planes)

    17

    18

    19defforward(self, x):

    20 resial = x

    21

    22 out = self.conv1(x)

    23 out = F.relu(self.bn1(out))

    24

    25 out = self.conv2(out)

    26 out = self.bn2(out)

    27

    28 out += resial

    29 out = F.relu(out)

    30

    31returnout

    然後,把它加到特徵提取模型裡面去:

    1classExtractor(nn.Mole):

    2def__init__(self, inplanes, outplanes):

    3 super(Extractor, self).__init__()

    4 self.conv1 = nn.Conv2d(inplanes, outplanes, stride=1,

    5 kernel_size=3, padding=1, bias=False)

    6 self.bn1 = nn.BatchNorm2d(outplanes)

    7

    8forblockinrange(BLOCKS):

    9 setattr(self, "res{}".format(block),

    10 BasicBlock(outplanes, outplanes))

    11

    12

    13defforward(self, x):

    14 x = F.relu(self.bn1(self.conv1(x)))

    15forblockinrange(BLOCKS - 1):

    16 x = getattr(self, "res{}".format(block))(x)

    17

    18 feature_maps = getattr(self, "res{}".format(BLOCKS - 1))(x)

    19returnfeature_maps

    策略網路

    策略網路就是普通的CNN了,裡面有個批量標准化(Batch Normalization) ,還有一個全連接層,輸出概率分布。

    1classPolicyNet(nn.Mole):

    2def__init__(self, inplanes, outplanes):

    3 super(PolicyNet, self).__init__()

    4 self.outplanes = outplanes

    5 self.conv = nn.Conv2d(inplanes, 1, kernel_size=1)

    6 self.bn = nn.BatchNorm2d(1)

    7 self.logsoftmax = nn.LogSoftmax(dim=1)

    8 self.fc = nn.Linear(outplanes - 1, outplanes)

    9

    10

    11defforward(self, x):

    12 x = F.relu(self.bn(self.conv(x)))

    13 x = x.view(-1, self.outplanes - 1)

    14 x = self.fc(x)

    15 probas = self.logsoftmax(x).exp()

    16

    17returnprobas

    價值網路

    這個網路稍微復雜一點。除了標配之外,還要再多加一個全連接層。最後,用雙曲正切 (Hyperbolic Tangent) 算出 (-1,1) 之間的數值,來表示當前狀態下的贏面多大。

    代碼長這樣——

    1classValueNet(nn.Mole):

    2def__init__(self, inplanes, outplanes):

    3 super(ValueNet, self).__init__()

    4 self.outplanes = outplanes

    5 self.conv = nn.Conv2d(inplanes, 1, kernel_size=1)

    6 self.bn = nn.BatchNorm2d(1)

    7 self.fc1 = nn.Linear(outplanes - 1, 256)

    8 self.fc2 = nn.Linear(256, 1)

    9

    10

    11defforward(self, x):

    12 x = F.relu(self.bn(self.conv(x)))

    13 x = x.view(-1, self.outplanes - 1)

    14 x = F.relu(self.fc1(x))

    15 winning = F.tanh(self.fc2(x))

    16returnwinning

    未雨綢繆的樹

    狗零,還有一個很重要的組成部分,就是蒙特卡洛樹搜索(MCTS) 。

    它可以讓AI棋手提前找出,勝率最高的落子點。

    在模擬器里,模擬對方的下一手,以及再下一手,給出應對之策,所以提前的遠不止是一步。

    節點 (Node)

    樹上的每一個節點,都代表一種不同的局勢,有不同的統計數據:

    每個節點被經過的次數n,總動作值w,經過這一點的先驗概率p,平均動作值q (q=w/n) ,還有從別處來到這個節點走的那一步,以及從這個節點出發、所有可能的下一步。

    1classNode:

    2def__init__(self, parent=None, proba=None, move=None):

    3 self.p = proba

    4 self.n = 0

    5 self.w = 0

    6 self.q = 0

    7 self.children = []

    8 self.parent = parent

    9 self.move = move

    部署 (Rollout)

    第一步是PUCT (多項式上置信樹) 演算法,選擇能讓PUCT函數 (下圖) 的某個變體 (Variant)最大化,的走法。

    寫成代碼的話——

    1defselect(nodes, c_puct=C_PUCT):

    2 " Optimized version of the selection based of the PUCT formula "

    3

    4 total_count = 0

    5foriinrange(nodes.shape[0]):

    6 total_count += nodes[i][1]

    7

    8 action_scores = np.zeros(nodes.shape[0])

    9foriinrange(nodes.shape[0]):

    10 action_scores[i] = nodes[i][0] + c_puct * nodes[i][2] *

    11 (np.sqrt(total_count) / (1 + nodes[i][1]))

    12

    13 equals = np.where(action_scores == np.max(action_scores))[0]

    14ifequals.shape[0] > 0:

    15returnnp.random.choice(equals)

    16returnequals[0]

    結束 (Ending)

    選擇在不停地進行,直至到達一個葉節點 (Leaf Node) ,而這個節點還沒有往下生枝。

    1defis_leaf(self):

    2 """ Check whether a node is a leaf or not """

    3

    4returnlen(self.children) == 0

    到了葉節點,那裡的一個隨機狀態就會被評估,得出所有“下一步”的概率。

    所有被禁的落子點,概率會變成零,然後重新把總概率歸為1。

    然後,這個葉節點就會生出枝節 (都是可以落子的位置,概率不為零的那些) 。代碼如下——

    1defexpand(self, probas):

    2 self.children = [Node(parent=self, move=idx, proba=probas[idx])

    3foridxinrange(probas.shape[0])ifprobas[idx] > 0]

    更新一下

    枝節生好之後,這個葉節點和它的媽媽們,身上的統計數據都會更新,用的是下面這兩串代碼。

    1defupdate(self, v):

    2 """ Update the node statistics after a rollout """

    3

    4 self.w = self.w + v

    5 self.q = self.w / self.nifself.n > 0else0

    1whilecurrent_node.parent:

    2 current_node.update(v)

    3 current_node = current_node.parent

    選擇落子點

    模擬器搭好了,每個可能的“下一步”,都有了自己的統計數據。

    按照這些數據,演算法會選擇其中一步,真要落子的地方。

    選擇有兩種,一就是選擇被模擬的次數最多的點。試用於測試和實戰。

    另外一種,隨機 (Stochastically) 選擇,把節點被經過的次數轉換成概率分布,用的是以下代碼——

    1 total = np.sum(action_scores)

    2 probas = action_scores / total

    3 move = np.random.choice(action_scores.shape[0], p=probas)

    後者適用於訓練,讓AlphaGo探索更多可能的選擇。

    三位一體的修煉

    狗零的修煉分為三個過程,是非同步的。

    一是自對弈(Self-Play) ,用來生成數據。

    1defself_play():

    2whileTrue:

    3 new_player, checkpoint = load_player()

    4ifnew_player:

    5 player = new_player

    6

    7 ## Create the self-play match queue of processes

    8 results = create_matches(player, cores=PARALLEL_SELF_PLAY,

    9 match_number=SELF_PLAY_MATCH)

    10for_inrange(SELF_PLAY_MATCH):

    11 result = results.get()

    12 db.insert({

    13 "game": result,

    14 "id": game_id

    15 })

    16 game_id += 1

    二是訓練(Training) ,拿新鮮生成的數據,來改進當前的神經網路。

    1deftrain():

    2 criterion = AlphaLoss()

    3 dataset = SelfPlayDataset()

    4 player, checkpoint = load_player(current_time, loaded_version)

    5 optimizer = create_optimizer(player, lr,

    6 param=checkpoint['optimizer'])

    7 best_player = deep(player)

    8 dataloader = DataLoader(dataset, collate_fn=collate_fn,

    9 batch_size=BATCH_SIZE, shuffle=True)

    10

    11whileTrue:

    12forbatch_idx, (state, move, winner)inenumerate(dataloader):

    13

    14 ## Evaluate a of the current network

    15iftotal_ite % TRAIN_STEPS == 0:

    16 pending_player = deep(player)

    17 result = evaluate(pending_player, best_player)

    18

    19ifresult:

    20 best_player = pending_player

    21

    22 example = {

    23 'state': state,

    24 'winner': winner,

    25 'move' : move

    26 }

    27 optimizer.zero_grad()

    28 winner, probas = pending_player.predict(example['state'])

    29

    30 loss = criterion(winner, example['winner'],

    31 probas, example['move'])

    32 loss.backward()

    33 optimizer.step()

    34

    35 ## Fetch new games

    36iftotal_ite % REFRESH_TICK == 0:

    37 last_id = fetch_new_games(collection, dataset, last_id)

    訓練用的損失函數表示如下:

    1classAlphaLoss(torch.nn.Mole):

    2def__init__(self):

    3 super(AlphaLoss, self).__init__()

    4

    5defforward(self, pred_winner, winner, pred_probas, probas):

    6 value_error = (winner - pred_winner) ** 2

    7 policy_error = torch.sum((-probas *

    8 (1e-6 + pred_probas).log()), 1)

    9 total_error = (value_error.view(-1) + policy_error).mean()

    10returntotal_error

    三是評估(Evaluation) ,看訓練過的智能體,比起正在生成數據的智能體,是不是更優秀了 (最優秀者回到第一步,繼續生成數據) 。

    1defevaluate(player, new_player):

    2 results = play(player, opponent=new_player)

    3 black_wins = 0

    4 white_wins = 0

    5

    6forresultinresults:

    7ifresult[0] == 1:

    8 white_wins += 1

    9elifresult[0] == 0:

    10 black_wins += 1

    11

    12 ## Check if the trained player (black) is better than

    13 ## the current best player depending on the threshold

    14ifblack_wins >= EVAL_THRESH * len(results):

    15returnTrue

    16returnFalse

    第三部分很重要,要不斷選出最優的網路,來不斷生成高質量的數據,才能提升AI的棋藝。

    三個環節周而復始,才能養成強大的棋手。

    有志於AI圍棋的各位,也可以試一試這個PyTorch實現。

    本來摘自量子位,原作 Dylan Djian。

    代碼實現傳送門:

    網頁鏈接

    教程原文傳送門:

    網頁鏈接

    AlphaGo Zero論文傳送門:

    網頁鏈接

Ⅳ 論文閱讀 | CVPR2017(Best Paper) | Densely Connected Convolutional Networks

大名鼎鼎的DenseNet,17年CVPR的best paper(當然有爭議是後話),不得不讀。黃高博士的扛鼎之作,之前在讀他的Snapshot-Ensembles時感覺就很舒服,整個文章邏輯很清楚,實驗對比做的也十分全面,相信這篇best paper更是沒有問題,會給讀者一種爽的感覺。

2019.2.20 2852次。絕對值很高,但相比其他經典網路,ResNet,GoogLeNet之類,有些差距。

本篇在16年8月掛到arXiv上,中了2017年CVPR,是繼16年何大神的ResNet之後,第二個華人的best paper, 這里 有個作者本尊的talk,現場講解。一作Gao Huang(黃高)05年北航的本科生(GPA第一),15年清華博士畢業(讀了6年。。),後來在康奈爾待了3年做博後,此刻在清華作青椒,本篇是在康奈爾時的工作。二作劉壯(同等貢獻)也是碉堡,現在在伯克利做博士生,之前是清華姚班的(13級),發這篇文章時還在清華,也就是說 本科生 。。。最近以一作的身份新發了一篇《Rethinking the Value of Network Pruning》,中了19年的ICLR,同時也是18年NIPS的best paper award。。這個世界太瘋狂了,這都不是潛力股了,而是才華橫溢溢的不行了。

官方實現在這里: https://github.com/liuzhuang13/DenseNet

黃高個人主頁在這里: http://www.gaohuang.net/

劉壯個人主頁在這里: https://liuzhuang13.github.io/

先前的研究中說明只要網路包含短路連接,基本上就能更深,更准確,更有效的訓練。本文基於這個觀察,引入了密集卷積網路(DenseNet),它以前饋方式將每個層連接到所有層。傳統的卷積網路L層有L個連接,而DenseNet有 個直接連接。對於每一層,它前面所有層的特徵圖都當作輸入,而其本身的特徵圖作為所有後面層的輸入(短路連接被發揮到極致,網路中每兩層都相連)。DenseNet具有幾個引入注目的優點: 可以緩解梯度消失問題,加強特徵傳播,鼓勵特徵重用,並大幅減少參數數量。

隨著CNN變得越來越深,一個新的研究問題出現了:隨著輸入信息或梯度通過多層,它在到達網路結尾(或開始)處就消失了。ResNets和Highway Networks通過恆等連接將信號從一層傳輸到下一層。Stochastic depth通過在訓練期間隨機丟棄層來縮短ResNets,以得到更好的信息和梯度流。FractalNets重復組合幾個並行層序列和不同數量的卷積塊,以獲得較深的標准深度,同時在網路中保持許多短路徑。盡管上述方法的網路結構都有所不同,但它們有一個共同特徵:創建從早期層到後期層的短路徑。

本文提出一個簡單的連接模式:為了確保網路中各層之間的最大信息流, 將所有層(匹配特徵圖大小)直接相互連接 。為了保持前向傳播性質,每個層從所有前面的層獲得附加輸入,並將其自身特徵圖傳遞給所有後續層。

至關重要的是,與ResNets相比,在傳遞給下一層之前, 不是通過求和來合並特徵,而是通過concat來合並特徵 。因此, 層有 個輸入,包括所有先前卷積塊的特徵圖。其特徵圖被傳遞到後續所有 層。這在L層網路中引入了 個連接,而不是傳統架構的L個連接。正是因為這種密集連接模式,所以稱本文方法為密集連接網路( Dense Convolutional Network DenseNet)。

相比傳統卷積網路,這種密集連接模式有有一點可能違反直覺的是,它需要更少的參數,因為無需重新學習冗餘的特徵圖。本文提出的DenseNet架構顯式區分了添加到網路的信息和保留的信息。DenseNet的層非常窄(如每層只有12個濾波器),只給網路的"集體知識"增加一小組特徵圖,並保持其餘的特徵圖不變。

除了更好的參數利用率之外,DenseNet的一大優勢是它改善了整個網路中的信息流和梯度,使得網路更易於訓練。每層都可以直接訪問損失函數和原始輸入信號的梯度( 我屮,這不就是GoogLeNet當時為解決梯度消失而在中間層引入分類器那種ugly辦法的替代嗎 ),從而導致隱式的深度監督。這有助於訓練更深的網路。

與DenseNet相似的級聯結構早在1989年就提出來了。。Adanet的提出差不多是與DenseNet並行的,跨層連接也相似(話說競爭真激烈。。)

本文作者提出的另一個網路Stochastic depth說明並非所有層都需要,在深度殘差網路中存在大量冗餘的層。本文的部分靈感也來源於此。

相比從極深或極寬的架構中提取表示能力,DenseNet是通過 特徵重用 來利用網路的潛力,得到易於訓練和高參數效率的壓縮模型。相比從不同層拼接特徵的Inception網路,DenseNet更簡單有效(看來Inception因其結構復雜性沒少被批判)。

定義 為單張輸入圖像,網路由 層組成,每一層實現非線性變換 ,其中 為層的索引號。 可以是BN,ReLU,Pooling,Conv等操作的復合函數,定義 層的輸出為 。

傳統的層連接: 。ResNets增加了跳躍連接: 。ResNets的一個優勢是梯度可以通過恆等函數直接從後面的層流向前面的層。然而,恆等函數和 的輸出通過加法合並,有可能會阻礙網路的信息流。

本文引入與ResNets不同的連接模式:從任意層到所有後續層的直接連接(圖1)。結果就是,第 層接收所有之前層的特徵圖作為輸入: 。為了便於實現,concat 的多個輸入為單一張量。

受ResNet v2啟發,定義 為三個連續運算的復合函數:BN,ReLU,3 x 3 Conv

當特徵圖的大小改變時,concat運算是不可能的,然鵝,卷積網路的一個關鍵組成部分就是下采樣層,通過它可以改變特徵圖大小。為了便於在架構中進行下采樣,將網路劃分為多個密集連接的密集塊(dense blocks),如圖2所示。

將密集塊之間的層稱為過渡層(transition layers),它們進行卷積和池化。本文實驗中的過渡層由BN,1 x 1卷積和 2 x 2平均池化組成。

如果每個函數 生成 個特徵圖,它後面跟著的 層有 個輸入特徵圖,其中 是輸入層的通道數。DenseNet和現有網路架構的一個重要區別是DenseNet可以有非常窄的層,如 。本文將超參數 定義為網路的成長率(growth rate)。對此的一種解釋是,每一層都可以訪問其塊中所有前面的特徵圖,即,網路的『集體知識』。可以將特徵圖視為網路的全局狀態。每一層增加自己的 個特徵圖到這個狀態。成長率反映了每層由多少新信息對全局狀態有貢獻。全局狀態一旦寫入,就可以被網路中的任何地方訪問,而不像傳統網路那樣,無需從一層復制到另一層。(全文精華應該就是這一段了)

1x1 conv非常有用(提升計算效率),本文也大用特用。本文定義DenseNet-B的 為 BN-ReLU-Conv(1x1)-BN-ReLU-Conv(3x3)

為了使模型更緊湊,可以減少過渡層的特徵圖數量。如果密集塊包含 個特徵圖,定義接下來的過渡層生成 個特徵圖,其中 表示壓縮率。定義 的DenseNet為DenseNet-C,本位實驗中設置為 。當同時使用瓶頸層和壓縮過渡層時,定義模型為DenseNet-BC。

非ImageNet數據集採用同一個架構,由3個密集塊構成。ImageNet的架構如表1所示

CIFAR SVHN ImageNet

所有網路都用SGD。

CIFAR和SVHN的batch size為64,epoch分別為300和40,初始學習率為0.1,在50%和75%的epoch時分別除10。

ImageNet的batch size為256,90個epoch,初始學習率為0.1,在30和60epoch時分別除10。

weight decay為 ,動量為0.9。用He初始化。

對於CIFAR和SVHN,還在每個卷積層後接了dropout層(除第一個卷積層外),丟失率為0.2。

看錶2的最後一行

DenseNet可以利用更大更深模型表示能力的增長。

如圖4所示

主要用DenseNet-BC和ResNet作比較。

表面上看,DenseNets和ResNets沒什麼不同,兩個式子的差別僅僅是輸入從加法變為concat,然而,這種看似很小的修改導致兩種網路架構的行為明顯不同。

因為鼓勵特徵重用,所以得到更緊湊的模型。

如圖4所示。

對DenseNets准確率提升的一種解釋是各個層通過短路連接從損失函數接收額外的監督(某種深度監督)。DenseNets用隱式的方式執行相似的深度監督:網路頂部的單個分類器通過最多兩到三個過渡層為所有層提供直接監督。 然而,由於在所有層之間共享相同的損失函數,因此DenseNets的損失函數和梯度基本上不那麼復雜。

和隨機深度的對比,隨機深度有點類似DenseNet:如果所有中間層都隨機丟棄,那麼在相同的池化層之間的任意兩層都有可能直接連接。

DenseNet就是好,就是好啊就是好。在遵循簡單的連接規則的同時,DenseNets自然地整合了恆等映射,深度監督和多樣化深度的屬性。

又是一篇沒有什麼數學公式的paper,越來越感覺深度學習像物理,很多結果都是基於做實驗得到的。通過對實驗的觀察對比分析,找出實驗中的缺陷不足,從而去改進,然後發paper。黃高博士的寫作套路還是非常討喜的,特別是開頭的地方,娓娓道來,一步一步告訴你為什麼要這么做,為什麼要引入這一步。此外,DenseNets和作者本人的工作『隨機深度』也有千絲萬縷的關系,看來功夫做扎實了,沿著一條道路是可以出一系列成果的。

這是個好問題。。是要進一步衍生ResNet嗎?

提出密集連接結構,將ResNet的跳躍連接發揚光大為兩兩連接

效果比ResNet還好,通過減少濾波器個數(文中稱作成長率),參數量也下來了

感覺效果提升並沒有那麼明顯,被後續出來的ResNeXt超過了

各種網路結構的實現: https://towardsdatascience.com/history-of-convolutional-blocks-in-simple-code-96a7ddceac0c

黃高本人視頻講解: https://zhuanlan.hu.com/p/53417625

作者本人的解答: CVPR 2017最佳論文作者解讀:DenseNet 的「what」、「why」和「how」

DenseNet的3個優勢:

https://towardsdatascience.com/history-of-convolutional-blocks-in-simple-code-96a7ddceac0c

Ⅳ 十分鍾一起學會ResNet殘差網路

深度卷積網路自然的整合了低中高不同層次的特徵,特徵的層次可以靠加深網路的層次來豐富。從而,在構建卷積網路時,網路的深度越高,可抽取的特徵層次就越豐富。所以一般我們會傾向於使用更深層次的網路結構,以便取得更高層次的特徵。但是在使用深層次的網路結構時我們會遇到兩個問題,梯度消失,梯度爆炸問題和網路退化的問題。

但是當使用更深層的網路時,會發生梯度消失、爆炸問題,這個問題很大程度通過標準的初始化和正則化層來基本解決,這樣可以確保幾十層的網路能夠收斂,但是隨著網路層數的增加,梯度消失或者爆炸的問題仍然存在。

還有一個問題就是網路的退化,舉個例子,假設已經有了一個最優化的網路結構,是18層。當我們設計網路結構的時候,我們並不知道具體多少層次的網路時最優化的網路結構,假設設計了34層網路結構。那麼多出來的16層其實是冗餘的,我們希望訓練網路的過程中,模型能夠自己訓練這五層為恆等映射,也就是經過這層時的輸入與輸出完全一樣。但是往往模型很難將這16層恆等映射的參數學習正確,那麼就一定會不比最優化的18層網路結構性能好,這就是隨著網路深度增加,模型會產生退化現象。它不是由過擬合產生的,而是由冗餘的網路層學習了不是恆等映射的參數造成的。

ResNet是在2015年有何凱明,張翔宇,任少卿,孫劍共同提出的,ResNet使用了一個新的思想,ResNet的思想是假設我們涉及一個網路層,存在最優化的網路層次,那麼往往我們設計的深層次網路是有很多網路層為冗餘層的。那麼我們希望這些冗餘層能夠完成恆等映射,保證經過該恆等層的輸入和輸出完全相同。具體哪些層是恆等層,這個會有網路訓練的時候自己判斷出來。將原網路的幾層改成一個殘差塊,殘差塊的具體構造如下圖所示:

可以看到X是這一層殘差塊的輸入,也稱作F(x)為殘差,x為輸入值,F(X)是經過第一層線性變化並激活後的輸出,該圖表示在殘差網路中,第二層進行線性變化之後激活之前,F(x)加入了這一層輸入值X,然後再進行激活後輸出。在第二層輸出值激活前加入X,這條路徑稱作shortcut連接。

我們發現,假設該層是冗餘的,在引入ResNet之前,我們想讓該層學習到的參數能夠滿足h(x)=x,即輸入是x,經過該冗餘層後,輸出仍然為x。但是可以看見,要想學習h(x)=x恆等映射時的這層參數時比較困難的。ResNet想到避免去學習該層恆等映射的參數,使用了如上圖的結構,讓h(x)=F(x)+x;這里的F(x)我們稱作殘差項,我們發現,要想讓該冗餘層能夠恆等映射,我們只需要學習F(x)=0。學習F(x)=0比學習h(x)=x要簡單,因為一般每層網路中的參數初始化偏向於0,這樣在相比於更新該網路層的參數來學習h(x)=x,該冗餘層學習F(x)=0的更新參數能夠更快收斂,如圖所示:

假設該曾網路只經過線性變換,沒有bias也沒有激活函數。我們發現因為隨機初始化權重一般偏向於0,那麼經過該網路的輸出值為[0.6 0.6],很明顯會更接近與[0 0],而不是[2 1],相比與學習h(x)=x,模型要更快到學習F(x)=0。

並且ReLU能夠將負數激活為0,過濾了負數的線性變化,也能夠更快的使得F(x)=0。這樣當網路自己決定哪些網路層為冗餘層時,使用ResNet的網路很大程度上解決了學習恆等映射的問題,用學習殘差F(x)=0更新該冗餘層的參數來代替學習h(x)=x更新冗餘層的參數。

這樣當網路自行決定了哪些層為冗餘層後,通過學習殘差F(x)=0來讓該層網路恆等映射上一層的輸入,使得有了這些冗餘層的網路效果與沒有這些冗餘層的網路效果相同,這樣很大程度上解決了網路的退化問題。

我們發現很深的網路層,由於參數初始化一般更靠近0,這樣在訓練的過程中更新淺層網路的參數時,很容易隨著網路的深入而導致梯度消失,淺層的參數無法更新。

可以看到,假設現在需要更新 參數因為隨機初始化偏向於0,通過鏈式求導我們會發現, 相乘會得到更加接近於0的數,那麼所求的這個 的梯度就接近於0,也就產生了梯度消失的現象。

ResNet最終更新某一個節點的參數時,由於 ,由於鏈式求導後的結果如圖所示,不管括弧內右邊部分的求導參數有多小,因為左邊的1的存在,並且將原來的鏈式求導中的連乘變成了連加狀態(正是 ),都能保證該節點參數更新不會發生梯度消失或梯度爆炸現象。

這樣ResNet在解決了阻礙更深層次網路優化問題的兩個重要問題後,ResNet就能訓練更深層次幾百層乃至幾千層的網路並取得更高的精確度了。

這里是應用了ResNet的網路圖,這里如果遇到了h(x)=F(x)+x中x的維度與F(x)不同的維度時,我們需要對identity加入Ws來保持Ws*x的維度與F(x)的維度一致。

x與F(x)維度相同時:

x與F(x)維度不同時:

下邊是ResNet的網路結構圖:

使用1*1卷積減少參數和計算量:

如果用了更深層次的網路時,考慮到計算量,會先用1 * 1的卷積將輸入的256維降到64維,然後通過1*1恢復。這樣做的目的是減少參數量和計算量。

左圖是ResNet34,右圖是ResNet50/101/152。這一個模塊稱作building block,右圖稱之為bottleneck design。在面對50,101,152層的深層次網路,意味著有很大的計算量,因此這里使用1 * 1卷積先將輸入進行降維,然後再經過3 * 3卷積後再用 卷積進行升維。使用1*1卷積的好處是大大降低參數量計算量。

通過上述的學習,你應該知道了,現如今大家普遍認為更好的網路是建立在更寬更深的網路基礎上,當你需要設計一個深度網路結構時,你永遠不知道最優的網路層次結構是多少層,一旦你設計的很深入了,那勢必會有很多冗餘層,這些冗餘層一旦沒有成功學習恆等變換 ,那就會影響網路的預測性能,不會比淺層的網路學習效果好從而產生退化問題。

ResNet的過人之處,是他很大程度上解決了當今深度網路頭疼的網路退化問題和梯度消失問題。使用殘差網路結構 代替原來的沒有shortcut連接的 ,這樣更新冗餘層的參數時需要學習 比學習 要容易得多。而shortcut連接的結構也保證了反向傳播更新參數時,很難有梯度為0的現象發生,不會導致梯度消失。

這樣,ResNet的構建,使我們更朝著符合我們的直覺走下去,即越深的網路對於高級抽象特徵的提取和網路性能更好,不用在擔心隨著網路的加深發生退化問題了。

近段時間,准備持續發表一些CNN常見的網路模型講解。好了,今天的十分鍾就帶你一起學會ResNet,下次的十分鍾我們再見。

Ⅵ 圖像分割模型U—Net融合淺層特徵的方式是什麼

摘要 提出一種將殘差結構與U-Net網路融合的視盤分割方法。殘差模塊的跳躍連接能將淺層特徵傳遞給更深一層網路,實現淺層特徵的重復使用,增強了圖像細節學習。將該方法在兩個公開數據集Messidor和Kaggle上進行驗證,在干擾較多的Kaggle數據集上,其AUC和MAP分別達到0.952 1和0.838 8,證明該方法可同時學習圖像細節特徵和全局結構特徵,能更好地區分眼底視盤與亮病灶