Level 2: 수학 기초
📐

Level 2

미분의 기초

경사하강법 완벽 정리

4분 30초
미분의 기초 강의 영상
강의 영상 보기 (새 탭에서 재생)YouTube

학습 내용

미분의 기초

학습 목표

이 레슨을 완료하면:

  • 미분이 "변화율"이라는 것을 일상 비유로 설명할 수 있습니다
  • 기본 미분 공식을 적용하고 Python으로 검증할 수 있습니다
  • 함수와 도함수를 나란히 그래프로 그릴 수 있습니다
  • 경사하강법의 원리를 이해하고 Python으로 직접 시뮬레이션할 수 있습니다
  • 학습률이 학습에 미치는 영향을 시각적으로 확인할 수 있습니다

핵심 메시지

"미분을 이해하면 AI가 어떻게 스스로 학습하는지 알 수 있습니다!" 미분은 "지금 이 순간 얼마나 빠르게 변하고 있는가"를 알려주는 도구이고, AI는 이것을 사용해서 스스로 똑똑해집니다.


1. 미분이란? - 변화율 이야기

비유: 자동차 속도계

고속도로에서 자동차를 운전한다고 상상해보세요.

  • 위치: 내가 지금 어디에 있는가 (서울에서 100km 지점)
  • 속도: 위치가 얼마나 빠르게 변하고 있는가 (시속 80km)

속도는 위치의 변화율입니다. 그리고 이 변화율을 구하는 것이 바로 미분입니다!

일상 용어수학 용어의미
위치함수 f(x)현재 상태
속도도함수 f'(x)변화율 (미분한 결과)
"지금 얼마나 빠른가?""이 점에서 기울기는?"같은 질문!

더 쉽게 말하면:

  • 온도가 올라가는 중이면 → 변화율은 양수 (+)
  • 온도가 내려가는 중이면 → 변화율은 음수 (-)
  • 온도가 안 변하면 → 변화율은 0

접선의 기울기 = 미분값

곡선 위의 한 점에 자를 대면 접선(살짝 닿는 직선)을 그릴 수 있습니다. 이 접선의 기울기가 바로 그 점에서의 미분값입니다.

접선의 기울기의미함수 상태
양수 (+)오른쪽 위로 올라감증가하는 중
음수 (-)오른쪽 아래로 내려감감소하는 중
0수평 (평평함)꼭대기 또는 바닥!

실행해보기: 미분의 의미를 눈으로 확인

python
import numpy as np import matplotlib.pyplot as plt # 함수: f(x) = x^2 def f(x): return x ** 2 x = np.linspace(-3, 3, 200) y = f(x) plt.figure(figsize=(8, 6)) plt.plot(x, y, 'b-', linewidth=2, label='f(x) = x^2') # 세 점에서의 접선 그리기 points = [-2, 0, 1.5] colors = ['red', 'green', 'orange'] for pt, color in zip(points, colors): slope = 2 * pt # f'(x) = 2x y_pt = f(pt) # 접선: y - y_pt = slope * (x - pt) x_tan = np.linspace(pt - 1.5, pt + 1.5, 50) y_tan = slope * (x_tan - pt) + y_pt plt.plot(x_tan, y_tan, '--', color=color, linewidth=2, label=f'tangent at x={pt} (slope={slope})') plt.plot(pt, y_pt, 'o', color=color, markersize=8) plt.axhline(y=0, color='gray', linewidth=0.5) plt.axvline(x=0, color='gray', linewidth=0.5) plt.ylim(-2, 10) plt.xlabel('x') plt.ylabel('f(x)') plt.title('Derivative = Tangent Line Slope') plt.legend() plt.grid(True, alpha=0.3) plt.tight_layout() plt.show() print('tangent slope at each point:') print(f' x=-2: slope = 2*(-2) = -4 (decreasing)') print(f' x= 0: slope = 2*( 0) = 0 (minimum!)') print(f' x=1.5: slope = 2*(1.5)= 3 (increasing)')

2. 기본 미분 공식

미분에는 규칙이 있습니다. 모든 것을 외울 필요 없이 핵심 패턴만 알면 됩니다.

핵심 미분 규칙

원래 함수 f(x)미분 결과 f'(x)예시
x^nn * x^(n-1)x^3 -> 3x^2
x^22xx=3일 때 기울기=6
x1항상 기울기 1 (직선)
상수 (예: 5)0변하지 않으므로 변화율 0
e^xe^x (자기 자신!)미분해도 변하지 않는 신기한 함수
a * f(x)a * f'(x)3x^2 -> 3*2x = 6x

가장 중요한 규칙: x^n을 미분하면 지수를 앞으로 내리고, 지수를 1 줄인다

실행해보기: 수치 미분으로 검증하기

수학 공식 없이도, 아주 작은 간격으로 기울기를 계산하면 미분값을 구할 수 있습니다. 이것을 수치 미분이라고 합니다.

python
import numpy as np def f(x): return x ** 2 def numerical_derivative(f, x, h=0.0001): """아주 작은 간격 h로 기울기를 구합니다""" return (f(x + h) - f(x - h)) / (2 * h) print('f(x) = x^2 numerical vs analytical derivative:') print(f'{"x":>5} | {"numerical f(x)":>18} | {"analytical 2x":>16} | {"match?":>8}') print('-' * 60) for x_val in [-3, -2, -1, 0, 1, 2, 3]: num = numerical_derivative(f, x_val) ana = 2 * x_val match = 'O' if abs(num - ana) < 0.001 else 'X' print(f'{x_val:5.1f} | {num:18.6f} | {ana:16.6f} | {match:>8}') print() print('numerical derivative is useful because:') print(' - no formula needed (just compute slope)') print(' - works with any function') print(' - this is how computers calculate derivatives!')

3. 함수와 도함수를 나란히 보기

함수 f(x)와 그 미분인 f'(x)를 나란히 그리면, 미분의 의미가 직관적으로 이해됩니다.

실행해보기: f(x) = x^3 - 3x 와 도함수

python
import numpy as np import matplotlib.pyplot as plt x = np.linspace(-2.5, 2.5, 200) # 원래 함수와 도함수 f = x**3 - 3*x # f(x) = x^3 - 3x f_prime = 3*x**2 - 3 # f'(x) = 3x^2 - 3 fig, axes = plt.subplots(2, 1, figsize=(8, 8), sharex=True) # 위: 원래 함수 axes[0].plot(x, f, 'b-', linewidth=2) axes[0].axhline(y=0, color='gray', linewidth=0.5) axes[0].set_ylabel('f(x)') axes[0].set_title('Original: f(x) = x^3 - 3x') axes[0].grid(True, alpha=0.3) # 극값 표시 axes[0].plot(-1, 2, 'ro', markersize=10) axes[0].plot(1, -2, 'ro', markersize=10) axes[0].annotate('local max', xy=(-1, 2), xytext=(-2, 3), arrowprops=dict(arrowstyle='->'), fontsize=11) axes[0].annotate('local min', xy=(1, -2), xytext=(2, -3), arrowprops=dict(arrowstyle='->'), fontsize=11) # 아래: 도함수 axes[1].plot(x, f_prime, 'r-', linewidth=2) axes[1].axhline(y=0, color='gray', linewidth=0.5) axes[1].fill_between(x, f_prime, 0, where=(f_prime > 0), alpha=0.1, color="green", label="f'(x)>0: increasing") axes[1].fill_between(x, f_prime, 0, where=(f_prime < 0), alpha=0.1, color="red", label="f'(x)<0: decreasing") axes[1].set_xlabel("x") axes[1].set_ylabel("f'(x)") axes[1].set_title("Derivative: f'(x) = 3x^2 - 3") axes[1].legend() axes[1].grid(True, alpha=0.3) # 도함수=0인 점 표시 axes[1].plot([-1, 1], [0, 0], 'ro', markersize=10) axes[1].annotate('slope=0\n(extremum!)', xy=(-1, 0), xytext=(-2, 5), arrowprops=dict(arrowstyle='->'), fontsize=10) plt.tight_layout() plt.show() print("Key observations:") print(" - Where f'(x) = 0 -> f(x) has max or min") print(" - Where f'(x) > 0 -> f(x) is going up") print(" - Where f'(x) < 0 -> f(x) is going down")

핵심: 도함수가 0인 지점이 바로 원래 함수의 최댓값 또는 최솟값입니다. AI는 이 성질을 이용해서 손실이 최소인 지점을 찾습니다!


4. 경사하강법: AI가 학습하는 원리

비유: 눈을 가리고 산에서 내려오기

당신이 눈을 가린 채 산꼭대기에 있다고 상상해보세요. 가장 낮은 곳(계곡)까지 내려가야 합니다.

어떻게 할까요?

  1. 발로 바닥을 더듬어 어느 쪽이 내리막인지 느낀다 (= 기울기 계산 = 미분!)
  2. 내리막 방향으로 한 발짝 이동한다 (= 기울기 반대 방향으로 이동)
  3. 반복한다 (= 여러 번의 학습 step)

이것이 바로 **경사하강법(Gradient Descent)**입니다!

핵심 공식

w_new = w_old - learning_rate * gradient

요소의미산 비유
w (가중치)AI가 학습하는 값현재 위치
learning_rate (학습률)한 번에 얼마나 이동?발걸음 크기
gradient (기울기)미분으로 계산한 방향바닥을 더듬은 결과
- (마이너스)반대 방향으로!내리막으로 가기 위해

🔬 실습: 경사하강법 단계별 시뮬레이션

AI가 실제로 어떻게 학습하는지 단계별로 확인해봅시다.

python
import numpy as np import matplotlib.pyplot as plt # ═══════════════════════════════════════════════════════════════ # 📊 경사하강법(Gradient Descent) 시뮬레이션 # 목표: 손실 함수의 최솟값(w=0)을 찾아가기 # ═══════════════════════════════════════════════════════════════ # 📐 손실 함수 정의: L(w) = w² (포물선 모양) # 최솟값은 w=0일 때 Loss=0 def loss(w): return w ** 2 def loss_gradient(w): return 2 * w # 📝 미분: dL/dw = 2w # ───────────────────────────────────────────────────────────────── # 🚀 경사하강법 실행 # ───────────────────────────────────────────────────────────────── w = 4.0 # 🎯 시작 위치 (산 중턱) learning_rate = 0.15 # 👣 발걸음 크기 history = [w] print("🏔️ 경사하강법 시뮬레이션 - 손실 최솟값 찾아가기") print("=" * 65) print(f'{"Step":>4} | {"위치(w)":>10} | {"손실":>10} | {"기울기":>10} | {"이동량":>10}') print("-" * 65) for step in range(15): grad = loss_gradient(w) # 📐 현재 위치의 기울기 계산 update = learning_rate * grad # 👣 이동할 거리 계산 print(f'{step:4d} | {w:10.4f} | {loss(w):10.4f} | {grad:10.4f} | {-update:10.4f}') w = w - update # ⬇️ 기울기 반대 방향으로 이동! history.append(w) print("-" * 65) print(f'{"완료":>4} | {w:10.4f} | {loss(w):10.4f} | 🎉 최솟값 도달!') # ───────────────────────────────────────────────────────────────── # 📈 시각화: 학습 과정을 그래프로 확인 # ───────────────────────────────────────────────────────────────── fig, axes = plt.subplots(1, 2, figsize=(14, 5)) # 📊 왼쪽 그래프: 손실 곡선 위의 이동 경로 w_range = np.linspace(-5, 5, 200) axes[0].plot(w_range, loss(w_range), 'b-', linewidth=2, label='Loss function L(w) = w²') history_arr = np.array(history) axes[0].plot(history_arr, loss(history_arr), 'ro-', markersize=8, label='Learning path') axes[0].plot(history_arr[0], loss(history_arr[0]), 'g*', markersize=20, label='Start point') axes[0].plot(0, 0, 'b*', markersize=15, label='Target (minimum)') axes[0].set_xlabel('Weight w', fontsize=12) axes[0].set_ylabel('Loss', fontsize=12) axes[0].set_title('Loss Curve: Descending to Minimum', fontsize=14) axes[0].legend(fontsize=10) axes[0].grid(True, alpha=0.3) # 📊 오른쪽 그래프: 학습 단계별 손실 감소 loss_history = [loss(w) for w in history] axes[1].plot(range(len(history)), loss_history, 'r-o', markersize=6, linewidth=2) axes[1].fill_between(range(len(history)), loss_history, alpha=0.3, color='red') axes[1].set_xlabel('Training Step', fontsize=12) axes[1].set_ylabel('Loss', fontsize=12) axes[1].set_title('Loss Decreases During Training', fontsize=14) axes[1].grid(True, alpha=0.3) plt.tight_layout() plt.show()

💡 핵심 포인트: w가 점점 0에 가까워지고, 손실도 점점 줄어듭니다!

  • 왼쪽 그래프: 산을 내려오듯이 최솟값으로 이동
  • 오른쪽 그래프: 학습할수록 손실(오차)가 감소

이것이 바로 AI가 학습하는 원리입니다!


5. 학습률의 중요성

학습률(learning rate)은 한 번에 얼마나 크게 이동할지를 결정합니다. 이 값을 잘 설정하는 것이 매우 중요합니다.

학습률결과산 비유
너무 크면최솟값을 지나쳐서 발산점프가 너무 커서 계곡을 넘어감
너무 작으면수렴은 하지만 너무 느림한 발짝이 너무 작아서 평생 걸림
적당하면빠르고 안정적으로 수렴적당한 걸음으로 계곡 도착!

실행해보기: 학습률 비교 (너무 큼 vs 적당함 vs 너무 작음)

python
import numpy as np import matplotlib.pyplot as plt def loss(w): return w ** 2 def gradient(w): return 2 * w def run_gradient_descent(start_w, lr, steps): w = start_w history = [w] for _ in range(steps): w = w - lr * gradient(w) history.append(w) return history start_w = 4.0 steps = 20 # 세 가지 학습률 configs = [ (0.01, 'too small (lr=0.01)', 'blue'), (0.15, 'just right (lr=0.15)', 'green'), (0.9, 'too large (lr=0.9)', 'red'), ] fig, axes = plt.subplots(1, 3, figsize=(15, 5)) for idx, (lr, label, color) in enumerate(configs): history = run_gradient_descent(start_w, lr, steps) # 손실 함수 곡선 w_range = np.linspace(-6, 6, 200) axes[idx].plot(w_range, loss(w_range), 'gray', linewidth=1, alpha=0.5) # 이동 경로 h = np.array(history[:steps+1]) axes[idx].plot(h, loss(h), 'o-', color=color, markersize=5, linewidth=1.5) axes[idx].plot(h[0], loss(h[0]), 'k*', markersize=12) axes[idx].set_title(label, fontsize=13, fontweight='bold') axes[idx].set_xlabel('w') axes[idx].set_ylabel('Loss') axes[idx].set_ylim(-2, 30) axes[idx].grid(True, alpha=0.3) final_loss = loss(history[-1]) axes[idx].text(0.05, 0.95, f'final loss={final_loss:.4f}', transform=axes[idx].transAxes, fontsize=10, verticalalignment='top', bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5)) plt.suptitle('Learning Rate Comparison', fontsize=14, fontweight='bold') plt.tight_layout() plt.show() print('Summary:') for lr, label, _ in configs: h = run_gradient_descent(start_w, lr, steps) print(f' {label}: final w={h[-1]:.6f}, final loss={loss(h[-1]):.6f}')

학습률 0.9는 최솟값 주위를 왔다갔다하면서 불안정합니다. 0.01은 안정적이지만 너무 느립니다. 0.15가 빠르면서도 안정적으로 수렴합니다. 실제 딥러닝에서는 보통 0.001 ~ 0.01 범위에서 시작합니다.


6. 더 복잡한 함수에서의 경사하강법

실제 AI의 손실 함수는 단순한 w^2가 아니라 울퉁불퉁한 모양입니다. 그래도 원리는 동일합니다.

실행해보기: 울퉁불퉁한 손실 함수에서의 경사하강법

python
import numpy as np import matplotlib.pyplot as plt # 좀 더 복잡한 손실 함수 def complex_loss(w): return w**4 - 8*w**2 + 2*w + 20 def complex_gradient(w): return 4*w**3 - 16*w + 2 # derivative w = -3.5 # 시작점 lr = 0.01 history = [(w, complex_loss(w))] for _ in range(100): grad = complex_gradient(w) w = w - lr * grad history.append((w, complex_loss(w))) history = np.array(history) plt.figure(figsize=(10, 5)) w_range = np.linspace(-4, 4, 300) plt.plot(w_range, complex_loss(w_range), 'b-', linewidth=2, label='Loss function') plt.plot(history[:, 0], history[:, 1], 'ro-', markersize=3, alpha=0.7, label='GD path') plt.plot(history[0, 0], history[0, 1], 'g*', markersize=15, label='start') plt.plot(history[-1, 0], history[-1, 1], 'r*', markersize=15, label='end') plt.xlabel('w') plt.ylabel('Loss') plt.title('Gradient Descent on Complex Loss') plt.legend() plt.grid(True, alpha=0.3) plt.tight_layout() plt.show() print(f'Start: w={history[0,0]:.2f}, loss={history[0,1]:.2f}') print(f'End: w={history[-1,0]:.4f}, loss={history[-1,1]:.4f}') print() print('Note: depending on start, GD may find a LOCAL minimum,') print('not the GLOBAL minimum. This is a real challenge in AI!')

AI와의 연결: 신경망의 손실 함수에는 수많은 "지역 최솟값(local minimum)"이 있습니다. 시작점에 따라 다른 결과가 나올 수 있어요. 이것이 딥러닝에서 가중치 초기화와 학습률이 중요한 이유입니다.


7. 왜 이것이 중요한가? - AI 학습의 전체 그림

지금까지 배운 것을 종합하면:

  1. 신경망은 입력을 받아 예측을 출력하는 거대한 함수입니다
  2. 손실 함수가 예측이 얼마나 틀렸는지 알려줍니다 (2차함수처럼 생겼어요)
  3. 미분으로 손실 함수의 기울기를 구합니다
  4. 경사하강법으로 기울기 반대 방향으로 가중치를 업데이트합니다
  5. 학습률이 한 번에 얼마나 움직일지 결정합니다
  6. 이 과정을 수천~수만 번 반복하면 → AI가 점점 똑똑해집니다!

이것이 바로 모든 AI 학습의 핵심 원리입니다.


핵심 요약

개념설명AI에서의 역할
미분변화율 (접선의 기울기)손실 함수의 기울기 계산
수치 미분작은 간격으로 기울기 근사컴퓨터가 미분을 계산하는 방법
도함수미분 결과 함수기울기가 0인 곳 = 극값
경사하강법기울기 반대 방향으로 이동AI 학습의 핵심 알고리즘
학습률이동 크기 결정너무 크면 발산, 너무 작으면 느림

학습 체크리스트

  • 미분이 "변화율"이라는 것을 자동차 속도 비유로 설명할 수 있다
  • x^2를 미분하면 2x, x^3를 미분하면 3x^2임을 안다
  • 수치 미분의 원리를 이해하고 Python으로 구현할 수 있다
  • 경사하강법이 왜 기울기의 "반대" 방향으로 이동하는지 설명할 수 있다
  • 학습률이 너무 크거나 작으면 어떤 문제가 생기는지 시각적으로 확인했다
  • w = w - learning_rate * gradient 공식을 이해한다

다음 강의 예고

"편미분" - 변수가 여러 개일 때 각각에 대해 미분하는 방법! 신경망의 수백만 파라미터를 동시에 학습시키는 핵심입니다.

레슨 정보

레벨
Level 2: 수학 기초
예상 소요 시간
4분 30초
참고 영상
YouTube 링크

💡실습 환경 안내

코드 블록의 ▶ 실행 버튼을 누르면 브라우저에서 바로 Python을 실행할 수 있습니다.

별도 설치 없이 NumPy, Matplotlib 등 기본 라이브러리를 사용할 수 있습니다.