習(xí)模型FLOPs計(jì)算全解析:從原理到工程實(shí)踐)
1. 項(xiàng)目概述為什么我們需要關(guān)心FLOPs在深度學(xué)習(xí)的項(xiàng)目里尤其是當(dāng)你開(kāi)始從跑通Demo轉(zhuǎn)向模型優(yōu)化、部署上線時(shí)總會(huì)遇到一個(gè)繞不開(kāi)的指標(biāo)FLOPs。我第一次被問(wèn)到“你這個(gè)模型有多少FLOPs”的時(shí)候也是一頭霧水心想這跟“FLOPS”每秒浮點(diǎn)運(yùn)算次數(shù)衡量硬件算力的單位不是一回事嗎后來(lái)在模型壓縮、移動(dòng)端部署上踩過(guò)幾次坑才明白搞清FLOPs并會(huì)計(jì)算它是模型工程師從“煉丹”走向“工程”的關(guān)鍵一步。簡(jiǎn)單來(lái)說(shuō)FLOPs注意小寫(xiě)‘s’是floating point operations的縮寫(xiě)指的是模型完成一次前向傳播或一次推理所需要的浮點(diǎn)運(yùn)算次數(shù)。它是一個(gè)衡量模型計(jì)算復(fù)雜度或“計(jì)算量”的指標(biāo)。而FLOPS大寫(xiě)‘S’是floating point operations per second的縮寫(xiě)則是衡量硬件如CPU、GPU計(jì)算速度的單位比如“這顆GPU的峰值算力是10 TFLOPS”意思是它每秒能進(jìn)行10萬(wàn)億次浮點(diǎn)運(yùn)算。一個(gè)關(guān)乎模型本身“有多重”一個(gè)關(guān)乎硬件“跑多快”兩者天差地別但名字又如此相似混淆它們是新手上路最常見(jiàn)的“坑”之一。那么我們?yōu)槭裁捶堑藐P(guān)心FLOPs呢從我實(shí)際做移動(dòng)端AI應(yīng)用和模型輕量化的經(jīng)驗(yàn)來(lái)看主要有三個(gè)核心場(chǎng)景模型選型與對(duì)比當(dāng)你在兩個(gè)精度相近的模型間猶豫時(shí)FLOPs是關(guān)鍵的決策依據(jù)。一個(gè)FLOPs更低的模型意味著在相同硬件上推理更快、耗電更少。在資源受限的邊緣設(shè)備如手機(jī)、攝像頭上這直接決定了應(yīng)用是否可行。性能瓶頸分析通過(guò)計(jì)算模型中各層的FLOPs你可以像做性能剖析Profiling一樣精準(zhǔn)定位到計(jì)算“熱點(diǎn)”??赡?0%的計(jì)算量都集中在某幾個(gè)卷積層那么優(yōu)化如剪枝、量化就應(yīng)該優(yōu)先針對(duì)這些層做到有的放矢。學(xué)術(shù)研究與創(chuàng)新在發(fā)表論文或設(shè)計(jì)新模型結(jié)構(gòu)如輕量化網(wǎng)絡(luò)MobileNet、ShuffleNet時(shí)FLOPs是和準(zhǔn)確率Accuracy并列的核心評(píng)價(jià)指標(biāo)。它回答了“你的模型創(chuàng)新在計(jì)算效率上帶來(lái)了多少提升”這個(gè)問(wèn)題。因此無(wú)論你是算法研究員、工程部署工程師還是剛?cè)腴T的學(xué)習(xí)者理解并掌握FLOPs的計(jì)算都是深入理解模型內(nèi)部運(yùn)作、進(jìn)行高效開(kāi)發(fā)和優(yōu)化的必備技能。下面我就結(jié)合具體的網(wǎng)絡(luò)層拆解FLOPs的計(jì)算方法并分享一些工具使用和實(shí)際分析中的心得。2. FLOPs核心計(jì)算原理與逐層拆解計(jì)算FLOPs本質(zhì)上是對(duì)模型前向傳播中所有涉及浮點(diǎn)數(shù)乘加運(yùn)算的計(jì)數(shù)。最基礎(chǔ)的運(yùn)算單元是乘加運(yùn)算Multiply-Add, MA。在深度學(xué)習(xí)中一次乘法和一次加法常被綁定在一起視為一次操作但值得注意的是有些計(jì)算庫(kù)或論文中將一次乘加計(jì)為1個(gè)FLOP而另一些則將其計(jì)為2個(gè)FLOP乘法1次加法1次。目前社區(qū)更常見(jiàn)的約定是1次乘加運(yùn)算 2次浮點(diǎn)運(yùn)算。我們?cè)诤罄m(xù)計(jì)算和工具使用時(shí)需要留意這個(gè)差異。為了統(tǒng)一本文后續(xù)均采用1 MAC 2 FLOPs的約定進(jìn)行闡述。2.1 全連接層的FLOPs計(jì)算全連接層是理解FLOPs計(jì)算最好的起點(diǎn)。假設(shè)一個(gè)全連接層輸入向量維度為M輸出向量維度為N。對(duì)于輸出的每一個(gè)元素都需要進(jìn)行M次乘法權(quán)重乘以輸入和M次加法累加求和。所以計(jì)算一個(gè)輸出元素需要2M次浮點(diǎn)運(yùn)算。該層共有N個(gè)輸出元素。因此該全連接層的總FLOPs為FLOPs_fc N * (2M) 2 * M * N注意這里通常忽略了偏置項(xiàng)bias的加法。如果考慮偏置每個(gè)輸出元素會(huì)額外增加一次加法總FLOPs約為2 * M * N N。當(dāng)M很大時(shí)偏置項(xiàng)的影響可以忽略不計(jì)。許多計(jì)算工具默認(rèn)不計(jì)入偏置。實(shí)操心得全連接層是FLOPs的“大戶”尤其是在分類網(wǎng)絡(luò)的最后幾層。例如ResNet-50最后一個(gè)全連接層1000個(gè)類別輸入維度是2048其FLOPs高達(dá)2 * 2048 * 1000 4.1M。這也是為什么在輕量化網(wǎng)絡(luò)中常用全局平均池化GAP替代全連接層因?yàn)镚AP幾乎不引入額外的FLOPs。2.2 卷積層的FLOPs計(jì)算卷積層是CNN中FLOPs的主要來(lái)源計(jì)算也稍復(fù)雜。我們定義以下參數(shù)H_in, W_in, C_in: 輸入特征圖的高、寬、通道數(shù)。K_h, K_w: 卷積核的高和寬。C_out: 輸出通道數(shù)即卷積核的個(gè)數(shù)。H_out, W_out: 輸出特征圖的高和寬由輸入尺寸、Padding、Stride等決定。計(jì)算分兩步理解一次卷積操作在一個(gè)空間位置用一個(gè)C_in通道的卷積核與輸入對(duì)應(yīng)位置的局部區(qū)域做逐通道相乘并求和。這需要K_h * K_w * C_in次乘法和同樣次數(shù)的加法減1次嚴(yán)格說(shuō)是K_h*K_w*C_in - 1次加法但通常近似。所以一次卷積操作的FLOPs約為2 * K_h * K_w * C_in。全部卷積操作輸出特征圖有H_out * W_out個(gè)空間位置并且有C_out個(gè)不同的卷積核輸出通道。因此總的FLOPs為FLOPs_conv 2 * K_h * K_w * C_in * H_out * W_out * C_out為什么這么算你可以想象為每個(gè)輸出特征圖上的一個(gè)像素點(diǎn)都是由C_out個(gè)卷積核分別與輸入的一個(gè)局部區(qū)域進(jìn)行三維立體寬、高、通道的乘加運(yùn)算得到的。這個(gè)公式清晰地揭示了計(jì)算量與卷積核大小、輸入輸出通道數(shù)以及特征圖尺寸的乘積關(guān)系。一個(gè)具體例子輸入為224x224x3的圖片經(jīng)過(guò)一個(gè)3x3卷積輸出通道為64步幅為1填充為1保證輸出尺寸不變。則H_out W_out 224。FLOPs 2 * 3 * 3 * 3 * 224 * 224 * 64 ≈ 173.4M。這是一個(gè)非常典型的計(jì)算量。2.3 其他常見(jiàn)層的FLOPs計(jì)算池化層最大/平均池化池化操作通常不涉及乘加運(yùn)算主要是比較或取平均。雖然有一些加法或比較操作但其計(jì)算量遠(yuǎn)小于卷積層在粗略估算模型FLOPs時(shí)常常被忽略。精確計(jì)算時(shí)平均池化可視為除法的加法但FLOPs占比極小。激活層ReLU, Sigmoid等像ReLU這樣的激活函數(shù)max(0, x)只涉及簡(jiǎn)單的比較和賦值操作不涉及浮點(diǎn)乘加因此通常不計(jì)入FLOPs。Sigmoid、Tanh等復(fù)雜激活函數(shù)涉及指數(shù)運(yùn)算計(jì)算成本較高但在現(xiàn)代網(wǎng)絡(luò)中如使用ReLU其影響通常也不單獨(dú)計(jì)算。批量歸一化層BatchNorm在訓(xùn)練時(shí)BN層需要計(jì)算均值和方差涉及加法和乘法。但在推理階段BN層通常會(huì)被“折疊”進(jìn)其前面的卷積層或全連接層的權(quán)重和偏置中因此不增加額外的FLOPs。這是模型部署時(shí)的一個(gè)重要優(yōu)化點(diǎn)。跳躍連接Skip Connection如ResNet中的加法操作需要將兩個(gè)張量相加。這會(huì)產(chǎn)生H*W*C次浮點(diǎn)加法。雖然計(jì)算量相對(duì)較小但在精確計(jì)算時(shí)應(yīng)當(dāng)計(jì)入。例如一個(gè)56x56x256的特征圖做逐元素相加會(huì)產(chǎn)生約56*56*256 0.8M次浮點(diǎn)運(yùn)算0.4M FLOPs如果按1加法1 FLOP算。3. 實(shí)戰(zhàn)手動(dòng)計(jì)算與工具使用指南理解了原理我們進(jìn)入實(shí)戰(zhàn)環(huán)節(jié)。在實(shí)際工作中我們很少徒手計(jì)算整個(gè)網(wǎng)絡(luò)的FLOPs但掌握手動(dòng)計(jì)算局部的能力有助于理解和驗(yàn)證工具結(jié)果。3.1 手動(dòng)計(jì)算一個(gè)小型CNN模塊假設(shè)我們有一個(gè)簡(jiǎn)單的CNN模塊Conv2d(3, 16, kernel_size3, stride1, padding1) - ReLU - MaxPool2d(2)。輸入圖片為32x32x3。卷積層K_h3, K_w3, C_in3, C_out16由于stride1, padding1輸出尺寸H_out W_out 32。FLOPs_conv 2 * 3 * 3 * 3 * 32 * 32 * 16 2 * 9 * 3 * 1024 * 16 2 * 9 * 3 * 16384 884,736。ReLU層忽略不計(jì)。最大池化層忽略不計(jì)。 所以這個(gè)模塊的FLOPs約為0.88M。你可以看到即使是一個(gè)很小的卷積在輸入尺寸稍大的情況下計(jì)算量也能達(dá)到百萬(wàn)級(jí)別。3.2 使用流行工具自動(dòng)計(jì)算FLOPs手動(dòng)計(jì)算整個(gè)網(wǎng)絡(luò)是不現(xiàn)實(shí)的。下面介紹兩個(gè)最常用的Python工具庫(kù)并分享我的使用心得。工具一thop(PyTorch)thop庫(kù)簡(jiǎn)單直接是PyTorch用戶的常用選擇。import torch import torch.nn as nn from thop import profile, clever_format # 定義一個(gè)簡(jiǎn)單網(wǎng)絡(luò) class SimpleNet(nn.Module): def __init__(self): super(SimpleNet, self).__init__() self.conv1 nn.Conv2d(3, 16, 3, 1, 1) self.pool nn.MaxPool2d(2) self.fc nn.Linear(16*16*16, 10) # 假設(shè)池化后是16x16 def forward(self, x): x self.pool(torch.relu(self.conv1(x))) x x.view(-1, 16*16*16) x self.fc(x) return x model SimpleNet() input torch.randn(1, 3, 32, 32) # 批大小1 flops, params profile(model, inputs(input,)) flops, params clever_format([flops, params], %.3f) print(fFLOPs: {flops}, Params: {params})注意事項(xiàng)thop默認(rèn)使用1 MAC 2 FLOPs的計(jì)數(shù)方式。它的clever_format函數(shù)能自動(dòng)將數(shù)字轉(zhuǎn)換為“G”、“M”等易讀格式。需要確保你的輸入張量是合法的形狀否則會(huì)報(bào)錯(cuò)。它有時(shí)會(huì)對(duì)某些特殊算子如深度可分離卷積的支持不夠細(xì)致需要留意。工具二fvcore(Facebook Research)fvcore是Facebook開(kāi)源的更強(qiáng)大的分析庫(kù)支持PyTorch和TensorFlow通過(guò)單獨(dú)的tfprof。from fvcore.nn import FlopCountAnalysis, parameter_count model SimpleNet() input torch.randn(1, 3, 32, 32) flops FlopCountAnalysis(model, input) print(Total FLOPs (G):, flops.total() / 1e9) print(Detailed FLOPs by operator:\n, flops.by_operator()) print(Detailed FLOPs by module:\n, flops.by_module())fvcore的強(qiáng)大之處在于它能提供按算子類型by_operator和按模型子模塊by_module的詳細(xì)分解。這對(duì)于性能瓶頸分析至關(guān)重要。例如你可以一眼看出是Conv2d還是Linear占用了大部分計(jì)算資源。工具對(duì)比與選擇建議特性thopfvcore易用性極高一行代碼出結(jié)果較高接口稍多但清晰詳細(xì)度提供總FLOPs和參數(shù)量提供總FLOPs、參數(shù)量并支持分層/分算子詳細(xì)統(tǒng)計(jì)定制性較弱較強(qiáng)可以注冊(cè)自定義算子的FLOPs計(jì)算規(guī)則推薦場(chǎng)景快速獲取模型整體計(jì)算量進(jìn)行粗略對(duì)比需要深入分析模型內(nèi)部計(jì)算分布定位瓶頸我個(gè)人在項(xiàng)目中的習(xí)慣是初期模型選型用thop快速篩選當(dāng)需要對(duì)一個(gè)候選模型進(jìn)行深度優(yōu)化時(shí)必定使用fvcore進(jìn)行詳細(xì)剖析。3.3 計(jì)算結(jié)果的解讀與常見(jiàn)陷阱拿到FLOPs數(shù)字后解讀它需要注意以下幾點(diǎn)單位與換算工具輸出的通常是原始數(shù)字如1769472。我們需要將其轉(zhuǎn)換為1.77 MFLOPs百萬(wàn)或1.77 GFLOPs十億。1 GFLOPs 10^9 FLOPs。僅前向傳播FLOPs通常只計(jì)算一次前向傳播推理。訓(xùn)練時(shí)的計(jì)算量大約是前向傳播的2-3倍因?yàn)檫€包括反向傳播梯度計(jì)算。反向傳播的FLOPs與前向傳播大致在同一數(shù)量級(jí)。動(dòng)態(tài)結(jié)構(gòu)與條件分支如果你的模型有動(dòng)態(tài)計(jì)算圖如基于輸入內(nèi)容的條件分支那么FLOPs可能不是固定的。工具給出的通常是針對(duì)你提供的示例輸入的計(jì)算量。FLOPs ≠ 實(shí)際推理時(shí)間這是一個(gè)最重要的認(rèn)知陷阱。FLOPs是理論計(jì)算量而實(shí)際推理時(shí)間還受眾多因素影響內(nèi)存訪問(wèn)成本如果模型計(jì)算量不大但需要在內(nèi)存中頻繁搬運(yùn)大量數(shù)據(jù)如特征圖那么實(shí)際瓶頸可能在內(nèi)存帶寬Memory Bandwidth上而非算力。這就是“內(nèi)存墻”問(wèn)題。算子優(yōu)化程度深度學(xué)習(xí)框架如PyTorch、TensorRT對(duì)算子的實(shí)現(xiàn)優(yōu)化水平不同。一個(gè)FLOPs更低的模型如果其算子沒(méi)有被高度優(yōu)化可能跑得比一個(gè)FLOPs高但算子優(yōu)化好的模型更慢。硬件特性GPU有強(qiáng)大的并行計(jì)算能力但對(duì)某些特殊操作如分組卷積Group Conv的支持效率可能不同。ARM CPU上的計(jì)算特點(diǎn)也與GPU迥異。因此FLOPs是一個(gè)重要的參考指標(biāo)但絕非唯一標(biāo)準(zhǔn)。在最終決策前必須在目標(biāo)硬件上進(jìn)行實(shí)際的端到端速度測(cè)試Latency Benchmark。4. 高級(jí)話題FLOPs在模型優(yōu)化中的應(yīng)用與局限掌握了基礎(chǔ)計(jì)算后我們可以更深入地探討FLOPs如何指導(dǎo)模型設(shè)計(jì)以及它的局限性。4.1 如何根據(jù)FLOPs指導(dǎo)模型輕量化設(shè)計(jì)輕量化模型設(shè)計(jì)的核心思想是在保持精度的前提下顯著降低FLOPs和參數(shù)量。主流技術(shù)背后都有其降低FLOPs的數(shù)學(xué)邏輯深度可分離卷積這是MobileNet的核心。它將標(biāo)準(zhǔn)卷積分解為深度卷積逐通道卷積和逐點(diǎn)卷積1x1卷積。對(duì)于一個(gè)標(biāo)準(zhǔn)卷積其FLOPs為2 * K*K * C_in * H_out * W_out * C_out。深度可分離卷積的FLOPs為深度卷積2 * K*K * C_in * H_out * W_out * 1逐點(diǎn)卷積2 * 1*1 * C_in * H_out * W_out * C_out總和約為2 * H_out * W_out * C_in * (K*K C_out)與標(biāo)準(zhǔn)卷積相比計(jì)算量降低了大約K*K * C_out / (K*K C_out)倍。當(dāng)C_out較大時(shí)如256這個(gè)降低倍數(shù)接近K*K9倍對(duì)于3x3卷積。模型剪枝通過(guò)移除網(wǎng)絡(luò)中不重要的連接權(quán)重或整個(gè)通道直接減少參與計(jì)算的權(quán)重?cái)?shù)量從而降低FLOPs。例如將一個(gè)C_in256, C_out512的卷積層通過(guò)通道剪枝將輸入通道減為200輸出通道減為400那么FLOPs將大致按比例(200/256)*(400/512) ≈ 0.61下降。知識(shí)蒸餾用一個(gè)龐大的“教師模型”指導(dǎo)一個(gè)輕量級(jí)“學(xué)生模型”的訓(xùn)練。學(xué)生模型本身結(jié)構(gòu)小巧FLOPs低但通過(guò)模仿教師模型的輸出或中間特征獲得接近教師模型的精度。FLOPs的降低來(lái)自于學(xué)生模型本身的結(jié)構(gòu)設(shè)計(jì)。實(shí)操心得在實(shí)際輕量化項(xiàng)目中我通常會(huì)先用FLOPs和參數(shù)量做第一輪篩選挑出幾個(gè)候選結(jié)構(gòu)如MobileNetV3, EfficientNet-Lite。然后務(wù)必在目標(biāo)硬件例如一款具體的手機(jī)芯片上測(cè)試它們的真實(shí)推理延遲和功耗。經(jīng)常遇到的情況是A模型FLOPs比B模型低20%但實(shí)際推理速度卻更慢原因可能就是B模型的算子更適合該硬件的計(jì)算單元。4.2 FLOPs的局限性它沒(méi)有告訴你什么過(guò)度依賴FLOPs會(huì)帶來(lái)誤導(dǎo)我們必須清楚它的邊界忽略內(nèi)存訪問(wèn)如前所述這是最大的局限。一個(gè)典型的例子是激活函數(shù)和逐元素相加。它們的FLOPs極低但會(huì)產(chǎn)生大量的內(nèi)存讀寫(xiě)。如果網(wǎng)絡(luò)中有很多跳躍連接如DenseNet雖然FLOPs增加不多但內(nèi)存訪問(wèn)量會(huì)劇增可能成為速度瓶頸。忽略并行度FLOPs是一個(gè)標(biāo)量總和它不反映計(jì)算的并行性。兩個(gè)FLOPs相同的模型一個(gè)計(jì)算高度并行另一個(gè)計(jì)算串行依賴嚴(yán)重在GPU上的運(yùn)行時(shí)間會(huì)相差巨大。忽略硬件特定優(yōu)化現(xiàn)代硬件如GPU的Tensor CoreNPU的專用指令集對(duì)某些計(jì)算模式如低精度INT8計(jì)算、特定尺寸的矩陣乘有極度優(yōu)化。一個(gè)FLOPs較高的模型如果其計(jì)算模式完美匹配硬件特性可能比一個(gè)FLOPs較低但計(jì)算模式“別扭”的模型快得多。忽略啟動(dòng)開(kāi)銷對(duì)于非常小的模型或?qū)佑?jì)算本身很快但內(nèi)核啟動(dòng)kernel launch、數(shù)據(jù)搬運(yùn)等固定開(kāi)銷可能占主導(dǎo)地位。此時(shí)FLOPs對(duì)比就失去了意義。因此一個(gè)更全面的模型效率評(píng)估體系應(yīng)該包括理論計(jì)算量FLOPs、內(nèi)存占用峰值顯存、內(nèi)存訪問(wèn)量MACs、實(shí)際推理延遲Latency以及能耗Power Consumption。對(duì)于部署工程師延遲和功耗是最終的黃金標(biāo)準(zhǔn)。4.3 實(shí)際項(xiàng)目中的FLOPs分析案例在我參與的一個(gè)手機(jī)端圖像增強(qiáng)項(xiàng)目中我們需要在15ms內(nèi)完成一張1080p圖片的處理。初始基線模型是一個(gè)精簡(jiǎn)的UNetFLOPs為5.6G。瓶頸分析使用fvcore分析發(fā)現(xiàn)超過(guò)60%的FLOPs集中在解碼器的前兩個(gè)上采樣層它們使用了大量的轉(zhuǎn)置卷積。優(yōu)化嘗試方案A降低FLOPs將轉(zhuǎn)置卷積替換為雙線性上采樣卷積。經(jīng)計(jì)算FLOPs降至3.8G降低32%。但在手機(jī)NPU上實(shí)測(cè)延遲僅從18ms降至16ms提升不明顯。原因是NPU對(duì)轉(zhuǎn)置卷積有專用優(yōu)化而對(duì)“上采樣卷積”這個(gè)組合操作效率一般。方案B改變結(jié)構(gòu)借鑒GhostNet的思想在瓶頸層使用更激進(jìn)的通道壓縮和廉價(jià)操作如深度卷積。FLOPs降至4.2G降低25%。實(shí)測(cè)延遲降至14ms滿足了要求分析原因是這種改變不僅降低了FLOPs更重要的是減少了中間特征圖的通道數(shù)從而顯著降低了內(nèi)存訪問(wèn)量和數(shù)據(jù)搬運(yùn)開(kāi)銷而這正是該NPU的瓶頸所在。這個(gè)案例深刻說(shuō)明優(yōu)化FLOPs是手段而不是目標(biāo)。最終要服務(wù)于降低實(shí)際延遲。結(jié)合詳細(xì)的分析工具理解FLOPs來(lái)源再針對(duì)目標(biāo)硬件特性進(jìn)行設(shè)計(jì)才能取得最佳效果。5. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄在實(shí)際工作中計(jì)算和使用FLOPs時(shí)總會(huì)遇到一些坑。這里記錄幾個(gè)典型問(wèn)題和我的解決方法。Q1我用不同工具計(jì)算同一個(gè)模型的FLOPs結(jié)果差異很大該信誰(shuí)的A這非常常見(jiàn)。首先檢查以下幾點(diǎn)計(jì)數(shù)標(biāo)準(zhǔn)確認(rèn)工具使用的是1 MAC 1 FLOP還是1 MAC 2 FLOPs。thop默認(rèn)是后者。如果A工具結(jié)果是10GB工具是5G很可能差了一倍。輸入尺寸確保傳遞給兩個(gè)工具的輸入張量尤其是批大小和圖片尺寸完全一致。FLOPs與輸入尺寸直接相關(guān)。算子覆蓋有些工具可能忽略了某些算子如自定義層、某些激活函數(shù)、池化層。檢查工具的文檔看它支持哪些算子。排查方法用一個(gè)極簡(jiǎn)的模型如只有一層卷積進(jìn)行交叉驗(yàn)證手動(dòng)計(jì)算和工具結(jié)果對(duì)比確定基準(zhǔn)。Q2模型訓(xùn)練時(shí)的FLOPs和推理時(shí)一樣嗎A不一樣。訓(xùn)練包含前向傳播和反向傳播。通常一次訓(xùn)練迭代的FLOPs大約是前向傳播的2到3倍。反向傳播需要計(jì)算梯度其計(jì)算量與前向傳播大致相當(dāng)有時(shí)還會(huì)更多例如某些激活函數(shù)的梯度計(jì)算更復(fù)雜。此外訓(xùn)練時(shí)可能開(kāi)啟Dropout、BatchNorm的訓(xùn)練模式等也會(huì)引入少量額外計(jì)算但這些通常不是主要部分。Q3如何估算模型在GPU上的理論最快推理時(shí)間A這是一個(gè)“屋頂線模型”的簡(jiǎn)化應(yīng)用。理論最快時(shí)間T_min Total_FLOPs / Peak_FLOPS。Total_FLOPs你的模型一次前向傳播的FLOPs。Peak_FLOPS你所用GPU的峰值單精度浮點(diǎn)算力以FLOPS為單位。例如NVIDIA RTX 3080的峰值算力約為30 TFLOPS每秒30萬(wàn)億次。例如一個(gè)10 GFLOPs的模型在RTX 3080上的理論最快時(shí)間T_min 10e9 / 30e12 ≈ 0.33 ms。注意這只是一個(gè)理論極限。由于內(nèi)存帶寬限制、內(nèi)核啟動(dòng)開(kāi)銷、計(jì)算并行度不足等原因?qū)嶋H時(shí)間實(shí)測(cè)可能為3ms會(huì)遠(yuǎn)大于這個(gè)值。這個(gè)值的主要作用是告訴你算力瓶頸的上限在哪里。如果實(shí)際時(shí)間已經(jīng)接近這個(gè)理論值說(shuō)明優(yōu)化重點(diǎn)可能在算法本身降低FLOPs如果相差甚遠(yuǎn)說(shuō)明優(yōu)化重點(diǎn)在內(nèi)存訪問(wèn)或算子實(shí)現(xiàn)上。Q4在論文中報(bào)告FLOPs有哪些注意事項(xiàng)A為了公平對(duì)比學(xué)術(shù)界逐漸形成了一些約定俗成的規(guī)范明確輸入尺寸必須說(shuō)明計(jì)算FLOPs所使用的輸入張量形狀通常是3 x H x W對(duì)于圖像。常見(jiàn)的是224x224或320x320。明確計(jì)數(shù)規(guī)則在論文的“實(shí)驗(yàn)設(shè)置”或附錄中最好注明“FLOPs計(jì)數(shù)遵循1 MAC 2 FLOPs的慣例”并說(shuō)明使用的計(jì)算工具如fvcore。區(qū)分訓(xùn)練與推理通常報(bào)告的是一次前向傳播的FLOPs。如果涉及訓(xùn)練成本分析需單獨(dú)說(shuō)明。報(bào)告乘加運(yùn)算數(shù)有些領(lǐng)域如硬件設(shè)計(jì)更習(xí)慣報(bào)告乘加運(yùn)算數(shù)MACs或MAdds。1 GFLOPs 0.5 GMACs如果按1 MAC2 FLOPs。務(wù)必清晰區(qū)分。Q5除了FLOPs還有哪些重要的效率指標(biāo)需要關(guān)注A構(gòu)建一個(gè)完整的模型效率評(píng)估清單我通常會(huì)看以下維度指標(biāo)描述常用工具/方法為什么重要FLOPs理論計(jì)算量thop,fvcore,ptflops衡量模型計(jì)算復(fù)雜度篩選候選模型參數(shù)量模型權(quán)重總數(shù)thop,fvcore,torchsummary影響模型存儲(chǔ)大小、內(nèi)存占用與過(guò)擬合風(fēng)險(xiǎn)相關(guān)內(nèi)存占用前向傳播峰值顯存torch.cuda.max_memory_allocated()決定模型能否在給定設(shè)備上運(yùn)行內(nèi)存訪問(wèn)量數(shù)據(jù)讀寫(xiě)總量較難直接測(cè)量可通過(guò)分析網(wǎng)絡(luò)結(jié)構(gòu)估算影響實(shí)際速度尤其是內(nèi)存帶寬受限的設(shè)備推理延遲單次預(yù)測(cè)耗時(shí)實(shí)際部署使用time.time()或torch.cuda.Event測(cè)量最終用戶體驗(yàn)的直接指標(biāo)黃金標(biāo)準(zhǔn)吞吐量單位時(shí)間處理樣本數(shù)壓力測(cè)試測(cè)量不同批大小下的FPS服務(wù)端場(chǎng)景的關(guān)鍵指標(biāo)最終我的建議是建立一個(gè)分層評(píng)估策略先用FLOPs和參數(shù)量進(jìn)行大量模型的快速初篩然后對(duì)少數(shù)候選模型在目標(biāo)硬件上進(jìn)行延遲和內(nèi)存占用的實(shí)測(cè)對(duì)于最關(guān)鍵的一兩個(gè)模型再進(jìn)行深入的剖析如使用Nsight Systems, Android Profiler等工具分析內(nèi)核執(zhí)行時(shí)間和內(nèi)存瓶頸指導(dǎo)最終的微調(diào)。FLOPs是這張效率地圖上一個(gè)重要但并非唯一的坐標(biāo)理解它的內(nèi)涵與邊界才能讓它真正為你的深度學(xué)習(xí)項(xiàng)目服務(wù)。