Нейронная сеть XOR сходится к 0,5 - PullRequest
0 голосов
/ 25 мая 2018

Я не могу найти, что не так с моей нейронной сетью, несмотря на проверку моей сети на основе этого примера , который предполагает, что мой backprop и forward prop работает нормально.Однако после обучения по 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.Моя сеть настроена на то, чтобы брать примеры в пакетах, но, как вы можете видеть ниже для этого конкретного примера, я отправляю его партиями по одному, или фактически не использую пакеты.что может быть не так?Мои параметры довольно хорошо определены, и я следовал всем советам о том, как следует инициализировать веса, какова должна быть скорость обучения и т. Д. Спасибо!

Ответы [ 2 ]

0 голосов
/ 29 мая 2018

Я понял это.У меня не было достаточно эпох.Это кажется мне немного глупым, но эта визуализация открыла мне, что сеть задерживается на ответах ~ 0,5 в течение длинного времени, прежде чем уменьшить ошибку до менее 0,00001.

0 голосов
/ 25 мая 2018

Вы только представляете первые 3 входа в свою нейронную сеть, потому что следующая строка неверна:

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

измените это значение на

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

, чтобы использовать все 4 возможныхвходы.

...