殘差神經網絡(ResNet)

殘差神經網絡(Residual Neural Network,簡稱 ResNet)是深度學習領域的里程碑式模型,由何凱明等人在 2015 年提出,成功解決了深層神經網絡訓練中的梯度消失 / 爆炸問題,使訓練超深網絡(如 152 層)成為可能。以下從核心原理、結構設計、優勢與應用等方面進行詳解。

一、核心問題:深層網絡的訓練困境

在 ResNet 提出前,隨著網絡層數增加,模型性能會先提升,然后迅速下降 —— 這種下降并非由過擬合導致,而是因為深層網絡的梯度難以有效傳遞到淺層,導致淺層參數無法被充分訓練(梯度消失 / 爆炸)。

ResNet 通過引入 “殘差連接”(Residual Connection)解決了這一問題。

二、核心原理:殘差連接與恒等映射

1. 傳統網絡的映射方式

傳統深層網絡中,每一層的目標是學習一個 “直接映射”(Direct Mapping):
設輸入為x,經過多層非線性變換后,輸出為H(x),即網絡需要學習H(x)。

2. 殘差網絡的映射方式

ResNet 提出:不直接學習H(x),而是學習 “殘差”F(x)=H(x)?x
此時,原映射可表示為:H(x)=F(x)+x
其中,F(x)是殘差函數(由若干卷積層 / 激活函數組成),x通過 “跳躍連接”(Skip Connection)直接與F(x)相加,形成最終輸出。

3. 為什么殘差連接有效?
  • 梯度傳遞更順暢:反向傳播時,梯度可通過x直接傳遞到淺層(避免梯度消失)。例如,若F(x)=0,則H(x)=x,形成 “恒等映射”,網絡可輕松學習到這種簡單映射,再在此基礎上優化殘差。
  • 簡化學習目標:學習殘差F(x)比直接學習H(x)更簡單。例如,當目標映射接近恒等映射時,F(x)接近 0,網絡只需微調即可,無需重新學習復雜的映射。

三、ResNet 的基本結構:殘差塊(Residual Block)

殘差塊是 ResNet 的基本單元,分為兩種類型:

1. 基本殘差塊(Basic Block,用于 ResNet-18/34)

由 2 個卷積層組成,結構如下:x→Conv2d(64,3x3)→BN→ReLU→Conv2d(64,3x3)→BN→(+x)→ReLU

  • 輸入x先經過兩個 3x3 卷積層(帶批歸一化 BN 和 ReLU 激活),得到殘差F(x)。
  • 若輸入x與F(x)的維度相同(通道數、尺寸一致),則直接相加(恒等映射);若維度不同(如 stride > 1 或通道數變化),則需通過 1x1 卷積調整x的維度(稱為 “投影捷徑”,Projection Shortcut):x→Conv2d(out_channels,1x1,stride)→BN→(+F(x))
2. 瓶頸殘差塊(Bottleneck Block,用于 ResNet-50/101/152)

為減少計算量,用 3 個卷積層(1x1 + 3x3 + 1x1)組成,結構如下:x→Conv2d(C,1x1)→BN→ReLU→Conv2d(C,3x3)→BN→ReLU→Conv2d(4C,1x1)→BN→(+x′)→ReLU

  • 1x1 卷積用于 “降維”(減少通道數),3x3 卷積用于提取特征,最后 1x1 卷積 “升維”(恢復通道數),顯著降低計算量。
  • 同樣支持投影捷徑(當維度不匹配時)。

四、完整 ResNet 的網絡架構

ResNet 通過堆疊殘差塊形成深層網絡,不同層數的 ResNet 結構如下表:

網絡類型殘差塊類型卷積層配置(每個階段的殘差塊數量)總層數
ResNet-18基本塊[2, 2, 2, 2]18
ResNet-34基本塊[3, 4, 6, 3]34
ResNet-50瓶頸塊[3, 4, 6, 3]50
ResNet-101瓶頸塊[3, 4, 23, 3]101
ResNet-152瓶頸塊[3, 8, 36, 3]152

  • 整體流程:輸入圖像 → 7x7 卷積(步長 2)+ 最大池化 → 4 個階段的殘差塊堆疊(每個階段通道數翻倍,尺寸減半) → 全局平均池化 → 全連接層(輸出分類結果)。

五、ResNet 的優勢

  1. 解決深層網絡訓練難題:通過殘差連接實現梯度有效傳遞,可訓練數百層甚至上千層的網絡。
  2. 性能優異:在 ImageNet 等數據集上,ResNet 的錯誤率顯著低于 VGG、GoogLeNet 等模型。
  3. 泛化能力強:殘差結構可遷移到其他任務(如目標檢測、語義分割),成為許多深度學習模型的基礎組件(如 Faster R-CNN、U-Net++)。

六、ResNet 的變體與延伸

  1. ResNeXt:引入 “分組卷積”(Group Convolution),在保持性能的同時減少參數。
  2. DenseNet:將殘差連接的 “相加” 改為 “拼接”(Concatenate),強化特征復用。
  3. Res2Net:在殘差塊中引入多尺度特征融合,提升細粒度特征提取能力。
  4. 應用擴展:從圖像分類擴展到目標檢測(如 FPN)、視頻分析(如 I3D)、自然語言處理(如殘差 LSTM)等領域。

七、總結

ResNet 通過殘差連接的創新設計,突破了深層網絡的訓練瓶頸,不僅推動了計算機視覺的發展,也為其他領域的深層模型設計提供了重要思路。其核心思想 ——通過簡化學習目標(學習殘差)提升模型性能—— 已成為深度學習的經典范式。

import torch
import torch.nn as nn
import torch.nn.functional as Fclass BasicBlock(nn.Module):"""基本殘差塊,用于ResNet-18/34"""expansion = 1  # 輸出通道數是輸入的多少倍def __init__(self, in_channels, out_channels, stride=1, downsample=None):super(BasicBlock, self).__init__()# 第一個卷積層self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)self.bn1 = nn.BatchNorm2d(out_channels)# 第二個卷積層(步長固定為1)self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)self.bn2 = nn.BatchNorm2d(out_channels)self.relu = nn.ReLU(inplace=True)self.downsample = downsample  # 用于調整輸入x的維度以匹配殘差def forward(self, x):identity = x  # 保存輸入用于殘差連接# 計算殘差F(x)out = self.conv1(x)out = self.bn1(out)out = self.relu(out)out = self.conv2(out)out = self.bn2(out)# 如果需要調整維度,則對輸入x進行下采樣if self.downsample is not None:identity = self.downsample(x)# 殘差連接:H(x) = F(x) + xout += identityout = self.relu(out)return outclass Bottleneck(nn.Module):"""瓶頸殘差塊,用于ResNet-50/101/152"""expansion = 4  # 輸出通道數是中間層的4倍def __init__(self, in_channels, out_channels, stride=1, downsample=None):super(Bottleneck, self).__init__()# 1x1卷積降維self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, bias=False)self.bn1 = nn.BatchNorm2d(out_channels)# 3x3卷積提取特征self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)self.bn2 = nn.BatchNorm2d(out_channels)# 1x1卷積升維self.conv3 = nn.Conv2d(out_channels, out_channels * self.expansion, kernel_size=1, stride=1, bias=False)self.bn3 = nn.BatchNorm2d(out_channels * self.expansion)self.relu = nn.ReLU(inplace=True)self.downsample = downsampledef forward(self, x):identity = x# 計算殘差F(x)out = self.conv1(x)out = self.bn1(out)out = self.relu(out)out = self.conv2(out)out = self.bn2(out)out = self.relu(out)out = self.conv3(out)out = self.bn3(out)# 調整輸入維度if self.downsample is not None:identity = self.downsample(x)# 殘差連接out += identityout = self.relu(out)return outclass ResNet(nn.Module):"""ResNet主網絡"""def __init__(self, block, layers, num_classes=1000):super(ResNet, self).__init__()self.in_channels = 64  # 初始輸入通道數# 初始卷積層self.conv1 = nn.Conv2d(3, self.in_channels, kernel_size=7, stride=2, padding=3, bias=False)self.bn1 = nn.BatchNorm2d(self.in_channels)self.relu = nn.ReLU(inplace=True)self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)# 四個階段的殘差塊self.layer1 = self._make_layer(block, 64, layers[0], stride=1)self.layer2 = self._make_layer(block, 128, layers[1], stride=2)self.layer3 = self._make_layer(block, 256, layers[2], stride=2)self.layer4 = self._make_layer(block, 512, layers[3], stride=2)# 分類頭self.avgpool = nn.AdaptiveAvgPool2d((1, 1))self.fc = nn.Linear(512 * block.expansion, num_classes)# 初始化權重for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')elif isinstance(m, nn.BatchNorm2d):nn.init.constant_(m.weight, 1)nn.init.constant_(m.bias, 0)def _make_layer(self, block, out_channels, blocks, stride=1):"""構建一個由多個殘差塊組成的層"""downsample = None# 如果步長不為1或輸入輸出通道數不匹配,需要下采樣調整維度if stride != 1 or self.in_channels != out_channels * block.expansion:downsample = nn.Sequential(nn.Conv2d(self.in_channels, out_channels * block.expansion,kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(out_channels * block.expansion),)layers = []# 添加第一個殘差塊(可能包含下采樣)layers.append(block(self.in_channels, out_channels, stride, downsample))self.in_channels = out_channels * block.expansion# 添加剩余的殘差塊(步長固定為1)for _ in range(1, blocks):layers.append(block(self.in_channels, out_channels))return nn.Sequential(*layers)def forward(self, x):# 初始特征提取x = self.conv1(x)x = self.bn1(x)x = self.relu(x)x = self.maxpool(x)# 經過四個殘差層x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)# 分類x = self.avgpool(x)x = torch.flatten(x, 1)x = self.fc(x)return x# 定義不同層數的ResNet
def resnet18(num_classes=1000):return ResNet(BasicBlock, [2, 2, 2, 2], num_classes)def resnet34(num_classes=1000):return ResNet(BasicBlock, [3, 4, 6, 3], num_classes)def resnet50(num_classes=1000):return ResNet(Bottleneck, [3, 4, 6, 3], num_classes)def resnet101(num_classes=1000):return ResNet(Bottleneck, [3, 4, 23, 3], num_classes)def resnet152(num_classes=1000):return ResNet(Bottleneck, [3, 8, 36, 3], num_classes)# 測試代碼
if __name__ == "__main__":# 創建ResNet-18模型model = resnet18(num_classes=10)# 隨機生成一個3通道輸入(模擬224x224圖像)x = torch.randn(2, 3, 224, 224)  # batch_size=2# 前向傳播output = model(x)print(f"輸入形狀: {x.shape}")print(f"輸出形狀: {output.shape}")  # 應輸出(2, 10)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/96306.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/96306.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/96306.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

學習嵌入式之驅動

一、基礎搭建1.基礎:c語言 軟件編程語言 數據結構 軟件編程思想2.驅動實現目標如果將Linux系統細致到開發板平臺上? Liunx系統與硬件設備的適配3.自我能力的鍛煉繼續強化C語言鍛煉大型代碼閱讀和分析能力學習大型項目的代碼搭建和管理的能力…

在 Golang 中復用 HTTP 連接

問題提出最近在實現一個轉發大模型調用請求的中轉功能,涉及到要構造client發送請求的內容,一開始我每次都是新建一個client來發送請求,這樣的代碼實現存在一些問題——每次都要構造新的client,并且要重新建立連接。后面了解到在Go…

前端:el-upload文件上傳與FormData 對象

<el-uploadclass"uploadDemo":limit"1"dragaccept".xls,.xlsx" <!-- 只保留Excel格式 -->:on-exceed"handleExceedFileLimit":on-change"handleChangeExcelFile":on-remove"handleRemoveExcelFile":bef…

自然處理語言NLP:One-Hot編碼、TF-IDF、詞向量、NLP特征輸入、EmbeddingLayer實現、word2vec

文章目錄自然語言處理&#xff08;NLP&#xff09;一、什么是自然語言處理&#xff08;NLP&#xff09;&#xff1f;二、NLP 的核心目標三、NLP 的主要應用方向&#xff08;應用場景&#xff09;四、NLP 的基本概念五、NLP 的基本處理流程1. 文本預處理2. 特征表示3. 模型選擇與…

單詞記憶-輕松記憶10個實用英語單詞(13)

1. board含義&#xff1a;板子&#xff1b;董事會&#xff1b;登機 讀音標注&#xff1a;/b??rd/ 例句&#xff1a;Write your name on the board. 譯文&#xff1a;把你的名字寫在板上。 衍生含義&#xff1a;董事會&#xff08;如“board of directors”&#xff09;&#…

Spring循環依賴源碼調試詳解,用兩級緩存代替三級緩存

Spring循環依賴源碼詳解&#xff0c;改用兩級緩存并實驗 背景 最近一直在研究Spring的循環依賴&#xff0c;發現好像兩級緩存也能解決循環依賴。 關于為何使用三級緩存&#xff0c;大致有兩個原因 對于AOP的類型&#xff0c;保證Bean生命周期的順序 對于有AOP代理增強的類型&am…

亞馬遜BALL PIT球池外觀專利侵權指控?不侵權意見書助力4條鏈接申訴成功!

兒童球池作為玩具品類中常見的一款產品&#xff0c;能夠給兒童提供游樂的安全空間&#xff0c;深受亞馬遜平臺用戶的喜愛。然而在近期&#xff0c;賽貝收到了部分亞馬遜賣家的咨詢&#xff0c;原因是他們在售的兒童球池產品鏈接被美國外觀專利USD1009203S&#xff08;下稱203專…

開源,LangExtract-Python庫用LLM從非結構化文本提取結構化信息

摘要&#xff1a; LangExtract是一個Python庫&#xff0c;利用大語言模型&#xff08;LLM&#xff09;根據用戶定義指令從非結構化文本文檔中提取結構化信息。它具備精確源定位、可靠結構化輸出、長文檔優化、交互式可視化、靈活LLM支持、適應任意領域等特點。可通過幾行代碼快…

如何根據團隊技術能力選擇最適合的PHP框架?

作為一名PHP開發者&#xff0c;面對眾多的PHP框架&#xff0c;你是否曾感到選擇困難&#xff1f;Laravel、Symfony、CodeIgniter、ThinkPHP…每個框架都有其特色和優勢&#xff0c;但沒有最好的框架&#xff0c;只有最適合的框架。而選擇合適框架的關鍵因素之一&#xff0c;就是…

多人同時導出 Excel 導致內存溢出

1、問題根因分析多人同時導出Excel導致內存溢出&#xff08;OOM&#xff09;的核心原因是&#xff1a;在短時間內&#xff0c;大量數據被加載到JVM堆內存中&#xff0c;且創建了大量大對象&#xff08;如Apache POI的Cell、Row、Sheet對象&#xff09;&#xff0c;超過了堆內存…

深入 RAG(檢索增強生成)系統架構:如何構建一個能查資料的大語言模型系統

&#x1f407;明明跟你說過&#xff1a;個人主頁 &#x1f3c5;個人專欄&#xff1a;《深度探秘&#xff1a;AI界的007》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目錄 一、前言 1、LLM 的局限&#xff1a;模型知識“封閉” vs 現實知識…

linux tftpboot燒寫地址分析

1&#xff0c;loadaddr 是一個環境變量&#xff0c;用于指定文件&#xff08;如內核鏡像、設備樹等&#xff09;加載到內存的起始地址。setenv loadaddr 0x82000000setenv loadaddr 0x80008000saveenv //.保存配置將 loadaddr 設置為 0x82000000&#xff0c;表示后續文件將加載…

硬件工程師9月實戰項目分享

目錄 簡介 人員情況 實戰項目簡介 功能需求 需求分析 方案設計 電源樹設計 時鐘樹設計 主芯片外圍設計 接口設計 模擬鏈路設計 PCB設計檢查要點 測試方案設計 硬件測試培訓 測試代碼學習 培訓目標 掌握基本的硬件設計流程 掌握以FPGA為核心的硬件設計業務知識 …

力扣刷題——59.螺旋矩陣II

力扣刷題——59.螺旋矩陣II 題目 給你一個正整數 n &#xff0c;生成一個包含 1 到 n2 所有元素&#xff0c;且元素按順時針順序螺旋排列的 n x n 正方形矩陣 matrix 。示例 1&#xff1a;輸入&#xff1a;n 3 輸出&#xff1a;[[1,2,3],[8,9,4],[7,6,5]]示例 2&#xff1a; 輸…

win11系統還原點恢復系統

背景 系統換位bug11后&#xff0c;真的是各種以前的操作和設置找不到&#xff0c;太煩了&#xff0c;我是沒想到&#xff0c;連系統恢復還原點都這么難找。然后搜了一圈都是恢復系統之類的&#xff0c;真的崩潰。只好自己記錄了。 ?內容找到設置—>系統–>系統信息系統信…

DHCP 原理與配置(一)

應用場景隨著網絡規模的不斷擴大&#xff0c;網絡復雜度不斷提升&#xff0c;網絡中的終端設備例如主機、手機、 平板等&#xff0c;位置經常變化。終端設備訪問網絡時需要配置IP地址、網關地址、DNS服務器 地址等。采用手工方式為終端配置這些參數非常低效且不夠靈活。 IETF于…

SARibbon的編譯構建及詳細用法

目錄 1.1 源碼構建 1.2 搭建項目 1.3 詳細用法 1.4 不同風格 1.5 完整代碼 引言:SARibbon是一個專門為Qt框架設計的開源Ribbon風格界面控件庫,它模仿了微軟Office和WPS的Ribbon UI風格,適用于需要復雜菜單和工具欄的大型桌面程序。本文從源碼編譯構建到詳細使用,做了一…

CSS【詳解】性能優化

精簡 CSS移除未使用的 CSS&#xff08;“死代碼”&#xff09;&#xff0c;可借助工具如 PurgeCSS、UnCSS 自動檢測并刪除未被頁面使用的樣式。避免重復樣式&#xff0c;通過提取公共樣式&#xff08;如 mixin 或公共類&#xff09;減少代碼冗余。利用預處理器&#xff08;Sass…

Flutter 線程模型詳解:主線程、異步與 Isolate

一、主線程&#xff1a;默認的執行環境 所有代碼默認運行在主線程。下面的例子展示了一個會阻塞主線程的錯誤示范&#xff1a; import package:flutter/material.dart;void main() {runApp(const MyApp()); }class MyApp extends StatelessWidget {const MyApp({super.key});ov…

ChartDB:可視化數據庫設計工具私有化部署

ChartDB:可視化數據庫設計工具私有化部署一、什么是ChartDB ChartDB 是一款基于 Web 的開源數據庫可視化工具&#xff0c;專為簡化數據庫設計與管理流程而開發。以下是其核心特性與功能概述: 1、核心功能 智能查詢可視化?&#xff1a;通過單條 SQL 查詢即可生成數據庫架構圖&a…