본문 바로가기

소프트웨어/Study

ML] Simple FeedForward & Simple Back Propagation

강의 및 소스 레퍼런스 : https://www.youtube.com/watch?v=lg-PZ-zIr98


ML 강의 동영상인데 너무 내용이 괜찮다.


Backpropagation의 ChainRule에대해 자세히 설명해주셔서 이해가 쉬웠다.


dE/db = dE/dy*dy/df*df/dsigma*dsigma/db

dE/dw = dE/dy*dy/df*df/dsigma*dsigma/dw

E = 1/2 * (y - ytarget)^2

dE/dy == y - ytarget // input의 FeedForward와 target의 차이

dy/df == 1 // y와 f는 같음

df/dsigma == Activation Gradient == [f(sigma)==sigma의 linear fcn가정 시, df/dsigma==1] == 1

w(x) == w*x + b

dsigma/db == 1

dsigma/dw == x

여기까지 해서 dE/dW와 dE/db를 찾았으면 update(back prop) 실행

Wupdate = w - alpha * dE/dW

Bupdate = b - alpha * dE/dB


여기까지 하면 Simple Node의 Back Propagation이 완성된다.



#include <iostream>

using namespace std;


class Neuron

{

public:

double w; // weight

double b; // bias


double GetActivation(const double& x);

double FeedForward(const double& input);


double m_input, m_output; // back propagation

double GetActivationGrad(const double& x);

void PropagationBackward(const double& target);

private:

#define MAX2(a,b) (a) > (b) ? (a) : (b)

};


double Neuron::GetActivation(const double& x)

{

// for linear or identity activation fcns

return x;


// for ReLU(Rectified Linear Unit) activation fcn

//return MAX2(0.0, x);

}


/* 

Gradient. df/d\sigma

sigma 변화에 따른 f의 양상

linear fcn 에서는 f(\sigma) == \sigma 이므로, \sigma로 미분 시 항상 1

*/

double Neuron::GetActivationGrad(const double& x)

{

// for linear or identity activation fcns

return 1.0;


// for ReLU(Rectified Linear Unit) activation fcn

// return (x>0.0f)?1.0:0.0;

}


double Neuron::FeedForward(const double& input)

{

/* 

output y = f(sigma)

sigma = w * x + b

for multiple inputs,

     sigma = w0 * x0 + w1 * x1 + ... + b

*/

/* Simple Fed Forward */

/*const double sigma = w * input + b;

return GetActivation(sigma);*/


/* Feed Forward */

const double sigma = w * input + b;

m_input = input;

m_output = GetActivation(sigma);

return m_output;

}


void Neuron::PropagationBackward(const double& target)

{

//내부적으로 w와 b를 업데이트하는게 목표이기때문에 리턴값 불필요함


//

const double alpha = 0.1f; // learning rate

const double grad = (m_output - target) * GetActivationGrad(m_output); // (y - ytarget) * 


w = w - (alpha * grad * m_input) ; // last input came fro md(wx+b)/dw = x

b = b - (alpha * grad * 1.0); // last 1.0 came from d(wx+b)/db = 1


}


int main(void)

{

Neuron cNeuron;


// Simple Feed Forward

/*cNeuron.w = 2.0f;

cNeuron.b = 1.0f;


for(int i=0; i<3; i++)

cout << "simple feed forward input"<< i << " " << cNeuron.FeedForward(i) << endl;*/


cNeuron.w = 2.0f;

cNeuron.b = 1.0f;

for(int i=0; i<10; i++)

{

cout<< "Input" << 1.0 <<" output " <<  cNeuron.FeedForward(1.0) <<endl;

cNeuron.PropagationBackward(4.0);

cout<< "BackProp" << 4.0 << endl;

}


return 0;