Java pisanie pojedynczego neuronu

0

Witam
Napisałem działający neuron problem jest taki że nie do końca jestem pewny o poprawność wzorów.
Niby działa ale nie jestem przekonany do : "NeuronTools.derivative(get_output(inputs))", to wygląda jakbym przepuścił funkcje dwa razy, próbowałem zmieniać i przestaję działać, więc nie wiem o co za bardzo chodzi. Tam gdzie liczę pochodną funkcji powinienem podać sumę neuronu, a podaje odpowiedź neuronu przepuszczaną przez funkcje sigmoidalną która następnie jest znowu zmieniana na funkcje sigmoidalną.

class Perceptron {
    private Random random;
    private double RATE_LERANING;
    private double weights[];
    private double bias;


    public Perceptron(int counts_inputs, double RATE_LERANING) {
        random = new Random();
        this.RATE_LERANING = RATE_LERANING;
        weights = new double[counts_inputs];

        for(int i = 0; i < counts_inputs; i++) {
            weights[i] = random.nextDouble();
        }
        bias = random.nextDouble();
    }

    public double get_output(double... inputs) {
        double e = 0;
        for(int i = 0; i < inputs.length; i++) {
            e += weights[i] * inputs[i];
        }
        e += bias;
        return NeuronTools.sigmoid(e);
    }

    public void train(double yTheata, double... inputs) {
        double error = yTheata - get_output(inputs);
        for(int i = 0; i < weights.length; i++) {
            weights[i] += RATE_LERANING * error * NeuronTools.derivative(get_output(inputs)) * inputs[i];
        }
        bias += RATE_LERANING * error * NeuronTools.derivative(get_output(inputs)) * 1;
    }

    public double[] getWeights() {return weights;}
}


class NeuronTools {
    public static double sigmoid(double x) {
        return 1d / (1 + Math.exp(-x));
    }
    public static double derivative(double x) {
        return (Math.exp(-x))/(Math.pow(1+Math.exp(-x),2));
    }
}
0

Tak "na oko" jest ok pod względem merytorycznym, ale funkcji sigmoidalnych masz od groma, więc ciężko powiedzieć, w każdym razie jak wklepałem to co masz w google, to wyszedł sigmoid o zakresie wartości (0, 1).

Problem leży w tym, że będzie to działało bardzo wolno w porównaniu do jakiegoś matlaba, czy innego tensorflow i zajmie sporo więcej pamięci. Jeżeli chcesz to koniecznie robić w Javie, to wciąż masz biblioteki do obliczeń na macierzach, do tego, to co widzę na szybko:
LEARNING_RATE powinno być zmienne, żeby szybko osiągnąć pierwsze przybliżenia, a po kilku epokach treningu zmniejszasz wartość, żeby minimalizować koszt.
Zamiast sigmoida możesz użyć ReLU w postaci max(x, 0); Jest różniczkowalny w prawie całym zakresie (wyłączając x=0) a takie x>0?1:0 działa duuuuużo szybciej niż logarytmy. Nadal nie przeskoczysz wykorzystania GPU, więc szybko nie będzie.
new Random() - możesz mieć jeden obiekt na poziomie grafu i przekazywać go przez konstruktor do neuronów, albo zwyczajnie zrobić sobie jakiegoś wizytatora, czy inną fabrykę neuronów - tych może być potencjalnie dużo.

Jeżeli chcesz się uczyć Java, to proponuję inne zagadnienia. Jeżeli chcesz się uczyć ML, NN itd. to polecam następujące kursy:
Prowadzony przez Andrew Ng. Od podstaw (trochę powyżej tabliczki mnożenia) kurs przechodzący przez podstawowe techniki ML, wszystko od strony bebechów, sporo matematyki, ale pozwala to naprawdę nieźle ogarnąć podstawy i rozumieć co się robi.
https://www.coursera.org/learn/machine-learning

Nie jestem pewien na ile zmieniła się struktura kursu TensorFlow na Udacity, prowadzonego przez ludzi z Google, kiedyś w materiałach występował inny człowiek, więc polecam z pewną dozą niepewności, czy to aby to samo co kilka lat temu:
https://www.udacity.com/course/intro-to-tensorflow-for-deep-learning--ud187

1

Taka uwaga bez wgłębiania się czy to w ogóle jest zgodne ze wzorami - widać gołym okiem, że masz przynajmniej dwa błędy techniczne.

Zamień:

    public void train(double yTheata, double... inputs) {
        double error = yTheata - get_output(inputs);
        for(int i = 0; i < weights.length; i++) {
            weights[i] += RATE_LERANING * error * NeuronTools.derivative(get_output(inputs)) * inputs[i];
        }
        bias += RATE_LERANING * error * NeuronTools.derivative(get_output(inputs)) * 1;
    }

Na:


    public void train(double yTheata, double... inputs) {
        double output = get_output(inputs);
        double error = yTheata - output;
        double derivative = NeuronTools.derivative(output);
        for(int i = 0; i < weights.length; i++) {
            weights[i] += RATE_LERANING * error * derivative * inputs[i];
        }
        bias += RATE_LERANING * error * derivative * 1;
    }

Czy to jest poprawne? Nie wiem. Usunąłem tylko wadliwe sprzężenia.

1 użytkowników online, w tym zalogowanych: 0, gości: 1