《動手學深度學習》第十天 模型構造

2021-09-25 16:28:07 字數 3239 閱讀 5423

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

from mxnet import nd

from mxnet.gluon import nn

class mlp(nn.block): //class 類名[(父類名)]:[成員函式及成員變數]

def __init__(self, **kwargs): // __init__構造用於在類的物件被建立時,馬上執行。該方法用於對物件初始化。

類的各屬性(或成員變數)均可以在建構函式中定義,定義時加上物件指標即可。

super(mlp, self).__init__(**kwargs)//呼叫super函式

self.hidden = nn.dense(256,activation='relu')//建立成員變數並賦予初值,隱藏層

self.output = nn.dense(10)//建立成員變數並賦予初值,輸出層

def forward(self,x)://子類過載函式forward

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

//super函式:第乙個引數是當前子類的類的名字,如mlp。第二個引數是self。

然後是點號,點號後面是要呼叫的父類的方法。

可以解決經過init後子類需要從父類繼承的屬性被初始化的問題。

class mysequential(nn.block)://mysequential類繼承自block類

def __init__(self, **kwargs)://過載建構函式,初始化物件的各屬性,第乙個引數是self

super(mysequential, self).__init__(**kwargs)//繼承父類的引數

def add(self, block):

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

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

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

self._children[block.name] = block

def forward(self, x):

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

for block in self._children.values():

x = block(x)

return x

這裡mysequential類的使用跟「多層感知機的簡潔實現」一節中sequential類的使用沒什麼區別。

這個例子看的其實不是很清楚,我依然不知道sequential的工作機制。

查閱了一些資料後,提煉一些關鍵句:

sequential可以被當成乙個有序的容器,神經網路模組按新增順(也就是add函式的功能)序進行執行(這就可以理解forward裡面的迴圈了)。

我們知道每乙個block都是block的子類,所以在forward中都會實現__call__方法,而__call__中呼叫了forward函式,而forward函式實現的是:inputweight + bias

block(x)實際上就是呼叫__call__(input),然後__call__(x)呼叫forward()函式,最後返回計算結果為:xblock_weight+block_bias

但需要注意的是計算時weight是經過轉置的。在定義裡面weight是[out_features,in_features]。

這樣就好理解啦!

from mxnet import nd

from mxnet.gluon import nn

class fancymlp(nn.block):

def __init__(self,**kwargs):

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

self.rand_weight = self.params.get_constant(

'rand_weight',nd.random.uniform(shape=(20,20)))#get_constant()檢索名為self.prefix+name的常數,該常數不會隨迭代過程而改變

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

def forward(self,x):

x = self.dense(x)

x = nd.relu(nd.dot(x,self.rand_weight.data())+1) # 使用建立的常數引數,以及ndarray的relu函式和dot函式

x = self.dense(x) # 復用全連線層。等價於兩個全連線層共享引數

while x.norm().asscalar() > 1:#計算範數。預設為l2範數

x/=2

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

x*=10

return x.sum()

class nestmlp(nn.block):

def __init__(self, **kwargs):

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

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)

學習第十天

一 介面 jdk1.8及之後新增了2中可以定義存在方法體的方法 預設方法 default關鍵字修飾的方法 使用 通過實現類物件使用 靜態方法 使用 通過介面名去呼叫 二 單例模式 保證類只能存在乙個例項 餓漢式 先建立物件,然後需要的人要這個物件,保證永遠使用的都是這個建立好的物件 執行緒安全的,效...

python學習第十天

class student count 0 def init self,name,age,address self.name name self.age age self.address address student.count 1 k print k w open a.txt w encodin...

菜鳥學習第十天

1.字串最大的特點 一旦初始化就不可以改變。不可改變的字串內容而不是指向字串的引用 2.string s abc 其中s是乙個類型別變數,abc 是乙個物件。3.string s1 abc 和string s2 new string abc s1 s2 和s1.equals s2 比較的是他們在記憶...