Witam serdecznie. Jest to mój twór, który napisałem po obejrzeniu tego http://vimeo.com/19569529 .
Jednak sam nie jestem pewien czy napisałem to dobrze. Wydaje się, że sieć działa, ale nie do końca.
To znaczy, dla przykładu chciałem nauczyć ją potęgować. Uczę ją na wartościach z zakresu 0.1-0.6. W tym zakresie daje sobie rade, ale dla wartości > 0.6 wyniki są bardzo niepoprawne.

class Neuron;
typedef vector<Neuron> Layer;

// **************** class Neuron ****************
struct Connection
{
    double weight;
    double deltaWeight;
};

class Neuron
{
public:
    Neuron(unsigned numConnections, unsigned index);
    void setOutput(double o) { output = o; }
    double getOutput(void) const { return output; }
    void feedForward(const Layer &prevLayer);
    void calcOutputGradients(double x);
    void calcHiddenGradients(const Layer &nextLayer);
    void updateInputWeights(Layer &prevLayer);

private:
    unsigned myIndex;
    vector<Connection> outputWeights;
    double output;
    double gradient;

    static double eta;
    static double alpha;

    static double RandomNumber(double Min, double Max) { return ((double(rand()) / double(RAND_MAX)) * (Max - Min)) + Min; }
    // Funckja aktywacji
    static double transferFunction(double x) { return tanh(x); }
    // Pochodna funkcji aktywacji
    static double transferFunctionDerivative(double x) { return 1.0 - tanh(x) * tanh(x); }
};

// Wspolczynniki uczenia sieci
double Neuron::eta = 0.15;
double Neuron::alpha = 0.5;

Neuron::Neuron(unsigned numConnections, unsigned index)
{
    // Tworzenie neuronu, polaczen z innymi neuronami,
    // ustawienie losowych wag

    for(unsigned i = 0; i < numConnections; i++)
    {
        outputWeights.push_back(Connection());
        outputWeights.back().weight = RandomNumber(0.0, 1.0);
        outputWeights.back().deltaWeight = 0.0;
    }

    myIndex = index;
}

void Neuron::feedForward(const Layer &prevLayer)
{
    double sum = 0.0;

    // Obliczanie wartosci wyjscia neuronu
    // dla kazdego wejscia: wyjscie += wejscie * waga
    for(unsigned n = 0; n < prevLayer.size(); n++)  {
        sum += prevLayer[n].getOutput() * prevLayer[n].outputWeights[myIndex].weight;
    }

    // Funkcja aktywacji
    output = transferFunction(sum);
}

void Neuron::calcOutputGradients(double x)
{
    // Obliczanie gradientu warstwy wyjsciowej

    double delta = x - output;
    gradient = delta * transferFunctionDerivative(x);
}

void Neuron::calcHiddenGradients(const Layer &nextLayer)
{
    // Obliczanie gradientu warstwy ukrytej

    double dow = 0.0;

    for(unsigned n = 0; n < nextLayer.size(); n++)  {
        dow += outputWeights[n].weight * nextLayer[n].gradient;
    }

    gradient = dow * transferFunctionDerivative(output);
}

void Neuron::updateInputWeights(Layer &prevLayer)
{
    // Aktualizacja wag na wejsciach neuronu (wyjsciach neuronow z poprzedniej warstwy)

    for(unsigned n = 0; n < prevLayer.size(); n++)
    {
        Neuron &neuron = prevLayer[n];

        double oldDelta = neuron.outputWeights[myIndex].deltaWeight;
        // Obliczanie nowej wartosci wagi
        double newDelta = eta * neuron.getOutput() * gradient + alpha * oldDelta;

        neuron.outputWeights[myIndex].weight += newDelta;
        neuron.outputWeights[myIndex].deltaWeight = newDelta;
    }
}

// **************** class Net ****************
class Net
{
public:
    Net(const vector<unsigned> &topology);
    void feedForward(const vector<double> &input);
    void backProp(const vector<double> &targetVal);
    void getResult(vector<double> &result);

private:
    vector<Layer> layers;
};

Net::Net(const vector<unsigned> &topology)
{
    // Tworzenie sieci na podstawie danych w kontenerze topology

    // Liczba warstw
    unsigned numLayers = topology.size();

    for(unsigned l = 0; l < numLayers; l++)
    {
        // Tworzenie nowej warstwy
        layers.push_back(Layer());

        // Jesli warstwa nie jest ostatnia warstwa, posiada wyjscia do innych warstw
        unsigned numConns = l == topology.size() - 1 ? 0 : topology[l + 1];

        // Tworzenie neuronow w warstwie
        for(unsigned n = 0; n < topology[l]; n++)       {
            layers[l].push_back(Neuron(numConns, n));
        }
    }
}

void Net::feedForward(const vector<double> &input)
{
    // Jesli ilosc danych wejsciowych nie rowna sie ilosci neuronow w warstwie wejsciowej- zakoncz dzialanie
    if(input.size() != layers[0].size())
        return;

    // Ustawienie danych wejsciowych jako wartosc wyjsciowa neuronow w pierwszej warstwie
    for(unsigned i = 0; i < input.size(); i++) {
        layers[0][i].setOutput(input[i]);
    }

    // Dla kazdego neuronu w warstwach ukrytych i warstwie wyjsciowej wykonaj obliczenia
    for(unsigned l = 1; l < layers.size(); l++) {
        Layer &prevLayer = layers[l - 1];

        for(unsigned n = 0; n < layers[l].size(); n++) {
            layers[l][n].feedForward(prevLayer);
        }
    }
}

void Net::backProp(const vector<double> &targetVal)
{
    // Korekcja bledu sieci

    Layer &outputLayer = layers.back();

    // Obliczanie gradientow warstwy wyjsciowej
    for(unsigned n = 0; n < outputLayer.size(); n++)    {
        outputLayer[n].calcOutputGradients(targetVal[n]);
    }

    // Obliczanie gradientow warstw ukrytych
    for(unsigned l = layers.size() - 2; l > 0; l--)
    {
        Layer &hidden = layers[l];
        Layer &next = layers[l + 1];

        for(unsigned n = 0; n < hidden.size(); n++)     {
            hidden[n].calcHiddenGradients(next);
        }
    }

    // Aktualizacja wag w warstwach ukrytych i warstwie wyjsciowej
    for(unsigned l = layers.size() - 1; l > 0; l--)
    {
        Layer &layer = layers[l];
        Layer &prevLayer = layers[l - 1];

        for(unsigned n = 0; n < layer.size(); n++)      {
            layer[n].updateInputWeights(prevLayer);
        }
    }
}

void Net::getResult(vector<double> &result)
{
    Layer &output = layers.back();

    for(unsigned n = 0; n < output.size(); n++) {
        result.push_back(output[n].getOutput());
    }
}