[ 딥러닝 구현 ] 직접 딥러닝 라이브러리를 개발하고 인공지능 도구 없이 딥러닝 구현 - Whitmem
[ 딥러닝 구현 ] 직접 딥러닝 라이브러리를 개발하고 인공지능 도구 없이 딥러닝 구현
AI Development Study
2025-03-29 20:45 게시 070a9cacfbd2d4730828

0
0
37
이 페이지는 외부 공간에 무단 복제할 수 없으며 오직 있는 그대로 게시되며 부정확한 내용을 포함할 수 있습니다. 법률이 허용하는 한 가이드 라인에 맞춰 게시 내용을 인용하거나 출처로 표기할 수 있습니다.
This page is not to be distributed to external services; it is provided as is and may contain inaccuracies.
AI 인공지능 뉴런 학습 구현
외부 인공지능 라이브러리를 사용하지 않고 C# 언어만으로 편미분 및 뉴런 학습을 수행하는 라이트한 라이브러리 및 소프트웨어를 개발하였다.
이 소프트웨어를 사용하여 선형 뉴런을 학습하고, 예측하는 기능을 포함하고 있다. 아직 Bias 를 처리하는 기능은 구현하지 않았지만 뉴런을 원하는대로 정의하고, 인풋/아웃풋 뉴런을 정의하며, 히든 층을 마음대로 추가할 수 있게끔 구현하였다.
활성화 함수는 RELU, Sigmoid 를 구현하였고, 손실 함수는 MSE만 우선 적용하였다.
기본적으로 이러한 작업 클래스들은 부모 클래스를 상속하기 때문에 추후 다른 손실 함수 등을 용이하게 구현할 수 있다.
기본적으로 모든 계산은 추적해야하기 때문에, 임시 메모리 공간 형태로 모두 저장한다. 그리고 미분식 또한 생성하여 보관하도록 한다.
기본적으로 구현한 메모리 노드는 덧셈 노드 선형 계산 노드 곱셈 노드 제곱 노드 Relu 노드 Sigmoid 노드 MSE 처리를 위한 차 제곱 노드를 구현하였다. 이 노드를 사용햇 미분 결과를 역 추적할 수 있고, 그 미분 결과를 다른 노드로 전달할 수 있다.
예를 들어 위 클래스는 sigmoid 를 처리하는 노드이다. 부모 노드인 CalculatorNode를 상속하여 forward, backward를 수행할 수 있는 하나의 계산 노드이다.
그리고 각 뉴런은 다른 뉴런과 연결되고 내용이 전파되어야 하기 때문에, 하나의 클래스로 관리한다. 즉 뉴런 하나 하나가 인스턴스가 되어 다른 뉴런과 연결할 수 있게끔 구현한다.
뉴런 하나 하나에 입력 값을 저장할 수 있고, 가중치 값, 가중치 미분, 입력 미분, 출력 값, 출력 미분 값을 저장하는 변수를 만들어 관리한다.
forward요청이 들어오면 각 해당 뉴런의 내부 총합 연산을 수행한다. 하나의 뉴런은 이전 입력에 대해서 모두 가중치와 곱하고 해당 노드의 아웃풋으로 지정한다. 그 과정에서 모든 계산 메모리를 변수에 저장해야 한다. 이 계산 메모리는 추후 역전파할 때 다시 곱하여 미분 값을 계산하는데 사용해야하기 때문이다.
그렇기 때문에 forward과정에서 추후 backward에 사용할 연산을 미리 정의하고, backward 시에 해당 콜을 순차적으로 수행하여 순서에 맞게끔 각 뉴런들을 미분할 수 있다.
또한 각 뉴런들을 미분하는 과정에서, 뒤의 뉴런이 앞으로 오는데, 각 뒤의 뉴런 입력 미분 된 값이 여러개 인 경우 해다 미분 값들을 모두 더해 기울기 총합을 구해야 한다.
즉 빨간 선과 같이 미분하는 과정에서, w1, w2 의 미분 값을 더해 o1의 아웃풋 미분으로 가정할 수 있다.
다음으로는 손실 함수를 계산하는 클래스인데, 기본적으로 개발자는 어떤 손실 함수를 구현할지 모르기 때문에, 가상 함수로 기본 뼈대를 구현해 놓는다. 아무튼 손실함수는 실제 레이블과 비교하면서 오차를 계산해야하므로, realValues 를 입력 받아 forward하고, 다시 역으로 backward하여 미분 값을 구할 수 있다. 이렇게 forward 된 값들의 최종 output 이 getOutputValue로부터 가져와 손실 오차를 가져올 수 있다.
MSE의 계산은 어렵지는 않은데, 결과적으로 (실제 값 - 예측 값)^2 총합 의 1/2 이기 때문에, 미분하면 해당하는 뉴런의 항만 빠져나올 것이고, 미분 값 역시 1/2로 시작하면 되기 때문에, 별도의 계산 노드 없이 바로 MSE에서 빼기 제곱만 하는 노드를 만들어 직접 계산할 수 있다.
단, 역전파할 때는 위에 마지막 1/2을 곱하기 때문에, 역으로 다시 1/2을 곱하여 미분을 시작한다.
최종적으로 이러한 작업을 모두 모아 학습을 수행하고, 추론을 수행하는 클래스 LayerWorker을 만들었다. 위 생성자를 보면 알 수 있다시피, 각 레이어 뉴런 개수 정보를 입력하고, learningRate 를 입력하고, loss 함수를 지정하고,
생성자 내부에서는 레이어의 초기화를 수행하고 각 레이어를 연결하는 작업을 수행한다. 이 과정 안에서 신경망을 서로 연결함으로써 결과적으로 우리가 흔히 보는 신경망이 완성된다.
이제 학습 부분을 구현하는데, learn 메서드로 인풋 데이터를 넣고 정답 데이터를 넣으면, 먼저 getLoss()를 통해 순전파 및 Loss 순전파를 수행하고, loss 역전파, 각 레이어들을 역으로 역전파한다.
그리고 계산된 모든 가중치 기울기들을 활용해 일정 Learning Rate만큼만 뺀다.
각 신경망의 입력 가중치에 기울기 * learning rate 값을 조금씩 빼주면서 경사하강을 수행한다.
사용 방법은 매우 간단하다.
LayerWorker 클래스를 인스턴스화 하면서, 첫 번째 파라메터에는 뉴런 개수를 순차적으로 입력한다. 예를 들어, 위 사진의 경우 입력 레이어에는 뉴런 1개, 히든 레이어는 각각 10개, 10개, 10개, 100개, 10개를 연결하고 마지막 출력 레이어의 뉴런은 1개로 지정한다.
그리고 한 에폭당 러닝 레이트는 0.0000000001f 로 지정하고, 직접 구현한 MSELoss 로스 함수가 구현된 클래스 인스턴스를 넘겨준다.
그리고 아직 배치 단위로 학습하거나 여러 데이터를 평균내어 학습하는 기능은 구현하지 않았기 때문에 하나 하나 학습을 무한 반복해야 한다. max(에폭)개수만큼 learn을 수행하면 된다. 1 값을 넣었을 때 5가 나오고, 2값을 넣었을 때 10.5가 나오게끔 학습한다.
그리고 1을 넣었을 때 5가 나오는지 로스 함수를 통해 로스 값을 확인한다.
학습을 수행하면 할수록 로스 값이 줄어드는 것을 확인할 수 있다. 손실 함수가 제대로 구현되었고 미분 및 기울기가 제대로 경사하강되고 있다는 것을 의미한다. 1을 넣었을 때 5가 나오도록 학습을 했기에 추론 할 때도 거의 5.2에 가까워지는 것을 확인할 수 있다.
다음에는 직접 각 활성화 함수를 구현하고, 여러 배치를 학습할 수 있게끔 구현하여 이미지를 학습해보도록 한다.
댓글 0개
댓글은 일회용 패스워드가 발급되며 사이트 이용 약관에 동의로 간주됩니다.
확인
Whitmemit 개인 일지 블로그는 개인이 운영하는 정보 공유 공간으로 사용자의 민감한 개인 정보를 직접 요구하거나 요청하지 않습니다. 기본적인 사이트 방문시 처리되는 처리 정보에 대해서는 '사이트 처리 방침'을 참고하십시오. 추가적인 기능의 제공을 위하여 쿠키 정보를 사용하고 있습니다. Whitmemit 에서 처리하는 정보는 식별 용도로 사용되며 기타 글꼴 및 폰트 라이브러리에서 쿠키 정보를 사용할 수 있습니다.
이 자료는 모두 필수 자료로 간주되며, 사이트 이용을 하거나, 탐색하는 경우 동의로 간주합니다.