对于我的一个大学项目,我需要在纯Java中实现深度学习神经网络。对应用程序进行性能分析后,我想查看使用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();


由于我不知道流够好,因此,我将不胜感激!

最佳答案

很好的尝试,但是您的流式处理方法势在必行。与命令式方法完全相同的是:

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?

10-08 08:52