bugfix> java > 投稿

に基づいてネットを検証しているにもかかわらず、ニューラルネットの何が問題なのか見つけることができないようです。この例、これは私のバックプロップとフォワードプロップがうまく機能していることを示唆しています。ただし、XORでトレーニングした後、入力に関係なく、出力に対して約0.5のネットが返されます。言い換えれば、ネットは、入力と出力の間の相関関係を確認することなく、できる限りエラーを最小限に抑えているようです。逆伝播の単一の反復以来らしい 正常に動作するために、私の本能は、問題が何らかの形で後続の反復にあることを示唆しています。ただし、これを引き起こす明らかな問題はなく、非常に困惑しています。

私は同様の問題が発生した他のスレッドを見てきましたが、ほとんどの場合、エラーはネットを設定する方法に対して非常にニッチであるか、学習率やエポックなどのパラメーターが本当にオフになっているようです。このようなケースを知っている人はいますか?

public class Net
{
int[] sizes;
double LEARNING_RATE;
double[][][] weights;
double[][] bias;
Random rand = new Random();  //53489085
public Net(int[] sizes_, double LEARNING_RATE_)
{
    LEARNING_RATE = LEARNING_RATE_;
    sizes = sizes_;
    int numInputs = sizes[0];
    double range = 1.0 / Math.sqrt(numInputs);
    bias = new double[sizes.length - 1][];
    weights = new double[sizes.length - 1][][];
    for(int w_layer = 0; w_layer < weights.length; w_layer++)
    {
        bias[w_layer] = new double[sizes[w_layer+1]];
        weights[w_layer] = new double[sizes[w_layer+1]][sizes[w_layer]];
        for(int j = 0; j < weights[w_layer].length; j++)
        {
            bias[w_layer][j] = 2*range*rand.nextDouble() - range;
            for(int i = 0; i < weights[w_layer][0].length; i++)
            {
                weights[w_layer][j][i] = 2*range*rand.nextDouble() - range;
            }
        }
    }
}
public double[] evaluate(double[] image_vector)
{
    return forwardPass(image_vector)[sizes.length-1];
}
public double totalError(double[][] expec, double[][] actual)
{
    double sum = 0;
    for(int i = 0; i < expec.length; i++)
    {
        sum += error(expec[i], evaluate(actual[i]));
    }
    return sum / expec.length;
}
private double error(double[] expec, double[] actual)
{
    double sum = 0;
    for(int i = 0; i < expec.length; i++)
    {
        double del = expec[i] - actual[i];
        sum += 0.5 * del * del;
    }
    return sum;
}
public void backpropagate(double[][] image_vector, double[][] outputs)
{
    double[][][] deltaWeights = new double[weights.length][][];
    double[][] deltaBias = new double[weights.length][];
    for(int w = 0; w < weights.length; w++)
    {
        deltaBias[w] = new double[bias[w].length];
        deltaWeights[w] = new double[weights[w].length][];
        for(int j = 0; j < weights[w].length; j++)
        {
            deltaWeights[w][j] = new double[weights[w][j].length];
        }
    }
    for(int batch = 0; batch < image_vector.length; batch++)
    {
        double[][] neuronVals = forwardPass(image_vector[batch]);
        /* OUTPUT DELTAS */
        int w_layer = weights.length-1;
        double[] deltas = new double[weights[w_layer].length];
        for(int j = 0; j < weights[w_layer].length; j++)
        {
            double actual = neuronVals[w_layer + 1][j]; 
            double expec = outputs[batch][j];
            double deltaErr = actual - expec;
            double deltaSig = actual * (1 - actual);
            double delta = deltaErr * deltaSig;
            deltas[j] = delta;
            deltaBias[w_layer][j] += delta;
            for(int i = 0; i < weights[w_layer][0].length; i++)
            {
                deltaWeights[w_layer][j][i] += delta * neuronVals[w_layer][i];
            }
        }
        w_layer--;
        /* REST OF THE DELTAS */
        while(w_layer >= 0)
        {   
            double[] nextDeltas = new double[weights[w_layer].length];
            for(int j = 0; j < weights[w_layer].length; j++)
            {
                double outNeur = neuronVals[w_layer+1][j];
                double deltaSig = outNeur * (1 - outNeur);
                double sum = 0;
                for(int i = 0; i < weights[w_layer+1].length; i++)
                {
                    sum += weights[w_layer+1][i][j] * deltas[i];
                }
                double delta = sum * deltaSig;
                nextDeltas[j] = delta;
                deltaBias[w_layer][j] += delta;
                for(int i = 0; i < weights[w_layer][0].length; i++)
                {
                    deltaWeights[w_layer][j][i] += delta * neuronVals[w_layer][i];
                }
            }
            deltas = nextDeltas;
            w_layer--;
        }
    }
    for(int w_layer = 0; w_layer < weights.length; w_layer++)
    {
        for(int j = 0; j < weights[w_layer].length; j++)
        {
            deltaBias[w_layer][j] /= (double) image_vector.length;
            bias[w_layer][j] -= LEARNING_RATE * deltaBias[w_layer][j];
            for(int i = 0; i < weights[w_layer][j].length; i++)
            {   
                deltaWeights[w_layer][j][i] /= (double) image_vector.length; // average of batches
                weights[w_layer][j][i] -= LEARNING_RATE * deltaWeights[w_layer][j][i];
            }
        }
    }
}
public double[][] forwardPass(double[] image_vector)
{
    double[][] outputs = new double[sizes.length][];
    double[] inputs = image_vector;
    for(int w = 0; w < weights.length; w++)
    {
        outputs[w] = inputs;
        double[] output = new double[weights[w].length];
        for(int j = 0; j < weights[w].length; j++)
        {
            output[j] = bias[w][j];
            for(int i = 0; i < weights[w][j].length; i++)
            {
                output[j] += weights[w][j][i] * inputs[i];
            }
            output[j] = sigmoid(output[j]);
        }
        inputs = output;
    }
    outputs[outputs.length-1] = inputs.clone();
    return outputs;
}
static public double sigmoid(double val)
{
    return 1.0 / (1.0 + Math.exp(-val));
}
}

そして、私のXORクラスは次のようになります。この部分にエラーが存在する可能性は非常に低いですが、単純さを考えると、XORがどのように機能するかについて根本的な誤解がある場合に投稿するのは無理だと考えました。私のネットはバッチで例をとるように設定されていますが、この特定の例については以下でわかるように、1つのバッチを送信するか、事実上バッチを使用しません。

public class SingleLayer {
static int numEpochs = 10000;
static double LEARNING_RATE = 0.001;
static int[] sizes = new int[] {2, 2, 1};
public static void main(String[] args)
{
    System.out.println("Initializing randomly generate neural net...");
    Net n = new Net(sizes, LEARNING_RATE);
    System.out.println("Complete!");
    System.out.println("Loading dataset...");
    double[][] inputs = new double[4][2];
    double[][] outputs = new double[4][1];
    inputs[0] = new double[] {1, 1};
    outputs[0] = new double[] {0};
    inputs[1] = new double[] {1, 0};
    outputs[1] = new double[] {1};
    inputs[2] = new double[] {0, 1};
    outputs[2] = new double[] {1};
    inputs[3] = new double[] {0, 0};
    outputs[3] = new double[] {0};
    System.out.println("Complete!");
    System.out.println("STARTING ERROR: " + n.totalError(outputs, inputs));
    for(int epoch = 0; epoch < numEpochs; epoch++)
    {
        double[][] in = new double[1][2];
        double[][] out = new double[1][1];
        int num = (int)(Math.random()*inputs.length);
        in[0] = inputs[num];
        out[0] = outputs[num];
        n.backpropagate(inputs, outputs);
        System.out.println("ERROR: " + n.totalError(out, in));
    }
    System.out.println("Prediction After Training: " + n.evaluate(inputs[0])[0] + "  Expected: " + outputs[0][0]);
    System.out.println("Prediction After Training: " + n.evaluate(inputs[1])[0] + "  Expected: " + outputs[1][0]);
    System.out.println("Prediction After Training: " + n.evaluate(inputs[2])[0] + "  Expected: " + outputs[2][0]);
    System.out.println("Prediction After Training: " + n.evaluate(inputs[3])[0] + "  Expected: " + outputs[3][0]);
}
}

誰が何が間違っているのかについての洞察を提供できますか?私のパラメーターはかなり明確に定義されており、重みをどのように初期化するべきか、学習率はどうあるべきかなど、すべての提案に従いました。ありがとう!

回答 2 件
  • 次の行が間違っているため、最初の3つの入力のみをニューラルネットワークに提示しています。

    int num = (int)(Math.random() * 3);
    
    

    それを変更する

    int num = (int)(Math.random() * inputs.length);
    
    

    4つの可能な入力すべてを使用します。

  • 私はそれを考え出した。十分なエポックを実行していませんでした。それは私には少しばかげているように思えますが、この視覚化は、ネットの回答が0.5長いです エラーを0.00001未満に減らすまでの時間。

あなたの答え