0
本文作者: AI研習(xí)社 | 2017-05-19 16:58 |
雷鋒網(wǎng)按:本文作者 wangongxi,原文載于作者個人博客,雷鋒網(wǎng)已獲授權(quán)。
在之前的博客中已經(jīng)用單機(jī)、Spark分布式兩種訓(xùn)練的方式對深度神經(jīng)網(wǎng)絡(luò)進(jìn)行訓(xùn)練,但其實DeepLearning4j也是支持多GPU訓(xùn)練的。
這篇文章我就總結(jié)下用GPU來對DNN/CNN進(jìn)行訓(xùn)練和評估過程。并且我會給出CPU、GPU和多卡GPU之前的性能比較圖表。不過,由于重點在于說明Mnist數(shù)據(jù)集在GPU上訓(xùn)練的過程,所以對于一些環(huán)境的部署,比如Java環(huán)境和CUDA的安裝就不再詳細(xì)說明了。
軟件環(huán)境的部署主要在于兩個方面,一個是JDK的安裝,另外一個是CUDA。目前最新版本的DeepLearning4j以及Nd4j支持CUDA-8.0,JDK的話1.7以上。
環(huán)境部署完后,分別用java -version和nvidia-smi來確認(rèn)環(huán)境是否部署正確,如果出現(xiàn)類似以下的信息,則說明環(huán)境部署正確,否則需要重新安裝。
從系統(tǒng)返回的信息可以看到,jdk是openJDK1.7,GPU是2張P40的卡。
由于我這里用了DeepLearning4j最新的版本--v0.8,所以和之前博客的pom文件有些修改,具體如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>DeepLearning</groupId>
<artifactId>DeepLearning</artifactId>
<version>2.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<nd4j.version>0.8.0</nd4j.version>
<dl4j.version>0.8.0</dl4j.version>
<datavec.version>0.8.0</datavec.version>
<scala.binary.version>2.11</scala.binary.version>
</properties>
<dependencies>
<dependency>
<groupId>org.nd4j</groupId>
<artifactId>nd4j-native</artifactId>
<version>${nd4j.version}</version>
</dependency>
<dependency>
<groupId>org.deeplearning4j</groupId>
<artifactId>deeplearning4j-core</artifactId>
<version>${dl4j.version}</version>
</dependency>
<dependency>
<groupId>org.nd4j</groupId>
<artifactId>nd4j-cuda-8.0</artifactId>
<version>${nd4j.version}</version>
</dependency>
<dependency>
<groupId>org.deeplearning4j</groupId>
<artifactId>deeplearning4j-parallel-wrapper_${scala.binary.version}</artifactId>
<version>${dl4j.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<archive>
<manifest>
<mainClass>cn.live.wangongxi.cv.CNNMnist</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
創(chuàng)建完Maven工程以及添加了上面POM文件的內(nèi)容之后,就可以開始著手上層應(yīng)用邏輯的構(gòu)建。這里我參考了官網(wǎng)的例子,具體由以下幾個部分構(gòu)成:
● 初始化CUDA的環(huán)境(底層邏輯包括硬件檢測、CUDA版本校驗和一些GPU參數(shù))
● 讀取Mnist二進(jìn)制文件(和之前的博客內(nèi)容一致)
● CNN的定義,這里我還是用的LeNet
● 訓(xùn)練以及評估模型的指標(biāo)
首先貼一下第一部分的代碼:
//精度設(shè)置,常用精度有單、雙、半精度
//HALF : 半精度
DataTypeUtil.setDTypeForContext(DataBuffer.Type.HALF);
//FLOAT : 單精度
//DataTypeUtil.setDTypeForContext(DataBuffer.Type.FLOAT);
//DOUBLE : 雙精度
//DataTypeUtil.setDTypeForContext(DataBuffer.Type.DOUBLE);
//創(chuàng)建CUDA上下文實例并設(shè)置參數(shù)
CudaEnvironment.getInstance().getConfiguration()
//是否允許多GPU
.allowMultiGPU(false)
//設(shè)置顯存中緩存數(shù)據(jù)的容量,單位:字節(jié)
.setMaximumDeviceCache(2L * 1024L * 1024L * 1024L)
//是否允許多GPU間點對點(P2P)的內(nèi)存訪問
.allowCrossDeviceAccess(false);
通常我們需要根據(jù)需要來設(shè)置GPU計算的精度,常用的就像代碼中寫的那樣有單、雙、半精度三種。通過選擇DataBuffer中定義的enum類型Type中的值來達(dá)到設(shè)置精度的目的。如果不設(shè)置,默認(rèn)的是單精度。
再下面就是設(shè)置CUDA的一些上下文參數(shù),比如代碼中羅列的cache數(shù)據(jù)的顯存大小,P2P訪問內(nèi)存和多GPU運(yùn)行的標(biāo)志位等等。對于網(wǎng)絡(luò)結(jié)構(gòu)相對簡單,數(shù)據(jù)量不大的情況下,默認(rèn)的參數(shù)就夠用了。這里我們也只是簡單設(shè)置了幾個參數(shù),這對于用LeNet來訓(xùn)練Mnist數(shù)據(jù)集來說已經(jīng)足夠了。
從2~4部分的邏輯和之前的博客里幾乎是一樣的,就直接上代碼了:
int nChannels = 1;
int outputNum = 10;
int batchSize = 128;
int nEpochs = 10;
int iterations = 1;
int seed = 123;
log.info("Load data....");
DataSetIterator mnistTrain = new MnistDataSetIterator(batchSize,true,12345);
DataSetIterator mnistTest = new MnistDataSetIterator(batchSize,false,12345);
log.info("Build model....");
MultiLayerConfiguration conf = new NeuralNetConfiguration.Builder()
.seed(seed)
.iterations(iterations)
.regularization(true).l2(0.0005)
.learningRate(.01)
.weightInit(WeightInit.XAVIER)
.optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
.updater(Updater.NESTEROVS).momentum(0.9)
.list()
.layer(0, new ConvolutionLayer.Builder(5, 5)
.nIn(nChannels)
.stride(1, 1)
.nOut(20)
.activation(Activation.IDENTITY)
.build())
.layer(1, new SubsamplingLayer.Builder(SubsamplingLayer.PoolingType.MAX)
.kernelSize(2,2)
.stride(2,2)
.build())
.layer(2, new ConvolutionLayer.Builder(5, 5)
.stride(1, 1)
.nOut(50)
.activation(Activation.IDENTITY)
.build())
.layer(3, new SubsamplingLayer.Builder(SubsamplingLayer.PoolingType.MAX)
.kernelSize(2,2)
.stride(2,2)
.build())
.layer(4, new DenseLayer.Builder().activation(Activation.RELU)
.nOut(500).build())
.layer(5, new OutputLayer.Builder(LossFunctions.LossFunction.NEGATIVELOGLIKELIHOOD)
.nOut(outputNum)
.activation(Activation.SOFTMAX)
.build())
.setInputType(InputType.convolutionalFlat(28,28,1))
.backprop(true).pretrain(false).build();
MultiLayerNetwork model = new MultiLayerNetwork(conf);
model.init();
log.info("Train model....");
model.setListeners(new ScoreIterationListener(100));
long timeX = System.currentTimeMillis();
for( int i=0; i<nEpochs; i++ ) {
long time1 = System.currentTimeMillis();
model.fit(mnistTrain);
long time2 = System.currentTimeMillis();
log.info("*** Completed epoch {}, time: {} ***", i, (time2 - time1));
}
long timeY = System.currentTimeMillis();
log.info("*** Training complete, time: {} ***", (timeY - timeX));
log.info("Evaluate model....");
Evaluation eval = new Evaluation(outputNum);
while(mnistTest.hasNext()){
DataSet ds = mnistTest.next();
INDArray output = model.output(ds.getFeatureMatrix(), false);
eval.eval(ds.getLabels(), output);
}
log.info(eval.stats());
log.info("****************Example finished********************");
以上邏輯就是利用一塊GPU卡進(jìn)行Mnist數(shù)據(jù)集進(jìn)行訓(xùn)練和評估的邏輯。如果想在多GPU下進(jìn)行并行訓(xùn)練的話,需要修改一些設(shè)置,例如在之前第一步的創(chuàng)建CUDA環(huán)境上下文的時候,需要允許多GPU和P2P內(nèi)存訪問,即設(shè)置為true。然后在邏輯里添加并行訓(xùn)練的邏輯:
ParallelWrapper wrapper = new ParallelWrapper.Builder(model)
.prefetchBuffer(24)
.workers(4)
.averagingFrequency(3)
.reportScoreAfterAveraging(true)
.useLegacyAveraging(true)
.build();
這樣如果有多張GPU卡就可以進(jìn)行單機(jī)多卡的并行訓(xùn)練。
下面貼一下訓(xùn)練Mnist數(shù)據(jù)集在CPU/GPU/多GPU下的性能比較還有訓(xùn)練時候的GPU使用情況:
最后做下簡單的總結(jié)。由于Deeplearning4j本身支持GPU單卡,多卡以及集群的訓(xùn)練方式,而且對于底層的接口都已經(jīng)進(jìn)行了很多的封裝,暴露的接口都是比較hig-level的接口,一般設(shè)置一些屬性就可以了。當(dāng)然前提是硬件包括CUDA都要正確安裝。
雷鋒網(wǎng)相關(guān)閱讀:
玩深度學(xué)習(xí)選哪塊英偉達(dá) GPU?有性價比排名還不夠!
谷歌說TPU比GPU更牛,Nvidia表示不服,并朝谷歌扔了一塊Tesla V100
NLP實戰(zhàn)特訓(xùn)班:阿里IDST9大專家?guī)闳腴T
iDST 九大工程師首次在線授課,帶你快速入門NLP技術(shù)
課程鏈接:http://www.mooc.ai/course/83
加入AI慕課學(xué)院人工智能學(xué)習(xí)交流QQ群:624413030,與AI同行一起交流成長
雷峰網(wǎng)版權(quán)文章,未經(jīng)授權(quán)禁止轉(zhuǎn)載。詳情見轉(zhuǎn)載須知。