日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

面向对象方法使用gluon

發布時間:2023/12/10 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 面向对象方法使用gluon 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、面向過程與面向對象的優缺點

面向過程使用mxnet,就是使用gluon封裝好的對象,不加改動的表達機器學習的邏輯過程,其特點是方便、快捷,缺點是不夠靈活(雖然可以應對90%以上的問題了),面向對象基于繼承、多態的性質,對原有的gluon類進行了繼承重寫,并在不改變應用接口的情況下(基于多態),靈活的改寫原有類,使之更加符合用戶特殊需求。本文從自定義模型、自定義層、自定義初始化三個方面說明gluon的繼承重寫,這三個基本操作足夠用戶隨心所欲的創造模型了。

二、自定義模型

1、定義靜態模型

靜態模型就是實例化后模型的結構就不能隨便改變了,其代碼如下:

from mxnet import nd from mxnet.gluon import nnclass MLP(nn.Block):# 聲明帶有模型參數的層,這里聲明了兩個全連接層def __init__(self, **kwargs):# 調用MLP父類Block的構造函數來進行必要的初始化。這樣在構造實例時還可以指定其他函數# 參數,如“模型參數的訪問、初始化和共享”一節將介紹的模型參數paramssuper(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))X = nd.random.uniform(shape=(2, 20)) net = MLP() net.initialize() net(X)

2、定義動態模型

動態模型就是在實例化以后,后續可以根據需要隨時修改模型結構,下面只定義一個增加網絡層的功能。

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[block.name] = blockdef forward(self, x):# OrderedDict保證會按照成員添加時的順序遍歷成員for block in self._children.values():x = block(x)return xnet = MySequential() net.add(nn.Dense(256, activation='relu')) net.add(nn.Dense(10)) net.initialize() net(X)

三、定義tensor流

tensor流就是tensor之間是怎樣運算的,gluon默認的tensor流是簡單的tensor乘法運算,自定義就對tengsor流使用if判斷、for循環手段,構造出更加復雜的tensor流,這一點在后面的卷積網絡、循環網絡中頻繁使用。

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 /= 2if x.norm().asscalar() < 0.8:x *= 10return x.sum()net = FancyMLP() net.initialize() net(X)

說明

  • 以上三個方法是可以結合起來使用的,基于這三點用戶可以使用gluon構造出各種卷積、循環網絡。
  • 以上三種繼承方式中,forward函數必須定義重寫,否則出現下面的錯誤,就是沒找到forward propagation。
  • print(net(X)) out = self.forward(*args) raise NotImplementedError NotImplementedError

    三、自定義層

    層與模型沒有本質區別,從語言角度講是一樣的,二者的數據結構都是tensor+forward,只是用途不同而已。層可以理解為整個模型的一層或一部分,是一段網絡,層的作用用來構造模型。

    1、gluon的層

    Dense層:forward = (X * weight + bias).relu()

    g_layer = nn.Dense(2) g_layer.initialize(init=init.One()) X = nd.array([1, 2, 3, 4]).reshape((1, 4)) y = g_layer(X) print('weight of g_layer:', g_layer.weight.data()) print('bias of g_layer:', g_layer.bias.data()) print('X:', X) print('g_layer(X):', y) print('structure of g_layer:', g_layer)""" # output weight of g_layer: [[1. 1. 1. 1.][1. 1. 1. 1.]] <NDArray 2x4 @cpu(0)> bias of g_layer: [0. 0.] <NDArray 2 @cpu(0)> X: [[1. 2. 3. 4.]] <NDArray 1x4 @cpu(0)> g_layer(X): [[10. 10.]] <NDArray 1x2 @cpu(0)> structure of g_layer: Dense(4 -> 2, linear) """

    說明:

  • 再次強調一遍,層和模型的要素是tensor + forward,上面的g_layer是gluon默認的forward,即進行簡單的乘法運算(X * tensor);
  • 因為上面的層從模型的角度看只有一個層,所以查看參數的時候使用g_layer.weight.data(),而不是g_layer[0].weight.data();
  • 2、自定義無參數層

    from mxnet import gluon, nd from mxnet.gluon import nnclass CenteredLayer(nn.Block):def __init__(self, **kwargs):super(CenteredLayer, self).__init__(**kwargs)def forward(self, x):return x - x.mean() layer = CenteredLayer() layer(nd.array([1, 2, 3, 4, 5]))

    說明: 與上面的g_layer沒有區別,都是tensor+forward,這里layer.weight.data()就會報錯,因為是0個層;

    3、自定義含參數層

    自定義的層的意思是tensor也要自定義,tensor就是weight + bias;

    class MyDense(nn.Block):def __init__(self, units, in_units, **kwargs):super(MyDense, self).__init__(**kwargs)self.weight1 = self.params.get('haha_weight', shape=(in_units, units))self.bias1 = self.params.get('haha_bias', shape=(units,))def forward(self, x):linear = nd.dot(x, self.weight1.data()) + self.bias1.data()return nd.relu(linear)if __name__ == '__main__':dense = MyDense(units=3, in_units=5)dense.initialize()dense(nd.random.uniform(shape=(2, 5)))print(dense.weight1.data()[0])""" [0.0068339 0.01299825 0.0301265 ] <NDArray 3 @cpu(0)> """

    說明:從這個代碼中可以看出一個層的本質就是一段網絡;

    4、層的應用

    net = nn.Sequential() net.add(MyDense(8, in_units=64),MyDense(1, in_units=8)) net.initialize() y = net(nd.random.uniform(shape=(2, 64))) print('self_define tensor:', net[0].weight1.data()[0])""" self_define tensor: [0.0068339 0.01299825 0.0301265 0.04819721 0.01438687 0.050112390.00628365 0.04861524] <NDArray 8 @cpu(0)> """

    四、自定義初始化

    1、_init_weight在做什么?

    # -*- coding: utf-8 -*- from mxnet import init, nd from mxnet.gluon import nnclass MyInit(init.Initializer):def _init_weight(self, name, data):print('Init', name, data.shape)if __name__ == '__main__':net = nn.Sequential()net.add(nn.Dense(256, activation='relu'),nn.Dense(256, activation='relu'),nn.Dense(10))net.initialize(init=MyInit())X = nd.random.uniform(shape=(2, 20))print('---------1---------')Y = net(X)print('---------2---------')net.initialize(init=MyInit(), force_reinit=True)""" # output ---------1--------- Init dense0_weight (256, 20) Init dense1_weight (256, 256) Init dense2_weight (10, 256) ---------2--------- Init dense0_weight (256, 20) Init dense1_weight (256, 256) Init dense2_weight (10, 256) """

    2、怎么使用_init_weight自定義初始化?

    class MyInit(init.Initializer):def _init_weight(self, name, data):print('Init', name, data.shape)data[:] = nd.random.uniform(low=-10, high=10, shape=data.shape)data *= data.abs() >= 5net.initialize(MyInit(), force_reinit=True) net[0].weight.data()[0]

    說明:上面僅說明對weight初始化,gulon也提供了_init_bias,但是最后還是強制bias=0,也就是重寫的_init_bias沒有被調用,從機器學習的角度講,bias一般初始化為0;

    總結

    以上是生活随笔為你收集整理的面向对象方法使用gluon的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。