Alink教程(Java版)

第25.2节 手写识别MNIST

本节使用数据集为手写识别MNIST数据集,在Alink教程的第13章已经对该数据集进行了详细介绍,而且尝试了几种常用的非深度多分类器,并对分类效果进行了对比,感兴趣的读者可以参阅,这里不再重复。本节的重点是演示如何使用深度神经网络(DNN)和卷积神经网络(CNN)进行图片分类。

25.2.1 Softmax算法

在原始训练、测试集中,每个图像数据被存成一个向量,我们可以使用常用的Softmax算法进行多分类,具体代码如下:

new Pipeline()
    .add(
        new Softmax()
            .setVectorCol("vec")
            .setLabelCol("label")
            .setPredictionCol("pred")
    )
    .fit(train_set)
    .transform(test_set)
    .link(
        new EvalMultiClassBatchOp()
            .setLabelCol("label")
            .setPredictionCol("pred")
            .lazyPrintMetrics()
    );

BatchOperator.execute();

输出评估结果如下,我们会将此作为baseline,后面构造深度模型提升效果。

-------------------------------- Metrics: --------------------------------
Accuracy:0.9224	Macro F1:0.9213	Micro F1:0.9224	Kappa:0.9137	
|Pred\Real|  9|  8|  7|...|  2|   1|  0|
|---------|---|---|---|---|---|----|---|
|        9|922| 11| 31|...|  4|   0|  0|
|        8|  9|859|  3|...| 37|  10|  2|
|        7| 23| 11|945|...|  8|   1|  3|
|      ...|...|...|...|...|...| ...|...|
|        2|  2|  5| 24|...|915|   6|  1|
|        1|  7| 10|  8|...| 10|1112|  0|
|        0|  6|  9|  2|...| 11|   0|954|



25.2.2 使用深度神经网络(DNN)


我们尝试使用深度神经网络构建模型,在输入层和输出层之间添加2个全连接层,分别有256个和128个神经元。网络描述如下:

_________________________________________________________________ 
Layer (type)                 Output Shape              Param #    
================================================================= 
tensor (InputLayer)          [(None, 784)]             0          
_________________________________________________________________ 
dense (Dense)                (None, 256)               200960     
_________________________________________________________________ 
dense_1 (Dense)              (None, 128)               32896      
_________________________________________________________________ 
logits (Dense)               (None, 10)                1290       
================================================================= 
Total params: 235,146                                             
Trainable params: 235,146                                         
Non-trainable params: 0                                           
_________________________________________________________________ 

在Alink中实现该网络很简单,可以在Pipeline中使用Keras 分类器组件(KerasSequentialClassifier),通过setLayers方法,设置深度神经网络;由特征维度数和分类类别数,组件会自动设置输入层(784 bins)和输出层(10 bins)。注意:原始向量中各个分量的取值范围为[0, 255],在使用深度学习模型前,将每个分量除以255,使得每个分量的取值范围变为[0, 1]。

new Pipeline()
	.add(
		new VectorFunction()
			.setSelectedCol("vec")
			.setFuncName("Scale")
			.setWithVariable(1.0 / 255.0)
	)
	.add(
		new VectorToTensor()
			.setTensorDataType("float")
			.setSelectedCol("vec")
			.setOutputCol("tensor")
			.setReservedCols("label")
	)
	.add(
		new KerasSequentialClassifier()
			.setTensorCol("tensor")
			.setLabelCol("label")
			.setPredictionCol("pred")
			.setLayers(
				"Dense(256, activation='relu')",
				"Dense(128, activation='relu')"
			)
			.setNumEpochs(50)
			.setBatchSize(512)
			.setValidationSplit(0.1)
			.setSaveBestOnly(true)
			.setBestMetric("sparse_categorical_accuracy")
			.setNumWorkers(1)
			.setNumPSs(0)
	)
	.fit(train_set)
	.transform(test_set)
	.link(
		new EvalMultiClassBatchOp()
			.setLabelCol("label")
			.setPredictionCol("pred")
			.lazyPrintMetrics()
	);

BatchOperator.execute();


计算出模型评估指标如下,相对于Softmax方法有明显提升。

-------------------------------- Metrics: --------------------------------
Accuracy:0.9795	Macro F1:0.9794	Micro F1:0.9795	Kappa:0.9772	
|Pred\Real|  9|  8|   7|...|   2|   1|  0|
|---------|---|---|----|---|----|----|---|
|        9|983|  4|   7|...|   0|   0|  1|
|        8|  3|947|   4|...|   6|   3|  2|
|        7|  3|  3|1000|...|   4|   1|  1|
|      ...|...|...| ...|...| ...| ...|...|
|        2|  0|  3|   9|...|1010|   3|  0|
|        1|  2|  0|   3|...|   0|1125|  0|
|        0|  1|  4|   2|...|   3|   0|970|


25.2.3 使用卷积神经网络(CNN)

本节侧重卷积神经网络(CNN)的实现,关于CNN的基本概念和理论不展开介绍。这里主要使用2维卷积层和2维最大池化层构建了卷积神经网络,详细网络描述如下:

_________________________________________________________________ 
Layer (type)                 Output Shape              Param #    
================================================================= 
tensor (InputLayer)          [(None, 28, 28)]          0          
_________________________________________________________________ 
reshape (Reshape)            (None, 28, 28, 1)         0          
_________________________________________________________________ 
conv2d (Conv2D)              (None, 26, 26, 32)        320        
_________________________________________________________________ 
max_pooling2d (MaxPooling2D) (None, 13, 13, 32)        0          
_________________________________________________________________ 
conv2d_1 (Conv2D)            (None, 11, 11, 64)        18496      
_________________________________________________________________ 
max_pooling2d_1 (MaxPooling2 (None, 5, 5, 64)          0          
_________________________________________________________________ 
flatten (Flatten)            (None, 1600)              0          
_________________________________________________________________ 
dropout (Dropout)            (None, 1600)              0          
_________________________________________________________________ 
logits (Dense)               (None, 10)                16010      
================================================================= 
Total params: 34,826                                              
Trainable params: 34,826                                          
Non-trainable params: 0                                           
_________________________________________________________________ 

可以在Pipeline中使用Keras 分类器组件(KerasSequentialClassifier),通过setLayers方法,设置卷积神经网络。

new Pipeline()
	.add(
		new VectorFunction()
			.setSelectedCol("vec")
			.setFuncName("Scale")
			.setWithVariable(1.0 / 255.0)
	)
	.add(
		new VectorToTensor()
			.setTensorDataType("float")
			.setTensorShape(28, 28)
			.setSelectedCol("vec")
			.setOutputCol("tensor")
			.setReservedCols("label")
	)
	.add(
		new KerasSequentialClassifier()
			.setTensorCol("tensor")
			.setLabelCol("label")
			.setPredictionCol("pred")
			.setLayers(
				"Reshape((28, 28, 1))",
				"Conv2D(32, kernel_size=(3, 3), activation='relu')",
				"MaxPooling2D(pool_size=(2, 2))",
				"Conv2D(64, kernel_size=(3, 3), activation='relu')",
				"MaxPooling2D(pool_size=(2, 2))",
				"Flatten()",
				"Dropout(0.5)"
			)
			.setNumEpochs(20)
			.setValidationSplit(0.1)
			.setSaveBestOnly(true)
			.setBestMetric("sparse_categorical_accuracy")
			.setNumWorkers(1)
			.setNumPSs(0)
	)
	.fit(train_set)
	.transform(test_set)
	.link(
		new EvalMultiClassBatchOp()
			.setLabelCol("label")
			.setPredictionCol("pred")
			.lazyPrintMetrics()
	);

BatchOperator.execute();


计算出模型评估指标如下,和前面的深度模型相比,效果进一步提升。

-------------------------------- Metrics: --------------------------------
Accuracy:0.9918	Macro F1:0.9918	Micro F1:0.9918	Kappa:0.9909	
|Pred\Real|  9|  8|   7|...|   2|   1|  0|
|---------|---|---|----|---|----|----|---|
|        9|995|  2|   1|...|   0|   0|  0|
|        8|  3|965|   1|...|   2|   1|  1|
|        7|  2|  1|1016|...|   3|   0|  1|
|      ...|...|...| ...|...| ...| ...|...|
|        2|  0|  1|   6|...|1026|   3|  0|
|        1|  2|  0|   3|...|   0|1131|  1|
|        0|  1|  2|   0|...|   1|   0|977|