Commit 00587836 authored by insun park's avatar insun park
Browse files

Update lecture materials: Enhance AI course content with new sections on...

Update lecture materials: Enhance AI course content with new sections on FastAPI model serving, advanced RAG techniques, and AI agents, while improving formatting and structure for better readability.
parent 07914407
# 인공지능의 역사: 개념의 진화 ---
marp: true
theme: gaia
class:
- lead
- invert
---
<!-- _class: lead -->
<!-- _header: "" -->
<!-- _footer: "" -->
<style>
h1 {
font-size: 2.5em;
font-weight: 600;
}
h2 {
font-size: 2em;
font-weight: 600;
}
h3 {
font-size: 1.6em;
font-weight: 600;
}
h4 {
font-size: 1.3em;
font-weight: 600;
}
h5 {
font-size: 1.1em;
font-weight: 600;
}
h6 {
font-size: 1em;
font-weight: 600;
}
p, li, ul, ol, table {
font-size: 28px;
}
pre, code {
font-size: 24px;
}
</style>
# Part 0.1: AI의 역사와 주요 이정표
## 서론: 생각하는 기계라는 오랜 꿈 ## 서론: 생각하는 기계라는 오랜 꿈
...@@ -143,4 +188,9 @@ ...@@ -143,4 +188,9 @@
인공지능의 역사는 낙관과 절망, 경쟁과 협력이 교차하는 거대한 서사시입니다. 뇌를 모방하려던 작은 아이디어에서 시작해, 두 번의 겨울을 거치며 패러다임을 전환했고, 마침내 데이터와 컴퓨팅 파워를 만나 딥러닝 혁명을 이루었습니다. 현재 우리는 AI가 인간의 지능과 창의성을 어떻게 확장시킬 수 있는지 목격하는 새로운 시대의 출발점에 서 있습니다. 인공지능의 역사는 낙관과 절망, 경쟁과 협력이 교차하는 거대한 서사시입니다. 뇌를 모방하려던 작은 아이디어에서 시작해, 두 번의 겨울을 거치며 패러다임을 전환했고, 마침내 데이터와 컴퓨팅 파워를 만나 딥러닝 혁명을 이루었습니다. 현재 우리는 AI가 인간의 지능과 창의성을 어떻게 확장시킬 수 있는지 목격하는 새로운 시대의 출발점에 서 있습니다.
--- ---
*이 문서는 [IBM의 AI 역사](https://www.ibm.com/think/topics/history-of-artificial-intelligence) 등 여러 AI 역사 관련 자료를 참고하여 개념의 흐름을 중심으로 재구성되었습니다.* *이 문서는 [IBM의 AI 역사](https://www.ibm.com/think/topics/history-of-artificial-intelligence) 등 여러 AI 역사 관련 자료를 참고하여 개념의 흐름을 중심으로 재구성되었습니다.*
\ No newline at end of file
---
**⬅️ 이전 시간: [Part 0: 시작하며 - AI 전문가 양성 과정](./part_0_introduction.md)**
**➡️ 다음 시간: [Part 1: AI 개발 환경 준비](../01_ai_development_environment/part_1_ai_development_environment.md)**
\ No newline at end of file
# Part 1: AI 개발 환경 완벽 구축 가이드 ---
marp: true
theme: gaia
class:
- lead
- invert
---
**⬅️ 이전 시간: [Part 0: 시작하며](../00_introduction/part_0_introduction.md)** <!-- _class: lead -->
<!-- _header: "" -->
<!-- _footer: "" -->
<style>
h1 {
font-size: 2.5em;
font-weight: 600;
}
h2 {
font-size: 2em;
font-weight: 600;
}
h3 {
font-size: 1.6em;
font-weight: 600;
}
h4 {
font-size: 1.3em;
font-weight: 600;
}
h5 {
font-size: 1.1em;
font-weight: 600;
}
h6 {
font-size: 1em;
font-weight: 600;
}
p, li, ul, ol, table {
font-size: 28px;
}
pre, code {
font-size: 24px;
}
</style>
# Part 1: AI 개발 환경 설정
**⬅️ 이전 시간: [인공지능의 역사](../00_introduction/part_0.1_history_of_ai.md)**
**➡️ 다음 시간: [Part 2: 파이썬 핵심 문법](../02_python_core_syntax/part_2_python_core_syntax.md)** **➡️ 다음 시간: [Part 2: 파이썬 핵심 문법](../02_python_core_syntax/part_2_python_core_syntax.md)**
--- ---
...@@ -570,5 +615,5 @@ Hacker News 커뮤니티와 실제 개발자들의 경험을 바탕으로 한 ...@@ -570,5 +615,5 @@ Hacker News 커뮤니티와 실제 개발자들의 경험을 바탕으로 한
--- ---
**⬅️ 이전 시간: [Part 0: 시작하며](../00_introduction/part_0_introduction.md)** **⬅️ 이전 시간: [인공지능의 역사](../00_introduction/part_0.1_history_of_ai.md)**
**➡️ 다음 시간: [Part 2: 파이썬 핵심 문법](../02_python_core_syntax/part_2_python_core_syntax.md)** **➡️ 다음 시간: [Part 2: 파이썬 핵심 문법](../02_python_core_syntax/part_2_python_core_syntax.md)**
\ No newline at end of file
...@@ -161,8 +161,13 @@ print(f"학점: {grade}") ...@@ -161,8 +161,13 @@ print(f"학점: {grade}")
> print(f"결과: {status}") # 출력: Pass > print(f"결과: {status}") # 출력: Pass
> ``` > ```
### 7.3. `for`: 순서대로 반복하기 ### 7.3. `for`: 파이썬답게 반복하기 (enumerate, zip)
리스트, 튜플, 문자열 등 순회 가능한 객체의 요소를 하나씩 순회합니다. `enumerate`를 사용하면 인덱스와 값을 함께 얻을 수 있습니다.
`for`문은 파이썬에서 가장 많이 사용되는 반복문입니다. 리스트, 튜플, 문자열 등 순회 가능한 객체의 요소를 하나씩 순회하며, `enumerate``zip`과 함께 사용하면 더욱 강력하고 파이썬다운 코드를 작성할 수 있습니다.
#### `enumerate`: 인덱스와 값을 동시에 얻기
`for`문으로 리스트를 순회할 때, 각 요소의 인덱스 번호가 필요할 때가 많습니다. `enumerate`를 사용하면 별도의 변수 없이 인덱스와 값을 함께 얻을 수 있습니다.
```python ```python
fruits = ["apple", "banana", "cherry"] fruits = ["apple", "banana", "cherry"]
...@@ -170,6 +175,35 @@ for idx, fruit in enumerate(fruits): ...@@ -170,6 +175,35 @@ for idx, fruit in enumerate(fruits):
print(f"{idx+1}번째 과일: {fruit}") print(f"{idx+1}번째 과일: {fruit}")
``` ```
#### `zip`: 여러 리스트를 나란히 묶기
여러 개의 리스트를 마치 하나의 리스트처럼, 각 리스트의 같은 인덱스에 있는 요소들을 짝지어 반복하고 싶을 때 `zip`을 사용합니다.
```python
names = ['앨리스', '밥', '찰리']
ages = [25, 30, 28]
for name, age in zip(names, ages):
print(f"{name}의 나이는 {age}세입니다.")
```
> [!TIP]
> `zip`은 가장 짧은 리스트의 길이를 기준으로 동작합니다. 리스트들의 길이가 다르면, 짧은 쪽이 끝났을 때 반복도 함께 종료됩니다.
#### `enumerate`와 `zip` 함께 사용하기: 인덱스와 여러 값 동시에 다루기
두 기능을 합치면, 여러 리스트를 순회하면서 동시에 인덱스 번호까지 얻을 수 있습니다. 학생들의 성적을 처리하는 경우를 예로 들어보겠습니다.
```python
names = ['Alice', 'Bob', 'Charlie']
subjects = ['Math', 'English', 'Science']
scores = [95, 88, 76]
for i, (name, subject, score) in enumerate(zip(names, subjects, scores)):
print(f"{i+1}번 학생 {name}{subject} 점수는 {score}점 입니다.")
```
이처럼 `enumerate``zip`을 활용하면 복잡한 반복 로직도 간결하고 읽기 좋은 코드로 표현할 수 있습니다.
### 7.4. `while`: 조건이 만족하는 동안 반복하기 ### 7.4. `while`: 조건이 만족하는 동안 반복하기
주어진 조건이 `True`인 동안 코드를 계속해서 반복합니다. 조건이 언젠가 `False`가 되도록 만들지 않으면 '무한 루프'에 빠지므로 주의해야 합니다. 주어진 조건이 `True`인 동안 코드를 계속해서 반복합니다. 조건이 언젠가 `False`가 되도록 만들지 않으면 '무한 루프'에 빠지므로 주의해야 합니다.
...@@ -204,52 +238,63 @@ print(f"홀수만 필터링: {odd_numbers}") # [1, 3, 5] ...@@ -204,52 +238,63 @@ print(f"홀수만 필터링: {odd_numbers}") # [1, 3, 5]
> `doubled_numbers = [x * 2 for x in numbers]` > `doubled_numbers = [x * 2 for x in numbers]`
> `odd_numbers = [x for x in numbers if x % 2 != 0]` > `odd_numbers = [x for x in numbers if x % 2 != 0]`
--- ### 8.4. 파이썬의 모든 것은 객체: 변수와 함수의 동작 원리 (Call by Object Reference)
## 8. 코드를 재사용하는 마법, 함수
> **🎯 5일차 목표:** 반복되는 코드를 `[함수(Function)](../../glossary.md#함수-function)`로 묶어 재사용하고, 함수의 입력([매개변수](../../glossary.md#매개변수-parameter와-인자-argument))과 출력([반환 값](../../glossary.md#반환-값-return-value))을 이해합니다. 파이썬의 동작 방식을 깊이 이해하려면 "모든 것이 객체(Object)다"라는 개념을 알아야 합니다. 숫자, 문자열, 심지어 함수까지도 모두 메모리 상의 '객체'이며, 변수는 그 객체를 가리키는 '이름표'일 뿐입니다. 이 개념은 함수에 인자를 전달하는 방식에도 그대로 적용됩니다.
### 8.1. 함수(Function): 나만의 미니 프로그램 #### 함수는 1급 객체 (First-class Citizen)
[함수]../../glossary.md#함수-function)는 특정 작업을 수행하는 코드 묶음에 이름을 붙인 **'재사용 가능한 레시피'**입니다. `def` 키워드로 정의하고, 이름으로 호출하여 사용합니다.
### 8.2. 입력(매개변수)과 출력(반환 값) 파이썬에서 함수는 특별한 취급을 받지 않습니다. 숫자나 리스트처럼 변수에 할당할 수 있고, 다른 함수의 인자로 전달하거나, 함수가 함수를 반환할 수도 있습니다. 이를 '함수는 1급 객체'라고 부릅니다.
- **[매개변수(Parameter)](../../glossary.md#매개변수-parameter와-인자-argument):** 함수에 전달하는 재료(입력 값).
- **[`return`](../../glossary.md#반환-값-return-value):** 함수가 작업을 마친 후 돌려주는 결과물(출력 값).
```python ```python
def add(a, b): def greeting(name):
result = a + b print(f"안녕하세요, {name}님!")
return result
# 함수 호출 및 결과 저장 # 함수 객체를 변수에 할당
sum_result = add(5, 3) welcome = greeting
print(f"5 + 3 = {sum_result}") welcome("파이썬") # "안녕하세요, 파이썬님!" 출력
# print 함수 자체도 객체이므로 변수에 할당 가능
say = print
say("이것도 print 함수처럼 동작합니다.")
``` ```
함수를 잘 사용하면 복잡한 문제를 여러 개의 간단한 함수로 나누어 해결할 수 있어, 훨씬 체계적인 프로그래밍이 가능해집니다. 이 특징은 데코레이터처럼 함수의 기능을 동적으로 확장하는 강력한 패턴의 기반이 됩니다.
#### Call by Object Reference: 변수는 이름표일 뿐
### 8.3. 한 줄로 끝내는 익명 함수: 람다(Lambda) 많은 언어에서 '값에 의한 호출(Call by Value)'과 '참조에 의한 호출(Call by Reference)'을 구분합니다. 파이썬은 이 둘을 섞어놓은 듯한 **'객체 참조에 의한 호출(Call by Object Reference)'** 방식을 사용합니다.
`lambda`는 이름 없이 사용하는 간단한 한 줄짜리 함수입니다. '익명 함수'라고도 불리며, 복잡한 `def` 함수 정의가 필요 없는 간단한 작업을 다른 함수의 인자로 전달할 때 매우 유용합니다.
- **기본 문법**: `lambda 인자: 표현식` - 함수에 인자를 전달할 때, 값의 복사본이나 변수의 메모리 주소가 넘어가는 것이 아니라, 변수가 가리키고 있는 **객체의 참조(주소값)가 복사되어** 전달됩니다.
예를 들어, 두 수를 더하는 간단한 함수는 `lambda`를 사용해 다음과 같이 표현할 수 있습니다. **1. 변경 가능한(Mutable) 객체를 전달할 때 (e.g., 리스트, 딕셔너리)**
함수 안에서 전달받은 객체의 내용을 변경하면, 원본 객체에도 그 변경 사항이 그대로 반영됩니다. 왜냐하면 함수 안과 밖의 변수가 **같은 객체**를 가리키고 있기 때문입니다.
```python ```python
# def add(a, b): def add_element(my_list):
# return a + b my_list.append(4) # 리스트 내용 변경
# 위 함수를 람다로 표현
add_lambda = lambda a, b: a + b numbers = [1, 2, 3]
add_element(numbers)
print(f"람다 함수 결과: {add_lambda(3, 5)}") # 출력: 람다 함수 결과: 8 print(f"결과: {numbers}") # 출력: [1, 2, 3, 4]
# sorted() 함수의 key 매개변수에 활용
points = [(1, 5), (3, 2), (2, 8)]
# 각 튜플의 두 번째 요소를 기준으로 정렬
sorted_points = sorted(points, key=lambda point: point[1])
print(f"두 번째 원소로 정렬: {sorted_points}") # 출력: [(3, 2), (1, 5), (2, 8)]
``` ```
`lambda`는 코드를 더 간결하고 직관적으로 만들어주지만, 복잡한 로직에는 일반적인 `def` 함수를 사용하는 것이 가독성에 더 좋습니다. > 함수 안과 밖의 `numbers`와 `my_list`는 정확히 동일한 리스트 객체를 가리키므로, 함수 안에서의 변경이 밖에 영향을 줍니다.
**2. 변경 불가능한(Immutable) 객체를 전달할 때 (e.g., 숫자, 문자열, 튜플)**
변경 불가능한 객체는 그 내용을 바꿀 수 없습니다. 만약 함수 안에서 해당 변수에 새로운 값을 할당하면, 그것은 기존 객체를 바꾸는 것이 아니라 **새로운 객체를 만들어** 그 변수가 가리키게 하는 것입니다. 따라서 원본 변수에는 아무런 영향이 없습니다.
```python
def reassign_value(my_var):
my_var = 100 # 새로운 정수 객체를 생성하고 my_var가 가리키게 함
num = 10
reassign_value(num)
print(f"결과: {num}") # 출력: 10 (바뀌지 않음!)
```
> `reassign_value` 함수 안에서 `my_var`는 새로운 객체(`100`)를 가리키게 되지만, 함수 밖의 `num`은 여전히 원래 객체(`10`)를 가리키고 있습니다.
이러한 동작 방식을 이해하는 것은 파이썬 코드가 어떻게 실행되고 데이터가 어떻게 변하는지 정확히 예측하는 데 매우 중요합니다.
--- ---
......
...@@ -5,58 +5,67 @@ ...@@ -5,58 +5,67 @@
--- ---
## 1. 학습 목표 (Learning Objectives) <br>
이번 파트가 끝나면, 여러분은 다음을 할 수 있게 됩니다. > ## 1. 학습 목표 (Learning Objectives)
>
- 머신러닝과 딥러닝의 수학적 기반이 되는 선형대수학의 핵심 개념을 이해할 수 있습니다. > 이번 파트가 끝나면, 여러분은 다음을 할 수 있게 됩니다.
- NumPy를 사용하여 벡터와 행렬 연산을 수행하고 선형대수학 개념을 코드로 구현할 수 있습니다. >
- 벡터, 행렬, 텐서의 차이점을 설명하고 각각의 연산 방법을 NumPy로 구현할 수 있습니다. > - 머신러닝과 딥러닝의 수학적 기반이 되는 선형대수학의 핵심 개념을 이해할 수 있습니다.
- 고유값과 고유벡터, 특이값 분해(SVD)의 개념을 이해하고 NumPy로 계산할 수 있습니다. > - NumPy를 사용하여 벡터와 행렬 연산을 수행하고 선형대수학 개념을 코드로 구현할 수 있습니다.
- 선형대수학 개념이 머신러닝과 딥러닝에서 어떻게 활용되는지 설명할 수 있습니다. > - 벡터, 행렬, 텐서의 차이점을 설명하고 각각의 연산 방법을 NumPy로 구현할 수 있습니다.
> - 고유값과 고유벡터, 특이값 분해(SVD)의 개념을 이해하고 NumPy로 계산할 수 있습니다.
## 2. 핵심 요약 (Key Summary) > - 선형대수학 개념이 머신러닝과 딥러닝에서 어떻게 활용되는지 설명할 수 있습니다.
이 파트에서는 머신러닝과 딥러닝의 기반이 되는 선형대수학의 핵심 개념들을 NumPy를 활용하여 학습합니다. 벡터와 행렬의 기본 연산부터 시작하여 내적, 외적, 행렬 분해, 고유값과 고유벡터, 특이값 분해(SVD)까지 다양한 선형대수학 개념을 직접 코드로 구현하며 이해합니다. 또한 이러한 개념들이 머신러닝 알고리즘과 딥러닝 모델에서 어떻게 활용되는지 실제 사례를 통해 학습합니다.
- **핵심 키워드**: `벡터(Vector)`, `행렬(Matrix)`, `텐서(Tensor)`, `내적(Dot Product)`, `외적(Cross Product)`, `행렬식(Determinant)`, `역행렬(Inverse Matrix)`, `고유값(Eigenvalue)`, `고유벡터(Eigenvector)`, `특이값 분해(SVD)`, `선형 변환(Linear Transformation)`
## 3. 도입: 머신러닝의 수학적 기반 (Introduction)
머신러닝과 딥러닝의 세계로 본격적으로 들어가기 전에, 이 분야의 수학적 기반인 선형대수학을 이해하는 것은 매우 중요합니다. 선형대수학은 벡터와 행렬을 다루는 수학의 한 분야로, 데이터 표현, 변환, 분석의 핵심 도구입니다.
> [!TIP]
> 본 파트의 모든 예제 코드는 `../../source_code/part_5.5_linear_algebra_with_numpy.py` 파일에서 직접 실행하고 수정해볼 수 있습니다.
### AI 프로젝트에서 선형대수학의 역할 <br>
```mermaid > ## 2. 핵심 요약 (Key Summary)
graph TD >
subgraph "선형대수학의 역할" > 이 파트에서는 머신러닝과 딥러닝의 기반이 되는 선형대수학의 핵심 개념들을 NumPy를 활용하여 학습합니다. 벡터와 행렬의 기본 연산부터 시작하여 내적, 외적, 행렬 분해, 고유값과 고유벡터, 특이값 분해(SVD)까지 다양한 선형대수학 개념을 직접 코드로 구현하며 이해합니다. 또한 이러한 개념들이 머신러닝 알고리즘과 딥러닝 모델에서 어떻게 활용되는지 실제 사례를 통해 학습합니다.
A["<b>데이터 표현</b><br/>- 벡터, 행렬, 텐서로 데이터 표현<br/>- 고차원 데이터의 효율적 처리"] >
B["<b>모델 구현</b><br/>- 선형 회귀, PCA 등의 알고리즘<br/>- 신경망의 가중치와 활성화"] > - **핵심 키워드**: `벡터(Vector)`, `행렬(Matrix)`, `텐서(Tensor)`, `내적(Dot Product)`, `외적(Cross Product)`, `행렬식(Determinant)`, `역행렬(Inverse Matrix)`, `고유값(Eigenvalue)`, `고유벡터(Eigenvector)`, `특이값 분해(SVD)`, `선형 변환(Linear Transformation)`
C["<b>최적화</b><br/>- 경사 하강법의 수학적 기반<br/>- 역전파 알고리즘"]
D["<b>차원 축소</b><br/>- PCA, SVD를 통한 특성 추출<br/>- 데이터 압축과 시각화"]
end
A -->|"기반 제공"| B <br>
B -->|"효율적 계산"| C
C -->|"성능 향상"| D
D -->|"피드백"| A
```
이번 파트에서는 NumPy를 활용하여 선형대수학의 핵심 개념들을 직관적으로 이해하고, 이를 코드로 구현하는 방법을 배웁니다. 이론과 실습을 병행하여, 추상적인 수학 개념이 실제 머신러닝과 딥러닝에서 어떻게 활용되는지 명확하게 이해할 수 있을 것입니다. > ## 3. 도입: 머신러닝의 수학적 기반 (Introduction)
>
> 머신러닝과 딥러닝의 세계로 본격적으로 들어가기 전에, 이 분야의 수학적 기반인 선형대수학을 이해하는 것은 매우 중요합니다. 선형대수학은 벡터와 행렬을 다루는 수학의 한 분야로, 데이터 표현, 변환, 분석의 핵심 도구입니다.
>
> > [!TIP]
> > 본 파트의 모든 예제 코드는 `../../source_code/part_5.5_linear_algebra_with_numpy.py` 파일에서 직접 실행하고 수정해볼 수 있습니다.
>
> ### AI 프로젝트에서 선형대수학의 역할
>
> ```mermaid
> graph TD
> subgraph "선형대수학의 역할"
> A["<b>데이터 표현</b><br/>- 벡터, 행렬, 텐서로 데이터 표현<br/>- 고차원 데이터의 효율적 처리"]
> B["<b>모델 구현</b><br/>- 선형 회귀, PCA 등의 알고리즘<br/>- 신경망의 가중치와 활성화"]
> C["<b>최적화</b><br/>- 경사 하강법의 수학적 기반<br/>- 역전파 알고리즘"]
> D["<b>차원 축소</b><br/>- PCA, SVD를 통한 특성 추출<br/>- 데이터 압축과 시각화"]
> end
>
> A -->|"기반 제공"| B
> B -->|"효율적 계산"| C
> C -->|"성능 향상"| D
> D -->|"피드백"| A
> ```
>
> 이번 파트에서는 NumPy를 활용하여 선형대수학의 핵심 개념들을 직관적으로 이해하고, 이를 코드로 구현하는 방법을 배웁니다. 이론과 실습을 병행하여, 추상적인 수학 개념이 실제 머신러닝과 딥러닝에서 어떻게 활용되는지 명확하게 이해할 수 있을 것입니다.
--- ---
## 4. 벡터와 행렬: 기본 개념과 연산 <br>
> **🎯 1일차 목표:** 벡터와 행렬의 기본 개념을 이해하고 NumPy로 연산하는 방법을 배웁니다. > ## 4. 벡터와 행렬: 기본 개념과 연산
>
### 4-1. 벡터(Vector): 방향과 크기를 가진 양 > > **🎯 1일차 목표:** 벡터와 행렬의 기본 개념을 이해하고 NumPy로 연산하는 방법을 배웁니다.
>
벡터는 크기와 방향을 가진 양으로, 수학적으로는 숫자의 순서 있는 집합으로 표현됩니다. NumPy에서는 1차원 배열로 표현됩니다. > ### 4-1. 벡터(Vector): 방향과 크기를 가진 양
>
```python > 벡터는 크기와 방향을 가진 양으로, 수학적으로는 숫자의 순서 있는 집합으로 표현됩니다. NumPy에서는 1차원 배열로 표현됩니다.
>
> ```python
import numpy as np import numpy as np
# 벡터 생성 # 벡터 생성
...@@ -87,7 +96,7 @@ cross_product = np.cross(v1, v2) ...@@ -87,7 +96,7 @@ cross_product = np.cross(v1, v2)
print(f"v1 × v2 = {cross_product}") print(f"v1 × v2 = {cross_product}")
``` ```
> **💡 내적(Dot Product)의 기하학적 의미** > [!NOTE] 내적(Dot Product)의 기하학적 의미
> >
> 두 벡터 A와 B의 내적은 `A·B = |A||B|cosθ`로 정의됩니다. 여기서 θ는 두 벡터 사이의 각도입니다. > 두 벡터 A와 B의 내적은 `A·B = |A||B|cosθ`로 정의됩니다. 여기서 θ는 두 벡터 사이의 각도입니다.
> >
...@@ -96,12 +105,12 @@ print(f"v1 × v2 = {cross_product}") ...@@ -96,12 +105,12 @@ print(f"v1 × v2 = {cross_product}")
> - **θ = 180° (반대 방향)**: 내적은 최소값(두 벡터 크기의 곱의 음수) > - **θ = 180° (반대 방향)**: 내적은 최소값(두 벡터 크기의 곱의 음수)
> >
> 이러한 특성 때문에 내적은 두 벡터의 유사도를 측정하는 데 자주 사용됩니다. 머신러닝에서 코사인 유사도(cosine similarity)가 바로 이 원리를 활용합니다. > 이러한 특성 때문에 내적은 두 벡터의 유사도를 측정하는 데 자주 사용됩니다. 머신러닝에서 코사인 유사도(cosine similarity)가 바로 이 원리를 활용합니다.
>
### 4-2. 행렬(Matrix): 2차원 데이터 구조 > ### 4-2. 행렬(Matrix): 2차원 데이터 구조
>
행렬은 숫자를 직사각형 형태로 배열한 것으로, 행(row)과 열(column)로 구성됩니다. NumPy에서는 2차원 배열로 표현됩니다. > 행렬은 숫자를 직사각형 형태로 배열한 것으로, 행(row)과 열(column)로 구성됩니다. NumPy에서는 2차원 배열로 표현됩니다.
>
```python > ```python
# 행렬 생성 # 행렬 생성
A = np.array([[1, 2], [3, 4]]) A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]]) B = np.array([[5, 6], [7, 8]])
...@@ -136,7 +145,7 @@ I = np.matmul(A, inv_A) ...@@ -136,7 +145,7 @@ I = np.matmul(A, inv_A)
print(f"A × A^(-1) =\n{np.round(I, decimals=10)}") # 부동소수점 오차 처리 print(f"A × A^(-1) =\n{np.round(I, decimals=10)}") # 부동소수점 오차 처리
``` ```
> **💡 행렬 곱셈의 의미** > [!NOTE] 행렬 곱셈의 의미
> >
> 행렬 곱셈은 선형 변환의 합성을 나타냅니다. 예를 들어, 행렬 A가 회전 변환을 나타내고 행렬 B가 크기 조절 변환을 나타낸다면, A×B는 "먼저 크기를 조절한 후 회전"하는 복합 변환을 나타냅니다. > 행렬 곱셈은 선형 변환의 합성을 나타냅니다. 예를 들어, 행렬 A가 회전 변환을 나타내고 행렬 B가 크기 조절 변환을 나타낸다면, A×B는 "먼저 크기를 조절한 후 회전"하는 복합 변환을 나타냅니다.
> >
...@@ -144,17 +153,19 @@ print(f"A × A^(-1) =\n{np.round(I, decimals=10)}") # 부동소수점 오차 ...@@ -144,17 +153,19 @@ print(f"A × A^(-1) =\n{np.round(I, decimals=10)}") # 부동소수점 오차
--- ---
## 5. 고급 선형대수학 개념과 NumPy 구현 <br>
> **🎯 2일차 목표:** 고유값, 고유벡터, SVD 등 고급 선형대수학 개념을 이해하고 NumPy로 구현합니다.
### 5-1. 고유값(Eigenvalue)과 고유벡터(Eigenvector)
고유벡터는 선형 변환(행렬 곱셈)을 거쳐도 방향이 변하지 않는 특별한 벡터입니다. 고유값은 그 과정에서 벡터의 크기가 변하는 비율을 나타냅니다. > ## 5. 고급 선형대수학 개념과 NumPy 구현
>
수학적으로, 정방행렬 A에 대해 Av = λv를 만족하는 벡터 v와 스칼라 λ가 있다면, v는 A의 고유벡터이고 λ는 대응하는 고유값입니다. > > **🎯 2일차 목표:** 고유값, 고유벡터, SVD 등 고급 선형대수학 개념을 이해하고 NumPy로 구현합니다.
>
```python > ### 5-1. 고유값(Eigenvalue)과 고유벡터(Eigenvector)
>
> 고유벡터는 선형 변환(행렬 곱셈)을 거쳐도 방향이 변하지 않는 특별한 벡터입니다. 고유값은 그 과정에서 벡터의 크기가 변하는 비율을 나타냅니다.
>
> 수학적으로, 정방행렬 A에 대해 Av = λv를 만족하는 벡터 v와 스칼라 λ가 있다면, v는 A의 고유벡터이고 λ는 대응하는 고유값입니다.
>
> ```python
# 예제 행렬 # 예제 행렬
A = np.array([[4, -2], [1, 1]]) A = np.array([[4, -2], [1, 1]])
...@@ -174,21 +185,21 @@ for i in range(len(eigenvalues)): ...@@ -174,21 +185,21 @@ for i in range(len(eigenvalues)):
print(f"λ × v = {lambda_v}") print(f"λ × v = {lambda_v}")
``` ```
> **💡 고유값과 고유벡터의 응용** > [!NOTE] 고유값과 고유벡터의 응용
> >
> 고유값과 고유벡터는 데이터 과학과 머신러닝에서 매우 중요한 역할을 합니다: > 고유값과 고유벡터는 데이터 과학과 머신러닝에서 매우 중요한 역할을 합니다:
> >
> - **주성분 분석(PCA)**: 데이터의 공분산 행렬의 고유벡터는 데이터의 주요 변동 방향을 나타냅니다. 이를 통해 차원 축소와 특성 추출이 가능합니다. > - **주성분 분석(PCA)**: 데이터의 공분산 행렬의 고유벡터는 데이터의 주요 변동 방향을 나타냅니다. 이를 통해 차원 축소와 특성 추출이 가능합니다.
> - **PageRank 알고리즘**: Google의 초기 검색 알고리즘은 웹 그래프의 인접 행렬의 주요 고유벡터를 사용하여 웹페이지의 중요도를 계산했습니다. > - **PageRank 알고리즘**: Google의 초기 검색 알고리즘은 웹 그래프의 인접 행렬의 주요 고유벡터를 사용하여 웹페이지의 중요도를 계산했습니다.
> - **안정성 분석**: 동적 시스템의 안정성은 시스템 행렬의 고유값을 통해 분석할 수 있습니다. > - **안정성 분석**: 동적 시스템의 안정성은 시스템 행렬의 고유값을 통해 분석할 수 있습니다.
>
### 5-2. 특이값 분해(Singular Value Decomposition, SVD) > ### 5-2. 특이값 분해(Singular Value Decomposition, SVD)
>
SVD는 어떤 행렬이든 세 개의 특별한 행렬의 곱으로 분해하는 방법입니다: A = UΣV^T. 여기서 U와 V는 직교 행렬이고, Σ는 대각 행렬입니다. > SVD는 어떤 행렬이든 세 개의 특별한 행렬의 곱으로 분해하는 방법입니다: A = UΣV^T. 여기서 U와 V는 직교 행렬이고, Σ는 대각 행렬입니다.
>
SVD는 행렬이 정방행렬이 아니거나 역행렬이 존재하지 않는 경우에도 적용할 수 있어, 더 일반적인 행렬 분해 방법입니다. > SVD는 행렬이 정방행렬이 아니거나 역행렬이 존재하지 않는 경우에도 적용할 수 있어, 더 일반적인 행렬 분해 방법입니다.
>
```python > ```python
# 예제 행렬 (비정방행렬) # 예제 행렬 (비정방행렬)
B = np.array([[3, 2, 2], [2, 3, -2]]) B = np.array([[3, 2, 2], [2, 3, -2]])
...@@ -209,7 +220,7 @@ B_reconstructed = U @ Sigma_matrix @ VT ...@@ -209,7 +220,7 @@ B_reconstructed = U @ Sigma_matrix @ VT
print(f"\n복원된 행렬:\n{B_reconstructed}") print(f"\n복원된 행렬:\n{B_reconstructed}")
``` ```
> **💡 SVD의 응용** > [!NOTE] SVD의 응용
> >
> SVD는 머신러닝과 데이터 과학에서 다양하게 활용됩니다: > SVD는 머신러닝과 데이터 과학에서 다양하게 활용됩니다:
> >
...@@ -217,20 +228,20 @@ print(f"\n복원된 행렬:\n{B_reconstructed}") ...@@ -217,20 +228,20 @@ print(f"\n복원된 행렬:\n{B_reconstructed}")
> - **이미지 압축**: 큰 이미지 행렬에서 가장 중요한 특이값만 사용하여 이미지를 압축할 수 있습니다. > - **이미지 압축**: 큰 이미지 행렬에서 가장 중요한 특이값만 사용하여 이미지를 압축할 수 있습니다.
> - **추천 시스템**: Netflix와 같은 추천 시스템에서 사용자-아이템 행렬의 SVD를 통해 잠재 요인(latent factors)을 추출하여 추천에 활용합니다. > - **추천 시스템**: Netflix와 같은 추천 시스템에서 사용자-아이템 행렬의 SVD를 통해 잠재 요인(latent factors)을 추출하여 추천에 활용합니다.
> - **노이즈 제거**: 신호 처리에서 작은 특이값에 해당하는 성분을 제거하여 노이즈를 줄일 수 있습니다. > - **노이즈 제거**: 신호 처리에서 작은 특이값에 해당하는 성분을 제거하여 노이즈를 줄일 수 있습니다.
### 5-3. 주성분 분석(PCA)과 고유값 분해
PCA는 고차원 데이터의 분산을 최대한 보존하면서 저차원으로 축소하는 기법입니다. 이는 데이터 공분산 행렬의 고유값 분해를 통해 구현됩니다.
> **💡 PCA와 고유값 분해의 관계**
> >
> 데이터의 공분산 행렬은 데이터가 각 차원에서 얼마나 흩어져 있는지, 그리고 차원 간에 어떤 상관관계가 있는지를 나타냅니다. > ### 5-3. 주성분 분석(PCA)과 고유값 분해
> - **고유벡터**: 공분산 행렬의 고유벡터는 데이터가 가장 크게 분산된 방향(주성분)을 가리킵니다. 즉, 데이터의 '주요 축'을 나타냅니다.
> - **고유값**: 각 고유벡터에 해당하는 고유값은 해당 방향으로 데이터가 얼마나 많이 분산되어 있는지를 나타냅니다. 고유값이 클수록 더 중요한 주성분입니다.
> >
> 따라서, 가장 큰 고유값들을 가진 고유벡터(주성분)들로 원래 데이터를 투영(projection)하면, 원본 데이터의 분산을 최대한 유지하면서 차원을 축소할 수 있습니다. > PCA는 고차원 데이터의 분산을 최대한 보존하면서 저차원으로 축소하는 기법입니다. 이는 데이터 공분산 행렬의 고유값 분해를 통해 구현됩니다.
>
```python > > [!NOTE] PCA와 고유값 분해의 관계
> >
> > 데이터의 공분산 행렬은 데이터가 각 차원에서 얼마나 흩어져 있는지, 그리고 차원 간에 어떤 상관관계가 있는지를 나타냅니다.
> > - **고유벡터**: 공분산 행렬의 고유벡터는 데이터가 가장 크게 분산된 방향(주성분)을 가리킵니다. 즉, 데이터의 '주요 축'을 나타냅니다.
> > - **고유값**: 각 고유벡터에 해당하는 고유값은 해당 방향으로 데이터가 얼마나 많이 분산되어 있는지를 나타냅니다. 고유값이 클수록 더 중요한 주성분입니다.
> >
> > 따라서, 가장 큰 고유값들을 가진 고유벡터(주성분)들로 원래 데이터를 투영(projection)하면, 원본 데이터의 분산을 최대한 유지하면서 차원을 축소할 수 있습니다.
>
> ```python
# PCA 예제 # PCA 예제
# 데이터 생성 # 데이터 생성
np.random.seed(42) np.random.seed(42)
...@@ -248,286 +259,135 @@ print(f"공분산 행렬:\n{cov_matrix}") ...@@ -248,286 +259,135 @@ print(f"공분산 행렬:\n{cov_matrix}")
# 고유값과 고유벡터 계산 # 고유값과 고유벡터 계산
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix) eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)
# 고유값 기준으로 고유벡터 정렬 # 고유값을 기준으로 내림차순 정렬
idx = eigenvalues.argsort()[::-1] sorted_indices = np.argsort(eigenvalues)[::-1]
eigenvalues = eigenvalues[idx] sorted_eigenvalues = eigenvalues[sorted_indices]
eigenvectors = eigenvectors[:, idx] sorted_eigenvectors = eigenvectors[:, sorted_indices]
print(f"고유값: {eigenvalues}")
print(f"고유벡터:\n{eigenvectors}")
# 주성분으로 데이터 투영 (차원 축소)
n_components = 1 # 첫 번째 주성분만 사용
X_pca = X @ eigenvectors[:, :n_components]
# 원래 차원으로 복원
X_recovered = X_pca @ eigenvectors[:, :n_components].T
print(f"원본 데이터 차원: {X.shape}")
print(f"축소된 데이터 차원: {X_pca.shape}")
print(f"복원된 데이터 차원: {X_recovered.shape}")
```
### 5-4. 신경망과 행렬 연산
신경망의 각 층은 기본적으로 입력 벡터와 가중치 행렬의 행렬 곱, 그리고 비선형 활성화 함수로 구성됩니다.
```python print(f"고유값: {sorted_eigenvalues}")
# 간단한 신경망 순전파 구현 print(f"고유벡터:\n{sorted_eigenvectors}")
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# 입력 데이터 # 주성분 (PC)
X = np.array([[0.1, 0.2, 0.3]]) pc1 = sorted_eigenvectors[:, 0]
pc2 = sorted_eigenvectors[:, 1]
# 첫 번째 층 가중치와 편향 print(f"\n첫 번째 주성분 (PC1): {pc1}")
W1 = np.array([[0.1, 0.2, 0.3], print(f"두 번째 주성분 (PC2): {pc2}")
[0.4, 0.5, 0.6],
[0.7, 0.8, 0.9]])
b1 = np.array([0.1, 0.2, 0.3])
# 두 번째 층 가중치와 편향 # 데이터를 주성분으로 투영 (차원 축소)
W2 = np.array([[0.1, 0.2, 0.3], transformed_data = X @ sorted_eigenvectors
[0.4, 0.5, 0.6]])
b2 = np.array([0.1, 0.2])
# 순전파 계산 # 시각화
z1 = X @ W1 + b1 import matplotlib.pyplot as plt
a1 = sigmoid(z1)
z2 = a1 @ W2 + b2
a2 = sigmoid(z2)
print(f"입력: {X}") plt.figure(figsize=(12, 6))
print(f"첫 번째 층 출력: {a1}")
print(f"최종 출력: {a2}") # 원본 데이터
plt.subplot(1, 2, 1)
plt.scatter(X[:, 0], X[:, 1], alpha=0.7)
# 주성분 벡터 그리기
origin = [0, 0]
plt.quiver(*origin, *pc1*np.sqrt(sorted_eigenvalues[0]), color='r', scale=5, label=f'PC1 (Variance: {sorted_eigenvalues[0]:.2f})')
plt.quiver(*origin, *pc2*np.sqrt(sorted_eigenvalues[1]), color='g', scale=5, label=f'PC2 (Variance: {sorted_eigenvalues[1]:.2f})')
plt.title('Original Data with Principal Components')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.axis('equal')
plt.legend()
# 변환된 데이터
plt.subplot(1, 2, 2)
plt.scatter(transformed_data[:, 0], transformed_data[:, 1], alpha=0.7)
plt.title('Data Transformed by PCA')
plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
plt.axis('equal')
plt.tight_layout()
plt.show()
``` ```
--- ---
## 6. 선형대수학과 머신러닝의 연결 <br>
> **🎯 3일차 목표:** 선형대수학 개념이 실제 머신러닝 알고리즘에서 어떻게 활용되는지 이해합니다.
### 6-1. 선형 회귀와 행렬 연산
선형 회귀는 가장 기본적인 머신러닝 알고리즘으로, 선형대수학을 직접적으로 활용합니다. 선형 회귀의 정규 방정식(Normal Equation)은 다음과 같습니다:
θ = (X^T X)^(-1) X^T y
여기서 θ는 모델 파라미터, X는 특성 행렬, y는 타겟 벡터입니다.
```python
# 선형 회귀 예제
# 데이터 생성
np.random.seed(42)
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
# X에 상수항(1)을 추가
X_b = np.c_[np.ones((100, 1)), X]
# 정규 방정식으로 파라미터 계산 > ## 6. 텐서(Tensor): 다차원 데이터의 표현
theta_best = np.linalg.inv(X_b.T @ X_b) @ X_b.T @ y
print(f"계산된 파라미터: {theta_best.flatten()}")
print(f"실제 파라미터: [4, 3]")
# 예측
X_new = np.array([[0], [2]])
X_new_b = np.c_[np.ones((2, 1)), X_new]
y_predict = X_new_b @ theta_best
print(f"예측값: {y_predict.flatten()}")
```
### 6-2. 주성분 분석(PCA)과 고유값 분해
PCA는 고차원 데이터의 분산을 최대한 보존하면서 저차원으로 축소하는 기법입니다. 이는 데이터 공분산 행렬의 고유값 분해를 통해 구현됩니다.
> **💡 PCA와 고유값 분해의 관계**
> >
> 데이터의 공분산 행렬은 데이터가 각 차원에서 얼마나 흩어져 있는지, 그리고 차원 간에 어떤 상관관계가 있는지를 나타냅니다. > > **🎯 3일차 목표:** 텐서의 개념을 이해하고 NumPy로 다차원 데이터를 다루는 방법을 학습합니다.
> - **고유벡터**: 공분산 행렬의 고유벡터는 데이터가 가장 크게 분산된 방향(주성분)을 가리킵니다. 즉, 데이터의 '주요 축'을 나타냅니다.
> - **고유값**: 각 고유벡터에 해당하는 고유값은 해당 방향으로 데이터가 얼마나 많이 분산되어 있는지를 나타냅니다. 고유값이 클수록 더 중요한 주성분입니다.
> >
> 따라서, 가장 큰 고유값들을 가진 고유벡터(주성분)들로 원래 데이터를 투영(projection)하면, 원본 데이터의 분산을 최대한 유지하면서 차원을 축소할 수 있습니다. > ### 6-1. 텐서란 무엇인가?
>
```python > 텐서는 벡터와 행렬을 일반화한 다차원 배열입니다. 딥러닝에서 텐서는 데이터를 표현하는 기본 단위로 사용됩니다.
# PCA 예제 >
# 데이터 생성 > - **0차원 텐서 (스칼라)**: 숫자 하나 (e.g., `5`)
np.random.seed(42) > - **1차원 텐서 (벡터)**: 숫자의 배열 (e.g., `[1, 2, 3]`)
mean = [0, 0] > - **2차원 텐서 (행렬)**: 숫자의 2차원 배열 (e.g., `[[1, 2], [3, 4]]`)
cov = [[5, 4], [4, 5]] # 공분산 행렬 > - **3차원 텐서**: 숫자의 3차원 배열 (e.g., 컬러 이미지 (높이, 너비, 채널))
data = np.random.multivariate_normal(mean, cov, 200) > - **4차원 텐서**: 숫자의 4차원 배열 (e.g., 이미지 데이터의 미니배치 (배치 크기, 높이, 너비, 채널))
>
# 데이터 중앙 정렬 > ### 6-2. NumPy로 텐서 다루기
X = data - data.mean(axis=0) >
> ```python
# 공분산 행렬 계산 > # 3차원 텐서 생성 (2x3x4)
cov_matrix = np.cov(X.T) > T = np.arange(24).reshape(2, 3, 4)
print(f"공분산 행렬:\n{cov_matrix}") >
> print(f"3차원 텐서 T:\n{T}")
# 고유값과 고유벡터 계산 > print(f"\n텐서의 모양(shape): {T.shape}")
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix) > print(f"텐서의 차원 수(ndim): {T.ndim}")
> print(f"텐서의 총 요소 수(size): {T.size}")
# 고유값 기준으로 고유벡터 정렬 >
idx = eigenvalues.argsort()[::-1] > # 텐서 인덱싱
eigenvalues = eigenvalues[idx] > print(f"\nT[1, 0, 2] = {T[1, 0, 2]}")
eigenvectors = eigenvectors[:, idx] >
> # 텐서 슬라이싱
print(f"고유값: {eigenvalues}") > print(f"\nT[:, 0, :] =\n{T[:, 0, :]}") # 각 행렬의 첫 번째 행
print(f"고유벡터:\n{eigenvectors}") > ```
>
# 주성분으로 데이터 투영 (차원 축소) > ### 6-3. 텐서 연산
n_components = 1 # 첫 번째 주성분만 사용 >
X_pca = X @ eigenvectors[:, :n_components] > 텐서 연산은 기본적으로 요소별(element-wise)로 수행됩니다.
>
# 원래 차원으로 복원 > ```python
X_recovered = X_pca @ eigenvectors[:, :n_components].T > T1 = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
> T2 = np.array([[[9, 10], [11, 12]], [[13, 14], [15, 16]]])
print(f"원본 데이터 차원: {X.shape}") >
print(f"축소된 데이터 차원: {X_pca.shape}") > # 텐서 덧셈
print(f"복원된 데이터 차원: {X_recovered.shape}") > T_sum = T1 + T2
``` > print(f"텐서 덧셈:\n{T_sum}")
>
### 6-3. 신경망과 행렬 연산 > # 텐서 곱셈 (요소별)
> T_prod = T1 * T2
신경망의 각 층은 기본적으로 입력 벡터와 가중치 행렬의 행렬 곱, 그리고 비선형 활성화 함수로 구성됩니다. > print(f"\n텐서 곱셈 (요소별):\n{T_prod}")
>
```python > # 텐서 내적 (Tensor Dot Product)
# 간단한 신경망 순전파 구현 > # np.tensordot은 축을 지정하여 내적을 수행
def sigmoid(x): > # 예: (2, 2, 2) 텐서와 (2, 2, 2) 텐서의 마지막 두 축에 대해 내적
return 1 / (1 + np.exp(-x)) > T_dot = np.tensordot(T1, T2, axes=([1, 2], [1, 2]))
> print(f"\n텐서 내적 (axes=([1,2],[1,2])):\n{T_dot}")
# 입력 데이터 > ```
X = np.array([[0.1, 0.2, 0.3]]) >
> > [!NOTE] 딥러닝에서의 텐서 연산
# 첫 번째 층 가중치와 편향 > > 딥러닝 프레임워크(TensorFlow, PyTorch)에서는 복잡한 텐서 연산을 효율적으로 처리하기 위한 다양한 함수를 제공합니다. 특히 GPU를 활용한 병렬 처리를 통해 대규모 텐서 연산을 가속화합니다.
W1 = np.array([[0.1, 0.2, 0.3],
[0.4, 0.5, 0.6],
[0.7, 0.8, 0.9]])
b1 = np.array([0.1, 0.2, 0.3])
# 두 번째 층 가중치와 편향
W2 = np.array([[0.1, 0.2, 0.3],
[0.4, 0.5, 0.6]])
b2 = np.array([0.1, 0.2])
# 순전파 계산
z1 = X @ W1 + b1
a1 = sigmoid(z1)
z2 = a1 @ W2 + b2
a2 = sigmoid(z2)
print(f"입력: {X}")
print(f"첫 번째 층 출력: {a1}")
print(f"최종 출력: {a2}")
```
--- ---
## 7. 연습 문제: 선형대수학과 NumPy 활용 <br>
> **🎯 4-5일차 목표:** 선형대수학 개념과 NumPy를 활용하여 실제 문제를 해결합니다.
### 문제 1: 이미지 압축 (SVD 활용)
SVD를 사용하여 이미지를 압축하는 코드를 작성하세요. 다양한 수의 특이값을 사용하여 이미지를 재구성하고, 원본과 비교해보세요.
**참고:** 이 코드를 실행하기 위해서는 `image.jpg` 파일이 필요합니다. 실습을 위해 아무 이미지나 `source_code` 디렉토리에 `image.jpg`로 저장하고 실행해주세요.
```python
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.image import imread
try:
# 이미지 로드 (그레이스케일로 변환)
img = imread('image.jpg')
if len(img.shape) == 3: # 컬러 이미지인 경우
img = np.mean(img, axis=2) # 그레이스케일로 변환
plt.figure(figsize=(8, 4))
plt.subplot(1, 2, 1)
plt.imshow(img, cmap='gray')
plt.title('Original Image')
plt.axis('off')
# SVD 계산
U, Sigma, VT = np.linalg.svd(img)
# 다양한 수의 특이값으로 이미지 재구성
k = 50 # 사용할 특이값 수
reconstructed = U[:, :k] @ np.diag(Sigma[:k]) @ VT[:k, :]
plt.subplot(1, 2, 2)
plt.imshow(reconstructed, cmap='gray')
plt.title(f'Reconstructed (k={k})')
plt.axis('off')
plt.tight_layout()
plt.show()
# 압축률과 오차 계산
original_size = img.shape[0] * img.shape[1]
compressed_size = k * (img.shape[0] + img.shape[1] + 1)
compression_ratio = original_size / compressed_size
error = np.linalg.norm(img - reconstructed) / np.linalg.norm(img)
print(f"압축률: {compression_ratio:.2f}x")
print(f"상대 오차: {error:.4f}")
except FileNotFoundError: > ## 7. 마무리 및 다음 파트 예고
print("오류: `source_code` 디렉토리에 'image.jpg' 파일을 찾을 수 없습니다.") >
print("실습을 진행하려면 이미지를 해당 경로에 추가해주세요.") > 이번 파트에서는 NumPy를 사용하여 선형대수학의 핵심 개념들을 살펴보았습니다. 벡터, 행렬, 텐서의 기본 연산부터 시작하여 고유값, 고유벡터, SVD와 같은 고급 주제까지 다루었습니다. 이러한 개념들은 머신러닝과 딥러닝 모델을 이해하고 구현하는 데 필수적인 수학적 도구입니다.
>
``` > 다음 파트에서는 드디어 본격적인 **머신러닝의 세계**로 들어갑니다. 선형 회귀, 로지스틱 회귀와 같은 기본적인 머신러닝 모델을 직접 구현하고 평가하며, 모델 학습의 전체 과정을 경험하게 될 것입니다. 이번 파트에서 배운 선형대수학 지식이 다음 파트의 모델들을 이해하는 데 어떻게 사용되는지 직접 확인할 수 있을 것입니다.
>
### 문제 2: 선형 시스템 해결 > > [!TIP]
다음 선형 방정식 시스템을 NumPy를 사용하여 해결하세요: > > **다음으로 무엇을 해야 할까요?**
> > - `source_code/part_5.5_linear_algebra_with_numpy.py` 파일의 코드를 직접 실행하고, 값을 바꿔보며 결과가 어떻게 변하는지 확인해보세요.
2x + y - z = 8 > > - 특히 SVD를 이용한 이미지 압축이나 PCA를 이용한 차원 축소 예제를 직접 다른 데이터에 적용해보세요.
-3x - y + 2z = -11 > > - 궁금한 점이 있다면 언제든지 질문해주세요!
-2x + y + 2z = -3
```python
# 계수 행렬 A와 상수 벡터 b 정의
A = np.array([[2, 1, -1],
[-3, -1, 2],
[-2, 1, 2]])
b = np.array([8, -11, -3])
# 선형 시스템 해결
x = np.linalg.solve(A, b)
print(f"해: x = {x[0]}, y = {x[1]}, z = {x[2]}")
# 검증
verification = A @ x
print(f"A @ x = {verification}")
print(f"b = {b}")
```
---
## 8. 트러블슈팅 (Troubleshooting)
- **`LinAlgError: Singular matrix`가 발생했나요?** <br>
- 이 오류는 행렬이 역행렬을 가지지 않을 때(특이 행렬) 발생합니다. 행렬식이 0이거나 행렬의 행이나 열이 선형 종속인 경우 이런 문제가 발생합니다. 이런 경우 `np.linalg.pinv()`를 사용하여 유사 역행렬(pseudo-inverse)을 계산할 수 있습니다.
- **행렬 곱셈 차원 오류가 발생했나요?**
- 행렬 곱셈 A @ B에서 A의 열 수와 B의 행 수가 일치해야 합니다. `A.shape[1] == B.shape[0]`를 확인하세요.
- **수치적 불안정성 문제가 있나요?**
- 부동소수점 연산으로 인해 매우 작은 오차가 발생할 수 있습니다. 이런 경우 `np.round(result, decimals=10)`와 같이 반올림하거나, `np.allclose(a, b)`를 사용하여 두 배열이 근사적으로 같은지 확인할 수 있습니다.
- **SVD나 고유값 분해 결과가 예상과 다른가요?**
- 고유벡터와 SVD의 결과는 부호가 반대로 나올 수도 있습니다. 이는 수학적으로 동등한 결과이므로 걱정하지 않아도 됩니다.
--- ---
## 9. 되짚어보기 (Summary) **⬅️ 이전 시간: [Part 5: AI 핵심 라이브러리](../05_ai_core_libraries/part_5_ai_core_libraries.md)**
**➡️ 다음 시간: [Part 6: 머신러닝 모델링과 평가](../06_machine_learning/part_6_machine_learning.md)**
이번 파트에서는 머신러닝과 딥러닝의 수학적 기반인 선형대수학의 핵심 개념들을 NumPy를 활용하여 학습했습니다. \ No newline at end of file
- **벡터와 행렬의 기본 연산**: 덧셈, 뺄셈, 곱셈, 내적, 외적 등 기본 연산을 NumPy로 구현했습니다.
- **고급 선형대수학 개념**: 고유값, 고유벡터, 특이값 분해(SVD)를 이해하고 코드로 구현하며, 주성분 분석(PCA)과의 연관성을 파악했습니다.
- **머신러닝과의 연결**: 선형 회귀, PCA, 신경망 등 실제 머신러닝 알고리즘에서 선형대수학이 어떻게 핵심적인 역할을 하는지 확인했습니다.
이제 여러분은 데이터를 벡터와 행렬로 표현하고, 선형 변환을 통해 데이터를 분석하고, 머신러닝 알고리즘의 내부 동작을 더 깊이 이해할 수 있는 수학적 기반을 갖추게 되었습니다.
\ No newline at end of file
# Part 5: AI 핵심 라이브러리 마스터하기 ---
marp: true
theme: gaia
class:
- lead
- invert
---
<!-- _class: lead -->
<!-- _header: "" -->
<!-- _footer: "" -->
<style>
h1 {
font-size: 2.5em;
font-weight: 600;
}
h2 {
font-size: 2em;
font-weight: 600;
}
h3 {
font-size: 1.6em;
font-weight: 600;
}
h4 {
font-size: 1.3em;
font-weight: 600;
}
h5 {
font-size: 1.1em;
font-weight: 600;
}
h6 {
font-size: 1em;
font-weight: 600;
}
p, li, ul, ol, table {
font-size: 28px;
}
pre, code {
font-size: 24px;
}
</style>
# Part 5: AI 핵심 라이브러리: NumPy, Pandas, Matplotlib
**⬅️ 이전 시간: [Part 4: 객체 지향 프로그래밍(OOP)](../04_object_oriented_programming/part_4_object_oriented_programming.md)** **⬅️ 이전 시간: [Part 4: 객체 지향 프로그래밍(OOP)](../04_object_oriented_programming/part_4_object_oriented_programming.md)**
**➡️ 다음 시간: [Part 6: 머신러닝 모델링과 평가](../06_machine_learning/part_6_machine_learning.md)** **➡️ 다음 시간: [Part 5.5: NumPy로 배우는 선형대수](../05.5_linear_algebra_with_numpy/part_5.5_linear_algebra_with_numpy.md)**
--- ---
...@@ -379,4 +424,4 @@ plt.show() ...@@ -379,4 +424,4 @@ plt.show()
--- ---
**➡️ 다음 시간: [Part 6: 머신러닝 모델링과 평가](../06_machine_learning/part_6_machine_learning.md)** **➡️ 다음 시간: [Part 5.5: NumPy로 배우는 선형대수](../05.5_linear_algebra_with_numpy/part_5.5_linear_algebra_with_numpy.md)**
\ No newline at end of file \ No newline at end of file
# Part 6: 머신러닝 모델링과 평가 # Part 6: 머신러닝 모델링과 평가
**⬅️ 이전 시간: [Part 5: AI 핵심 라이브러리](../05_ai_core_libraries/part_5_ai_core_libraries.md)** **⬅️ 이전 시간: [Part 5.5: NumPy로 배우는 선형대수학](../05.5_linear_algebra_with_numpy/part_5.5_linear_algebra_with_numpy.md)**
**➡️ 다음 시간: [Part 7: 딥러닝 기초와 PyTorch](../07_deep_learning/part_7_deep_learning.md)** **➡️ 다음 시간: [Part 7: 딥러닝 기초와 PyTorch](../07_deep_learning/part_7_deep_learning.md)**
--- ---
## 1. 학습 목표 (Learning Objectives) <br>
이번 파트가 끝나면, 여러분은 다음을 할 수 있게 됩니다. > ## 1. 학습 목표 (Learning Objectives)
>
- Matplotlib와 Seaborn을 사용하여 데이터의 분포, 관계, 추세를 시각화하고 인사이트를 도출할 수 있습니다. > 이번 파트가 끝나면, 여러분은 다음을 할 수 있게 됩니다.
- 지도학습, 훈련/테스트 데이터 분할의 개념을 설명할 수 있습니다. >
- Scikit-learn의 `fit()`, `predict()` 인터페이스를 사용하여 머신러닝 모델을 훈련하고, 새로운 데이터에 대한 예측을 만들 수 있습니다. > - Matplotlib와 Seaborn을 사용하여 데이터의 분포, 관계, 추세를 시각화하고 인사이트를 도출할 수 있습니다.
- 피처 스케일링(StandardScaler, MinMaxScaler)과 같은 핵심 전처리 기법을 모델 성능 향상을 위해 적용할 수 있습니다. > - 지도학습, 훈련/테스트 데이터 분할의 개념을 설명할 수 있습니다.
- 데이터 불러오기부터 전처리, 훈련, 평가까지 이어지는 머신러닝의 전체 파이프라인을 코드로 구현할 수 있습니다. > - Scikit-learn의 `fit()`, `predict()` 인터페이스를 사용하여 머신러닝 모델을 훈련하고, 새로운 데이터에 대한 예측을 만들 수 있습니다.
> - 피처 스케일링(StandardScaler, MinMaxScaler)과 같은 핵심 전처리 기법을 모델 성능 향상을 위해 적용할 수 있습니다.
## 2. 핵심 요약 (Key Summary) > - 데이터 불러오기부터 전처리, 훈련, 평가까지 이어지는 머신러닝의 전체 파이프라인을 코드로 구현할 수 있습니다.
이 파트에서는 데이터에서 패턴을 발견하고 미래를 예측하는 머신러닝의 전 과정을 학습합니다. Matplotlib와 Seaborn을 이용한 데이터 시각화로 숨겨진 인사이트를 찾는 법을 배우고, Scikit-learn 라이브러리를 통해 지도학습의 기본 개념과 모델 훈련/평가 프로세스를 익힙니다. 훈련/테스트 데이터 분리, 피처 스케일링 등 핵심적인 데이터 전처리 기법을 적용하여 모델의 성능을 향상시키는 방법을 실습하며, 머신러닝 프로젝트의 전체 파이프라인을 직접 구축해 봅니다.
- **핵심 키워드**: `데이터 시각화`, `Matplotlib`, `Seaborn`, `Scikit-learn`, `지도학습(Supervised Learning)`, `훈련/테스트 분리(Train/Test Split)`, `데이터 전처리(Preprocessing)`, `피처 스케일링(Feature Scaling)`, `모델 평가(Evaluation)`, `정확도(Accuracy)`
## 3. 도입: 데이터에서 지혜를 캐내는 기술 (Introduction)
이전 파트에서 우리는 NumPy와 Pandas로 데이터를 자유자재로 다루는 법을 배웠습니다. 하지만 숫자로만 가득한 표는 우리에게 많은 것을 알려주지 않습니다. 이번 파트에서는 데이터에 '생명'을 불어넣는 두 가지 핵심 기술, **시각화****머신러닝**을 배웁니다. <br>
- **시각화**는 데이터 속에 숨겨진 패턴과 이야기를 발견하는 '눈'이 되어줄 것입니다. > ## 2. 핵심 요약 (Key Summary)
- **머신러닝**은 그 패턴을 학습하여 미래를 예측하는 '두뇌' 역할을 합니다. >
> 이 파트에서는 데이터에서 패턴을 발견하고 미래를 예측하는 머신러닝의 전 과정을 학습합니다. Matplotlib와 Seaborn을 이용한 데이터 시각화로 숨겨진 인사이트를 찾는 법을 배우고, Scikit-learn 라이브러리를 통해 지도학습의 기본 개념과 모델 훈련/평가 프로세스를 익힙니다. 훈련/테스트 데이터 분리, 피처 스케일링 등 핵심적인 데이터 전처리 기법을 적용하여 모델의 성능을 향상시키는 방법을 실습하며, 머신러닝 프로젝트의 전체 파이프라인을 직접 구축해 봅니다.
>
> - **핵심 키워드**: `데이터 시각화`, `Matplotlib`, `Seaborn`, `Scikit-learn`, `지도학습(Supervised Learning)`, `훈련/테스트 분리(Train/Test Split)`, `데이터 전처리(Preprocessing)`, `피처 스케일링(Feature Scaling)`, `모델 평가(Evaluation)`, `정확도(Accuracy)`
Scikit-learn이라는 강력한 도구를 통해, 우리는 이 모든 과정을 직접 체험해볼 것입니다. <br>
> [!TIP] > ## 3. 도입: 데이터에서 지혜를 캐내는 기술 (Introduction)
> 본 파트의 모든 예제 코드는 `../../source_code/part_6_machine_learning.py` 파일에서 직접 실행하고 수정해볼 수 있습니다. >
> 이전 파트에서 우리는 NumPy와 Pandas로 데이터를 자유자재로 다루는 법을 배웠습니다. 하지만 숫자로만 가득한 표는 우리에게 많은 것을 알려주지 않습니다. 이번 파트에서는 데이터에 '생명'을 불어넣는 두 가지 핵심 기술, **시각화**와 **머신러닝**을 배웁니다.
>
> - **시각화**는 데이터 속에 숨겨진 패턴과 이야기를 발견하는 '눈'이 되어줄 것입니다.
> - **머신러닝**은 그 패턴을 학습하여 미래를 예측하는 '두뇌' 역할을 합니다.
>
> Scikit-learn이라는 강력한 도구를 통해, 우리는 이 모든 과정을 직접 체험해볼 것입니다.
>
> > [!TIP]
> > 본 파트의 모든 예제 코드는 `../../source_code/part_6_machine_learning.py` 파일에서 직접 실행하고 수정해볼 수 있습니다.
--- ---
## 4. 데이터 시각화: 그림으로 데이터와 대화하기 <br>
> **🎯 1-2일차 목표:** Matplotlib와 Seaborn으로 데이터를 시각화하여 인사이트를 발견합니다.
데이터를 숫자로만 보는 것은 숲을 보지 못하고 나무만 보는 것과 같습니다. 시각화는 데이터 속에 숨겨진 패턴, 관계, 이상치를 한눈에 파악하게 해주는 강력한 도구입니다.
- **Matplotlib**: 파이썬 시각화의 근간. 거의 모든 종류의 그래프를 그릴 수 있습니다. (비유: 하얀 도화지)
- **Seaborn**: Matplotlib을 더 쉽고 예쁘게 사용하도록 만든 고수준 라이브러리. 통계 기능이 특화되어 있습니다. (비유: 밑그림과 색칠 도구가 갖춰진 스케치북)
#### 4-1. 어떤 그래프를 언제 쓸까?
- **선 그래프 (Line Plot)**: 시간에 따른 주가 변화처럼, 연속적인 데이터의 **추세**를 볼 때
- **막대 그래프 (Bar Plot)**: 반별 평균 키처럼, 여러 그룹 간의 값을 **비교**할 때
- **산점도 (Scatter Plot)**: 공부 시간과 성적처럼, 두 변수 간의 **관계**나 분포를 볼 때
- **히스토그램 (Histogram)**: 우리 반 학생들의 키 분포처럼, 데이터의 **분포**를 볼 때
- **히트맵 (Heatmap)**: 여러 변수들 간의 상관관계를 한눈에 **색상**으로 파악할 때
#### 4-2. Seaborn 실전 예제 > ## 4. 데이터 시각화: 그림으로 데이터와 대화하기
```python >
> > **🎯 1-2일차 목표:** Matplotlib와 Seaborn으로 데이터를 시각화하여 인사이트를 발견합니다.
>
> 데이터를 숫자로만 보는 것은 숲을 보지 못하고 나무만 보는 것과 같습니다. 시각화는 데이터 속에 숨겨진 패턴, 관계, 이상치를 한눈에 파악하게 해주는 강력한 도구입니다.
>
> - **Matplotlib**: 파이썬 시각화의 근간. 거의 모든 종류의 그래프를 그릴 수 있습니다. (비유: 하얀 도화지)
> - **Seaborn**: Matplotlib을 더 쉽고 예쁘게 사용하도록 만든 고수준 라이브러리. 통계 기능이 특화되어 있습니다. (비유: 밑그림과 색칠 도구가 갖춰진 스케치북)
>
> #### 4-1. 어떤 그래프를 언제 쓸까?
> - **선 그래프 (Line Plot)**: 시간에 따른 주가 변화처럼, 연속적인 데이터의 **추세**를 볼 때
> - **막대 그래프 (Bar Plot)**: 반별 평균 키처럼, 여러 그룹 간의 값을 **비교**할 때
> - **산점도 (Scatter Plot)**: 공부 시간과 성적처럼, 두 변수 간의 **관계**나 분포를 볼 때
> - **히스토그램 (Histogram)**: 우리 반 학생들의 키 분포처럼, 데이터의 **분포**를 볼 때
> - **히트맵 (Heatmap)**: 여러 변수들 간의 상관관계를 한눈에 **색상**으로 파악할 때
>
> #### 4-2. Seaborn 실전 예제
> ```python
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import seaborn as sns import seaborn as sns
...@@ -76,60 +85,64 @@ plt.show() ...@@ -76,60 +85,64 @@ plt.show()
--- ---
## 4.5. 머신러닝의 종류: 어떤 문제를 풀고 싶은가? <br>
본격적으로 모델을 만들기 전에, 머신러닝이 해결할 수 있는 문제의 종류를 이해하는 것은 매우 중요합니다. 머신러닝은 크게 **지도학습, 비지도학습, 강화학습** 세 가지로 나뉩니다. > ## 4.5. 머신러닝의 종류: 어떤 문제를 풀고 싶은가?
>
| 학습 유형 | 핵심 아이디어 | 대표적인 예시 | 주요 알고리즘 | > 본격적으로 모델을 만들기 전에, 머신러닝이 해결할 있는 문제의 종류를 이해하는 것은 매우 중요합니다. 머신러닝은 크게 **지도학습, 비지도학습, 강화학습** 가지로 나뉩니다.
| :--- | :--- | :--- | :--- | >
| **지도학습<br>(Supervised)** | **'정답'이 있는 데이터**로 학습 | 스팸 메일 분류, 집값 예측, 이미지 분류 (개/고양이) | 선형 회귀, 로지스틱 회귀, SVM, 결정 트리, 랜덤 포레스트 | > | 학습 유형 | 핵심 아이디어 | 대표적인 예시 | 주요 알고리즘 |
| **비지도학습<br>(Unsupervised)** | **'정답'이 없는 데이터**에서 패턴 발견 | 고객 그룹 분석, 토픽 모델링, 이상 탐지 | K-평균 군집, 주성분 분석(PCA) | > | :--- | :--- | :--- | :--- |
| **강화학습<br>(Reinforcement)** | **'보상'**을 최대화하는 행동을 학습 | 알파고(바둑), 자율주행, 로봇 제어 | Q-러닝, SARSA, DQN | > | **지도학습<br>(Supervised)** | **'정답' 있는 데이터** 학습 | 스팸 메일 분류, 집값 예측, 이미지 분류 (/고양이) | 선형 회귀, 로지스틱 회귀, SVM, 결정 트리, 랜덤 포레스트 |
> | **비지도학습<br>(Unsupervised)** | **'정답' 없는 데이터**에서 패턴 발견 | 고객 그룹 분석, 토픽 모델링, 이상 탐지 | K-평균 군집, 주성분 분석(PCA) |
![머신러닝 종류](https://i.imgur.com/8aE5E9U.png) > | **강화학습<br>(Reinforcement)** | **'보상'** 최대화하는 행동을 학습 | 알파고(바둑), 자율주행, 로봇 제어 | Q-러닝, SARSA, DQN |
>
이번 파트에서는 이 중에서 가장 널리 사용되고 산업적으로도 중요한 **지도학습**에 집중하여, '정답'이 주어진 데이터를 통해 미래를 예측하는 모델을 만드는 방법을 깊이 있게 다룰 것입니다. > ![머신러닝 종류](https://i.imgur.com/8aE5E9U.png)
>
> 이번 파트에서는 중에서 가장 널리 사용되고 산업적으로도 중요한 **지도학습** 집중하여, '정답' 주어진 데이터를 통해 미래를 예측하는 모델을 만드는 방법을 깊이 있게 다룰 것입니다.
--- ---
## 5. Scikit-learn으로 첫 머신러닝 모델 만들기 <br>
> **🎯 3-4일차 목표:** Scikit-learn을 사용하여 머신러닝의 기본 프로세스(학습, 예측, 평가)를 이해합니다.
### 5-1. 머신러닝의 핵심: 훈련과 시험 > ## 5. Scikit-learn으로 머신러닝 모델 만들기
- **지도학습(Supervised Learning)**: **입력(문제)****정답**이 있는 데이터를 사용해, 문제와 정답 사이의 '패턴'을 기계에 학습시키는 방법입니다. >
> > **🎯 3-4일차 목표:** Scikit-learn 사용하여 머신러닝의 기본 프로세스(학습, 예측, 평가) 이해합니다.
> **💡 비유: 머신러닝은 '공부'와 '시험' 과정입니다.** >
> - **훈련 데이터 (Training Data)**: 모델이 학습하는 데 사용하는 **'교과서/모의고사'**. > ### 5-1. 머신러닝의 핵심: 훈련과 시험
> - **테스트 데이터 (Test Data)**: 모델의 최종 성능을 평가하기 위해, 학습 과정에서 **전혀 사용하지 않은 새로운 '수능 문제'**. > - **지도학습(Supervised Learning)**: **입력(문제)** **정답** 있는 데이터를 사용해, 문제와 정답 사이의 '패턴' 기계에 학습시키는 방법입니다.
> >
> 훈련 데이터로만 반복해서 시험 보면 100점이 나오겠지만, 진짜 실력이라고 할 수 없겠죠? 그래서 우리는 훈련/테스트 데이터를 엄격히 분리하여 모델의 **일반화 성능**(처음 보는 데이터에 대한 예측 능력)을 측정합니다. > > [!NOTE] 비유: 머신러닝은 '공부'와 '시험' 과정입니다.
> > - **훈련 데이터 (Training Data)**: 모델이 학습하는 사용하는 **'교과서/모의고사'**.
### 5-2. 핵심 개념: 과적합, 과소적합, 그리고 편향-분산 트레이드오프 > > - **테스트 데이터 (Test Data)**: 모델의 최종 성능을 평가하기 위해, 학습 과정에서 **전혀 사용하지 않은 새로운 '수능 문제'**.
> >
모델을 훈련시킬 때 가장 흔하게 마주치는 문제는 **과적합(Overfitting)****과소적합(Underfitting)**입니다. > > 훈련 데이터로만 반복해서 시험 보면 100점이 나오겠지만, 진짜 실력이라고 없겠죠? 그래서 우리는 훈련/테스트 데이터를 엄격히 분리하여 모델의 **일반화 성능**(처음 보는 데이터에 대한 예측 능력) 측정합니다.
>
- **과소적합 (Underfitting)**: 모델이 너무 단순해서 데이터의 내재된 패턴을 제대로 학습하지 못하는 상태입니다. **훈련 데이터에서도 성능이 낮고, 테스트 데이터에서도 성능이 낮은** 특징을 보입니다. (비유: 시험 범위의 절반만 공부한 학생) > ### 5-2. 핵심 개념: 과적합, 과소적합, 그리고 편향-분산 트레이드오프
- **과적합 (Overfitting)**: 모델이 훈련 데이터에만 너무 과도하게 맞춰져, 노이즈나 특정 패턴까지 전부 외워버린 상태입니다. **훈련 데이터에서는 성능이 매우 높지만, 새로운 테스트 데이터에서는 성능이 급격히 떨어지는** 특징을 보입니다. (비유: 모의고사 족보만 달달 외워, 새로운 유형의 수능 문제에 대처하지 못하는 학생) >
> 모델을 훈련시킬 가장 흔하게 마주치는 문제는 **과적합(Overfitting)** **과소적합(Underfitting)**입니다.
이 두 문제는 **모델의 복잡도(Model Complexity)**와 깊은 관련이 있으며, 이를 **편향-분산 트레이드오프(Bias-Variance Tradeoff)** 라고 부릅니다. >
> - **과소적합 (Underfitting)**: 모델이 너무 단순해서 데이터의 내재된 패턴을 제대로 학습하지 못하는 상태입니다. **훈련 데이터에서도 성능이 낮고, 테스트 데이터에서도 성능이 낮은** 특징을 보입니다. (비유: 시험 범위의 절반만 공부한 학생)
![Bias-Variance Tradeoff](https://i.imgur.com/2s42p4s.png) > - **과적합 (Overfitting)**: 모델이 훈련 데이터에만 너무 과도하게 맞춰져, 노이즈나 특정 패턴까지 전부 외워버린 상태입니다. **훈련 데이터에서는 성능이 매우 높지만, 새로운 테스트 데이터에서는 성능이 급격히 떨어지는** 특징을 보입니다. (비유: 모의고사 족보만 달달 외워, 새로운 유형의 수능 문제에 대처하지 못하는 학생)
>
- **편향 (Bias)**: 모델이 실제 관계와 얼마나 다른지를 나타냅니다. 편향이 높으면 모델이 너무 단순하여 과소적합 경향을 보입니다. > 문제는 **모델의 복잡도(Model Complexity)** 깊은 관련이 있으며, 이를 **편향-분산 트레이드오프(Bias-Variance Tradeoff)** 라고 부릅니다.
- **분산 (Variance)**: 데이터의 작은 변화에 모델이 얼마나 민감하게 변하는지를 나타냅니다. 분산이 높으면 모델이 너무 복잡하여 과적합 경향을 보입니다. >
> ![Bias-Variance Tradeoff](https://i.imgur.com/2s42p4s.png)
우리의 목표는 **편향과 분산이 모두 낮은, 즉 전체 오류가 최소가 되는 '최적의 균형점(Optimal Balance)'**을 찾는 것입니다. >
> - **편향 (Bias)**: 모델이 실제 관계와 얼마나 다른지를 나타냅니다. 편향이 높으면 모델이 너무 단순하여 과소적합 경향을 보입니다.
### 5-3. Scikit-learn 기본 4단계 프로세스 > - **분산 (Variance)**: 데이터의 작은 변화에 모델이 얼마나 민감하게 변하는지를 나타냅니다. 분산이 높으면 모델이 너무 복잡하여 과적합 경향을 보입니다.
Scikit-learn은 다음과 같은 통일된 인터페이스를 제공하여 누구나 쉽게 머신러닝 모델을 만들 수 있게 해줍니다. >
> 우리의 목표는 **편향과 분산이 모두 낮은, 전체 오류가 최소가 되는 '최적의 균형점(Optimal Balance)'** 찾는 것입니다.
1. **모델 객체 생성**: `model = ModelName()` >
2. **모델 학습**: `model.fit(X_train, y_train)` (훈련 데이터로 공부) > ### 5-3. Scikit-learn 기본 4단계 프로세스
3. **예측**: `predictions = model.predict(X_test)` (테스트 데이터로 시험) > Scikit-learn 다음과 같은 통일된 인터페이스를 제공하여 누구나 쉽게 머신러닝 모델을 만들 있게 해줍니다.
4. **평가**: `score = accuracy_score(y_test, predictions)` (채점) >
> 1. **모델 객체 생성**: `model = ModelName()`
```python > 2. **모델 학습**: `model.fit(X_train, y_train)` (훈련 데이터로 공부)
> 3. **예측**: `predictions = model.predict(X_test)` (테스트 데이터로 시험)
> 4. **평가**: `score = accuracy_score(y_test, predictions)` (채점)
>
> ```python
from sklearn.model_selection import train_test_split from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score from sklearn.metrics import accuracy_score
...@@ -163,7 +176,7 @@ print(f"정확도: {accuracy:.4f}") ...@@ -163,7 +176,7 @@ print(f"정확도: {accuracy:.4f}")
- **StandardScaler**: 평균 0, 표준편차 1로 변환. (분포가 정규분포에 가까울 때 효과적) - **StandardScaler**: 평균 0, 표준편차 1로 변환. (분포가 정규분포에 가까울 때 효과적)
- **MinMaxScaler**: 최솟값 0, 최댓값 1로 변환. (모든 값을 0과 1 사이로 만들고 싶을 때) - **MinMaxScaler**: 최솟값 0, 최댓값 1로 변환. (모든 값을 0과 1 사이로 만들고 싶을 때)
> **💡 스케일러의 수학적 원리** > [!NOTE] 스케일러의 수학적 원리
> >
> - **StandardScaler (표준화)**: 각 특성의 평균(μ)을 0, 표준편차(σ)를 1로 만듭니다. > - **StandardScaler (표준화)**: 각 특성의 평균(μ)을 0, 표준편차(σ)를 1로 만듭니다.
> \[ z = \frac{x - \mu}{\sigma} \] > \[ z = \frac{x - \mu}{\sigma} \]
...@@ -172,8 +185,8 @@ print(f"정확도: {accuracy:.4f}") ...@@ -172,8 +185,8 @@ print(f"정확도: {accuracy:.4f}")
> - **MinMaxScaler (정규화)**: 각 특성의 모든 값을 0과 1 사이로 조정합니다. > - **MinMaxScaler (정규화)**: 각 특성의 모든 값을 0과 1 사이로 조정합니다.
> \[ x' = \frac{x - \min(x)}{\max(x) - \min(x)} \] > \[ x' = \frac{x - \min(x)}{\max(x) - \min(x)} \]
> 이미지 픽셀 값을 0~255에서 0~1 사이로 변환하거나, 신경망 모델의 입력으로 사용할 때 자주 사용됩니다. > 이미지 픽셀 값을 0~255에서 0~1 사이로 변환하거나, 신경망 모델의 입력으로 사용할 때 자주 사용됩니다.
>
```python > ```python
from sklearn.preprocessing import StandardScaler, MinMaxScaler from sklearn.preprocessing import StandardScaler, MinMaxScaler
import numpy as np import numpy as np
...@@ -244,7 +257,7 @@ Scikit-learn에는 수많은 머신러닝 모델이 존재합니다. 문제의 ...@@ -244,7 +257,7 @@ Scikit-learn에는 수많은 머신러닝 모델이 존재합니다. 문제의
| **랜덤 포레스트<br>(Random Forest)** | 여러 개의 작은 결정 트리들을 만들어, 그 결과를 **투표(Voting)**하여 종합. (앙상블 기법) | **성능이 매우 우수함**. 과적합에 강하고 안정적임. | 결정 트리보다 **해석이 어려움 (Black Box)**. 훈련 속도가 느리고 메모리를 더 많이 사용. | **높은 예측 성능**이 가장 중요할 때. 대부분의 분류 문제에서 좋은 성능을 보임. | | **랜덤 포레스트<br>(Random Forest)** | 여러 개의 작은 결정 트리들을 만들어, 그 결과를 **투표(Voting)**하여 종합. (앙상블 기법) | **성능이 매우 우수함**. 과적합에 강하고 안정적임. | 결정 트리보다 **해석이 어려움 (Black Box)**. 훈련 속도가 느리고 메모리를 더 많이 사용. | **높은 예측 성능**이 가장 중요할 때. 대부분의 분류 문제에서 좋은 성능을 보임. |
| **서포트 벡터 머신<br>(SVM)** | 클래스 간의 **마진(Margin)을 최대화**하는 결정 경계를 찾음. | 고차원 데이터에서 잘 작동하며, 과적합에 강함. | 데이터가 많을 때 훈련 속도가 매우 느림. 파라미터 튜닝에 민감함. | 특성(Feature)이 매우 많은 복잡한 데이터셋 (e.g., 이미지, 바이오인포매틱스)에 효과적. | | **서포트 벡터 머신<br>(SVM)** | 클래스 간의 **마진(Margin)을 최대화**하는 결정 경계를 찾음. | 고차원 데이터에서 잘 작동하며, 과적합에 강함. | 데이터가 많을 때 훈련 속도가 매우 느림. 파라미터 튜닝에 민감함. | 특성(Feature)이 매우 많은 복잡한 데이터셋 (e.g., 이미지, 바이오인포매틱스)에 효과적. |
> **💡 핵심 질문: 해석 가능성(Interpretability) vs. 성능(Performance)** > [!NOTE] 핵심 질문: 해석 가능성(Interpretability) vs. 성능(Performance)
> - **해석이 중요하다면?** -> Logistic Regression, Decision Tree > - **해석이 중요하다면?** -> Logistic Regression, Decision Tree
> - **성능이 중요하다면?** -> Random Forest, Gradient Boosting (더 발전된 앙상블), SVM > - **성능이 중요하다면?** -> Random Forest, Gradient Boosting (더 발전된 앙상블), SVM
> >
...@@ -266,7 +279,7 @@ Scikit-learn에는 수많은 머신러닝 모델이 존재합니다. 문제의 ...@@ -266,7 +279,7 @@ Scikit-learn에는 수많은 머신러닝 모델이 존재합니다. 문제의
![K-Fold Cross Validation](https://i.imgur.com/0K3jTf7.png) ![K-Fold Cross Validation](https://i.imgur.com/0K3jTf7.png)
> **💡 장점:** > [!NOTE] 장점:
> - 데이터를 더 효율적으로 사용하며, 모델의 성능을 훨씬 더 안정적이고 신뢰성 있게 평가할 수 있습니다. > - 데이터를 더 효율적으로 사용하며, 모델의 성능을 훨씬 더 안정적이고 신뢰성 있게 평가할 수 있습니다.
> - 특정 데이터 분할에 따른 성능 변동의 위험을 줄여줍니다. > - 특정 데이터 분할에 따른 성능 변동의 위험을 줄여줍니다.
...@@ -285,7 +298,6 @@ print(f"교차 검증 점수: {scores}") ...@@ -285,7 +298,6 @@ print(f"교차 검증 점수: {scores}")
print(f"평균 정확도: {scores.mean():.4f} (+/- {scores.std() * 2:.4f})") print(f"평균 정확도: {scores.mean():.4f} (+/- {scores.std() * 2:.4f})")
``` ```
### 5-8. 실제 기업 적용 사례 (Real-world Enterprise Use Cases) ### 5-8. 실제 기업 적용 사례 (Real-world Enterprise Use Cases)
우리가 배운 머신러닝 기술은 단순히 학문적인 개념에 머무르지 않고, 오늘날 수많은 글로벌 기업들의 핵심 서비스를 구동하는 엔진이 되고 있습니다. 몇 가지 대표적인 사례를 통해 머신러닝이 실제로 어떻게 가치를 창출하는지 살펴보겠습니다. 우리가 배운 머신러닝 기술은 단순히 학문적인 개념에 머무르지 않고, 오늘날 수많은 글로벌 기업들의 핵심 서비스를 구동하는 엔진이 되고 있습니다. 몇 가지 대표적인 사례를 통해 머신러닝이 실제로 어떻게 가치를 창출하는지 살펴보겠습니다.
...@@ -298,7 +310,7 @@ print(f"평균 정확도: {scores.mean():.4f} (+/- {scores.std() * 2:.4f})") ...@@ -298,7 +310,7 @@ print(f"평균 정확도: {scores.mean():.4f} (+/- {scores.std() * 2:.4f})")
| **Meta (Facebook)** | **뉴스피드 랭킹** | 랭킹 알고리즘, 대규모 추천 시스템 | 수천 개의 잠재적 게시물 중 사용자에게 가장 흥미로울 만한 콘텐츠를 예측하여 보여줌으로써, **플랫폼 체류 시간을 늘리고** 광고 효율을 높임. | | **Meta (Facebook)** | **뉴스피드 랭킹** | 랭킹 알고리즘, 대규모 추천 시스템 | 수천 개의 잠재적 게시물 중 사용자에게 가장 흥미로울 만한 콘텐츠를 예측하여 보여줌으로써, **플랫폼 체류 시간을 늘리고** 광고 효율을 높임. |
| **Amazon** | **상품 추천 (Customers who bought this item also bought...)** | 협업 필터링 (Item-to-Item), 개인화 랭킹 | 사용자의 구매 패턴을 분석하여 관련 상품을 추천함으로써, **객단가(Average Order Value)를 높이고** 새로운 상품을 발견할 기회를 제공. | | **Amazon** | **상품 추천 (Customers who bought this item also bought...)** | 협업 필터링 (Item-to-Item), 개인화 랭킹 | 사용자의 구매 패턴을 분석하여 관련 상품을 추천함으로써, **객단가(Average Order Value)를 높이고** 새로운 상품을 발견할 기회를 제공. |
> **💡 시사점: 문제 정의의 중요성** > [!NOTE] 시사점: 문제 정의의 중요성
> 위 사례들의 공통점은 기술 자체가 목적이 아니라, '고객 이탈 방지', '사용자 경험 보호', '관련성 높은 정보 제공'과 같은 **명확한 비즈니스 문제를 해결하기 위해 머신러닝을 '도구'로 사용했다는 점**입니다. 성공적인 머신러닝 프로젝트를 위해서는 "어떤 모델을 쓸까?" 보다 "**어떤 문제를 풀고 싶은가?**"를 먼저 정의하는 것이 중요합니다. > 위 사례들의 공통점은 기술 자체가 목적이 아니라, '고객 이탈 방지', '사용자 경험 보호', '관련성 높은 정보 제공'과 같은 **명확한 비즈니스 문제를 해결하기 위해 머신러닝을 '도구'로 사용했다는 점**입니다. 성공적인 머신러닝 프로젝트를 위해서는 "어떤 모델을 쓸까?" 보다 "**어떤 문제를 풀고 싶은가?**"를 먼저 정의하는 것이 중요합니다.
--- ---
...@@ -325,7 +337,6 @@ Scikit-learn을 사용하면 몇 줄의 코드로 쉽게 모델을 만들 수 ...@@ -325,7 +337,6 @@ Scikit-learn을 사용하면 몇 줄의 코드로 쉽게 모델을 만들 수
- 이러한 의사 결정이 왜 섣부른 판단일 수 있을까요? 랜덤 포레스트는 특성 중요도를 어떤 방식으로 계산하나요? - 이러한 의사 결정이 왜 섣부른 판단일 수 있을까요? 랜덤 포레스트는 특성 중요도를 어떤 방식으로 계산하나요?
- 높은 특성 중요도가 '인과 관계'를 의미할까요, 아니면 단순한 '상관 관계'일 가능성이 높을까요? 이처럼 중요한 비즈니스 결정을 내리기 전에, 어떤 추가적인 분석이나 실험을 수행해야 할까요? - 높은 특성 중요도가 '인과 관계'를 의미할까요, 아니면 단순한 '상관 관계'일 가능성이 높을까요? 이처럼 중요한 비즈니스 결정을 내리기 전에, 어떤 추가적인 분석이나 실험을 수행해야 할까요?
## 8. 되짚어보기 (Summary) ## 8. 되짚어보기 (Summary)
이번 주 우리는 데이터에서 패턴을 찾아 미래를 예측하는 머신러닝의 세계를 여행했습니다. 이번 주 우리는 데이터에서 패턴을 찾아 미래를 예측하는 머신러닝의 세계를 여행했습니다.
......
# Part 7: Deep Learning > # Part 7: Deep Learning
<br>
이 파트에서는 인공 신경망의 개념부터 시작하여 CNN, RNN, Transformer 등 주요 딥러닝 아키텍처를 학습하고, PyTorch와 LangChain을 이용해 LLM 애플리케이션까지 구축하는 방법을 다룹니다. 이 파트에서는 인공 신경망의 개념부터 시작하여 CNN, RNN, Transformer 등 주요 딥러닝 아키텍처를 학습하고, PyTorch와 LangChain을 이용해 LLM 애플리케이션까지 구축하는 방법을 다룹니다.
## 📚 학습 자료 <br>
> ## 📚 학습 자료
- **[메인 강의 노트](./part_7_deep_learning.md)**: 딥러닝의 전반적인 개념을 소개합니다. - **[메인 강의 노트](./part_7_deep_learning.md)**: 딥러닝의 전반적인 개념을 소개합니다.
- **[7.1 순환 신경망 (RNN)](./part_7.1_recurrent_neural_networks.md)** - **[7.1 순환 신경망 (RNN)](./part_7.1_recurrent_neural_networks.md)**
...@@ -13,11 +17,15 @@ ...@@ -13,11 +17,15 @@
- **[핵심 용어집](../../glossary.md)** - **[핵심 용어집](../../glossary.md)**
- **[LLM 앱 개발 용어집](./glossary_llm_application.md)** - **[LLM 앱 개발 용어집](./glossary_llm_application.md)**
## 💻 실습 코드 <br>
> ## 💻 실습 코드
- **[딥러닝 예제 코드](../../source_code/07_deep_learning/part_7_deep_learning.py)** - **[딥러닝 예제 코드](../../source_code/07_deep_learning/part_7_deep_learning.py)**
- **[LLM 앱 개발 예제 코드](../../source_code/07_deep_learning/7.3_llm_application_development_with_langchain/part_7.3_llm_application_development.py)** - **[LLM 앱 개발 예제 코드](../../source_code/07_deep_learning/7.3_llm_application_development_with_langchain/part_7.3_llm_application_development.py)**
--- ---
<br>
[↩️ 전체 커리큘럼으로 돌아가기](../../README.md) [↩️ 전체 커리큘럼으로 돌아가기](../../README.md)
\ No newline at end of file
# Live Coding 시나리오: Transformer Block 직접 만들어보기 # Live Coding 시나리오: Transformer Block 직접 만들어보기
## 학습 목표 (Learning Objectives) <br>
Transformer의 핵심 구성 요소인 Self-Attention, Multi-Head Attention, Feed-Forward Network를 PyTorch를 사용하여 밑바닥부터(from scratch) 구현함으로써 Transformer의 내부 동작 원리를 깊이 있게 이해합니다. > ## 학습 목표 (Learning Objectives)
>
> Transformer의 핵심 구성 요소인 Self-Attention, Multi-Head Attention, Feed-Forward Network를 PyTorch를 사용하여 밑바닥부터(from scratch) 구현함으로써 Transformer의 내부 동작 원리를 깊이 있게 이해합니다.
## 핵심 요약 (Key takeaways) <br>
Transformer의 핵심 동작 원리를 이해하기 위해, PyTorch를 사용해 주요 구성 요소인 Scaled Dot-Product Attention, Multi-Head Attention, Feed-Forward Network를 직접 구현합니다. 이 과정에서 Q, K, V의 개념과 행렬 연산, 마스킹, 그리고 여러 Attention 헤드를 사용하는 이유를 학습합니다. 최종적으로 이들을 결합하고 잔차 연결(Residual Connection)과 Layer Normalization을 추가하여 완전한 Transformer Block 하나를 조립합니다. > ## 핵심 요약 (Key takeaways)
>
**대상:** Python 및 PyTorch 기본 문법에 익숙하지만, Transformer의 내부 구조를 더 명확히 알고 싶은 개발자 > Transformer의 핵심 동작 원리를 이해하기 위해, PyTorch를 사용해 주요 구성 요소인 Scaled Dot-Product Attention, Multi-Head Attention, Feed-Forward Network를 직접 구현합니다. 이 과정에서 Q, K, V의 개념과 행렬 연산, 마스킹, 그리고 여러 Attention 헤드를 사용하는 이유를 학습합니다. 최종적으로 이들을 결합하고 잔차 연결(Residual Connection)과 Layer Normalization을 추가하여 완전한 Transformer Block 하나를 조립합니다.
>
**예상 소요 시간:** 45-50분 > **대상:** Python 및 PyTorch 기본 문법에 익숙하지만, Transformer의 내부 구조를 더 명확히 알고 싶은 개발자
>
**결과물:** `source_code/07_deep_learning/live_coding_transformer_from_scratch.py` > **예상 소요 시간:** 45-50분
>
> **결과물:** `source_code/07_deep_learning/live_coding_transformer_from_scratch.py`
--- ---
## 세션 개요 및 진행 계획 <br>
| 시간 (분) | 내용 | 핵심 포인트 | > ## 세션 개요 및 진행 계획
| :-------- | :------------------------------------------------------------------------ | :--------------------------------------------------------------------------- | >
| 5 | **도입:** Transformer 아키텍처 개요 및 Live Coding 목표 소개 | "Attention is All You Need", Encoder-Decoder 구조, 오늘 만들 부분(Block) 소개 | > | 시간 (분) | 내용 | 핵심 포인트 |
| 15 | **Part 1: Scaled Dot-Product Attention 구현** | Q, K, V의 의미, 행렬 연산, 마스킹(masking)의 역할, 스케일링(scaling)의 중요성 | > | :-------- | :------------------------------------------------------------------------ | :--------------------------------------------------------------------------- |
| 15 | **Part 2: Multi-Head Attention 구현** | Attention을 여러 "헤드"로 나누는 이유, `split``concat`을 통한 구현 | > | 5 | **도입:** Transformer 아키텍처 개요 및 Live Coding 목표 소개 | "Attention is All You Need", Encoder-Decoder 구조, 오늘 만들 부분(Block) 소개 |
| 10 | **Part 3: Transformer Block 조립** | 잔차 연결(Residual Connection)과 Layer Normalization의 역할, FFN 추가 | > | 15 | **Part 1: Scaled Dot-Product Attention 구현** | Q, K, V의 의미, 행렬 연산, 마스킹(masking)의 역할, 스케일링(scaling)의 중요성 |
| 5 | **마무리:** 완성된 코드 리뷰 및 전체 아키텍처 내에서의 역할 설명, Q&A | Encoder Block과 Decoder Block의 차이점, 다음 학습 단계 제안 | > | 15 | **Part 2: Multi-Head Attention 구현** | Attention을 여러 "헤드"로 나누는 이유, `split`과 `concat`을 통한 구현 |
> | 10 | **Part 3: Transformer Block 조립** | 잔차 연결(Residual Connection)과 Layer Normalization의 역할, FFN 추가 |
> | 5 | **마무리:** 완성된 코드 리뷰 및 전체 아키텍처 내에서의 역할 설명, Q&A | Encoder Block과 Decoder Block의 차이점, 다음 학습 단계 제안 |
--- ---
## Live Coding 상세 시나리오 <br>
### 1. 도입 (5분) > ## Live Coding 상세 시나리오
>
- Transformer가 NLP뿐만 아니라 다양한 분야에서 왜 혁신적인지를 간략히 설명합니다. > ### 1. 도입 (5분)
- "Attention is All You Need" 논문의 핵심 아이디어(RNN/CNN 없이 Attention만으로 시퀀스 처리)를 강조합니다. >
- 거대한 Transformer 아키텍처 그림을 보여주며, 오늘 우리가 집중할 부분은 이 아키텍처를 구성하는 핵심 부품인 'Encoder Block' 또는 'Decoder Block' 하나라는 것을 명확히 합니다. > - Transformer가 NLP뿐만 아니라 다양한 분야에서 왜 혁신적인지를 간략히 설명합니다.
> - "Attention is All You Need" 논문의 핵심 아이디어(RNN/CNN 없이 Attention만으로 시퀀스 처리)를 강조합니다.
### 2. Part 1: Scaled Dot-Product Attention (15분) > - 거대한 Transformer 아키텍처 그림을 보여주며, 오늘 우리가 집중할 부분은 이 아키텍처를 구성하는 핵심 부품인 'Encoder Block' 또는 'Decoder Block' 하나라는 것을 명확히 합니다.
>
- **개념 설명**: > ### 2. Part 1: Scaled Dot-Product Attention (15분)
- Attention의 직관적 의미를 "Query가 Key와의 유사도를 계산하여 Value의 가중합을 얻는 과정"으로 설명합니다. >
- Q, K, V 행렬의 형태(shape)와 의미를 설명합니다. `(batch_size, seq_len, d_model)` > - **개념 설명**:
- **코드 구현**: > - Attention의 직관적 의미를 "Query가 Key와의 유사도를 계산하여 Value의 가중합을 얻는 과정"으로 설명합니다.
- `torch.matmul(q, k.transpose(-2, -1))` 로 Attention Score를 계산하는 것부터 시작합니다. > - Q, K, V 행렬의 형태(shape)와 의미를 설명합니다. `(batch_size, seq_len, d_model)`
- 스케일링 팩터 `sqrt(d_k)`로 나누는 이유(gradient 안정화)를 설명하며 코드를 추가합니다. > - **코드 구현**:
- (선택적) 마스킹이 필요한 이유(padding token 무시, decoder의 look-ahead 방지)를 설명하고, `masked_fill_`을 사용하여 구현합니다. > - `torch.matmul(q, k.transpose(-2, -1))` 로 Attention Score를 계산하는 것부터 시작합니다.
- `torch.softmax`를 적용하여 최종 Attention Weight를 얻고, 이를 `v`와 곱하여 결과(context vector)를 계산하는 코드를 완성합니다. > - 스케일링 팩터 `sqrt(d_k)`로 나누는 이유(gradient 안정화)를 설명하며 코드를 추가합니다.
- 입력과 출력의 텐서 형태가 동일하게 유지됨을 확인합니다. > - (선택적) 마스킹이 필요한 이유(padding token 무시, decoder의 look-ahead 방지)를 설명하고, `masked_fill_`을 사용하여 구현합니다.
> - `torch.softmax`를 적용하여 최종 Attention Weight를 얻고, 이를 `v`와 곱하여 결과(context vector)를 계산하는 코드를 완성합니다.
### 3. Part 2: Multi-Head Attention (15분) > - 입력과 출력의 텐서 형태가 동일하게 유지됨을 확인합니다.
>
- **개념 설명**: > ### 3. Part 2: Multi-Head Attention (15분)
- "한 번에 보는 것보다, 여러 관점에서 나누어 보는 것"이 왜 더 효과적인지를 비유적으로 설명합니다. (e.g., "문장의 다른 의미적/문법적 관계를 동시에 파악") >
- `d_model` 차원의 벡터를 `num_heads`개의 `d_k` (d_model / num_heads) 차원 벡터로 나누는 과정을 설명합니다. > - **개념 설명**:
- **코드 구현**: > - "한 번에 보는 것보다, 여러 관점에서 나누어 보는 것"이 왜 더 효과적인지를 비유적으로 설명합니다. (e.g., "문장의 다른 의미적/문법적 관계를 동시에 파악")
- 입력으로 들어온 Q, K, V를 각각 `nn.Linear`를 통과시켜 새로운 Q, K, V를 만듭니다. > - `d_model` 차원의 벡터를 `num_heads`개의 `d_k` (d_model / num_heads) 차원 벡터로 나누는 과정을 설명합니다.
- 이 Q, K, V를 `num_heads`에 맞게 `split`하고 `transpose`하여 `(batch_size, num_heads, seq_len, d_k)` 형태로 변환하는 함수를 작성합니다. > - **코드 구현**:
- Part 1에서 만든 `scaled_dot_product_attention` 함수를 재사용하여 Attention을 계산합니다. > - 입력으로 들어온 Q, K, V를 각각 `nn.Linear`를 통과시켜 새로운 Q, K, V를 만듭니다.
- Attention 계산 후, 흩어졌던 헤드들을 `concat`하고 `nn.Linear`를 통과시켜 최종 출력을 만드는 코드를 완성합니다. > - 이 Q, K, V를 `num_heads`에 맞게 `split`하고 `transpose`하여 `(batch_size, num_heads, seq_len, d_k)` 형태로 변환하는 함수를 작성합니다.
- `nn.Module`을 상속받아 `MultiHeadAttention` 클래스로 전체 로직을 캡슐화합니다. > - Part 1에서 만든 `scaled_dot_product_attention` 함수를 재사용하여 Attention을 계산합니다.
> - Attention 계산 후, 흩어졌던 헤드들을 `concat`하고 `nn.Linear`를 통과시켜 최종 출력을 만드는 코드를 완성합니다.
### 4. Part 3: Transformer Block 조립 (10분) > - `nn.Module`을 상속받아 `MultiHeadAttention` 클래스로 전체 로직을 캡슐화합니다.
>
- **개념 설명**: > ### 4. Part 3: Transformer Block 조립 (10분)
- Add & Norm (잔차 연결 + Layer Normalization)의 역할을 설명합니다. (그래디언트 소실 문제 완화, 학습 안정화) >
- Position-wise Feed-Forward Network (FFN)의 구조와 역할을 설명합니다. (비선형성 추가) > - **개념 설명**:
- **코드 구현**: > - Add & Norm (잔차 연결 + Layer Normalization)의 역할을 설명합니다. (그래디언트 소실 문제 완화, 학습 안정화)
- **Sub-layer 1**: `MultiHeadAttention`을 적용한 결과에 `input`을 더하고(`x + self.attention(x)`) `LayerNorm`을 적용합니다. > - Position-wise Feed-Forward Network (FFN)의 구조와 역할을 설명합니다. (비선형성 추가)
- **Sub-layer 2**: 위 결과물을 `FFN`에 통과시킨 후, 다시 한번 Add & Norm을 적용합니다. > - **코드 구현**:
- 위 과정을 `EncoderBlock` (또는 `DecoderBlock`) 이라는 `nn.Module` 클래스로 캡슐화합니다. > - **Sub-layer 1**: `MultiHeadAttention`을 적용한 결과에 `input`을 더하고(`x + self.attention(x)`) `LayerNorm`을 적용합니다.
> - **Sub-layer 2**: 위 결과물을 `FFN`에 통과시킨 후, 다시 한번 Add & Norm을 적용합니다.
### 5. 마무리 (5분) > - 위 과정을 `EncoderBlock` (또는 `DecoderBlock`) 이라는 `nn.Module` 클래스로 캡슐화합니다.
>
- 오늘 만든 Transformer Block이 어떻게 여러 개 쌓여 전체 Encoder/Decoder를 구성하는지 보여줍니다. > ### 5. 마무리 (5분)
- Encoder Block과 Decoder Block의 미세한 차이(Masked Multi-Head Attention 사용 여부 등)를 짚어줍니다. >
- 완성된 `live_coding_transformer_from_scratch.py` 코드를 전체적으로 리뷰합니다. > - 오늘 만든 Transformer Block이 어떻게 여러 개 쌓여 전체 Encoder/Decoder를 구성하는지 보여줍니다.
- `transformers` 라이브러리의 `BertModel`과 같은 실제 구현체와 오늘 만든 코드의 관계를 설명하며, 라이브러리 사용의 중요성을 강조합니다. > - Encoder Block과 Decoder Block의 미세한 차이(Masked Multi-Head Attention 사용 여부 등)를 짚어줍니다.
- Q&A 시간을 갖습니다. > - 완성된 `live_coding_transformer_from_scratch.py` 코드를 전체적으로 리뷰합니다.
\ No newline at end of file > - `transformers` 라이브러리의 `BertModel`과 같은 실제 구현체와 오늘 만든 코드의 관계를 설명하며, 라이브러리 사용의 중요성을 강조합니다.
> - Q&A 시간을 갖습니다.
\ No newline at end of file
...@@ -5,97 +5,111 @@ ...@@ -5,97 +5,111 @@
--- ---
## 1. 학습 목표 (Learning Objectives) <br>
이번 파트가 끝나면, 여러분은 다음을 할 수 있게 됩니다. > ## 1. 학습 목표 (Learning Objectives)
>
- 순차 데이터(Sequential Data)의 특징을 이해하고 RNN이 왜 필요한지 설명할 수 있습니다. > 이번 파트가 끝나면, 여러분은 다음을 할 수 있게 됩니다.
- RNN의 기본 구조와 순환하는 아이디어, 그리고 은닉 상태(Hidden State)의 역할을 이해합니다. >
- 장기 의존성 문제(Vanishing/Exploding Gradient)가 무엇인지 설명할 수 있습니다. > - 순차 데이터(Sequential Data)의 특징을 이해하고 RNN이 왜 필요한지 설명할 수 있습니다.
- LSTM의 게이트(Gate) 구조가 어떻게 장기 의존성 문제를 해결하는지 기본 원리를 이해합니다. > - RNN의 기본 구조와 순환하는 아이디어, 그리고 은닉 상태(Hidden State)의 역할을 이해합니다.
- PyTorch를 사용하여 간단한 RNN/LSTM 모델을 구축하고 텍스트 생성 문제를 해결할 수 있습니다. > - 장기 의존성 문제(Vanishing/Exploding Gradient)가 무엇인지 설명할 수 있습니다.
> - LSTM의 게이트(Gate) 구조가 어떻게 장기 의존성 문제를 해결하는지 기본 원리를 이해합니다.
## 2. 핵심 요약 (Key takeaways) > - PyTorch를 사용하여 간단한 RNN/LSTM 모델을 구축하고 텍스트 생성 문제를 해결할 수 있습니다.
순서가 중요한 순차 데이터를 처리하기 위해 RNN(순환 신경망)이 등장했습니다. RNN은 출력이 다시 입력으로 들어가는 순환 구조와 과거 정보를 기억하는 은닉 상태를 특징으로 하지만, 정보가 길어지면 과거를 잊는 장기 의존성 문제가 발생합니다. 이 문제를 해결하기 위해 등장한 LSTM은 셀 상태와 3개의 게이트(망각, 입력, 출력)를 통해 정보의 흐름을 정교하게 제어하여 효과적인 장기 기억을 가능하게 합니다. 이를 바탕으로 텍스트 생성, 시계열 예측 등 다양한 문제를 해결할 수 있습니다. <br>
## 3. 도입: 과거를 기억하는 모델, RNN > ## 2. 핵심 요약 (Key Summary)
>
지금까지 우리가 다룬 MLP나 CNN은 입력 데이터 간의 순서나 시간적인 관계를 고려하지 않았습니다. 사진 속 고양이의 픽셀 위치는 중요하지만, '고양이'라는 단어를 이루는 '고', '양', '이' 글자들은 **순서**가 없다면 의미가 없습니다. > 순서가 중요한 순차 데이터를 처리하기 위해 RNN(순환 신경망)이 등장했습니다. RNN은 출력이 다시 입력으로 들어가는 순환 구조와 과거 정보를 기억하는 은닉 상태를 특징으로 하지만, 정보가 길어지면 과거를 잊는 장기 의존성 문제가 발생합니다. 이 문제를 해결하기 위해 등장한 LSTM은 셀 상태와 3개의 게이트(망각, 입력, 출력)를 통해 정보의 흐름을 정교하게 제어하여 효과적인 장기 기억을 가능하게 합니다. 이를 바탕으로 텍스트 생성, 시계열 예측 등 다양한 문제를 해결할 수 있습니다.
이렇게 **순서가 중요한 데이터****순차 데이터(Sequential Data)**라고 합니다. <br>
- **텍스트**: 단어의 순서가 문장의 의미를 결정합니다. ("나는 너를 좋아해" vs "너는 나를 좋아해")
- **시계열 데이터**: 주가, 날씨 등 시간의 흐름에 따라 기록된 데이터입니다. 어제의 주가가 오늘의 주가에 영향을 미칩니다. > ## 3. 도입: 과거를 기억하는 모델, RNN
- **음성**: 소리의 파형은 시간 순서대로 이어져 의미를 가집니다. >
> 지금까지 우리가 다룬 MLP나 CNN은 입력 데이터 간의 순서나 시간적인 관계를 고려하지 않았습니다. 사진 속 고양이의 픽셀 위치는 중요하지만, '고양이'라는 단어를 이루는 '고', '양', '이' 글자들은 **순서**가 없다면 의미가 없습니다.
**순환 신경망(Recurrent Neural Network, RNN)**은 바로 이 순차 데이터를 처리하기 위해 탄생한 특별한 아키텍처입니다. RNN은 모델 내부에 '기억'을 할 수 있는 **순환(Recurrent)** 구조를 가지고 있어, 이전 시간 단계(time step)의 정보를 현재 계산에 활용할 수 있습니다. >
> 이렇게 **순서가 중요한 데이터**를 **순차 데이터(Sequential Data)**라고 합니다.
> - **텍스트**: 단어의 순서가 문장의 의미를 결정합니다. ("나는 너를 좋아해" vs "너는 나를 좋아해")
> - **시계열 데이터**: 주가, 날씨 등 시간의 흐름에 따라 기록된 데이터입니다. 어제의 주가가 오늘의 주가에 영향을 미칩니다.
> - **음성**: 소리의 파형은 시간 순서대로 이어져 의미를 가집니다.
>
> **순환 신경망(Recurrent Neural Network, RNN)**은 바로 이 순차 데이터를 처리하기 위해 탄생한 특별한 아키텍처입니다. RNN은 모델 내부에 '기억'을 할 수 있는 **순환(Recurrent)** 구조를 가지고 있어, 이전 시간 단계(time step)의 정보를 현재 계산에 활용할 수 있습니다.
--- ---
## 4. RNN의 작동 원리 <br>
### 4-1. 순환과 은닉 상태 (Recurrence and Hidden State) > ## 4. RNN의 작동 원리
>
RNN의 핵심 아이디어는 간단합니다. 네트워크의 출력이 다시 자기 자신에게 입력으로 들어가는 것입니다. > ### 4-1. 순환과 은닉 상태 (Recurrence and Hidden State)
>
![RNN Unrolled](https://i.imgur.com/4f2p7gH.png) > RNN의 핵심 아이디어는 간단합니다. 네트워크의 출력이 다시 자기 자신에게 입력으로 들어가는 것입니다.
*(이미지 출처: Christopher Olah's Blog)* >
> ![RNN Unrolled](https://i.imgur.com/4f2p7gH.png)
왼쪽의 압축된 형태를 보면, RNN 계층은 입력(`x_t`)을 받아 출력(`h_t`)을 내보내고, 이 출력(`h_t`)이 다시 다음 계산을 위해 자기 자신에게 입력됩니다. 이 과정을 오른쪽처럼 시간의 흐름에 따라 펼쳐보면(Unrolled), 각 시간 단계(time step)별로 동일한 가중치를 공유하는 네트워크가 연결된 모습과 같습니다. > *(이미지 출처: Christopher Olah's Blog)*
>
여기서 가장 중요한 개념은 **은닉 상태(Hidden State)**, 즉 `h_t` 입니다. > 왼쪽의 압축된 형태를 보면, RNN 계층은 입력(`x_t`)을 받아 출력(`h_t`)을 내보내고, 이 출력(`h_t`)이 다시 다음 계산을 위해 자기 자신에게 입력됩니다. 이 과정을 오른쪽처럼 시간의 흐름에 따라 펼쳐보면(Unrolled), 각 시간 단계(time step)별로 동일한 가중치를 공유하는 네트워크가 연결된 모습과 같습니다.
>
- **은닉 상태 (h_t)**: 해당 시간 단계 `t`까지의 '기억' 또는 '문맥'을 요약한 벡터입니다. 이 벡터는 이전 시간 단계의 은닉 상태(`h_t-1`)와 현재 시간 단계의 입력(`x_t`)을 함께 사용하여 계산됩니다. > 여기서 가장 중요한 개념은 **은닉 상태(Hidden State)**, 즉 `h_t` 입니다.
- **수식**: `h_t = tanh(W_xh * x_t + W_hh * h_t-1 + b)` >
- `W_xh`: 입력 `x_t`에 대한 가중치 > - **은닉 상태 (h_t)**: 해당 시간 단계 `t`까지의 '기억' 또는 '문맥'을 요약한 벡터입니다. 이 벡터는 이전 시간 단계의 은닉 상태(`h_t-1`)와 현재 시간 단계의 입력(`x_t`)을 함께 사용하여 계산됩니다.
- `W_hh`: 이전 은닉 상태 `h_t-1`에 대한 가중치 > - **수식**: `h_t = tanh(W_xh * x_t + W_hh * h_t-1 + b)`
- `b`: 편향(bias) > - `W_xh`: 입력 `x_t`에 대한 가중치
- `tanh`: 활성화 함수 (주로 Tanh가 사용됨) > - `W_hh`: 이전 은닉 상태 `h_t-1`에 대한 가중치
> - `b`: 편향(bias)
이 과정을 통해 RNN은 "나는", "너를" 이라는 단어를 순서대로 읽으며, "좋아해"라는 단어가 나올 차례라는 것을 예측할 수 있게 됩니다. > - `tanh`: 활성화 함수 (주로 Tanh가 사용됨)
>
### 4-2. 시간 역전파 (BPTT) > 이 과정을 통해 RNN은 "나는", "너를" 이라는 단어를 순서대로 읽으며, "좋아해"라는 단어가 나올 차례라는 것을 예측할 수 있게 됩니다.
RNN의 학습은 시간의 흐름에 따라 펼쳐진 네트워크를 따라 오차를 거꾸로 전파하는 **BPTT(Backpropagation Through Time)** 방식을 사용합니다. 이는 일반적인 역전파와 원리는 같지만, 모든 시간 단계에 걸쳐 역전파가 일어난다는 점이 다릅니다. >
> ### 4-2. 시간 역전파 (BPTT)
> RNN의 학습은 시간의 흐름에 따라 펼쳐진 네트워크를 따라 오차를 거꾸로 전파하는 **BPTT(Backpropagation Through Time)** 방식을 사용합니다. 이는 일반적인 역전파와 원리는 같지만, 모든 시간 단계에 걸쳐 역전파가 일어난다는 점이 다릅니다.
--- ---
## 5. 장기 의존성 문제 (The Long-Term Dependency Problem) <br>
RNN의 아이디어는 훌륭하지만, 치명적인 약점이 있습니다. 문장이 길어지면 **아주 먼 과거의 정보가 현재까지 전달되지 못하는 현상**, 즉 **장기 의존성 문제**가 발생합니다. > ## 5. 장기 의존성 문제 (The Long-Term Dependency Problem)
>
> "오늘 아침 [프랑스]에서 유창하게 [프랑스어]를 구사하는 사람들을 만났다." > RNN의 아이디어는 훌륭하지만, 치명적인 약점이 있습니다. 문장이 길어지면 **아주 먼 과거의 정보가 현재까지 전달되지 못하는 현상**, 즉 **장기 의존성 문제**가 발생합니다.
>
위 문장에서 마지막 단어 '프랑스어'를 예측하려면, 문장 맨 앞의 '프랑스'라는 단어를 기억해야 합니다. 하지만 이 두 단어 사이의 거리가 너무 멀면, BPTT 과정에서 그래디언트(기울기)가 전달되다가 점점 희미해지거나( **기울기 소실, Vanishing Gradient** ), 반대로 너무 커져서 발산하는( **기울기 폭발, Exploding Gradient** ) 문제가 발생합니다. > > "오늘 아침 [프랑스]에서 유창하게 [프랑스어]를 구사하는 사람들을 만났다."
>
- **기울기 소실**: 활성화 함수(주로 `tanh`)의 미분값은 최대 1입니다. 역전파 과정에서 1보다 작은 값이 계속 곱해지면, 그래디언트는 0에 수렴하게 됩니다. 결국, 먼 과거의 정보는 가중치 업데이트에 거의 영향을 주지 못합니다. 이것이 RNN이 긴 문장을 잘 기억하지 못하는 주된 이유입니다. > 위 문장에서 마지막 단어 '프랑스어'를 예측하려면, 문장 맨 앞의 '프랑스'라는 단어를 기억해야 합니다. 하지만 이 두 단어 사이의 거리가 너무 멀면, BPTT 과정에서 그래디언트(기울기)가 전달되다가 점점 희미해지거나( **기울기 소실, Vanishing Gradient** ), 반대로 너무 커져서 발산하는( **기울기 폭발, Exploding Gradient** ) 문제가 발생합니다.
>
## 6. LSTM: 장기 기억을 위한 해법 > - **기울기 소실**: 활성화 함수(주로 `tanh`)의 미분값은 최대 1입니다. 역전파 과정에서 1보다 작은 값이 계속 곱해지면, 그래디언트는 0에 수렴하게 됩니다. 결국, 먼 과거의 정보는 가중치 업데이트에 거의 영향을 주지 못합니다. 이것이 RNN이 긴 문장을 잘 기억하지 못하는 주된 이유입니다.
**LSTM(Long Short-Term Memory)** 은 이 장기 의존성 문제를 해결하기 위해 고안된 RNN의 개선된 버전입니다. LSTM은 '단기 기억'과 '장기 기억'을 모두 효과적으로 다룰 수 있습니다. <br>
LSTM의 핵심은 **셀 상태(Cell State)****게이트(Gate)** 라는 정교한 메커니즘입니다. > ## 6. LSTM: 장기 기억을 위한 해법
>
![LSTM Structure](https://i.imgur.com/0uTjG3E.png) > **LSTM(Long Short-Term Memory)** 은 이 장기 의존성 문제를 해결하기 위해 고안된 RNN의 개선된 버전입니다. LSTM은 '단기 기억'과 '장기 기억'을 모두 효과적으로 다룰 수 있습니다.
*(이미지 출처: Christopher Olah's Blog)* >
> LSTM의 핵심은 **셀 상태(Cell State)** 와 **게이트(Gate)** 라는 정교한 메커니즘입니다.
- **셀 상태 (Cell State)**: 컨베이어 벨트처럼 네트워크 전체를 가로지르는 정보의 흐름입니다. LSTM은 이 셀 상태에 정보를 추가하거나 제거하는 능력을 가지고 있습니다. >
- **게이트 (Gates)**: 정보가 셀 상태를 통과하도록 제어하는 장치입니다. 게이트는 시그모이드(Sigmoid) 함수를 통해 0(정보를 차단)과 1(정보를 통과) 사이의 값을 출력하여 정보의 양을 조절합니다. > ![LSTM Structure](https://i.imgur.com/0uTjG3E.png)
> *(이미지 출처: Christopher Olah's Blog)*
LSTM에는 3가지 주요 게이트가 있습니다. >
> - **셀 상태 (Cell State)**: 컨베이어 벨트처럼 네트워크 전체를 가로지르는 정보의 흐름입니다. LSTM은 이 셀 상태에 정보를 추가하거나 제거하는 능력을 가지고 있습니다.
1. **Forget Gate (망각 게이트)**: 과거의 정보 중 **무엇을 잊어버릴지** 결정합니다. "새로운 문장이 시작되었으니, 이전 문장의 주어는 잊어버리자." > - **게이트 (Gates)**: 정보가 셀 상태를 통과하도록 제어하는 장치입니다. 게이트는 시그모이드(Sigmoid) 함수를 통해 0(정보를 차단)과 1(정보를 통과) 사이의 값을 출력하여 정보의 양을 조절합니다.
2. **Input Gate (입력 게이트)**: 새로운 정보 중 **무엇을 저장할지** 결정합니다. "새로운 주어 '그녀'가 등장했으니, 이 정보를 셀 상태에 추가하자." >
3. **Output Gate (출력 게이트)**: 셀 상태의 정보 중 **무엇을 출력으로 내보낼지** 결정합니다. "현재 시점에서는 주어 정보가 필요하니, '그녀'에 대한 정보를 출력하자." > LSTM에는 3가지 주요 게이트가 있습니다.
>
이러한 게이트 구조 덕분에 LSTM은 중요한 정보는 오래 기억하고, 불필요한 정보는 잊어버릴 수 있어 RNN의 장기 의존성 문제를 효과적으로 해결합니다. > 1. **Forget Gate (망각 게이트)**: 과거의 정보 중 **무엇을 잊어버릴지** 결정합니다. "새로운 문장이 시작되었으니, 이전 문장의 주어는 잊어버리자."
> 2. **Input Gate (입력 게이트)**: 새로운 정보 중 **무엇을 저장할지** 결정합니다. "새로운 주어 '그녀'가 등장했으니, 이 정보를 셀 상태에 추가하자."
> 3. **Output Gate (출력 게이트)**: 셀 상태의 정보 중 **무엇을 출력으로 내보낼지** 결정합니다. "현재 시점에서는 주어 정보가 필요하니, '그녀'에 대한 정보를 출력하자."
>
> 이러한 게이트 구조 덕분에 LSTM은 중요한 정보는 오래 기억하고, 불필요한 정보는 잊어버릴 수 있어 RNN의 장기 의존성 문제를 효과적으로 해결합니다.
--- ---
## 7. 연습 문제: "hello" 예측하기 <br>
간단한 RNN 모델을 만들어, "hell" 이라는 입력을 받았을 때 마지막 글자 "o"를 예측하도록 학습시켜 보겠습니다. > ## 7. 연습 문제: "hello" 예측하기
>
```python > 간단한 RNN 모델을 만들어, "hell" 이라는 입력을 받았을 때 마지막 글자 "o"를 예측하도록 학습시켜 보겠습니다.
>
> ```python
import torch import torch
import torch.nn as nn import torch.nn as nn
import numpy as np import numpy as np
...@@ -177,185 +191,100 @@ predicted_char = idx_to_char[predicted_idx.item()] ...@@ -177,185 +191,100 @@ predicted_char = idx_to_char[predicted_idx.item()]
print(f'\nFinal prediction after training: "hell" -> "{predicted_char}"') print(f'\nFinal prediction after training: "hell" -> "{predicted_char}"')
``` ```
>
> [!TIP] > > [!TIP]
> 위 코드를 직접 실행해보면서 `hidden_size`, `learning_rate`, `epoch` 등의 하이퍼파라미터를 바꿔보세요. `nn.RNN`을 `nn.LSTM`으로 바꾸고 실행해보는 것도 좋습니다. (LSTM은 `forward`에서 `hidden`이 `(h_0, c_0)` 튜플 형태여야 합니다) > > 위 코드를 직접 실행해보면서 `hidden_size`, `learning_rate`, `epoch` 등의 하이퍼파라미터를 바꿔보세요. `nn.RNN`을 `nn.LSTM`으로 바꾸고 실행해보는 것도 좋습니다. (LSTM은 `forward`에서 `hidden`이 `(h_0, c_0)` 튜플 형태여야 합니다)
--- ---
## 8. 심화 토론 (What Could Go Wrong?) <br>
RNN과 LSTM은 순차 데이터 처리의 혁신이었지만, 실제 적용 과정에서는 여러 가지 한계와 어려움에 부딪힙니다. 다음 시나리오들에 대해 함께 토론해보세요. > ## 8. 심화 토론 (What Could Go Wrong?)
>
1. **훈련 중 손실(Loss)이 `NaN`으로 폭발하는 현상** > RNN과 LSTM은 순차 데이터 처리의 혁신이었지만, 실제 적용 과정에서는 여러 가지 한계와 어려움에 부딪힙니다. 다음 시나리오들에 대해 함께 토론해보세요.
- **상황**: 시계열 예측을 위한 RNN 모델을 훈련하던 중, 손실(loss) 값이 갑자기 `NaN` (Not a Number)으로 바뀌면서 훈련이 멈춰버렸습니다. >
- **토론**: > 1. **훈련 중 손실(Loss)이 `NaN`으로 폭발하는 현상**
- 이 현상의 가장 유력한 원인은 무엇일까요? 본문에서 배운 '기울기 소실' 문제와 '기울기 폭발' 문제 중 어느 쪽에 해당하며, 그 이유는 무엇일까요? > - **상황**: 시계열 예측을 위한 RNN 모델을 훈련하던 중, 손실(loss) 값이 갑자기 `NaN` (Not a Number)으로 바뀌면서 훈련이 멈춰버렸습니다.
- 이 문제를 해결하기 위한 가장 대표적인 기법인 **그래디언트 클리핑(Gradient Clipping)**이란 무엇이며, 어떤 원리로 동작하는지 설명해보세요. (PyTorch의 `torch.nn.utils.clip_grad_norm_` 함수를 찾아보는 것을 추천합니다.) > - **토론**:
> - 이 현상의 가장 유력한 원인은 무엇일까요? 본문에서 배운 '기울기 소실' 문제와 '기울기 폭발' 문제 중 어느 쪽에 해당하며, 그 이유는 무엇일까요?
2. **순차 처리의 본질적인 병목 현상** > - 이 문제를 해결하기 위한 가장 대표적인 기법인 **그래디언트 클리핑(Gradient Clipping)**이란 무엇이며, 어떤 원리로 동작하는지 설명해보세요. (PyTorch의 `torch.nn.utils.clip_grad_norm_` 함수를 찾아보는 것을 추천합니다.)
- **상황**: 아주 긴 문서(예: 책 한 권)를 LSTM으로 번역하는 모델을 학습시키려 합니다. 강력한 GPU를 사용함에도 불구하고, 이전 챕터에서 배운 CNN 모델에 비해 학습 속도가 매우 느리고, GPU 메모리 문제로 배치 사이즈(batch size)를 키우기도 어렵습니다. >
- **토론**: > 2. **순차 처리의 본질적인 병목 현상**
- RNN/LSTM 계열의 모델들이 CNN에 비해 병렬화가 어려운 근본적인 아키텍처상의 이유는 무엇일까요? `h_t``h_t-1`에 의존해야만 하는 순차적 계산 방식이 왜 성능의 병목이 될까요? > - **상황**: 아주 긴 문서(예: 책 한 권)를 LSTM으로 번역하는 모델을 학습시키려 합니다. 강력한 GPU를 사용함에도 불구하고, 이전 챕터에서 배운 CNN 모델에 비해 학습 속도가 매우 느리고, GPU 메모리 문제로 배치 사이즈(batch size)를 키우기도 어렵습니다.
- 이러한 한계점이 이후에 배울 Transformer와 같은 새로운 아키텍처의 등장을 어떻게 촉진시켰을지 토론해보세요. > - **토론**:
> - RNN/LSTM 계열의 모델들이 CNN에 비해 병렬화가 어려운 근본적인 아키텍처상의 이유는 무엇일까요? `h_t`가 `h_t-1`에 의존해야만 하는 순차적 계산 방식이 왜 성능의 병목이 될까요?
3. **"잊는 것"은 기능이지만, 완벽하지는 않다** > - 이러한 한계점이 이후에 배울 Transformer와 같은 새로운 아키텍처의 등장을 어떻게 촉진시켰을지 토론해보세요.
- **상황**: LSTM 기반의 챗봇을 만들었습니다. 대화 초반에 사용자가 자신의 이름을 알려주면, 챗봇은 대화 내내 사용자의 이름을 잘 기억하고 사용합니다. 하지만 대화가 길어진 후 "내가 처음에 했던 질문이 뭐였지?"라고 물어보면, 챗봇은 그 내용을 기억하지 못합니다. >
- **토론**: > 3. **"잊는 것"은 기능이지만, 완벽하지는 않다**
- LSTM은 장기 의존성 문제를 해결하기 위해 고안되었지만, 여전히 위와 같은 한계를 보입니다. 일반적인 문맥(사용자 이름)은 잘 유지하면서도, 구체적이고 덜 중요한 과거의 정보를 놓치는 이유는 무엇일까요? > - **상황**: LSTM 기반의 챗봇을 만들었습니다. 대화 초반에 사용자가 자신의 이름을 알려주면, 챗봇은 대화 내내 사용자의 이름을 잘 기억하고 사용합니다. 하지만 대화가 길어진 후 "내가 처음에 했던 질문이 뭐였지?"라고 물어보면, 챗봇은 그 내용을 기억하지 못합니다.
- LSTM의 게이트들이 0 또는 1의 이산적인 값이 아닌 0과 1 사이의 연속적인 값을 갖는다는 점이, 어떻게 정보의 '완벽한 보존'이 아닌 점진적인 '희미해짐'에 기여할 수 있을지 토론해보세요. > - **토론**:
> - LSTM은 장기 의존성 문제를 해결하기 위해 고안되었지만, 여전히 위와 같은 한계를 보입니다. 일반적인 문맥(사용자 이름)은 잘 유지하면서도, 구체적이고 덜 중요한 과거의 정보를 놓치는 이유는 무엇일까요?
4. **양방향 RNN: 미래를 보는 것이 항상 정답일까?** > - LSTM의 게이트들이 0 또는 1의 이산적인 값이 아닌 0과 1 사이의 연속적인 값을 갖는다는 점이, 어떻게 정보의 '완벽한 보존'이 아닌 점진적인 '희미해짐'에 기여할 수 있을지 토론해보세요.
- **상황**: 영화 리뷰의 긍정/부정을 판단하는 감성 분석 모델을 만들 때, 단방향(unidirectional) LSTM보다 양방향(Bidirectional) LSTM이 훨씬 좋은 성능을 보였습니다. 한 동료가 "이 모델은 문장의 미래를 보고 예측하는 것이니, 반칙이 아닌가?"라고 질문했습니다. >
- **토론**: > 4. **양방향 RNN: 미래를 보는 것이 항상 정답일까?**
- 양방향 LSTM의 개념을 비전공자에게 어떻게 설명할 수 있을까요? 왜 감성 분석이나 기계 번역 같은 Task에서는 문장의 전체 문맥(과거+미래)을 보는 것이 유리할까요? > - **상황**: 영화 리뷰의 긍정/부정을 판단하는 감성 분석 모델을 만들 때, 단방향(unidirectional) LSTM보다 양방향(Bidirectional) LSTM이 훨씬 좋은 성능을 보였습니다. 한 동료가 "이 모델은 문장의 미래를 보고 예측하는 것이니, 반칙이 아닌가?"라고 질문했습니다.
- 반대로, 실시간 주가 예측이나 일기예보와 같은 Task에 양방향 모델을 사용하는 것이 왜 부적절하거나 불가능한지 토론해보세요. > - **토론**:
> - 양방향 LSTM의 개념을 비전공자에게 어떻게 설명할 수 있을까요? 왜 감성 분석이나 기계 번역 같은 Task에서는 문장의 전체 문맥(과거+미래)을 보는 것이 유리할까요?
## 9. 더 깊이 알아보기 (Further Reading) > - 반대로, 실시간 주가 예측이나 일기예보와 같은 Task에 양방향 모델을 사용하는 것이 왜 부적절하거나 불가능한지 토론해보세요.
- [The Unreasonable Effectiveness of Recurrent Neural Networks](http://karpathy.github.io/2015/05/21/rnn-effectiveness/): Andrej Karpathy의 전설적인 블로그 포스트. RNN의 매력적인 가능성을 보여줍니다.
- [Understanding LSTM Networks](http://colah.github.io/posts/2015-08-Understanding-LSTMs/): Christopher Olah의 블로그 포스트. LSTM의 구조를 그림으로 매우 알기 쉽게 설명한 최고의 자료입니다. <br>
> ## 9. 더 깊이 알아보기 (Further Reading)
> - [The Unreasonable Effectiveness of Recurrent Neural Networks](http://karpathy.github.io/2015/05/21/rnn-effectiveness/): Andrej Karpathy의 전설적인 블로그 포스트. RNN의 매력적인 가능성을 보여줍니다.
> - [Understanding LSTM Networks](http://colah.github.io/posts/2015-08-Understanding-LSTMs/): Christopher Olah의 블로그 포스트. LSTM의 구조를 그림으로 매우 알기 쉽게 설명한 최고의 자료입니다.
--- ---
## 10. 심화 프로젝트: 주가 예측 (LSTM) <br>
RNN과 LSTM의 가장 대표적인 활용 사례 중 하나는 주가, 날씨, 판매량과 같은 시계열(Time-series) 데이터를 예측하는 것입니다. 이번 미니 프로젝트에서는 LSTM 모델을 사용하여, 과거의 주가 데이터 패턴을 학습하고 미래의 주가를 예측하는 간단한 주가 예측기를 만들어 봅니다. > ## 10. 심화 프로젝트: 주가 예측 (LSTM)
>
이 프로젝트의 핵심은 **연속된 시계열 데이터를 딥러닝 모델의 입력 형식(sequence, target)으로 가공**하는 방법을 배우고, 회귀(Regression) 문제에 맞는 손실 함수를 사용하여 모델을 훈련시키는 것입니다. > RNN과 LSTM의 가장 대표적인 활용 사례 중 하나는 주가, 날씨, 판매량과 같은 시계열(Time-series) 데이터를 예측하는 것입니다. 이번 미니 프로젝트에서는 LSTM 모델을 사용하여, 과거의 주가 데이터 패턴을 학습하고 미래의 주가를 예측하는 간단한 주가 예측기를 만들어 봅니다.
>
### 프로젝트 목표 > 이 프로젝트의 핵심은 **연속된 시계열 데이터를 딥러닝 모델의 입력 형식(sequence, target)으로 가공**하는 방법을 배우고, 회귀(Regression) 문제에 맞는 손실 함수를 사용하여 모델을 훈련시키는 것입니다.
>
1. 연속된 시계열 데이터를 정규화(Normalization)하고, 지도 학습을 위한 입력 시퀀스와 타겟 값으로 분리합니다. > ### 프로젝트 목표
2. PyTorch `nn.LSTM` 레이어를 사용하여 시계열 예측 모델을 설계합니다. >
3. 회귀 문제에 적합한 손실 함수(`nn.MSELoss`)를 사용하여 모델을 훈련합니다. > 1. 연속된 시계열 데이터를 정규화(Normalization)하고, 지도 학습을 위한 입력 시퀀스와 타겟 값으로 분리합니다.
4. 예측된 값을 실제 값과 함께 시각화하여 모델의 성능을 직관적으로 평가합니다. > 2. PyTorch `nn.LSTM` 레이어를 사용하여 시계열 예측 모델을 설계합니다.
> 3. 회귀 문제에 적합한 손실 함수(`nn.MSELoss`)를 사용하여 모델을 훈련합니다.
**최종 분석 리포트 (예시):** > 4. 예측된 값을 실제 값과 함께 시각화하여 모델의 성능을 직관적으로 평가합니다.
``` >
Epoch [20/200], Loss: 0.0451 > **최종 분석 리포트 (예시):**
Epoch [40/200], Loss: 0.0218 > ```
... > Epoch [20/200], Loss: 0.0451
Epoch [200/200], Loss: 0.0015 > Epoch [40/200], Loss: 0.0218
``` > ...
(여기에 실제 주가와 예측 주가를 비교하는 Matplotlib 그래프가 추가됩니다) > Epoch [200/200], Loss: 0.0015
> ```
![Stock Prediction Chart](https://i.imgur.com/r8O0e2b.png) > (여기에 실제 주가와 예측 주가를 비교하는 Matplotlib 그래프가 추가됩니다)
>
### 단계별 구현 가이드 > ![Stock Prediction Chart](https://i.imgur.com/r8O0e2b.png)
>
**1. 데이터 준비** > ### 단계별 구현 가이드
- `numpy`를 사용하여 가상의 일일 주가 데이터를 생성합니다. >
- `MinMaxScaler`를 사용하여 데이터 값을 0과 1 사이로 정규화합니다. 이는 LSTM의 안정적인 학습을 위해 매우 중요합니다. > **1. 데이터 준비**
- 정규화된 데이터를 `(입력 시퀀스, 타겟 값)` 쌍으로 만듭니다. 예를 들어, `sequence_length=5` 라면, `[0일차~4일차]` 데이터로 `5일차` 데이터를 예측하는 쌍을 만듭니다. > - `numpy`를 사용하여 가상의 일일 주가 데이터를 생성합니다.
- 데이터를 훈련용과 테스트용으로 분리하고, PyTorch `Tensor`로 변환합니다. > - `MinMaxScaler`를 사용하여 데이터 값을 0과 1 사이로 정규화합니다. 이는 LSTM의 안정적인 학습을 위해 매우 중요합니다.
> - 정규화된 데이터를 `(입력 시퀀스, 타겟 값)` 쌍으로 만듭니다. 예를 들어, `sequence_length=5` 라면, `[0일차~4일차]` 데이터로 `5일차` 데이터를 예측하는 쌍을 만듭니다.
**2. LSTM 모델 정의** > - 데이터를 훈련용과 테스트용으로 분리하고, PyTorch `Tensor`로 변환합니다.
- `nn.Module`을 상속받는 `StockLSTM` 클래스를 만드세요. >
- `__init__`: `nn.LSTM` 레이어와, LSTM의 출력을 받아 최종 예측값(1개)을 만드는 `nn.Linear` 레이어를 정의합니다. > **2. LSTM 모델 정의**
- `forward`: 데이터가 LSTM과 Linear 레이어를 순서대로 통과하는 흐름을 정의합니다. > - `nn.Module`을 상속받는 `StockPredictor` 클래스를 만드세요.
> - `__init__`: `nn.LSTM`과 `nn.Linear` 레이어를 정의합니다.
**3. 학습 및 평가** > - `forward`: LSTM 레이어를 통과한 출력 중, 마지막 시퀀스의 출력만을 선택하여 `nn.Linear` 레이어로 전달합니다.
- 모델, 손실 함수(`nn.MSELoss`), 옵티마이저를 초기화합니다. >
- 학습 루프를 통해 모델을 훈련시킵니다. > **3. 학습 및 평가 루프 구현**
- **(중요)** 평가 시에는 모델이 예측한 값과 실제 정답 값을 `scaler.inverse_transform`을 사용하여 원래의 주가 스케일로 되돌려 비교하고 시각화합니다. > - 모델, 손실 함수(`nn.MSELoss`), 옵티마이저(`torch.optim.Adam`)를 초기화합니다.
> - **학습 루프**:
**전체 코드 구조:** > - `model.train()` 모드로 설정합니다.
```python > - 훈련 데이터로 모델을 학습시키고, 주기적으로 손실을 출력합니다.
import torch > - **평가 루프**:
import torch.nn as nn > - `model.eval()` 모드로 전환하고, `with torch.no_grad():` 블록 안에서 실행합니다.
import numpy as np > - 테스트 데이터에 대한 예측을 수행하고, 예측된 값을 원래 스케일로 되돌립니다.
import matplotlib.pyplot as plt > - `matplotlib.pyplot`을 사용하여 실제 주가와 예측 주가를 그래프로 비교하여 시각화합니다.
from sklearn.preprocessing import MinMaxScaler >
> 이 프로젝트를 통해 여러분은 PyTorch를 사용하여 시계열 데이터를 다루고, 미래를 예측하는 딥러닝 모델을 구축하는 실전 경험을 쌓게 될 것입니다.
# 1. 데이터 준비
# 가상의 일일 주가 데이터 (20일치)
data = np.array([
100, 102, 105, 103, 108, 110, 112, 115, 118, 120,
122, 125, 123, 128, 130, 132, 135, 133, 138, 140
], dtype=np.float32).reshape(-1, 1)
# 데이터 정규화
scaler = MinMaxScaler(feature_range=(0, 1))
data_scaled = scaler.fit_transform(data)
# 입력 시퀀스, 타겟 쌍 생성
def create_sequences(data, seq_length):
xs, ys = [], []
for i in range(len(data) - seq_length):
x = data[i:i+seq_length]
y = data[i+seq_length]
xs.append(x)
ys.append(y)
return np.array(xs), np.array(ys)
SEQ_LENGTH = 5
X, y = create_sequences(data_scaled, SEQ_LENGTH)
# 훈련/테스트 데이터 분리 (뒤의 20%를 테스트용으로 사용)
train_size = int(len(X) * 0.8)
X_train, X_test = X[:train_size], X[train_size:]
y_train, y_test = y[:train_size], y[train_size:]
# PyTorch 텐서로 변환
X_train_tensor = torch.from_numpy(X_train).float()
y_train_tensor = torch.from_numpy(y_train).float()
X_test_tensor = torch.from_numpy(X_test).float()
y_test_tensor = torch.from_numpy(y_test).float()
# 2. LSTM 모델 정의
class StockLSTM(nn.Module):
def __init__(self, input_size=1, hidden_size=50, output_size=1):
super(StockLSTM, self).__init__()
self.hidden_size = hidden_size
self.lstm = nn.LSTM(input_size, hidden_size, batch_first=True)
self.fc = nn.Linear(hidden_size, output_size)
def forward(self, x):
h0 = torch.zeros(1, x.size(0), self.hidden_size).to(x.device)
c0 = torch.zeros(1, x.size(0), self.hidden_size).to(x.device)
out, _ = self.lstm(x, (h0, c0))
out = self.fc(out[:, -1, :]) # 마지막 타임스텝의 출력만 사용
return out
# 3. 학습
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = StockLSTM().to(device)
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
num_epochs = 200
for epoch in range(num_epochs):
model.train()
# 전체 데이터를 한번에 학습 (배치로더는 생략)
outputs = model(X_train_tensor.to(device))
optimizer.zero_grad()
loss = criterion(outputs, y_train_tensor.to(device))
loss.backward()
optimizer.step()
if (epoch+1) % 20 == 0:
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')
# 4. 평가 및 시각화
model.eval()
with torch.no_grad():
test_predict = model(X_test_tensor.to(device))
# 원래 스케일로 되돌리기
test_predict_inv = scaler.inverse_transform(test_predict.cpu().numpy())
y_test_inv = scaler.inverse_transform(y_test)
# 시각화
plt.figure(figsize=(10, 6))
plt.plot(y_test_inv, label='Actual Price')
plt.plot(test_predict_inv, label='Predicted Price')
plt.title('Stock Price Prediction')
plt.xlabel('Time (days)')
plt.ylabel('Price')
plt.legend()
plt.grid(True)
plt.show()
```
이 프로젝트는 시계열 데이터 전처리의 핵심적인 과정을 이해하고, 회귀 문제에 딥러닝을 적용하는 실질적인 경험을 제공할 것입니다.
--- ---
......
...@@ -5,142 +5,162 @@ ...@@ -5,142 +5,162 @@
--- ---
## 1. 학습 목표 (Learning Objectives) <br>
이번 파트가 끝나면, 여러분은 다음을 할 수 있게 됩니다. > ## 1. 학습 목표 (Learning Objectives)
- 순차 데이터 처리에서 RNN이 가졌던 한계를 설명하고, 이를 해결하기 위해 'Attention'이 왜 등장했는지 이해할 수 있습니다.
- Transformer의 핵심 구성 요소인 인코더(Encoder), 디코더(Decoder), 그리고 셀프 어텐션(Self-Attention)의 역할을 설명할 수 있습니다.
- Transformer가 단어의 순서를 학습하는 방법, 즉 Positional Encoding의 필요성을 이해할 수 있습니다.
- Transformer 아키텍처를 기반으로 한 BERT와 GPT가 각각 어떤 구조적 특징을 가지며, 어떤 종류의 작업에 더 특화되어 있는지 설명할 수 있습니다.
## 2. 핵심 요약 (Key takeaways)
RNN의 순차 처리 방식과 장기 의존성 문제를 해결하기 위해 등장한 Transformer는, 문장 전체를 한 번에 보고 단어 간의 관계와 중요도를 파악하는 Self-Attention 메커니즘을 사용합니다. Transformer는 문장을 이해하는 인코더와 문장을 생성하는 디코더로 구성되며, 단어의 순서 정보는 Positional Encoding으로 학습합니다. 이 구조를 기반으로 문맥 이해에 특화된 BERT(인코더 활용)와 텍스트 생성에 특화된 GPT(디코더 활용) 같은 현대적인 LLM이 탄생했습니다.
## 3. 도입: 문장의 '진짜 의미'를 파악하는 똑똑한 번역가 (Introduction)
> **💡 비유: Transformer는 '능숙한 동시통역사'**
> - **초보 번역가 (RNN)**: 문장을 앞에서부터 한 단어씩 순서대로 듣고 바로 번역합니다. "나는 강가에 가서..." 까지 듣고 'I go to the river bank and...' 라고 번역을 시작합니다. 하지만 뒤에 '낚시를 했다'가 나올지 '수영을 했다'가 나올지에 따라 문맥이 달라질 수 있습니다. 긴 문장을 들으면 앞부분을 잊어버리는 단점도 있습니다.
> - **능숙한 통역사 (Transformer)**: 문장 전체("그는 강가에서 낚시를 했다")를 일단 다 듣습니다. 그리고 '낚시를 했다'라는 핵심 행동을 파악한 뒤, 이 행동과 가장 관련이 깊은 '강가', '그'라는 단어에 **더 집중(Attention)**하여 "He went fishing by the river" 라는 자연스러운 번역을 완성합니다. 문장 전체의 핵심과 단어 간의 관계를 파악하는 데 능숙합니다.
이처럼 Transformer는 문장 전체를 보고 단어 간의 관계와 중요도를 파악하는 **Attention** 메커니즘을 사용하여 자연어의 복잡한 문맥을 이해하는 혁신적인 방법을 제시했습니다.
---
## 4. Transformer 핵심 원리 파헤치기
### 4-1. Attention 메커니즘의 등장: RNN의 한계를 넘어서
기존의 순차 데이터 처리 모델인 RNN(Recurrent Neural Network)은 문장이 길어질수록 앞쪽 정보가 뒤로 전달되며 소실되는 **장기 의존성 문제(Long-Term Dependency Problem)**가 있었습니다. 또한, 순차적으로 계산해야 해서 GPU 병렬 처리가 어려워 학습 속도가 느렸습니다.
이를 해결하기 위해 **Attention**이 제안되었습니다. 출력 단어를 예측할 때마다, 입력 문장 전체를 다시 참고하여 **가장 관련 높은 단어에 '주목'**하는 방식입니다.
### 4-2. Transformer: "Attention Is All You Need"
2017년 구글 논문 "Attention Is All You Need"에서 소개된 Transformer는 RNN 구조를 완전히 버리고 오직 Attention 메커니즘만으로 언어를 처리하는 모델입니다.
**주요 구성 요소**
- **인코더 (Encoder)**: 입력 문장을 받아 각 단어의 의미와 문맥 정보를 풍부하게 담은 **표현(Representation)**으로 변환합니다. 문장을 '이해'하는 데 특화된 부분입니다.
- **디코더 (Decoder)**: 인코더가 만든 표현과 이전에 생성된 단어들을 바탕으로 다음 단어를 예측하여 새로운 문장을 '생성'하는 데 특화된 부분입니다.
### 4-3. 핵심 메커니즘: Self-Attention
Transformer의 심장은 **Self-Attention**입니다. 문장 안에서 단어들이 **서로에게 얼마나 중요한지**를 계산하여, 문맥에 맞는 단어의 의미를 파악하는 과정입니다.
> **예시**: "The animal didn't cross the street because **it** was too tired."
> >
> 여기서 'it'이 가리키는 대상은 'animal'일까요, 'street'일까요? 사람은 쉽게 'animal'이라고 파악합니다. Self-Attention은 'it'과 문장 내 다른 모든 단어와의 관련도 점수를 계산하여, 'it'이 'animal'을 가리킨다는 것을 높은 확률로 학습하게 됩니다. > 이번 파트가 끝나면, 여러분은 다음을 할 수 있게 됩니다.
>
> - 순차 데이터 처리에서 RNN이 가졌던 한계를 설명하고, 이를 해결하기 위해 'Attention'이 왜 등장했는지 이해할 수 있습니다.
> - Transformer의 핵심 구성 요소인 인코더(Encoder), 디코더(Decoder), 그리고 셀프 어텐션(Self-Attention)의 역할을 설명할 수 있습니다.
> - Transformer가 단어의 순서를 학습하는 방법, 즉 Positional Encoding의 필요성을 이해할 수 있습니다.
> - Transformer 아키텍처를 기반으로 한 BERT와 GPT가 각각 어떤 구조적 특징을 가지며, 어떤 종류의 작업에 더 특화되어 있는지 설명할 수 있습니다.
이 과정은 각 단어에 대해 `Query(Q)`, `Key(K)`, `Value(V)`라는 세 가지 벡터를 만들어 계산합니다. <br>
- `Query`: 현재 단어의 정보 (분석의 주체)
- `Key`: 다른 단어들과의 관련성을 계산하기 위한 '꼬리표'
- `Value`: 다른 단어들의 실제 의미
현재 단어의 `Query`가 다른 모든 단어의 `Key`들과 얼마나 '어울리는지(유사도)'를 계산하고, 이 점수를 각 단어의 `Value`에 곱해 최종적으로 문맥이 반영된 새로운 표현을 만들어냅니다. > ## 2. 핵심 요약 (Key Summary)
>
> RNN의 순차 처리 방식과 장기 의존성 문제를 해결하기 위해 등장한 Transformer는, 문장 전체를 한 번에 보고 단어 간의 관계와 중요도를 파악하는 Self-Attention 메커니즘을 사용합니다. Transformer는 문장을 이해하는 인코더와 문장을 생성하는 디코더로 구성되며, 단어의 순서 정보는 Positional Encoding으로 학습합니다. 이 구조를 기반으로 문맥 이해에 특화된 BERT(인코더 활용)와 텍스트 생성에 특화된 GPT(디코더 활용) 같은 현대적인 LLM이 탄생했습니다.
### 4-4. 순서 정보 학습: Positional Encoding <br>
Transformer는 RNN과 달리 단어를 한 번에 처리하므로, "나는 너를 좋아해"와 "너는 나를 좋아해"를 구분하지 못합니다. 단어의 순서 정보를 알려주기 위해, 각 단어의 위치마다 고유한 값을 더해주는 **Positional Encoding**을 사용합니다. 사인(sine), 코사인(cosine) 함수를 이용해 각 위치에 대한 벡터를 만들어 입력 임베딩에 추가해 줍니다. > ## 3. 도입: 문장의 '진짜 의미'를 파악하는 똑똑한 번역가 (Introduction)
>
> > [!NOTE] 비유: Transformer는 '능숙한 동시통역사'
> > - **초보 번역가 (RNN)**: 문장을 앞에서부터 한 단어씩 순서대로 듣고 바로 번역합니다. "나는 강가에 가서..." 까지 듣고 'I go to the river bank and...' 라고 번역을 시작합니다. 하지만 뒤에 '낚시를 했다'가 나올지 '수영을 했다'가 나올지에 따라 문맥이 달라질 수 있습니다. 긴 문장을 들으면 앞부분을 잊어버리는 단점도 있습니다.
> > - **능숙한 통역사 (Transformer)**: 문장 전체("그는 강가에서 낚시를 했다")를 일단 다 듣습니다. 그리고 '낚시를 했다'라는 핵심 행동을 파악한 뒤, 이 행동과 가장 관련이 깊은 '강가', '그'라는 단어에 **더 집중(Attention)**하여 "He went fishing by the river" 라는 자연스러운 번역을 완성합니다. 문장 전체의 핵심과 단어 간의 관계를 파악하는 데 능숙합니다.
>
> 이처럼 Transformer는 문장 전체를 보고 단어 간의 관계와 중요도를 파악하는 **Attention** 메커니즘을 사용하여 자연어의 복잡한 문맥을 이해하는 혁신적인 방법을 제시했습니다.
--- ---
## 5. Transformer의 두 갈래: BERT와 GPT <br>
Transformer 아키텍처는 현대 LLM의 근간이 되었습니다. 대표적인 두 모델인 BERT와 GPT는 Transformer의 구조를 각기 다른 방식으로 활용합니다. > ## 4. Transformer 핵심 원리 파헤치기
>
| 구분 | BERT (Bidirectional Encoder Representations from Transformers) | GPT (Generative Pre-trained Transformer) | > ### 4-1. Attention 메커니즘의 등장: RNN의 한계를 넘어서
|---|---|---| >
| **개발사** | Google | OpenAI | > 기존의 순차 데이터 처리 모델인 RNN(Recurrent Neural Network)은 문장이 길어질수록 앞쪽 정보가 뒤로 전달되며 소실되는 **장기 의존성 문제(Long-Term Dependency Problem)**가 있었습니다. 또한, 순차적으로 계산해야 해서 GPU 병렬 처리가 어려워 학습 속도가 느렸습니다.
| **주요 구조** | Transformer의 **인코더(Encoder)만** 사용 | Transformer의 **디코더(Decoder)만** 사용 | >
| **특징** | **"문맥을 이해하는 전문가"**<br>문장 전체를 보고 빈칸(Mask)을 채우는 방식으로 학습 (양방향). 문맥 이해, 의미 분석, 분류 등 **이해(Understanding)** 기반 작업에 강력함. | **"이야기를 만들어내는 작가"**<br>이전 단어들을 보고 다음 단어를 예측하며 순차적으로 학습 (단방향). 문장 생성, 요약, 번역 등 **생성(Generation)** 기반 작업에 강력함. | > 이를 해결하기 위해 **Attention**이 제안되었습니다. 출력 단어를 예측할 때마다, 입력 문장 전체를 다시 참고하여 **가장 관련 높은 단어에 '주목'**하는 방식입니다.
| **주요 활용** | 구글 검색 엔진, 텍스트 분류, 감성 분석, 개체명 인식 | 챗봇(ChatGPT), 콘텐츠 초안 생성, 코드 자동 완성 | >
> ### 4-2. Transformer: "Attention Is All You Need"
>
> 2017년 구글 논문 "Attention Is All You Need"에서 소개된 Transformer는 RNN 구조를 완전히 버리고 오직 Attention 메커니즘만으로 언어를 처리하는 모델입니다.
>
> **주요 구성 요소**
>
> - **인코더 (Encoder)**: 입력 문장을 받아 각 단어의 의미와 문맥 정보를 풍부하게 담은 **표현(Representation)**으로 변환합니다. 문장을 '이해'하는 데 특화된 부분입니다.
> - **디코더 (Decoder)**: 인코더가 만든 표현과 이전에 생성된 단어들을 바탕으로 다음 단어를 예측하여 새로운 문장을 '생성'하는 데 특화된 부분입니다.
>
> ### 4-3. 핵심 메커니즘: Self-Attention
>
> Transformer의 심장은 **Self-Attention**입니다. 문장 안에서 단어들이 **서로에게 얼마나 중요한지**를 계산하여, 문맥에 맞는 단어의 의미를 파악하는 과정입니다.
>
> > **예시**: "The animal didn't cross the street because **it** was too tired."
> >
> > 여기서 'it'이 가리키는 대상은 'animal'일까요, 'street'일까요? 사람은 쉽게 'animal'이라고 파악합니다. Self-Attention은 'it'과 문장 내 다른 모든 단어와의 관련도 점수를 계산하여, 'it'이 'animal'을 가리킨다는 것을 높은 확률로 학습하게 됩니다.
>
> 이 과정은 각 단어에 대해 `Query(Q)`, `Key(K)`, `Value(V)`라는 세 가지 벡터를 만들어 계산합니다.
> - `Query`: 현재 단어의 정보 (분석의 주체)
> - `Key`: 다른 단어들과의 관련성을 계산하기 위한 '꼬리표'
> - `Value`: 다른 단어들의 실제 의미
>
> 현재 단어의 `Query`가 다른 모든 단어의 `Key`들과 얼마나 '어울리는지(유사도)'를 계산하고, 이 점수를 각 단어의 `Value`에 곱해 최종적으로 문맥이 반영된 새로운 표현을 만들어냅니다.
>
> ### 4-4. 순서 정보 학습: Positional Encoding
>
> Transformer는 RNN과 달리 단어를 한 번에 처리하므로, "나는 너를 좋아해"와 "너는 나를 좋아해"를 구분하지 못합니다. 단어의 순서 정보를 알려주기 위해, 각 단어의 위치마다 고유한 값을 더해주는 **Positional Encoding**을 사용합니다. 사인(sine), 코사인(cosine) 함수를 이용해 각 위치에 대한 벡터를 만들어 입력 임베딩에 추가해 줍니다.
--- ---
## 6. 연습 문제 <br>
1. **개념 확인**: Transformer 이전의 순차 데이터 모델(RNN)이 가졌던 가장 큰 한계점은 무엇이었나요? > ## 5. Transformer의 두 갈래: BERT와 GPT
2. **개념 확인**: 'Self-Attention' 메커니즘의 역할을 한 문장으로 설명해 보세요. >
3. **개념 확인**: GPT가 주로 사용하는 Transformer의 구성요소는 인코더(Encoder)인가요, 디코더(Decoder)인가요? > Transformer 아키텍처는 현대 LLM의 근간이 되었습니다. 대표적인 두 모델인 BERT와 GPT는 Transformer의 구조를 각기 다른 방식으로 활용합니다.
4. **심화 조사**: BERT와 GPT가 각각 어떤 종류의 AI 서비스(e.g., 검색 엔진, 챗봇, 번역기)에 더 적합한지, 그 이유와 함께 실제 서비스 예시를 2가지 이상 찾아 설명해 주세요. >
5. **설명 능력**: 'Self-Attention'의 원리를 비전공자 친구에게 설명한다고 상상하고, 쉬운 비유를 들어 3문장 이내로 설명하는 글을 작성해 주세요. (예: "칵테일 파티에서 여러 사람과 대화할 때, 나와 가장 관련 있는 주제를 이야기하는 사람의 목소리에 더 집중하는 것과 같아요.") > | 구분 | BERT (Bidirectional Encoder Representations from Transformers) | GPT (Generative Pre-trained Transformer) |
> |---|---|---|
> | **개발사** | Google | OpenAI |
> | **주요 구조** | Transformer의 **인코더(Encoder)만** 사용 | Transformer의 **디코더(Decoder)만** 사용 |
> | **특징** | **"문맥을 이해하는 전문가"**<br>문장 전체를 보고 빈칸(Mask)을 채우는 방식으로 학습 (양방향). 문맥 이해, 의미 분석, 분류 등 **이해(Understanding)** 기반 작업에 강력함. | **"이야기를 만들어내는 작가"**<br>이전 단어들을 보고 다음 단어를 예측하며 순차적으로 학습 (단방향). 문장 생성, 요약, 번역 등 **생성(Generation)** 기반 작업에 강력함. |
> | **주요 활용** | 구글 검색 엔진, 텍스트 분류, 감성 분석, 개체명 인식 | 챗봇(ChatGPT), 콘텐츠 초안 생성, 코드 자동 완성 |
--- ---
## 7. 심화 토론 (What Could Go Wrong?) <br>
Transformer는 현대 AI의 혁신을 이끌었지만, 그 강력함만큼 새로운 종류의 문제와 한계를 드러냈습니다. 다음 시나리오들에 대해 함께 토론해보세요. > ## 6. 연습 문제
>
1. **Self-Attention의 연산량 병목(Quadratic Bottleneck)** > 1. **개념 확인**: Transformer 이전의 순차 데이터 모델(RNN)이 가졌던 가장 큰 한계점은 무엇이었나요?
- **상황**: 한 연구팀이 고해상도 이미지를 처리하기 위해, 각 픽셀을 하나의 토큰으로 간주하여 표준 Transformer 모델에 입력했습니다. 최고 사양의 GPU를 사용했음에도 불구하고, 시퀀스 길이가 조금만 길어져도 메모리 부족(Out of Memory) 오류가 발생하며 모델을 훈련시킬 수 없었습니다. > 2. **개념 확인**: 'Self-Attention' 메커니즘의 역할을 한 문장으로 설명해 보세요.
- **토론**: > 3. **개념 확인**: GPT가 주로 사용하는 Transformer의 구성요소는 인코더(Encoder)인가요, 디코더(Decoder)인가요?
- Self-Attention은 RNN의 순차 처리 병목을 해결했지만, 대신 어떤 새로운 병목을 만들었을까요? 왜 Self-Attention의 연산량과 메모리 사용량은 시퀀스 길이(n)에 따라 제곱(O(n²))으로 증가할까요? > 4. **심화 조사**: BERT와 GPT가 각각 어떤 종류의 AI 서비스(e.g., 검색 엔진, 챗봇, 번역기)에 더 적합한지, 그 이유와 함께 실제 서비스 예시를 2가지 이상 찾아 설명해 주세요.
- 이러한 한계점 때문에 표준 Transformer를 매우 긴 시퀀스(긴 문서, 고화질 이미지, 음성 등)에 적용하기 어려운 이유는 무엇이며, 이를 해결하기 위해 어떤 아이디어(예: Sparse Attention, Longformer, Linformer 등)들이 제시되었는지 조사하고 토론해보세요. > 5. **설명 능력**: 'Self-Attention'의 원리를 비전공자 친구에게 설명한다고 상상하고, 쉬운 비유를 들어 3문장 이내로 설명하는 글을 작성해 주세요. (예: "칵테일 파티에서 여러 사람과 대화할 때, 나와 가장 관련 있는 주제를 이야기하는 사람의 목소리에 더 집중하는 것과 같아요.")
2. **위치 정보의 한계와 일반화 문제**
- **상황**: 최대 512 토큰 길이의 문장으로 학습된 Transformer 모델이 있습니다. 추론 시점에 600 토큰 길이의 문장을 입력하자, 모델의 성능이 급격히 저하되고 문법에 맞지 않는 문장을 생성하기 시작했습니다.
- **토론**:
- 왜 기본적인 Positional Encoding 방식은 학습 시 사용된 최대 길이를 넘어선 위치에 대해 잘 일반화하지 못할까요? 모델이 한 번도 본 적 없는 위치 값(예: 513번째 위치)을 마주했을 때 어떤 일이 벌어질까요?
- 이러한 문제를 해결하기 위한 대안적인 위치 인코딩 방식들에는 어떤 것들이 있을까요? (예: Relative Positional Encoding, RoPE 등)
3. **LLM의 환각(Hallucination) 현상**
- **상황**: GPT 기반의 역사 Q&A 봇에게 잘 알려지지 않은 역사적 인물에 대해 질문하자, 매우 유창하고 그럴듯하지만 완전히 허구인 사실을 자신감 있게 생성해냈습니다.
- **토론**:
- 이러한 '환각' 현상은 왜 발생할까요? 모델이 '거짓말'을 하는 것일까요, 아니면 다른 원인이 있을까요? 이 현상이 모델의 근본적인 학습 목표("정답을 말하기"가 아닌 "다음에 올 가장 그럴듯한 단어 예측하기")와 어떻게 연결되는지 토론해보세요.
- 이러한 환각 현상을 완화하기 위한 기술적인 전략들에는 어떤 것들이 있을까요? (예: Retrieval-Augmented Generation (RAG), Grounding, Fact-Checking 등)
4. **"이해" 모델 vs. "생성" 모델: 올바른 도구 선택하기**
- **상황**: 한 개발자가 문장의 긍정/부정을 판단하는 감성 분류(Classification) Task에 GPT(Decoder-only) 모델을 사용했습니다. 모델이 작동은 하지만, 비슷한 크기의 BERT(Encoder-only) 모델에 비해 추론 속도가 훨씬 느리고 정확도도 낮았습니다.
- **토론**:
- 왜 GPT와 같은 생성 모델이 BERT와 같은 이해 모델에 비해 분류 Task에서 비효율적일까요? Decoder 아키텍처의 단방향(Causal) 어텐션 마스크가 어떻게 전체 문맥을 파악하는 능력에 한계를 주는지, BERT의 양방향(Bidirectional) 어텐션과 비교하여 설명해보세요.
- 풀고자 하는 문제(Downstream Task)의 성격에 맞게 모델의 아키텍처와 사전학습 방식을 선택하는 것이 왜 중요한지 토론해보세요.
## 8. 더 깊이 알아보기 (Further Reading)
- [Attention Is All You Need (원문 논문)](https://arxiv.org/abs/1706.03762): 모든 것의 시작이 된 논문.
- [The Illustrated Transformer (영문 블로그)](http://jalammar.github.io/illustrated-transformer/): 그림과 함께 Transformer를 쉽게 설명한 최고의 자료 중 하나.
- [Hugging Face Course - How do Transformers work?](https://huggingface.co/learn/llm-course/en/chapter1/4): 본문에 많이 참고된 허깅페이스의 LLM 강좌.
--- ---
## 9. 심화 프로젝트: Self-Attention 계산해보기 <br>
> ## 7. 심화 토론 (What Could Go Wrong?)
>
> Transformer는 현대 AI의 혁신을 이끌었지만, 그 강력함만큼 새로운 종류의 문제와 한계를 드러냈습니다. 다음 시나리오들에 대해 함께 토론해보세요.
>
> 1. **Self-Attention의 연산량 병목(Quadratic Bottleneck)**
> - **상황**: 한 연구팀이 고해상도 이미지를 처리하기 위해, 각 픽셀을 하나의 토큰으로 간주하여 표준 Transformer 모델에 입력했습니다. 최고 사양의 GPU를 사용했음에도 불구하고, 시퀀스 길이가 조금만 길어져도 메모리 부족(Out of Memory) 오류가 발생하며 모델을 훈련시킬 수 없었습니다.
> - **토론**:
> - Self-Attention은 RNN의 순차 처리 병목을 해결했지만, 대신 어떤 새로운 병목을 만들었을까요? 왜 Self-Attention의 연산량과 메모리 사용량은 시퀀스 길이(n)에 따라 제곱(O(n²))으로 증가할까요?
> - 이러한 한계점 때문에 표준 Transformer를 매우 긴 시퀀스(긴 문서, 고화질 이미지, 음성 등)에 적용하기 어려운 이유는 무엇이며, 이를 해결하기 위해 어떤 아이디어(예: Sparse Attention, Longformer, Linformer 등)들이 제시되었는지 조사하고 토론해보세요.
>
> 2. **위치 정보의 한계와 일반화 문제**
> - **상황**: 최대 512 토큰 길이의 문장으로 학습된 Transformer 모델이 있습니다. 추론 시점에 600 토큰 길이의 문장을 입력하자, 모델의 성능이 급격히 저하되고 문법에 맞지 않는 문장을 생성하기 시작했습니다.
> - **토론**:
> - 왜 기본적인 Positional Encoding 방식은 학습 시 사용된 최대 길이를 넘어선 위치에 대해 잘 일반화하지 못할까요? 모델이 한 번도 본 적 없는 위치 값(예: 513번째 위치)을 마주했을 때 어떤 일이 벌어질까요?
> - 이러한 문제를 해결하기 위한 대안적인 위치 인코딩 방식들에는 어떤 것들이 있을까요? (예: Relative Positional Encoding, RoPE 등)
>
> 3. **LLM의 환각(Hallucination) 현상**
> - **상황**: GPT 기반의 역사 Q&A 봇에게 잘 알려지지 않은 역사적 인물에 대해 질문하자, 매우 유창하고 그럴듯하지만 완전히 허구인 사실을 자신감 있게 생성해냈습니다.
> - **토론**:
> - 이러한 '환각' 현상은 왜 발생할까요? 모델이 '거짓말'을 하는 것일까요, 아니면 다른 원인이 있을까요? 이 현상이 모델의 근본적인 학습 목표("정답을 말하기"가 아닌 "다음에 올 가장 그럴듯한 단어 예측하기")와 어떻게 연결되는지 토론해보세요.
> - 이러한 환각 현상을 완화하기 위한 기술적인 전략들에는 어떤 것들이 있을까요? (예: Retrieval-Augmented Generation (RAG), Grounding, Fact-Checking 등)
>
> 4. **"이해" 모델 vs. "생성" 모델: 올바른 도구 선택하기**
> - **상황**: 한 개발자가 문장의 긍정/부정을 판단하는 감성 분류(Classification) Task에 GPT(Decoder-only) 모델을 사용했습니다. 모델이 작동은 하지만, 비슷한 크기의 BERT(Encoder-only) 모델에 비해 추론 속도가 훨씬 느리고 정확도도 낮았습니다.
> - **토론**:
> - 왜 GPT와 같은 생성 모델이 BERT와 같은 이해 모델에 비해 분류 Task에서 비효율적일까요? Decoder 아키텍처의 단방향(Causal) 어텐션 마스크가 어떻게 전체 문맥을 파악하는 능력에 한계를 주는지, BERT의 양방향(Bidirectional) 어텐션과 비교하여 설명해보세요.
> - 풀고자 하는 문제(Downstream Task)의 성격에 맞게 모델의 아키텍처와 사전학습 방식을 선택하는 것이 왜 중요한지 토론해보세요.
<br>
> ## 8. 더 깊이 알아보기 (Further Reading)
> - [Attention Is All You Need (원문 논문)](https://arxiv.org/abs/1706.03762): 모든 것의 시작이 된 논문.
> - [The Illustrated Transformer (영문 블로그)](http://jalammar.github.io/illustrated-transformer/): 그림과 함께 Transformer를 쉽게 설명한 최고의 자료 중 하나.
> - [Hugging Face Course - How do Transformers work?](https://huggingface.co/learn/llm-course/en/chapter1/4): 본문에 많이 참고된 허깅페이스의 LLM 강좌.
이론으로 배운 Self-Attention 메커니즘이 실제 코드 레벨에서 어떻게 동작하는지 직접 구현해보며 Transformer의 심장을 파헤쳐봅니다. 이 과정을 통해 캡스톤 프로젝트에서 Transformer 기반 모델을 다룰 때 내부 동작에 대한 깊은 직관을 얻을 수 있습니다. ---
- **목표**: PyTorch를 사용하여 Self-Attention의 핵심 계산 과정을 단계별로 직접 구현합니다. <br>
- **핵심 단계**:
1. **입력 준비**: 간단한 문장을 토큰화하고, 각 토큰을 표현하는 임베딩 벡터(여기서는 랜덤 텐서)를 생성합니다. > ## 9. 심화 프로젝트: Self-Attention 계산해보기
2. **Q, K, V 생성**: 각 임베딩 벡터로부터 Query, Key, Value 벡터를 만들어내는 가중치 행렬(`nn.Linear`)을 정의하고, 행렬 곱을 통해 Q, K, V 행렬을 계산합니다. >
3. **Attention Score 계산**: `(Q @ K.transpose) / sqrt(d_k)` 공식을 그대로 코드로 옮겨 어텐션 스코어를 계산합니다. > 이론으로 배운 Self-Attention 메커니즘이 실제 코드 레벨에서 어떻게 동작하는지 직접 구현해보며 Transformer의 심장을 파헤쳐봅니다. 이 과정을 통해 캡스톤 프로젝트에서 Transformer 기반 모델을 다룰 때 내부 동작에 대한 깊은 직관을 얻을 수 있습니다.
4. **Attention Distribution**: 스코어에 `Softmax` 함수를 적용하여 특정 단어가 다른 모든 단어에 얼마나 '집중'할지를 나타내는 확률 분포를 구합니다. >
5. **최종 결과**: 계산된 어텐션 가중치를 Value 행렬에 곱하여 문맥이 풍부하게 반영된 최종 결과 벡터를 얻습니다. > - **목표**: PyTorch를 사용하여 Self-Attention의 핵심 계산 과정을 단계별로 직접 구현합니다.
- **기대 효과**: > - **핵심 단계**:
- `Q`, `K`, `V`의 역할과 텐서의 차원 변화를 명확하게 이해합니다. > 1. **입력 준비**: 간단한 문장을 토큰화하고, 각 토큰을 표현하는 임베딩 벡터(여기서는 랜덤 텐서)를 생성합니다.
- Self-Attention의 복잡한 수식이 실제로는 몇 줄의 행렬 연산 코드로 구현됨을 확인하며 자신감을 얻습니다. > 2. **Q, K, V 생성**: 각 임베딩 벡터로부터 Query, Key, Value 벡터를 만들어내는 가중치 행렬(`nn.Linear`)을 정의하고, 행렬 곱을 통해 Q, K, V 행렬을 계산합니다.
- Hugging Face 라이브러리의 Transformer 모델 내부를 상상할 수 있는 능력을 기릅니다. > 3. **Attention Score 계산**: `(Q @ K.transpose) / sqrt(d_k)` 공식을 그대로 코드로 옮겨 어텐션 스코어를 계산합니다.
- **구현 가이드**: [live_coding_transformer_block.md](./live_coding_transformer_block.md) 파일의 단계별 가이드를 참고하여 직접 코드를 작성해보세요. > 4. **Attention Distribution**: 스코어에 `Softmax` 함수를 적용하여 특정 단어가 다른 모든 단어에 얼마나 '집중'할지를 나타내는 확률 분포를 구합니다.
> 5. **최종 결과**: 계산된 어텐션 가중치를 Value 행렬에 곱하여 문맥이 풍부하게 반영된 최종 결과 벡터를 얻습니다.
> - **기대 효과**:
> - `Q`, `K`, `V`의 역할과 텐서의 차원 변화를 명확하게 이해합니다.
> - Self-Attention의 복잡한 수식이 실제로는 몇 줄의 행렬 연산 코드로 구현됨을 확인하며 자신감을 얻습니다.
> - Hugging Face 라이브러리의 Transformer 모델 내부를 상상할 수 있는 능력을 기릅니다.
> - **구현 가이드**: [live_coding_transformer_block.md](./live_coding_transformer_block.md) 파일의 단계별 가이드를 참고하여 직접 코드를 작성해보세요.
--- ---
<br>
**➡️ 다음 시간: [Part 7.3: LangChain으로 LLM 애플리케이션 개발 맛보기](./part_7.3_llm_application_development_with_langchain.md)** **➡️ 다음 시간: [Part 7.3: LangChain으로 LLM 애플리케이션 개발 맛보기](./part_7.3_llm_application_development_with_langchain.md)**
\ No newline at end of file
...@@ -5,193 +5,161 @@ ...@@ -5,193 +5,161 @@
--- ---
## 1. 학습 목표 (Learning Objectives) <br>
이번 파트가 끝나면, 여러분은 다음을 할 수 있게 됩니다. > ## 1. 학습 목표 (Learning Objectives)
>
- LLM의 한계점(최신성 부족, 환각 등)을 설명하고, RAG가 이를 어떻게 해결하는지 이해할 수 있습니다. > 이번 파트가 끝나면, 여러분은 다음을 할 수 있게 됩니다.
- LangChain의 역할을 이해하고, RAG 파이프라인의 핵심 5단계(Load, Split, Embed, Store, Retrieve)를 설명할 수 있습니다. >
- 문서 분할(Chunking)의 중요성을 이해하고, 기본적인 분할 전략을 적용할 수 있습니다. > - LLM의 한계점(최신성 부족, 환각 등)을 설명하고, RAG가 이를 어떻게 해결하는지 이해할 수 있습니다.
- LangChain을 사용하여 외부 문서의 내용을 기반으로 질문에 답변하는 RAG 시스템을 직접 코드로 구현할 수 있습니다. > - LangChain의 역할을 이해하고, RAG 파이프라인의 핵심 5단계(Load, Split, Embed, Store, Retrieve)를 설명할 수 있습니다.
> - 문서 분할(Chunking)의 중요성을 이해하고, 기본적인 분할 전략을 적용할 수 있습니다.
## 2. 핵심 키워드 (Keywords) > - LangChain을 사용하여 외부 문서의 내용을 기반으로 질문에 답변하는 RAG 시스템을 직접 코드로 구현할 수 있습니다.
`거대 언어 모델(LLM)`, `LangChain`, `검색 증강 생성(RAG)`, `환각(Hallucination)`, `임베딩(Embedding)`, `벡터 저장소(Vector Store)`, `FAISS`, `Chroma`, `문서 분할(Chunking)` <br>
## 3. 도입: 똑똑한 LLM을 더 똑똑하게 만들기 (Introduction) > ## 2. 핵심 키워드 (Keywords)
>
우리는 앞에서 LLM이라는 강력한 '두뇌'를 배웠습니다. 하지만 이 두뇌는 몇 가지 결정적인 한계를 가집니다. 훈련 데이터에 없는 최신 정보나, 우리 회사 내부 문서 같은 사적인 내용은 전혀 알지 못합니다. 가끔은 그럴듯한 거짓말, 즉 '환각' 현상을 보이기도 하죠. > `거대 언어 모델(LLM)`, `LangChain`, `검색 증강 생성(RAG)`, `환각(Hallucination)`, `임베딩(Embedding)`, `벡터 저장소(Vector Store)`, `FAISS`, `Chroma`, `문서 분할(Chunking)`
이번 시간에는 이 한계를 극복하는 가장 효과적인 기술인 **검색 증강 생성(RAG, Retrieval-Augmented Generation)**을 배웁니다. RAG의 핵심 아이디어는 간단합니다. <br>
> **"LLM에게 정답을 바로 묻지 말고, 먼저 관련 정보를 찾아서 '오픈북 시험'을 보게 하자!"** > ## 3. 도입: 똑똑한 LLM을 더 똑똑하게 만들기 (Introduction)
>
그리고 이 복잡한 '오픈북 시험' 과정을 손쉽게 만들어주는 도구가 바로 **LangChain**입니다. LangChain을 통해 LLM이 외부 지식과 소통하게 하여, 훨씬 더 정확하고 신뢰성 있는 AI 애플리케이션을 만드는 방법을 탐험해 봅시다. > 우리는 앞에서 LLM이라는 강력한 '두뇌'를 배웠습니다. 하지만 이 두뇌는 몇 가지 결정적인 한계를 가집니다. 훈련 데이터에 없는 최신 정보나, 우리 회사 내부 문서 같은 사적인 내용은 전혀 알지 못합니다. 가끔은 그럴듯한 거짓말, 즉 '환각' 현상을 보이기도 하죠.
>
> [!TIP] > 이번 시간에는 이 한계를 극복하는 가장 효과적인 기술인 **검색 증강 생성(RAG, Retrieval-Augmented Generation)**을 배웁니다. RAG의 핵심 아이디어는 간단합니다.
> 본 파트의 모든 예제 코드는 `../../source_code/part_7_5_llm_application_development.py` 파일에서 직접 실행하고 수정해볼 수 있습니다. >
> > "LLM에게 정답을 바로 묻지 말고, 먼저 관련 정보를 찾아서 '오픈북 시험'을 보게 하자!"
>
> 그리고 이 복잡한 '오픈북 시험' 과정을 손쉽게 만들어주는 도구가 바로 **LangChain**입니다. LangChain을 통해 LLM이 외부 지식과 소통하게 하여, 훨씬 더 정확하고 신뢰성 있는 AI 애플리케이션을 만드는 방법을 탐험해 봅시다.
>
> > [!TIP]
> > 본 파트의 모든 예제 코드는 `../../source_code/part_7_5_llm_application_development.py` 파일에서 직접 실행하고 수정해볼 수 있습니다.
--- ---
## 4. RAG 파이프라인: 5단계로 완전 정복 <br>
RAG는 크게 **'인덱싱(Indexing)'****'검색 및 생성(Retrieval & Generation)'** 두 단계로 나뉩니다. 이 과정을 5개의 세부 단계로 나누어 살펴보겠습니다. > ## 4. RAG 파이프라인: 5단계로 완전 정복
>
![RAG Pipeline](https://raw.githubusercontent.com/gogodov/Images/main/ai_expert_course/rag_pipeline.png) > RAG는 크게 **'인덱싱(Indexing)'**과 **'검색 및 생성(Retrieval & Generation)'** 두 단계로 나뉩니다. 이 과정을 5개의 세부 단계로 나누어 살펴보겠습니다.
>
### [인덱싱 단계: 도서관에 책 정리하기] > ![RAG Pipeline](https://raw.githubusercontent.com/gogodov/Images/main/ai_expert_course/rag_pipeline.png)
>
#### 1단계: Load (문서 불러오기) > ### [인덱싱 단계: 도서관에 책 정리하기]
- PDF, 웹사이트, DB 등 다양한 소스에서 원본 문서를 불러옵니다. (`Document Loaders`) >
> #### 1단계: Load (문서 불러오기)
#### 2단계: Split (문서 분할하기) > - PDF, 웹사이트, DB 등 다양한 소스에서 원본 문서를 불러옵니다. (`Document Loaders`)
- 문서를 LLM이 처리하기 좋은 작은 조각(Chunk)으로 나눕니다. 의미가 잘 유지되도록 자르는 것이 중요합니다. (`Text Splitters`) >
- **왜 중요할까?** 너무 작게 자르면 문맥을 잃고, 너무 크면 관련 없는 내용이 섞여 LLM의 집중력을 방해합니다. > #### 2단계: Split (문서 분할하기)
> - 문서를 LLM이 처리하기 좋은 작은 조각(Chunk)으로 나눕니다. 의미가 잘 유지되도록 자르는 것이 중요합니다. (`Text Splitters`)
#### 3단계: Embed (의미의 벡터화) > - **왜 중요할까?** 너무 작게 자르면 문맥을 잃고, 너무 크면 관련 없는 내용이 섞여 LLM의 집중력을 방해합니다.
- 각 Chunk를 텍스트 임베딩 모델을 사용해, 의미를 담은 숫자들의 배열, 즉 '벡터'로 변환합니다. >
> #### 3단계: Embed (의미의 벡터화)
#### 4단계: Store (벡터 저장소에 저장) > - 각 Chunk를 텍스트 임베딩 모델을 사용해, 의미를 담은 숫자들의 배열, 즉 '벡터'로 변환합니다.
- 변환된 벡터와 원본 Chunk를 '벡터 저장소(Vector Store)'에 저장하여 언제든 빠르게 검색할 수 있도록 준비합니다. >
- > **💡 비유: 벡터 저장소는 '의미로 책을 찾는 도서관 사서'** > #### 4단계: Store (벡터 저장소에 저장)
> 일반 DB가 '정확한 제목'으로 책을 찾는다면, 벡터 저장소는 "사랑과 희생에 관한 이야기"처럼 **추상적인 의미**로 책을 찾아주는 똑똑한 사서와 같습니다. **FAISS** (빠른 임시 저장), **Chroma** (영구 저장) 등이 대표적입니다. > - 변환된 벡터와 원본 Chunk를 '벡터 저장소(Vector Store)'에 저장하여 언제든 빠르게 검색할 수 있도록 준비합니다.
> - > [!NOTE] 비유: 벡터 저장소는 '의미로 책을 찾는 도서관 사서'
### [검색 및 생성 단계: 똑똑하게 질문하고 답변하기] > > 일반 DB가 '정확한 제목'으로 책을 찾는다면, 벡터 저장소는 "사랑과 희생에 관한 이야기"처럼 **추상적인 의미**로 책을 찾아주는 똑똑한 사서와 같습니다. **FAISS** (빠른 임시 저장), **Chroma** (영구 저장) 등이 대표적입니다.
>
#### 5단계: Retrieve & Generate (검색 후 생성) > ### [검색 및 생성 단계: 똑똑하게 질문하고 답변하기]
- **Retrieve**: 사용자의 질문도 벡터로 변환한 뒤, 벡터 저장소에서 의미적으로 가장 유사한 Chunk들을 찾아냅니다. >
- **Generate**: 검색된 Chunk들을 사용자의 원본 질문과 함께 프롬프트에 담아 LLM에게 전달합니다. LLM은 이 '참고 자료'를 바탕으로 신뢰성 높은 답변을 생성합니다. > #### 5단계: Retrieve & Generate (검색 후 생성)
> - **Retrieve**: 사용자의 질문도 벡터로 변환한 뒤, 벡터 저장소에서 의미적으로 가장 유사한 Chunk들을 찾아냅니다.
> - **Generate**: 검색된 Chunk들을 사용자의 원본 질문과 함께 프롬프트에 담아 LLM에게 전달합니다. LLM은 이 '참고 자료'를 바탕으로 신뢰성 높은 답변을 생성합니다.
--- ---
## 5. 직접 해보기 (Hands-on Lab): 나만의 RAG 챗봇 만들기 <br>
이제 LangChain을 사용하여, 주어진 텍스트에 대해 답변할 수 있는 간단한 RAG 시스템을 직접 구축해 보겠습니다. > ## 5. 직접 해보기 (Hands-on Lab): 나만의 RAG 챗봇 만들기
>
> [!WARNING] > 이제 LangChain을 사용하여, 주어진 텍스트에 대해 답변할 수 있는 간단한 RAG 시스템을 직접 구축해 보겠습니다.
> 이 실습은 OpenAI의 `gpt-3.5-turbo` 모델을 사용하므로, `OPENAI_API_KEY`가 필요합니다. [이곳](https://platform.openai.com/api-keys)에서 API 키를 발급받아 아래 코드에 입력해주세요. >
> > [!WARNING]
### 문제: > > 이 실습은 OpenAI의 `gpt-3.5-turbo` 모델을 사용하므로, `OPENAI_API_KEY`가 필요합니다. [이곳](https://platform.openai.com/api-keys)에서 API 키를 발급받아 아래 코드에 입력해주세요.
아래 `my_document` 텍스트를 RAG 파이프라인에 넣어, 마지막 `query`에 대한 답변을 생성하는 전체 코드를 완성하세요. >
> ### 문제:
```python > 아래 `my_document` 텍스트를 RAG 파이프라인에 넣어, 마지막 `query`에 대한 답변을 생성하는 전체 코드를 완성하세요.
# 필요한 라이브러리 설치 >
# !pip install langchain langchain-openai faiss-cpu tiktoken sentence-transformers > ```python
// ... existing code ...
import os
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_openai import ChatOpenAI
from langchain.text_splitter import CharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain.chains import RetrievalQA
# 1. OpenAI API 키 설정
# os.environ["OPENAI_API_KEY"] = "sk-..." # 여기에 자신의 API 키를 입력하세요.
# 2. RAG를 위한 샘플 문서 정의
my_document = """
AI 기술이 발전하면서, 많은 사람들이 AI 비전공자를 위한 최고의 입문서가 무엇인지 궁금해합니다.
여러 전문가들은 '핸즈온 머신러닝(2판)'을 최고의 책으로 꼽습니다.
이 책은 머신러닝의 기초부터 딥러닝, 그리고 실제 프로젝트에 적용하는 방법까지 폭넓게 다룹니다.
특히, 복잡한 수학적 이론보다는 실제 코드를 통해 개념을 익힐 수 있도록 구성되어 있어,
프로그래밍에 익숙한 비전공자들이 접근하기에 매우 용이합니다.
물론, '밑바닥부터 시작하는 딥러닝' 시리즈도 훌륭한 선택지이지만,
이 책은 이론적인 깊이가 상당하여 전공자에게 더 적합할 수 있습니다.
"""
# 3. 문서 분할 (Split)
# Hint: CharacterTextSplitter를 사용하여 문서를 chunk_size=200, chunk_overlap=0 으로 분할
text_splitter = CharacterTextSplitter(chunk_size=200, chunk_overlap=0)
docs = text_splitter.create_documents([my_document])
# 4. 임베딩 모델 준비 (Embed)
# Hugging Face의 오픈소스 한국어 임베딩 모델 사용
model_name = "jhgan/ko-sroberta-multitask"
hf_embeddings = HuggingFaceEmbeddings(model_name=model_name)
# 5. 벡터 저장소 생성 (Store)
# FAISS를 사용하여 docs를 임베딩하고 벡터 저장소(db)를 생성
db = FAISS.from_documents(docs, hf_embeddings)
# 6. RAG 체인 생성 및 실행 (Retrieve & Generate)
# OpenAI 모델을 LLM으로 사용
llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)
# RetrievalQA 체인 생성
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=db.as_retriever(),
)
# 7. 질문 및 답변
query = "AI 비전공자가 입문하기 좋은 책은 무엇인가요? 그리고 그 이유는 무엇인가요?" query = "AI 비전공자가 입문하기 좋은 책은 무엇인가요? 그리고 그 이유는 무엇인가요?"
response = qa_chain.invoke(query) response = qa_chain.invoke(query)
print(response["result"]) print(response["result"])
``` ```
>
> ---
>
> ### 캡스톤 프로젝트 연계 미니 프로젝트: "회사 내부 문서 Q&A 봇 만들기 (실전 RAG)"
>
> 앞서 배운 RAG 파이프라인을 활용하여, 단순 텍스트가 아닌 실제 파일(`.md`)을 기반으로 질문에 답변하는 실용적인 Q&A 봇을 구축합니다. 이 과제는 최종 캡스톤 프로젝트에서 특정 도메인(예: 법률, 의료, 금융)의 문서를 다루는 LLM 애플리케이션을 구현할 때 훌륭한 기반이 됩니다.
>
> - **목표**: LangChain의 `DocumentLoader`를 사용하여 외부 마크다운 파일을 로드하고, 해당 문서의 내용에 대해서만 정확하게 답변하는 RAG 시스템을 완성합니다.
> - **과제**:
> 1. **샘플 문서 확인**: `../../source_code/data/rag_sample_company_rules.md` 파일의 내용을 확인합니다. 이 문서는 가상의 회사 보안 규정에 대한 내용을 담고 있습니다.
> 2. **Document Loader 사용**: 기존의 `my_document` 변수 대신, LangChain의 `TextLoader`를 사용하여 위 마크다운 파일을 로드하도록 코드를 수정하세요.
> 3. **성능 테스트**:
> - **문서 기반 질문**: "업무용 노트북에서 개인 이메일 사용이 가능한가요?" 와 같이 문서에 명시된 내용에 대해 질문하고, RAG 시스템이 정확한 답변을 생성하는지 확인합니다.
> - **문서 외 질문 (Grounding 테스트)**: "회사의 연봉 정책에 대해 알려줘" 와 같이 문서에 없는 내용에 대해 질문했을 때, 모델이 "문서에서 관련 정보를 찾을 수 없습니다" 또는 "알 수 없습니다" 와 같이 솔직하게 답변하는지(Grounding) 확인합니다.
> - **기대 효과**:
> - `DocumentLoader`의 역할을 이해하고, 다양한 포맷의 문서를 LLM 애플리케이션에 통합하는 방법을 학습합니다.
> - RAG 시스템의 핵심 역량인 'Grounding'(제공된 정보에 기반하여 답변하는 능력)의 중요성을 체감합니다.
> - 환각(Hallucination) 현상을 줄이고 LLM의 신뢰도를 높이는 실용적인 방법을 터득합니다.
> - **구현 가이드**: `../../source_code/part_7_5_llm_application_development.py` 파일의 주석 가이드를 따라 코드를 완성해보세요.
--- ---
### 💡 Capstone Project 연계 미니 프로젝트: "회사 내부 문서 Q&A 봇 만들기 (실전 RAG)" <br>
앞서 배운 RAG 파이프라인을 활용하여, 단순 텍스트가 아닌 실제 파일(`.md`)을 기반으로 질문에 답변하는 실용적인 Q&A 봇을 구축합니다. 이 과제는 최종 캡스톤 프로젝트에서 특정 도메인(예: 법률, 의료, 금융)의 문서를 다루는 LLM 애플리케이션을 구현할 때 훌륭한 기반이 됩니다.
- **목표**: LangChain의 `DocumentLoader`를 사용하여 외부 마크다운 파일을 로드하고, 해당 문서의 내용에 대해서만 정확하게 답변하는 RAG 시스템을 완성합니다. > ## 6. 되짚어보기 (Summary)
- **과제**: >
1. **샘플 문서 확인**: `../../source_code/data/rag_sample_company_rules.md` 파일의 내용을 확인합니다. 이 문서는 가상의 회사 보안 규정에 대한 내용을 담고 있습니다. > 이번 시간에는 LLM의 한계를 넘어, 외부 세계와 소통하는 AI를 만드는 강력한 기술인 RAG를 배웠습니다.
2. **Document Loader 사용**: 기존의 `my_document` 변수 대신, LangChain의 `TextLoader`를 사용하여 위 마크다운 파일을 로드하도록 코드를 수정하세요. >
3. **성능 테스트**: > - **RAG의 필요성**: LLM의 최신성 부족, 환각 현상과 같은 문제를 해결하기 위해, LLM에게 '오픈북 시험'을 보게 하는 방식이 RAG임을 이해했습니다.
- **문서 기반 질문**: "업무용 노트북에서 개인 이메일 사용이 가능한가요?" 와 같이 문서에 명시된 내용에 대해 질문하고, RAG 시스템이 정확한 답변을 생성하는지 확인합니다. > - **RAG 파이프라인**: **Load → Split → Embed → Store → Retrieve & Generate** 로 이어지는 5단계의 과정을 통해 RAG 시스템이 어떻게 작동하는지 파악했습니다.
- **문서 외 질문 (Grounding 테스트)**: "회사의 연봉 정책에 대해 알려줘" 와 같이 문서에 없는 내용에 대해 질문했을 때, 모델이 "문서에서 관련 정보를 찾을 수 없습니다" 또는 "알 수 없습니다" 와 같이 솔직하게 답변하는지(Grounding) 확인합니다. > - **실전 RAG 구축**: LangChain을 사용하여, 주어진 문서의 내용을 기반으로 질문에 답변하는 RAG 챗봇을 직접 코드로 구현하는 경험을 쌓았습니다.
- **기대 효과**: >
- `DocumentLoader`의 역할을 이해하고, 다양한 포맷의 문서를 LLM 애플리케이션에 통합하는 방법을 학습합니다. > 이제 여러분은 단순히 LLM을 사용하는 것을 넘어, LLM을 다른 데이터, 다른 도구와 '연결'하여 훨씬 더 지능적이고 실용적인 애플리케이션을 만들 수 있는 첫걸음을 뗐습니다.
- RAG 시스템의 핵심 역량인 'Grounding'(제공된 정보에 기반하여 답변하는 능력)의 중요성을 체감합니다.
- 환각(Hallucination) 현상을 줄이고 LLM의 신뢰도를 높이는 실용적인 방법을 터득합니다.
- **구현 가이드**: `../../source_code/part_7_5_llm_application_development.py` 파일의 주석 가이드를 따라 코드를 완성해보세요.
--- <br>
## 6. 되짚어보기 (Summary) > ## 7. 더 깊이 알아보기 (Further Reading)
> - [LangChain 공식 문서: RAG](https://python.langchain.com/v0.2/docs/concepts/#retrieval-augmented-generation-rag): LangChain이 설명하는 RAG의 개념과 다양한 활용법
이번 시간에는 LLM의 한계를 넘어, 외부 세계와 소통하는 AI를 만드는 강력한 기술인 RAG를 배웠습니다. > - [Pinecone: What is RAG?](https://www.pinecone.io/learn/retrieval-augmented-generation/): 대표적인 벡터 DB 회사인 Pinecone이 설명하는 RAG 가이드
> - [Hugging Face 블로그: RAG](https://huggingface.co/docs/transformers/main/en/rag): 허깅페이스에서 제공하는 RAG에 대한 기술적인 설명
- **RAG의 필요성**: LLM의 최신성 부족, 환각 현상과 같은 문제를 해결하기 위해, LLM에게 '오픈북 시험'을 보게 하는 방식이 RAG임을 이해했습니다.
- **RAG 파이프라인**: **Load → Split → Embed → Store → Retrieve & Generate** 로 이어지는 5단계의 과정을 통해 RAG 시스템이 어떻게 작동하는지 파악했습니다.
- **실전 RAG 구축**: LangChain을 사용하여, 주어진 문서의 내용을 기반으로 질문에 답변하는 RAG 챗봇을 직접 코드로 구현하는 경험을 쌓았습니다.
이제 여러분은 단순히 LLM을 사용하는 것을 넘어, LLM을 다른 데이터, 다른 도구와 '연결'하여 훨씬 더 지능적이고 실용적인 애플리케이션을 만들 수 있는 첫걸음을 뗐습니다.
## 7. 더 깊이 알아보기 (Further Reading)
- [LangChain 공식 문서: RAG](https://python.langchain.com/v0.2/docs/concepts/#retrieval-augmented-generation-rag): LangChain이 설명하는 RAG의 개념과 다양한 활용법
- [Pinecone: What is RAG?](https://www.pinecone.io/learn/retrieval-augmented-generation/): 대표적인 벡터 DB 회사인 Pinecone이 설명하는 RAG 가이드
- [Hugging Face 블로그: RAG](https://huggingface.co/docs/transformers/main/en/rag): 허깅페이스에서 제공하는 RAG에 대한 기술적인 설명
--- ---
### ⚠️ What Could Go Wrong? (토론 주제) <br>
LangChain은 LLM 기반 애플리케이션 개발을 가속화하는 강력한 도구이지만, 실제 프로덕션 환경에 적용할 때는 여러 잠재적 위험과 한계를 고려해야 합니다. > ### ⚠️ What Could Go Wrong? (토론 주제)
>
1. **지나친 추상화의 함정 (The Pitfall of Over-abstraction)** > LangChain은 LLM 기반 애플리케이션 개발을 가속화하는 강력한 도구이지만, 실제 프로덕션 환경에 적용할 때는 여러 잠재적 위험과 한계를 고려해야 합니다.
* LangChain의 고수준 추상화가 내부 동작을 이해하기 어렵게 만들어, 특정 요구사항에 맞게 커스터마이징하거나 디버깅할 때 오히려 더 복잡해지는 상황이 발생할 수 있습니다. "간단한 일은 더 간단하게, 복잡한 일은 불가능하게" 만드는 경우가 될 수 있을까요? >
* 특정 컴포넌트(예: Vectorstore)를 교체하거나 세부 동작을 수정하려 할 때, LangChain의 추상화 계층 때문에 예상보다 많은 노력이 드는 경우를 겪어본 적이 있나요? > 1. **지나친 추상화의 함정 (The Pitfall of Over-abstraction)**
> * LangChain의 고수준 추상화가 내부 동작을 이해하기 어렵게 만들어, 특정 요구사항에 맞게 커스터마이징하거나 디버깅할 때 오히려 더 복잡해지는 상황이 발생할 수 있습니다. "간단한 일은 더 간단하게, 복잡한 일은 불가능하게" 만드는 경우가 될 수 있을까요?
2. **프롬프트 주입 및 보안 취약점 (Prompt Injection & Security Vulnerabilities)** > * 특정 컴포넌트(예: Vectorstore)를 교체하거나 세부 동작을 수정하려 할 때, LangChain의 추상화 계층 때문에 예상보다 많은 노력이 드는 경우를 겪어본 적이 있나요?
* RAG(Retrieval-Augmented Generation) 파이프라인에서 사용자가 악의적으로 조작한 문서를 데이터 소스에 포함시켜, 시스템 프롬프트를 탈취하거나 의도치 않은 결과를 유도하는 '프롬프트 주입' 공격에 어떻게 대비해야 할까요? >
* LangChain 에이전트가 파일 시스템 접근이나 API 호출과 같은 위험한 도구(Tool)를 사용할 때, 권한 상승이나 데이터 유출과 같은 보안 사고를 방지하기 위한 안전장치는 무엇이 있을까요? > 2. **프롬프트 주입 및 보안 취약점 (Prompt Injection & Security Vulnerabilities)**
> * RAG(Retrieval-Augmented Generation) 파이프라인에서 사용자가 악의적으로 조작한 문서를 데이터 소스에 포함시켜, 시스템 프롬프트를 탈취하거나 의도치 않은 결과를 유도하는 '프롬프트 주입' 공격에 어떻게 대비해야 할까요?
3. **에이전트의 예측 불가능성과 제어의 어려움 (Unpredictability and Controllability of Agents)** > * LangChain 에이전트가 파일 시스템 접근이나 API 호출과 같은 위험한 도구(Tool)를 사용할 때, 권한 상승이나 데이터 유출과 같은 보안 사고를 방지하기 위한 안전장치는 무엇이 있을까요?
* ReAct와 같은 복잡한 에이전트가 잘못된 추론 경로에 빠져 무한 루프를 돌거나, 의도치 않게 비싼 유료 API를 계속 호출하여 막대한 비용을 발생시키는 상황을 어떻게 방지할 수 있을까요? >
* "목표를 줄 테니 알아서 해줘"라는 에이전트의 방식이, 실제 비즈니스 로직처럼 엄격한 제어가 필요한 경우에 적합할까요? 에이전트의 자율성과 시스템의 안정성 사이의 균형점은 어디일까요? > 3. **에이전트의 예측 불가능성과 제어의 어려움 (Unpredictability and Controllability of Agents)**
> * ReAct와 같은 복잡한 에이전트가 잘못된 추론 경로에 빠져 무한 루프를 돌거나, 의도치 않게 비싼 유료 API를 계속 호출하여 막대한 비용을 발생시키는 상황을 어떻게 방지할 수 있을까요?
4. **디버깅과 투명성 부족 (Lack of Debuggability and Transparency)** > * "목표를 줄 테니 알아서 해줘"라는 에이전트의 방식이, 실제 비즈니스 로직처럼 엄격한 제어가 필요한 경우에 적합할까요? 에이전트의 자율성과 시스템의 안정성 사이의 균형점은 어디일까요?
* 여러 체인과 에이전트, 도구가 복잡하게 얽혀 있을 때, 최종 결과가 어떤 중간 단계를 거쳐 나왔는지 추적하기 어려운 경험을 한 적이 있나요? (e.g., "왜 이 답변이 나왔지?") >
* LangSmith와 같은 추적 도구가 이러한 문제를 어느 정도 해결해주지만, 근본적인 복잡성 자체는 여전히 높은 진입 장벽이 될 수 있지 않을까요? > 4. **디버깅과 투명성 부족 (Lack of Debuggability and Transparency)**
> * 여러 체인과 에이전트, 도구가 복잡하게 얽혀 있을 때, 최종 결과가 어떤 중간 단계를 거쳐 나왔는지 추적하기 어려운 경험을 한 적이 있나요? (e.g., "왜 이 답변이 나왔지?")
5. **프레임워크 종속성 문제 (Framework Lock-in)** > * LangSmith와 같은 추적 도구가 이러한 문제를 어느 정도 해결해주지만, 근본적인 복잡성 자체는 여전히 높은 진입 장벽이 될 수 있지 않을까요?
* 애플리케이션의 핵심 로직을 LangChain의 특정 구조와 기능에 깊이 의존하여 개발했을 때, 나중에 다른 프레임워크나 순수 API 호출 기반의 코드로 전환하기 어려워지는 '기술 부채'가 될 수 있습니다. 이러한 종속성을 최소화하며 LangChain을 현명하게 활용하는 전략은 무엇일까요? >
> 5. **프레임워크 종속성 문제 (Framework Lock-in)**
> * 애플리케이션의 핵심 로직을 LangChain의 특정 구조와 기능에 깊이 의존하여 개발했을 때, 나중에 다른 프레임워크나 순수 API 호출 기반의 코드로 전환하기 어려워지는 '기술 부채'가 될 수 있습니다. 이러한 종속성을 최소화하며 LangChain을 현명하게 활용하는 전략은 무엇일까요?
--- ---
<br>
**➡️ 다음 시간: [Part 7.4: 그래프 신경망 (GNN)](./part_7.4_graph_neural_networks.md)** **➡️ 다음 시간: [Part 7.4: 그래프 신경망 (GNN)](./part_7.4_graph_neural_networks.md)**
\ No newline at end of file
...@@ -5,118 +5,140 @@ ...@@ -5,118 +5,140 @@
--- ---
<br>
> [!WARNING] > [!WARNING]
> 이 파트는 현재 준비 중입니다. GNN의 핵심 개념과 PyTorch Geometric을 사용한 실습 코드가 추가될 예정입니다. > 이 파트는 현재 준비 중입니다. GNN의 핵심 개념과 PyTorch Geometric을 사용한 실습 코드가 추가될 예정입니다.
## 1. 학습 목표 (Learning Objectives) <br>
이번 파트가 끝나면, 여러분은 다음을 할 수 있게 됩니다.
- 그래프(Graph) 데이터의 구조와 특징을 이해합니다.
- GNN이 왜 필요한지, 기존의 신경망과 무엇이 다른지 설명할 수 있습니다.
- GNN의 핵심 아이디어인 메시지 패싱(Message Passing)의 기본 개념을 이해합니다.
- PyTorch Geometric 라이브러리를 사용하여 간단한 GNN 모델을 구성할 수 있습니다.
## 2. 핵심 키워드 (Keywords)
`그래프 신경망(GNN)`, `그래프 데이터(Graph Data)`, `노드(Node)`, `엣지(Edge)`, `인접 행렬(Adjacency Matrix)`, `메시지 패싱(Message Passing)`, `PyTorch Geometric` > ## 1. 학습 목표 (Learning Objectives)
>
> 이번 파트가 끝나면, 여러분은 다음을 할 수 있게 됩니다.
>
> - 그래프(Graph) 데이터의 구조와 특징을 이해합니다.
> - GNN이 왜 필요한지, 기존의 신경망과 무엇이 다른지 설명할 수 있습니다.
> - GNN의 핵심 아이디어인 메시지 패싱(Message Passing)의 기본 개념을 이해합니다.
> - PyTorch Geometric 라이브러리를 사용하여 간단한 GNN 모델을 구성할 수 있습니다.
## 3. 도입: 관계를 학습하는 모델, GNN <br>
세상은 연결의 집합입니다. > ## 2. 핵심 키워드 (Keywords)
- **소셜 네트워크**: 사람(노드)들은 친구 관계(엣지)로 연결됩니다. >
- **분자 구조**: 원자(노드)들은 화학 결합(엣지)으로 연결됩니다. > `그래프 신경망(GNN)`, `그래프 데이터(Graph Data)`, `노드(Node)`, `엣지(Edge)`, `인접 행렬(Adjacency Matrix)`, `메시지 패싱(Message Passing)`, `PyTorch Geometric`
- **도로망**: 교차로(노드)들은 도로(엣지)로 연결됩니다.
이처럼 **객체(노드)와 그들의 관계(엣지)로 표현되는 데이터****그래프 데이터**라고 합니다. 기존의 MLP나 CNN, RNN은 이러한 복잡한 관계성을 직접 다루기 어렵습니다. <br>
**그래프 신경망(Graph Neural Network, GNN)**은 그래프 구조 자체를 입력으로 받아, 노드의 특징과 노드 간의 연결 관계를 종합적으로 학습하는 강력한 아키텍처입니다. > ## 3. 도입: 관계를 학습하는 모델, GNN
>
> 세상은 연결의 집합입니다.
> - **소셜 네트워크**: 사람(노드)들은 친구 관계(엣지)로 연결됩니다.
> - **분자 구조**: 원자(노드)들은 화학 결합(엣지)으로 연결됩니다.
> - **도로망**: 교차로(노드)들은 도로(엣지)로 연결됩니다.
>
> 이처럼 **객체(노드)와 그들의 관계(엣지)로 표현되는 데이터**를 **그래프 데이터**라고 합니다. 기존의 MLP나 CNN, RNN은 이러한 복잡한 관계성을 직접 다루기 어렵습니다.
>
> **그래프 신경망(Graph Neural Network, GNN)**은 그래프 구조 자체를 입력으로 받아, 노드의 특징과 노드 간의 연결 관계를 종합적으로 학습하는 강력한 아키텍처입니다.
--- ---
## 4. GNN의 핵심 아이디어: 메시지 패싱 (Message Passing) <br>
GNN의 핵심 원리는 "이웃 노드로부터 정보를 받아서 나의 정보를 업데이트한다"는 **메시지 패싱** 아이디어로 요약할 수 있습니다. > ## 4. GNN의 핵심 아이디어: 메시지 패싱 (Message Passing)
>
![Message Passing](https://distill.pub/2021/gnn-intro/images/gnn-computation-2.gif) > GNN의 핵심 원리는 "이웃 노드로부터 정보를 받아서 나의 정보를 업데이트한다"는 **메시지 패싱** 아이디어로 요약할 수 있습니다.
*(이미지 출처: distill.pub)* >
> ![Message Passing](https://distill.pub/2021/gnn-intro/images/gnn-computation-2.gif)
1. **메시지 생성**: 각 노드는 자신의 이웃 노드들에게 보낼 '메시지'를 생성합니다. > *(이미지 출처: distill.pub)*
2. **정보 취합 (Aggregation)**: 각 노드는 이웃들로부터 받은 메시지들을 하나로 모읍니다. (예: 평균을 내거나, 합산) >
3. **정보 업데이트 (Update)**: 각 노드는 취합된 정보와 자기 자신의 기존 정보를 바탕으로 새로운 상태(표현 벡터)를 계산합니다. > 1. **메시지 생성**: 각 노드는 자신의 이웃 노드들에게 보낼 '메시지'를 생성합니다.
> 2. **정보 취합 (Aggregation)**: 각 노드는 이웃들로부터 받은 메시지들을 하나로 모읍니다. (예: 평균을 내거나, 합산)
이 과정을 여러 번 반복(여러 GNN 레이어를 쌓음)함으로써, 노드들은 더 멀리 있는 이웃들의 정보까지 전달받아 자신의 표현을 더욱 풍부하게 만들 수 있습니다. > 3. **정보 업데이트 (Update)**: 각 노드는 취합된 정보와 자기 자신의 기존 정보를 바탕으로 새로운 상태(표현 벡터)를 계산합니다.
>
> 이 과정을 여러 번 반복(여러 GNN 레이어를 쌓음)함으로써, 노드들은 더 멀리 있는 이웃들의 정보까지 전달받아 자신의 표현을 더욱 풍부하게 만들 수 있습니다.
--- ---
## 5. 직접 해보기 (Hands-on Lab): (내용 추가 예정) <br>
PyTorch Geometric 라이브러리를 사용하여 소셜 네트워크의 사용자 직업을 예측하는 GNN 모델을 만들어볼 예정입니다. > ## 5. 직접 해보기 (Hands-on Lab): (내용 추가 예정)
>
> PyTorch Geometric 라이브러리를 사용하여 소셜 네트워크의 사용자 직업을 예측하는 GNN 모델을 만들어볼 예정입니다.
--- ---
## 6. 되짚어보기 (Summary) <br>
- **GNN**: 노드와 엣지로 구성된 그래프 구조의 데이터를 직접 처리하기 위한 신경망입니다. > ## 6. 되짚어보기 (Summary)
- **핵심 원리**: 이웃 노드와 '메시지'를 주고받으며 자신의 정보를 업데이트하는 **메시지 패싱**을 기반으로 합니다. >
- **활용**: 추천 시스템, 신약 개발, 금융 사기 탐지 등 관계 속에서 패턴을 찾아내는 다양한 분야에 활용됩니다. > - **GNN**: 노드와 엣지로 구성된 그래프 구조의 데이터를 직접 처리하기 위한 신경망입니다.
> - **핵심 원리**: 이웃 노드와 '메시지'를 주고받으며 자신의 정보를 업데이트하는 **메시지 패싱**을 기반으로 합니다.
> - **활용**: 추천 시스템, 신약 개발, 금융 사기 탐지 등 관계 속에서 패턴을 찾아내는 다양한 분야에 활용됩니다.
--- ---
<br>
**➡️ 다음 시간: [Part 7.5: 강화학습 (Reinforcement Learning)](./part_7.5_reinforcement_learning.md)** **➡️ 다음 시간: [Part 7.5: 강화학습 (Reinforcement Learning)](./part_7.5_reinforcement_learning.md)**
### 참고 자료 <br>
* [A Gentle Introduction to Graph Neural Networks](https://distill.pub/2021/gnn-intro/): GNN에 대한 시각적이고 직관적인 설명이 담긴 distill.pub 아티클 > ### 참고 자료
* [PyTorch Geometric 라이브러리](https://pytorch-geometric.readthedocs.io/en/latest/): PyTorch 기반의 GNN 라이브러리 >
> * [A Gentle Introduction to Graph Neural Networks](https://distill.pub/2021/gnn-intro/): GNN에 대한 시각적이고 직관적인 설명이 담긴 distill.pub 아티클
> * [PyTorch Geometric 라이브러리](https://pytorch-geometric.readthedocs.io/en/latest/): PyTorch 기반의 GNN 라이브러리
--- ---
### ⚠️ What Could Go Wrong? (토론 주제) <br>
GNN은 관계형 데이터를 다루는 강력한 패러다임이지만, 실제 적용 시에는 고유한 기술적 난제들을 마주하게 됩니다. > ### ⚠️ What Could Go Wrong? (토론 주제)
>
1. **과잉 평탄화 문제 (Over-smoothing Problem)** > GNN은 관계형 데이터를 다루는 강력한 패러다임이지만, 실제 적용 시에는 고유한 기술적 난제들을 마주하게 됩니다.
* GNN 레이어를 깊게 쌓았을 때, 여러 홉 떨어진 노드들의 정보가 섞이면서 결국 모든 노드 임베딩이 서로 유사해져 버리는 '과잉 평탄화' 현상이 발생합니다. 이 때문에 깊은 GNN 모델의 성능이 얕은 모델보다 오히려 떨어질 수 있는데, 왜 이런 현상이 발생할까요? >
* 이를 해결하기 위해 제안된 방법들(예: Jumping Knowledge, GCNII, Skip-connection)은 어떤 원리로 이 문제를 완화하며, 각각 어떤 장단점을 가질까요? > 1. **과잉 평탄화 문제 (Over-smoothing Problem)**
> * GNN 레이어를 깊게 쌓았을 때, 여러 홉 떨어진 노드들의 정보가 섞이면서 결국 모든 노드 임베딩이 서로 유사해져 버리는 '과잉 평탄화' 현상이 발생합니다. 이 때문에 깊은 GNN 모델의 성능이 얕은 모델보다 오히려 떨어질 수 있는데, 왜 이런 현상이 발생할까요?
2. **이웃 폭발 및 확장성 문제 (Neighbor Explosion & Scalability Issues)** > * 이를 해결하기 위해 제안된 방법들(예: Jumping Knowledge, GCNII, Skip-connection)은 어떤 원리로 이 문제를 완화하며, 각각 어떤 장단점을 가질까요?
* 하나의 노드 임베딩을 계산하기 위해 이웃 노드들을 재귀적으로 참조하다 보면, 몇 홉만 거쳐도 관련 노드의 수가 기하급수적으로 증가하여 '이웃 폭발'이 발생합니다. 이는 대규모 그래프에서 메모리 부족(Out-of-Memory)과 연산량 폭증의 원인이 됩니다. >
* GraphSAGE에서 제안한 '이웃 샘플링(Neighbor Sampling)' 방식은 이 문제를 어떻게 해결하나요? 샘플링이 가져오는 성능과 연산량 간의 트레이드오프는 무엇일까요? > 2. **이웃 폭발 및 확장성 문제 (Neighbor Explosion & Scalability Issues)**
> * 하나의 노드 임베딩을 계산하기 위해 이웃 노드들을 재귀적으로 참조하다 보면, 몇 홉만 거쳐도 관련 노드의 수가 기하급수적으로 증가하여 '이웃 폭발'이 발생합니다. 이는 대규모 그래프에서 메모리 부족(Out-of-Memory)과 연산량 폭증의 원인이 됩니다.
3. **동적 그래프 처리의 어려움 (Difficulty with Dynamic Graphs)** > * GraphSAGE에서 제안한 '이웃 샘플링(Neighbor Sampling)' 방식은 이 문제를 어떻게 해결하나요? 샘플링이 가져오는 성능과 연산량 간의 트레이드오프는 무엇일까요?
* 실세계의 많은 그래프(소셜 네트워크, 금융 거래망)는 시간이 지남에 따라 노드와 엣지가 끊임없이 변하는 '동적 그래프'입니다. 새로운 노드가 추가될 때마다 전체 모델을 다시 학습시켜야 할까요? >
* 시간의 흐름에 따른 변화를 GNN 모델이 학습하게 하려면 어떤 접근법(예: Temporal GNNs)이 필요하며, 기존 GNN과 비교하여 어떤 점이 더 복잡할까요? > 3. **동적 그래프 처리의 어려움 (Difficulty with Dynamic Graphs)**
> * 실세계의 많은 그래프(소셜 네트워크, 금융 거래망)는 시간이 지남에 따라 노드와 엣지가 끊임없이 변하는 '동적 그래프'입니다. 새로운 노드가 추가될 때마다 전체 모델을 다시 학습시켜야 할까요?
4. **비관계형 데이터에 대한 부적절한 적용 (Inappropriate Application to Non-relational Data)** > * 시간의 흐름에 따른 변화를 GNN 모델이 학습하게 하려면 어떤 접근법(예: Temporal GNNs)이 필요하며, 기존 GNN과 비교하여 어떤 점이 더 복잡할까요?
* 모든 데이터를 그래프 형태로 표현할 수는 있지만, 그것이 항상 유용한 것은 아닙니다. 노드 간의 '관계'가 명확하지 않거나 의미 없는 데이터를 억지로 그래프로 구성하여 GNN을 적용하면 어떤 문제가 발생할 수 있을까요? >
* GNN이 다른 모델(예: CNN, RNN, Transformer)에 비해 확실한 강점을 가지는 데이터의 특징은 무엇이라고 생각하시나요? > 4. **비관계형 데이터에 대한 부적절한 적용 (Inappropriate Application to Non-relational Data)**
> * 모든 데이터를 그래프 형태로 표현할 수는 있지만, 그것이 항상 유용한 것은 아닙니다. 노드 간의 '관계'가 명확하지 않거나 의미 없는 데이터를 억지로 그래프로 구성하여 GNN을 적용하면 어떤 문제가 발생할 수 있을까요?
5. **그래프 구조 자체의 편향 (Bias in Graph Structure)** > * GNN이 다른 모델(예: CNN, RNN, Transformer)에 비해 확실한 강점을 가지는 데이터의 특징은 무엇이라고 생각하시나요?
* 소셜 네트워크에서 특정 인구 집단이 다른 집단보다 더 촘촘하게 연결된 '에코 체임버'나 '필터 버블'이 존재할 수 있습니다. 이런 편향된 구조를 학습한 GNN 모델이 소수 집단에 대해 불공정한 예측을 내릴 위험은 없을까요? 이러한 구조적 편향을 어떻게 탐지하고 완화할 수 있을까요? >
> 5. **그래프 구조 자체의 편향 (Bias in Graph Structure)**
> * 소셜 네트워크에서 특정 인구 집단이 다른 집단보다 더 촘촘하게 연결된 '에코 체임버'나 '필터 버블'이 존재할 수 있습니다. 이런 편향된 구조를 학습한 GNN 모델이 소수 집단에 대해 불공정한 예측을 내릴 위험은 없을까요? 이러한 구조적 편향을 어떻게 탐지하고 완화할 수 있을까요?
--- ---
## 캡스톤 프로젝트 연계 미니 프로젝트: 소셜 네트워크 기반 친구 추천 시스템 <br>
이 챕터에서 배운 GNN의 개념을 활용하여, 15장 캡스톤 프로젝트의 '추천 시스템' 아이디어에 적용해볼 수 있는 미니 프로젝트를 진행합니다. 사용자의 연결 관계(그래프)를 기반으로 새로운 친구를 추천하는 모델을 직접 만들어보면서, GNN의 실용성을 체감하는 것을 목표로 합니다. > ## 캡스톤 프로젝트 연계 미니 프로젝트: 소셜 네트워크 기반 친구 추천 시스템
>
### 프로젝트 목표 > 이 챕터에서 배운 GNN의 개념을 활용하여, 15장 캡스톤 프로젝트의 '추천 시스템' 아이디어에 적용해볼 수 있는 미니 프로젝트를 진행합니다. 사용자의 연결 관계(그래프)를 기반으로 새로운 친구를 추천하는 모델을 직접 만들어보면서, GNN의 실용성을 체감하는 것을 목표로 합니다.
- `PyTorch Geometric`을 사용하여 소셜 네트워크 데이터를 로드하고 시각화합니다. >
- 간단한 GCN(Graph Convolutional Network) 모델을 구축하여, 그래프의 '링크 예측(Link Prediction)' 문제를 해결합니다. > ### 프로젝트 목표
- 특정 사용자가 주어졌을 때, 연결될 가능성이 가장 높은 다른 사용자(새로운 친구)를 추천하는 API의 프로토타입을 구상합니다. > - `PyTorch Geometric`을 사용하여 소셜 네트워크 데이터를 로드하고 시각화합니다.
> - 간단한 GCN(Graph Convolutional Network) 모델을 구축하여, 그래프의 '링크 예측(Link Prediction)' 문제를 해결합니다.
### 개발 과정 > - 특정 사용자가 주어졌을 때, 연결될 가능성이 가장 높은 다른 사용자(새로운 친구)를 추천하는 API의 프로토타입을 구상합니다.
1. **데이터셋 선정**: `PyTorch Geometric`에 내장된 `Cora` 또는 `CiteSeer`와 같은 인용 네트워크 데이터셋을 소셜 네트워크라고 가정하고 사용합니다. 각 논문은 '사용자', 인용 관계는 '친구 관계'로 간주합니다. >
2. **모델링**: > ### 개발 과정
- 노드(사용자)의 특징을 입력으로 받아, GCN 레이어를 통과시켜 임베딩을 생성합니다. > 1. **데이터셋 선정**: `PyTorch Geometric`에 내장된 `Cora` 또는 `CiteSeer`와 같은 인용 네트워크 데이터셋을 소셜 네트워크이라고 가정하고 사용합니다. 각 논문은 '사용자', 인용 관계는 '친구 관계'로 간주합니다.
- 두 노드 임베딩의 내적(dot product)을 계산하여, 두 노드 사이에 링크(친구 관계)가 존재할 확률을 예측하는 모델을 만듭니다. > 2. **모델링**:
3. **학습 및 평가**: > - 노드(사용자)의 특징을 입력으로 받아, GCN 레이어를 통과시켜 임베딩을 생성합니다.
- 기존의 링크 중 일부를 일부러 숨기고(train/test split), 모델이 이 숨겨진 링크를 얼마나 잘 예측하는지 평가합니다. (AUC, Accuracy 등) > - 두 노드 임베딩의 내적(dot product)을 계산하여, 두 노드 사이에 링크(친구 관계)가 존재할 확률을 예측하는 모델을 만듭니다.
4. **결과 해석 및 활용**: > 3. **학습 및 평가**:
- 학습된 모델을 사용하여, 현재 연결되지 않은 노드 쌍 중에서 연결 확률이 가장 높은 쌍을 찾습니다. > - 기존의 링크 중 일부를 일부러 숨기고(train/test split), 모델이 이 숨겨진 링크를 얼마나 잘 예측하는지 평가합니다. (AUC, Accuracy 등)
- 이를 "사용자 A에게 사용자 B, C, D를 추천합니다"와 같은 기능으로 연결하여, 캡스톤 프로젝트에서 만들 최종 서비스의 그림을 그려봅니다. > 4. **결과 해석 및 활용**:
> - 학습된 모델을 사용하여, 현재 연결되지 않은 노드 쌍 중에서 연결 확률이 가장 높은 쌍을 찾습니다.
### 캡스톤 프로젝트 연계 방안 > - 이를 "사용자 A에게 사용자 B, C, D를 추천합니다"와 같은 기능으로 연결하여, 캡스톤 프로젝트에서 만들 최종 서비스의 그림을 그려봅니다.
- **추천 시스템 고도화**: 실제 캡스톤 프로젝트에서는 단순 친구 관계를 넘어, '사용자-상품' 관계, '영화-배우-감독' 관계 등 더 복잡한 그래프를 구축하여 GNN 기반 추천 모델을 만들 수 있습니다. >
- **FastAPI 연동**: 이 미니 프로젝트에서 개발한 모델을 `part_8_model_serving_with_fastapi.md`에서 배울 FastAPI를 사용해 API로 서빙하는 기능을 구현해볼 수 있습니다. 예를 들어, `GET /users/{user_id}/recommendations` 와 같은 엔드포인트를 설계할 수 있습니다. > ### 캡스톤 프로젝트 연계 방안
\ No newline at end of file > - **추천 시스템 고도화**: 실제 캡스톤 프로젝트에서는 단순 친구 관계를 넘어, '사용자-상품' 관계, '영화-배우-감독' 관계 등 더 복잡한 그래프를 구축하여 GNN 기반 추천 모델을 만들 수 있습니다.
> - **FastAPI 연동**: 이 미니 프로젝트에서 개발한 모델을 `part_8_model_serving_with_fastapi.md`에서 배울 FastAPI를 사용해 API로 서빙하는 기능을 구현해볼 수 있습니다. 예를 들어, `GET /users/{user_id}/recommendations` 와 같은 엔드포인트를 설계할 수 있습니다.
\ No newline at end of file
...@@ -5,127 +5,149 @@ ...@@ -5,127 +5,149 @@
--- ---
<br>
> [!WARNING] > [!WARNING]
> 이 파트는 현재 준비 중입니다. 강화학습의 핵심 개념과 Gymnasium 라이브러리를 사용한 실습 코드가 추가될 예정입니다. > 이 파트는 현재 준비 중입니다. 강화학습의 핵심 개념과 Gymnasium 라이브러리를 사용한 실습 코드가 추가될 예정입니다.
## 1. 학습 목표 (Learning Objectives) <br>
이번 파트가 끝나면, 여러분은 다음을 할 수 있게 됩니다. > ## 1. 학습 목표 (Learning Objectives)
>
- 강화학습이 지도/비지도학습과 어떻게 다른지 설명할 수 있습니다. > 이번 파트가 끝나면, 여러분은 다음을 할 수 있게 됩니다.
- 에이전트, 환경, 상태, 행동, 보상 등 강화학습의 핵심 구성요소를 이해합니다. >
- 정책(Policy)과 가치 함수(Value Function)의 개념을 설명할 수 있습니다. > - 강화학습이 지도/비지도학습과 어떻게 다른지 설명할 수 있습니다.
- 강화학습이 어떤 문제들을 해결하는 데 사용될 수 있는지 이해합니다. > - 에이전트, 환경, 상태, 행동, 보상 등 강화학습의 핵심 구성요소를 이해합니다.
> - 정책(Policy)과 가치 함수(Value Function)의 개념을 설명할 수 있습니다.
## 2. 핵심 키워드 (Keywords) > - 강화학습이 어떤 문제들을 해결하는 데 사용될 수 있는지 이해합니다.
`강화학습(Reinforcement Learning)`, `에이전트(Agent)`, `환경(Environment)`, `상태(State)`, `행동(Action)`, `보상(Reward)`, `정책(Policy)`, `Q-러닝(Q-Learning)`, `Gymnasium` <br>
## 3. 도입: 보상을 통해 학습하는 모델 > ## 2. 핵심 키워드 (Keywords)
>
지금까지 우리가 배운 딥러닝(지도학습)은 '정답'이 있는 데이터를 기반으로 했습니다. '이 이미지는 고양이'라는 정답을 알려주며 학습시켰습니다. > `강화학습(Reinforcement Learning)`, `에이전트(Agent)`, `환경(Environment)`, `상태(State)`, `행동(Action)`, `보상(Reward)`, `정책(Policy)`, `Q-러닝(Q-Learning)`, `Gymnasium`
하지만 '자전거 타는 법'이나 '게임에서 이기는 법'을 배울 때를 생각해보세요. 모든 순간마다 '정답' 행동이 주어지지 않습니다. 우리는 수많은 '시행착오'를 통해 '이렇게 하니 넘어지더라(나쁜 보상)', '저렇게 하니 더 멀리 가더라(좋은 보상)'를 스스로 터득합니다. <br>
**강화학습(Reinforcement Learning, RL)**은 이처럼 '정답' 대신 **'보상(Reward)'** 이라는 신호를 통해, 주어진 환경(Environment) 속에서 보상을 최대로 얻을 수 있는 행동 전략, 즉 **정책(Policy)** 을 학습하는 패러다임입니다. > ## 3. 도입: 보상을 통해 학습하는 모델
>
![Reinforcement Learning](https://i.imgur.com/g8nN8e6.gif) > 지금까지 우리가 배운 딥러닝(지도학습)은 '정답'이 있는 데이터를 기반으로 했습니다. '이 이미지는 고양이'라는 정답을 알려주며 학습시켰습니다.
*(이미지 출처: MathWorks)* >
> 하지만 '자전거 타는 법'이나 '게임에서 이기는 법'을 배울 때를 생각해보세요. 모든 순간마다 '정답' 행동이 주어지지 않습니다. 우리는 수많은 '시행착오'를 통해 '이렇게 하니 넘어지더라(나쁜 보상)', '저렇게 하니 더 멀리 가더라(좋은 보상)'를 스스로 터득합니다.
- **에이전트 (Agent)**: 학습의 주체. 우리의 모델 (예: 게임 플레이어, 로봇) >
- **환경 (Environment)**: 에이전트가 상호작용하는 세상 (예: 게임 맵, 실제 공간) > **강화학습(Reinforcement Learning, RL)**은 이처럼 '정답' 대신 **'보상(Reward)'** 이라는 신호를 통해, 주어진 환경(Environment) 속에서 보상을 최대로 얻을 수 있는 행동 전략, 즉 **정책(Policy)** 을 학습하는 패러다임입니다.
- **상태 (State)**: 환경의 현재 상황. >
- **행동 (Action)**: 에이전트가 상태를 보고 취할 수 있는 행동. > ![Reinforcement Learning](https://i.imgur.com/g8nN8e6.gif)
- **보상 (Reward)**: 행동의 결과로 환경이 에이전트에게 주는 신호. (긍정적 또는 부정적) > *(이미지 출처: MathWorks)*
>
에이전트의 목표는 단 하나, **누적 보상을 최대화**하는 것입니다. > - **에이전트 (Agent)**: 학습의 주체. 우리의 모델 (예: 게임 플레이어, 로봇)
> - **환경 (Environment)**: 에이전트가 상호작용하는 세상 (예: 게임 맵, 실제 공간)
> - **상태 (State)**: 환경의 현재 상황.
> - **행동 (Action)**: 에이전트가 상태를 보고 취할 수 있는 행동.
> - **보상 (Reward)**: 행동의 결과로 환경이 에이전트에게 주는 신호. (긍정적 또는 부정적)
>
> 에이전트의 목표는 단 하나, **누적 보상을 최대화**하는 것입니다.
--- ---
## 4. 강화학습의 핵심 개념 <br>
- **정책 (Policy, π)**: 특정 상태에서 어떤 행동을 할지 결정하는 에이전트의 전략 또는 뇌. `π(action | state)`는 상태 `s`에서 행동 `a`를 할 확률을 의미합니다.
- **가치 함수 (Value Function, V, Q)**: 특정 상태 또는 (상태, 행동) 쌍이 미래에 얻을 것으로 예상되는 누적 보상의 기댓값. 즉, 현재 상태가 얼마나 '좋은지'를 나타냅니다.
- `V(s)`: 상태 `s`의 가치.
- `Q(s, a)`: 상태 `s`에서 행동 `a`를 했을 때의 가치.
강화학습은 이 정책과 가치 함수를 반복적으로 업데이트하며 최적의 해를 찾아갑니다. > ## 4. 강화학습의 핵심 개념
>
> - **정책 (Policy, π)**: 특정 상태에서 어떤 행동을 할지 결정하는 에이전트의 전략 또는 뇌. `π(action | state)`는 상태 `s`에서 행동 `a`를 할 확률을 의미합니다.
> - **가치 함수 (Value Function, V, Q)**: 특정 상태 또는 (상태, 행동) 쌍이 미래에 얻을 것으로 예상되는 누적 보상의 기댓값. 즉, 현재 상태가 얼마나 '좋은지'를 나타냅니다.
> - `V(s)`: 상태 `s`의 가치.
> - `Q(s, a)`: 상태 `s`에서 행동 `a`를 했을 때의 가치.
>
> 강화학습은 이 정책과 가치 함수를 반복적으로 업데이트하며 최적의 해를 찾아갑니다.
--- ---
## 5. 직접 해보기 (Hands-on Lab): (내용 추가 예정) <br>
`Gymnasium` 라이브러리를 사용하여, 간단한 게임 환경('CartPole')에서 막대가 쓰러지지 않도록 균형을 잡는 에이전트를 학습시키는 딥러닝 모델(DQN)을 만들어볼 예정입니다. > ## 5. 직접 해보기 (Hands-on Lab): (내용 추가 예정)
>
> `Gymnasium` 라이브러리를 사용하여, 간단한 게임 환경('CartPole')에서 막대가 쓰러지지 않도록 균형을 잡는 에이전트를 학습시키는 딥러닝 모델(DQN)을 만들어볼 예정입니다.
--- ---
## 6. 되짚어보기 (Summary) <br>
- **강화학습**: 정답이 아닌 '보상'을 통해 시행착오를 거쳐 학습하는 머신러닝의 한 분야입니다. > ## 6. 되짚어보기 (Summary)
- **핵심 구성요소**: **에이전트****환경** 속에서 특정 **상태**를 인식하고 **행동**을 취하면, 환경은 **보상**을 줍니다. >
- **목표**: 에이전트는 누적 보상을 최대화하는 **정책**을 학습합니다. > - **강화학습**: 정답이 아닌 '보상'을 통해 시행착오를 거쳐 학습하는 머신러닝의 한 분야입니다.
- **활용**: 게임 AI(알파고), 로봇 제어, 자율주행, 자원 최적화 등 복잡한 의사결정 문제에 널리 사용됩니다. > - **핵심 구성요소**: **에이전트**가 **환경** 속에서 특정 **상태**를 인식하고 **행동**을 취하면, 환경은 **보상**을 줍니다.
> - **목표**: 에이전트는 누적 보상을 최대화하는 **정책**을 학습합니다.
> - **활용**: 게임 AI(알파고), 로봇 제어, 자율주행, 자원 최적화 등 복잡한 의사결정 문제에 널리 사용됩니다.
--- ---
<br>
**➡️ 다음 시간: [Part 8: FastAPI를 이용한 모델 서빙](../08_model_serving_with_fastapi/part_8_model_serving_with_fastapi.md)** **➡️ 다음 시간: [Part 8: FastAPI를 이용한 모델 서빙](../08_model_serving_with_fastapi/part_8_model_serving_with_fastapi.md)**
### 참고 자료 <br>
* [OpenAI Spinning Up in Deep RL](https://spinningup.openai.com/en/latest/): 심층 강화학습에 대한 체계적인 가이드 > ### 참고 자료
* [Hugging Face Deep RL Course](https://huggingface.co/learn/deep-rl-course/unit0/introduction): 허깅페이스에서 제공하는 실습 중심의 강화학습 코스 >
> * [OpenAI Spinning Up in Deep RL](https://spinningup.openai.com/en/latest/): 심층 강화학습에 대한 체계적인 가이드
> * [Hugging Face Deep RL Course](https://huggingface.co/learn/deep-rl-course/unit0/introduction): 허깅페이스에서 제공하는 실습 중심의 강화학습 코스
--- ---
### ⚠️ What Could Go Wrong? (토론 주제) <br>
강화학습은 에이전트가 스스로 최적의 전략을 학습한다는 점에서 매력적이지만, 실제 문제에 적용하기까지는 수많은 난관을 극복해야 합니다. > ### ⚠️ What Could Go Wrong? (토론 주제)
>
1. **탐험과 활용의 딜레마 (Exploration vs. Exploitation Dilemma)** > 강화학습은 에이전트가 스스로 최적의 전략을 학습한다는 점에서 매력적이지만, 실제 문제에 적용하기까지는 수많은 난관을 극복해야 합니다.
* 에이전트가 현재까지 알아낸 최선의 방법(활용)만 고집하면 더 좋은 해결책을 찾을 기회를 놓치고, 새로운 시도(탐험)에만 집중하면 보상을 극대화하지 못합니다. 이 근본적인 딜레마를 해결하기 위한 전략(e.g., Epsilon-Greedy, UCB)들은 각각 어떤 상황에서 유리하고 불리할까요? >
* 실제 비즈니스 문제(예: 추천 시스템)에서, 사용자의 만족도를 떨어뜨릴 수 있는 '탐험'을 어느 수준까지 허용해야 할까요? 탐험의 비용과 잠재적 이득을 어떻게 정량화할 수 있을까요? > 1. **탐험과 활용의 딜레마 (Exploration vs. Exploitation Dilemma)**
> * 에이전트가 현재까지 알아낸 최선의 방법(활용)만 고집하면 더 좋은 해결책을 찾을 기회를 놓치고, 새로운 시도(탐험)에만 집중하면 보상을 극대화하지 못합니다. 이 근본적인 딜레마를 해결하기 위한 전략(e.g., Epsilon-Greedy, UCB)들은 각각 어떤 상황에서 유리하고 불리할까요?
2. **희소한 보상 문제 (Sparse Reward Problem)** > * 실제 비즈니스 문제(예: 추천 시스템)에서, 사용자의 만족도를 떨어뜨릴 수 있는 '탐험'을 어느 수준까지 허용해야 할까요? 탐험의 비용과 잠재적 이득을 어떻게 정량화할 수 있을까요?
* 체스나 바둑처럼 게임이 끝날 때만 승패라는 보상이 주어지는 경우, 수많은 중간 행동들 중 어떤 것이 승리에 기여했는지 알기 어렵습니다. 이러한 '희소한 보상' 환경에서 에이전트를 효과적으로 학습시키기 어려운 이유는 무엇일까요? >
* 이를 해결하기 위해 인위적으로 중간 보상을 설계('Reward Shaping')해주는 것은 어떤 부작용을 낳을 수 있을까요? (예: 에이전트가 보상의 허점을 파고들어 의도치 않은 행동을 학습하는 경우) > 2. **희소한 보상 문제 (Sparse Reward Problem)**
> * 체스나 바둑처럼 게임이 끝날 때만 승패라는 보상이 주어지는 경우, 수많은 중간 행동들 중 어떤 것이 승리에 기여했는지 알기 어렵습니다. 이러한 '희소한 보상' 환경에서 에이전트를 효과적으로 학습시키기 어려운 이유는 무엇일까요?
3. **시뮬레이션과 현실의 차이 (Sim2Real Gap)** > * 이를 해결하기 위해 인위적으로 중간 보상을 설계('Reward Shaping')해주는 것은 어떤 부작용을 낳을 수 있을까요? (예: 에이전트가 보상의 허점을 파고들어 의도치 않은 행동을 학습하는 경우)
* 시뮬레이션 환경에서 완벽하게 작동하도록 학습된 로봇 팔이, 실제 공장 라인에서는 미묘한 마찰력이나 조명 변화 때문에 처참하게 실패하는 'Sim2Real Gap'은 왜 발생할까요? >
* 이 간극을 줄이기 위해 시뮬레이션 환경을 최대한 현실과 비슷하게 만들려는 노력과, 오히려 환경을 무작위로 계속 바꾸어 에이전트의 강인함(Robustness)을 키우려는 'Domain Randomization' 전략 중 어느 것이 더 효과적일까요? > 3. **시뮬레이션과 현실의 차이 (Sim2Real Gap)**
> * 시뮬레이션 환경에서 완벽하게 작동하도록 학습된 로봇 팔이, 실제 공장 라인에서는 미묘한 마찰력이나 조명 변화 때문에 처참하게 실패하는 'Sim2Real Gap'은 왜 발생할까요?
4. **안전성과 예측 불가능성 (Safety and Unpredictability)** > * 이 간극을 줄이기 위해 시뮬레이션 환경을 최대한 현실과 비슷하게 만들려는 노력과, 오히려 환경을 무작위로 계속 바꾸어 에이전트의 강인함(Robustness)을 키우려는 'Domain Randomization' 전략 중 어느 것이 더 효과적일까요?
* 자율주행차가 보상을 최대로 하기 위해 위험한 추월을 학습하거나, 청소 로봇이 특정 구역을 피하도록 음(-)의 보상을 주었더니 아예 움직이지 않는 방법을 터득하는 등, RL 에이전트는 명시적으로 금지하지 않은 모든 행동을 할 수 있습니다. >
* '절대로 해서는 안 되는 행동'을 어떻게 정의하고 학습시킬 수 있을까요? 시스템의 안전을 보장하기 위한 강화학습 설계는 어떻게 접근해야 할까요? > 4. **안전성과 예측 불가능성 (Safety and Unpredictability)**
> * 자율주행차가 보상을 최대로 하기 위해 위험한 추월을 학습하거나, 청소 로봇이 특정 구역을 피하도록 음(-)의 보상을 주었더니 아예 움직이지 않는 방법을 터득하는 등, RL 에이전트는 명시적으로 금지하지 않은 모든 행동을 할 수 있습니다.
5. **샘플 비효율성 (Sample Inefficiency)** > * '절대로 해서는 안 되는 행동'을 어떻게 정의하고 학습시킬 수 있을까요? 시스템의 안전을 보장하기 위한 강화학습 설계는 어떻게 접근해야 할까요?
* 많은 강화학습 알고리즘, 특히 Model-Free 방식은 최적 정책을 배우기 위해 수백만, 수천만 번의 시행착오를 거쳐야 합니다. 현실 세계에서 이 정도의 데이터를 수집하는 것이 불가능한 경우가 많습니다. (예: 로봇이 수백만 번 넘어져야 걷는 법을 배울 수는 없음) >
* '환경 모델'을 학습하여 상호작용을 시뮬레이션하는 Model-Based RL은 이 문제를 어떻게 완화하며, 그 접근법의 근본적인 한계(예: 모델이 부정확할 경우의 성능 저하)는 무엇일까요? > 5. **샘플 비효율성 (Sample Inefficiency)**
> * 많은 강화학습 알고리즘, 특히 Model-Free 방식은 최적 정책을 배우기 위해 수백만, 수천만 번의 시행착오를 거쳐야 합니다. 현실 세계에서 이 정도의 데이터를 수집하는 것이 불가능한 경우가 많습니다. (예: 로봇이 수백만 번 넘어져야 걷는 법을 배울 수는 없음)
> * '환경 모델'을 학습하여 상호작용을 시뮬레이션하는 Model-Based RL은 이 문제를 어떻게 완화하며, 그 접근법의 근본적인 한계(예: 모델이 부정확할 경우의 성능 저하)는 무엇일까요?
--- ---
## 캡스톤 프로젝트 연계 미니 프로젝트: 게임 AI 에이전트 훈련시키기 <br>
강화학습의 핵심은 '최적의 의사결정'을 찾는 것입니다. 15장 캡스톤 프로젝트에서 자원 관리, 추천 순서 최적화, 자율 에이전트 등 동적인 시스템을 구상하고 있다면, 강화학습은 강력한 무기가 될 수 있습니다. 이번 미니 프로젝트에서는 `Gymnasium` 라이브러리를 사용해 간단한 게임 환경 속에서 스스로 학습하고 성장하는 AI 에이전트를 만들며 강화학습의 원리를 체득합니다. > ## 캡스톤 프로젝트 연계 미니 프로젝트: 게임 AI 에이전트 훈련시키기
>
### 프로젝트 목표 > 강화학습의 핵심은 '최적의 의사결정'을 찾는 것입니다. 15장 캡스톤 프로젝트에서 자원 관리, 추천 순서 최적화, 자율 에이전트 등 동적인 시스템을 구상하고 있다면, 강화학습은 강력한 무기가 될 수 있습니다. 이번 미니 프로젝트에서는 `Gymnasium` 라이브러리를 사용해 간단한 게임 환경 속에서 스스로 학습하고 성장하는 AI 에이전트를 만들며 강화학습의 원리를 체득합니다.
- `Gymnasium` 라이브러리를 사용하여 'LunarLander-v2' 환경을 설정하고 이해합니다. >
- DQN(Deep Q-Network) 알고리즘의 기본 아이디어를 이해하고, `stable-baselines3`와 같은 라이브러리를 사용해 에이전트를 학습시킵니다. > ### 프로젝트 목표
- 학습된 에이전트가 게임을 플레이하는 과정을 시각화하고, 학습 전후의 성능을 '누적 보상'으로 비교 분석합니다. > - `Gymnasium` 라이브러리를 사용하여 'LunarLander-v2' 환경을 설정하고 이해합니다.
> - DQN(Deep Q-Network) 알고리즘의 기본 아이디어를 이해하고, `stable-baselines3`와 같은 라이브러리를 사용해 에이전트를 학습시킵니다.
### 개발 과정 > - 학습된 에이전트가 게임을 플레이하는 과정을 시각화하고, 학습 전후의 성능을 '누적 보상'으로 비교 분석합니다.
1. **환경 설정**: `pip install gymnasium[box2d] stable-baselines3[extra]` 명령어로 필요한 라이브러리를 설치합니다. >
2. **에이전트 학습**: > ### 개발 과정
- `stable-baselines3` 라이브러리의 `DQN` 모델을 불러옵니다. > 1. **환경 설정**: `pip install gymnasium[box2d] stable-baselines3[extra]` 명령어로 필요한 라이브러리를 설치합니다.
- 'LunarLander-v2' 환경을 생성하고, 모델에 환경을 지정하여 학습을 시작합니다. (`model.learn(total_timesteps=100000)`) > 2. **에이전트 학습**:
- 학습된 모델을 저장합니다. > - `stable-baselines3` 라이브러리의 `DQN` 모델을 불러옵니다.
3. **성능 평가 및 시각화**: > - 'LunarLander-v2' 환경을 생성하고, 모델에 환경을 지정하여 학습을 시작합니다. (`model.learn(total_timesteps=100000)`)
- 학습된 모델을 불러와, 렌더링 모드로 환경을 실행하여 에이전트가 어떻게 우주선을 착륙시키는지 직접 관찰합니다. > - 학습된 모델을 저장합니다.
- 학습하지 않은 무작위 에이전트의 평균 누적 보상과, 학습된 에이전트의 평균 누적 보상을 비교하여 성능 향상을 수치적으로 확인합니다. > 3. **성능 평가 및 시각화**:
4. **결과 해석 및 활용**: > - 학습된 모델을 불러와, 렌더링 모드로 환경을 실행하여 에이전트가 어떻게 우주선을 착륙시키는지 직접 관찰합니다.
- 에이전트는 어떤 전략(Policy)을 학습했을까요? (예: 특정 상황에서 어떤 엔진을 분사하는가) > - 학습하지 않은 무작위 에이전트의 평균 누적 보상과, 학습된 에이전트의 평균 누적 보상을 비교하여 성능 향상을 수치적으로 확인합니다.
- 학습의 '보상'을 어떻게 설계하는지에 따라 에이전트의 행동이 어떻게 달라질지 토론해봅니다. > 4. **결과 해석 및 활용**:
> - 에이전트는 어떤 전략(Policy)을 학습했을까요? (예: 특정 상황에서 어떤 엔진을 분사하는가)
### 캡스톤 프로젝트 연계 방안 > - 학습의 '보상'을 어떻게 설계하는지에 따라 에이전트의 행동이 어떻게 달라질지 토론해봅니다.
- **커스텀 환경 제작**: 캡스톤 프로젝트의 주제에 맞춰 `Gymnasium``Env` 클래스를 상속받아 '나만의 강화학습 환경'을 직접 만들어볼 수 있습니다. 예를 들어, '웹사이트 광고 배치 최적화' 환경을 만들고, '광고 클릭 수'를 보상으로 설정하여 최적의 광고 배치 전략을 학습하는 에이전트를 개발할 수 있습니다. >
- **금융 트레이딩 봇**: 주가 데이터를 상태로, '매수/매도/보유'를 행동으로, '수익률'을 보상으로 하는 환경을 설계하여, 시장 상황에 맞춰 최적의 투자를 수행하는 트레이딩 봇을 강화학습으로 개발할 수 있습니다. > ### 캡스톤 프로젝트 연계 방안
- **자율 에이전트**: `LangChain`의 'Agent' 개념과 강화학습을 결합하여, 특정 목표(예: '최신 AI 논문 3개 요약하기')를 달성하기 위해 스스로 웹 검색, 코드 실행 등의 도구를 선택하고 사용하는 고차원적인 자율 에이전트를 구상해볼 수 있습니다. > - **커스텀 환경 제작**: 캡스톤 프로젝트의 주제에 맞춰 `Gymnasium`의 `Env` 클래스를 상속받아 '나만의 강화학습 환경'을 직접 만들어볼 수 있습니다. 예를 들어, '웹사이트 광고 배치 최적화' 환경을 만들고, '광고 클릭 수'를 보상으로 설정하여 최적의 광고 배치 전략을 학습하는 에이전트를 개발할 수 있습니다.
\ No newline at end of file > - **금융 트레이딩 봇**: 주가 데이터를 상태로, '매수/매도/보유'를 행동으로, '수익률'을 보상으로 하는 환경을 설계하여, 시장 상황에 맞춰 최적의 투자를 수행하는 트레이딩 봇을 강화학습으로 개발할 수 있습니다.
> - **자율 에이전트**: `LangChain`의 'Agent' 개념과 강화학습을 결합하여, 특정 목표(예: '최신 AI 논문 3개 요약하기')를 달성하기 위해 스스로 웹 검색, 코드 실행 등의 도구를 선택하고 사용하는 고차원적인 자율 에이전트를 구상해볼 수 있습니다.
\ No newline at end of file
...@@ -5,62 +5,70 @@ ...@@ -5,62 +5,70 @@
--- ---
## 1. 학습 목표 (Learning Objectives) <br>
이번 파트가 끝나면, 여러분은 다음을 할 수 있게 됩니다. > ## 1. 학습 목표 (Learning Objectives)
>
- 딥러닝과 머신러닝의 차이점을 설명하고, PyTorch의 역할을 이해할 수 있습니다. > 이번 파트가 끝나면, 여러분은 다음을 할 수 있게 됩니다.
- PyTorch `Tensor`를 다루고, `nn.Module`을 상속받아 직접 인공 신경망 모델을 설계할 수 있습니다. >
- 손실 함수, 옵티마이저의 역할을 이해하고, 딥러닝의 핵심인 학습 루프(Training Loop)를 구현할 수 있습니다. > - 딥러닝과 머신러닝의 차이점을 설명하고, PyTorch의 역할을 이해할 수 있습니다.
- 순전파(Forward Propagation)와 역전파(Backward Propagation)의 기본 개념을 설명할 수 있습니다. > - PyTorch `Tensor`를 다루고, `nn.Module`을 상속받아 직접 인공 신경망 모델을 설계할 수 있습니다.
- `torchvision`을 사용하여 표준 데이터셋(MNIST)을 불러오고, 간단한 CNN 모델을 만들어 이미지 분류 문제를 해결할 수 있습니다. > - 손실 함수, 옵티마이저의 역할을 이해하고, 딥러닝의 핵심인 학습 루프(Training Loop)를 구현할 수 있습니다.
> - 순전파(Forward Propagation)와 역전파(Backward Propagation)의 기본 개념을 설명할 수 있습니다.
## 핵심 요약 (Key takeaways) > - `torchvision`을 사용하여 표준 데이터셋(MNIST)을 불러오고, 간단한 CNN 모델을 만들어 이미지 분류 문제를 해결할 수 있습니다.
딥러닝은 Scikit-learn과 달리 PyTorch와 같은 '조립 키트'를 사용하여 모델을 직접 설계합니다. 데이터의 기본 단위인 텐서(Tensor)를 다루고, `nn.Module`을 상속받아 신경망을 구성합니다. 학습은 모델의 예측(순전파)과 실제 값의 오차를 계산(손실 함수)하고, 이 오차를 기반으로 파라미터를 조정(옵티마이저, 역전파)하는 과정을 반복(학습 루프)하는 것입니다. 이 과정을 통해 MNIST 같은 이미지 데이터를 분류하는 CNN 모델까지 구현할 수 있습니다.
## 3. 도입: 모델을 직접 조립하는 즐거움, PyTorch (Introduction)
드디어 딥러닝의 세계에 입문합니다. 지난 시간까지 우리는 Scikit-learn이라는 강력한 '완성품'을 사용했다면, 이제부터는 **PyTorch**라는 '조립 키트'를 사용하여 우리만의 모델을 직접 만들어 볼 것입니다.
> **💡 비유: PyTorch는 '레고 블록', Scikit-learn은 '완성된 장난감'**
> - **Scikit-learn**: '트럭', '비행기'처럼 이미 완성된 모델을 가져와 사용하는 **'완성품 장난감'**과 같습니다. 사용하기 편리하고 대부분의 정형 데이터 문제에 효과적입니다.
> - **PyTorch**: 다양한 모양의 **'레고 블록'**을 제공하여, 사용자가 원하는 어떤 복잡한 구조(신경망)라도 직접 조립할 수 있게 해줍니다. 이미지, 텍스트 등 비정형 데이터를 다루는 딥러닝에 필수적이며, 연구와 산업 현장에서 가장 널리 쓰이는 도구 중 하나입니다.
### 3.1. 왜 딥러닝인가? 머신러닝의 한계와 표현 학습
그렇다면 왜 Scikit-learn의 편리한 모델들을 두고, 굳이 복잡하게 신경망을 직접 조립해야 할까요? 이는 전통적인 머신러닝이 **비정형 데이터(이미지, 텍스트, 음성 등)**를 다루는 데 명확한 한계를 가지고 있기 때문입니다.
- **전통적인 머신러닝의 한계: 수동 특징 공학 (Manual Feature Engineering)** <br>
- 머신러닝 모델이 좋은 성능을 내기 위해서는, 데이터의 특성을 잘 나타내는 '특징(Feature)'을 사람이 직접 설계하고 추출해야 했습니다. 예를 들어, 고양이 사진을 분류하기 위해 '귀가 뾰족한가?', '수염이 있는가?'와 같은 특징을 코드로 구현해야 했습니다. 이 과정은 매우 어렵고, 많은 시간과 도메인 지식이 필요하며, 데이터가 복잡해질수록 사실상 불가능에 가깝습니다.
- **딥러닝의 혁신: 표현 학습 (Representation Learning)** > ## 2. 핵심 요약 (Key Summary)
- 딥러닝은 이 **특징 추출 과정을 자동화**합니다. 개발자는 모델의 큰 구조만 설계하고 데이터를 보여주기만 하면, 모델이 데이터로부터 직접 문제 해결에 필요한 특징들을 **스스로 학습**합니다. 이것이 바로 **표현 학습**입니다. >
- 딥러닝 모델의 '깊은(deep)' 여러 계층들은, 데이터의 원초적인 형태(픽셀, 단어)로부터 시작하여 점차 더 복잡하고 추상적인 특징(선 -> 형태 -> 객체)을 학습해 나갑니다. > 딥러닝은 Scikit-learn과 달리 PyTorch와 같은 '조립 키트'를 사용하여 모델을 직접 설계합니다. 데이터의 기본 단위인 텐서(Tensor)를 다루고, `nn.Module`을 상속받아 신경망을 구성합니다. 학습은 모델의 예측(순전파)과 실제 값의 오차를 계산(손실 함수)하고, 이 오차를 기반으로 파라미터를 조정(옵티마이저, 역전파)하는 과정을 반복(학습 루프)하는 것입니다. 이 과정을 통해 MNIST 같은 이미지 데이터를 분류하는 CNN 모델까지 구현할 수 있습니다.
![ML vs DL](https://i.imgur.com/x0G3R9a.png) <br>
> [!TIP] > ## 3. 도입: 모델을 직접 조립하는 즐거움, PyTorch (Introduction)
> 본 파트의 모든 예제 코드는 `../../source_code/part_7_deep_learning.py` 파일에서 직접 실행하고 수정해볼 수 있습니다. >
> 드디어 딥러닝의 세계에 입문합니다. 지난 시간까지 우리는 Scikit-learn이라는 강력한 '완성품'을 사용했다면, 이제부터는 **PyTorch**라는 '조립 키트'를 사용하여 우리만의 모델을 직접 만들어 볼 것입니다.
>
> > [!NOTE] 비유: PyTorch는 '레고 블록', Scikit-learn은 '완성된 장난감'
> > - **Scikit-learn**: '트럭', '비행기'처럼 이미 완성된 모델을 가져와 사용하는 **'완성품 장난감'**과 같습니다. 사용하기 편리하고 대부분의 정형 데이터 문제에 효과적입니다.
> > - **PyTorch**: 다양한 모양의 **'레고 블록'**을 제공하여, 사용자가 원하는 어떤 복잡한 구조(신경망)라도 직접 조립할 수 있게 해줍니다. 이미지, 텍스트 등 비정형 데이터를 다루는 딥러닝에 필수적이며, 연구와 산업 현장에서 가장 널리 쓰이는 도구 중 하나입니다.
>
> ### 3.1. 왜 딥러닝인가? 머신러닝의 한계와 표현 학습
>
> 그렇다면 왜 Scikit-learn의 편리한 모델들을 두고, 굳이 복잡하게 신경망을 직접 조립해야 할까요? 이는 전통적인 머신러닝이 **비정형 데이터(이미지, 텍스트, 음성 등)**를 다루는 데 명확한 한계를 가지고 있기 때문입니다.
>
> - **전통적인 머신러닝의 한계: 수동 특징 공학 (Manual Feature Engineering)**
> - 머신러닝 모델이 좋은 성능을 내기 위해서는, 데이터의 특성을 잘 나타내는 '특징(Feature)'을 사람이 직접 설계하고 추출해야 했습니다. 예를 들어, 고양이 사진을 분류하기 위해 '귀가 뾰족한가?', '수염이 있는가?'와 같은 특징을 코드로 구현해야 했습니다. 이 과정은 매우 어렵고, 많은 시간과 도메인 지식이 필요하며, 데이터가 복잡해질수록 사실상 불가능에 가깝습니다.
>
> - **딥러닝의 혁신: 표현 학습 (Representation Learning)**
> - 딥러닝은 이 **특징 추출 과정을 자동화**합니다. 개발자는 모델의 큰 구조만 설계하고 데이터를 보여주기만 하면, 모델이 데이터로부터 직접 문제 해결에 필요한 특징들을 **스스로 학습**합니다. 이것이 바로 **표현 학습**입니다.
> - 딥러닝 모델의 '깊은(deep)' 여러 계층들은, 데이터의 원초적인 형태(픽셀, 단어)로부터 시작하여 점차 더 복잡하고 추상적인 특징(선 -> 형태 -> 객체)을 학습해 나갑니다.
>
> ![ML vs DL](https://i.imgur.com/x0G3R9a.png)
>
> > [!TIP]
> > 본 파트의 모든 예제 코드는 `../../source_code/part_7_deep_learning.py` 파일에서 직접 실행하고 수정해볼 수 있습니다.
--- ---
## 4. PyTorch 딥러닝의 기본 구성 요소 <br>
> **🎯 1-2일차 목표:** PyTorch의 텐서를 이해하고, 인공 신경망의 기본 구조를 코드로 구현합니다.
### 4-1. 딥러닝의 데이터, 텐서(Tensor)
- **텐서**: PyTorch에서 데이터를 다루는 기본 단위입니다. NumPy의 `ndarray`와 매우 유사하지만, 두 가지 결정적인 차이가 있습니다.
1. **GPU 가속**: `.to('cuda')` 코드 한 줄로 GPU를 사용한 초고속 연산이 가능합니다.
2. **자동 미분(Autograd)**: 딥러닝 학습의 핵심인 '역전파'를 위해 자동으로 미분값을 계산해줍니다.
### 4-2. 인공 신경망(ANN)과 다층 퍼셉트론(MLP) 모델 만들기
PyTorch에서는 `torch.nn.Module`을 상속받아 우리만의 신경망 클래스(레고 조립 설명서)를 정의합니다. 가장 기본적이면서도 강력한 신경망 구조 중 하나는 바로 **다층 퍼셉트론(Multi-Layer Perceptron, MLP)** 입니다. 아래 `SimpleNet` 예제가 바로 MLP의 간단한 구현체입니다.
- **`__init__(self)`**: 모델에 필요한 레고 블록들(레이어)을 정의하는 곳.
- **`forward(self, x)`**: 레고 블록들을 어떤 순서로 조립할지(데이터 흐름) 정의하는 곳.
```python > ## 4. PyTorch 딥러닝의 기본 구성 요소
>
> > **🎯 1-2일차 목표:** PyTorch의 텐서를 이해하고, 인공 신경망의 기본 구조를 코드로 구현합니다.
>
> ### 4-1. 딥러닝의 데이터, 텐서(Tensor)
> - **텐서**: PyTorch에서 데이터를 다루는 기본 단위입니다. NumPy의 `ndarray`와 매우 유사하지만, 두 가지 결정적인 차이가 있습니다.
> 1. **GPU 가속**: `.to('cuda')` 코드 한 줄로 GPU를 사용한 초고속 연산이 가능합니다.
> 2. **자동 미분(Autograd)**: 딥러닝 학습의 핵심인 '역전파'를 위해 자동으로 미분값을 계산해줍니다.
>
> ### 4-2. 인공 신경망(ANN)과 다층 퍼셉트론(MLP) 모델 만들기
> PyTorch에서는 `torch.nn.Module`을 상속받아 우리만의 신경망 클래스(레고 조립 설명서)를 정의합니다. 가장 기본적이면서도 강력한 신경망 구조 중 하나는 바로 **다층 퍼셉트론(Multi-Layer Perceptron, MLP)** 입니다. 아래 `SimpleNet` 예제가 바로 MLP의 간단한 구현체입니다.
>
> - **`__init__(self)`**: 모델에 필요한 레고 블록들(레이어)을 정의하는 곳.
> - **`forward(self, x)`**: 레고 블록들을 어떤 순서로 조립할지(데이터 흐름) 정의하는 곳.
>
> ```python
import torch import torch
import torch.nn as nn import torch.nn as nn
...@@ -83,6 +91,7 @@ class SimpleNet(nn.Module): ...@@ -83,6 +91,7 @@ class SimpleNet(nn.Module):
model = SimpleNet(input_size=784, hidden_size=500, num_classes=10) # MNIST 예시 model = SimpleNet(input_size=784, hidden_size=500, num_classes=10) # MNIST 예시
print(model) print(model)
``` ```
>
> ### 심화: 활성화 함수, 필요한가? (Deep Dive: Activation Functions) > ### 심화: 활성화 함수, 필요한가? (Deep Dive: Activation Functions)
> >
> **Q: 굳이 `ReLU` 같은 활성화 함수를 중간에 삽입해야 할까요? 선형 계층(`nn.Linear`) 여러 쌓으면 간단하지 않을까요?** > **Q: 굳이 `ReLU` 같은 활성화 함수를 중간에 삽입해야 할까요? 선형 계층(`nn.Linear`) 여러 쌓으면 간단하지 않을까요?**
...@@ -100,11 +109,12 @@ print(model) ...@@ -100,11 +109,12 @@ print(model)
> | **Tanh** | `(e^x - e^-x) / (e^x + e^-x)`<br>출력을 (-1, 1) 사이로 압축 | 출력의 중심이 0 (Sigmoid 단점 보완) | **Vanishing Gradient** 문제 여전히 존재 | RNN 은닉층에서 종종 사용 | > | **Tanh** | `(e^x - e^-x) / (e^x + e^-x)`<br>출력을 (-1, 1) 사이로 압축 | 출력의 중심이 0 (Sigmoid 단점 보완) | **Vanishing Gradient** 문제 여전히 존재 | RNN 은닉층에서 종종 사용 |
> | **ReLU** | `max(0, x)`<br>입력이 0보다 작으면 0, 크면 그대로 출력 | 계산이 매우 빠름<br>Vanishing Gradient 문제 해결 | **Dying ReLU** 문제 (입력이 음수면 뉴런이 죽음) | 대부분의 딥러닝 모델의 은닉층 (가장 대중적) | > | **ReLU** | `max(0, x)`<br>입력이 0보다 작으면 0, 크면 그대로 출력 | 계산이 매우 빠름<br>Vanishing Gradient 문제 해결 | **Dying ReLU** 문제 (입력이 음수면 뉴런이 죽음) | 대부분의 딥러닝 모델의 은닉층 (가장 대중적) |
> | **Leaky ReLU** | `max(α*x, x)` (α는 작은 , : 0.01)<br>ReLU 변형 | Dying ReLU 문제 해결 | α 값을 직접 설정해야 | ReLU 대신 사용해볼 있는 대안 | > | **Leaky ReLU** | `max(α*x, x)` (α는 작은 , : 0.01)<br>ReLU 변형 | Dying ReLU 문제 해결 | α 값을 직접 설정해야 | ReLU 대신 사용해볼 있는 대안 |
>| **Softmax** | `e^zi / Σ(e^zj)`<br>다중 클래스 분류의 출력을 확률 분포로 변환 | 각 클래스에 대한 확률을 직관적으로 보여줌 | - | 다중 클래스 분류 문제의 출력층 | > | **Softmax** | `e^zi / Σ(e^zj)`<br>다중 클래스 분류의 출력을 확률 분포로 변환 | 클래스에 대한 확률을 직관적으로 보여줌 | - | 다중 클래스 분류 문제의 출력층 |
>
> ---
> ---
> <br>
> ## 5. 딥러닝 모델 학습 과정 > ## 5. 딥러닝 모델 학습 과정
> >
> > **🎯 3-4일차 목표:** 손실 함수, 옵티마이저의 개념을 이해하고 전체 학습 루프를 구현합니다. > > **🎯 3-4일차 목표:** 손실 함수, 옵티마이저의 개념을 이해하고 전체 학습 루프를 구현합니다.
...@@ -167,7 +177,7 @@ print(model) ...@@ -167,7 +177,7 @@ print(model)
> 4. **`loss.backward()`**: 계산된 오차를 기반으로, 파라미터가 오차에 얼마나 기여했는지 미분값을 계산합니다 (**역전파**). > 4. **`loss.backward()`**: 계산된 오차를 기반으로, 파라미터가 오차에 얼마나 기여했는지 미분값을 계산합니다 (**역전파**).
> 5. **`optimizer.step()`**: 계산된 미분값을 바탕으로 모델의 파라미터를 업데이트하여 오차를 줄이는 방향으로 나아갑니다. > 5. **`optimizer.step()`**: 계산된 미분값을 바탕으로 모델의 파라미터를 업데이트하여 오차를 줄이는 방향으로 나아갑니다.
> >
> > **💡 순전파와 역전파 (Forward & Backward Propagation)** > > [!NOTE] 순전파와 역전파 (Forward & Backward Propagation)
> > - **순전파 (Forward)**: 내가 만든 레시피로 요리를 해서(모델 예측) 손님에게 내놓는 과정. > > - **순전파 (Forward)**: 내가 만든 레시피로 요리를 해서(모델 예측) 손님에게 내놓는 과정.
> > - **역전파 (Backward)**: 손님의 피드백("너무 짜요!") 듣고, 소금을 얼마나 넣었는지, 간장을 얼마나 넣었는지 원인을 **연쇄 법칙(Chain Rule)** 따라 거슬러 올라가 재료(파라미터) '책임' 계산하는 과정. `optimizer.step()` 분석을 바탕으로 다음 요리에서는 소금을 넣는 행동입니다. > > - **역전파 (Backward)**: 손님의 피드백("너무 짜요!") 듣고, 소금을 얼마나 넣었는지, 간장을 얼마나 넣었는지 원인을 **연쇄 법칙(Chain Rule)** 따라 거슬러 올라가 재료(파라미터) '책임' 계산하는 과정. `optimizer.step()` 분석을 바탕으로 다음 요리에서는 소금을 넣는 행동입니다.
> >
...@@ -200,336 +210,114 @@ print(model) ...@@ -200,336 +210,114 @@ print(model)
> > `model.train()` `model.eval()` 모드를 반드시 전환해주어야 합니다. > > `model.train()` `model.eval()` 모드를 반드시 전환해주어야 합니다.
> > - `model.train()`: 드롭아웃과 배치 정규화를 **활성화**합니다. > > - `model.train()`: 드롭아웃과 배치 정규화를 **활성화**합니다.
> > - `model.eval()`: 드롭아웃과 배치 정규화를 **비활성화**하고, 학습 과정에서 계산해둔 전체 데이터의 통계량을 사용하여 일관된 출력을 보장합니다. 검증 추론 시에는 반드시 `eval()` 모드를 사용해야 합니다. > > - `model.eval()`: 드롭아웃과 배치 정규화를 **비활성화**하고, 학습 과정에서 계산해둔 전체 데이터의 통계량을 사용하여 일관된 출력을 보장합니다. 검증 추론 시에는 반드시 `eval()` 모드를 사용해야 합니다.
---
<br>
> ## 6. 연습 문제: MNIST 손글씨 분류
> >
> ---
>
> ## 연습 문제: MNIST 손글씨 분류
> > **🎯 5일차 목표:** PyTorch 사용하여 딥러닝의 "Hello, World!" MNIST 손글씨 분류기를 직접 만듭니다. > > **🎯 5일차 목표:** PyTorch 사용하여 딥러닝의 "Hello, World!" MNIST 손글씨 분류기를 직접 만듭니다.
> >
> ### 문제: > ### 문제:
> `torchvision` 사용하여 MNIST 데이터셋을 불러오고, 간단한 CNN(합성곱 신경망) 모델을 구축하여 손글씨 숫자를 분류하는 전체 코드를 완성하세요. > `torchvision` 사용하여 MNIST 데이터셋을 불러오고, 간단한 CNN(합성곱 신경망) 모델을 구축하여 손글씨 숫자를 분류하는 전체 코드를 완성하세요.
> >
> ```python > ```python
> import torch
> import torch.nn as nn
> import torchvision
> import torchvision.transforms as transforms
> from torch.utils.data import DataLoader
>
> # 1. 데이터셋 및 로더 준비
> transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
> train_dataset = torchvision.datasets.MNIST(root='./data', train=True, transform=transform, download=True)
> test_dataset = torchvision.datasets.MNIST(root='./data', train=False, transform=transform)
> train_loader = DataLoader(dataset=train_dataset, batch_size=64, shuffle=True)
> test_loader = DataLoader(dataset=test_dataset, batch_size=64, shuffle=False)
>
> # 2. CNN 모델 정의
> class ConvNet(nn.Module):
> def __init__(self):
> super(ConvNet, self).__init__()
> self.layer1 = nn.Sequential(
> nn.Conv2d(1, 32, kernel_size=5, stride=1, padding=2),
> nn.ReLU(),
> nn.MaxPool2d(kernel_size=2, stride=2))
> self.layer2 = nn.Sequential(
> nn.Conv2d(32, 64, kernel_size=5, stride=1, padding=2),
> nn.ReLU(),
> nn.MaxPool2d(kernel_size=2, stride=2))
> self.fc = nn.Linear(7*7*64, 10)
>
> def forward(self, x):
> out = self.layer1(x)
> out = self.layer2(out)
> out = out.reshape(out.size(0), -1) # Flatten
> out = self.fc(out)
> return out
>
> # 3. 모델, 손실함수, 옵티마이저 설정
> device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
> model = ConvNet().to(device)
> criterion = nn.CrossEntropyLoss()
> optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
>
> # 4. 학습 루프 구현
> # model.train() 모드 설정
> # for epoch ...
> # for i, (images, labels) in enumerate(train_loader):
> # - images, labels를 device로 이동
> # - 옵티마이저 그래디언트 초기화
> # - 순전파, 손실 계산, 역전파, 파라미터 업데이트 코드 작성
> #
> # 5. 평가 루프 구현
> # model.eval() 모드 설정
> # with torch.no_grad():
> # for images, labels in test_loader:
> # - 정확도 계산 코드 작성
>
> ### 6-1. 심화: 주요 CNN 아키텍처의 발전사
> 간단한 CNN 모델을 직접 만들어본 지금, 딥러닝 역사에 한 획을 그은 주요 CNN 아키텍처들이 어떻게 발전해왔는지 살펴보는 것은 매우 의미 있는 일입니다. 각 모델이 어떤 문제를 해결하려 했고, 어떤 아이디어를 제시했는지 이해하면 더 깊이 있는 모델을 설계하는 데 도움이 될 것입니다.
>
| 모델명 | 발표 연도 | 주요 특징 및 기여 | 주요 사용처 및 선택 가이드 |
|---|---|---|---|
| **LeNet-5** | 1998 | LeCun 교수가 제안. 최초의 성공적인 CNN. `Conv`-`Pool`-`Conv`-`Pool`-`FC` 구조의 기반을 마련. | **학습용/기본 CNN 구조 이해**: CNN의 기본 동작 원리를 학습하고 간단한 분류 문제를 해결할 때 좋습니다. 현대적인 문제에 직접 사용하기에는 성능이 부족합니다. |
| **AlexNet** | 2012 | 이미지넷(ILSVRC) 챌린지에서 압도적 성능으로 우승하며 **딥러닝의 부흥**을 이끌었다. **ReLU**, **Dropout**, **GPU 활용** 등 현재까지도 널리 쓰이는 기법들을 대거 도입했다. | **성능 개선의 출발점**: LeNet보다 복잡한 문제에 적용 가능. 딥러닝 모델의 성능을 어떻게 개선하는지에 대한 아이디어(활성화 함수, 규제)를 얻고 싶을 때 분석해볼 만합니다. |
| **VGGNet** | 2014 | **3x3의 작은 커널**을 여러 겹 깊게 쌓는 단순하지만 효과적인 구조를 제시. 깊이(Depth)가 성능에 미치는 영향을 증명했다. | **전이 학습(Transfer Learning)의 베이스라인**: 구조가 단순하고 특징 추출 능력이 우수하여, 사전 훈련된 모델을 다른 이미지 문제에 적용하는 전이 학습의 베이스라인으로 널리 사용됩니다. |
| **GoogLeNet** | 2014 | **인셉션 모듈(Inception Module)**을 도입하여, 여러 크기의 커널을 병렬로 사용함으로써 연산 효율성과 성능을 동시에 잡았다. **파라미터 수를 줄이는 데** 집중했다. | **연산량/메모리가 제한된 환경**: 모바일 기기나 임베디드 시스템처럼 계산 비용에 민감한 환경에서 높은 성능을 내야 할 때 우선적으로 고려됩니다. |
| **ResNet** | 2015 | **잔차 학습(Residual Learning)****스킵 연결(Skip Connection)**이라는 혁신적인 아이디어로 100층이 넘는 **매우 깊은 신경망**의 학습을 가능하게 했다. **Vanishing Gradient 문제를 해결**하며 딥러닝의 한계를 돌파했다. | **대부분의 컴퓨터 비전 문제의 표준**: 현재까지도 이미지 분류, 객체 탐지, 세그멘테이션 등 다양한 컴퓨터 비전 문제에서 매우 강력한 '기본/표준' 모델로 사용됩니다. |
>
> #### 1. LeNet-5: CNN의 서막
> - Yann LeCun 교수가 제안한 모델로, 현대적인 CNN 구조(합성곱 층과 풀링 층의 반복, 마지막에 완전 연결 계층)의 청사진을 제시했습니다. 당시에는 손글씨 숫자 인식과 같은 제한된 문제에서 큰 성공을 거두었습니다.
>
> #### 2. AlexNet: 딥러닝의 폭발
> - 2012년 이미지넷 분류 챌린지에서 전통적인 컴퓨터 비전 기법들을 압도적인 성능 차이로 이기고 우승하며, AI 커뮤니티에 엄청난 충격을 주었습니다. 딥러닝이 학계를 넘어 산업계의 주류 기술로 발돋움하는 결정적인 계기가 되었습니다.
> - **주요 기여**:
> - **ReLU 활성화 함수**: Sigmoid/Tanh의 Vanishing Gradient 문제를 해결하고 학습 속도를 크게 향상시켰습니다.
> - **Dropout**: 학습 시 일부 뉴런을 무작위로 비활성화하여 과적합을 방지하는 효과적인 규제(Regularization) 기법을 제시했습니다.
> - **GPU 활용**: 2개의 GPU를 병렬로 사용하여 대규모 연산을 효율적으로 처리하며 딥러닝의 대중화를 이끌었습니다.
>
> #### 3. VGGNet: 깊고 단순함의 미학
> - "더 깊게 쌓으면 성능이 좋아질까?"라는 단순한 질문에서 출발했습니다.
> - **주요 기여**:
> - **3x3 합성곱 필터**: 큰 크기(예: 5x5, 7x7)의 필터를 사용하는 대신, 3x3의 작은 필터를 여러 개 연속으로 사용하여 동일한 Receptive Field를 가지면서도 파라미터 수를 줄이고 비선형성을 증가시켰습니다.
> - **균일한 구조**: VGG-16, VGG-19 등 깊이만 다른 균일한 구조를 제시하여 모델 설계의 단순함을 보여주었습니다.
>
> #### 4. GoogLeNet (Inception): 효율적인 깊이의 추구
> - VGGNet처럼 무작정 깊게 쌓는 것이 아니라, "어떻게 하면 연산 자원을 효율적으로 사용하면서 성능을 높일 수 있을까?"를 고민했습니다.
> - **주요 기여**:
> - **인셉션 모듈(Inception Module)**: 1x1, 3x3, 5x5 합성곱과 3x3 풀링을 하나의 블록 안에서 병렬로 처리하고 그 결과를 합칩니다. 이를 통해 모델이 다양한 스케일의 특징을 동시에 학습할 수 있게 됩니다.
> - **1x1 Convolution 활용**: 채널(Channel) 수를 줄여(BottleNeck) 전체 연산량을 획기적으로 감소시켜 성능은 유지하거나 향상시켰습니다.
>
> #### 5. ResNet: 깊이의 한계를 넘어서
> - 네트워크가 깊어질수록 오히려 학습이 더 어려워지고 성능이 저하되는 **퇴화(Degradation) 문제**가 발생했습니다. 이는 Vanishing/Exploding Gradient와는 다른 현상으로, 깊은 망이 얕은 망보다 학습하기 더 어렵다는 문제였습니다.
> - **주요 기여**:
> - **잔차 학습(Residual Learning)**: 층이 입력값 `x`를 `H(x)`로 직접 변환하도록 학습하는 대신, **변화량(Residual), 즉 `F(x) = H(x) - x`**를 학습하도록 구조를 바꿨습니다.
> - **스킵 연결(Skip Connection)**: 입력 `x`를 몇 개의 층을 건너뛰어 출력에 그대로 더해주는 `H(x) = F(x) + x` 구조입니다. 이 간단한 '지름길'을 통해 그래디언트가 깊은 층까지 소실되지 않고 잘 흘러갈 수 있게 되어, 152층이라는 전례 없는 깊이의 네트워크 학습을 성공시켰습니다. ResNet의 등장은 이후 수많은 딥러닝 아키텍처에 지대한 영향을 미쳤습니다.
>
> ### 6-2. 실제 기업 적용 사례 (Real-world Enterprise Use Cases)
>
> 앞서 살펴본 CNN 아키텍처들의 발전은 오늘날 다양한 산업 분야에서 AI 혁신을 이끄는 밑거름이 되었습니다. 딥러닝 기술이 실제 비즈니스 문제를 어떻게 해결하고 있는지 최신 사례를 통해 살펴보겠습니다.
---
## 심화 프로젝트: 와인 품질 예측 (PyTorch MLP)
이번 장의 MNIST 실습을 통해 이미지 데이터에 대한 딥러닝(CNN)의 맛을 보았습니다. 이번 미니 프로젝트에서는 우리가 더 익숙한 **표(tabular) 형식의 데이터**에 딥러닝을 적용해 봅니다. 이 과정을 통해 딥러닝의 기본 원리(모델 정의, 학습 루프)가 데이터의 종류와 상관없이 동일하게 적용된다는 중요한 사실을 체득하게 됩니다.
Scikit-learn에 내장된 '와인 품질' 데이터셋을 사용하여, 와인의 화학적 특성으로 품질 등급('좋음'/'나쁨')을 예측하는 다층 퍼셉트론(MLP) 모델을 PyTorch로 직접 구축, 훈련, 평가하는 전체 과정을 경험합니다.
### 프로젝트 목표
1. Scikit-learn의 데이터를 PyTorch `Tensor`로 변환하고, `DataLoader`를 구성합니다.
2. `nn.Module`을 상속받아 1개 이상의 은닉층을 가진 MLP 모델을 설계합니다.
3. 이진 분류(Binary Classification) 문제에 맞는 손실 함수(`BCEWithLogitsLoss`)와 옵티마이저를 선택합니다.
4. 모델을 훈련시키고, 테스트 데이터에 대한 정확도를 측정하여 성능을 평가합니다.
**최종 분석 리포트 (예시):**
```
Epoch [10/50], Loss: 0.6123
Epoch [20/50], Loss: 0.5248
Epoch [30/50], Loss: 0.4581
Epoch [40/50], Loss: 0.4132
Epoch [50/50], Loss: 0.3887
Test Accuracy: 0.8611
```
### 단계별 구현 가이드
**1. 데이터 준비 (Scikit-learn -> PyTorch)**
- `sklearn.datasets.load_wine`을 사용해 데이터를 불러옵니다.
- 데이터를 Feature와 Target으로 나누고, `train_test_split`으로 훈련/테스트셋을 분리합니다.
- **(중요)** MLP는 스케일링에 민감하므로, `StandardScaler`를 사용해 Feature 데이터를 표준화합니다.
- 모든 데이터를 NumPy 배열에서 PyTorch `Tensor`로 변환합니다.
- `TensorDataset``DataLoader`를 사용하여 PyTorch가 배치(batch) 단위로 데이터를 처리할 수 있도록 준비합니다.
**2. MLP 모델 정의**
- `nn.Module`을 상속받는 `WineNet` 클래스를 만드세요.
- `__init__`: 입력층, 1개 이상의 은닉층(`nn.Linear` + `nn.ReLU`), 출력층(`nn.Linear`)을 정의합니다. 이진 분류이므로 출력층의 뉴런 수는 1개입니다.
- `forward`: 데이터가 각 층을 순서대로 통과하는 흐름을 정의합니다.
**3. 학습 및 평가 루프 구현**
- 모델, 손실 함수(`nn.BCEWithLogitsLoss`), 옵티마이저(`torch.optim.Adam`)를 초기화합니다.
- **학습 루프**: `for epoch in ...`:
- `for inputs, labels in train_loader:`:
- `optimizer.zero_grad()`: 이전 배치의 기울기 초기화
- `outputs = model(inputs)`: 순전파
- `loss = criterion(outputs, labels.unsqueeze(1))`: 손실 계산
- `loss.backward()`: 역전파
- `optimizer.step()`: 가중치 업데이트
- **평가 루프**:
- `model.eval()` 모드로 전환하고, `with torch.no_grad():` 블록 안에서 실행합니다.
- 테스트 로더에서 예측을 수행하고, `torch.sigmoid`와 임계값(0.5)을 사용해 로짓(logit)을 0 또는 1의 예측값으로 변환한 뒤, 정확도를 계산합니다.
**전체 코드 구조:**
```python
import torch import torch
import torch.nn as nn import torch.nn as nn
from torch.utils.data import TensorDataset, DataLoader import torchvision
from sklearn.datasets import load_wine import torchvision.transforms as transforms
from sklearn.model_selection import train_test_split from torch.utils.data import DataLoader
from sklearn.preprocessing import StandardScaler
# 1. 데이터셋 로더 준비
# 1. 데이터 준비 transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
# 데이터 로드 및 DataFrame 변환 train_dataset = torchvision.datasets.MNIST(root='./data', train=True, transform=transform, download=True)
# 와인 데이터셋은 13개의 feature와 3개의 클래스(0, 1, 2)를 가짐 test_dataset = torchvision.datasets.MNIST(root='./data', train=False, transform=transform)
X, y = load_wine(return_X_y=True) train_loader = DataLoader(dataset=train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(dataset=test_dataset, batch_size=64, shuffle=False)
# 이진 분류 문제로 변환: class 0을 1(good)로, 나머지(1, 2)를 0(bad)으로
y_binary = (y == 0).astype(int) # 2. CNN 모델 정의
class ConvNet(nn.Module):
# 데이터 분리 및 스케일링 def __init__(self):
X_train, X_test, y_train, y_test = train_test_split(X, y_binary, test_size=0.2, random_state=42, stratify=y_binary) super(ConvNet, self).__init__()
scaler = StandardScaler() self.layer1 = nn.Sequential(
X_train_scaled = scaler.fit_transform(X_train) nn.Conv2d(1, 32, kernel_size=5, stride=1, padding=2),
X_test_scaled = scaler.transform(X_test) nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2))
# PyTorch 텐서로 변환 self.layer2 = nn.Sequential(
X_train_tensor = torch.FloatTensor(X_train_scaled) nn.Conv2d(32, 64, kernel_size=5, stride=1, padding=2),
y_train_tensor = torch.FloatTensor(y_train) nn.ReLU(),
X_test_tensor = torch.FloatTensor(X_test_scaled) nn.MaxPool2d(kernel_size=2, stride=2))
y_test_tensor = torch.FloatTensor(y_test) self.fc = nn.Linear(7*7*64, 10)
# DataLoader 생성
train_dataset = TensorDataset(X_train_tensor, y_train_tensor)
train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)
# 2. MLP 모델 정의
class WineNet(nn.Module):
def __init__(self, input_features):
super(WineNet, self).__init__()
self.layer1 = nn.Linear(input_features, 64)
self.layer2 = nn.Linear(64, 32)
self.output_layer = nn.Linear(32, 1)
self.relu = nn.ReLU()
def forward(self, x): def forward(self, x):
x = self.relu(self.layer1(x)) out = self.layer1(x)
x = self.relu(self.layer2(x)) out = self.layer2(out)
x = self.output_layer(x) out = out.reshape(out.size(0), -1) # Flatten
return x out = self.fc(out)
return out
# 3. 모델, 손실함수, 옵티마이저 설정 # 3. 모델, 손실함수, 옵티마이저 설정
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = WineNet(input_features=X_train.shape[1]).to(device) model = ConvNet().to(device)
criterion = nn.BCEWithLogitsLoss() criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001) optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
# 4. 학습 루프 # 4. 모델 학습
num_epochs = 50 num_epochs = 5
for epoch in range(num_epochs): for epoch in range(num_epochs):
model.train() for i, (images, labels) in enumerate(train_loader):
for inputs, labels in train_loader: images = images.to(device)
inputs, labels = inputs.to(device), labels.to(device) labels = labels.to(device)
# 순전파
outputs = model(images)
loss = criterion(outputs, labels)
# 역전파 최적화
optimizer.zero_grad() optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels.unsqueeze(1))
loss.backward() loss.backward()
optimizer.step() optimizer.step()
if (epoch+1) % 10 == 0:
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')
# 5. 평가 루프 if (i+1) % 100 == 0:
model.eval() print(f'Epoch [{epoch+1}/{num_epochs}], Step [{i+1}/{len(train_loader)}], Loss: {loss.item():.4f}')
with torch.no_grad():
X_test_tensor, y_test_tensor = X_test_tensor.to(device), y_test_tensor.to(device)
y_pred_logits = model(X_test_tensor)
y_pred_prob = torch.sigmoid(y_pred_logits)
y_pred = (y_pred_prob > 0.5).float()
accuracy = (y_pred.squeeze() == y_test_tensor).float().mean()
print(f'\nTest Accuracy: {accuracy.item():.4f}')
# 5. 모델 평가
model.eval() # 평가 모드
with torch.no_grad():
correct = 0
total = 0
for images, labels in test_loader:
images = images.to(device)
labels = labels.to(device)
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'Test Accuracy of the model on the 10000 test images: {100 * correct / total} %')
``` ```
이 프로젝트를 통해 여러분은 어떤 종류의 데이터(이미지, 텍스트, 정형 데이터)를 다루든, PyTorch의 일관된 설계 철학 안에서 문제를 해결하는 능력을 갖추게 될 것입니다.
---
## ⚠️ What Could Go Wrong? (토론 주제)
이론을 배우고 코드를 실행하는 것을 넘어, 실제 딥러닝 프로젝트에서 마주할 수 있는 문제들에 대해 미리 고민해보는 것은 매우 중요합니다. 다음 주제들에 대해 함께 토론해보세요.
1. **"Dying ReLU" 문제의 심각성**
- **상황**: 학습 과정 모니터링 중, 특정 은닉층의 뉴런 중 상당수가 항상 0만을 출력하는 'Dying ReLU' 현상을 발견했습니다.
- **토론**:
- 이 현상이 모델 학습에 구체적으로 어떤 악영향을 미칠까요? (그래디언트 흐름, 파라미터 업데이트 등)
- 이론 섹션에서 배운 Leaky ReLU 외에, 이 문제를 진단하고 해결하기 위해 시도해볼 수 있는 방법에는 어떤 것들이 있을까요? (가중치 초기화 기법, 학습률 조정 등)
2. **교과서적인 과적합(Overfitting) 발생**
- **상황**: 우리가 만든 MNIST 분류기의 훈련(train) 정확도는 99%에 달하지만, 검증(validation) 정확도는 90%에서 정체되고 있습니다. 훈련 손실은 계속 감소하지만, 검증 손실은 오히려 증가하기 시작합니다.
- **토론**:
- 이는 전형적인 과적합 신호입니다. 현재 `ConvNet` 코드 구조를 기준으로, 과적합을 완화하기 위해 시도해볼 수 있는 구체적인 방법 3가지를 논의하고, 각 방법의 장단점을 설명해보세요. (예: `nn.Dropout` 추가, `torchvision.transforms`를 이용한 데이터 증강, 모델 구조 변경 등)
3. **옵티마이저 선택의 중요성**
- **상황**: 실습 코드에서는 `Adam` 옵티마이저를 기본으로 사용했습니다. 만약 `SGD` with momentum으로 옵티마이저를 변경하여 처음부터 다시 학습시킨다면, 학습 곡선(learning curve)은 어떻게 달라질 것으로 예상되나요?
- **토론**:
- `Adam``SGD`의 핵심적인 차이점은 무엇인가요? (파라미터별 학습률 조정, 모멘텀 등)
- 어떤 종류의 문제나 데이터셋에서 `Adam`이, 또 어떤 상황에서 `SGD`가 더 나은 선택이 될 수 있을지 각자의 경험과 근거를 들어 토론해보세요.
4. **배치 사이즈(Batch Size)는 클수록 좋을까?**
- **상황**: 더 빠른 학습을 위해 배치 사이즈를 64에서 1024로 크게 늘렸더니, GPU 메모리 부족(Out of Memory) 오류 없이 학습은 완료되었지만 최종 검증 정확도가 오히려 약간 떨어졌습니다.
- **토론**:
- 배치 사이즈를 크게 하는 것의 장점(학습 속도, 안정적인 그래디언트)과 단점(메모리 사용량, 일반화 성능 저하 가능성)은 무엇일까요?
- '큰 배치 사이즈가 일반화 성능을 해칠 수 있다'는 주장의 배경이 되는 'Sharp Minimum'과 'Flat Minimum'의 개념에 대해 조사하고 설명해보세요.
---
## 7. 트러블슈팅 (Troubleshooting)
- **`RuntimeError: mat1 and mat2 shapes cannot be multiplied (...)` 오류가 발생했나요?**
- 신경망의 연속된 두 `nn.Linear` 계층 간에 입력과 출력의 크기가 맞지 않는다는 의미입니다. 예를 들어, `nn.Linear(in_features=10, out_features=20)` 다음에는 `nn.Linear(in_features=20, ...)`가 와야 합니다. 특히 CNN에서 `nn.Linear` 계층으로 넘어갈 때 Flatten 이후의 크기를 정확히 계산했는지 확인해야 합니다.
- **손실(Loss)이 전혀 줄어들지 않나요?**
- **학습률(Learning Rate)**이 너무 높거나 낮을 수 있습니다. 너무 높으면 최적점을 지나쳐 발산하고, 너무 낮으면 학습이 매우 느리거나 지역 최적점(Local Minima)에 갇힐 수 있습니다. 옵티마이저의 `lr` 값을 조절해보세요.
- 데이터에 문제가 있을 수도 있습니다. 입력 데이터와 레이블이 제대로 매칭되었는지, 데이터 정규화가 올바르게 적용되었는지 확인해보세요.
- **GPU를 사용하고 있는데도 `CUDA out of memory` 오류가 발생하나요?**
- GPU 메모리보다 큰 모델이나 데이터를 올리려고 할 때 발생합니다. **배치 사이즈(Batch Size)**를 줄이는 것이 가장 일반적인 해결책입니다. 그래도 문제가 해결되지 않는다면, 모델의 파라미터 수를 줄이거나(더 얕은 모델 사용), 이미지의 해상도를 낮추는 방법을 고려할 수 있습니다.
- **`model.eval()`과 `torch.no_grad()`는 왜 사용해야 하나요?**
- **`model.eval()`**: 모델을 평가(evaluation/inference) 모드로 전환합니다. 이는 드롭아웃(Dropout)이나 배치 정규화(Batch Normalization)와 같이 훈련 때와 평가 때 다르게 동작해야 하는 레이어들을 올바르게 설정해주는 역할을 합니다.
- **`torch.no_grad()`**: 이 컨텍스트 블록 안에서는 그래디언트 계산을 수행하지 않도록 하여, 불필요한 메모리 사용을 막고 계산 속도를 높이는 것이 일반적입니다. 모델 평가나 추론 시에는 역전파가 필요 없으므로 반드시 사용해주는 것이 좋습니다.
더 자세한 문제 해결 가이드나 다른 동료들이 겪은 문제에 대한 해결책이 궁금하다면, 아래 문서를 참고해주세요.
- **➡️ [Geumdo-Docs: TROUBLESHOOTING.md](../../../TROUBLESHOOTING.md)**
---
| 기업 | 적용 분야 | 사용 기술 및 모델 (추정) | 비즈니스 가치 |
| :--- | :--- | :--- | :--- |
| **Tesla** | **자율 주행 (Autopilot / FSD)** | 다중 카메라 영상 기반의 **컴퓨터 비전**, Transformer 기반의 End-to-End 딥러닝 모델 (e.g., HydraNets) | 주변 환경(차선, 차량, 신호등, 보행자)을 3D 공간으로 인식하고, 차량의 행동을 결정. **운전자 보조 및 완전 자율 주행**을 목표로 함. |
| **Google (DeepMind)** | **단백질 구조 예측 (AlphaFold)** | 어텐션 기반의 딥러닝 네트워크 (Transformer와 유사) | 수십 년간 난제였던 단백질 3차원 구조 예측 문제를 해결. **신약 개발, 질병 연구** 등 생명 과학 분야에 혁신적인 발전을 가져옴. |
| **OpenAI** | **대규모 언어 모델 / 생성형 AI (GPT-4, DALL-E, Sora)** | **Transformer** 아키텍처 기반의 GPT(Generative Pre-trained Transformer) | 인간과 유사한 수준의 **텍스트 생성, 코드 작성, 이미지/영상 제작** 등 복잡한 창작 및 지능적 작업 수행. 생산성의 패러다임을 바꾸고 있음. |
| **Meta (FAIR)** | **콘텐츠 이해 및 추천, AR/VR** | CNN, RNN, Transformer 등 다양한 모델 활용 | 뉴스피드/릴스 추천, 유해 콘텐츠 자동 감지, 번역 등 핵심 서비스를 고도화. 차세대 플랫폼인 **AR 글래스, VR 헤드셋**의 객체 인식 및 상호작용에 활용. |
| **NVIDIA** | **AI 기반 신약/소재 개발 (BioNeMo)** | 생성형 AI, 분자 역학 시뮬레이션 | 신약 개발 후보 물질을 탐색하고 설계하는 데 드는 막대한 시간과 비용을 획기적으로 절감. **디지털 트윈** 기술과 결합하여 신소재 개발 가속화. |
--- ---
## 8. 되짚어보기 (Summary) <br>
이번 파트에서는 머신러닝의 한계를 넘어, 이미지와 텍스트 같은 비정형 데이터까지 처리할 수 있는 딥러닝의 세계로 들어섰습니다. > ## 7. 마무리 및 다음 파트 예고
>
- **PyTorch는 레고 블록**: 우리는 `nn.Module`이라는 '설명서'와 `nn.Linear`, `nn.Conv2d` 같은 '블록'으로 직접 신경망을 조립하는 법을 배웠습니다. > 이번 파트에서는 PyTorch를 사용하여 딥러닝의 기본 개념부터 실제 모델 구현까지의 여정을 함께했습니다. 이제 여러분은 딥러닝 모델을 '조립'하는 데 필요한 핵심 부품들(텐서, `nn.Module`, 손실 함수, 옵티마이저)을 이해하고, 이를 조합하여 학습 루프를 통해 모델을 훈련시킬 수 있습니다.
- **학습은 레시피 수정 과정**: 모델이 예측(순전파)을 하면, 손실 함수로 오차를 계산하고, 옵티마이저를 통해 오차를 줄이는 방향으로 파라미터를 수정(역전파)하는 학습 루프의 원리를 이해했습니다. >
- **CNN은 이미지 전문가**: 합성곱(Convolution)과 풀링(Pooling) 연산을 통해 이미지의 공간적 특징을 효과적으로 추출하는 CNN의 원리를 배우고, MNIST 분류 실습을 통해 직접 구현해보았습니다. > 우리가 만든 간단한 CNN 모델이 어떻게 수많은 손글씨 이미지를 보고 99%에 가까운 정확도로 숫자를 맞추는지, 그 과정의 신비로움을 조금이나마 느끼셨기를 바랍니다.
- **거인의 어깨 위에서**: LeNet부터 ResNet에 이르기까지, 딥러닝 아키텍처의 발전사를 통해 문제 해결을 위한 다양한 아이디어를 엿보았고, Tesla, OpenAI 등 실제 기업들이 어떻게 딥러닝으로 세상을 바꾸고 있는지 확인했습니다. >
> 다음 파트에서는 딥러닝의 또 다른 중요한 축인 **순차 데이터(Sequential Data)**를 다루는 방법을 배웁니다. 주가, 문장, 음악과 같이 '순서'가 중요한 데이터를 처리하기 위해 탄생한 **순환 신경망(Recurrent Neural Network, RNN)**과 그 발전된 형태인 **LSTM**에 대해 깊이 있게 탐구할 것입니다.
이제 여러분은 복잡한 딥러닝 모델의 구조를 이해하고, PyTorch를 사용하여 직접 구현할 수 있는 탄탄한 기초를 갖추게 되었습니다. >
> > [!TIP]
## 9. 더 깊이 알아보기 (Further Reading) > > **다음으로 무엇을 해야 할까요?**
> > - `source_code/part_7_deep_learning.py` 파일의 코드를 실행하며, 하이퍼파라미터(학습률, 배치 크기, 에포크 수)를 변경해보세요. 성능이 어떻게 변하는지 관찰하는 것은 매우 중요합니다.
### 실전 코드 & 튜토리얼 > > - `ConvNet` 모델의 구조를 바꿔보세요. `nn.Conv2d` 레이어를 더 추가하거나, `kernel_size`, `hidden_size`를 변경해보는 등 다양한 실험을 해보세요.
- [PyTorch 공식 튜토리얼 (한국어)](https://tutorials.pytorch.kr/): "60분 만에 끝내는 딥러닝"부터 분야별 심화 예제까지, PyTorch를 마스터하기 위한 최고의 자료입니다. > > - `torchvision.datasets.CIFAR10`과 같이 다른 데이터셋에 도전해보세요. (이미지 크기와 채널 수가 다르므로 모델 구조 수정이 필요합니다.)
- [PyTorch Lightning](https://www.pytorchlightning.ai/): `trainer.fit(model)`과 같이 PyTorch 코드를 더 구조화하고, 보일러플레이트를 획기적으로 줄여주는 상위 프레임워크입니다. > > - 궁금한 점이 있다면 언제든지 질문해주세요!
- [Hugging Face](https://huggingface.co/): 최신 Transformer 모델들을 쉽게 다운로드하고 사용할 수 있는 플랫폼. 자연어 처리를 한다면 반드시 알아야 할 필수 라이브러리입니다.
### 이론 및 개념 심화
- **[Dive into Deep Learning](https://d2l.ai/)**: 딥러닝의 거의 모든 주제를 다루는 포괄적인 온라인 교재. 수학적 설명과 PyTorch 코드가 함께 제공됩니다.
- **[CS231n: Convolutional Neural Networks for Visual Recognition](https://cs231n.github.io/)**: 스탠포드 대학의 전설적인 컴퓨터 비전 강의. CNN의 원리와 응용에 대해 가장 깊이 있게 배우고 싶다면 강력히 추천합니다.
- **[Attention Is All You Need (논문)](https://arxiv.org/abs/1706.03762)**: 현대 딥러닝의 흐름을 바꾼 Transformer 모델을 제안한 논문. `part_7.2`를 학습하기 전에 한번쯤 읽어보는 것을 권장합니다.
- **[3Blue1Brown: 신경망 영상 시리즈](https://www.youtube.com/playlist?list=PLZHQObOWTQDNU6R1_67000Dx_ZCJB-3pi)**: 역전파(Backpropagation)와 같은 딥러닝의 핵심 수학 개념을 세상에서 가장 직관적인 시각 자료로 설명해줍니다.
- **[A Comprehensive Guide to Convolutional Neural Networks](https://towardsdatascience.com/a-comprehensive-guide-to-convolutional-neural-networks-the-eli5-way-3bd2b1164a53)**: CNN의 기본 개념부터 주요 아키텍처까지 시각 자료와 함께 친절하게 설명해주는 아티클입니다.
--- ---
**⬅️ 이전 시간: [Part 6: 머신러닝 모델링과 평가](../06_machine_learning/part_6_machine_learning.md)**
**➡️ 다음 시간: [Part 7.1: 순환 신경망 (RNN)과 LSTM](./part_7.1_recurrent_neural_networks.md)** **➡️ 다음 시간: [Part 7.1: 순환 신경망 (RNN)과 LSTM](./part_7.1_recurrent_neural_networks.md)**
\ No newline at end of file
# Part 8: Model Serving with FastAPI ---
<h1>Part 8: 모델 서빙 (FastAPI)</h1>
이 파트에서는 훈련된 머신러닝/딥러닝 모델을 빠르고 효율적인 웹 프레임워크인 FastAPI를 사용하여 API로 외부에 제공하는 방법을 학습합니다. 이 파트에서는 훈련된 머신러닝/딥러닝 모델을 빠르고 효율적인 웹 프레임워크인 FastAPI를 사용하여 API로 외부에 제공하는 방법을 학습합니다.
...@@ -9,8 +10,10 @@ ...@@ -9,8 +10,10 @@
## 💻 실습 코드 ## 💻 실습 코드
- **[예제 코드](../../source_code/08_model_serving_with_fastapi/)**: 강의 내용을 직접 실행해볼 수 있는 코드입니다. - **[예제 코드](../../source_code/part_8_fastapi_project/)**: 강의 내용을 직접 실행해볼 수 있는 코드입니다.
--- ---
[↩️ 전체 커리큘럼으로 돌아가기](../../README.md) [↩️ 전체 커리큘럼으로 돌아가기](../../README.md)
\ No newline at end of file
---
\ No newline at end of file
# Part 8: FastAPI를 이용한 모델 서빙 ---
marp: true
theme: gaia
class:
- lead
- invert
---
**⬅️ 이전 시간: [Part 7.5: 강화학습 (Reinforcement Learning)](../07_deep_learning/part_7.5_reinforcement_learning.md)** <!-- _class: lead -->
<!-- _header: "" -->
<!-- _footer: "" -->
<style>
h1 {
font-size: 2.5em;
font-weight: 600;
}
h2 {
font-size: 2em;
font-weight: 600;
}
h3 {
font-size: 1.6em;
font-weight: 600;
}
h4 {
font-size: 1.3em;
font-weight: 600;
}
h5 {
font-size: 1.1em;
font-weight: 600;
}
h6 {
font-size: 1em;
font-weight: 600;
}
p, li, ul, ol, table {
font-size: 28px;
}
pre, code {
font-size: 24px;
}
</style>
# Part 8. FastAPI를 이용한 모델 서빙
**⬅️ 이전 시간: [Part 7.5: 강화학습 (Reinforcement Learning)](../07_deep_learning/part_7.5_reinforcement_learning.md)**<br/>
**➡️ 다음 시간: [Part 9: 프로덕션 레벨 API와 Docker](../09_production_ready_api/part_9_production_ready_api.md)** **➡️ 다음 시간: [Part 9: 프로덕션 레벨 API와 Docker](../09_production_ready_api/part_9_production_ready_api.md)**
--- ---
...@@ -15,11 +60,15 @@ ...@@ -15,11 +60,15 @@
- Pydantic을 사용하여 API의 요청/응답 데이터 형식을 정의하고 자동으로 검증할 수 있습니다. - Pydantic을 사용하여 API의 요청/응답 데이터 형식을 정의하고 자동으로 검증할 수 있습니다.
- FastAPI의 자동 생성 문서(Swagger UI)를 통해 브라우저에서 직접 API를 테스트하고 디버깅할 수 있습니다. - FastAPI의 자동 생성 문서(Swagger UI)를 통해 브라우저에서 직접 API를 테스트하고 디버깅할 수 있습니다.
---
## 2. 핵심 키워드 (Keywords) ## 2. 핵심 키워드 (Keywords)
`모델 서빙(Model Serving)`, `API`, `FastAPI`, `uvicorn`, `Pydantic`, `경로 매개변수(Path Parameter)`, `요청 본문(Request Body)`, `Swagger UI`, `lifespan` `모델 서빙(Model Serving)`, `API`, `FastAPI`, `uvicorn`, `Pydantic`, `경로 매개변수(Path Parameter)`, `요청 본문(Request Body)`, `Swagger UI`, `lifespan`
## 3. 도입: 나만 알던 맛집 레시피, 세상에 공개하기 (Introduction) ---
## 3. 도입 (Introduction)
지금까지 우리는 Scikit-learn과 PyTorch로 강력한 AI 모델, 즉 세상에 없는 '비법 레시피'를 개발했습니다. 하지만 이 레시피를 내 서랍 속에만 둔다면 아무도 그 맛을 볼 수 없습니다. 지금까지 우리는 Scikit-learn과 PyTorch로 강력한 AI 모델, 즉 세상에 없는 '비법 레시피'를 개발했습니다. 하지만 이 레시피를 내 서랍 속에만 둔다면 아무도 그 맛을 볼 수 없습니다.
...@@ -218,7 +267,7 @@ def predict_iris(data: IrisFeatures): ...@@ -218,7 +267,7 @@ def predict_iris(data: IrisFeatures):
--- ---
## ⚠️ What Could Go Wrong? (토론 주제) ## 7. 토론 주제 (Discussion Topics)
FastAPI를 사용하면 매우 빠르게 API를 만들 수 있지만, 실제 프로덕션 환경에서는 간단한 예제 코드에서 보이지 않던 문제들이 발생합니다. 다음 상황들에 대해 함께 토론해보세요. FastAPI를 사용하면 매우 빠르게 API를 만들 수 있지만, 실제 프로덕션 환경에서는 간단한 예제 코드에서 보이지 않던 문제들이 발생합니다. 다음 상황들에 대해 함께 토론해보세요.
...@@ -246,41 +295,22 @@ FastAPI를 사용하면 매우 빠르게 API를 만들 수 있지만, 실제 프 ...@@ -246,41 +295,22 @@ FastAPI를 사용하면 매우 빠르게 API를 만들 수 있지만, 실제 프
- Pydantic은 단순히 데이터 타입을 변환해주는 것 외에, 우리를 위해 어떤 '보이지 않는' 중요한 일들을 해주고 있었을까요? (예: 필수 필드 검사, 타입 강제, 상세한 오류 메시지 리포팅 등) - Pydantic은 단순히 데이터 타입을 변환해주는 것 외에, 우리를 위해 어떤 '보이지 않는' 중요한 일들을 해주고 있었을까요? (예: 필수 필드 검사, 타입 강제, 상세한 오류 메시지 리포팅 등)
- Pydantic을 사용하여 명확한 데이터 계약(Data Contract)을 정의하는 것이 프론트엔드와 백엔드 개발자 간의 협업에 어떻게 도움이 될까요? - Pydantic을 사용하여 명확한 데이터 계약(Data Contract)을 정의하는 것이 프론트엔드와 백엔드 개발자 간의 협업에 어떻게 도움이 될까요?
## 7. 되짚어보기 (Summary)
이번 주에는 FastAPI를 이용하여 머신러닝 모델을 API로 만드는 첫걸음을 떼었습니다.
- **AI 레스토랑**: 모델을 '레시피', API 서버를 '레스토랑'에 비유하여 모델 서빙의 개념을 이해했습니다.
- **FastAPI와 Uvicorn**: 파이썬 웹 서버를 구축하고 실행하는 방법을 배웠습니다.
- **Pydantic과 lifespan**: API의 데이터 형식을 강제하고, 서버 시작 시 모델을 효율적으로 로드하는 방법을 익혔습니다.
- **Swagger UI**: `/docs`의 '스마트 메뉴판'을 통해 API를 쉽고 빠르게 테스트하는 강력한 기능을 체험했습니다.
--- ---
## 8. 트러블슈팅 (Troubleshooting) ## 8. 되짚어보기 (Summary)
- **`uvicorn` 실행 시 `ModuleNotFoundError: No module named 'main'` 오류가 발생하나요?**
- `uvicorn main:app` 명령은 현재 터미널이 위치한 디렉토리에서 `main.py` 파일을 찾으라는 의미입니다. `main.py` 파일이 있는 디렉토리로 이동한 후 다시 명령을 실행해보세요.
- **`/docs` 접속 시 `{"detail":"Not Found"}`가 표시되나요?**
- 이는 주로 URL 주소를 잘못 입력했을 때 발생합니다. `http://12.0.0.1:8000/docs` 가 맞는지, 끝에 `/`가 빠지지는 않았는지 다시 한번 확인해보세요.
- **`Try it out` 실행 시 `422 Unprocessable Entity` 오류가 발생하나요?**
- FastAPI가 Pydantic 모델을 통해 요청 본문을 검증했지만, 형식이 맞지 않아 처리할 수 없다는 의미입니다. 예를 들어, `IrisFeatures` 모델은 `{"features": [1.0, 2.0, 3.0, 4.0]}` 형태의 JSON을 기대하는데, `{"feature": ...}` 와 같이 키 이름을 잘못 입력했거나 리스트의 요소 개수가 맞지 않는 경우 발생합니다.
- **모델을 로드할 때 `FileNotFoundError: [Errno 2] No such file or directory: 'iris_model.pkl'` 오류가 발생하나요?**
- `joblib.load()``iris_model.pkl` 파일을 찾지 못한 경우입니다. `main.py`를 실행하는 위치 기준으로 `iris_model.pkl` 파일이 같은 폴더에 있는지 확인하세요. 만약 다른 위치에 있다면, 절대 경로 또는 올바른 상대 경로를 지정해주어야 합니다.
- **서버 로그에 `ERROR: Traceback (most recent call last):` 와 함께 예상치 못한 오류가 표시되나요?**
- `uvicorn`을 실행한 터미널에 출력되는 로그는 최고의 디버깅 도구입니다. 오류 메시지의 가장 마지막 줄과 그 위의 몇 줄을 자세히 읽어보면, 어떤 코드 라인에서 어떤 종류의 예외(e.g., `AttributeError`, `ValueError`)가 발생했는지에 대한 단서를 얻을 수 있습니다.
더 자세한 문제 해결 가이드나 다른 동료들이 겪은 문제에 대한 해결책이 궁금하다면, 아래 문서를 참고해주세요.
- **➡️ [Geumdo-Docs: TROUBLESHOOTING.md](../../../TROUBLESHOOTING.md)** 이번 파트에서는 FastAPI를 사용하여 머신러닝 모델을 API로 서빙하는 방법을 배웠습니다. 주요 내용은 다음과 같습니다.
- **FastAPI 기본**: `uvicorn`으로 서버를 실행하고, 경로 매개변수와 요청 본문을 처리하는 방법을 학습했습니다.
- **Pydantic 모델**: API의 입출력 데이터 형식을 Pydantic으로 명확하게 정의하고, 데이터 유효성 검사를 자동화했습니다.
- **모델 서빙**: `lifespan` 이벤트를 활용하여 서버 시작 시 모델을 효율적으로 로드하고, 예측 결과를 반환하는 API 엔드포인트를 구현했습니다.
- **자동 API 문서**: FastAPI가 제공하는 Swagger UI를 통해 브라우저에서 직접 API를 테스트하고 사용법을 확인하는 방법을 익혔습니다.
- **프로덕션 고려사항**: `async`의 올바른 사용법, 무거운 모델 로딩 문제, 동시성 이슈 등 실제 운영 환경에서 발생할 수 있는 문제점들을 토론했습니다.
--- ---
## 9. 더 깊이 알아보기 (Further Reading) ## 9. 참고 자료 (References)
- [FastAPI 공식 튜토리얼](https://fastapi.tiangolo.com/tutorial/): FastAPI의 모든 것을 배울 수 있는 최고의 가이드
- [Pydantic 공식 문서](https://docs.pydantic.dev/latest/): 데이터 유효성 검사를 더 깊이 있게 활용하는 방법
- [Serving Machine Learning Models](https://www.manning.com/books/serving-machine-learning-models): 모델 서빙에 대한 전반적인 내용을 다루는 전문 서적
--- - [FastAPI 공식 문서](https://fastapi.tiangolo.com/)
- [Pydantic 공식 문서](https://pydantic-docs.helpmanual.io/)
**➡️ 다음 시간: [Part 9: 프로덕션 레벨 API와 Docker](../09_production_ready_api/part_9_production_ready_api.md)** ---
# 고급 RAG 기법: 검색 증강 생성의 최신 기술과 구현 # 고급 RAG 기법: 검색 증강 생성의 최신 기술과 구현
**⬅️ 이전 시간: [Part 13: 생성형 AI 및 AI 에이전트 심화](./part_13_generative_ai.md)**
**➡️ 다음 시간: [AI 에이전트 심화](./part_13.2_advanced_ai_agents.md)**
## 📋 학습 목표 ## 📋 학습 목표
이 모듈을 통해 다음을 학습하게 됩니다: 이 모듈을 통해 다음을 학습하게 됩니다:
......
# AI 에이전트 심화: LLM 기반 자율 에이전트 설계와 구현 # AI 에이전트 심화: LLM 기반 자율 에이전트 설계와 구현
**⬅️ 이전 시간: [고급 RAG 기법](./part_13.1_advanced_rag_techniques.md)**
**➡️ 다음 시간: [Part 14: AI 윤리 및 거버넌스 실무](../14_ai_ethics/part_14_ai_ethics.md)**
## 📋 학습 목표 ## 📋 학습 목표
이 모듈을 통해 다음을 학습하게 됩니다: 이 모듈을 통해 다음을 학습하게 됩니다:
......
# Part 13: 생성형 AI 및 AI 에이전트 심화 # Part 13: 생성형 AI 및 AI 에이전트 심화
**⬅️ 이전 시간: [Part 12: 대규모 AI 모델 최적화 및 서빙](../12_model_optimization/part_12_model_optimization.md)** **⬅️ 이전 시간: [Part 12: 대규모 AI 모델 최적화 및 서빙](../12_model_optimization/part_12_model_optimization.md)**
**➡️ 다음 시간: [Part 14: AI 윤리 및 거버넌스 실무](../14_ai_ethics/part_14_ai_ethics.md)** **➡️ 다음 시간: [고급 RAG 기법](./part_13.1_advanced_rag_techniques.md)**
--- ---
...@@ -352,7 +352,7 @@ LangSmith는 개발 초기 단계의 디버깅부터 프로덕션 환경의 모 ...@@ -352,7 +352,7 @@ LangSmith는 개발 초기 단계의 디버깅부터 프로덕션 환경의 모
--- ---
**➡️ 다음 시간: [Part 14: AI 윤리 및 거버넌스 실무](../14_ai_ethics/part_14_ai_ethics.md)** **➡️ 다음 시간: [고급 RAG 기법](./part_13.1_advanced_rag_techniques.md)**
### 참고 자료 ### 참고 자료
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment