博主在學習三值神經網路時,使用了lenet-5模型,程式設計**,需要對lenet-5模型中的卷積層與全連線層進行自定義,搜尋他人方法後,博主產生了乙個疑問,絕大多數提供的自定義層方法都是繼承nn.module模型,而這方法據說是官方提供(官網**:pytorch),自定義線性層**如下:
class
linear
(nn.module)
:def
__init__
(self, input_features, output_features, bias=
true):
super
(linear, self)
.__init__(
) self.input_features = input_features
self.output_features = output_features
self.weight = nn.parameter(torch.tensor(output_features, input_features)
)if bias:
self.bias = nn.parameter(torch.tensor(output_features)
)else
: self.register_parameter(
'bias'
,none
) self.weight.data.uniform_(
-0.1
,0.1
)if bias is
notnone
: self.bias.data.uniform_(
-0.1
,0.1
)def
forward
(self,
input):
return linearfunction.
(input
, self.weight, self.bias)
博主因涉獵pytorch時長過短,對此了解不多,初始僅是覺得奇怪,為何自定義層需要繼承nn.module模型,乍一看像是自定義模型而非自定義層
因博主過於小白,當時就想,這麼誤人子弟的自定義方法不應該籠統地用nn.module一齊實現,pytorch是乙個成熟的軟體,應該知道還有博主這種小小白沒辦法立刻上手以nn.module為依賴的自定義層方法(說實話,博主看了幾天才看懂上面的**是啥意思……哭泣……)
所以博主又搜尋了github中與已發表**相關的pytorch深度學習**,終於發現了pytorch自定義層的簡單方法,可以細節到區分具體層的種類,而不會產生混淆
以下為博主使用的lenet-5模型,為直觀體現自定義層的方法,博主僅留下了自定義的卷積層與全連線層,即**中ternaryconv2d(1, 32, kernel_size=5)與ternarylinear(512, 10)部分
# lenet-5模型
class
lenet_5
(nn.module)
:def
__init__
(self)
:super
(lenet_5, self)
.__init__(
) self.conv1 = ternaryconv2d(1,
32, kernel_size=5)
# 卷積
self.fc1 = ternarylinear(
512,10)
# 全連線
defforward
(self, x)
: x = self.conv1(x)
x = self.fc1(x)
return x
以下為博主自定義的卷積層(ternaryconv2d)與全連線層(ternarylinear)
class
ternaryconv2d
(nn.conv2d)
:# def __init__(self, *args, **kwargs):
# 該方法接受任意個數的引數,其中不指定key的引數會以list形式儲存到args變數中,指定key的引數會以dict的形式儲存到kwargs變數中
def__init__
(self,
*args,
**kwargs)
:super
(ternaryconv2d, self)
.__init__(
*args,
**kwargs)
defforward
(self,
input):
out = f.conv2d(
input
, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups)
return out
class
ternarylinear
(nn.linear)
:def
__init__
(self,
*args,
**kwargs)
:super
(ternarylinear, self)
.__init__(
*args,
**kwargs)
defforward
(self,
input):
out = f.linear(
input
, self.weight, self.bias)
return out
以卷積層為例,類名可自行定義,但必須繼承nn.conv2d,在該層初始化使用時,若無引數設定,將會預設卷積層的引數,預設引數可查閱官方文件(在 python api 中)獲知,這裡博主將其貼上了過來:
class torch
.nn.conv2d(in_channels, out_channels, kernel_size, stride=
1, padding=
0, dilation=
1, groups=
1, bias=
true
, padding_mode=
'zeros'
)
而後,在definit() 函式中可初始化引數,在def forward()函式中可對卷積層自行設計
若想自定義其他型別的層,只需修改繼承的nn.conv2d即可,操作非常簡單且不會產生歧義
博主將模型與層的**整合如下,便於複製使用:
class
ternaryconv2d
(nn.conv2d)
:# def __init__(self, *args, **kwargs):
# 該方法接受任意個數的引數,其中不指定key的引數會以list形式儲存到args變數中,指定key的引數會以dict的形式儲存到kwargs變數中
def__init__
(self,
*args,
**kwargs)
:super
(ternaryconv2d, self)
.__init__(
*args,
**kwargs)
defforward
(self,
input):
out = f.conv2d(
input
, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups)
return out
class
ternarylinear
(nn.linear)
:def
__init__
(self,
*args,
**kwargs)
:super
(ternarylinear, self)
.__init__(
*args,
**kwargs)
defforward
(self,
input):
out = f.linear(
input
, self.weight, self.bias)
return out
# lenet-5模型
class
lenet_5
(nn.module)
:def
__init__
(self)
:super
(lenet_5, self)
.__init__(
) self.conv1 = ternaryconv2d(1,
32, kernel_size=5)
# 卷積
self.fc1 = ternarylinear(
512,10)
# 全連線
defforward
(self, x)
: x = self.conv1(x)
x = self.fc1(x)
return x
因官方模型類api過多,博主無法一一檢視,博主猜測nn.module模型中應該與自定義層所使用的nn.conv2d有著某種繼承關係,所以可以如此使用 PyTorch 自定義層
與使用module類構造模型類似。下面的centeredlayer類通過繼承module類自定義了乙個將輸入減掉均值後輸出的層,並將層的計算定義在了forward函式裡。這個層裡不含模型引數。class mydense nn.module def init self super mydense,se...
從頭學pytorch 十一 自定義層
一文裡說了怎麼寫自定義的模型.本篇說怎麼自定義層.分兩種 核心都一樣,自定義乙個繼承自nn.module的類,在類的forward函式裡實現該layer的計算,不同的是,帶引數的layer需要用到nn.parameter 直接繼承nn.module import torch from torch i...
Pytorch 實現自定義引數層的例子
注意,一般官方介面都帶有可導功能,如果你實現的層不具有可導功能,就需要自己實現梯度的反向傳遞。官方linear層 class linear module def init self,in features,www.cppcns.com out features,bias true super lin...