diff --git a/Net.h b/Net.h new file mode 100644 index 0000000..ecfb44f --- /dev/null +++ b/Net.h @@ -0,0 +1,159 @@ +#pragma once + +#include + +class Neuron +{ +private: + double outputValue; + std::vector outputWeights; + +public: + void setOutputValue(double value) + { + outputValue = value; + } + + static double transferFunction(double inputValue) + { + return std::tanh(inputValue); + } + + void feedForward(double inputValue) + { + outputValue = Neuron::transferFunction(inputValue); + } + + double getWeightedOutputValue(int outputNeuron) const + { + return outputValue * outputWeights[outputNeuron]; + } + + void createOutputWeights(unsigned int number) + { + outputWeights.clear(); + + for (unsigned int i = 0; i < number; ++i) + { + outputWeights.push_back(std::rand() / (double)RAND_MAX); + } + } + + double getOutputValue() const + { + return outputValue; + } +}; + +class Layer : public std::vector < Neuron > +{ +public: + Layer(unsigned int numNeurons) + { + for (unsigned int i = 0; i < numNeurons; ++i) + { + push_back(Neuron()); + } + } + + void setOutputValues(const std::vector & outputValues) + { + if (size() != outputValues.size()) + { + throw std::exception("The number of output values has to match the layer size"); + } + + auto valueIt = outputValues.begin(); + for (Neuron &neuron : *this) + { + neuron.setOutputValue(*valueIt++); + } + } + + void feedForward(const Layer &inputLayer) + { + int neuronNumber = 0; + for (Neuron &neuron : *this) + { + neuron.feedForward(inputLayer.getWeightedSum(neuronNumber)); + } + } + + double getWeightedSum(int outputNeuron) const + { + double sum = 0.0; + + for (const Neuron &neuron : *this) + { + sum += neuron.getWeightedOutputValue(outputNeuron); + } + + return sum; + } + + void connectTo(const Layer & nextLayer) + { + for (Neuron &neuron : *this) + { + neuron.createOutputWeights(nextLayer.size()); + } + } +}; + +class Net : public std::vector < Layer > +{ +public: + Net(std::initializer_list layerSizes) + { + if (layerSizes.size() < 3) + { + throw std::exception("A net needs at least 3 layers"); + } + + for (unsigned int numNeurons : layerSizes) + { + push_back(Layer(numNeurons)); + } + + for (auto layerIt = begin(); layerIt != end() - 1; ++layerIt) + { + Layer ¤tLayer = *layerIt; + const Layer &nextLayer = *(layerIt + 1); + + currentLayer.connectTo(nextLayer); + } + } + + void feedForward(const std::vector &inputValues) + { + Layer &inputLayer = front(); + + if (inputLayer.size() != inputValues.size()) + { + throw std::exception("The number of input values has to match the input layer size"); + } + + inputLayer.setOutputValues(inputValues); + + for (auto layerIt = begin(); layerIt != end() - 1; ++layerIt) + { + const Layer ¤tLayer = *layerIt; + Layer &nextLayer = *(layerIt + 1); + + nextLayer.feedForward(currentLayer); + } + } + + std::vector getResult() + { + std::vector result; + + const Layer &outputLayer = back(); + for (const Neuron &neuron : outputLayer) + { + result.push_back(neuron.getOutputValue()); + } + + return result; + } +}; \ No newline at end of file diff --git a/Neuro.cpp b/Neuro.cpp new file mode 100644 index 0000000..193d020 --- /dev/null +++ b/Neuro.cpp @@ -0,0 +1,33 @@ +#include +#include + +#include "Net.h" + +int main() +{ + try + { + std::cout << "Neuro running" << std::endl; + + Net myNet({ 2, 3, 1 }); + + myNet.feedForward({ 1.0, 0.0 }); + + std::vector result = myNet.getResult(); + + std::cout << "Result: "; + for (double &value : result) + { + std::cout << value << " "; + } + std::cout << std::endl; + } + catch (std::exception &ex) + { + std::cerr << "Error: " << ex.what() << std::endl; + + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/Neuro.sln b/Neuro.sln new file mode 100644 index 0000000..650931c --- /dev/null +++ b/Neuro.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Neuro", "Neuro.vcxproj", "{EC045881-3BCD-4054-895B-176FAD3FB8C2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EC045881-3BCD-4054-895B-176FAD3FB8C2}.Debug|Win32.ActiveCfg = Debug|Win32 + {EC045881-3BCD-4054-895B-176FAD3FB8C2}.Debug|Win32.Build.0 = Debug|Win32 + {EC045881-3BCD-4054-895B-176FAD3FB8C2}.Release|Win32.ActiveCfg = Release|Win32 + {EC045881-3BCD-4054-895B-176FAD3FB8C2}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Neuro.vcxproj b/Neuro.vcxproj new file mode 100644 index 0000000..5b97cd8 --- /dev/null +++ b/Neuro.vcxproj @@ -0,0 +1,89 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {EC045881-3BCD-4054-895B-176FAD3FB8C2} + Win32Proj + Neuro + + + + Application + true + v120 + Unicode + + + Application + false + v120 + true + Unicode + + + + + + + + + + + + + true + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/Neuro.vcxproj.filters b/Neuro.vcxproj.filters new file mode 100644 index 0000000..fe9b3fe --- /dev/null +++ b/Neuro.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file