How to create own operator with python in mxnet?
阿新 • • 發佈:2017-09-11
處理 需要 調用父類 rgs rop 數據類型 賦值 創建 recipe
繼承CustomOp
1 class LossLayer(mxnet.operator.CustomOp): 2 def __init__(self, *args, **kwargs): 3 super(LossLayer, self).__init__() 4 # recipe some arguments for forward or backward calculation 5 6 def forward(self, is_train, req, in_data, out_data, aux):7 """ 8 in_data是一個列表,其中tensor的順序和對應屬性類中定義的list_arguments()參數一一對應 9 out_data輸出列表 10 is_train 是否是訓練過程 11 req [Null, write or inplace, add]指如何處理對應的復制操作 12 """ 13 pass 14 # 函數最後一般調用父類的self.assign(dst, req[0], src)進行賦值操作 15 # 但對於dst或者src是list類型的時候要調用多次assign函數處理,此時也可以直接自己賦值16 # dst[:]=src 17 18 def backward(self, req, out_grad, in_data, out_data, in_grad, aux): 19 """ 20 out_grad 上一層反傳的誤差 21 in_data 輸入數據,list 22 out_data 輸出的數據,由forward方法確定, 其類型大小和out_grad一致 23 in_grad 需要計算的回傳誤差 24 """ 25 pass26 # 其操作值得復制操作類似於forward方法
- 定義好操作符之後還需要定義其對應的屬性類,並將其註冊到operator中
1 @mx.operator.register(‘losslayer‘) # 註意這裏註冊的名字將是後面調用該操作符使用的類型名
- 重寫對應的屬性類
1 class LossLayerProp(mx.operator.CustomOpProp): # 這裏的名字並非必須對應操作類名稱,被@修飾符修飾 2 def __init__(self, params): 3 super(LossLayerProp,self).__init__(need_top_grad=False) 4 # 最後的損失層不需要接收上層的誤差,則將need_top_grad設置為False 5 # 可以傳遞一些參數用以傳遞給操作類 6 7 def list_arguments(self): 8 # 這個方法非常重要,定義了該操作符的輸入參數,當綁定對應操作符時,輸入量由該方法指定 9 return [‘data1‘,‘data2‘,‘data3‘,‘label‘] 10 11 def list_outputs(self): 12 # 同樣返回的是列表,表示輸出的量,這個其實是輸出變量的後綴suffix 13 # 若返回的是[‘output1‘,‘output2‘]則輸出為 操作類的名稱name加上對應後綴的量[name_output1, name_output2] 14 return [‘output‘] 15 16 def infer_shape(self, in_shape): 17 # 給定in_shape,顯示每一個變量的對應大小,以判斷大小是否一致 18 return [],[],[] 19 # 返回的必須是3個列表,即使列表為空,分別對應著輸入參數的大小、輸出數據的大小、aux參數的大小,一般最後一個為空 20 21 def infer_type(self, in_type): 22 # 該方法類似於infer_shape,推斷數據類型 23 24 def create_operator(self, ctx, shapes, dtypes): 25 # 該方法真正的創建操作類對象,默認調用 26 return LossLayer()
- 自定義操作符的使用
1 data1=mx.sym.Variable(‘data1‘) 2 data2=mx.sym.Variable(‘data2‘) 3 data3=mx.sym.Variable(‘data3‘) 4 label = mx.sym.Variable(‘label‘) 5 # 下面這句調用很重要,顯示指定輸入的symbol,然後指定自定義操作符類型 6 net = mx.sym.Custom(data1=data1, data2=data2, data3=data3, label=label, name=‘net‘, op_type=‘losslayer‘) 7 # 輸出操作符的相關屬性 8 print(net.infer_shape(data1=(4,1,10,10), data2=(4,1,10,10),data3=(4,1,10,10) label=(4,))) 9 # data1=(4,1,10,10)表示對應symbol的shape 10 print(net.infer_type(data1=np.int, data2=np.int, data3=np.int, label=np.int)) 11 # data1=np.int 標識對應symbol的數據類型 12 print(net.list_arguments()) # 變量參數 13 print(net.list_outputs()) #輸出的變量參數 14 15 ex = net.simple_bind(ctx=mx.gpu(0), data1=(4,1,10,10), data2=(4,1,10,10),data3=(4,1,10,10) label=(4,)) # simple_bind只需要指定輸入參數的大小 16 ex.forward(data1=data1, data2=data2, label=label)) 17 print(ex.outputs[0])
- 上面是沒有參數的層,創建帶有參數的中間層和上面類似, 只是修改下面部分代碼
1 def list_arguments(self): 2 return [‘data‘,‘weight‘, ‘bias‘] 3 4 def infer_shape(self, in_shape): 5 data_shape = in_shape[0] 6 weight_shape = ... 7 bias_shape = ... 8 output_shape = ... 9 return [data_shape, weight_shape, bias_shape], [output_shape], []
調用方式:
net = mx.symbol.Custom(data, name=‘newLayer‘, op_type=‘myLayer‘)
包含參數的layer在定義backward方法時要註意梯度的更新方式,即req的選擇
How to create own operator with python in mxnet?