Commit 69e437d8 authored by insun park's avatar insun park
Browse files

AI 교육 관련 초안 작성

parent ea7ff45b
# 핵심 용어집 (Glossary)
AI Lecture 시리즈 전반에 걸쳐 사용되는 주요 기술 용어들을 알파벳 순으로 정리했습니다.
---
### A
- **API (Application Programming Interface)**
- **정의**: 두 소프트웨어 구성 요소가 서로 통신할 수 있게 하는 메커니즘. 웹 API는 클라이언트(예: 웹 브라우저, 모바일 앱)가 서버의 기능이나 데이터에 접근할 수 있도록 미리 정해놓은 규칙의 집합입니다.
- **비유**: 식당의 메뉴판. 손님(클라이언트)은 메뉴판(API)을 보고 주문(요청)할 수 있으며, 주방(서버)은 정해진 메뉴에 따라 음식을 만들어 제공(응답)합니다.
- **관련 파트**: [Part 6](part_6_model_serving_with_fastapi.md), [Part 7](part_7_production_ready_api.md)
- **ASGI (Asynchronous Server Gateway Interface)**
- **정의**: 비동기 파이썬 웹 서버와 프레임워크(예: FastAPI, Starlette)가 통신하기 위한 표준 인터페이스. 많은 수의 I/O 바운드 작업을 동시에 효율적으로 처리하는 데 강점이 있습니다.
- **비교**: WSGI(Web Server Gateway Interface)는 동기식 파이썬 웹 프레임워크(예: Flask, Django)를 위한 전통적인 인터페이스입니다. ASGI는 WSGI의 후속 버전으로 비동기 기능을 지원합니다.
- **관련 파트**: [Part 6](part_6_model_serving_with_fastapi.md)
### D
- **Dependency Injection (의존성 주입)**
- **정의**: 객체가 필요로 하는 다른 객체(의존성)를 외부에서 직접 생성하여 전달하는 디자인 패턴. 객체 스스로 의존성을 생성하지 않으므로, 코드의 결합도(Coupling)를 낮추고 유연성과 테스트 용이성을 높입니다.
- **예시**: FastAPI에서 `Depends`를 사용하여 데이터베이스 세션(`db: Session = Depends(get_db)`)을 라우터 함수에 주입하는 것. 이를 통해 라우터 함수는 DB 세션 생성 방법을 알 필요 없이 사용에만 집중할 수 있습니다.
- **관련 파트**: [Part 7](part_7_production_ready_api.md)
### E
- **Endpoint (엔드포인트)**
- **정의**: API가 리소스에 접근할 수 있도록 제공하는 최종 통신 지점의 URL. 각 엔드포인트는 특정 기능(예: 사용자 정보 조회, 상품 추가)과 연결됩니다.
- **예시**: `https://api.example.com/users/123` 에서 `/users/123` 부분이 엔드포인트입니다.
- **관련 파트**: [Part 6](part_6_model_serving_with_fastapi.md)
### H
- **HTTP (HyperText Transfer Protocol)**
- **정의**: 클라이언트와 서버가 웹에서 데이터를 주고받기 위해 사용하는 통신 규약. `GET`(조회), `POST`(생성), `PUT`(수정), `DELETE`(삭제)와 같은 메서드를 사용하여 특정 작업을 요청합니다.
- **관련 파트**: [Part 6](part_6_model_serving_with_fastapi.md)
### O
- **ORM (Object-Relational Mapping)**
- **정의**: 객체 지향 프로그래밍 언어(예: 파이썬)의 객체(Class)와 관계형 데이터베이스(RDB)의 테이블을 자동으로 매핑(연결)해주는 기술. 개발자는 SQL 쿼리를 직접 작성하는 대신, 익숙한 프로그래밍 언어의 코드로 데이터베이스를 조작할 수 있습니다.
- **예시**: SQLAlchemy 라이브러리를 사용하여 파이썬 클래스로 DB 테이블을 정의하고, 파이썬 코드로 데이터를 추가/조회하는 것.
- **관련 파트**: [Part 7](part_7_production_ready_api.md)
### P
- **Pydantic**
- **정의**: 파이썬의 타입 힌트(Type Hint)를 사용하여 데이터의 유효성을 검사하고 설정을 관리하는 라이브러리. FastAPI에서 요청 및 응답 데이터의 형식을 정의하고 자동으로 검증하는 데 핵심적인 역할을 합니다.
- **장점**: 개발자가 직접 데이터 검증 코드를 작성할 필요 없이, 모델 클래스를 정의하는 것만으로 복잡한 데이터 유효성 검사를 수행할 수 있어 코드의 안정성과 가독성을 크게 향상시킵니다.
- **관련 파트**: [Part 7](part_7_production_ready_api.md)
\ No newline at end of file
# Part 0: 시작하며 - AI 서비스 개발, 첫걸음을 떼다
안녕하세요! "AI Lecture" 시리즈에 오신 것을 환영합니다.
이 시리즈는 프로그래밍의 기초를 다지고, AI 모델을 활용하여 실제 동작하는 API 서버를 구축하는 여정을 함께합니다. 막연하게 느껴졌던 'AI 서비스 개발'을 구체적인 코드로 구현하며 자신감을 얻는 것을 목표로 합니다.
## 🏁 최종 목표: 나만의 AI API 서버 구축
우리는 이 시리즈를 통해 **"붓꽃 품종을 예측하는 AI 모델이 내장된 API 서버"** 를 완성하게 될 것입니다. 사용자가 API에 붓꽃의 꽃잎, 꽃받침 정보를 보내면, 서버는 AI 모델을 통해 어떤 품종인지 예측하여 응답해주는 서비스입니다.
이 과정을 통해 여러분은 다음과 같은 결과물을 얻게 됩니다.
- Python 프로그래밍에 대한 깊이 있는 이해
- 실제 작동하는 FastAPI 기반의 API 서버
- AI 모델을 서빙하고 활용하는 방법에 대한 실전 경험
- Docker를 이용한 배포 및 운영의 기초 지식
## 🙋‍♂️ 대상 독자
이 강의는 다음과 같은 분들을 위해 만들어졌습니다.
- 프로그래밍은 처음이지만 AI 서비스를 직접 만들어보고 싶은 입문자
- Python 기본 문법은 알지만, 실제 프로젝트 경험이 부족한 학생 또는 주니어 개발자
- AI 모델을 개발했지만, 이를 어떻게 서비스로 만들어야 할지 막막한 연구자
## 🗺️ 전체 커리큘럼 맵
우리는 다음과 같은 순서로 학습을 진행합니다.
```mermaid
graph TD
A[Part 0: 시작하며] --> B[Part 1: AI 개발 환경 준비];
B --> C[Part 2: Python 핵심 문법];
C --> D[Part 3: Python 자료구조];
D --> E[Part 4: 객체 지향 프로그래밍];
E --> F[Part 5: AI 핵심 라이브러리];
F --> G[Part 6: FastAPI로 모델 서빙하기];
G --> H[Part 7: 프로덕션 수준의 API 만들기];
H --> I[Part 8: 전문가로 가는 길];
subgraph "기초 다지기"
B
C
D
E
end
subgraph "AI 모델 활용 및 API 개발"
F
G
H
end
subgraph "심화"
I
end
```
## 🎓 필요한 선수 지식
본격적인 학습에 앞서, 특별한 선수 지식은 필요하지 않습니다. 모든 과정을 하나하나 차근차근 설명합니다. 다만, 컴퓨터를 다루는 데 기본적인 지식이 있고, 배우고자 하는 열정과 꾸준함이 있다면 충분합니다!
---
자, 이제 모든 준비가 끝났습니다. 다음 파트에서는 본격적인 개발을 위해 필요한 프로그램들을 설치하고 환경을 설정해보겠습니다.
**➡️ 다음 시간: [Part 1: AI 개발 환경 준비](part_1_ai_development_environment.md)**
\ No newline at end of file
# Part 1: AI 개발 환경 구축
성공적인 AI 개발의 첫걸음은 안정적이고 효율적인 개발 환경을 구축하는 것입니다. 어떤 도구를 선택하느냐에 따라 개발 생산성과 경험이 크게 달라질 수 있습니다. 이 섹션에서는 현재 업계에서 널리 사용되는 대표적인 AI 개발 도구들을 소개합니다. 각 도구의 특징, 장단점, 그리고 추천 사용자를 상세히 비교하여, 여러분의 프로젝트와 개인적인 선호도에 가장 적합한 환경을 선택하고 구성하는 데 도움을 드리고자 합니다.
---
### 💡 지난 시간 복습
[Part 0: 시작하며](part_0_introduction.md)에서는 본 강의의 최종 목표가 **'붓꽃 품종 예측 AI API 서버'** 구축임을 명확히 하고, 전체 학습 로드맵을 함께 살펴보았습니다.
---
## 0. 시작하기 전에: 왜 가상환경을 사용해야 할까요?
AI 개발을 시작하면 프로젝트마다 사용하는 라이브러리(e.g., `TensorFlow`, `PyTorch`)와 그 버전이 달라지는 경우가 많습니다. 이때 가상환경(Virtual Environment)을 사용하지 않으면, 시스템에 설치된 단 하나의 파이썬 환경에 모든 라이브러리가 뒤섞이게 됩니다.
- **A 프로젝트**: `TensorFlow 2.5` 버전 필요
- **B 프로젝트**: `TensorFlow 2.10` 버전 필요
이런 상황에서 가상환경이 없다면 두 프로젝트를 동시에 원활하게 진행하기 어렵습니다. 가상환경은 이처럼 프로젝트별로 독립된 공간을 만들어주어 **라이브러리 버전 충돌 문제를 원천적으로 방지**하는 필수적인 도구입니다.
Python 3.3부터 기본 내장된 `venv` 모듈을 사용하는 것이 가장 표준적인 방법입니다.
### 가상환경 생성 및 활성화 (`venv`)
1. **가상환경 생성하기**
프로젝트 폴더를 만들고, 해당 폴더 내에서 터미널을 열어 아래 명령어를 실행합니다. `.venv`라는 이름의 가상환경 폴더가 생성됩니다.
```bash
# python3 또는 python으로 실행
python -m venv .venv
```
2. **가상환경 활성화하기**
생성된 가상환경을 사용하려면 반드시 '활성화'해야 합니다.
```bash
# Windows (cmd.exe)
.venv\\Scripts\\activate.bat
# Windows (PowerShell)
.venv\\Scripts\\Activate.ps1
# macOS / Linux (bash)
source .venv/bin/activate
```
활성화되면 터미널 프롬프트 앞에 `(.venv)`와 같은 표시가 나타납니다. 이 상태에서 설치하는 패키지는 모두 `.venv` 폴더 내에만 설치됩니다.
3. **패키지 설치 및 관리**
가상환경이 활성화된 상태에서 `pip`으로 필요한 라이브러리를 설치합니다.
```bash
# 예시: numpy와 pandas 설치
pip install numpy pandas
```
설치된 패키지 목록을 `requirements.txt` 파일로 저장하여 다른 사람과 공유하거나 다른 환경에서 동일하게 복원할 수 있습니다.
```bash
# 현재 환경의 패키지 목록을 requirements.txt로 저장
pip freeze > requirements.txt
# requirements.txt 파일로부터 모든 패키지를 설치
pip install -r requirements.txt
```
4. **가상환경 비활성화하기**
작업이 끝나면 `deactivate` 명령어로 가상환경을 빠져나올 수 있습니다.
```bash
deactivate
```
> 💡 **`.gitignore` 설정**: `.venv` 폴더는 Git으로 관리할 필요가 없으므로, 프로젝트의 `.gitignore` 파일에 `.venv`를 반드시 추가해주세요.
---
## 1. Spyder (스파이더)
<p align="center">
<img src="https://www.spyder-ide.org/static/images/spyder-logo-background.png" alt="Spyder-logo" width="150"/>
</p>
- **개요**: Spyder는 과학 및 공학 계산, 데이터 분석에 특화된 파이썬 통합 개발 환경(IDE)입니다. MATLAB과 유사한 인터페이스를 가지고 있어, 해당 툴에 익숙한 사용자에게 친숙합니다. 특히, 코드와 함께 변수의 상태, 데이터프레임, 그래프 등을 실시간으로 확인하며 작업할 수 있는 기능이 강력합니다.
- **핵심 특징**:
- **변수 탐색기(Variable Explorer)**: 현재 메모리에 로드된 모든 변수, 객체, 데이터프레임의 내용과 형태를 GUI 상에서 직접 확인하고 수정할 수 있습니다. 코드를 한 줄씩 실행하며 데이터가 어떻게 변하는지 직관적으로 파악하는 데 매우 유용합니다.
- **IPython 콘솔**: 코드를 대화형으로 실행하고 즉시 결과를 확인할 수 있습니다. 코드 전체를 실행하지 않고 특정 부분만 테스트하기에 용이합니다.
- **정적 분석 및 디버깅**: 코드의 오류를 사전에 감지하고, 중단점(Breakpoint)을 설정하여 코드 실행을 단계별로 추적하는 강력한 디버깅 기능을 제공합니다.
- **플롯(Plots) 창**: Matplotlib 등으로 생성된 그래프가 별도의 창에 표시되어, 코드를 수정하며 그래프의 변화를 바로 확인할 수 있습니다.
- **장점**:
- 데이터 분석 및 시각화에 매우 직관적인 환경.
- 변수와 데이터 구조를 시각적으로 탐색하는 기능이 탁월함.
- 학술 및 연구 커뮤니티에서 여전히 널리 사용됨.
- **단점**:
- 웹 개발이나 범용 소프트웨어 개발보다는 데이터 분석 작업에 치우쳐 있음.
- VSCode 등에 비해 확장성이 다소 부족함.
- **권장 사용자**:
- 데이터의 구조와 내용을 시각적으로 확인하며 탐색적 데이터 분석(EDA)을 주로 수행하는 데이터 분석가.
- 파이썬으로 데이터 과학에 입문하는 학생 및 연구자.
- MATLAB, RStudio와 같은 통계 분석 툴에 익숙한 사용자.
- **설치 및 시작**:
Anaconda 배포판을 설치하면 Spyder가 기본적으로 포함되어 있어 가장 쉽게 시작할 수 있습니다.
```bash
# Anaconda 설치 후, Anaconda Navigator에서 Spyder를 실행하거나
# 터미널에서 아래 명령어로 실행할 수 있습니다.
spyder
```
> [공식 홈페이지 바로가기](https://www.spyder-ide.org/)
---
## 2. JupyterLab (주피터랩)
<p align="center">
<img src="https://jupyter.org/assets/main-logo.svg" alt="Jupyter-logo" width="150"/>
</p>
- **개요**: JupyterLab은 웹 브라우저에서 실행되는 차세대 대화형 개발 환경입니다. 코드, 실행 결과, 시각화, 마크다운 설명 등을 '노트북(.ipynb)'이라는 파일 형식으로 통합하여 관리합니다. 실험 과정과 결과를 이야기처럼 풀어낼 수 있어, 연구 내용을 공유하고 재현하는 데 매우 효과적입니다.
- **핵심 특징**:
- **노트북 인터페이스**: 코드 셀과 마크다운 셀을 조합하여 실행 가능한 문서를 만들 수 있습니다. 코드와 그 결과, 그리고 설명이 함께 저장되므로 프로젝트의 논리적 흐름을 이해하기 쉽습니다.
- **셀(Cell) 단위 실행**: 전체 코드를 한 번에 실행할 필요 없이, 코드 블록(셀) 단위로 실행하고 결과를 즉시 확인할 수 있어 빠른 실험과 디버깅이 가능합니다.
- **유연한 인터페이스**: 터미널, 텍스트 편집기, 노트북, CSV 뷰어 등 다양한 컴포넌트를 탭과 분할 화면으로 자유롭게 배치하여 자신만의 작업 공간을 구성할 수 있습니다.
- **광범위한 커널 지원**: 파이썬뿐만 아니라 R, Julia, Scala 등 다양한 프로그래밍 언어를 지원합니다.
- **장점**:
- 빠른 프로토타이핑과 데이터 탐색에 매우 강력함.
- 코드, 결과, 설명을 함께 묶어 공유 및 발표 자료로 활용하기 좋음.
- 웹 기반이므로 원격 서버에 설치하여 어디서든 접속해 사용할 수 있음.
- **단점**:
- .ipynb 파일은 일반 .py 파일과 달리 JSON 형식이라 버전 관리(Git) 시 충돌 해결이 다소 까다로움.
- 긴 코드나 복잡한 프로젝트 전체를 관리하기에는 IDE보다 불편할 수 있음.
- **권장 사용자**:
- 빠른 아이디어 검증과 데이터 시각화가 중요한 모든 AI/ML 연구원 및 개발자.
- 분석 과정을 단계별로 기록하고 다른 사람과 공유해야 하는 데이터 분석가.
- 강의나 튜토리얼 자료를 작성하는 교육자.
- **설치 및 시작**:
```bash
# pip을 이용한 설치
pip install jupyterlab
# 설치 후 터미널에서 실행
jupyter lab
```
> [공식 홈페이지 바로가기](https://jupyterlab.readthedocs.io/)
---
## 3. VSCode (비주얼 스튜디오 코드)
<p align="center">
<img src="https://code.visualstudio.com/assets/images/code-stable.png" alt="VSCode-logo" width="150"/>
</p>
- **개요**: 가볍고 빠르면서도 강력한 기능을 자랑하는 Microsoft의 범용 코드 편집기입니다. 풍부한 확장 기능 생태계를 통해 단순한 텍스트 에디터를 넘어, 거의 모든 언어와 프레임워크를 지원하는 완전한 통합 개발 환경(IDE)으로 변신할 수 있습니다. AI 개발에 필요한 모든 작업을 하나의 툴에서 해결할 수 있는 'All-in-One' 솔루션입니다.
- **핵심 특징**:
- **강력한 확장성**: 마켓플레이스에 등록된 수많은 확장을 통해 원하는 기능을 무한히 추가할 수 있습니다. (Python, Jupyter, Docker, 원격 접속 등)
- **통합 터미널**: 편집기 내에서 바로 터미널을 열어 명령어를 실행할 수 있어 작업 흐름이 끊기지 않습니다.
- **Git 통합**: 코드 버전 관리를 위한 Git 기능이 기본적으로 내장되어 있어 GUI 환경에서 편리하게 `commit`, `push`, `pull` 등을 수행할 수 있습니다.
- **IntelliSense**: 단순한 자동 완성을 넘어, 코드 문맥을 이해하고 함수 시그니처, 변수 타입 등을 스마트하게 제안해줍니다.
- **장점**:
- AI 모델 개발부터 API 서버, 웹 프론트엔드 개발까지 하나의 툴에서 가능함.
- 가볍고 실행 속도가 빠름.
- 강력한 디버깅, 원격 개발, Git 통합 기능 제공.
- 활발한 커뮤니티와 풍부한 확장 기능.
- **단점**:
- 순수한 데이터 분석 환경으로는 Spyder나 Jupyter보다 초기 설정이 조금 더 필요할 수 있음.
- 기능이 매우 많아 처음에는 모든 기능을 파악하기 어려울 수 있음.
- **권장 사용자**:
- AI 모델뿐만 아니라, 해당 모델을 사용하는 API 서버 등 다양한 컴포넌트를 함께 개발해야 하는 풀스택 개발자 및 소프트웨어 엔지니어.
- 원격 서버나 Docker 컨테이너 환경에서 개발을 자주 하는 개발자.
- 하나의 도구로 모든 개발 작업을 통일하고 싶은 사용자.
- **추천 확장 기능**:
- `Python` (ms-python.python): Microsoft 공식 파이썬 지원. IntelliSense, 린팅, 디버깅, 포맷팅 등 필수 기능 제공.
- `Jupyter` (ms-toolsai.jupyter): VSCode 내에서 주피터 노트북(.ipynb)을 직접 실행하고 변수 확인, 데이터 시각화 등을 지원. JupyterLab의 장점을 그대로 누릴 수 있음.
- `Docker` (ms-azuretools.vscode-docker): 컨테이너와 이미지를 GUI로 관리하고, Dockerfile 및 docker-compose 파일 작성을 도와줌.
- `Remote - SSH` (ms-vscode-remote.remote-ssh): 원격 서버에 SSH로 접속하여, 마치 로컬 머신에서 작업하는 것처럼 파일을 편집하고 터미널을 사용할 수 있게 해줌.
- `GitHub Copilot` (GitHub.copilot): AI가 코드 전체 라인이나 함수를 통째로 제안해주는 강력한 코드 어시스턴트.
> [공식 홈페이지 바로가기](https://code.visualstudio.com/)
---
## 4. Google Colab (구글 코랩)
<p align="center">
<img src="https://colab.research.google.com/img/colab_favicon_256px.png" alt="Colab-logo" width="150"/>
</p>
- **개요**: Google에서 제공하는 클라우드 기반의 무료 Jupyter 노트북 환경입니다. 별도의 설치 과정 없이 웹 브라우저만 있으면 즉시 파이썬 코드를 작성하고 실행할 수 있습니다. 특히, 무료로 고성능 GPU(NVIDIA Tesla T4 등) 및 TPU를 사용할 수 있다는 점이 가장 큰 장점입니다.
- **핵심 특징**:
- **무설치 환경**: 로컬 PC에 파이썬이나 라이브러리를 설치할 필요가 없습니다. 구글 계정만 있으면 바로 시작할 수 있습니다.
- **무료 GPU/TPU 지원**: `런타임 > 런타임 유형 변경` 메뉴를 통해 몇 번의 클릭만으로 GPU나 TPU 가속을 활성화할 수 있어, 딥러닝 모델 학습 시간을 획기적으로 단축시킬 수 있습니다.
- **Google Drive 연동**: Google Drive를 Colab 노트북에 마운트하여 파일을 쉽게 읽고 쓸 수 있습니다. 데이터셋이나 학습된 모델을 저장하기에 편리합니다.
- **공유 및 협업**: 작성한 노트북을 다른 사람과 쉽게 공유하고, 여러 명이 동시에 편집할 수도 있습니다.
- **장점**:
- 복잡한 개발 환경 설정 없이 AI/ML을 바로 시작할 수 있음.
- 고가의 GPU 장비 없이도 딥러닝 모델을 학습시킬 수 있음.
- Google Drive와의 연동으로 데이터 관리가 편리함.
- **단점**:
- 일정 시간(기본 12시간) 이상 사용하면 런타임이 초기화되며, 설치했던 라이브러리와 변수들이 사라짐.
- 무료 버전은 GPU 할당이 보장되지 않으며, 자원 사용량에 제한이 있음(Colab Pro/Pro+ 유료 플랜으로 업그레이드 가능).
- 로컬 파일 시스템에 직접 접근하기는 다소 번거로움.
- **권장 사용자**:
- 로컬 PC 사양이 낮거나 개발 환경 구축이 부담스러운 AI 입문자.
- 딥러닝 모델 학습 등 고사양의 GPU 자원이 필요한 학생 및 연구자.
- 빠르게 아이디어를 테스트하고 결과를 공유하고 싶은 모든 개발자.
> [서비스 바로가기](https://colab.research.google.com/)
---
## 5. Kaggle (캐글)
<p align="center">
<img src="https://www.kaggle.com/static/images/site-logo.svg" alt="Kaggle-logo" width="150"/>
</p>
- **개요**: Kaggle은 세계 최대의 데이터 과학 커뮤니티이자, 데이터 분석 및 머신러닝 모델링 대회를 주최하는 플랫폼입니다. Google Colab과 유사하게 클라우드 기반의 무료 Jupyter 노트북 환경(Kaggle Notebooks)을 제공하여, 누구나 데이터 분석과 모델 개발을 쉽게 시작할 수 있습니다.
- **핵심 특징**:
- **데이터 과학 대회(Competitions)**: 기업과 연구 기관이 실제 데이터를 문제와 함께 제공하면, 전 세계 데이터 과학자들이 모델을 개발하여 순위를 경쟁합니다. 실전 경험을 쌓고 최신 기술을 접목해볼 최고의 기회입니다.
- **방대한 데이터셋**: 수만 개가 넘는 공개 데이터셋을 탐색하고 다운로드하여 자신의 프로젝트에 활용할 수 있습니다.
- **무료 GPU/TPU 지원**: Colab과 마찬가지로, 모델 학습에 필요한 GPU 및 TPU를 무료로 사용할 수 있습니다 (주간 사용량 제한 있음).
- **노트북 공유 및 학습**: 다른 참가자들이 공개한 노트북(코드)을 보며 문제 해결 아이디어를 얻고, 자신의 코드를 공유하며 토론할 수 있는 강력한 학습 환경을 제공합니다.
- **장점**:
- 실제 산업 문제를 기반으로 한 대회를 통해 실무 경험을 쌓을 수 있음.
- 세계적인 전문가들의 코드를 보며 학습하고 성장할 수 있음.
- 다양한 종류의 정제된 데이터셋에 쉽게 접근 가능함.
- **단점**:
- 무료 GPU/TPU 사용 시간에 주간 제한이 있음.
- Colab에 비해 동시 사용이나 런타임의 유연성이 다소 떨어질 수 있음.
- 플랫폼이 대회와 커뮤니티 중심으로 구성되어 있어, 순수 개인 프로젝트 개발에는 Colab이 더 편리할 수 있음.
- **권장 사용자**:
- 데이터 과학 및 머신러닝 분야의 포트폴리오를 만들고 싶은 취업 준비생.
- 실제 데이터를 다루며 실력을 검증하고 싶은 데이터 분석가 및 AI 개발자.
- 다른 사람의 문제 해결 방식을 배우고 최신 AI/ML 트렌드를 따라가고 싶은 학생 및 연구자.
- **설치 및 시작**:
```bash
# pip을 이용한 설치
pip install kaggle
# Kaggle API 토큰 설정 후 사용
```
> [공식 홈페이지 바로가기](https://www.kaggle.com/)
---
## 요약 및 어떤 도구를 선택해야 할까?
각 도구는 뚜렷한 장단점을 가지고 있어, 하나의 정답은 없습니다. 프로젝트의 성격과 개인의 선호도에 따라 최적의 선택이 달라집니다.
| 구분 | Spyder | JupyterLab | VSCode | Google Colab | Kaggle |
| :--- | :--- | :--- | :--- | :--- | :--- |
| **형태** | 데스크탑 IDE | 웹 기반 노트북 | 범용 코드 편집기 | 클라우드 노트북 | 클라우드 노트북 |
| **주요 장점** | 데이터 시각화, 변수 탐색 | 대화형 코드 실행, 문서화 | 강력한 확장성, 통합 개발 | 무료 GPU, 무설치 | 데이터셋, 대회, 커뮤니티 |
| **주요 단점**| 확장성 부족 | 버전 관리 복잡 | 초기 설정 필요 | 런타임 제한 | 사용량 제한 |
| **추천 사용자** | 데이터 분석가, 과학자 | 연구원, 교육자 | 풀스택/SW 엔지니어 | AI 입문자, 학생 | AI 실무 지망생, 데이터 과학자 |
---
### 🚀 다음 시간엔...
지금까지 AI 개발을 위한 다양한 도구와 환경 설정 방법을 알아보았습니다. 이제 도구는 준비되었으니, 본격적으로 코드를 작성할 시간입니다.
다음 [Part 2: 파이썬 핵심 문법](part_2_python_core_syntax.md)에서는 데이터 분석과 AI 모델링의 기반이 되는 파이썬의 필수 문법을 빠르게 훑어보겠습니다.
\ No newline at end of file
# Part 2: 파이썬 핵심 문법 마스터하기
---
### 💡 지난 시간 복습
[Part 1: AI 개발 환경 구축](part_1_ai_development_environment.md)에서는 VSCode, Jupyter, Colab 등 다양한 개발 도구의 특징을 알아보고, 프로젝트의 독립성을 보장하는 **가상환경**의 중요성과 사용법을 익혔습니다. 이제 우리는 코드를 작성하고 실행할 준비를 마쳤습니다.
---
AI 개발의 세계에 오신 것을 환영합니다! 파이썬은 AI와 데이터 과학 분야에서 가장 사랑받는 언어입니다. 문법이 간결하고 사람의 생각과 비슷해서, 프로그래밍을 처음 시작하는 분들도 쉽게 배울 수 있습니다. 이 문서는 [점프 투 파이썬](https://wikidocs.net/book/1)을 참고하여 파이썬을 처음 접하시거나, 다시 복습하고 싶은 분들을 위해 가장 핵심적인 문법만을 골라 친절하게 설명합니다.
## 1. 변수와 자료형: 데이터 다루기의 첫걸음
### 1.1. 변수(Variable): 데이터에 이름표 붙이기
프로그래밍은 결국 '데이터'를 다루는 일입니다. **변수(Variable)**는 데이터에 이름을 붙이고 저장하는 '라벨이 붙은 상자'와 같습니다. 상자에 물건을 넣고 필요할 때 꺼내 쓰는 것처럼, 변수에 데이터를 저장하고 필요할 때마다 이름을 불러 사용합니다.
```python
# 'box'라는 이름의 상자(변수)에 숫자 100을 저장합니다.
box = 100
print(box) # 100
# 이제 'box'에 문자열 "Hello"를 저장합니다. 상자의 내용물이 바뀌었습니다.
box = "Hello"
print(box) # "Hello"
```
파이썬은 매우 유연해서, 상자에 어떤 종류의 물건이 들어갈지 미리 말해주지 않아도 됩니다. 숫자를 넣으면 숫자 상자가, 글자를 넣으면 글자 상자가 되는 식이죠. 이를 **동적 타이핑(Dynamic Typing)**이라고 부릅니다.
### 1.2. 자료형(Data Types): 데이터의 종류
파이썬은 다양한 종류의 데이터를 다룰 수 있습니다. 이를 **자료형**이라고 부릅니다.
#### 1.2.1. 숫자형 (Numeric)
정수(`int`), 실수(`float`)는 계산을 위해 사용되는 가장 기본적인 자료형입니다.
```python
# 정수(Integer)와 실수(Float)
a = 10
b = 3.14
# 기본적인 사칙연산
print(f"덧셈: {a + b}")
print(f"나눗셈: {a / b}")
# 프로그래밍에서만 볼 수 있는 연산
print(f"나눗셈 후 나머지: {10 % 3}") # 1
print(f"나눗셈 후 몫만: {10 // 3}") # 3
print(f"거듭제곱: {2 ** 4}") # 2의 4제곱 = 16
```
> 💡 **Tip: 파이썬 3의 나눗셈**
> 파이썬 2에서는 `10 / 3`의 결과가 `3`(정수)이었지만, 파이썬 3부터는 `/` 연산자가 항상 `float`(실수)를 반환합니다 (`3.333...`). 정수 나눗셈의 몫을 원할 때는 `//` 연산자를 사용해야 합니다. 이 차이점을 기억하는 것은 매우 중요합니다.
#### 1.2.2. 문자열 (String)
'글자'들의 나열입니다. 작은따옴표(`'`) 또는 큰따옴표(`"`)로 감싸서 만듭니다.
```python
greeting = "Hello, Python!"
# f-string을 사용하면 문자열 안에 {변수명} 형태로 값을 쉽게 넣을 수 있습니다.
name = "앨리스"
print(f"안녕하세요, {name}님!")
# 인덱싱 (Indexing): 특정 위치의 글자 하나를 가져오기 (0부터 시작!)
first_char = greeting[0] # 'H'
# 슬라이싱 (Slicing): [시작:끝] 형태로 범위를 지정하여 여러 글자를 가져오기
py_string = greeting[7:13] # 'Python'
# 주요 문자열 메서드
text = " Welcome to Python! "
print(f"대문자로: {text.upper()}")
print(f"공백 제거: '{text.strip()}'")
print(f"치환: {text.replace('Python', 'World')}")
print(f"분리: {text.strip().split(' ')}")
```
> 💡 **Tip: f-string을 생활화하세요!**
> 과거에는 `"... %s ..." % name` 이나 `"... {}".format(name)` 같은 방식으로 문자열을 포맷팅했지만, f-string (`f"..."`)은 훨씬 간결하고, 직관적이며, 빠릅니다. 특별한 이유가 없다면 항상 f-string을 사용하는 것이 현대 파이썬 코딩 스타일입니다.
#### 1.2.3. 불리언 (Boolean)
`True`(참)와 `False`(거짓) 단 두 가지 값만 가지는 특별한 자료형입니다. 조건 판단의 기준이 됩니다.
```python
is_active = True
has_permission = False
# 논리 연산자: and, or, not
print(f"is_active and has_permission: {is_active and has_permission}") # False
print(f"10 > 5: {10 > 5}") # True
```
> 🚫 **Common Pitfall: `==` vs `is`**
> 파이썬 초보자들이 가장 흔하게 혼동하는 것 중 하나가 `==`와 `is`의 차이입니다.
> - `==` (동등 연산자): 두 변수의 **값**이 같은지 비교합니다. (예: `[1, 2]` == `[1, 2]` -> `True`)
> - `is` (식별 연산자): 두 변수가 **완전히 동일한 객체(메모리 주소)**를 가리키는지 비교합니다. (예: `[1, 2]` is `[1, 2]` -> `False`, 서로 다른 리스트 객체이므로)
>
> 일반적으로는 값의 일치 여부를 확인하는 `==`를 사용하는 것이 안전하고, `None`이나 `True`, `False`와 같이 유일한 객체임을 보장할 수 있는 경우에만 `is`를 사용하는 것이 좋습니다. (예: `if my_var is None:`)
### 1.3. 여러 데이터를 묶어서 관리하는 자료구조
하나가 아닌 여러 개의 데이터를 효율적으로 관리하기 위한 자료형입니다.
#### 1.3.1. 리스트 (List)
- 여러 개의 값을 순서대로 저장하는 **변경 가능한** 자료구조입니다.
- 대괄호 `[]`로 감싸고, 각 요소는 쉼표 `,`로 구분합니다.
```python
# 리스트 생성
fruits = ["apple", "banana", "cherry"]
numbers = [1, 2, 3, 4, 5]
# 인덱싱과 슬라이싱 (문자열과 동일)
print(f"첫 번째 과일: {fruits[0]}") # apple
print(f"마지막 두 개 과일: {fruits[1:]}") # ['banana', 'cherry']
# 리스트 값 변경하기
fruits[1] = "blueberry"
print(f"변경된 과일 리스트: {fruits}") # ['apple', 'blueberry', 'cherry']
# 리스트에 요소 추가/제거
fruits.append("strawberry") # 맨 뒤에 추가
print(f"추가 후: {fruits}")
fruits.remove("apple") # 특정 값 제거
print(f"제거 후: {fruits}")
# 리스트 길이 구하기
print(f"리스트의 길이: {len(fruits)}")
> 💡 **Tip: 리스트 컴프리헨션(List Comprehension)으로 파이썬답게 코딩하기**
> `for` 반복문과 `append` 사용하여 리스트를 만드는 것은 직관적이지만, 파이썬에서는 간결하고 가독성 높은 방법이 있습니다. 바로 **리스트 컴프리헨션**입니다.
>
> ```python
> # 0부터 9까지의 숫자 중 짝수만 제곱하여 리스트 만들기
>
> # 일반적인 for문 사용
> squares = []
> for i in range(10):
> if i % 2 == 0:
> squares.append(i**2)
> print(squares) # [0, 4, 16, 36, 64]
>
> # 리스트 컴프리헨션 사용
> squares_comp = [i**2 for i in range(10) if i % 2 == 0]
> print(squares_comp) # [0, 4, 16, 36, 64]
> ```
> 리스트 컴프리헨션을 사용하면 줄로 동일한 작업을 수행할 있어 코드가 훨씬 깔끔해집니다. 익숙해지면 코드를 읽고 쓰는 속도가 매우 빨라집니다.
#### 1.3.2. 튜플 (Tuple)
- 여러 개의 값을 순서대로 저장하는 **변경 불가능한** 자료구조입니다.
- 소괄호 `()` 감싸서 만듭니다. 한번 만들어지면 내용을 바꿀 없어서, 안정성이 중요할 사용됩니다.
```python
# 튜플 생성
point = (10, 20)
colors = ("red", "green", "blue")
# 인덱싱과 슬라이싱 (리스트와 동일)
print(f"x좌표: {point[0]}")
# 튜플은 변경 불가! 아래 코드는 오류를 발생시킵니다.
# point[0] = 15 # TypeError
```
#### 1.3.3. 딕셔너리 (Dictionary)
- `Key:Value` 쌍으로 데이터를 저장하는 순서가 없는 자료구조입니다.
- 중괄호 `{}`로 감싸서 만듭니다. '이름'='홍길동', '나이'=30 처럼 의미를 가진 데이터를 관리할 때 매우 유용합니다.
```python
# 딕셔너리 생성
user = {
"name": "앨리스",
"age": 30,
"city": "New York"
}
# Key를 이용해 Value에 접근
print(f"이름: {user['name']}")
print(f"나이: {user.get('age')}")
# 데이터 추가 및 변경
user['email'] = "alice@example.com" # 새로운 Key-Value 쌍 추가
user['age'] = 31 # 기존 Key의 Value 변경
print(f"수정된 사용자 정보: {user}")
# 데이터 삭제
del user['city']
print(f"삭제 후 사용자 정보: {user}")
# 모든 Key와 Value 보기
print(f"키 목록: {list(user.keys())}")
print(f"값 목록: {list(user.values())}")
```
#### 1.3.4. 집합 (Set)
- **중복을 허용하지 않는** 순서 없는 데이터의 모음입니다.
- 중괄호 `{}`를 사용하지만, Key가 없는 점이 딕셔너리와 다릅니다.
- 주로 데이터의 중복을 제거하거나, 여러 데이터 그룹 간의 연산(합집합, 교집합 등)에 사용됩니다.
```python
# 집합 생성
unique_numbers = {1, 2, 3, 2, 1, 4}
print(f"중복이 제거된 집합: {unique_numbers}") # {1, 2, 3, 4}
set_a = {1, 2, 3, 4}
set_b = {3, 4, 5, 6}
# 집합 연산
print(f"합집합 (A | B): {set_a | set_b}") # {1, 2, 3, 4, 5, 6}
print(f"교집합 (A & B): {set_a & set_b}") # {3, 4}
print(f"차집합 (A - B): {set_a - set_b}") # {1, 2}
```
---
## 2. 제어문: 코드의 흐름 조종하기
**제어문(Control Flow)**을 사용하면 특정 조건에 따라 코드를 실행하거나, 반복 실행하는 등 코드의 실행 흐름을 통제할 수 있습니다.
### 2.1. 파이썬의 핵심, 들여쓰기 (Indentation)
파이썬은 **들여쓰기(indentation)**로 코드 블록을 구분합니다. 보통 4개의 공백(스페이스바 4번)을 사용하며, 이는 파이썬 문법의 필수 요소이므로 매우 중요합니다.
### 2.2. if-elif-else (조건문)
조건에 따라 다른 코드를 실행하고 싶을 때 사용합니다.
```python
score = 85
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
else:
grade = "F"
print(f"당신의 학점은 {grade}입니다.")
```
### 2.3. for (반복문)
리스트, 튜플, 문자열 등 순회 가능한(iterable) 객체의 요소를 하나씩 순회하며 코드를 반복 실행합니다.
```python
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(f"나는 {fruit}를 좋아합니다!")
# enumerate를 사용하면 인덱스 번호와 값을 함께 사용할 수 있습니다.
for idx, fruit in enumerate(fruits):
print(f"{idx+1}번째 과일은 {fruit}입니다.")
# range() 함수는 정해진 횟수만큼 반복할 때 유용합니다.
for i in range(5): # 0부터 4까지 5번 반복
print(f"반복 횟수: {i}")
```
### 2.4. while (반복문)
특정 조건이 `True`인 **동안** 계속해서 코드를 반복 실행합니다. `while`문은 무한 루프에 빠질 위험이 있으니 항상 주의해야 합니다.
```python
count = 5
while count > 0:
print(f"카운트다운: {count}")
count -= 1
print("발사!")
# break(탈출)와 continue(건너뛰기)로 반복 제어
i = 0
while True: # 의도적인 무한 루프
i += 1
if i % 2 == 0:
continue # 짝수이면 아래 print를 건너뛰고 다음 반복으로
print(i) # 홀수만 출력
if i >= 10:
break # 10 이상이 되면 반복 중단
```
---
## 3. 함수: 코드 재사용을 위한 레시피
**함수(Function)**는 특정 작업을 수행하는 코드 묶음에 이름을 붙여놓은 것입니다. 함수를 사용하면 코드가 간결해지고(DRY: Don't Repeat Yourself), 수정 및 관리가 쉬워집니다.
### 3.1. 함수 정의와 호출
```python
# 'greet'라는 이름의 함수를 정의합니다.
# 'name'은 함수에 필요한 재료(인자, parameter)입니다.
def greet(name: str) -> str:
"""사용자에게 인사하는 문자열을 반환합니다.""" # Docstring
return f"안녕하세요, {name}님!"
# 함수를 호출하여 사용합니다.
message = greet("파이썬")
print(message)
```
* **타입 힌트(Type Hint)**: `name: str`이나 `-> str` 처럼 함수의 인자나 반환값의 타입을 명시하여 코드의 가독성과 안정성을 높일 수 있습니다. (강력 권장)
### 3.2. 다양한 인자(Argument) 전달 방식
```python
# 위치 인자, 키워드 인자, 기본값 인자
def introduce(name, age=30):
print(f"이름: {name}, 나이: {age}")
introduce("홍길동") # age는 기본값 30 사용
introduce("이순신", age=40) # 키워드 인자
# 가변 인자 (*args, **kwargs)
# *args: 여러 개의 위치 인자를 '튜플'로 받음
def sum_all(*numbers):
return sum(numbers)
# **kwargs: 여러 개의 키워드 인자를 '딕셔너리'로 받음
def print_user_profile(**user_info):
for key, value in user_info.items():
print(f"- {key}: {value}")
print(f"합계: {sum_all(1, 2, 3, 4, 5)}")
print_user_profile(name="John Doe", city="New York")
```
### 3.3. 함수의 반환값은 여러 개일 수 있으며, 이 경우 튜플로 반환됩니다.
```python
def greet_user(name, email):
return f"{name}님, 환영합니다!", f"이메일: {email}"
# 함수의 반환값은 여러 개일 수 있으며, 이 경우 튜플로 반환됩니다.
welcome_message, email_info = greet_user("홍길동", "hong@example.com")
print(welcome_message)
print(email_info)
🚫 **Common Pitfall: 함수 기본값으로 mutable 객체 사용하기**
파이썬에서 가장 까다로운 함정 중 하나입니다. 함수의 기본값 인자로 리스트(`[]`)나 딕셔너리(`{}`) 같은 **변경 가능한(mutable)** 객체를 사용하면 예상치 못한 결과를 초래할 수 있습니다.
```python
# 잘못된 예시
def add_to_list(item, my_list=[]):
my_list.append(item)
return my_list
# 함수 호출
print(add_to_list(1)) # 결과: [1] (예상대로)
print(add_to_list(2)) # 결과: [1, 2] (예상과 다름! [2]가 아님)
print(add_to_list(3)) # 결과: [1, 2, 3]
# 올바른 패턴
def add_to_list_safe(item, my_list=None):
if my_list is None:
my_list = []
my_list.append(item)
return my_list
print(add_to_list_safe(1)) # [1]
print(add_to_list_safe(2)) # [2]
```
- **왜 이런 일이?**: 함수 기본값은 함수가 **정의될 때 단 한 번만** 생성됩니다. `my_list=[]`는 함수가 처음 메모리에 올라갈 때 빈 리스트를 만들고, 이후 모든 호출에서 그 *동일한 리스트*를 계속 공유하여 사용하기 때문에 위와 같은 문제가 발생합니다.
- **해결책**: 기본값으로 `None`을 사용하고, 함수 내부에서 `if my_list is None:` 과 같이 체크하여 필요할 때 새로운 객체를 생성하는 것이 안전하고 표준적인 방법입니다.
---
### 🚀 다음 시간엔...
지금까지 파이썬의 가장 기본적인 구성 요소인 변수, 자료형, 제어문, 함수에 대해 알아보았습니다. 이것들은 우리가 앞으로 만들 모든 프로그램의 뼈대가 될 것입니다.
다음 [Part 3: 데이터 관리를 위한 파이썬 컬렉션](part_3_python_collections.md)에서는 여러 개의 데이터를 한 번에 담고 효율적으로 관리하는 리스트(List), 튜플(Tuple), 딕셔너리(Dictionary), 셋(Set) 자료구조에 대해 깊이 있게 탐구해 보겠습니다.
\ No newline at end of file
# Part 3: 데이터 관리를 위한 파이썬 컬렉션
---
### 💡 지난 시간 복습
[Part 2: 파이썬 핵심 문법 마스터하기](part_2_python_core_syntax.md)에서는 변수, 자료형, 제어문(if, for, while), 함수 등 파이썬 프로그래밍의 뼈대를 이루는 기본 문법을 학습했습니다. 이를 통해 코드의 기본적인 흐름을 제어하는 능력을 갖추게 되었습니다.
---
여러 개의 데이터를 효율적으로 저장하고 관리하는 파이썬의 핵심 자료구조를 '컬렉션(Collection)'이라고 부릅니다. 각 자료구조는 고유한 특징과 장점을 가지고 있으므로, 상황에 맞는 적절한 컬렉션을 선택하는 것은 코드의 성능과 가독성을 높이는 데 매우 중요합니다. 이 섹션에서는 리스트, 튜플, 딕셔너리, 셋의 차이점을 명확히 이해하고, 다양한 활용 예제를 통해 실전 감각을 익힙니다.
## 1. List (리스트)
- **특징**: **순서가 있는(ordered)**, **변경 가능한(mutable)** 데이터의 모음입니다. 파이썬에서 가장 보편적으로 사용되는 자료구조로, 다른 언어의 배열(Array)과 유사합니다.
- **사용 시점**: 데이터의 순서가 중요하고, 프로그램 실행 중에 내용의 추가, 수정, 삭제가 빈번하게 필요할 때 사용합니다.
### 1.1. 리스트 생성 및 기본 조작
```python
# 리스트 생성
fruits = ["apple", "banana", "cherry"]
numbers = [1, 2, 3, 4, 5]
mixed_list = [1, "hello", 3.14, True]
# 인덱싱과 슬라이싱 (문자열과 동일)
print(f"첫 번째 과일: {fruits[0]}") # apple
print(f"마지막 과일: {fruits[-1]}") # cherry
print(f"1번부터 3번 앞까지: {numbers[1:3]}") # [2, 3]
```
### 1.2. 리스트의 주요 메서드
```python
fruits = ["apple", "banana", "cherry"]
print(f"초기 리스트: {fruits}")
# 요소 추가
fruits.append("orange") # 맨 끝에 추가
print(f"append('orange'): {fruits}")
fruits.insert(1, "blueberry") # 특정 인덱스에 추가
print(f"insert(1, 'blueberry'): {fruits}")
# 요소 제거
fruits.remove("cherry") # 값으로 제거 (첫 번째로 발견된 값만)
print(f"remove('cherry'): {fruits}")
popped_fruit = fruits.pop(2) # 인덱스로 제거하고, 제거된 값을 반환
print(f"pop(2): {fruits} (제거된 값: {popped_fruit})")
# 정렬 및 순서 뒤집기
numbers = [3, 1, 4, 1, 5, 9, 2]
numbers.sort() # 오름차순 정렬 (원본 리스트 변경)
print(f"numbers.sort(): {numbers}")
numbers.sort(reverse=True) # 내림차순 정렬
print(f"numbers.sort(reverse=True): {numbers}")
fruits.reverse() # 리스트 순서를 뒤집음 (원본 리스트 변경)
print(f"fruits.reverse(): {fruits}")
> 🚫 **Common Pitfall: 리스트를 순회하면서 아이템 제거하기**
> `for` 루프를 사용해 리스트를 순회하는 동안 해당 리스트의 아이템을 제거하면, 일부 아이템을 건너뛰는 예기치 못한 결과가 발생할 있습니다.
>
> ```python
> numbers = [1, 2, 3, 4, 5, 6]
>
> # 잘못된 방법: 리스트를 순회하며 직접 제거
> # 2, 4, 6을 제거하고 싶지만...
> for num in numbers:
> if num % 2 == 0:
> numbers.remove(num)
>
> print(f"잘못된 방법 후 리스트: {numbers}") # 예상 결과: [1, 3, 5], 실제 결과: [1, 3, 5, 6]
> ```
> - ** 이런 일이?**: `remove(2)` 실행되면 리스트는 `[1, 3, 4, 5, 6]` 됩니다. 리스트의 길이가 줄어들고 인덱스가 앞으로 당겨지면서, 다음 순회 차례였던 `3` 건너뛰고 바로 `4` 넘어가기 때문입니다.
> - **올바른 해결책**:
> 1. **새로운 리스트 생성 (권장)**: 컴프리헨션 등을 이용해 조건을 만족하는 아이템만으로 리스트를 만드는 것이 가장 안전하고 파이썬다운 방법입니다.
> ```python
> numbers_original = [1, 2, 3, 4, 5, 6]
> odd_numbers = [num for num in numbers_original if num % 2 != 0]
> print(f"컴프리헨션 사용: {odd_numbers}")
> ```
> 2. **리스트의 복사본으로 순회**: 원본 리스트를 수정해야만 한다면, `numbers[:]` 같이 리스트의 복사본을 만들어 순회하고 원본을 변경해야 합니다.
> ```python
> numbers_original = [1, 2, 3, 4, 5, 6]
> for num in numbers_original[:]: # 복사본으로 순회
> if num % 2 == 0:
> numbers_original.remove(num) # 원본에서 제거
> print(f"복사본 순회 사용: {numbers_original}")
> ```
### 1.3. 리스트 컴프리헨션 (List Comprehension)
`for` 반복문과 `if` 조건문을 줄로 간결하게 표현하여 새로운 리스트를 만드는 강력한 기능입니다.
```python
# 0부터 9까지의 숫자를 제곱한 리스트 생성
# 일반적인 방법
squares = []
for i in range(10):
squares.append(i**2)
print(f"일반적인 방법: {squares}")
# 리스트 컴프리헨션 사용
squares_comp = [i**2 for i in range(10)]
print(f"컴프리헨션 사용: {squares_comp}")
# 조건문을 포함한 리스트 컴프리헨션
# 1부터 10까지의 숫자 중 짝수만 제곱하여 리스트로 만들기
even_squares = [i**2 for i in range(1, 11) if i % 2 == 0]
print(f"짝수 제곱 리스트: {even_squares}")
# {1: 1, 2: 4, 3: 9, 4: 16} 형태의 딕셔너리 생성
square_dict = {num: num**2 for num in numbers}
print(f"제곱 딕셔너리: {square_dict}")
> 💡 **Tip: 아이템 개수 세기, `collections.Counter`로 스마트하게!**
> 리스트나 문자열에 포함된 각 아이템이 몇 번 등장하는지 세어야 할 때, `for` 문과 딕셔너리로 직접 구현할 수도 있지만, `collections.Counter`를 사용하면 훨씬 간결하고 효율적입니다.
>
> ```python
> from collections import Counter
>
> # 리스트에서 각 과일의 개수 세기
> fruit_basket = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
> fruit_counts = Counter(fruit_basket)
>
> print(fruit_counts)
> # 출력: Counter({'apple': 3, 'banana': 2, 'orange': 1})
>
> # 가장 흔한 아이템 2개 찾기
> print(fruit_counts.most_common(2))
> # 출력: [('apple', 3), ('banana', 2)]
>
> # 특정 아이템의 개수 확인
> print(f"사과는 몇 개? {fruit_counts['apple']}") # 3
> print(f"포도는 몇 개? {fruit_counts['grape']}") # 키가 없어도 에러 없이 0을 반환
> ```
> `Counter`는 딕셔너리를 상속받아 만들어져, 딕셔너리의 모든 기능을 포함하면서도 아이템 개수를 세는 데 유용한 추가 메서드(`most_common` 등)를 제공합니다. 데이터 분석이나 자연어 처리에서 단어 빈도를 계산할 때 매우 유용하게 사용됩니다.
```
---
## 2. Tuple (튜플)
- **특징**: **순서가 있지만**, 한번 생성되면 내용을 **변경할 수 없는(immutable)** 데이터의 모음입니다. 소괄호 `()`를 사용하여 정의합니다.
- **사용 시점**: 프로그램 실행 중 절대 변하면 안 되는 값(예: 설정값, 좌표, 함수의 고정된 반환값)을 저장하거나, 딕셔너리의 키로 사용해야 할 때 유용합니다. 리스트보다 메모리를 적게 사용하고 속도가 조금 더 빠릅니다.
```python
# 튜플 생성
point = (10, 20)
colors = ("red", "green", "blue")
print(f"x좌표: {point[0]}")
# 튜플은 변경 불가능
# point[0] = 15 # 이 코드는 TypeError를 발생시킵니다.
# 튜플 패킹(packing)과 언패킹(unpacking)
person_info = ("John Doe", 30, "New York") # 패킹
name, age, city = person_info # 언패킹
print(f"이름: {name}, 나이: {age}, 도시: {city}")
# 함수에서 여러 값을 반환할 때 튜플이 유용하게 사용됨
def get_user_info(user_id):
# (사용자 이름, 이메일, 권한 등급)을 DB에서 조회했다고 가정
return ("Alice", "alice@example.com", "admin")
user_name, user_email, user_role = get_user_info(123)
print(f"사용자: {user_name}, 이메일: {user_email}, 역할: {user_role}")
```
---
## 3. Dictionary (딕셔너리)
- **특징**: '키(Key)'와 '값(Value)'을 쌍으로 저장하는, **순서가 없는(Python 3.7+ 부터는 입력 순서 유지)** 데이터 모음입니다. 키는 고유해야 하며, 일반적으로 문자열이나 숫자를 사용합니다. 중괄호 `{}`를 사용하여 정의합니다.
- **사용 시점**: 각 데이터에 고유한 이름표(Key)를 붙여 의미를 명확히 하고, 키를 통해 값을 매우 빠르게 조회하고 싶을 때 사용합니다. (JSON 형식과 매우 유사)
### 3.1. 딕셔너리 생성 및 기본 조작
```python
# 딕셔너리 생성
person = {"name": "John", "age": 25, "city": "New York"}
# 값 조회
print(f"이름: {person['name']}")
# print(person['job']) # 키가 없으면 KeyError 발생
# .get() 메서드를 사용한 안전한 조회
print(f"직업: {person.get('job')}") # 키가 없으면 None 반환
print(f"직업: {person.get('job', 'Unemployed')}") # 기본값 지정 가능
# 값 추가 및 수정
person["job"] = "Developer" # 새로운 키-값 쌍 추가
person["age"] = 26 # 기존 키의 값 수정
print(f"수정된 정보: {person}")
# 값 삭제
del person["city"]
print(f"삭제 후 정보: {person}")
```
### 3.2. 딕셔너리 순회
```python
person = {"name": "Alice", "age": 30, "city": "Seoul"}
# 1. 키 순회
for key in person.keys():
print(f"키: {key}")
# 2. 값 순회
for value in person.values():
print(f"값: {value}")
# 3. 키와 값 동시 순회 (가장 많이 사용)
for key, value in person.items():
print(f"{key}: {value}")
```
### 3.3. 딕셔너리 컴프리헨션
리스트 컴프리헨션과 유사하게, 한 줄로 간결하게 딕셔너리를 생성할 수 있습니다.
```python
numbers = [1, 2, 3, 4]
# {1: 1, 2: 4, 3: 9, 4: 16} 형태의 딕셔너리 생성
square_dict = {num: num**2 for num in numbers}
print(f"제곱 딕셔너리: {square_dict}")
```
---
## 4. Set (셋)
- **특징**: **중복을 허용하지 않는**, **순서 없는(unordered)** 데이터의 모음입니다. 중괄호 `{}`를 사용하지만, `{}`는 빈 딕셔너리를 의미하므로 빈 셋은 `set()`으로 만들어야 합니다.
- **사용 시점**: 리스트 등에서 중복된 값을 효율적으로 제거하거나, 두 데이터 집합 간의 교집합, 합집합, 차집합 등 수학적인 집합 연산이 필요할 때 효과적입니다. 특정 요소의 존재 여부를 매우 빠르게 확인해야 할 때도 사용됩니다.
```python
# 셋 생성
numbers = [1, 2, 3, 2, 1, 4, 5, 4]
unique_numbers = set(numbers)
print(f"리스트: {numbers}")
print(f"셋 (중복 제거): {unique_numbers}") # {1, 2, 3, 4, 5} (순서는 보장되지 않음)
# 요소 추가 및 제거
unique_numbers.add(6)
print(f"add(6): {unique_numbers}")
unique_numbers.remove(3)
print(f"remove(3): {unique_numbers}")
# 요소 존재 여부 확인 (리스트보다 훨씬 빠름)
print(f"5가 셋에 포함되어 있는가? {5 in unique_numbers}") # True
```
### 4.1. 집합 연산
```python
set_a = {1, 2, 3, 4, 5}
set_b = {4, 5, 6, 7, 8}
# 합집합 (Union)
print(f"합집합: {set_a | set_b}")
print(f"합집합 (메서드): {set_a.union(set_b)}")
# 교집합 (Intersection)
print(f"교집합: {set_a & set_b}")
print(f"교집합 (메서드): {set_a.intersection(set_b)}")
# 차집합 (Difference)
print(f"차집합 (A-B): {set_a - set_b}")
print(f"차집합 (메서드): {set_a.difference(set_b)}")
# 대칭 차집합 (Symmetric Difference) - 합집합에서 교집합을 뺀 부분
print(f"대칭 차집합: {set_a ^ set_b}")
print(f"대칭 차집합 (메서드): {set_a.symmetric_difference(set_b)}")
```
### 4.2. 컬렉션 요약 및 선택 가이드
지금까지 배운 네 가지 기본 컬렉션은 각각의 고유한 특징을 가지고 있어, 상황에 맞게 선택하는 것이 중요합니다. 아래 다이어그램은 어떤 상황에서 어떤 자료구조를 선택해야 하는지에 대한 간단한 가이드입니다.
```mermaid
graph TD
subgraph "자료구조 선택 가이드"
direction LR
start("데이터가 여러 개인가?") -->|"Yes"| q1("순서가 중요한가?")
start -->|"No"| others("단일 변수 사용")
q1 -->|"Yes"| q2("데이터 변경이 필요한가?")
q1 -->|"No"| q3("Key-Value 형태인가?")
q2 -->|"Yes"| list_("[List]<br/>- 순서 O<br/>- 변경 O<br/>- 중복 O<br/>- 사용 예: 할 일 목록, 학생 명단")
q2 -->|"No"| tuple_("[Tuple]<br/>- 순서 O<br/>- 변경 X<br/>- 중복 O<br/>- 사용 예: 함수의 반환값, 좌표")
q3 -->|"Yes"| dict_("[Dictionary]<br/>- Key-Value<br/>- Key 중복 X<br/>- 순서 O (3.7+)<br/>- 사용 예: 사람의 정보, JSON 데이터")
q3 -->|"No"| set_("[Set]<br/>- 순서 X<br/>- 중복 X<br/>- 집합 연산<br/>- 사용 예: 중복 아이템 제거, 멤버십 테스트")
end
```
이 가이드를 통해 해결하려는 문제의 성격에 가장 적합한 자료구조를 선택하여 더 효율적이고 읽기 좋은 코드를 작성할 수 있습니다.
---
## 5. 종합 연습문제
아래 문제들을 풀어보면서 리스트, 튜플, 딕셔너리, 셋의 활용법을 익혀보세요.
### 문제 1: 리스트 컴프리헨션 활용
`names` 리스트에서 5글자 이상인 이름만 대문자로 변경하여 새로운 리스트 `long_names_upper`를 만드세요.
```python
names = ["Alice", "Bob", "Charlie", "David", "Eva", "Frank"]
# 여기에 코드를 작성하세요
long_names_upper = [name.upper() for name in names if len(name) >= 5]
print(long_names_upper)
# 예상 출력: ['CHARLIE', 'DAVID', 'FRANK']
```
### 문제 2: 튜플 리스트 데이터 처리
학생들의 정보가 `(이름, 점수)` 형태의 튜플로 리스트에 저장되어 있습니다. 점수가 80점 이상인 학생들의 이름만 추출하여 `high_scorers` 리스트를 만드세요.
```python
students = [("Alice", 85), ("Bob", 72), ("Charlie", 95), ("David", 68), ("Eva", 88)]
# 여기에 코드를 작성하세요
high_scorers = [name for name, score in students if score >= 80]
print(high_scorers)
# 예상 출력: ['Alice', 'Charlie', 'Eva']
```
### 문제 3: 딕셔너리를 이용한 데이터 집계
여러 과목의 성적이 딕셔너리로 주어졌을 때, 각 학생의 평균 점수를 계산하여 `average_scores` 딕셔너리에 저장하세요.
```python
scores = {
"Alice": {"math": 90, "english": 85, "science": 92},
"Bob": {"math": 78, "english": 80, "science": 75},
"Charlie": {"math": 88, "english": 92, "science": 95}
}
average_scores = {}
# 여기에 코드를 작성하세요
for name, subject_scores in scores.items():
average_scores[name] = sum(subject_scores.values()) / len(subject_scores)
print(average_scores)
# 예상 출력: {'Alice': 89.0, 'Bob': 77.666..., 'Charlie': 91.666...}
```
### 문제 4: 셋을 이용한 공통 항목 찾기
두 개의 프로젝트에 참여하고 있는 팀원들의 명단이 각각 리스트로 주어졌습니다. 두 프로젝트에 모두 참여하고 있는 팀원을 찾아 `common_members` 셋으로 만드세요.
```python
project_a_members = ["Alice", "Bob", "Charlie", "David"]
project_b_members = ["Charlie", "Eva", "Frank", "Alice"]
# 여기에 코드를 작성하세요
common_members = set(project_a_members) & set(project_b_members)
print(common_members)
# 예상 출력: {'Alice', 'Charlie'} (순서는 다를 수 있음)
```
---
### ✅ 정리 및 다음 단계
이번 파트에서는 파이썬에서 여러 데이터를 관리하는 핵심 도구인 **컬렉션(Collection)**에 대해 배웠습니다.
- **리스트(List)**: 순서가 있고 변경 가능한 데이터 모음
- **튜플(Tuple)**: 순서가 있지만 변경 불가능한 데이터 모음
- **딕셔너리(Dictionary)**: Key-Value 쌍으로 이루어진 데이터 모음
- **셋(Set)**: 중복을 허용하지 않는 데이터 모음
각 컬렉션의 특징을 이해하고 상황에 맞게 사용하는 것은 효율적인 코드를 작성하는 데 매우 중요합니다.
지금까지 우리는 파이썬의 기본 도구들을 모두 익혔습니다. 이제 이 도구들을 활용하여 더 체계적이고 구조적인 코드를 작성하는 방법을 배울 차례입니다.
**➡️ 다음 시간: [Part 4: 객체 지향 프로그래밍 (OOP)의 이해](part_4_object_oriented_programming.md)**
다음 시간에는 AI 라이브러리의 근간을 이루는 **객체 지향 프로그래밍(OOP)**의 세계로 들어갑니다. **클래스(Class)**와 **객체(Object)**의 개념을 이해하고, 우리만의 '설계도'를 만들어 코드를 더욱 체계적으로 관리하는 방법을 배우게 될 것입니다.
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
# Part 6: AI 모델 서비스화 기초 (FastAPI)
---
### 💡 지난 시간 복습
[Part 5: AI 개발 핵심 라이브러리](part_5_ai_core_libraries.md)에서는 NumPy, Pandas, Scikit-learn 등을 사용하여 데이터를 처리하고, 붓꽃 품종 예측 모델을 학습시킨 후 `iris_model.pkl` 파일로 저장했습니다. 이제 우리는 예측 모델이라는 결과물을 손에 쥐게 되었습니다.
---
학습된 AI 모델은 그 자체로는 가치를 창출하기 어렵습니다. API(Application Programming Interface)를 통해 다른 서비스와 연동되고, 실제 사용자의 요청을 처리할 수 있을 때 비로소 가치를 갖게 됩니다. 이 섹션에서는 **Part 5에서 학습하고 저장한 Scikit-learn 모델(`iris_model.pkl`)**을 빠르고 안정적인 API로 만드는 방법을 소개합니다.
이를 위해 **FastAPI**라는 현대적인 고성능 웹 프레임워크를 사용합니다. FastAPI는 Python 3.7+의 타입 힌트(Type Hint)에 기반하여, 코드 작성과 동시에 데이터 유효성 검사, 자동 API 문서 생성을 지원하여 개발 생산성을 획기적으로 높여줍니다.
---
## 1. 왜 FastAPI를 사용하는가?
- **고성능**: 비동기(Asynchronous) 웹 요청을 지원하는 `ASGI`(Asynchronous Server Gateway Interface) 기반으로 만들어져, Node.js나 Go에 버금가는 매우 빠른 성능을 보여줍니다.
- **빠른 개발 속도**: 타입 힌트를 기반으로 코드를 작성하면, FastAPI가 입력 데이터의 유효성을 자동으로 검사해주므로 개발자가 직접 검증 코드를 작성하는 수고를 덜어줍니다.
- **자동 대화형 문서**: 코드만 작성하면 OpenAPI(Swagger UI)와 ReDoc 형태의 대화형 API 문서를 자동으로 생성해줍니다. 이를 통해 프론트엔드 개발자나 API 사용자가 별도의 문서 없이도 API를 쉽게 테스트하고 이해할 수 있습니다.
- **간편함과 표준 준수**: 배우기 쉽고 사용하기 간편하며, OpenAPI, JSON Schema 등 웹 표준을 철저히 준수합니다.
---
## 2. API 서버 구축 단계별 예제
> **사전 준비**: 아래 명령어를 터미널에 입력하여 필요한 라이브러리들을 설치해야 합니다. `uvicorn`은 FastAPI 애플리케이션을 실행시켜주는 경량 ASGI 서버입니다.
> **`Part 5`에서 생성된 `iris_model.pkl` 파일이 지금 만들 `main.py` 파일과 같은 디렉토리에 있어야 합니다.**
```bash
pip install fastapi "uvicorn[standard]" scikit-learn joblib numpy
```
### 2.1. 기본 FastAPI 앱 만들기 (`main.py`)
아래 코드를 `main.py` 라는 이름의 파일로 저장하세요.
```python
# main.py
from fastapi import FastAPI, HTTPException, Request
from pydantic import BaseModel
from typing import List
import joblib
import numpy as np
from contextlib import asynccontextmanager
# -------------------------------------------------------------------
# 1. 모델 로딩 및 리소스 관리를 위한 Lifespan 이벤트 핸들러 정의
# -------------------------------------------------------------------
@asynccontextmanager
async def lifespan(app: FastAPI):
# 애플리케이션 시작 시 실행될 코드
print("--- 서버 시작: 모델을 로드합니다. ---")
try:
# 모델을 로드하여 app.state에 저장
app.state.model = joblib.load("iris_model.pkl")
# 모델이 예측할 클래스(품종)의 실제 이름 정보도 함께 저장
app.state.iris_target_names = {0: 'setosa', 1: 'versicolor', 2: 'virginica'}
print("--- 모델 로드 성공 ---")
except FileNotFoundError:
print("!!! 모델 파일(iris_model.pkl)을 찾을 수 없습니다. !!!")
app.state.model = None
yield # 여기에서 애플리케이션이 실행됨
# 애플리케이션 종료 시 실행될 코드
print("--- 서버 종료: 리소스를 정리합니다. ---")
# 필요한 경우 리소스 정리 로직 추가 (예: DB 연결 해제 등)
app.state.clear()
# 2. FastAPI 애플리케이션 인스턴스 생성 및 Lifespan 연결
app = FastAPI(
title="붓꽃 품종 예측 API",
description="Scikit-learn 모델을 이용한 붓꽃 품종 예측 API입니다.",
lifespan=lifespan
)
# 3. 입력 데이터의 형식을 Pydantic 모델로 정의
class IrisFeatures(BaseModel):
features: List[float]
class Config:
json_schema_extra = {
"example": {
"features": [5.1, 3.5, 1.4, 0.2] # setosa 품종의 실제 데이터
}
}
# 4. API 엔드포인트(Endpoint) 정의
@app.get("/")
def read_root():
"""API의 루트 경로로, 간단한 환영 메시지를 반환합니다."""
return {"message": "붓꽃 품종 예측 API에 오신 것을 환영합니다!"}
@app.post("/predict")
def predict_iris(request: Request, data: IrisFeatures):
"""
붓꽃의 특징(features) 4개를 입력받아 품종을 예측하고 결과를 반환합니다.
- **data**: `IrisFeatures` Pydantic 모델 형식의 요청 Body
"""
# Lifespan에서 로드한 모델 객체를 가져옴
model = request.app.state.model
iris_target_names = request.app.state.iris_target_names
if model is None:
raise HTTPException(status_code=503, detail="모델이 로드되지 않았습니다. 서버 로그를 확인하세요.")
if len(data.features) != 4:
raise HTTPException(status_code=400, detail="입력 피처는 4개여야 합니다. (sepal length, sepal width, petal length, petal width)")
try:
model_input = np.array(data.features).reshape(1, -1)
except Exception as e:
raise HTTPException(status_code=400, detail=f"입력 데이터 변환 중 오류 발생: {e}")
prediction_idx = model.predict(model_input)[0]
prediction_proba = model.predict_proba(model_input)[0]
class_name = iris_target_names.get(int(prediction_idx), "Unknown")
confidence = prediction_proba[int(prediction_idx)]
return {
"input_features": data.features,
"predicted_class_id": int(prediction_idx),
"predicted_class_name": class_name,
"confidence": float(confidence)
}
```
### 2.2. API 서버 실행 및 테스트
1. **서버 실행**:
터미널을 열고 `main.py` 파일이 있는 디렉토리에서 아래 명령어를 실행합니다.
```bash
uvicorn main:app --reload
```
- `main`: `main.py` 파일을 의미합니다.
- `app`: `main.py` 파일 안에서 `app = FastAPI()`로 생성한 FastAPI 인스턴스 객체를 의미합니다.
- `--reload`: 코드가 변경될 때마다 서버를 자동으로 재시작해주는 개발용 옵션입니다.
2. **자동 생성된 API 문서 확인**:
서버가 성공적으로 실행되면 (`Application startup complete.`), 웹 브라우저를 열고 다음 두 주소 중 하나로 접속합니다.
- **Swagger UI**: http://127.0.0.1:8000/docs
- **ReDoc**: http://127.0.0.1:8000/redoc
<p align="center">
<img src="https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png" alt="FastAPI Swagger UI" width="700"/>
</p>
3. **API 테스트**:
- Swagger UI 화면에서 `/predict` 엔드포인트를 클릭하여 펼칩니다.
- 오른쪽 위에 있는 `Try it out` 버튼을 클릭합니다.
- `Request body`에 예시로 있는 JSON 데이터를 그대로 두거나 다른 값으로 수정합니다.
```json
{
"features": [6.7, 3.0, 5.2, 2.3] // virginica 품종의 데이터
}
```
- `Execute` 버튼을 누르면 API 서버로 요청이 전송되고, 그 아래 `Response body`에서 예측 결과를 확인할 수 있습니다.
---
### ✅ 정리 및 다음 단계
이번 파트에서는 **FastAPI**를 사용하여, Part 5에서 만든 `iris_model.pkl` 머신러닝 모델을 **실시간으로 예측 결과를 제공하는 API 서버**로 만드는 과정을 실습했습니다.
- **FastAPI**: 높은 성능과 빠른 개발 속도, 자동 문서 생성 기능을 갖춘 현대적인 웹 프레임워크
- **`lifespan`**: 서버 시작/종료 시 모델 로딩과 같은 초기화/정리 작업을 수행
- **Pydantic**: API의 입출력 데이터 형식을 명확하게 정의하고 자동으로 유효성 검사
- **Uvicorn**: FastAPI 애플리케이션을 실행하는 ASGI 서버
이제 여러분은 학습된 모델을 실제 서비스로 만들 수 있는 첫걸음을 떼었습니다. 하지만 현재의 코드는 모든 로직이 `main.py` 단일 파일에 집중되어 있어, 기능이 복잡해질수록 유지보수가 어려워지는 한계가 있습니다.
**➡️ 다음 시간: [Part 7: 실전형 AI API 서버 구축](part_7_production_ready_api.md)**
다음 시간에는 단일 파일 구조를 벗어나, 실제 프로덕션 환경에서도 통용되는 **체계적인 프로젝트 구조**로 API 서버를 리팩토링합니다. **라우터 분리, 데이터베이스 연동, 설정 관리** 등 더 견고하고 확장 가능한 서버를 만드는 방법을 배우게 될 것입니다.
\ No newline at end of file
This diff is collapsed.
# Part 8: AI 전문가로의 성장 (심화 과정)
---
### 💡 지난 시간 복습
지난 [Part 7: 실전형 AI API 서버 구축](part_7_production_ready_api.md)에서는 단일 파일 API를 기능별로 모듈화하고, 데이터베이스와 연동하여 예측 로그를 기록하는 등 실제 운영 환경에 가까운 서버로 리팩토링했습니다. 이를 통해 확장과 유지가 용이한 코드 구조의 중요성을 학습했습니다.
---
AI 서비스 개발의 기초를 성공적으로 다졌다면, 이제 한 단계 더 나아가 재현 가능하고(reproducible), 확장 가능하며(scalable), 신뢰할 수 있는(reliable) 시스템을 구축하는 진정한 AI 전문가로 성장할 차례입니다. 이 단계에서는 개발(Dev)과 운영(Ops)을 통합하는 MLOps, 대규모 데이터 처리, 그리고 클라우드 네이티브 기술과 같은 고급 주제들을 학습합니다.
이러한 기술들은 AI 서비스를 단순한 '프로토타입'에서 수백만 명의 사용자를 감당할 수 있는 '프로덕션 시스템'으로 격상시키는 핵심 요소입니다.
---
## 1. 컨테이너화와 배포 자동화 (Docker & CI/CD)
"제 PC에서는 잘 됐는데, 서버에서는 왜 안 되죠?" 라는 고질적인 문제를 원천적으로 해결하고, 어떤 환경에서든 AI 서비스를 동일하게 배포하고 실행하는 표준 기술을 익힙니다.
### 1.1. Docker: 애플리케이션 격리 및 패키징
- **핵심 개념**: Docker는 애플리케이션, 그 의존성(라이브러리 등), 그리고 실행 환경 자체를 '컨테이너(Container)'라는 격리된 공간에 패키징하는 기술입니다. 이 컨테이너는 어디서든 동일하게 실행되므로, 개발 환경과 운영 환경의 차이로 인한 문제를 근본적으로 해결합니다.
- **Dockerfile**: 컨테이너 이미지를 만들기 위한 '레시피' 또는 '설명서'입니다. 베이스 이미지 선택, 필요한 파일 복사, 의존성 설치, 실행 명령어 정의 등의 절차를 코드로 명시합니다.
#### 예제: Part 7의 FastAPI 앱을 위한 Dockerfile
```dockerfile
# Dockerfile
# 1. 베이스 이미지 선택
# 파이썬 3.9 버전을 기반으로 하는 공식 이미지를 사용합니다.
FROM python:3.9-slim
# 2. 작업 디렉토리 설정
# 컨테이너 내에서 명령어가 실행될 기본 경로를 설정합니다.
WORKDIR /app
# 3. 의존성 파일 복사
# 먼저 의존성 정의 파일만 복사하여, 소스 코드가 변경되어도
# 의존성이 바뀌지 않았다면 캐시된 레이어를 사용해 빌드 속도를 높입니다.
COPY ./requirements.txt .
# 4. 의존성 설치
# --no-cache-dir 옵션으로 불필요한 캐시를 남기지 않아 이미지 크기를 줄입니다.
RUN pip install --no-cache-dir -r requirements.txt
# 5. 소스 코드 및 모델 파일 복사
# 로컬의 현재 디렉토리(.)에 있는 모든 파일을 컨테이너의 /app 디렉토리로 복사합니다.
COPY . .
# 6. 컨테이너 실행 명령어
# 컨테이너가 시작될 때 실행할 명령어를 정의합니다.
# 0.0.0.0 주소로 실행하여 외부에서 컨테이너에 접근할 수 있도록 합니다.
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
```
- **Docker Compose**: 여러 개의 컨테이너(예: FastAPI 서버, 데이터베이스, 메시지 큐)로 구성된 복잡한 애플리케이션을 단일 `docker-compose.yml` 파일로 정의하고, `docker-compose up` 이라는 단일 명령으로 실행하고 관리할 수 있게 해줍니다.
### 1.2. CI/CD: 빌드, 테스트, 배포의 자동화
- **핵심 개념**: CI/CD(Continuous Integration/Continuous Deployment)는 소스 코드가 변경될 때마다 빌드, 테스트, 배포 과정을 자동으로 수행하는 파이프라인을 구축하는 것입니다. 이를 통해 개발자는 코드 변경 사항을 빠르고 안정적으로 사용자에게 전달할 수 있습니다.
- **대표적인 도구**: GitHub Actions, Jenkins, GitLab CI 등
<details>
<summary><b>✨ CI/CD 파이프라인 흐름도</b></summary>
```mermaid
graph TD
subgraph "Developer"
A[1. Code Push to<br>Git Repository]
end
subgraph "CI: Continuous Integration"
direction LR
B(2. Trigger<br>GitHub Actions) --> C{3. Run Tests}
C -- "Success" --> D(4. Build<br>Docker Image)
D --> E(5. Push Image to<br>Container Registry)
end
subgraph "CD: Continuous Deployment"
direction LR
F(6. Deploy Server<br>Pulls New Image) --> G(7. Run New<br>Container)
end
A --> B
E -- "Triggers" --> F
style A fill:#cde4ff,stroke:#6b6b6b
style G fill:#d4edda,stroke:#155724
```
</details>
- **CI/CD 파이프라인 예시 (GitHub Actions)**:
1. **Trigger**: 개발자가 코드를 변경하고 `main` 브랜치에 `push` 합니다.
2. **CI (Continuous Integration)**:
- GitHub Actions가 트리거를 감지하고 가상 머신을 할당합니다.
- 소스 코드를 내려받습니다.
- 유닛 테스트, 통합 테스트 등을 자동으로 실행합니다.
- 테스트가 통과하면, 위에서 작성한 `Dockerfile`을 사용하여 Docker 이미지를 빌드합니다.
- 빌드된 이미지를 Docker Hub나 AWS ECR 같은 컨테이너 레지스트리에 푸시합니다.
3. **CD (Continuous Deployment)**:
- 운영 서버에 SSH로 접속합니다.
- 레지스트리에서 최신 버전의 이미지를 `pull` 받습니다.
- 기존에 실행 중이던 구버전 컨테이너를 중단하고, 새로운 이미지로 컨테이너를 실행합니다.
---
## 2. MLOps: AI 개발 및 운영의 표준화
MLOps(Machine Learning Operations)는 모델 개발(Dev)과 IT 운영(Ops)을 통합하여, 머신러닝의 전체 생명주기(데이터 수집 → 모델 학습 → 배포 → 모니터링 → 재학습)를 자동화하고 효율적으로 관리하는 방법론입니다.
<details>
<summary><b>✨ MLOps 생애주기 다이어그램</b></summary>
```mermaid
graph TD
subgraph "Development and Training"
A["1. Data Collection and Versioning<br/>(DVC)"]
B["2. Model Training and Experiment Tracking<br/>(MLflow)"]
C["3. Model Packaging<br/>(Docker)"]
end
subgraph "Operations"
D["4. Model Deployment<br/>(Kubernetes, FastAPI)"]
E["5. Monitoring<br/>(Prometheus, Grafana)"]
F["6. Performance Analysis<br/>(Data/Model Drift)"]
end
A --> B
B --> C
C --> D
D --> E
E --> F
F -- "Retraining Trigger" --> A
style F fill:#f5c6cb,stroke:#721c24
```
</details>
### 2.1. 실험 관리 및 재현성 (MLflow, DVC)
- **MLflow**: 모델 학습에 사용된 파라미터(learning rate 등), 코드 버전, 성능 지표(accuracy 등), 그리고 결과물(모델 파일, 시각화 자료)을 체계적으로 추적하고 기록합니다. 이를 통해 "어떤 조건에서 가장 좋은 모델이 나왔는지"를 명확하게 관리하여 실험의 재현성을 보장하고 최적의 모델을 쉽게 선정할 수 있습니다.
- **DVC (Data Version Control)**: Git은 대용량 파일을 처리하는 데 적합하지 않습니다. DVC는 Git과 함께 사용하여 대용량 데이터셋과 모델 파일의 버전을 관리하고, 특정 버전의 코드와 데이터를 쉽게 매칭시켜줍니다.
### 2.2. 모델 서빙 및 모니터링
- **Model/Data Drift**: 배포된 모델의 성능은 시간이 지나면서 저하될 수 있습니다. 실제 데이터의 분포가 학습 데이터와 달라지는 현상(Data Drift)이나, 데이터와 예측값 간의 관계가 변하는 현상(Concept Drift)을 감지하고 대응하는 것이 중요합니다.
- **모니터링 도구**: API 서버의 상태(응답 시간, 에러율 등)와 모델의 예측 결과 분포, 데이터의 통계적 특성 변화 등을 지속적으로 시각화하고 추적합니다. 이상 징후가 발생하면 자동으로 알림을 보내 운영자가 개입하거나 재학습 파이프라인을 트리거하도록 설정합니다. (e.g., Prometheus, Grafana, Evidently AI)
### 2.3. 자동화된 ML 파이프라인 (Kubeflow, Airflow)
데이터 수집, 전처리, 모델 학습, 평가, 배포로 이어지는 전체 워크플로우를 코드로 정의하고 자동화합니다. 이를 통해 새로운 데이터가 쌓이면 자동으로 모델을 재학습하고, 성능이 더 좋은 경우 기존 모델을 자동으로 교체하는 등 사람의 개입을 최소화하는 완전 자동화 시스템을 구축할 수 있습니다.
---
## 3. 대용량 데이터 처리 기술
기가바이트를 넘어 테라바이트, 페타바이트급의 대용량 데이터를 효율적으로 저장, 처리, 분석하는 기술은 빅데이터 기반 AI 서비스의 핵심 역량입니다.
- **NoSQL 데이터베이스 (MongoDB, DynamoDB 등)**: 정형화되지 않은 비정형 데이터(JSON, 로그, 센서 데이터 등)를 유연하게 저장하고 빠르게 조회할 수 있어, 로그 데이터나 사용자 행동 데이터 등을 다루는 데 적합합니다.
- **분산 처리 시스템 (Apache Spark, Kafka)**:
- **Apache Kafka**: 대용량 실시간 데이터 스트림을 안정적으로 수집하고 여러 시스템에 전달하는 메시징 시스템입니다. 이벤트 기반 아키텍처의 중심 역할을 합니다.
- **Apache Spark**: 대규모 데이터셋에 대한 분산 처리를 통해 배치(Batch) 기반의 데이터 전처리 및 모델 학습을 고속으로 수행합니다. SQL, 스트리밍, 머신러닝 라이브러리(MLlib) 등 통합된 분석 엔진을 제공합니다.
---
## 4. 클라우드 네이티브 AI
클라우드 플랫폼(AWS, GCP, Azure 등)이 제공하는 강력한 관리형 서비스들을 활용하여 AI 시스템을 더 빠르고, 효율적이며, 탄력적으로 구축합니다.
- **서버리스 (AWS Lambda, Google Cloud Functions)**: 서버 인프라를 직접 프로비저닝하거나 관리할 필요 없이, 코드 실행 단위로 서비스를 배포하고 사용한 만큼만 비용을 지불하여 운영 효율성을 극대화합니다. 간단한 데이터 전처리나 모델 추론 API에 적합합니다.
- **관리형 AI/ML 플랫폼 (Amazon SageMaker, Google Vertex AI, Azure Machine Learning)**: 데이터 라벨링, 노트북 환경, 모델 학습, 하이퍼파라미터 튜닝, 모델 배포, 모니터링에 이르는 MLOps 파이프라인 전체를 클라우드에서 제공하는 완전 관리형 서비스로 구축하여, 인프라 관리 부담을 최소화하고 AI 모델 개발 자체에만 집중할 수 있게 해줍니다.
이러한 심화 과정들을 통해 여러분은 단순히 모델을 만드는 개발자를 넘어, 비즈니스 가치를 지속적으로 창출하는 안정적이고 확장 가능한 AI 시스템을 설계하고 운영하는 'AI 시스템 아키텍트'로 성장하게 될 것입니다.
---
## 5. GitHub 스타터 키트
Part 8에서 다룬 Docker, CI/CD, MLOps 관련 설정이 포함된 프로젝트 예제를 스타터 키트로 제공합니다.
> 🔗 **Part 8 스타터 키트 리포지토리**: [여기에 GitHub 리포지토리 링크가 제공될 예정입니다.]
이 리포지토리를 시작점으로 삼아, 여러분의 AI 프로젝트에 바로 Docker와 CI/CD 파이프라인을 적용해보세요.
\ No newline at end of file
# 1. 베이스 이미지 설정
# 공식 Python 3.9 이미지를 기반으로 합니다.
FROM python:3.9-slim
# 2. 작업 디렉토리 설정
# 컨테이너 내에서 명령이 실행될 기본 경로입니다.
WORKDIR /app
# 3. 의존성 설치
# 먼저 requirements.txt 파일만 복사하여 캐시를 활용합니다.
# 이렇게 하면 소스 코드가 변경되어도 매번 의존성을 새로 설치하지 않습니다.
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 4. 소스 코드 복사
# 현재 디렉토리의 모든 파일을 컨테이너의 /app 디렉토리로 복사합니다.
COPY . .
# 5. 포트 노출
# FastAPI 기본 포트인 8000번을 외부에 노출합니다.
EXPOSE 8000
# 6. 애플리케이션 실행
# 컨테이너가 시작될 때 실행할 명령입니다.
# Uvicorn을 사용하여 main.py 파일의 app 객체를 실행합니다.
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
\ No newline at end of file
version: '3.8'
services:
ai-lecture-service:
# 빌드에 사용할 Dockerfile의 경로를 지정합니다.
# '.'는 현재 디렉토리를 의미합니다.
build: .
# 컨테이너의 이름을 지정합니다.
container_name: ai_lecture_container
# 포트 매핑을 설정합니다.
# "호스트 포트:컨테이너 포트" 형식입니다.
ports:
- "8000:8000"
# 볼륨 매핑을 설정합니다.
# 현재 디렉토리(.)의 모든 파일을 컨테이너의 /app 디렉토리와 동기화합니다.
# 이를 통해 호스트에서 코드를 수정하면 즉시 컨테이너에 반영됩니다.
volumes:
- .:/app
# 컨테이너가 항상 재시작되도록 설정합니다.
restart: always
\ No newline at end of file
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