对于我的大学项目,我需要在普通的java中实现一个deeplearning神经网络。在分析应用程序之后,我想看看使用java的流api的自动并行化是否会导致性能的显着提高,但我正在努力将我的旧代码转换为基于流的方法。
该方法采用向量(双数组),执行矩阵乘法,然后为每个元素添加一个值,最后将lambda函数(DoubleFunction)应用于每个元素。
以下是我要替换的旧代码:
/* e.g.
double[] x = double[100]
int inputNeurons = 100
int outputNeurons = 200
double[][] weights = double[200][100]
double[] biases = double[200]
*/
private double[] output(double[] x) {
double[] y = new double[outputNeurons];
for (int i = 0; i < outputNeurons; i++) {
double preActivation = 0.;
for (int j = 0; j < inputNeurons; j++) {
preActivation += weights[i][j] * x[j];
}
preActivation += biases[i];
y[i] = activation.apply(preActivation);
}
}
这是我到目前为止提出的(它不起作用):
private double[] output(double[] x) {
return Arrays.stream(weights).parallel()
.map(outputNeuron -> IntStream.range(0, outputNeurons)
.mapToDouble(i -> IntStream.range(0, inputNeurons)
.mapToDouble(j -> x[i] * outputNeuron[i]).sum()
).map(activation::apply)
).toArray();
由于我不太了解溪流,我真的很感激任何帮助!
答案 0 :(得分:2)
很好的尝试,但你的流方法完全不是必须的。与你的命令式方法完全相同的是:
return IntStream.range(0, outputNeurons)
//.parallel() uncomment to see difference in performance
.mapToDouble(i -> IntStream.range(0, inputNeurons)
.mapToDouble(j -> weights[i][j] * x[j]).sum() + biases[i])
.map(activation::apply)
.toArray();
请注意,有许多因素会影响并行流是否会使您的代码比命令式方法或顺序流更快或更慢。因此,在进行并行之前,您需要考虑一些因素。
每个元素的成本(意味着并行执行的时间以及分解和合并的开销)
源数据结构
您还应该考虑阅读Should I always use a parallel stream when possible?