【PyTorch】バイアスBiasの値を書き換える 自作畳み込み層・全結合層

Python

バイアスを書き換えたい【自作の畳み込み層と全結合層 】

前回の記事では畳み込み層および全結合層の重みを+1,-1の2値に量子化する方法を紹介しました。

今回は線形結合のバイアスを操作する方法を紹介します。

バイアスを整数に丸める処理を加えたと思います。

modelus.pyに畳み込み層を記述していきます。

class BinaryConv2d(nn.Conv2d):

    def __init__(self, *kargs, **kwargs):
        super(BinaryConv2d, self).__init__(*kargs, **kwargs)

    def forward(self, input):
    
        self.weight.data = Binary(self.weight.data)
        
        out = F.conv2d(input, self.weight, None, self.stride, self.padding, self.dilation, self.groups)
        
        if not self.bias is None:
            self.bias.data = round(self.bias.data)
            out += self.bias.view(1, -1, 1, 1).expand_as(out)

        return out

ここで、敢えてバイアスを

out += self.bias.view(1, -1, 1, 1).expand_as(out)

として加算しました。

私の場合はバイアスを整数に丸める処理を加えるだけでなく、そもそもバイアスを使わない場合どうなるかという実験もしたかったので後で選択できるようにこのような書き方にしました。

具体的に、通常の積和ではy=xw+bですがバイアスを使いたくないときy=xwなります。

もっとシンプルにバイアスだけ操作したいときは下記のようにします。

class BinaryConv2d(nn.Conv2d):

    def __init__(self, *kargs, **kwargs):
        super(BinaryConv2d, self).__init__(*kargs, **kwargs)

    def forward(self, input):

    self.weight.data = Binary(self.weight.data)
    self.bias.data = round(self.bias.data)
        
        out = F.conv2d(input, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups)
      
        return out

畳み込み層のカスタマイズが終わったので次は全結合層をカスタマイズします。

from modules import *

class BinaryLinear(nn.Linear):
    def __init__(self, *kargs, **kwargs):
        super(BinaryLinear, self).__init__(*kargs, **kwargs)

    def forward(self, input):
       
        self.weight.data = Binary(self.weight.data)

        out = F.linear(input, self.weight)
    
        if not self.bias is None:
           
            self.bias.data = round(self.bias.data)
            out += self.bias.view(1, -1).expand_as(out)
     
        return out

これで自作全結合層・畳み込み層を作成し、バイアスの値に処理を加えることができました。

モデルは下記のようにしました。

class MyNet(nn.Module):

    def __init__(self):
        super(MyNet, self).__init__()
        self.features = nn.Sequential(
       
            BinaryConv2d(3, 128, kernel_size=3, padding=1,bias=True),
            nn.BatchNorm2d(128),

            BinaryConv2d(128, 128, kernel_size=3, padding=1, bias=True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.BatchNorm2d(128),

            BinaryConv2d(128, 256, kernel_size=3, padding=1, bias=True),
            nn.BatchNorm2d(256),

            BinaryConv2d(256, 256, kernel_size=3, padding=1, bias=True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.BatchNorm2d(256),

            BinaryConv2d(256, 512, kernel_size=3, padding=1, bias=True),
            nn.BatchNorm2d(512),

            BinaryConv2d(512, 512, kernel_size=3, padding=1, bias=True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.BatchNorm2d(512)
        )
        self.classifier = nn.Sequential(
         
            BinaryLinear(512 * 4 * 4, 1024, bias=True),
            nn.BatchNorm1d(1024),
           
            BinaryLinear(1024, 1024, bias=True),
            nn.BatchNorm1d(1024),
           
            BinaryLinear(1024, 10, bias=True),
            nn.BatchNorm1d(10)
           
        )

    def forward(self, x):
        x = self.features(x)
        x = x.view(-1, 512 * 4 * 4)
        x = self.classifier(x)
        return x

終わりに

自作の畳み込み層、全結合層を作成しバイアスに好きな処理を加える方法を説明しました。

また、nn.Conv2d()の引数のオプションでバイアスを使うかどうかも選択できるのでぜひ試してみてください。bias=falseとするとバイアスを使わない畳み込み演算をします。

nn.Conv2d(128, 128, kernel_size=3, padding=1, bias=False)

参考資料

コメント

タイトルとURLをコピーしました