网站首页 > 技术文章 正文
雷锋网按:本文作者 wangongxi,原文载于作者个人博客,雷锋网已获授权。
在之前的博客中已经用单机、Spark分布式两种训练的方式对深度神经网络进行训练,但其实DeepLearning4j也是支持多GPU训练的。
这篇文章我就总结下用GPU来对DNN/CNN进行训练和评估过程。并且我会给出CPU、GPU和多卡GPU之前的性能比较图表。不过,由于重点在于说明Mnist数据集在GPU上训练的过程,所以对于一些环境的部署,比如Java环境和CUDA的安装就不再详细说明了。
软件环境的部署主要在于两个方面,一个是JDK的安装,另外一个是CUDA。目前最新版本的DeepLearning4j以及Nd4j支持CUDA-8.0,JDK的话1.7以上。
环境部署完后,分别用java -version和nvidia-smi来确认环境是否部署正确,如果出现类似以下的信息,则说明环境部署正确,否则需要重新安装。
GPU配置:
Java环境截图:
从系统返回的信息可以看到,jdk是openJDK1.7,GPU是2张P40的卡。
下面说明下代码的构成:
由于我这里用了DeepLearning4j最新的版本--v0.8,所以和之前博客的pom文件有些修改,具体如下:
创建完Maven工程以及添加了上面POM文件的内容之后,就可以开始着手上层应用逻辑的构建。这里我参考了官网的例子,具体由以下几个部分构成:
● 初始化CUDA的环境(底层逻辑包括硬件检测、CUDA版本校验和一些GPU参数)
● 读取Mnist二进制文件(和之前的博客内容一致)
● CNN的定义,这里我还是用的LeNet
● 训练以及评估模型的指标
首先贴一下第一部分的代码:
//精度设置,常用精度有单、双、半精度
//HALF : 半精度
DataTypeUtil.setDTypeForContext(DataBuffer.Type.HALF);
//FLOAT : 单精度
//DataTypeUtil.setDTypeForContext(DataBuffer.Type.FLOAT);
//DOUBLE : 双精度
//DataTypeUtil.setDTypeForContext(DataBuffer.Type.DOUBLE);
//创建CUDA上下文实例并设置参数
CudaEnvironment.getInstance.getConfiguration
//是否允许多GPU
.allowMultiGPU(false)
//设置显存中缓存数据的容量,单位:字节
.setMaximumDeviceCache(2L * 1024L * 1024L * 1024L)
//是否允许多GPU间点对点(P2P)的内存访问
.allowCrossDeviceAccess(false);
通常我们需要根据需要来设置GPU计算的精度,常用的就像代码中写的那样有单、双、半精度三种。通过选择DataBuffer中定义的enum类型Type中的值来达到设置精度的目的。如果不设置,默认的是单精度。
再下面就是设置CUDA的一些上下文参数,比如代码中罗列的cache数据的显存大小,P2P访问内存和多GPU运行的标志位等等。对于网络结构相对简单,数据量不大的情况下,默认的参数就够用了。这里我们也只是简单设置了几个参数,这对于用LeNet来训练Mnist数据集来说已经足够了。
从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
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卡进行Mnist数据集进行训练和评估的逻辑。如果想在多GPU下进行并行训练的话,需要修改一些设置,例如在之前第一步的创建CUDA环境上下文的时候,需要允许多GPU和P2P内存访问,即设置为true。然后在逻辑里添加并行训练的逻辑:
ParallelWrapper wrapper = new ParallelWrapper.Builder(model)
.prefetchBuffer(24)
.workers(4)
.averagingFrequency(3)
.reportScoreAfterAveraging(true)
.useLegacyAveraging(true)
.build;
这样如果有多张GPU卡就可以进行单机多卡的并行训练。
下面贴一下训练Mnist数据集在CPU/GPU/多GPU下的性能比较还有训练时候的GPU使用情况:
单卡训练截图:
双卡并行训练截图:
训练时间评估:
最后做下简单的总结。由于Deeplearning4j本身支持GPU单卡,多卡以及集群的训练方式,而且对于底层的接口都已经进行了很多的封装,暴露的接口都是比较hig-level的接口,一般设置一些属性就可以了。当然前提是硬件包括CUDA都要正确安装。
雷锋网相关阅读:
玩深度学习选哪块英伟达 GPU?有性价比排名还不够!
谷歌说TPU比GPU更牛,Nvidia表示不服,并朝谷歌扔了一块Tesla V100
猜你喜欢
- 2024-10-29 你还在用 Date?快使用 LocalDateTime 了!
- 2024-10-29 Java修炼终极指南:79,80,81 签到终极修炼天赋
- 2024-10-29 硬核!最全的延迟任务实现方式汇总!附代码(强烈推荐)
- 2024-10-29 还在实体类中用Date?JDK8新的日期类型不香么?
- 2024-10-29 LocalDateTime 说:2020,是时候换个更好的日期时间类了
- 2024-10-29 程序员,你还在使用Date嘛?建议你使用LocalDateTime哦
- 2024-10-29 深度思考:在JDK8中,日期类型该如何使用?
- 2024-10-29 为什么建议使用你 LocalDateTime,而不是 Date?
- 2024-10-29 百度开源的分布式唯一ID生成器UidGenerator,解决了时钟回拨问题
- 2024-10-29 老大,你为什么在代码中要求我们使用LocalDateTime而不是Date?
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)