単純なフィードフォワードニューラルネットワークのJavaポートを作成しようとしています。
これには明らかに多くの数値計算が含まれるため、中央ループを可能な限り最適化しようとしています。float
結果は、データ型の制限内で正しいはずです。
私の現在のコードは次のようになります(エラー処理と初期化が削除されました):
/**
* Simple implementation of a feedforward neural network. The network supports
* including a bias neuron with a constant output of 1.0 and weighted synapses
* to hidden and output layers.
*
* @author Martin Wiboe
*/
public class FeedForwardNetwork {
private final int outputNeurons; // No of neurons in output layer
private final int inputNeurons; // No of neurons in input layer
private int largestLayerNeurons; // No of neurons in largest layer
private final int numberLayers; // No of layers
private final int[] neuronCounts; // Neuron count in each layer, 0 is input
// layer.
private final float[][][] fWeights; // Weights between neurons.
// fWeight[fromLayer][fromNeuron][toNeuron]
// is the weight from fromNeuron in
// fromLayer to toNeuron in layer
// fromLayer+1.
private float[][] neuronOutput; // Temporary storage of output from previous layer
public float[] compute(float[] input) {
// Copy input values to input layer output
for (int i = 0; i < inputNeurons; i++) {
neuronOutput[0][i] = input[i];
}
// Loop through layers
for (int layer = 1; layer < numberLayers; layer++) {
// Loop over neurons in the layer and determine weighted input sum
for (int neuron = 0; neuron < neuronCounts[layer]; neuron++) {
// Bias neuron is the last neuron in the previous layer
int biasNeuron = neuronCounts[layer - 1];
// Get weighted input from bias neuron - output is always 1.0
float activation = 1.0F * fWeights[layer - 1][biasNeuron][neuron];
// Get weighted inputs from rest of neurons in previous layer
for (int inputNeuron = 0; inputNeuron < biasNeuron; inputNeuron++) {
activation += neuronOutput[layer-1][inputNeuron] * fWeights[layer - 1][inputNeuron][neuron];
}
// Store neuron output for next round of computation
neuronOutput[layer][neuron] = sigmoid(activation);
}
}
// Return output from network = output from last layer
float[] result = new float[outputNeurons];
for (int i = 0; i < outputNeurons; i++)
result[i] = neuronOutput[numberLayers - 1][i];
return result;
}
private final static float sigmoid(final float input) {
return (float) (1.0F / (1.0F + Math.exp(-1.0F * input)));
}
}
-serverオプションを指定してJVMを実行していますが、現在のところ、私のコードは同様のCコードよりも25%から50%遅くなっています。この状況を改善するために何ができますか?
ありがとうございました、
マーティン・ウィボエ
編集#1:膨大な量の回答を見た後、私はおそらく私たちのシナリオの数字を明確にする必要があります。通常の実行中に、メソッドはさまざまな入力で約50.000回呼び出されます。典型的なネットワークは、numberLayers = 3層で、それぞれ190、2、1ニューロンです。したがって、最も内側のループには約2*191+3=385
反復があります(レイヤー0および1に追加されたバイアスニューロンをカウントする場合)
編集#1:このスレッドでさまざまな提案を実装した後、私たちの実装は実質的にCバージョンと同じくらい高速です(約2%以内)。すべての助けをありがとう!for
すべての提案は役に立ちましたが、正しい答えとしてマークできるのは1つだけなので、配列の最適化を提案することと、ループヘッダーを事前に計算する唯一のことの両方について、@Durandalに渡します。