CNTK2.3 C# CNN训练MNIST(CNTK C#入门3)

20180110

keywords: CNTK  C#  CNN  MNIST


1、CNN使用需明白的参数

对CNN不太明白的童鞋参见这篇,很生动cnn动态展示

卷积网络的基本运算过程如下,z = wx + b,w是权重矩阵,b是偏差矩阵


CNTK2.3 C# CNN训练MNIST(CNTK C#入门3)_第1张图片

看了上面的连接应该明白下面这三个参数的意思了,创建CNN网络时要用到,在此不多说了。

filter、stride、pad


2、CNN网络创建

var scaledInput = CNTKLib.ElementTimes(Constant.Scalar(0.00390625f, device), input);

                double convWScale = 0.26;// parameter initialization hyper parameter

                var m1 = new Parameter(new int[] { 5, 5, 1, 4 }, DataType.Float, CNTKLib.GlorotUniformInitializer(convWScale, -1, 2), device);

                var c1 = CNTKLib.ReLU(CNTKLib.Convolution(m1, scaledInput, new int[] { 1, 1, 1 }));

                var p1 = CNTKLib.Pooling(c1, PoolingType.Max, new int[] { 4, 4 }, new int[] { 4, 4 }, new bool[] { true });

                var m2 = new Parameter(new int[] { 4, 4, 4, 8 }, DataType.Float, CNTKLib.GlorotUniformInitializer(convWScale, -1, 2), device);

                var c2 = CNTKLib.ReLU(CNTKLib.Convolution(m2, p1, new int[] { 1, 1, 4 }));

                var p2 = CNTKLib.Pooling(c2, PoolingType.Max, new int[] { 3, 3 }, new int[] { 3, 3 }, new bool[] { true });

                var m3 = new Parameter(new int[] { 3, 3, 8, 16 }, DataType.Float, CNTKLib.GlorotUniformInitializer(convWScale, -1, 2), device);

                var c3 = CNTKLib.ReLU(CNTKLib.Convolution(m3, p2, new int[] { 1, 1, 8 }));

                var p3 = CNTKLib.Pooling(c3, PoolingType.Max, new int[] { 2, 2 }, new int[] { 2, 2 }, new bool[] { true });

                dout = TestHelper.Dense(p3, numClasses, device, Activation.None, classifierName);

上面的程序创建了3个卷积层(c1、c2、c3)、3个pooling层(p1、p2、p3)和一个输出层(dout),下面单看一个卷积层和一个pooling层如何创建

var m1 = new Parameter(new int[] { 5, 5, 1, 4 }, DataType.Float, CNTKLib.GlorotUniformInitializer(convWScale, -1, 2), device);

                var c1 = CNTKLib.ReLU(CNTKLib.Convolution(m1, scaledInput, new int[] { 1, 1, 1 }));

                var p1 = CNTKLib.Pooling(c1, PoolingType.Max, new int[] { 4, 4 }, new int[] { 4, 4 }, new bool[] { true });

{ 5, 5, 1, 4 }表示卷积核filter是5*5,输入1通道,输出4通道

{ 1, 1, 1 }表示卷积stride是1、1;最后一个1表示输入通道

前一个 { 4, 4 }表示Pooling filter是4*4,后一个 { 4, 4 }表示Pooling的stride是4、4,也就是没有重复的区域

3、几点注意事项

1)卷积层的stride,{ 1, 1, 1 }中最后一个1表示输入通道,如果填错或不填,程序会莫名其妙的飞掉

var c1 = CNTKLib.ReLU(CNTKLib.Convolution(cp1, scaledInput, new int[] { 1, 1, 1 }));

2)使用下面这句正确率会降低1个点(不使用pad),由此看出 1、使用pad会提高正确率;2、创建卷积时缺省pad为true

var c1 = CNTKLib.ReLU(CNTKLib.Convolution(cp1, scaledInput, new int[] { 1, 1, 1 }, new bool[] { true }, new bool[] { false }));

3)前面的Pooling层filter比后面的Pooling层大,会提高正确率

4、测试结论

1)卷积网络会比MLP提高2个点的正确率

2)对于mnist,增加卷积层并没有提高正确率

3)我测试的结果只能达到98.86,为啥没有超过99呢?

4)单纯使用卷积层,不使用Pooling层,计算时间会增加几倍,结果也会下降2个点。可见Pooling层的抽象提取作用还是有效的。


下节讨论LSTM长短记忆模型

你可能感兴趣的:(CNTK2.3 C# CNN训练MNIST(CNTK C#入门3))