🚨cs231n 2017 강의를 듣고 작성하였습니다.
🚨해당 게시글에 포함된 이미지 중 출처가 쓰여있지 않은 이미지는 모두 직접 그렸습니다.
4.1. Motivation
classifier를 정의할 때를 떠올려보자.

함수 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를 예로 들어 생각해보자.

곱셈 노드를 통해 파라미터 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로 나타내면 아래와 같다.

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를 나타내면 아래와 같다.

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

backpropagation은 굉장히 지역적인(local) 프로세스이다.
위 그림을 보면 알 수 있듯이, 입력을 받아들이면 두 가지 값을 계산할 수 있다.
(1) 게이트의 출력 값, (2) 게이트 출력에 대한 입력들의 local gradient 값
그리고 forward pass가 끝나면, backward pass를 수행한다.
backpropagation 과정에서 전체 회로의 마지막 출력에 대한 게이트 출력의 그라디언트 값을 알 수 있고, 연쇄 법칙을 통해 게이트는 이 그라디언트 값을 받아들여 모든 입력에 대한 그라디언트 값을 구할 수 있게 된다.
위에서 구한 예시를 통해 직관적으로 다시 이해해보자.

덧셈 게이트는 입력 [-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로 나타내면 아래와 같다.

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

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

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

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

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

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

4.7. 벡터 기반의 그라디언트 계산
변수가 만약 스칼라가 아닌 벡터라면, gradient는 Jacobian 행렬이 된다.

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

입력과 출력이 위와 같은 4096차원의 벡터이라고 하자.
주어진 함수 f는 요소별로 최대값을 가진다.
이 경우에 Jacobian 행렬의 사이즈는 4096*4096이 된다.
Jacobian 행렬의 각 행은 입력에 대한 출력의 편미분이 된다.

max니까 f에 대한 L의 gradient와 x에 대한 L의 그라디언트가 같아야한다.(∂L/∂f=∂L/∂x)
즉, 행렬을 통해 곱해지는 값이 1이다.
이때 Jacobian 행렬은 대각행렬이어야하고, 단위행렬이어야한다.(대각성분 모두 1)

x와 W에 대한 함수 f는 x에 의해 곱해진 W의 L2와 같다.
이 경우 x는 n차원, W는 n*n차원이라 하자.
x와 W의 값이 다음과 같이 주어져있다.

곱셈 노드를 q라고 하자. 그러면 q=W*x이다.
즉, 아래와 같이 나타낼 수 있다.

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

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

W에 대한 f의 gradient는 곱셈 노드에서 gradient를 구했던 방식대로 x와 q의 gradient를 곱하면 된다.
x에 대한 f의 gradient는 위와 마찬가지로 W와 q의 gradient를 곱하면 된다.
따라서 모든 gradient값을 구했다.


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
'ML,DL' 카테고리의 다른 글
| [cs231n] 신경망 파트 2 : 데이터 준비 및 Loss (0) | 2026.02.04 |
|---|---|
| [cs231n] 신경망 파트 1 : 네트워크 구조 정하기 (0) | 2026.02.03 |
| [cs231n] 최적화 : 확률 그라디언트 하강(Stochastic Gradient Descent) (0) | 2026.02.01 |
| [cs231n] 선형 분류 : Support Vector Machine, Softmax (0) | 2026.01.31 |
| [cs231n] 이미지 분류 : 데이터 기반 방법론, k-Nearest Neighbor, train/val/test 구분 (0) | 2026.01.30 |