【专知-Java Deeplearning4j深度学习教程05】无监督特征提取神器—AutoEncoder:图文+代码

【导读】主题链路知识是我们专知的核心功能之一,为用户提供AI领域系统性的知识学习服务,一站式学习人工智能的知识,包含人工智能( 机器学习、自然语言处理、计算机视觉等)、大数据、编程语言、系统架构。使用请访问专知 进行主题搜索查看 - 桌面电脑访问www.zhuanzhi.ai, 手机端访问www.zhuanzhi.ai 或关注微信公众号后台回复" 专知"进入专知,搜索主题查看。继Pytorch教程后,我们推出面向Java程序员的深度学习教程DeepLearning4J。Deeplearning4j的案例和资料很少,官方的doc文件也非常简陋,基本上所有的类和函数的都没有解释。为此,我们推出来自中科院自动化所专知小组博士生Hujun与Sanglei创作的-分布式Java开源深度学习框架Deeplearning4j学习教程,第五篇,无监督特征提取神器—AutoEncoder。

  1. Deeplearning4j开发环境配置
  2. ND4J(DL4J的矩阵运算库)教程
  3. 使用多层神经网络分类MNIST数据集
  4. 使用CNN进行文本分类:图文+代码
  5. 基于DL4J的AutoEncoder、RNN、Word2Vec等模型的实现

特征提取

对很多机器学习/数据挖掘任务来说,选取或设计优质的的特征比设计一个好的分类器显得更为重要,然而优质特征的设计往往需要耗费大量的时间。深度学习包含了许多优质的无监督的特征自动提取算法,可以自动化地从原始特征(例如图像像素向量、文本词频向量等)中提取优质的特征,大大地节约了特征设计的成本,收到工业界的青睐。本文介绍一种无监督学习特征的模型——AutoEncoder,并提供DL4J实现AutoEncoder的代码。

特征提取示例

Iris是一个经典的数据集,数据由150个样本组成,包含3个类别的样本(3种标签),每个样本由4个特征和1个标签组成。例如数据的前几行如下所示,数据的前4列分别表示样本的4个特征,最后一列Iris-setosa是样本的标签,即样本的所属类别,是分类器需要预测的标签。

5.1,3.5,1.4,0.2,Iris-setosa
4.9,3.0,1.4,0.2,Iris-setosa
4.7,3.2,1.3,0.2,Iris-setosa
4.6,3.1,1.5,0.2,Iris-setosa
5.0,3.6,1.4,0.2,Iris-setosa
5.4,3.9,1.7,0.4,Iris-setosa

Iris数据集的下载地址为https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data。可以看出,很难人工设计一个区分这三种花。将Iris数据集可视化之后如下图所示,每个小图表示从某2个维度(一个维度对应一种特征)去观察Iris得到的结果,可以看出该数据集在一些小图中是线性可分的(任选两类样本,可以用一条直线去大致分隔这两类样本)。

但依赖可视化的方法是不可行的,Iris数据集只有4个特征和150个样本,如果换成MNIST数据集,则有784个特征,会产生613872张小图。另外,大部分情况下不是选取2个特征进行线性组合就可以获得优质特征的,而是需要多个特征做复杂的数学运算才可以得到优质的特征,因此,需要其他的方法来解决设计优质特征的问题。

PCA(主成分分析)是一种传统的学习特征的方法。PCA可以将Iris数据集的4个特征变换为2个新的特征,2个新特征的可视化如下图所示,可以看到,学到的特征是线性可分的,可直接用于分类。下面,我们将介绍深度学习中一个简单粗暴的特征学习神器——AutoEncoder。

AutoEncoder

AutoEncoder其实就是一个3层神经网络,由1个输入层、1个隐藏层和1个输出层构成(如下图所示)。AutoEncoder用网络的输入数据作为Label,即希望网络的输出层输出和输入层一样的东西。如果将整个网络看作一个函数,这个函数为hW,b(x)≈x,其中x表示网络的输入(例如对于Iris数据集来说,x是一个4维向量,代表某个样本的4个特征)。AutoEncoder训练成功后,输入一个样本的特征,隐藏层的激活值即为学习到的该样本的新特征。

直观地理解为什么AutoEncoder为什么可以学习到特征,数据从AutoEncoder的输入层到输出层会经过两次变换,第一次将输入数据变换为隐藏层的激活值,第二次将隐藏层的激活值变换为输出层(即还原为输入),如果可以成功地还原输入数据,则说明隐藏层的激活值包含了输入层所有的信息(严格地说,是隐藏层的激活值加上AutoEncoder的网络参数包含了输入层的所有信息,但网络参数是所有样本共享的,因此在网络参数固定的情况下,可以认为隐藏层的激活值等价于其对应的输入数据)。

下面给出Deeplearning4j实现AutoEncoder的代码,有几个需要注意的地方:

  • 除了DL4J所需的基础库,还需要导入JMathPlot的Maven依赖:https://mvnrepository.com/artifact/com.github.yannrichet/JMathPlot
  • 由于AutoEncoder需要还原数据,且输出层的激活值大小有范围(例如tanh的大小范围是(-1,1)),因此在代码中设置了数据的归一化。
import org.deeplearning4j.datasets.iterator.impl.IrisDataSetIterator;
import org.deeplearning4j.nn.api.OptimizationAlgorithm;
import org.deeplearning4j.nn.conf.MultiLayerConfiguration;
import org.deeplearning4j.nn.conf.NeuralNetConfiguration;
import org.deeplearning4j.nn.conf.layers.DenseLayer;
import org.deeplearning4j.nn.conf.layers.OutputLayer;
import org.deeplearning4j.nn.multilayer.MultiLayerNetwork;
import org.deeplearning4j.optimize.listeners.ScoreIterationListener;
import org.math.plot.Plot2DPanel;
import org.nd4j.linalg.activations.Activation;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.dataset.DataSet;
import org.nd4j.linalg.dataset.api.iterator.DataSetIterator;
import org.nd4j.linalg.dataset.api.preprocessor.DataNormalization;
import org.nd4j.linalg.dataset.api.preprocessor.NormalizerMinMaxScaler;
import org.nd4j.linalg.lossfunctions.LossFunctions.LossFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.awt.*;
import java.util.List;


/**
 *
 * 本教程由专知提供:http://www.zhuanzhi.ai/
 *
 * 本教程演示如何用Deeplearning4j构建AutoEncoder
 * 除了DL4J所需的基础库,还需要导入JMathPlot的Maven依赖:
 *   https://mvnrepository.com/artifact/com.github.yannrichet/JMathPlot
 *
 * 本教程用DL4J在Iris数据集上学习AutoEncoder
 * 将Iris数据集的4维的原始特征变换为2维的优质特征
 * 最后用JMathPlot绘制学习到的特征
 *
 * @author hu
 */
public class AutoEncoderExample {

    private static Logger log = LoggerFactory.getLogger(AutoEncoderExample.class);

    public static void main(String[] args) throws Exception {
        int inputDim = 4; // 输入数据维度,即原始特征数量
        final int hiddenDim = 2; //隐藏层维度,即学习到的特征的维度

        int batchSize = 150; // 这里用整个数据集的大小作为batchSize
        int rngSeed = 123; // 随机种子,保证每次运行程序获得同样的结果
        int numEpochs = 1000; // epoch数量,扫描一遍数据集为一个epoch

        //用DL4J自带的Iris数据集
        DataSetIterator irisDataSet = new IrisDataSetIterator(batchSize, 150);
        //将Iris数据集归一化到-1和1之间
        //本示例用tanh激活输出层,所以用-1到1
        DataNormalization norm = new NormalizerMinMaxScaler(-1,1);
        norm.fit(irisDataSet);
        irisDataSet.setPreProcessor(norm);


        log.info("Build model....");
        MultiLayerConfiguration conf = new NeuralNetConfiguration.Builder()
                .seed(rngSeed) //设置随机种子,保证每次运行程序获得同样的结果
                .optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
                .iterations(1)
                .learningRate(3e-2) //学习速率
                .regularization(true).l2(1e-4)
                .list()
                //构建Encoder
                .layer(0, new DenseLayer.Builder()
                        .nIn(inputDim)
                        .nOut(hiddenDim)
                        .activation(Activation.TANH)
                        .build())
                //构建Decoder
                .layer(1, new OutputLayer.Builder(LossFunction.MSE)
                        .nIn(hiddenDim)
                        .nOut(inputDim)
                        .activation(Activation.TANH)
                        .build())
                .pretrain(false).backprop(true)
                .build();

        MultiLayerNetwork model = new MultiLayerNetwork(conf);
        model.init();
        //每50个Iteration就print一次score
        model.setListeners(new ScoreIterationListener(50));

        log.info("Train model....");
        //训练
        for( int i=0; i<numEpochs; i++ ){
            irisDataSet.reset();
            while(irisDataSet.hasNext()){
                INDArray inputs = irisDataSet.next().getFeatures();
                //将网络的输入和Label都设置为样本原始特征
                model.fit(inputs, inputs);
            }
        }

        log.info("Plot learned features....");
        irisDataSet.reset();
        //取一个batch的数据,这里batchSize为数据集大小
        //因此这里会取出所有的数据
        DataSet plotDataSet = irisDataSet.next();
        //获取原始特征
        INDArray inputs = plotDataSet.getFeatures();
        //前向传播到第0层(即隐藏层)
        //返回的是一个数组,数组包含前向传播到指定层所经过的所有层的激活值(包括指定层)
        List<INDArray> activationList = model.feedForwardToLayer(0,inputs,false);
        //取出数组中的最后一层激活值(也就是隐藏层的激活值)
        INDArray features = activationList.get(activationList.size() - 1);
        //取出原始数据的Label,原始数据的Label用one hot格式,因此需要用argMax(1)将其转换为普通数值Label
        INDArray labels = plotDataSet.getLabels().argMax(1);

        //使用JMathPlot绘制特征2D图
        //用2个坐标轴表示学习到的特征的2个维度
        //用颜色表示样本的类别
        Plot2DPanel plot = new Plot2DPanel();
        Color[] colors = new Color[]{Color.red, Color.green, Color.blue};
        for(int i = 0;i<features.shape()[0];i++){
            Color color = colors[labels.getInt(i)];
            double x = features.getDouble(i,0);
            double y = features.getDouble(i,1);
            plot.addScatterPlot("iris", color,new double[]{x},new double[]{y});
        }
        //将JMathPlot嵌套在JFrame里展示
        JFrame frame = new JFrame("a plot panel");
        frame.setBounds(200,200,800,800);
        frame.setContentPane(plot);
        frame.setVisible(true);

    }

}

运行结果:

原文发布于微信公众号 - 专知(Quan_Zhuanzhi)

原文发表时间:2017-10-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大学生计算机视觉学习DeepLearning

深度学习(七)U-Net原理以及keras代码实现医学图像眼球血管分割

原文链接:https://www.cnblogs.com/DOMLX/p/9780786.html

1.3K4
来自专栏大数据挖掘DT机器学习

R分类器性能评价:图形方法

几个基本概念 对于二元分类器,我们可以把分类样本的真实值记为1(positive,正例/阳性),-1(或0,negative,负例/阴性)分类结果记作1(s...

30010
来自专栏人工智能

MLlib中的随机森林和提升方法

本帖是与来自于Origami Logic 的Manish Amd共同撰写的。

27210
来自专栏机器之心

ACL 2018 | 神经语言模型如何利用上下文信息:长距离上下文的词序并不重要

2305
来自专栏专知

100+中文词向量,总有一款适合你

2254
来自专栏AI研习社

决策树:一种像人脑一样工作的算法

决策树是用于机器学习最流行的算法之一,尤其对于分类和回归问题。我们每次做决策时大脑都像决策树一样工作。

1283
来自专栏计算机视觉战队

CVPR—II | 经典网络再现,全内容跟踪

今天首先给大家带来“YOLO”!也被上一篇“Faith”读者说对了,在此也感谢大家的关注与阅读,O(∩_∩)O谢谢 YOLO ? 看到这个封面,相信很多很多...

3565
来自专栏机器学习之旅

应用:多算法识别撞库刷券等异常用户

在运营业务中,绝大多数公司会面临恶意注册,恶意刷接口,恶意刷券等流量问题,此类问题的常规解决方案都是拍定单位时间内的ip访问上限次数、qps上限次数等等,会存在...

1142
来自专栏AI派

如何使用sklearn加载和下载机器学习数据集

sklearn 中提供了很多常用(或高级)的模型和算法,但是真正决定一个模型效果的最后还是取决于训练(喂养)模型时所用的数据。sklearn 中的 sklear...

6745
来自专栏CreateAMind

KITTI数据集简介与使用

摘要:本文融合了Are we ready for Autonomous Driving? The KITTI Vision Benchmark Suite和Vi...

9852

扫码关注云+社区