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());
	}
}