建神經(jīng)網(wǎng)絡(luò):從 Dense 層到自定義 Block 與 HybridBlock 實(shí)戰(zhàn)指南)
使用 Apache MXNet Gluon 創(chuàng)建神經(jīng)網(wǎng)絡(luò)從 Dense 層到自定義 Block 與 HybridBlock 實(shí)戰(zhàn)指南【免費(fèi)下載鏈接】mxnetLightweight, Portable, Flexible Distributed/Mobile Deep Learning with Dynamic, Mutation-aware Dataflow Dep Scheduler; for Python, R, Julia, Scala, Go, Javascript and more項(xiàng)目地址: https://gitcode.com/gh_mirrors/mx/mxnet本教程是 MXNet 快速入門(mén)系列的第 2 步聚焦于使用 Gluon 高階 API 創(chuàng)建神經(jīng)網(wǎng)絡(luò)。你將學(xué)會(huì)從單個(gè)Dense全連接層出發(fā)依次掌握nn.Sequential快速堆疊網(wǎng)絡(luò)、基于nn.Block定制任意網(wǎng)絡(luò)架構(gòu)含經(jīng)典 LeNet、用Parameter編寫(xiě)自定義層以及利用HybridBlock在命令式與符號(hào)式編程之間自由切換并獲得性能提升最后掌握模型的保存、加載與可視化方法。讀完本文你可以獨(dú)立用 Gluon 搭建、訓(xùn)練、導(dǎo)出并部署一個(gè)神經(jīng)網(wǎng)絡(luò)模型。前置知識(shí)本文默認(rèn)你已完成本系列 Step 1: Manipulate data with NP on MXNet熟悉mxnet.np的數(shù)組操作。準(zhǔn)備工作導(dǎo)入必要的包在 MXNet 中np包mxnet.np提供與 NumPy 一致的數(shù)組接口而神經(jīng)網(wǎng)絡(luò)的層與容器則位于 Gluon 的兩個(gè)模塊中mxnet.gluon.nn由 MXNet 團(tuán)隊(duì)維護(hù)的正式神經(jīng)網(wǎng)絡(luò)層模塊mxnet.gluon.contrib.nn由社區(qū)貢獻(xiàn)的實(shí)驗(yàn)性模塊。使用下面的命令導(dǎo)入本步所需的包并調(diào)用npx.set_np()將 MXNet 切換到 numpy 風(fēng)格模式from mxnet import np, npx from mxnet.gluon import nn npx.set_np() # Change MXNet to the numpy-like mode.從源碼結(jié)構(gòu)看gluon.nn中按類(lèi)別組織了大量?jī)?nèi)置層順序容器Sequential、HybridSequential、基礎(chǔ)層Dense、Activation、Dropout、Flatten、卷積層Conv1D/2D/3D、池化層MaxPool、AvgPool系列、歸一化層BatchNorm、LayerNorm等、嵌入層與高級(jí)激活層LeakyReLU、ELU、GELU等完整清單可查閱 gluon.nn API 文檔。創(chuàng)建神經(jīng)網(wǎng)絡(luò)的第一個(gè)層Dense最基礎(chǔ)的神經(jīng)網(wǎng)絡(luò)層是Dense 層全連接層 / 稠密連接層輸入層的每個(gè)節(jié)點(diǎn)都與下一層的每個(gè)節(jié)點(diǎn)相連。創(chuàng)建一個(gè)輸出維度為 5 的 Dense 層layer nn.Dense(5) layer # output: Dense(-1 - 5, linear)輸出中的-1表示輸入層大小在初始化時(shí)尚未指定會(huì)被推遲到第一次前向傳播時(shí)根據(jù)輸入數(shù)據(jù)形狀自動(dòng)推斷。如果你事先知道輸入維度可以直接通過(guò)in_units參數(shù)指定layer nn.Dense(5, in_units3) layerDense 層實(shí)現(xiàn)的計(jì)算為$$output \sigma(W \cdot X b)$$其中 $W$ 為權(quán)重矩陣、$b$ 為偏置向量、$\sigma$ 為激活函數(shù)??梢酝ㄟ^(guò)activation參數(shù)為層附加激活函數(shù)layer nn.Dense(5, in_units3, activationrelu)從源碼來(lái)看Dense類(lèi)定義在 python/mxnet/gluon/nn/basic_layers.py其完整簽名支持更多參數(shù)use_bias默認(rèn)True是否使用偏置、flatten默認(rèn)True是否將輸入除第一維外的所有維度展平、dtype默認(rèn)float32、weight_initializer與bias_initializer默認(rèn)偏置初始化為zeros。其forward內(nèi)部通過(guò)npx.fully_connected完成矩陣乘加運(yùn)算后再套用激活函數(shù)。初始化權(quán)重與前向傳播創(chuàng)建網(wǎng)絡(luò)后需要先初始化權(quán)重。Gluon 默認(rèn)的初始化方式是在 $[-0.7, 0.7]$ 區(qū)間內(nèi)均勻隨機(jī)取值layer.initialize()Note關(guān)于初始化的深入探討會(huì)在本系列的后續(xù)教程中展開(kāi)。初始化完成后即可向網(wǎng)絡(luò)輸入數(shù)據(jù)執(zhí)行前向傳播forward pass。下面的例子創(chuàng)建形狀為(10, 3)的隨機(jī)輸入x送入層中計(jì)算輸出x np.random.uniform(-1, 1, (10, 3)) layer(x)輸入為(10, 3)Dense 層輸出形狀為(10, 5)。當(dāng)你未指定in_units參數(shù)時(shí)系統(tǒng)會(huì)在首次前向傳播時(shí)根據(jù)輸入數(shù)據(jù)自動(dòng)推斷輸入維度。這一點(diǎn)在源碼中由Dense.infer_shape實(shí)現(xiàn)basic_layers.py若flattenTrue會(huì)將除 batch 維外所有維度尺寸相乘得到in_units若flattenFalse則取最后一維作為輸入維度??梢酝ㄟ^(guò)layer.params查看該層全部參數(shù)layer.params權(quán)重和偏置可以通過(guò).data()方法訪問(wèn)layer.weight.data()使用 nn.Sequential 將層鏈成網(wǎng)絡(luò)Sequential提供了一種快速搭建網(wǎng)絡(luò)的途徑適用于層像煎餅一樣堆疊的常見(jiàn)網(wǎng)絡(luò)結(jié)構(gòu)每一層的輸出直接作為下一層的輸入。使用net.add()依次添加層即可。下面用它把前面的 Dense 層組合成一個(gè) 3 層多層感知機(jī)MLPnet nn.Sequential() net.add(nn.Dense(5, in_units3, activationrelu), nn.Dense(25, activationrelu), nn.Dense(2)) net層按照添加順序排列索引從 0 開(kāi)始可以用[]下標(biāo)訪問(wèn)指定層net[1]從實(shí)現(xiàn)上看Sequential繼承自Blockbasic_layers.pyadd()內(nèi)部將每個(gè)子塊追加到_layers列表并調(diào)用register_child注冊(cè)forward()則按序執(zhí)行所有子塊并把上一塊的輸出作為下一塊的輸入。源碼還提供了一條性能提示當(dāng)Sequential的所有子層都是HybridBlock時(shí)會(huì)給出警告并建議改用HybridSequential以獲得最佳性能——這正是后文要介紹的混合式容器。靈活創(chuàng)建自定義網(wǎng)絡(luò)架構(gòu)nn.Blocknn.Sequential只能使用gluon.nn中現(xiàn)成的層且預(yù)定義了順序執(zhí)行的前向函數(shù)。當(dāng)內(nèi)置層無(wú)法滿(mǎn)足需求例如要搭建 ResNet 這類(lèi)由可復(fù)用復(fù)雜組件構(gòu)成的網(wǎng)絡(luò)時(shí)就需要自定義架構(gòu)。在 Gluon 中每一個(gè)神經(jīng)網(wǎng)絡(luò)層都由基類(lèi)nn.Block定義。Block的核心職責(zé)是定義一個(gè)forward方法接收輸入x產(chǎn)生輸出。它既可以簡(jiǎn)單到只施加一個(gè)激活函數(shù)也可以組合多個(gè)層乃至多個(gè) Block構(gòu)建 ResNet 級(jí)別的復(fù)雜網(wǎng)絡(luò)。自定義 Block 只需實(shí)現(xiàn)兩個(gè)方法__init__創(chuàng)建所需的層forward定義前向計(jì)算邏輯。先看一個(gè)最小骨架class Net(nn.Block): def __init__(self): super().__init__() def forward(self, x): return x再看一個(gè)完整的 MLPclass MLP(nn.Block): def __init__(self): super().__init__() self.dense1 nn.Dense(5, activationrelu) self.dense2 nn.Dense(25, activationrelu) self.dense3 nn.Dense(2) def forward(self, x): layer1 self.dense1(x) layer2 self.dense2(layer1) layer3 self.dense3(layer2) return layer3 net MLP() net每個(gè)層內(nèi)部的參數(shù)保存在Parameter類(lèi)中可通過(guò)params()方法訪問(wèn)net.dense1.params從 block.py 的源碼可以看出Block的設(shè)計(jì)精巧之處它的__setattr__會(huì)被重載——當(dāng)你把子Block或Parameter賦值為實(shí)例屬性時(shí)會(huì)自動(dòng)完成注冊(cè)register_child/ 加入_reg_params因此collect_params()可以遞歸收集整棵網(wǎng)絡(luò)樹(shù)上的全部參數(shù)這也是后續(xù)save_parameters、export等功能的基礎(chǔ)。使用 Parameter 創(chuàng)建自定義層Blocks APIMXNet 用Parameter類(lèi)保存每一層的參數(shù)。內(nèi)置層如 Dense內(nèi)部正是通過(guò)Parameter創(chuàng)建權(quán)重和偏置的如果你想在現(xiàn)有層基礎(chǔ)上增加額外計(jì)算可以基于Parameter自己實(shí)現(xiàn)。先實(shí)例化參數(shù)用shape參數(shù)指定形狀例如形狀(5, -1)其中 -1 表示維度待推斷from mxnet.gluon import Parameter weight Parameter(custom_parameter_weight, shape(5, -1)) bias Parameter(custom_parameter_bias, shape(5, -1)) weight, biasParameter還包含grad_req參數(shù)用于指定該參數(shù)梯度的捕獲方式。默認(rèn)值為grad_reqwrite即每次梯度寫(xiě)入 grad 時(shí)都會(huì)更新。底層機(jī)制上這讓 Gluon 知道需要對(duì)其底層數(shù)組調(diào)用.attach_grad()?;诖丝梢詣?chuàng)建自己的全連接自定義層——用nn.Block的骨架實(shí)現(xiàn)一個(gè)不帶激活函數(shù)的w*x b計(jì)算class custom_layer(nn.Block): def __init__(self, out_units, in_units0): super().__init__() self.weight Parameter(weight, shape(in_units, out_units), allow_deferred_initTrue) self.bias Parameter(bias, shape(out_units,), allow_deferred_initTrue) def forward(self, x): return np.dot(x, self.weight.data()) self.bias.data()注意allow_deferred_initTrueParameter允許在對(duì)應(yīng)數(shù)據(jù)尚未實(shí)例化之前就被創(chuàng)建。例如實(shí)例化 Block 時(shí)各參數(shù)的形狀還需要推斷Parameter會(huì)等待形狀確定后再分配內(nèi)存。dense custom_layer(3, in_units5) dense.initialize() dense(np.random.uniform(size(4, 5)))類(lèi)似地可以用nn.Block完整復(fù)現(xiàn)經(jīng)典的LeNet網(wǎng)絡(luò)——前兩段使用內(nèi)置Conv2DMaxPool2D后接 Dense 層并將最后一層換成上面自定義的custom_layerclass LeNet(nn.Block): def __init__(self): super().__init__() self.conv1 nn.Conv2D(channels6, kernel_size3, activationrelu) self.pool1 nn.MaxPool2D(pool_size2, strides2) self.conv2 nn.Conv2D(channels16, kernel_size3, activationrelu) self.pool2 nn.MaxPool2D(pool_size2, strides2) self.dense1 nn.Dense(120, activationrelu) self.dense2 nn.Dense(84, activationrelu) self.dense3 nn.Dense(10) def forward(self, x): x self.conv1(x) x self.pool1(x) x self.conv2(x) x self.pool2(x) x self.dense1(x) x self.dense2(x) x self.dense3(x) return x lenet LeNet()使用自定義層作為最后一層的 LeNet 變體class LeNet_custom(nn.Block): def __init__(self): super().__init__() self.conv1 nn.Conv2D(channels6, kernel_size3, activationrelu) self.pool1 nn.MaxPool2D(pool_size2, strides2) self.conv2 nn.Conv2D(channels16, kernel_size3, activationrelu) self.pool2 nn.MaxPool2D(pool_size2, strides2) self.dense1 nn.Dense(120, activationrelu) self.dense2 nn.Dense(84, activationrelu) self.dense3 custom_layer(10, 84) def forward(self, x): x self.conv1(x) x self.pool1(x) x self.conv2(x) x self.pool2(x) x self.dense1(x) x self.dense2(x) x self.dense3(x) return x lenet_custom LeNet_custom()用 28×28 的單通道隨機(jī)圖像同時(shí)跑通兩個(gè) LeNet驗(yàn)證自定義層與內(nèi)置層行為一致image_data np.random.uniform(-1, 1, (1, 1, 28, 28)) lenet.initialize() lenet_custom.initialize() print(Lenet:) print(lenet(image_data)) print(Custom Lenet:) print(lenet_custom(image_data))同樣可以用.data方法訪問(wèn)任意一層的權(quán)重與偏置例如訪問(wèn)第一層的權(quán)重和第六層的偏置形狀lenet.conv1.weight.data().shape, lenet.dense1.bias.data().shape使用預(yù)定義預(yù)訓(xùn)練架構(gòu)如果不想從零搭建模型而是希望在常見(jiàn)數(shù)據(jù)集上用經(jīng)典模型快速?gòu)?fù)現(xiàn)或作為 baselineGluon 的Model Zoo直接提供了開(kāi)箱即用的現(xiàn)成架構(gòu)例如計(jì)算機(jī)視覺(jué)領(lǐng)域的 ResNet、自然語(yǔ)言處理領(lǐng)域的 BERT 等對(duì)應(yīng) Gluon CV / Gluon NLP 模型庫(kù)。在倉(cāng)庫(kù)內(nèi)可通過(guò) gluon 模型庫(kù)目錄 查看已收錄的視覺(jué)模型實(shí)現(xiàn)。使用示例——加載預(yù)訓(xùn)練的 ResNet50 v2 并做一次前向傳播from mxnet.gluon import model_zoo net model_zoo.vision.resnet50_v2(pretrainedTrue) net.hybridize() dummy_input np.ones(shape(1, 3, 224, 224)) output net(dummy_input) output.shape為網(wǎng)絡(luò)選擇編程范式命令式還是符號(hào)式MXNet 的 Gluon API 采用**命令式編程Imperative范式對(duì)熟悉 Python 的用戶(hù)而言原型開(kāi)發(fā)快、易于調(diào)試、控制流自然。但在后端MXNet 也可以通過(guò)符號(hào)式 / 聲明式編程Symbolic / Declarative**把網(wǎng)絡(luò)轉(zhuǎn)換為靜態(tài)圖從而對(duì)算子進(jìn)行底層優(yōu)化。靜態(tài)圖的缺點(diǎn)是靈活性受限任何邏輯都必須編碼為圖中特殊的算子如scan、while_loop、cond而且難以調(diào)試。如何兼顧符號(hào)式編程的性能與命令式編程的靈活、易調(diào)試答案是HybridBlock。HybridBlock既可以用真實(shí)輸入、真實(shí)函數(shù)以完全命令式的方式運(yùn)行也可以作用于占位符以符號(hào)方式運(yùn)行。Gluon 將大部分細(xì)節(jié)隱藏在底層通常只有在自己編寫(xiě)層時(shí)才需要了解其工作原理。先創(chuàng)建混合式順序容器net_hybrid_seq nn.HybridSequential() net_hybrid_seq.add(nn.Dense(5, in_units3, activationrelu), nn.Dense(25, activationrelu), nn.Dense(2)) net_hybrid_seq調(diào)用hybridize()即可編譯并優(yōu)化HybridSequentialnet_hybrid_seq.hybridize()從源碼看HybridSequentialbasic_layers.py與Sequential結(jié)構(gòu)一致但繼承自HybridBlock而hybridize()定義在 block.py它會(huì)遞歸地把整棵網(wǎng)絡(luò)樹(shù)轉(zhuǎn)化為符號(hào)化圖。此外倉(cāng)庫(kù)內(nèi) MLP 等內(nèi)置層全部繼承自HybridBlock意味著任何完全由內(nèi)置層構(gòu)成的網(wǎng)絡(luò)都可以通過(guò)一次.hybridize()調(diào)用獲得編譯加速。使用 Parameter 創(chuàng)建自定義層HybridBlocks API在實(shí)例化自定義層時(shí)如果通過(guò)in_units指定了輸入維度權(quán)重會(huì)按該形狀初始化如果輸入維度未知?jiǎng)t形狀被推遲到第一次前向傳播時(shí)確定。對(duì)于自定義HybridBlock層可以定義infer_shape()方法讓形狀在運(yùn)行時(shí)被推斷class CustomLayer(nn.HybridBlock): def __init__(self, out_units, in_units-1): super().__init__() self.weight Parameter(weight, shape(in_units, out_units), allow_deferred_initTrue) self.bias Parameter(bias, shape(out_units,), allow_deferred_initTrue) def forward(self, x): print(self.weight.shape, self.bias.shape) return np.dot(x, self.weight.data()) self.bias.data() def infer_shape(self, x): print(self.weight.shape, x.shape) self.weight.shape (x.shape[-1], self.weight.shape[1]) dense CustomLayer(3) dense.initialize() dense(np.random.uniform(size(4, 5)))性能對(duì)比hybridize 前后的速度差為了直觀感受混合化帶來(lái)的加速可以對(duì)比網(wǎng)絡(luò)在 hybridize 前后各執(zhí)行 1000 次前向傳播的耗時(shí)from time import time def benchmark(net, x): y net(x) start time() for i in range(1, 1000): y net(x) return time() - start x_bench np.random.normal(size(1, 512)) net_hybrid_seq nn.HybridSequential() net_hybrid_seq.add(nn.Dense(256, activationrelu), nn.Dense(128, activationrelu), nn.Dense(2)) net_hybrid_seq.initialize() print(Before hybridizing: %.4f sec % (benchmark(net_hybrid_seq, x_bench))) net_hybrid_seq.hybridize() print(After hybridizing: %.4f sec % (benchmark(net_hybrid_seq, x_bench)))再進(jìn)一步HybridBlock是BlockAPI 的混合版本。與BlocksAPI 類(lèi)似只需為HybridBlock定義接收輸入x的forward函數(shù)MXNet 會(huì)在后端負(fù)責(zé)模型的混合化無(wú)需改動(dòng)代碼即可切換到符號(hào)式范式from mxnet.gluon import HybridBlock class MLP_Hybrid(HybridBlock): def __init__(self): super().__init__() self.dense1 nn.Dense(256, activationrelu) self.dense2 nn.Dense(128, activationrelu) self.dense3 nn.Dense(2) def forward(self, x): layer1 self.dense1(x) layer2 self.dense2(layer1) layer3 self.dense3(layer2) return layer3 net_hybrid MLP_Hybrid() net_hybrid.initialize() print(Before hybridizing: %.4f sec % (benchmark(net_hybrid, x_bench))) net_hybrid.hybridize() print(After hybridizing: %.4f sec % (benchmark(net_hybrid, x_bench)))只要一個(gè)HybridBlock的前向計(jì)算完全由其他HybridBlock組成就可以通過(guò)調(diào)用該塊的.hybridize()方法編譯這整段網(wǎng)絡(luò)。由于 MXNet 的全部預(yù)定義層都是HybridBlock完全由預(yù)定義層組成的網(wǎng)絡(luò)調(diào)用.hybridize()后即可編譯并以更快的速度運(yùn)行。保存與加載模型BlocksAPI 支持在訓(xùn)練期間或訓(xùn)練結(jié)束后保存模型便于部署推理、避免重新訓(xùn)練也支持用 Python 等訓(xùn)練生態(tài)豐富的語(yǔ)言訓(xùn)練、再用其他語(yǔ)言做推理。MXNet 提供兩種保存方式僅保存 / 加載模型權(quán)重參數(shù)同時(shí)保存 / 加載模型權(quán)重與網(wǎng)絡(luò)架構(gòu)。方式一僅保存 / 加載模型參數(shù)使用save_parameters與load_parameters方法保存、加載模型權(quán)重。以最簡(jiǎn)單的layer為例這里保存的是訓(xùn)練后的模型參數(shù)file_name layer.params layer.save_parameters(file_name)要加載參數(shù)需要先重建模型結(jié)構(gòu)再載入?yún)?shù)def build_model(): layer nn.Dense(5, in_units3, activationrelu) return layer layer_new build_model()layer_new.load_parameters(layer.params)Notesave_parameters與load_parameters適用于基于Block而非HybridBlock構(gòu)建的模型。這類(lèi)模型可能有復(fù)雜架構(gòu)且在運(yùn)行期間可能發(fā)生變化——例如用 if-else 條件語(yǔ)句在兩個(gè)不同架構(gòu)之間選擇。方式二同時(shí)保存 / 加載模型參數(shù)與架構(gòu)對(duì)于基于HybridBlock的模型網(wǎng)絡(luò)架構(gòu)是靜態(tài)的、運(yùn)行期間不會(huì)改變因此模型參數(shù)和架構(gòu)都可以通過(guò)export、imports方法一并保存、加載。對(duì)上面的MLP_Hybrid調(diào)用export導(dǎo)出模型。從 block.py 中export的實(shí)現(xiàn) 看export會(huì)把網(wǎng)絡(luò)架構(gòu)導(dǎo)出為.json文件、模型參數(shù)導(dǎo)出為.params文件命名規(guī)則為{path}-symbol.json與{path}-{epoch 四位數(shù)}.params并支持epoch參數(shù)指定保存的輪次編號(hào)net_hybrid.export(MLP_hybrid)運(yùn)行后會(huì)生成MLP_hybrid-symbol.json與MLP_hybrid-0000.params兩個(gè)文件。注意export要求先對(duì)該塊調(diào)用過(guò)hybridize()并至少完成一次前向傳播否則會(huì)拋出RuntimeError提示先 hybridize 再 forward因?yàn)閷?dǎo)出的符號(hào)圖正是混合化緩存的結(jié)果。加載時(shí)使用gluon.nn.SymbolBlock.imports指定符號(hào)文件、輸入名列表與參數(shù)文件import warnings with warnings.catch_warnings(): warnings.simplefilter(ignore) net_loaded nn.SymbolBlock.imports(MLP_hybrid-symbol.json, [data], MLP_hybrid-0000.params, deviceNone)加載完成后即可直接對(duì)數(shù)據(jù)執(zhí)行前向傳播net_loaded(x_bench)可視化模型結(jié)構(gòu)summary()Block.summary()方法可以查看塊的形狀參數(shù)與參數(shù)信息。當(dāng)多個(gè)塊組合成一個(gè)模型后對(duì)模型調(diào)用summary()可以查看每個(gè)塊的摘要、參數(shù)總數(shù)以及塊在模型中的順序。實(shí)現(xiàn)上Block.summary()block.py需要執(zhí)行一次數(shù)據(jù)前向傳播以構(gòu)建捕獲形狀與參數(shù)所需的圖另外該方法應(yīng)在hybridize()之前調(diào)用因?yàn)閔ybridize會(huì)把圖轉(zhuǎn)換為符號(hào)圖可能改變算子以進(jìn)行最優(yōu)計(jì)算。看下面三個(gè)例子單層網(wǎng)絡(luò)layer、未混合化的 LeNet、以及混合化的 MLP Hybrid 網(wǎng)絡(luò)。layer.summary(x)lenet.summary(image_data)layer和lenet都未混合化可以輕松打印摘要而net_hybrid之前已 hybridize直接調(diào)用net_hybrid.summary(x_bench)會(huì)拋出AssertionError。要為混合化網(wǎng)絡(luò)打印摘要需要新建一個(gè)同架構(gòu)的實(shí)例先打印摘要再 hybridizenet_hybrid_summary MLP_Hybrid() net_hybrid_summary.initialize() net_hybrid_summary.summary(x_bench) net_hybrid_summary.hybridize()下一步至此你已經(jīng)掌握了用 Gluon 創(chuàng)建、定制、混合化、保存與可視化神經(jīng)網(wǎng)絡(luò)的完整流程。接下來(lái)可以學(xué)習(xí)如何自動(dòng)計(jì)算梯度進(jìn)入 Step 3: Automatic differentiation with autograd。本系列后續(xù)教程Step 4: 訓(xùn)練組件、Step 6: 訓(xùn)練神經(jīng)網(wǎng)絡(luò)會(huì)在此基礎(chǔ)上展開(kāi)損失函數(shù)、優(yōu)化器與完整訓(xùn)練循環(huán)的講解。參考閱讀gluon.nn 模塊 API 文檔內(nèi)置層完整清單Dense 層源碼實(shí)現(xiàn)含in_units推斷邏輯與全部構(gòu)造參數(shù)Sequential / HybridSequential 源碼實(shí)現(xiàn)順序容器的注冊(cè)與執(zhí)行機(jī)制Block / HybridBlock 源碼實(shí)現(xiàn)基類(lèi)設(shè)計(jì)、參數(shù)自動(dòng)注冊(cè)與collect_paramsParameter 類(lèi)源碼實(shí)現(xiàn)參數(shù)聲明、grad_req與延遲初始化模型導(dǎo)出實(shí)現(xiàn)export生成.json與.params文件的細(xì)節(jié)【免費(fèi)下載鏈接】mxnetLightweight, Portable, Flexible Distributed/Mobile Deep Learning with Dynamic, Mutation-aware Dataflow Dep Scheduler; for Python, R, Julia, Scala, Go, Javascript and more項(xiàng)目地址: https://gitcode.com/gh_mirrors/mx/mxnet創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考