ML,DL

[cs231n] Backpropagation, 직관

yeeunnnn 2026. 2. 2. 23:32

🚨cs231n 2017 강의를 듣고 작성하였습니다.

🚨해당 게시글에 포함된 이미지 중 출처가 쓰여있지 않은 이미지는 모두 직접 그렸습니다.

 

4.1. Motivation

classifier를 정의할 때를 떠올려보자.

출처 : https://cs231n.stanford.edu/

 

함수 f가 weights W를 파라미터로 가지고 있다.

데이터 x가 입력(input)이고, 분류하고자하는 클래스들에 대한 score vector가 출력(output)이다.

SVM loss function을 예로 들면 total loss를 통해 얼마나 W가 좋지 않은지를 알 수 있다.

최적의 loss를 갖게 하는 파라미터 W를 찾고 싶으므로, loss function의 W에 관한 gradient를 찾는다.

gradient를 구할 때 유한 차분 근사, analytic gradient 등을 통해 계산할 수 있었다.

여기에서는 임의의 복잡한 함수를 통해 analytic gradient를 계산하는 방법에 대해 공부해보자.


4.2. 그라디언트(Gradient)에 대한 간단한 표현과 이해

1차원 함수의 경우, 기울기는 함수값의 순간증가율을 나타낸다.

그라디언트(gradient) ∇f(x)는 이 기울기를 변수 하나가 아니라 여러 개인 경우로, 입력 데이터 공간의 각 차원에 해당하는 기울기들의 벡터이다.

함수가 숫자 하나가 아닌 벡터를 입력으로 받는 경우 우리는 미분을 편미분이라고 부르고, 그라디언트는 단순히 각 차원으로의 편미분들을 모아놓은 벡터이다.


4.3. Computational graph

임의의 복잡한 함수를 통해 analytic gradient를 계산하기 위해서는 Computational graph라고 부르는 프레임워크를 사용하면 된다.

이 그래프를 이용하여 어떤 함수든지 표현할 수 있고, 그래프의 각 노드는 연산 단계를 나타낸다.

선형 classifier를 예로 들어 생각해보자.

출처 : https://cs231n.stanford.edu/

 

곱셈 노드를 통해 파라미터 W와 입력 데이터 x의 행렬의 곱셈을 계산한 뒤, hinge loss라는 노드를 계산한다.

정규화항 R을 구하는 노드를 통해 정규화항을 계산한다.

덧셈 노드를 통해 두 값을 더하여 최종 loss를 구한다.


4.4. 복합 표현식(Compound Expression), 연쇄 법칙(Chain rule), Backpropagation

Backpropagation은 네트워크 전체에 대해 반복적인 연쇄법칙(Chain rule)을 적용하여 그라디언트를 계산하는 방법 중 하나이다.

 

f(x,y,z)=(x+y)z로 정의된 함수 f가 있다. x=-2, y=5, z=-4라 할 때, f를 computational graph로 나타내면 아래와 같다.

출처 : https://cs231n.stanford.edu/

x+y를 계산하는 덧셈 노드를 q라고 하면, q=x+y,f=q*z 라는 식을 구할 수 있다.

x와 y 각각에 대한 q의 gradient는 ∂q/∂x=1,∂q/∂y=1로, q와 z 각각에 대한 f의 gradient는 ∂f/∂q=z,∂f/∂z=q로 나타낼 수 있다.

우리가 구하고자 하는 것은 ∂f/∂x,∂f/∂y,∂f/∂z이다.

연쇄 법칙(chain rule)을 이용하여 각각을 구해보자.

 

따라서, computational graph에 각각의 gradient를 나타내면 아래와 같다.

출처 : https://cs231n.stanford.edu/

 


4.5. Backpropagation에 대한 직관적인 이해

출처 : https://cs231n.stanford.edu/

backpropagation은 굉장히 지역적인(local) 프로세스이다.

위 그림을 보면 알 수 있듯이, 입력을 받아들이면 두 가지 값을 계산할 수 있다.

(1) 게이트의 출력 값, (2) 게이트 출력에 대한 입력들의 local gradient 값

그리고 forward pass가 끝나면, backward pass를 수행한다.

backpropagation 과정에서 전체 회로의 마지막 출력에 대한 게이트 출력의 그라디언트 값을 알 수 있고, 연쇄 법칙을 통해 게이트는 이 그라디언트 값을 받아들여 모든 입력에 대한 그라디언트 값을 구할 수 있게 된다.

 

위에서 구한 예시를 통해 직관적으로 다시 이해해보자.

출처 : https://cs231n.stanford.edu/

덧셈 게이트는 입력 [-2,5]를 받아 3을 출력한다. 이때, 두 입력에 대한 게이트의 지역적 그라이언트 값은 1이 된다.

곱셈 게이트는 입력 [3,-4]를 받아 -12를 출력한다. 따라서, 최종 출력값은 12이다.

backward pass에서 마지막 출력에 대한 그라디언트 값은 1임을 알 수 있고, 덧셈 게이트는 출력 값에 대한 그라디언트 값이 -4임을 알 수있다.

따라서 모든 입력에 대한 그라디언트 값을 연쇄 법칙을 통해 구할 수 있다.

4.5.1. 모듈성 : 시그모이드(Sigmoid) 예제

아래의 주어진 식은 시그모이드 활성 함수를 사용하는 2차원 뉴런을 나타낸다.

w0=2.00, x0=-1.00, w1=-3.00, x1=-2.00, w2=-3.00이라 하자.

이 식을 computational graph로 나타내면 아래와 같다.

출처 : https://cs231n.stanford.edu/

또한, backpropagation 과정을 시행할 때 이용하는 각 게이트들에 대한 식은 아래와 같다.

따라서, 아래와 같이 한 스텝씩 묶어 각각의 gradient를 구해보자.

따라서 모든 입력의 gradient를 구할 수 있고 아래와 같이 나타낼 수 있다.

출처 : https://cs231n.stanford.edu/

4.5.2. 시그모이드 함수(sigmoid function)

시그모이드 함수와 그의 미분은 아래와 같이 나타낼 수 있다.

따라서 위에 주어진 예제를 아래와 같이 나타낼 수 있다.

출처 : https://cs231n.stanford.edu/


4.6. 역방향 흐름의 패턴(Patterns in backward flow)

출처 : https://cs231n.stanford.edu/


4.7. 벡터 기반의 그라디언트 계산

변수가 만약 스칼라가 아닌 벡터라면, gradient는 Jacobian 행렬이 된다.

출처 : https://cs231n.stanford.edu/

그래서 이것들은 X의 각 원소에 대해 Z에 대한 미분을 포함하는 행렬이 될 것이다.

출처 : https://cs231n.stanford.edu/

입력과 출력이 위와 같은 4096차원의 벡터이라고 하자.

주어진 함수 f는 요소별로 최대값을 가진다.

이 경우에 Jacobian 행렬의 사이즈는 4096*4096이 된다.

Jacobian 행렬의 각 행은 입력에 대한 출력의 편미분이 된다.

max니까 f에 대한 L의 gradient와 x에 대한 L의 그라디언트가 같아야한다.(∂L/∂f=∂L/∂x)

즉, 행렬을 통해 곱해지는 값이 1이다.

이때 Jacobian 행렬은 대각행렬이어야하고, 단위행렬이어야한다.(대각성분 모두 1)

출처 : https://cs231n.stanford.edu/

x와 W에 대한 함수 f는 x에 의해 곱해진 W의 L2와 같다.

이 경우 x는 n차원, W는 n*n차원이라 하자.

x와 W의 값이 다음과 같이 주어져있다.

출처 : https://cs231n.stanford.edu/

곱셈 노드를 q라고 하자. 그러면 q=W*x이다.

즉, 아래와 같이 나타낼 수 있다.

qi에 대한 f의 gradient를 구하면 아래와 같고 q벡터에 대한 f의 gradient를 구할 수 있다.

그리고 gradient값을 computational graph에서 보자.

출처 : https://cs231n.stanford.edu/

W에 대한 f의 gradient는 곱셈 노드에서 gradient를 구했던 방식대로 x와 q의 gradient를 곱하면 된다.

x에 대한 f의 gradient는 위와 마찬가지로 W와 q의 gradient를 곱하면 된다.

따라서 모든 gradient값을 구했다.

출처 : https://cs231n.stanford.edu/


4.8. 실제 backprop : 단계적 계산

다음과 같은 형태의 함수가 있다고 하자.

위에 주어진 함수에 대하여 forward pass를 구조화하면 아래와 같다.

x = 3 #example values
y = -4

#forward pass
sigy = 1.0 \\ (1 + math.exp(-y)) #sigmoid in numerator    #(1)
num = x + sigy # numerator                               #(2)
sigx = 1.0 / (1 + math.exp(-x)) # sigmoid in denominator #(3)
xpy = x + y                                              #(4)
xpysqr = xpy**2                                          #(5)
den = sigx + xpysqr # denominator                        #(6)
invden = 1.0 / den                                       #(7)
f = num * invden # done!                                 #(8)

backprop 전달을 구조화하면 아래와 같다.

# backprop f = num * invden
dnum = invden # gradient on numerator                             #(8)
dinvden = num                                                     #(8)
# backprop invden = 1.0 / den
dden = (-1.0 / (den**2)) * dinvden                                #(7)
# backprop den = sigx + xpysqr
dsigx = (1) * dden                                                #(6)
dxpysqr = (1) * dden                                              #(6)
# backprop xpysqr = xpy**2
dxpy = (2 * xpy) * dxpysqr                                        #(5)
# backprop xpy = x + y
dx = (1) * dxpy                                                   #(4)
dy = (1) * dxpy                                                   #(4)
# backprop sigx = 1.0 / (1 + math.exp(-x))
dx += ((1 - sigx) * sigx) * dsigx # Notice += !! See notes below  #(3)
# backprop num = x + sigy
dx += (1) * dnum                                                  #(2)
dsigy = (1) * dnum                                                #(2)
# backprop sigy = 1.0 / (1 + math.exp(-y))
dy += ((1 - sigy) * sigy) * dsigy                                 #(1)
# done! phew