java移位运算 cpu gpu_ND4J求多元线性回归以及GPU和CPU计算性能对比

上一篇博客《梯度下降法求多元线性回归及Java实现》简单了介绍了梯度下降法,并用Java实现了一个梯度下降法求回归的例子。本篇博客,尝试用dl4j的张量运算库nd4j来实现梯度下降法求多元线性回归,并比较GPU和CPU计算的性能差异。

一、ND4J简介

ND4J是DL4J提供的张量运算库,提供了多种张量运算的封装,以下内容复杂于ND4J官网:

ND4J和ND4S是JVM的科学计算库,并为生产环境设计,亦即例程运行速度快,RAM要求低。

主要特点:

多用途多维数组对象

多平台功能,包括GPU

线性代数和信号处理功能

由于易用性上存在的缺口,Java、Scala和Clojure编程人员无法充分利用NumPy或Matlab等数据分析方面最强大的工具。Breeze等其他库则不支持多维数组或张量,而这却是深度学习和其他任务的关键。ND4J和ND4S正得到国家级实验室的使用,以完成气候建模等任务。这类任务要求完成计算密集的模拟运算。

ND4J在开源、分布式、支持GPU的库内,为JVM带来了符合直觉的、Python编程人员所用的科学计算工具。在结构上,ND4J与SLF4J相似。ND4J让生产环境下的工程师能够轻松将算法和界面移植到Java和Scala体系内的其他库内。

更详细的特性,可以去nd4j官网了解,地址:https://nd4j.org/cn

二、具体实现

1、maven配置

首先建一个maven工程,pom.xml完整配置如下:

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

org.dl4j

linear-regression

0.0.1-SNAPSHOT

jar

linear-regression

http://maven.apache.org

UTF-8

1.1.7

1.0.0-beta

nd4j-native-platform

org.nd4j

${nd4j.backend}

${nd4j.version}

ch.qos.logback

logback-classic

${logback.version}

junit

junit

3.8.1

test

说明:nd4j-native-platform 计算后台为CPU

也可以换为Cuda GPU计算,1.0.0 beta版支持cuda8.0、cuda9.0、cuda9.1,对应的配置可改为nd4j-cuda-8.0-platform, nd4j-cuda-9.0-platform 或者 nd4j-cuda-9.1-platform

2、首先构建训练集,这里我们用的还是如下函数:

代码如下:

int exampleCount = 100;

Random random = new Random();

double[] data = new double[exampleCount * 3];

double[] param = new double[exampleCount * 3];

for (int i = 0; i < exampleCount * 3; i++) {

data[i] = random.nextDouble();

}

for (int i = 0; i < exampleCount * 3; i++) {

param[i] = 3;

param[++i] = 4;

param[++i] = 5;

}

INDArray features = Nd4j.create(data, new int[] { exampleCount, 3 });

INDArray params = Nd4j.create(param, new int[] { exampleCount, 3 });

INDArray label = features.mul(params).sum(1).add(10);

mul:表示两个矩阵对应的维度相乘

sum:指定沿着某一维的方向求和,这里sum(1)表示沿着列的方向求和

add:给张量中的每一个值都加上一个标量,当然也可以是加上张量

3、批量梯度下降(BGD)实现

private static void BGD(INDArray features, INDArray label, double learningRate, double[] parameter) {

INDArray temp=features.getColumn(0).mul(parameter[0]).add(features.getColumn(1).mul(parameter[1]))

.add(features.getColumn(2).mul(parameter[2])).add(parameter[3]).sub(label);

parameter[0]=parameter[0]-2*learningRate*temp.mul(features.getColumn(0)).sum(0).getDouble(0)/features.size(0);

parameter[1]=parameter[1]-2*learningRate*temp.mul(features.getColumn(1)).sum(0).getDouble(0)/features.size(0);

parameter[2]=parameter[2]-2*learningRate*temp.mul(features.getColumn(2)).sum(0).getDouble(0)/features.size(0);

parameter[3]=parameter[3]-2*learningRate*temp.sum(0).getDouble(0)/features.size(0);

INDArray functionResult=features.getColumn(0).mul(parameter[0]).add(features.getColumn(1).mul(parameter[1]))

.add(features.getColumn(2).mul(parameter[2])).add(parameter[3]).sub(label);//用最新的参数计算总损失用

double totalLoss=functionResult.mul(functionResult).sum(0).getDouble(0);

System.out.println("totalLoss:"+totalLoss);

System.out.println(parameter[0] + " " + parameter[1] + " " + parameter[2] + " " + parameter[3]);

}

4、完整代码如下,我们循环3000次,基本找出了参数。

public class LinearRegression {

public static void main(String[] args) {

int exampleCount = 100;

double learningRate = 0.01;

Random random = new Random();

double[] data = new double[exampleCount * 3];

double[] param = new double[exampleCount * 3];

for (int i = 0; i < exampleCount * 3; i++) {

data[i] = random.nextDouble();

}

for (int i = 0; i < exampleCount * 3; i++) {

param[i] = 3;

param[++i] = 4;

param[++i] = 5;

}

INDArray features = Nd4j.create(data, new int[] { exampleCount, 3 });

INDArray params = Nd4j.create(param, new int[] { exampleCount, 3 });

INDArray label = features.mul(params).sum(1).add(10);

double[] parameter = new double[] { 1.0, 1.0, 1.0, 1.0 };

long startTime = System.currentTimeMillis();

for (int i = 0; i < 3000; i++) {

BGD(features, label, learningRate, parameter);

}

System.out.println("耗时:" + (System.currentTimeMillis() - startTime));

}

private static void BGD(INDArray features, INDArray label, double learningRate, double[] parameter) {

INDArray temp = features.getColumn(0).mul(parameter[0]).add(features.getColumn(1).mul(parameter[1]))

.add(features.getColumn(2).mul(parameter[2])).add(parameter[3]).sub(label);

parameter[0] = parameter[0]

- 2 * learningRate * temp.mul(features.getColumn(0)).sum(0).getDouble(0) / features.size(0);

parameter[1] = parameter[1]

- 2 * learningRate * temp.mul(features.getColumn(1)).sum(0).getDouble(0) / features.size(0);

parameter[2] = parameter[2]

- 2 * learningRate * temp.mul(features.getColumn(2)).sum(0).getDouble(0) / features.size(0);

parameter[3] = parameter[3] - 2 * learningRate * temp.sum(0).getDouble(0) / features.size(0);

INDArray functionResult = features.getColumn(0).mul(parameter[0]).add(features.getColumn(1).mul(parameter[1]))

.add(features.getColumn(2).mul(parameter[2])).add(parameter[3]).sub(label);// 用最新的参数计算总损失用

double totalLoss = functionResult.mul(functionResult).sum(0).getDouble(0);

System.out.println("totalLoss:" + totalLoss);

System.out.println(parameter[0] + " " + parameter[1] + " " + parameter[2] + " " + parameter[3]);

}

}

5、运行结果

totalLoss:0.2690272927284241

参数:3.1580112185120623 、4.092539676684143、 5.0879424870036525、 9.820665847778292

三、GPU与CPU运行性能对比

操作系统:window10

CPU:Intel core(TM) i7-5700HQ CPU @2.70GHz

GPU:NVIDIA Geforce GTX 950M

CUDA:Cuda 8.0,V8.0.44

样本数量

CPU耗时

GPU耗时

1000

1314ms

11013ms

10000

3430ms

11608ms

100000

16544ms

17873ms

500000

78713ms

49151ms

1000000

156387ms

83001ms

GPU在矩阵运算加速有优势,在深度学习中,当参数规模和样本规模比较大的时候,选择GPU加速,计算速度会有明显的提升

快乐源于分享。

此博客乃作者原创, 转载请注明出处

你可能感兴趣的:(java移位运算,cpu,gpu)