無監督特徵提取神器—AutoEncoder:圖文+代碼
【導讀】主題鏈路知識是我們專知的核心功能之一,為用戶提供AI領域系統性的知識學習服務,一站式學習人工智慧的知識,包含人工智慧( 機器學習、自然語言處理、計算機視覺等)、大數據、編程語言、系統架構。使用請訪問專知 進行主題搜索查看 - 桌面電腦訪問www.zhuanzhi.ai, 手機端訪問www.zhuanzhi.ai 或關注微信公眾號後台回復" 專知"進入專知,搜索主題查看。繼Pytorch教程後,我們推出面向Java程序員的深度學習教程DeepLearning4J。Deeplearning4j的案例和資料很少,官方的doc文件也非常簡陋,基本上所有的類和函數的都沒有解釋。為此,我們推出來自中科院自動化所專知小組博士生Hujun與Sanglei創作的-分散式Java開源深度學習框架Deeplearning4j學習教程,第五篇,無監督特徵提取神器—AutoEncoder。
特徵提取
對很多機器學習/數據挖掘任務來說,選取或設計優質的的特徵比設計一個好的分類器顯得更為重要,然而優質特徵的設計往往需要耗費大量的時間。深度學習包含了許多優質的無監督的特徵自動提取演算法,可以自動化地從原始特徵(例如圖像像素向量、文本詞頻向量等)中提取優質的特徵,大大地節約了特徵設計的成本,收到工業界的青睞。本文介紹一種無監督學習特徵的模型——AutoEncoder,並提供DL4J實現AutoEncoder的代碼。
特徵提取示例
Iris是一個經典的數據集,數據由150個樣本組成,包含3個類別的樣本(3種標籤),每個樣本由4個特徵和1個標籤組成。例如數據的前幾行如下所示,數據的前4列分別表示樣本的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)),因此在代碼中設置了數據的歸一化。
importorg.deeplearning4j.datasets.iterator.impl.IrisDataSetIterator;
importorg.deeplearning4j.nn.api.OptimizationAlgorithm;
importorg.deeplearning4j.nn.conf.MultiLayerConfiguration;
importorg.deeplearning4j.nn.conf.NeuralNetConfiguration;
importorg.deeplearning4j.nn.conf.layers.DenseLayer;
importorg.deeplearning4j.nn.conf.layers.OutputLayer;
importorg.deeplearning4j.nn.multilayer.MultiLayerNetwork;
importorg.deeplearning4j.optimize.listeners.ScoreIterationListener;
importorg.math.plot.Plot2DPanel;
importorg.nd4j.linalg.activations.Activation;
importorg.nd4j.linalg.api.ndarray.INDArray;
importorg.nd4j.linalg.dataset.DataSet;
importorg.nd4j.linalg.dataset.api.iterator.DataSetIterator;
importorg.nd4j.linalg.dataset.api.preprocessor.DataNormalization;
importorg.nd4j.linalg.dataset.api.preprocessor.NormalizerMinMaxScaler;
importorg.nd4j.linalg.lossfunctions.LossFunctions.LossFunction;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importjavax.swing.*;
importjava.awt.*;
importjava.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繪製學習到的特徵
*
*@authorhu
*/
public classAutoEncoderExample {
private staticLoggerlog= LoggerFactory.getLogger(AutoEncoderExample.class);
public static voidmain(String[] args)throwsException {
intinputDim =4;//輸入數據維度,即原始特徵數量
final inthiddenDim =2;//隱藏層維度,即學習到的特徵的維度
intbatchSize =150;//這裡用整個數據集的大小作為batchSize
intrngSeed =123;//隨機種子,保證每次運行程序獲得同樣的結果
intnumEpochs =1000;// epoch數量,掃描一遍數據集為一個epoch
//用DL4J自帶的Iris數據集
DataSetIterator irisDataSet =newIrisDataSetIterator(batchSize,150);
//將Iris數據集歸一化到-1和1之間
//本示例用tanh激活輸出層,所以用-1到1
DataNormalization norm =newNormalizerMinMaxScaler(-1,1);
norm.fit(irisDataSet);
irisDataSet.setPreProcessor(norm);
log.info("Build model....");
MultiLayerConfiguration conf =newNeuralNetConfiguration.Builder()
.seed(rngSeed)//設置隨機種子,保證每次運行程序獲得同樣的結果
.optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
.iterations(1)
.learningRate(3e-2)//學習速率
.regularization(true).l2(1e-4)
.list()
//構建Encoder
.layer(, newDenseLayer.Builder()
.nIn(inputDim)
.nOut(hiddenDim)
.activation(Activation.TANH)
.build())
//構建Decoder
.layer(1, newOutputLayer.Builder(LossFunction.MSE)
.nIn(hiddenDim)
.nOut(inputDim)
.activation(Activation.TANH)
.build())
.pretrain(false).backprop(true)
.build();
MultiLayerNetwork model =newMultiLayerNetwork(conf);
model.init();
//每50個Iteration就print一次score
model.setListeners(newScoreIterationListener(50));
log.info("Train model....");
//訓練
for(inti=;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();
//前向傳播到第層(即隱藏層)
//返回的是一個數組,數組包含前向傳播到指定層所經過的所有層的激活值(包括指定層)
List activationList = model.feedForwardToLayer(,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 =newPlot2DPanel();
Color[] colors =newColor[];
for(inti =;i
Color color = colors[labels.getInt(i)];
doublex = features.getDouble(i,);
doubley = features.getDouble(i,1);
plot.addScatterPlot("iris",color,new double[],new double[]);
}
//將JMathPlot嵌套在JFrame里展示
JFrame frame =newJFrame("a plot panel");
frame.setBounds(200,200,800,800);
frame.setContentPane(plot);
frame.setVisible(true);
}
}
運行結果:
搜索「DeepLearning4j」,查看獲得代碼。
明天請繼續關注「DeepLearning4j」教程。
完整系列搜索查看,請PC登錄
對DeepLearning4j教程感興趣的同學,歡迎進入我們的專知DeepLearning4j主題群一起交流、學習、討論,掃一掃如下群二維碼即可進入:
如果群滿,請掃描小助手,加入進群~
了解使用專知-獲取更多AI知識!


※專知-PyTorch手把手深度學習教程07
※專知中秋呈獻-PyTorch手把手深度學習教程03
TAG:專知 |