Search

인공지능 수학_인공지능 신경망의 학습 비결, 역전파

생성일
2025/09/09 01:53
태그
파이쌤
인공지능 수학
신경망 학습
역전파
안녕하세요. 파이쌤 입니다. 인공지능은 어떻게 스스로 똑똑해질까요?
그 비밀은 놀랍게도 '요리' 과정과 닮아있습니다. 요리사가 맛을 보고 레시피를 수정하며 완벽한 요리를 만들어가듯, 인공지능도 자신의 실수를 거꾸로 되짚어보며 학습합니다. 이번 소식지에서는 인공지능 학습의 핵심 원리인 '오차역전파'에 대해서 다뤄보려고 합니다. 인공지능의 학습 원리가 궁금하셨다면 이번 글을 놓치지 마세요!
요리사가 처음 해보는 요리가 있습니다. 레시피를 보고 정성껏 재료를 넣고 조리하지만, 완성된 음식의 맛이 기대와 다를 수 있습니다. 이때 그는 맛을 본 후 요리 과정을 거꾸로 생각해 보면서 무엇이 부족했는지 분석해본 후 다음 조리 시에는 이를 보완해 요리를 할 것입니다.
예를 들어, 간이 싱겁다면 다음에는 소금을 더 넣고, 너무 짜다면 소금 양을 줄일 것입니다. 조리 시간이 길어 음식이 퍽퍽했다면 다음에는 조금 덜 익히도록 조정할 것입니다. 이처럼 완성된 결과물(음식)을 평가하고, 이상적인 맛과의 차이가 어디에서 비롯되었는지 거꾸로 추적하여 원인(조리 과정)을 수정하는 것이 바로 인공지능 신경망을 학습시키는 역전파(Backpropagation)의 핵심 원리와 같습니다.
신경망의 학습 과정도 이와 마찬가지입니다. 모델이 예측한 값과 실제 값의 차이, 즉 오차(Error)를 계산한 뒤, 그 오차가 네트워크 안의 어느 부분에서 비롯되었는지를 단계별로 거슬러 올라가 확인합니다. 그리고 각 단계의 가중치(Weight)를 조금씩 조정하여 다음 예측에서는 오차를 줄일 수 있도록 학습합니다.
이번 글에서는 신경망에서 이 과정을 어떻게 해나가는지 자세히 살펴보도록 하겠습니다.

오차역전파

오차역전파(Backpropagation)는 신경망 학습에서 각 가중치에 대한 기울기(gradient)를 효율적으로 계산하는 알고리즘입니다.
신경망은 먼저 임의의 가중치와 편향(bias)으로 초깃값을 설정한 뒤, 입력 데이터를 순서대로 계산하여 예측값을 출력합니다(순전파, forward propagation). 이후 예측값과 실제 정답의 차이를 바탕으로 손실(Loss)을 구합니다.
손실을 줄여 모델을 최적화하기 위해, 각 가중치와 편향이 손실에 얼마나 영향을 미쳤는지(기울기)를 계산하고, 이를 이용해 매개변수 값을 미세하게 조정합니다. 이때 미분의 연쇄 법칙(chain rule)을 이용해 출력층에서부터 입력층 방향으로 기울기를 차례차례 전달하며 계산하는데, 이 과정을 오차역전파라고 부릅니다.
이를 정리하면 신경망의 다음과 같은 순서로 학습을 진행합니다.
1.
순전파 (Forward Propagation): 일단 임의의 가중치를 설정하고 입력 데이터로 계산을 수행하여 예측값을 출력합니다.
2.
손실 계산 (Calculate Loss): 예측값과 실제 정답의 차이, 즉 손실(Loss) 또는 오차(Error)를 계산합니다.
3.
역전파 (Backpropagation): 계산된 손실에 각 가중치가 얼마나 영향을 미쳤는지 미분의 연쇄법칙(Chain Rule)을 이용해 거꾸로 추적하며 계산합니다. 이 과정에서 각 가중치에 대한 손실함수의 '기울기'를 구합니다.
4.
가중치 업데이트: 구해진 기울기를 바탕으로 손실이 줄어드는 방향으로 가중치를 약간 수정합니다.
이 과정을 수없이 반복하며 신경망은 점점 더 정확한 예측을 하게 됩니다.

경사하강법

머신러닝과 신경망의 목표는 손실 함수 값을 최소로 만드는 최적의 가중치를 찾는 것입니다. 경사 하강법(Gradient Descent)은 손실을 줄이기 위해, 오차역전파로 구한 기울기를 이용해 매개변수를 점진적으로 조정하는 방법입니다.
기울기(Gradient)란 그래프의 한 점에서의 변화 방향과 크기를 나타냅니다. 기울기가 양수이면 값이 증가하는 방향(오르막)을, 음수이면 값이 감소하는 방향(내리막)을 가리킵니다. 경사 하강법은 이름 그대로, 기울기가 가리키는 내리막 방향으로 이동하여 손실 함수의 최솟값에 도달하는 것을 목표로 합니다.
지오지브라에서 f:y=x2f:y=x^2의 그래프의 접선의 기울기 그래프를 그려 봅시다.
xx값이 양수일 때 :
입력식: Tangent(1,f)Tangent (1, \mathrm{f}) 접선의 기울기가 양수로 x x 값이 증가할 때 yy 값이 증가하는 오르막입니다. 최솟값에 도달하려면 x를 줄여야 합니다.
xx 값이 음수일 때: 입력식: Tangetn(1,f)Tangetn(-1, f) 접선의 기울기가 음수로 xx 값이 증가할 때 y y 값이 감소하는 내리막입니다. 최솟값에 도달하려면 x를 늘려야 합니다.
x=0x=0 일 때:
기울기는 0이며, 이곳이 바로 손실 값이 최소인 지점입니다.

언덕 내려가기

높은 언덕(손실 값이 큰 상태)에 서 있다고 상상해 봅시다. 가장 낮은 계곡(손실 값이 최소인 상태)에 도달하기 위해, 우리는 발밑의 경사가 가장 가파른 방향을 보고 조금씩 내려가야 합니다.
경사 하강법은 이 과정을 수학적으로 구현한 것입니다. yy 가 손실 값일 때 그래프에서 yy 값이 큰 상태를 말합니다. 그래프에서는 xx00일 때 yy값이 00으로 손실 값이 최소인 상태입니다.
(출처: HYPERLINK "https//hackernoon.com/life-is-gradient-descent-880c60ac1be8"https://hackernoon.com/life-is-gradient-descent-880c60ac1be8)
수식
손실함수 L(w)L(w)가 있을 때 가중치 ww를 업데이트하는 공식은 다음과 같습니다.

Wnew=WoldηLwW_{new}= W_{old} - \eta \frac{\partial L}{\partial w}

W_new: 업데이트될 새로운 가중치
W_old: 현재 가중치
η (에타): 학습률(learning rate). 한 번에 얼마나 이동할지 보폭을 정하는 값입니다.
W/L∂W/∂L: 기울기(gradient). 현재 위치에서 손실이 가장 가파르게 변하는 방향과 크기입니다.
요약하면, 오차역전파는 경사 하강법에 필요한 '기울기'를 효율적으로 구하는 방법이며, 경사 하강법은 그 기울기를 사용해 매개변수를 최적화하는 방법입니다.

연쇄법칙

연쇄법칙(chain rule)은 합성 함수의 미분법으로, 여러 함수가 사슬처럼 연결되어 있을 때 각 함수의 미분 결과를 곱하여 최종 미분 값을 구하는 원리입니다
위 식은 zz 함수를 xx 에 대해 미분한 결과는 zz 함수를 y y 에 대해 미분한 결과와 yy 함수를 xx 에 대해 미분한 결과를 곱하여 구할 수 있다는 것이 핵심입니다.
연쇄법칙의 성질을 이용하여 손실함수 EEw7w7에 대해 미분을 하면 아래의 식과 같습니다.

Ew7=Eo1×o1zo1×zo1w7\frac{\partial E}{\partial w_7}=\frac{\partial E}{\partial o_1} \times \frac{\partial o_1}{\partial z_{o 1}} \times \frac{\partial z_{o 1}}{\partial_{w 7}}

손실함수의 값을 줄이기 위해 가중치를 갱신하는 과정을 간략하게 정리하면, 먼저 가중치의 초깃값들로 순방향 전파(forward pass)를 합니다.
그후 오차역전파를 통해 손실함수를 각 가중치에 대해 미분한 값을 구하여 그 미분값과 learningratelearning rate 와 -(마이너스) 부호를 곱하여 새로운 가중치로 갱신합니다.

W=WW=W- learningratelearning rate LW* \frac{\partial L}{\partial W}

역전파 구현하기

역전파 시 계산 노드(덧셈, 곱셈 등)는 어떻게 기울기를 전달할까요?
덧셈 노드 z = x + y
덧셈 노드의 역전파는 상류에서 들어온 미분 값을 그대로 하류로 흘려보냅니다.
z=x+yz=x+y 일 때 zz 에 대한 xx 의 미분 값은 11입니다. (yy도 마찬가지….).
어떤 값에 1을 곱하면 자기 자신이며 즉 뒤에서 들어온 미분 값을 변동 없이 그대로 전달하는 것입니다.
[그림] 덧셈일 때 역전파되어 흘러가는 값
역전파에서 덧셈 연산을 통과할 때 입력 값에 대해 변화율(기울기)이 그대로 전달되는 이유는 미분의 기본 성질 때문입니다.. 덧셈 연산이 있을 땐 이를 수식으로 나타내면 다음과 같습니다.

z=x+yz = x + y

이제 zz에 대한 각각의 입력 값 xxyy에 대한 편미분을 구하면 아래와 같이 됩니다.

zx=1,zy=1\frac{\partial z}{\partial x}=1, \quad \frac{\partial z}{\partial y}=1

곱셈 노드 z = x * y
z=xyz=xy 일 때 곱셈 노드에서 흘러가는 값은 상대 값을 곱해 주면 됩니다.
[그림] 곱셈일 때 역전파되어 흘러가는 값
곱셈 연산은 한 변수가 변할 때 결괏값이 상대방의 값만큼 영향을 받는 연산입니다.
예를 들어 x=2,y=3x=2, y=3 일 때 z=2×3=6z=2×3=6 입니다.
여기서 xx11 증가시켜서 33 이 되면 zz3×3=93×3=9로 변합니다.
즉 z의 증가량은 yy값인 33만큼 변합니다.
반대로, yy11 증가시켜서 44가 되면 zz2×4=82×4=8 이 됩니다.
zz의 증가량은 xx값인 22만큼 변합니다.
이 말은 곧, 입력 값이 변할 때 결괏값이 상대방의 값만큼 영향을 받기 때문에 역전파할 때도 상대방을 곱해 줘야 한다는 걸 의미합니다.
코드로 구현하면 아래와 같습니다.
class Add: def __init__(self): self.x = None self.y = None def forward(self, x, y): self.x = x self.y = y result = x + y return result def backward(self, d_result): dx = d_result # dz/dx = 1 dy = d_result # dz/dy = 1 return dx, dy class Mul: def __init__(self): self.x = None self.y = None def forward(self, x, y): self.x = x self.y = y result = x *y return result def backward(self, d_result): dx = d_result * self.y # dz/dx = y dy = d_result * self.x # dz/dy = x return dx, dy # --------------------------------- # 예제 실행: z = (x * y) + b # ---------------------------------- x, y, b = 2, 3, 1 # 입력값 # 레이어 생성 add_layer = Add() mul_layer = Mul() # 순전파 xy = mul_layer.forward(x, y) # x * y z = add_layer.forward(xy, b) #(x * y) + b print("Forward 결과:", z) # (2*3)+1 = 7 # 역전파 (dL/dz = 1 가정) dout = 1 dxy, db = add_layer.backward(dout) # dL/d(xy), dL/db dout = 1 dxy, db = add_layer.backward(dout) # dL/d(xy), dL/db dx, dy = mul_layer.backward(dxy) # dL/dx, dL/dy print("Backward 결과:") print("dx:", dx) # әz/әx = y = 3 print("dy:", dy) # әz/әy = x = 2 print("db:", db) # әz/ab = 1
Python
복사

시그모이드 함수의 오차역전파

시그모이드 함수 공식을 다시 보겠습니다.

σ(x)=11+ex\sigma(x)=\frac{1}{1+e^{-x}}

시그모이드의 미분은 자기 자신과 (1-자기 자신)의 곱으로 표현할 수 있습니다.

dσdx=σ(x)(1σ(x))\frac{d \sigma}{d x}=\sigma(x) \cdot(1-\sigma(x))

코드로는 다음과 같습니다.
class Sigmoid: def __init__(self): self.result = None # 순전파의 출력을 저장해 두었다가 역전파 계산 때 사용 def forward(self, x): result = sigmoid(x) self.result = result return result def backward(self, d_out): dx = d_out * (1.0 - self.result) * self.result
Python
복사
오차를 전달하는 역전파는 이처럼 명확한 수학적 계산을 통해 이루어집니다. 이 과정을 수없이 반복하면, 신경망의 가중치는 정답을 더 잘 출력하는 방향으로 점차 조정되어 갑니다.
다음에는 오차는 어떻게 값을 정할까? 에 대해 살펴보도록 하겠습니다.
인공지능 수학 3탄도 기대해 주세요~^^