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 比較的是他們在記憶...