4 1 模型構造

2022-07-10 04:33:09 字數 4349 閱讀 9321

基於block類的模型構造方法:它讓模型構造更加靈活。

繼承block類來構造模型

block類是nn模組裡提供的乙個模型構造類,我們可以繼承它來定義我們想要的模型。下面繼承block類構造本節開頭提到的多層感知機。這裡定義的mlp類過載了block類的__init__函式和forward函式。它們分別用於建立模型引數和定義前向計算。前向計算也即正向傳播。

#導包

from mxnet import nd

from mxnet.gluon import nn

#mlp從block繼承

class mlp(nn.block):

# 宣告帶有模型引數的層,這裡宣告了兩個全連線層

def __init__(self, **kwargs):

# 呼叫mlp父類block的建構函式來進行必要的初始化。這樣在構造例項時還可以指定其他函式

# 引數,如「模型引數的訪問、初始化和共享」一節將介紹的模型引數params

##用super()來繼承另乙個類的引數,以dict的形式放在kwargs變數裡面

super(mlp, self).__init__(**kwargs)

self.hidden = nn.dense(256, activation='relu') # 隱藏層

self.output = nn.dense(10) # 輸出層

# 定義模型的前向計算,即如何根據輸入x計算返回所需要的模型輸出

def forward(self, x):

return self.output(self.hidden(x))

#初始化net並傳入輸入資料x做一次前向計算

x = nd.random.uniform(shape=(2, 20))

net = mlp()

net.initialize()

net(x)

net(x)會呼叫mlp繼承自block類的__call__函式,這個函式將呼叫mlp類定義的forward函式來完成前向計算。

這裡並沒有將block類命名為layer(層)或者model(模型)之類的名字,這是因為該類是乙個可供自由組建的部件。它的子類既可以是乙個層(如gluon提供的dense類),又可以是乙個模型(如這裡定義的mlp類),或者是模型的乙個部分。

sequential類繼承自block

block類是乙個通用的部件.

sequential類繼承自block類。當模型的前向計算為簡單串聯各個層的計算時,可以通過更加簡單的方式定義模型。這正是sequential類的目的:它提供add函式來逐一新增串聯的block子類例項,而模型的前向計算就是將這些例項按新增的順序逐一計算。

實現乙個與sequential類有相同功能的mysequential類:

#mysequential類繼承block類

class mysequential(nn.block):

#繼承實現建構函式

def __init__(self, **kwargs):

super(mysequential, self).__init__(**kwargs)

def add(self, block):

# block是乙個block子類例項,假設它有乙個獨一無二的名字。我們將它儲存在block類的

# 成員變數_children裡,其型別是ordereddict。當mysequential例項呼叫

# initialize函式時,系統會自動對_children裡所有成員初始化

#self._children = ordereddict(),有序字典可以按字典中元素的插入順序來輸出。

self._children[block.name] = block

def forward(self, x):

# ordereddict保證會按照成員新增時的順序遍歷成員

for block in self._children.values():

#直接利用__call__做前向傳播

#out = self.forward(*args)

x = block(x)

return x

mysequential類來實現前面描述的mlp類,並使用隨機初始化的模型做一次前向計算。

#先申明mysequential()例項

net = mysequential()

#新增隱藏層

net.add(nn.dense(256, activation='relu'))

#新增輸出層

net.add(nn.dense(10))

#初始化

net.initialize()

net(x)

構造複雜的模型

構造乙個稍微複雜點的網路fancymlp。在這個網路中,我們通過get_constant函式建立訓練中不被迭代的引數,即常數引數。在前向計算中,除了使用建立的常數引數外,我們還使用ndarray的函式和python的控制流,並多次呼叫相同的層。

class fancymlp(nn.block):

def __init__(self, **kwargs):

super(fancymlp, self).__init__(**kwargs)

# 使用get_constant建立的隨機權重引數不會在訓練中被迭代(即常數引數)

self.rand_weight = self.params.get_constant(

'rand_weight', nd.random.uniform(shape=(20, 20)))

self.dense = nn.dense(20, activation='relu')

def forward(self, x):

x = self.dense(x)

# 使用建立的常數引數,以及ndarray的relu函式和dot函式

x = nd.relu(nd.dot(x, self.rand_weight.data()) + 1)

# 復用全連線層。等價於兩個全連線層共享引數

x = self.dense(x)

# 控制流,這裡我們需要呼叫asscalar函式來返回標量進行比較

while x.norm().asscalar() > 1:

x /= 2

if x.norm().asscalar() < 0.8:

x *= 10

return x.sum()

net = fancymlp()

net.initialize()

net(x)

class nestmlp(nn.block):

def __init__(self, **kwargs):

super(nestmlp, self).__init__(**kwargs)

#巢狀呼叫sequential()類

self.net = nn.sequential()

#新增兩個隱藏層

self.net.add(nn.dense(64, activation='relu'),

nn.dense(32, activation='relu'))

#新增輸出層

self.dense = nn.dense(16, activation='relu')

#正向傳播

def forward(self, x):

return self.dense(self.net(x))

net = nn.sequential()

net.add(nestmlp(), nn.dense(20), fancymlp())

net.initialize()

net(x)

軟體構造複習4 1

levels of reuse 最主要的復用在 層面,但是軟體構造過程中任何實體都可能被復用 級 方法,模組級 類,介面 庫級 api 架構級 框架 types of code reuse sources of reuse module level reuse libraries 提供可重用功能的一...

軟體體系結構4 1模型

用例檢視 use cases vie 最初稱為場景檢視 scenarios 關注終端使用者需求,為整個技術架構的上線文環境.通常用uml用例圖和活 描述。邏輯檢視 logical view 主要是整個系統的抽象結構表述,關注系統提供終端使用者的功能,不涉及具體的編譯即輸出和部署,通常在uml中用類圖...

41 構造乙個觸發器audit log

構造乙個觸發器audit log,在向employees test表中插入一條資料的時候,觸發插入相關的資料到audit中。create table employees test id int primary key not null,name text not null,age int not n...