本文以标准的chainer模型构建的方式构建lenet结构,代码阅读性强。
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)