zl程序教程

您现在的位置是:首页 >  云平台

当前栏目

chainer-骨干网络backbone-LeNet5代码重构【附源码】

2023-09-27 14:21:00 时间


前言

本文以标准的chainer模型构建的方式构建lenet结构,代码阅读性强。


一、LeNet5简单版实现

class LeNet5_Simple(chainer.Chain):
    def __init__(self,num_classes=10, channels=1,image_size=28,initialW=chainer.initializers.Normal(0.01)):
        super(LeNet5_Simple, self).__init__()
        with self.init_scope():
            # (28-5+2*0)/1+1=24 12   (224-5+2*0)/1+1=220 maxpooling:110
            self.conv1 = L.Convolution2D(in_channels=channels, out_channels=6, ksize=5, stride=1,initialW=initialW)
            out_size = math.ceil(((image_size-5+2*0)//1+1)/2)
            # (12-5+2*0)/1+1=8  4    (110-5+2*0)/1+1=106 maxpooling:53
            self.conv2 = L.Convolution2D(in_channels=6, out_channels=16, ksize=5, stride=1,initialW=initialW)
            out_size = math.ceil(((out_size-5+2*0)//1+1)/2)
            # (4-4+2*0)/1+1=1        (53-4+2*0)/1+1=50
            self.conv3 = L.Convolution2D(in_channels=16, out_channels=120, ksize=4, stride=1,initialW=initialW)
            out_size = ((out_size-4+2*0)//1+1)
            self.fc4 = L.Linear(120*out_size*out_size, 84,initialW=initialW)
            self.fc5 = L.Linear(84, num_classes,initialW=initialW)

    def __call__(self, x):
        h = F.sigmoid(self.conv1(x))
        h = F.max_pooling_2d(h, 2, 2)
        h = F.sigmoid(self.conv2(h))
        h = F.max_pooling_2d(h, 2, 2)
        h = F.sigmoid(self.conv3(h))
        h = F.sigmoid(self.fc4(h))
        
        if chainer.config.train:
            return self.fc5(h)
        return F.softmax(self.fc5(h))

二、利用列表形式进行构建网络

class LeNet5_Complex(chainer.Chain):
    def __init__(self,num_classes=10, channels=1,image_size=28,initialW=chainer.initializers.Normal(0.01)):
        super(LeNet5_Complex, self).__init__()
        # (28-5+2*0)/1+1=24 12   (224-5+2*0)/1+1=220 maxpooling:110
        net = [('conv1', L.Convolution2D(in_channels=channels, out_channels=6, ksize=5, stride=1,initialW=initialW))]
        net += [('_sigm1', Sigmoid())]
        net += [('_mpool1', MaxPooling2D(2, 2))]
        out_size = math.ceil(((image_size-5+2*0)//1+1)/2)
        # (12-5+2*0)/1+1=8  4    (110-5+2*0)/1+1=106 maxpooling:53
        net += [('conv2', L.Convolution2D(in_channels=6, out_channels=16, ksize=5, stride=1,initialW=initialW))]
        net += [('_sigm2', Sigmoid())]
        net += [('_mpool2', MaxPooling2D(2, 2))]
        out_size = math.ceil(((out_size-5+2*0)//1+1)/2)
        # (4-4+2*0)/1+1=1        (53-4+2*0)/1+1=50
        net += [('conv3', L.Convolution2D(in_channels=16, out_channels=120, ksize=4, stride=1,initialW=initialW))]
        out_size = ((out_size-4+2*0)//1+1)
        net += [('_sigm3', Sigmoid())]
        # net += [('_mpool3', MaxPooling2D(2, 2))]
        net += [('fc4', L.Linear(120*out_size*out_size, 84))]
        net += [('_sigm4', Sigmoid())]
        net += [('fc5', L.Linear(84, num_classes))]
        net += [('_sigm5', Sigmoid())]
        with self.init_scope():
            for n in net:
                if not n[0].startswith('_'):
                    setattr(self, n[0], n[1])
        self.forward = net

    def __call__(self, x):
        for n, f in self.forward:
            origin_size = x.shape
            if not n.startswith('_'):
                x = getattr(self, n)(x)
            else:
                x = f.apply((x,))[0]
            print(n,origin_size,x.shape)
        if chainer.config.train:
            return x
        return F.softmax(x)

以上两种方式效果一致


总结

调用方式

if __name__ == '__main__':
    batch_size = 4
    n_channels = 1
    image_size = 28
    num_classes = 10
    
    model_simple = LeNet5_Simple(num_classes=num_classes, channels=n_channels,image_size=image_size)
    model_complex = LeNet5_Complex(num_classes=num_classes, channels=n_channels,image_size=image_size)
    print(model_simple.count_params())
    print(model_complex.count_params())
    x = np.random.rand(batch_size, n_channels, image_size, image_size).astype(np.float32)
    t = np.random.randint(0, num_classes, size=(batch_size,)).astype(np.int32)
    with chainer.using_config('train', True):
        y1 = model_simple(x)
        y2 = model_complex(x)
    loss1 = F.softmax_cross_entropy(y1, t)
    loss2 = F.softmax_cross_entropy(y2, t)
    print(loss1.data,loss2.data)