实 验 报 告
0、BaseNet(三层、sigmoid、784-386-10) 1
1、Hidden_Net(784-112-10和784-543-10) 2
2、reluActivation_Net 3
3、DeepNet(四层、五层) 4
4、DeepNet(四层、五层;训练轮数增加) 5
5、DeepNet(五层;Dropout) 6
7、DeepNet(五层;Dropout+relu) 8
8、AutoEncoder_Net(五层;AutoEncoder) 9
9、结论 10
摘要:本次试验的数据集为MNIST digits,使用keras构建了各式各样的网络,完成了手写数字识别,实验结果比较理想。除此之外,我们还比较了不同模型之间的差别,定性或定量的分析了各种超参数(结点个数、激活函数、隐含层个数、训练轮数等)、是否采用dropout策略、是否有预训练(使用AutoEncoder)等细节选择对实验结果的影响,通过这种定性或定量的深入分析,让我们对神经网络有了更清晰的认识,对不同情境下神经网络的选择也有了更深入的理解。
三层结构、激活函数为常见的sigmoid,网络结构784-386-10,代码如下:
#*************build your model model=Sequential() model.add( Dense( 386, input_dim=784, init='uniform' ) ) model.add(Activation('sigmoid')) model.add(Dense(10, activation='softmax')) #'softmax' for multi-calss
#*************compile your model sgd=SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True) model.compile(loss='categorical_crossentropy', optimizer=sgd, class_mode=None, sample_weight_mode=None)
#*************train your model #Returns a history object. #Its history attribute is a record of training loss values at successive epochs, #as well as validation loss values (if applicable). model.fit(X=Xtrain, y=ytrain, nb_epoch=10, batch_size=200, verbose=1, callbacks=[], validation_split=0.0, validation_data=(XCV, yCV), shuffle=True, show_accuracy=True, class_weight=None, sample_weight=None)
#*************evaluate your model score=model.evaluate(X=Xtest, y=ytest, batch_size=200, show_accuracy=True, verbose=1, sample_weight=None) print "loss="+str(score[0])+" acc="+str(score[1]) |
Training和evaluation的结果如下:
Loss=0.128940589167;acc=0.962099999189
这个结果作为baseline,不做分析。
结构和上面一样,不过隐藏层节点数改为112。
Training和evaluation的结果如下:
Loss=0.0937348691374;acc=0.970400002003
结构和上面一样,不过隐藏层节点数改为543。
Training和evaluation的结果如下:
Loss=1.6589958334;acc=0.869799996614
通过对比试验0和1,我们发现:隐藏层节点数较少时,效果较好;隐藏层节点数较多时,效果相对较差。
结构和上面一样,不过激活函数改为relu。
Training和evaluation的结果如下:
Loss=0.0602644333878;acc=0.980100008249
通过对比试验0和2,我们发现:激活函数改为relu比使用sigmoid效果更好,loss更小,acc更大(提高了0.02,已经非常不错了!);实际上relu(Rectified Linear Units)激活函数已经被证明,在大多数情况下要好于sigmoid函数。
四层,sigmoid激活函数,网络结构784-426-246-10,代码如下:
model=Sequential() model.add( Dense( 426, input_dim=784, init='uniform' ) ) model.add(Activation('sigmoid')) model.add(Dense(246, activation='sigmoid')) model.add(Dense(10, activation='softmax')) #'softmax' for multi-calss |
Training和evaluation的结果如下:
Loss=0.132126849946;acc=0.960399998426
五层,sigmoid激活函数,网络结构784-543-386-112-10,代码如下:
model=Sequential() model.add( Dense( 543, input_dim=784, init='uniform' ) ) model.add(Activation('sigmoid')) model.add(Dense(386, activation='sigmoid')) model.add(Dense(112, activation='sigmoid')) model.add(Dense(10, activation='softmax')) #'softmax' for multi-calss |
Training和evaluation的结果如下:
Loss=0.142769166548;acc=0.955300002098
通过对比试验0和3以及实验3本身的两个子实验,我们发现:层数越多反而效果越差;仔细分析发现可能的原因是“层数较多的情况下需要经过较长次数的训练,否则网络不容易达到最优”,这个结论从val_acc一直在增加也可以证明,至少网络当前处于underfitting的状态!
为了验证这个猜想,我们做了如下实验:将nb_epoch=10改为nb_epoch=20。
四层,将nb_epoch=10改为nb_epoch=20,Training和evaluation的结果如下:
Loss=0.0860328582302;acc=0.973700002432
五层,将nb_epoch=10改为nb_epoch=20,Training和evaluation的结果如下:
Loss=0.079075542494;acc=0.976300004721
通过对比试验3、4以及实验3本身的两个子实验和实验4本身的两个子实验,我们发现:随着训练轮数的增多,效果越来越好,这说明我们前面的分析是正确的!这也告诉我们,如果网络比较深,应该多训练几轮以使网络得到充分训练。
sigmoid激活函数,网络结构784-543-386-112-10,使用随机Dropout,nb_epoch=20,代码如下:
#*************build your model model=Sequential() model.add( Dense( 543, input_dim=784, init='uniform' ) ) model.add(Activation('sigmoid')) model.add(Dropout(0.05)) model.add(Dense(386, activation='sigmoid')) model.add(Dropout(0.05)) model.add(Dense(112, activation='sigmoid')) model.add(Dropout(0.05)) model.add(Dense(10, activation='softmax')) #'softmax' for multi-calss |
Training和evaluation的结果如下:
Loss=0.098954036464;acc=0.970100002289
通过对比试验4和5,我们发现:当网络的某一层的节点数比较少的时候采取dropout策略反而容易引起网络性能的下降!这可能因为比较少的节点难以捕获数据内在关系有关。为了解决上面的问题,我们猜测需要进一步加大训练轮数才可以,所以进行了下面的试验。
6、DeepNet(五层;Dropout+nb_epoch=30)
sigmoid激活函数,网络结构784-543-386-112-10,使用随机Dropout,nb_epoch=30:
Training和evaluation的结果如下:
Loss=0.0791375797056;acc=0.975700001717
通过对比试验4、5和6,我们发现:在采取dropout策略时适当增大训练轮数也能在一定程度上提高网络性能。
relu激活函数,网络结构784-543-386-112-10,使用随机Dropout,nb_epoch=20,代码如下:
#*************build your model model=Sequential() model.add( Dense( 543, input_dim=784, init='uniform' ) ) model.add(Activation('relu')) model.add(Dropout(0.05)) model.add(Dense(386, activation='relu')) model.add(Dropout(0.05)) model.add(Dense(112, activation='relu')) model.add(Dropout(0.05)) model.add(Dense(10, activation='softmax')) #'softmax' for multi-calss |
Training和evaluation的结果如下:
Loss=0.0797024395682;acc=0.983800008297
通过对比试验4、5、6和7,我们发现:relu激活函数的性能非常好,即便是在采取dropout策略时保持训练轮数不变,也能在一定程度上提高网络性能;这也验证了试验2的结论。
网络结构784-543-386-112-10,nb_epoch=30,sigmoid激活函数,关键代码如下:
#*************add the softmax layer to create the DEEP(AutoEncoder) neural network #*************and fine turning the DEEP(AutoEncoder) neural network model=Sequential() model.add(autoencoder1.encoder) model.add(autoencoder2.encoder) model.add(autoencoder3.encoder) model.add(Dense(input_dim=112, output_dim=10, activation='softmax')) sgd=SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True) model.compile(loss='categorical_crossentropy', optimizer=sgd, class_mode=None, sample_weight_mode=None) #model.fit(X=Xtrain, y=ytrain, nb_epoch=10) #note: y=Xtrain model.fit(X=Xtrain, y=ytrain, nb_epoch=30, batch_size=200, verbose=1, callbacks=[], validation_split=0.0, validation_data=(XCV, yCV), shuffle=True, show_accuracy=True, class_weight=None, sample_weight=None) |
Training和evaluation的结果如下:
Loss=0.0799347099484;acc=0.976900002956
通过对比试验4和8,我们发现:使用AutoEncoder进行预训练,能在一定程度上提高网络性能。另外,训练的时间也大大缩短(大约缩短1/3的时间)!
通过实验0到实验8的对比分析,我们主要得到以下结论:
1)结点个数:最后一个隐藏层结点个数越接近输出层的结点个数,效果相对越好。
2)激活函数:relu比sigmoid等效果普遍较好;该结论也被其他实验证明。
3)隐含层个数:如果保持训练轮数不变,那么隐含层个数越多,效果相对越差;但如果同时增大训练轮数,那么效果就会相对较好。
4)训练轮数:增大训练轮数在一定程度上能够提高网络性能;尤其是在增大隐含层个数的情况下,增加训练轮数非常有必要。
5)Dropout策略:在网络的结点个数相对较少时,采用dropout策略会降低网络性能;在网络的结点个数相对较多时,采用dropout策略则会在一定程度上提升网络性能。
6)预训练:使用AutoEncoder进行预训练,能在一定程度上提高网络性能;另外,训练的时间也大大缩短(大约缩短1/3的时间)!