Skip to content

Instantly share code, notes, and snippets.

@wortelstoemp
Last active November 23, 2018 10:44
Show Gist options
  • Select an option

  • Save wortelstoemp/bd3b8fe2478b95a827bd0f4e2c737c7b to your computer and use it in GitHub Desktop.

Select an option

Save wortelstoemp/bd3b8fe2478b95a827bd0f4e2c737c7b to your computer and use it in GitHub Desktop.
Neural Network From Scratch
#pragma once
// Proof of concept so I know how a neural network is built under the hood.
// Author: Tom Quareme
// TODO: https://www.youtube.com/watch?v=MJ_7qe--cvo 2-2
#include <iostream>
#include <vector>
#include <cmath>
#include <random>
namespace tqNN
{
template <typename T>
class Neuron
{
private:
T value; // raw value z
T activatedValue; // f(z) in [0..1]
T derivativeValue; // f'(z)
public:
Neuron(const T value = 0)
{
this->value = value;
ComputeActivation();
ComputeDerivative();
}
T Value() const { return value; }
T ActivatedValue() const { return activatedValue; }
T DerivativeValue() const { return derivativeValue; }
void Value(const T value)
{
this->value = value;
ComputeActivation();
ComputeDerivative();
}
// Fast Sigmoid Function (has easier derivative)
// a = f(z) = z / (1 + abs(z))
void ComputeActivation()
{
activatedValue = value / (1 + std::fabs(value));
}
// Derivative of Sigmoid Function used in Backprop Algorithm
// a' = f'(z) = f(z) * (1 - f(z))
void ComputeDerivative()
{
derivativeValue = activatedValue * (1 - activatedValue);
}
};
template <typename T>
std::ostream &operator<<(std::ostream &os, const Neuron<T> &obj)
{
os << "Value: " << obj.Value() << std::endl;
os << "Activated value: " << obj.ActivatedValue() << std::endl;
os << "Derivative value: " << obj.DerivativeValue();
return os;
}
template <typename T>
class Matrix
{
private:
std::vector<T> elements;
unsigned int rows;
unsigned int cols;
public:
Matrix(const unsigned int rows = 1, const unsigned int cols = 1, const bool isRandom = false)
{
const unsigned int size = rows * cols;
elements.resize(size);
this->rows = rows;
this->cols = cols;
if (isRandom) {
for (unsigned int i = 0; i < rows; ++i) {
for (unsigned int j = 0; j < cols; ++j) {
elements[i * cols + j] = GenerateRandomNumber(0.0, 1.0);
}
}
return;
}
for (unsigned int i = 0; i < rows; ++i) {
for (unsigned int j = 0; j < cols; ++j) {
elements[i * cols + j] = 0.0;
}
}
}
unsigned int Rows() const { return rows; }
unsigned int Cols() const { return cols; }
std::vector<T> ToVector()
{
return elements;
}
Matrix Transpose()
{
Matrix m(cols, rows);
for (unsigned int i = 0; i < rows; ++i) {
for (unsigned int j = 0; j < cols; ++j) {
m(j, i) = elements[i * cols + j];
}
}
return m;
}
T &operator() (unsigned int i, unsigned int j)
{
return elements[(i*cols) + j];
}
Matrix<T> operator*(const Matrix<T> &other) const
{
Matrix<T> result(this->rows, other.cols, false);
for (unsigned int i = 0; i < this->rows; ++i) {
for (unsigned int j = 0; j < other.cols; ++j) {
double sum = 0.0;
for (unsigned int k = 0; k < this->cols; ++k) {
sum += elements[(i*cols) + k] * other.elements[(k*other.cols) + j];
}
result(i, j) = sum;
}
}
return result;
}
double GenerateRandomNumber(double startIncl = 0.0, double endExcl = 1.0)
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(startIncl, endExcl);
return dis(gen);
}
};
template <typename T>
std::ostream &operator<<(std::ostream &os, Matrix<T> &obj)
{
os << "[" << std::endl;
for (unsigned int i = 0; i < obj.Rows(); ++i) {
for (unsigned int j = 0; j < obj.Cols(); ++j) {
os << obj(i, j) << " ";
}
os << std::endl;
}
os << "]";
return os;
}
template <typename T>
class Layer
{
private:
std::vector< Neuron<T> > neurons;
public:
Layer(unsigned int size)
{
neurons.reserve(size);
for (unsigned int i = 0; i < size; ++i) {
neurons.push_back(Neuron<T>(0.0));
}
}
Neuron<T> &operator[] (unsigned int i)
{
return neurons[i];
}
Matrix<T> ToMatrixValues()
{
const unsigned int neuronCount = neurons.size();
Matrix<T> m(1, neuronCount, false);
for (unsigned int i = 0; i < neuronCount; ++i) {
m(0, i) = neurons[i].Value();
}
return m;
}
Matrix<T> ToMatrixActivatedValues()
{
const unsigned int neuronCount = neurons.size();
Matrix<T> m(1, neuronCount, false);
for (unsigned int i = 0; i < neuronCount; ++i) {
m(0, i) = neurons[i].ActivatedValue();
}
return m;
}
Matrix<T> ToMatrixDerivedValues()
{
const unsigned int neuronCount = neurons.size();
Matrix<T> m(1, neuronCount, false);
for (int i = 0; i < neuronCount; ++i) {
m(0, i) = neurons[i].DerivativeValue();
}
return m;
}
};
template <typename T>
class NeuralNetwork
{
private:
std::vector<unsigned int> topology;
std::vector<double> inputs;
std::vector< Layer<T> > layers;
std::vector< Matrix<T> > weightMatrices;
public:
NeuralNetwork(const std::vector<T> &inputs)
{
this->Inputs(inputs);
}
NeuralNetwork(const std::vector<unsigned int> &topology)
{
const unsigned int layerCount = topology.size();
layers.reserve(layerCount);
for (unsigned int i = 0; i < layerCount; ++i) {
layers.push_back(Layer<T>(topology[i]));
}
const unsigned int weightMatricesCount = layerCount - 1;
for (unsigned int i = 0; i < weightMatricesCount; ++i) {
Matrix<T> w(topology[i], topology[i + 1], true);
weightMatrices.push_back(w);
}
}
unsigned int LayerCount() { return layers.size(); }
void Inputs(const std::vector<T> &inputs)
{
this->inputs = inputs;
const unsigned int inputCount = inputs.size();
for (unsigned int i = 0; i < inputCount; ++i) {
Layer<T> l = layers[0];
Neuron<T> n = l[i];
n.Value(inputs[i]);
}
}
Layer<T> &operator[] (unsigned int i)
{
return layers[i];
}
void FeedForward()
{
// Loop through each layer starting from the input layer.
// Take the product of the current layer and the connected weights
//
for (unsigned int i = 0; i < LayerCount() - 1; ++i) {
Layer<T> l = layers[i];
Matrix<T> a = (i == 0)
? l.ToMatrixValues()
: l.ToMatrixActivatedValues();
Matrix<T> b;
}
}
};
template <typename T>
std::ostream &operator<<(std::ostream &os, NeuralNetwork<T> &obj)
{
const unsigned int layerCount = obj.LayerCount();
for (unsigned int i = 0; i < layerCount; ++i) {
os << "Layer: " << i << std::endl;
Layer<T> layer = obj[i];
Matrix<T> m = (i == 0)
? layer.ToMatrixValues()
: layer.ToMatrixActivatedValues();
os << m;
}
return os;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment