정보공간_1

[2기 수원 이동욱] 인공신경망 Neural Network #1 본문

IT 놀이터/Elite Member Tech & Talk

[2기 수원 이동욱] 인공신경망 Neural Network #1

알 수 없는 사용자 2012. 11. 22. 13:24


안녕하세요!

수원멤버십에서 활동하고 있는 21-1기 이동욱입니다.

지금까지는 사운드와 관련된 이야기를 포스팅 했었는데요~


이제 조금 주제를 바꿔서

Neural Network(뉴럴네트워크, 인공신경망) 에 대한 이야기를 해볼까 합니다.



1. 뉴럴 네트워크란?

컴퓨터 공학에서 뉴럴네트워크(Neural Network)란 인공지능 분야에 속하는 기술로써, 인간의 뇌 속에 있는 신경네트워크를 모델링하여 문제를 해결하는 소프트웨어적 방법을 말합니다.

뉴럴 네트워크를 사용하면, 복잡하거나 해가 알려지지 않은 문제에 대해서 아주 정확하진 않지만 만족할만한 해를 구할 수 있습니다. 

재미있는 것은 이 만족할 만한 해를 뉴럴 네트워크 스스로 학습을 통해서 구할 수 있다는 점입니다. 컴퓨터에게 무엇인가를 가르칠 수 있다는 것은 누구에게나 상당히 흥미로운 일이지요!


2. 뉴런



뉴런(Neuron)은 신경망을 구성하는 신경세포 한 개를 말합니다. 뉴런 하나만 떼어놓고 보면 기능이 아주 단순합니다. 하지만 이런 뉴런들이 1000억개 정도 모이면 인간의 지능을 가질 수가 있는 것이죠. (인간의 뇌 속에는 약 1000억개의 뉴런들이 네트워크를 이루고 있다고 합니다.)

그러면 뉴런이 어떻게 동작하는지 살펴보겠습니다.


위키피디아에서 가져온 뉴런 그림입니다.

뉴런은 핵을 중심으로 여러 개의 작은 수상돌기와 한 개의 커다란 축색돌기(축삭)가 뻗어나와 있습니다. 용어도 어렵고 그림은 복잡하지만 생물시간이 아니기 때문에 중요하지 않습니다. 기능이 중요하죠.

먼저 수상돌기라고 되어 있는 부분이 다른 뉴런이 보내주는 신호를 전달 받는 곳입니다. 쉽게 말해서 Input 입니다. 한 개의 뉴런은 수상돌기를 통해서 만 개에서 10만개 정도의 다른 뉴런과 연결되어 있다고 합니다! 와~

그 다음으로, 축색돌기라고도 하고 축삭이라고도 하는 혼자 거대한 돌기가 바로 다른 뉴런에게 신호를 전달하는 역할을 합니다. Output이 되는 것이죠. 뉴런은 축색돌기를 하나씩만 가지고 있다고 합니다.

자 그런데 뉴런은 받은 신호를 무조건 전달할까요? 아닙니다. 그렇지 않기 때문에 연산이 가능합니다. 

뉴런과 뉴런은 시냅스라고 하는 연결부가 있는데요, 시냅스는 전기신호를 화학신호로 바꾸어서 전달한다고 합니다. 그런데, 각 시냅스마다 연결강도가 달라서 이 화학신호의 강도가 제각각이지요.

뉴런은 다른 뉴런에게서 받은 이 화학신호 강도의 합이 일정한 값(역치) 이상이 되면 비로소 축색돌기로 전기신호를 전달하는 것이죠.


자 여기까지 설명한 뉴런의 특징 및 동작을 정리하면 다음과 같습니다.

1. 수상돌기는 다른 여러 개의 뉴런에게 화학신호를 받아들인다.

2. 각 연결부의 화학신호의 강도(연결강도)가 다르다.  

3. 받아들인 화학신호 강도의 합이 일정값(역치) 이상이되면 축색돌기로 전기신호를 전달한다.

4. 축색돌기의 전기신호가 다른 뉴런들에게 전달된다.


자, 이제 이와 같은 동작을 코드로 옮기기만 하면 여러분들은 신비의 뉴런을 창조하신 겁니다! (물론 많은 생물학적 과정이 생략되었습니다.)


3. 뉴런 만들기

이상 설명한 내용을 제가 직접 C++ 코드로 작성해 보았습니다.

1 #include <cstdlib> 2 3 class Neuron 4 { 5 private: 6 int num_of_input; // Number of input synapse 7 double* input_weight;         // Chemical signal weight 8 double threshold; // Threshold to transmit signal 9 10 public: 11 Neuron(int num_of_input) 12 { 13 this->num_of_input = num_of_input; 14 input_weight = new double[num_of_input]; 15 16 for(int i=0; i<num_of_input; i++) 17 input_weight[i] = ((double)rand()/RAND_MAX)*2-1; // -1 ~ 1 Random 18 19 threshold = 0; 20 } 21 ~Neuron() 22 { 23 delete[] input_weight; 24 } 25 26 bool work(bool input[]) 27 { 28 double sum = 0; 29 for(int i=0; i<num_of_input; i++) 30 { 31 if(input[i]) 32 sum += input_weight[i]; 33 } 34 35 if(sum >= threshold) 36 return true; 37 else 38 return false; 39 } 40 };

자 뉴런 클래스를 만들었습니다! 

(사실 뉴럴네트워크는 연산속도를 위해서 객체지향으로 작성하는 경우가 거의 없는 것 같습니다만, 이해를 돕기위해서 앞으로도 C++ 스타일로 작성하겠습니다.)

먼저 멤버변수 중 num_of_input이 수상돌기의 시냅스 수, 즉 input의 갯수를 뜻합니다.

그리고 input_weight 가 바로 각 연결부(시냅스)들의 연결강도를 나타냅니다. 위에서 설명한 것 처럼, 각 연결부의 연결강도는 다른 값을 가집니다. 일단은 모든 연결강도를 -1 에서 1까지 랜덤으로 정해지게끔 초기화하였습니다. (나중에 살펴보겠지만, 학습을 통해 조정됩니다.)

마지막으로 threshold 는 역치값을 뜻합니다. 여기서는 0으로 초기화 하였습니다.

work 라는 함수에 입력신호를 배열로 넘겨주면, 연결강도에 의해 sum에 화학신호량이 더해지고, 이 값이 역치값인 threshold를 넘으면 true를 반환함으로써 축색돌기로 전기신호를 전달하게 됩니다. 이 신호는 다시 다음 뉴런의 input 으로 사용되겠지요.

우와! 이제 이 뉴런들을 이렇게 저렇게 잘 연결하기만 하면 뉴럴네트워크가 되는 것입니다!


4. 결과를 알 수 없는 뉴럴네트워크 만들어 보기

위에서 구현한 뉴런 클래스를 이용하여 2개의 입력과 1개의 출력을 갖는 뉴런을 3 개 만들고, 이들을 연결하여, 아래 그림과 같이 2 개의 입력과 1 개의 출력을 갖는 뉴럴네트워크를 구성해 보겠습니다.


먼저 두 개의 뉴런이 외부로 부터 입력을 받고, 이 두 뉴런의 출력(있을 수도 없을 수도 있습니다.)을 다시 한 개의 뉴런이 전달 받는 구성입니다. 이 때 마지막 뉴런이 신호를 출력하는지를 살펴보겠습니다.

입력은 네 가지 경우의 수 (0,0), (1,0), (0,1), (1,1) 모두 테스트해보겠습니다.

각 경우에서 마지막 뉴런의 신호출력 여부를 살펴보겠습니다.

테스트코드는 아래와 같습니다.

  1 #include <iostream>
  2 #include <ctime>
  3 using namespace std;
  4 
  5 void main()
  6 {
  7 	srand((unsigned)time(NULL));	// Set random seed
  8 
  9 	Neuron* input_n1 = new Neuron(2);
 10 	Neuron* input_n2 = new Neuron(2);
 11 	Neuron* output_n = new Neuron(2);
 12 
 13 	bool input[4][2] = { {0,0}, {1,0}, {0,1}, {1,1} };	// Test inputs
 14 	bool middle_output[2] = {0, 0};
 15 	bool output = 0;
 16 
 17 	for(int i=0; i<4; i++)
 18 	{
 19 		middle_output[0] = input_n1->work(input[i]);
 20 		middle_output[1] = input_n2->work(input[i]);
 21 		output = output_n->work(middle_output);
 22 		cout<<"input : "<<input[i][0]<<" "<<input[i][1]<<" / output : "<<output<<endl;
 23 	}
 24 
 25 	delete input_n1;
 26 	delete input_n2;
 27 	delete output_n;
 28 }



결과는 당연히 알 수 없습니다. 연결강도를 모두 랜덤으로 했으니까요.

실행할 때 마다 결과가 달라집니다. 위 결과에서는 결과가 반반 이군요.


5. 마치며

여러분 아직 갈 길이 멉니다.

맞습니다. 도데체 이딴걸로 어떤 의미있는 연산을 할 수 있을까 하는 생각이 듭니다.

다음 포스팅에서는 뉴런의 동작을 조금 개선하여 네트워크를 구성해보고,

뉴럴네트워크 스스로 학습을 하게 하는 방법에 대해서 알아보겠습니다!

많이 기대해주세요~