Deeplearning4j 实战(5):基于多层感知机的Mnist压缩以及在Spark实现

Eclipse Deeplearning4j GiChat课程https://gitbook.cn/gitchat/column/5bfb6741ae0e5f436e35cd9f
Eclipse Deeplearning4j 系列博客https://blog.csdn.net/wangongxi
Eclipse Deeplearning4j Githubhttps://github.com/eclipse/deeplearning4j

在上一篇博客中,我们用基于RBM的的Deep AutoEncoder对Mnist数据集进行压缩,应该说取得了不错的效果。这里,我们将神经网络这块替换成传统的全连接的前馈神经网络对Mnist数据集进行压缩,看看两者的效果有什么异同。整个代码依然是利用Deeplearning4j进行实现,并且为了方便以后的扩展,我们将其与Spark平台结合。下面,就具体来说一下模型的结构、训练过程以及最终的压缩效果。

首先,我们新建Maven工程并加入Deeplearning4j的相关依赖(这一块内容在之前的文章中多次提及,因此这里就不再啰嗦了)。接下来,我们新建Spark任务,读取已经存放在HDFS上的Mnist数据集(和之前文章中提到的一样,Mnist数据集已经事先以JavaRDD<DataSet>的形式存储在HDFS上,具体操作可以参考之前的博客。),并生成训练数据集JavaRDD。具体代码如下:

 

        SparkConf conf = new SparkConf()
                            .set("spark.kryo.registrator", "org.nd4j.Nd4jRegistrator")
                            .setAppName("MLP AutoEncoder Mnist(Java)");
        JavaSparkContext jsc = new JavaSparkContext(conf);
        //
        final String inputPath = args[0];
        final String savePath = args[1];
        double lr = Double.parseDouble(args[2]);
        final int batchSize = Integer.parseInt(args[3]);
        final int numEpoch = Integer.parseInt(args[4]);
        //
        JavaRDD<DataSet> javaRDDMnist = jsc.objectFile(inputPath);//read mnist data from HDFS
        JavaRDD<DataSet> javaRDDTrain = javaRDDMnist.map(new Function<DataSet, DataSet>() {

            @Override
            public DataSet call(DataSet next) throws Exception {
                return new DataSet(next.getFeatureMatrix(),next.getFeatureMatrix());
            }
        });


构筑完训练数据集之后,我们就可以定义网络结构并配以相应的超参数:

 

 

        MultiLayerConfiguration netconf = new NeuralNetConfiguration.Builder()
                .seed(123)
                .iterations(1)
                .learningRate(lr)
                .learningRateScoreBasedDecayRate(0.5)
                .optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
                .updater(Updater.ADAM).adamMeanDecay(0.9).adamVarDecay(0.999)
                .list()
                .layer(0, new DenseLayer.Builder().nIn(784).nOut(1000).activation("relu").build())
                .layer(1, new DenseLayer.Builder().nIn(1000).nOut(500).activation("relu").build())
                .layer(2, new DenseLayer.Builder().nIn(500).nOut(250).activation("relu").build())
                .layer(3, new DenseLayer.Builder().nIn(250).nOut(500).activation("relu").build())
                .layer(4, new DenseLayer.Builder().nIn(500).nOut(1000).activation("relu").build())
                .layer(5, new OutputLayer.Builder(LossFunctions.LossFunction.MSE)
                                        .nIn(1000)
                                        .nOut(784)
                                        .activation("relu")
                                        .build())
                .backprop(true).pretrain(false)
                .build();
        ParameterAveragingTrainingMaster trainMaster = new ParameterAveragingTrainingMaster.Builder(batchSize)
                                                            .workerPrefetchNumBatches(0)
                                                            .saveUpdater(true)
                                                            .averagingFrequency(5)
                                                            .batchSizePerWorker(batchSize)
                                                            .build();
        MultiLayerNetwork net = new MultiLayerNetwork(netconf);
        net.init();
        SparkDl4jMultiLayer sparkNetwork = new SparkDl4jMultiLayer(jsc, net, trainMaster);
        sparkNetwork.setListeners(Collections.<IterationListener>singletonList(new ScoreIterationListener(1)));

这里我们做一些简要的说明:我们一共定义了5层的神经网络,并且每一层都是普通的全连接网络。学习率等超参数可以通过入口参数传递进来,损失函数用的是均方误差。后面的ParameterAveragingTrainingMaster以及Spark网络的定义在之前的文章中有过说明,这里就略过了。

 

那么,接下来就是训练的代码:

 

for( int i = 0; i < numEpoch; ++i ){
            sparkNetwork.fit(javaRDDTrain);   //train modek
            System.out.println("----- Epoch " + i + " complete -----");
            MultiLayerNetwork trainnet = sparkNetwork.getNetwork();
			System.out.println("Epoch " + i + " Score: " + sparkNetwork.getScore());
			List<DataSet> listDS = javaRDDTrain.takeSample(false, 50); 
			for( DataSet ds : listDS ){ 
				INDArray testFeature = ds.getFeatureMatrix(); 
				INDArray testRes = trainnet.output(testFeature); 
				System.out.println("Euclidean Distance: " + testRes.distance2(testFeature)); 
			}
			DataSet first = listDS.get(0); 
			INDArray testFeature = first.getFeatureMatrix(); 
			double[] doubleFeature = testFeature.data().asDouble(); 
			INDArray testRes = trainnet.output(testFeature); 
			double[] doubleRes = testRes.data().asDouble(); 
			for( int j = 0; j < doubleFeature.length && j < doubleRes.length; ++j ){ 
				double f = doubleFeature[j]; double t = doubleRes[j]; 
				System.out.print(f + ":" + t + " "); 
			} 
			System.out.println(); 
		}

 

训练过程中我们将在每一轮训练结束后随机抽取一些数据进行预测,并将预测值和原值进行欧氏距离的计算。同时我们也会随机抽取一张图片直接比较每个像素点值的不同。具体可以看下面的两张图:

 

完整的训练过程,Spark任务截图:

随机抽取的数据的比较:

在经过多轮次的训练后,我们将模型保存在HDFS上(具体的代码实现可以参考之前的博客)并且将其拉到本地后,随机预测/重构一些图片来看看效果,具体的,我随机选择了9张图进行重构,如下图:

  

 

 

 

 

最后做下小结。

这里我们用多层感知机来对Mnsit数据集进行压缩,并且也取得不错的压缩效果。和之前利用Deep AutoEncoder进行数据进行压缩的不同在于我们将每一层中RBM替换成了FNN。应当说,从肉眼的角度我们没法分辨两种网络对Mnist数据集压缩的好坏程度,但是从理论上,基于RBM的压缩网络应该会取得更好的效果,在Hinton教授的论文中,也拿两者做了比较,结论也是基于RBM的Deep AutoEncoder效果更好,实际中,两者都会应用到。所以还得还情况而定!

多层感知机(Multilayer Perceptron,MLP)是一种前馈神经网络,它由至少三层节点组成,其中一层是输入层,一层是输出层,其余层都是隐藏层。MLP通过反向传播算法进行训练,可以用于分类和回归问题。MNIST是一个手写数字识别数据集,包含60,000个训练样本和10,000个测试样本,MLP可以用于对MNIST数据集进行分类任务。以下是一个简单的MLP实现MNIST分类的代码示例: ```python import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms # 定义超参数 batch_size = 64 learning_rate = 0.01 num_epochs = 10 # 加载MNIST数据集 train_dataset = datasets.MNIST(root='./data', train=True, transform=transforms.ToTensor(), download=True) test_dataset = datasets.MNIST(root='./data', train=False, transform=transforms.ToTensor()) # 定义数据加载器 train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True) test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False) # 定义MLP模型 class MLP(nn.Module): def __init__(self): super(MLP, self).__init__() self.fc1 = nn.Linear(784, 512) self.fc2 = nn.Linear(512, 256) self.fc3 = nn.Linear(256, 10) self.relu = nn.ReLU() def forward(self, x): x = x.view(-1, 784) x = self.relu(self.fc1(x)) x = self.relu(self.fc2(x)) x = self.fc3(x) return x # 实例化模型和损失函数 model = MLP() criterion = nn.CrossEntropyLoss() # 定义优化器 optimizer = optim.SGD(model.parameters(), lr=learning_rate) # 训练模型 for epoch in range(num_epochs): for i, (images, labels) in enumerate(train_loader): # 前向传播 outputs = model(images) loss = criterion(outputs, labels) # 反向传播和优化 optimizer.zero_grad() loss.backward() optimizer.step() # 每100个batch输出一次训练状态 if (i+1) % 100 == 0: print('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'.format(epoch+1, num_epochs, i+1, len(train_loader), loss.item())) # 测试模型 with torch.no_grad(): correct = 0 total = 0 for images, labels in test_loader: outputs = model(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print('Accuracy of the model on the 10000 test images: {} %'.format(100 * correct / total)) ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wangongxi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值