Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/354.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:微优化数组操作_Java_Performance_Optimization_Neural Network_Micro Optimization - Fatal编程技术网

Java:微优化数组操作

Java:微优化数组操作,java,performance,optimization,neural-network,micro-optimization,Java,Performance,Optimization,Neural Network,Micro Optimization,我正在尝试制作一个简单的前馈神经网络的Java端口。 这显然涉及到大量的数值计算,所以我正在尽可能优化我的中心循环。结果应在float数据类型的限制范围内正确 我的当前代码如下所示(已删除错误处理和初始化): /** *前馈神经网络的简单实现。网络支持 *包括一个恒定输出为1.0的偏置神经元和加权突触 *隐藏和输出图层。 * *@作者Martin Wiboe */ 公共类前馈网络{ private final int outputNeurons;//输出层中的神经元数 私有final int

我正在尝试制作一个简单的前馈神经网络的Java端口。
这显然涉及到大量的数值计算,所以我正在尽可能优化我的中心循环。结果应在
float
数据类型的限制范围内正确

我的当前代码如下所示(已删除错误处理和初始化):

/**
*前馈神经网络的简单实现。网络支持
*包括一个恒定输出为1.0的偏置神经元和加权突触
*隐藏和输出图层。
* 
*@作者Martin Wiboe
*/
公共类前馈网络{
private final int outputNeurons;//输出层中的神经元数
私有final int inputNeurons;//输入层中的神经元数
private int largestLayerNeurons;//最大层中的神经元数量
私有final int numberLayers;//层数
private final int[]neuronCounts;//每层神经元计数,输入0
//层。
私有最终浮点[][]fWeights;//神经元之间的权重。
//fWeight[fromLayer][fromNeuron][toNeuron]
//fromNeuron的重量是多少
//从图层到图层中的toNeuron
//fromLayer+1。
私有浮点[][]输出;//上一层输出的临时存储
公共浮点[]计算(浮点[]输入){
//将输入值复制到输入层输出
对于(int i=0;i
我使用-server选项运行JVM,到目前为止,我的代码比类似的C代码慢25%到50%。我能做些什么来改善这种情况

谢谢,

马丁·维博

编辑#1:在看到大量的回应之后,我可能应该澄清我们场景中的数字。在典型运行期间,将使用不同的输入调用该方法大约50000次。一个典型的网络将有numberLayers=3层,分别有190个、2个和1个神经元。因此,最里面的循环将有大约
2*191+3=385次迭代(当计算第0层和第1层中添加的偏差神经元时)


编辑#1:在这个线程中实现了各种建议之后,我们的实现速度实际上与C版本一样快(在~2%以内)。谢谢你的帮助!所有的建议都很有帮助,但由于我只能将一个答案标记为正确答案,因此我将把它交给@Durandal,以建议数组优化,并作为唯一一个预先计算
for
循环头的人。

我要研究的第一件事是看
Math.exp
是否会让你慢下来。请参阅以获取本机替代方案。

首先,不要这样做:

// Copy input values to input layer output
for (int i = 0; i < inputNeurons; i++) {
    neuronOutput[0][i] = input[i];
}

纯粹基于代码检查,您最内部的循环必须计算对三维参数的引用,并且需要做很多工作。根据您的阵列尺寸,您可能会因为每次循环迭代都必须在内存中跳转而出现缓存问题。也许您可以重新排列维度,以便内部循环尝试访问比现在更接近的内存元素


在任何情况下,在进行任何更改之前,请先评测代码,看看真正的瓶颈在哪里。

我建议使用定点系统,而不是浮点系统。在几乎所有使用int的处理器上都比float快。实现这一点的最简单方法是将所有剩余的数据移位一定量(4或5是良好的起点),并将底部的4位视为十进制


您最内部的循环正在进行浮点运算,因此这可能会给您带来很大的提升。

优化的关键是首先测量所花费的时间。通过调用System.nanoTime()围绕算法的各个部分:

我想使用System.arraycopy()会有所帮助,但您会在内部循环中发现实际成本

根据您所发现的,可以考虑用整数运算替换浮点运算。 一些提示

  • 在最内部的循环中,考虑如何遍历CPU缓存并重新排列矩阵,以便按顺序访问最外部的阵列。这将导致您按顺序访问缓存,而不是到处乱跳。缓存命中可以比缓存未命中快两个数量级。 e、 g重组权重,使其作为
激活+=神经元输出[第1层][输入神经元]*重量[第1层][神经元][输入神经元]

  • 不要在内部执行工作
    // Copy input values to input layer output
    for (int i = 0; i < inputNeurons; i++) {
        neuronOutput[0][i] = input[i];
    }
    
    System.arraycopy( input, 0, neuronOutput[0], 0, inputNeurons );
    
    long start_time = System.nanoTime();
    doStuff();
    long time_taken = System.nanoTime() - start_time;
    
    final int[] neuronOutputSlice = neuronOutput[layer - 1];
    final int[][] fWeightSlice = fWeights[layer - 1];
    for (int inputNeuron = 0; inputNeuron < biasNeuron; inputNeuron++) {
        activation += neuronOutputSlice[inputNeuron] * fWeightsSlice[inputNeuron][neuron];
    }
    
    for (int neuron = 0; neuron < neuronCounts[layer]; neuron++) { ... }
    // transform to precalculated exit condition (move invariant array access outside loop)
    for (int neuron = 0, neuronCount = neuronCounts[layer]; neuron < neuronCount; neuron++) { ... }
    
    float activation = 1.0F * fWeights[layer - 1][biasNeuron][neuron];