Commit 932f390a authored by insun park's avatar insun park
Browse files

강의 자료 업데이트 및 용어집 정리

parent 69e437d8
# Part 6: 머신러닝 기초 실습 (Scikit-learn)
# 이 스크립트를 실행하기 전에 라이브러리를 설치해야 합니다.
# pip install scikit-learn matplotlib
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
import seaborn as sns
import os
# --- 데이터 준비 ---
print("--- 1. 데이터 준비 ---")
# Scikit-learn에 내장된 붓꽃(Iris) 데이터셋 로드
iris = load_iris()
X = iris.data # 특성 (꽃받침 길이/너비, 꽃잎 길이/너비)
y = iris.target # 타겟 (품종)
print(f"데이터셋 크기: {X.shape}")
print(f"타겟 크기: {y.shape}")
print(f"클래스 종류: {iris.target_names}")
print("-" * 30)
# --- 훈련/테스트 데이터 분리 ---
print("\n--- 2. 훈련/테스트 데이터 분리 ---")
# 데이터를 훈련용 80%, 테스트용 20%로 분리
# random_state를 고정하여 항상 같은 결과로 분리되도록 함
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
print(f"훈련 데이터 크기: {X_train.shape}")
print(f"테스트 데이터 크기: {X_test.shape}")
print("-" * 30)
# --- 데이터 스케일링 (특성 표준화) ---
print("\n--- 3. 데이터 스케일링 ---")
# 특성의 스케일이 다를 경우 모델 성능에 영향을 줄 수 있으므로 표준화 수행
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
print("데이터 스케일링 완료 (StandardScaler 적용)")
print("-" * 30)
# --- 모델 훈련 ---
print("\n--- 4. 모델 훈련 ---")
# 모델 1: 로지스틱 회귀 (Logistic Regression)
log_reg = LogisticRegression(random_state=42)
log_reg.fit(X_train_scaled, y_train)
print("로지스틱 회귀 모델 훈련 완료")
# 모델 2: 결정 트리 (Decision Tree)
tree_clf = DecisionTreeClassifier(max_depth=3, random_state=42)
tree_clf.fit(X_train_scaled, y_train)
print("결정 트리 모델 훈련 완료")
print("-" * 30)
# --- 예측 및 평가 ---
print("\n--- 5. 예측 및 평가 ---")
# 로지스틱 회귀 모델 평가
y_pred_log_reg = log_reg.predict(X_test_scaled)
accuracy_log_reg = accuracy_score(y_test, y_pred_log_reg)
print("\n--- 로지스틱 회귀 평가 결과 ---")
print(f"정확도(Accuracy): {accuracy_log_reg:.4f}")
print("분류 보고서(Classification Report):")
print(classification_report(y_test, y_pred_log_reg, target_names=iris.target_names))
# 결정 트리 모델 평가
y_pred_tree = tree_clf.predict(X_test_scaled)
accuracy_tree = accuracy_score(y_test, y_pred_tree)
print("\n--- 결정 트리 평가 결과 ---")
print(f"정확도(Accuracy): {accuracy_tree:.4f}")
print("분류 보고서(Classification Report):")
print(classification_report(y_test, y_pred_tree, target_names=iris.target_names))
print("-" * 30)
# --- 결과 시각화 (혼동 행렬) ---
print("\n--- 6. 결과 시각화 ---")
# 그래프 저장 디렉터리 확인
output_dir = "plot_outputs"
if not os.path.exists(output_dir):
os.makedirs(output_dir)
print(f"시각화 결과는 '{output_dir}' 폴더에 저장됩니다.")
# 로지스틱 회귀 혼동 행렬
cm_log_reg = confusion_matrix(y_test, y_pred_log_reg)
plt.figure(figsize=(8, 6))
sns.heatmap(cm_log_reg, annot=True, fmt='d', cmap='Blues',
xticklabels=iris.target_names, yticklabels=iris.target_names)
plt.title('Logistic Regression - Confusion Matrix')
plt.xlabel('Predicted Label')
plt.ylabel('True Label')
log_reg_cm_path = os.path.join(output_dir, "logistic_regression_confusion_matrix.png")
plt.savefig(log_reg_cm_path)
print(f"로지스틱 회귀 혼동 행렬 저장 완료: {log_reg_cm_path}")
plt.close()
# 결정 트리 혼동 행렬
cm_tree = confusion_matrix(y_test, y_pred_tree)
plt.figure(figsize=(8, 6))
sns.heatmap(cm_tree, annot=True, fmt='d', cmap='Greens',
xticklabels=iris.target_names, yticklabels=iris.target_names)
plt.title('Decision Tree - Confusion Matrix')
plt.xlabel('Predicted Label')
plt.ylabel('True Label')
tree_cm_path = os.path.join(output_dir, "decision_tree_confusion_matrix.png")
plt.savefig(tree_cm_path)
print(f"결정 트리 혼동 행렬 저장 완료: {tree_cm_path}")
plt.close()
print("-" * 30)
\ No newline at end of file
# Part 7.5: LLM 애플리케이션 개발 실습 (LangChain)
# 이 스크립트를 실행하기 전에 라이브러리를 설치해야 합니다.
# pip install langchain langchain_community faiss-cpu sentence-transformers
import os
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain.chains import LLMChain
from langchain_core.prompts import PromptTemplate
# --- 모의(Mock) 객체 ---
# 실제 환경에서는 HuggingFaceEmbeddings, ChatOllama 등 실제 모델을 사용해야 합니다.
# 여기서는 API 키나 모델 다운로드 없이 실행 가능하도록 간단한 모의 객체를 사용합니다.
from langchain.embeddings.base import Embeddings
from langchain.llms.base import LLM
from typing import List, Any, Optional, Dict
class MockEmbeddings(Embeddings):
"""간단한 모의 임베딩 클래스"""
def embed_documents(self, texts: List[str]) -> List[List[float]]:
# 각 텍스트의 길이를 기반으로 간단한 벡터 생성
return [[len(text) / 10] for text in texts]
def embed_query(self, text: str) -> List[float]:
# 쿼리의 길이를 기반으로 간단한 벡터 생성
return [len(text) / 10]
class MockLLM(LLM):
"""간단한 모의 LLM 클래스"""
@property
def _llm_type(self) -> str:
return "mock"
def _call(self, prompt: str, stop: Optional[List[str]] = None, **kwargs: Any) -> str:
return f"모의 LLM이 응답합니다: '{prompt}'라는 질문을 받았습니다."
@property
def _identifying_params(self) -> Dict[str, Any]:
return {"name": "mock_llm"}
# --- 1. 문서 준비 및 로드 ---
print("--- 1. 문서 준비 및 로드 ---")
# 실습을 위한 간단한 텍스트 파일 생성
doc_content = """
인공지능(AI)은 인간의 학습능력, 추론능력, 지각능력을 인공적으로 구현하려는 컴퓨터 과학의 한 분야입니다.
머신러닝은 AI의 하위 분야로, 기계가 데이터로부터 학습하여 스스로 성능을 향상시키는 기술을 의미합니다.
딥러닝은 머신러닝의 한 종류로, 인공신경망(Artificial Neural Network)을 기반으로 합니다.
최근에는 거대 언어 모델(LLM)이 큰 주목을 받고 있으며, 이는 방대한 텍스트 데이터로 사전 학습된 모델입니다.
RAG(Retrieval-Augmented Generation)는 LLM이 외부 지식 베이스를 참조하여 답변을 생성하는 기술입니다.
"""
doc_path = "sample_document.txt"
with open(doc_path, "w", encoding="utf-8") as f:
f.write(doc_content)
# TextLoader로 문서 로드
loader = TextLoader(doc_path, encoding="utf-8")
documents = loader.load()
print("문서 로드 완료.")
# print(documents)
print("-" * 30)
# --- 2. 문서 분할 (Splitting) ---
print("\n--- 2. 문서 분할 ---")
text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=20)
docs = text_splitter.split_documents(documents)
print(f"{len(docs)}개의 조각(chunk)으로 분할되었습니다.")
# print(docs[0])
print("-" * 30)
# --- 3. 임베딩 및 벡터 저장소 생성 (Embedding & Vector Store) ---
print("\n--- 3. 임베딩 및 벡터 저장소 생성 ---")
# 실제 환경: from langchain_community.embeddings import HuggingFaceEmbeddings
# embeddings = HuggingFaceEmbeddings(model_name="jhgan/ko-sbert-nli")
embeddings = MockEmbeddings()
print(f"사용한 임베딩 모델: {type(embeddings).__name__}")
# FAISS 벡터 저장소에 문서 임베딩하여 저장
# from_documents: 문서 목록을 받아 임베딩을 수행하고 인덱스를 빌드
vectorstore = FAISS.from_documents(docs, embeddings)
print("FAISS 벡터 저장소 생성 완료.")
print("-" * 30)
# --- 4. 검색 (Retrieval) ---
print("\n--- 4. 검색 ---")
query = "RAG 기술이란 무엇인가요?"
# similarity_search: 쿼리와 가장 유사한 문서를 벡터 공간에서 검색
retrieved_docs = vectorstore.similarity_search(query, k=1)
retrieved_text = retrieved_docs[0].page_content
print(f"쿼리: '{query}'")
print(f"검색된 문서: '{retrieved_text}'")
print("-" * 30)
# --- 5. 생성 (Generation) - LLM Chain 활용 ---
print("\n--- 5. 생성 (RAG) ---")
# 실제 환경: from langchain_community.chat_models import ChatOllama
# llm = ChatOllama(model="llama3")
llm = MockLLM()
print(f"사용한 LLM: {llm._identifying_params['name']}")
# 프롬프트 템플릿 정의
# 검색된 문서를 'context'로, 사용자의 질문을 'question'으로 받아 프롬프트를 구성
prompt_template = """
주어진 컨텍스트를 바탕으로 질문에 답변해주세요.
컨텍스트: {context}
질문: {question}
답변:
"""
prompt = PromptTemplate.from_template(prompt_template)
# LLMChain 생성
llm_chain = LLMChain(llm=llm, prompt=prompt)
# 검색된 문서와 원본 질문을 이용해 답변 생성
result = llm_chain.invoke({
"context": retrieved_text,
"question": query
})
print("\n--- 최종 결과 ---")
print(f"질문: {result['question']}")
print(f"제공된 컨텍스트: {result['context']}")
print(f"생성된 답변: {result['text']}")
print("-" * 30)
# 임시 파일 삭제
os.remove(doc_path)
\ No newline at end of file
# Part 7: 딥러닝 기초 실습 (PyTorch)
# 이 스크립트를 실행하기 전에 라이브러리를 설치해야 합니다.
# pip install torch torchvision scikit-learn
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score
import numpy as np
# --- 1. 데이터 준비 및 전처리 ---
print("--- 1. 데이터 준비 및 전처리 ---")
# Scikit-learn에 내장된 붓꽃(Iris) 데이터셋 로드
iris = load_iris()
X = iris.data
y = iris.target
# 훈련/테스트 데이터 분리
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
# 데이터 스케일링
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# PyTorch 텐서로 변환
X_train_tensor = torch.FloatTensor(X_train_scaled)
y_train_tensor = torch.LongTensor(y_train)
X_test_tensor = torch.FloatTensor(X_test_scaled)
y_test_tensor = torch.LongTensor(y_test)
# DataLoader 생성
# 딥러닝 모델은 보통 미니배치 단위로 학습하므로 DataLoader를 사용
train_dataset = TensorDataset(X_train_tensor, y_train_tensor)
train_loader = DataLoader(dataset=train_dataset, batch_size=16, shuffle=True)
print("PyTorch 텐서 및 DataLoader 준비 완료")
print(f"훈련 데이터 크기: {X_train_tensor.shape}")
print(f"훈련 타겟 크기: {y_train_tensor.shape}")
print("-" * 30)
# --- 2. 딥러NING 모델 정의 ---
print("\n--- 2. 딥러닝 모델 정의 ---")
class SimpleNN(nn.Module):
def __init__(self, input_size, hidden_size, num_classes):
super(SimpleNN, self).__init__()
self.fc1 = nn.Linear(input_size, hidden_size)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(hidden_size, num_classes)
def forward(self, x):
out = self.fc1(x)
out = self.relu(out)
out = self.fc2(out)
return out
# 모델 파라미터 설정
input_size = X_train.shape[1] # 특성의 수: 4
hidden_size = 32
num_classes = len(np.unique(y_train)) # 클래스의 수: 3
learning_rate = 0.01
num_epochs = 50
model = SimpleNN(input_size, hidden_size, num_classes)
print("모델 구조:")
print(model)
print("-" * 30)
# --- 3. 손실 함수 및 옵티마이저 정의 ---
print("\n--- 3. 손실 함수 및 옵티마이저 정의 ---")
# 다중 분류 문제이므로 CrossEntropyLoss 사용
criterion = nn.CrossEntropyLoss()
# Adam 옵티마이저 사용
optimizer = optim.Adam(model.parameters(), lr=learning_rate)
print(f"손실 함수: {criterion}")
print(f"옵티마이저: {optimizer}")
print("-" * 30)
# --- 4. 모델 훈련 ---
print("\n--- 4. 모델 훈련 ---")
for epoch in range(num_epochs):
for i, (features, labels) in enumerate(train_loader):
# 순전파 (Forward pass)
outputs = model(features)
loss = criterion(outputs, labels)
# 역전파 및 최적화 (Backward and optimize)
optimizer.zero_grad() # 이전 그래디언트 초기화
loss.backward() # 그래디언트 계산
optimizer.step() # 가중치 업데이트
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')
print("모델 훈련 완료")
print("-" * 30)
# --- 5. 모델 평가 ---
print("\n--- 5. 모델 평가 ---")
# 모델을 평가 모드로 설정 (dropout, batchnorm 등 비활성화)
model.eval()
# 테스트 데이터로 예측
with torch.no_grad(): # 그래디언트 계산 비활성화
outputs = model(X_test_tensor)
# 가장 높은 확률을 가진 클래스를 예측값으로 선택
_, predicted = torch.max(outputs.data, 1)
accuracy = accuracy_score(y_test_tensor.numpy(), predicted.numpy())
print(f'테스트 데이터 정확도: {100 * accuracy:.2f}%')
# 일부 예측 결과 확인
print("\n일부 샘플 예측 결과:")
print(f"실제 값: {y_test_tensor[:10].numpy()}")
print(f"예측 값: {predicted[:10].numpy()}")
print("-" * 30)
\ No newline at end of file
# api.py
# API 엔드포인트의 실제 로직을 정의합니다.
from fastapi import APIRouter, HTTPException
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
import numpy as np
from . import schemas # 현재 패키지(디렉터리)의 schemas 모듈을 임포트
# --- 모델 준비 ---
# 실제 프로덕션 환경에서는 미리 학습되고 저장된 모델 파일(e.g., .joblib, .pkl)을 로드해야 합니다.
# 여기서는 실습 편의를 위해 서버 시작 시 간단한 모델을 학습시켜 메모리에 올립니다.
iris = load_iris()
X = iris.data
y = iris.target
# 간단한 결정 트리 모델 훈련
model = DecisionTreeClassifier(max_depth=3, random_state=42)
model.fit(X, y)
model_info = {
"name": "Iris Species Predictor",
"version": "1.0",
"description": "A simple Decision Tree classifier for Iris species."
}
print(f"'{model_info['name']}' 모델이 준비되었습니다.")
# --- API 라우터 설정 ---
# APIRouter를 사용하면 엔드포인트를 모듈화하여 관리할 수 있습니다.
router = APIRouter()
@router.get("/model", response_model=schemas.ModelInfo)
async def get_model_info():
"""로드된 머신러닝 모델의 정보를 반환합니다."""
return model_info
@router.post("/predict", response_model=schemas.IrisPrediction)
async def predict_species(iris_input: schemas.IrisInput):
"""
붓꽃의 특성(sepal/petal length/width)을 입력받아 품종을 예측합니다.
- **입력**: 붓꽃의 4가지 특성 (JSON)
- **출력**: 예측된 품종 이름과 클래스 번호 (JSON)
"""
try:
# Pydantic 모델에서 받은 입력을 numpy 배열로 변환
input_data = np.array([[
iris_input.sepal_length,
iris_input.sepal_width,
iris_input.petal_length,
iris_input.petal_width
]])
# 모델 예측
prediction_value = model.predict(input_data)
predicted_class_index = int(prediction_value[0])
# 예측된 클래스 인덱스에 해당하는 품종 이름 찾기
predicted_species_name = iris.target_names[predicted_class_index]
return schemas.IrisPrediction(
species_name=predicted_species_name,
prediction=predicted_class_index
)
except Exception as e:
# 예외 발생 시, 서버 에러(500)와 함께 상세 내용을 반환
raise HTTPException(status_code=500, detail=str(e))
\ No newline at end of file
# main.py
# FastAPI 애플리케이션을 생성하고, 라우터를 포함시켜 서버를 실행하는 진입점입니다.
import uvicorn
from fastapi import FastAPI
from . import api # api.py에서 정의한 라우터를 임포트
# FastAPI 앱 인스턴스 생성
app = FastAPI(
title="AI 모델 서빙 API",
description="머신러닝 모델을 서빙하기 위한 FastAPI 기반 API입니다.",
version="1.0.0"
)
# 루트 경로
@app.get("/")
async def root():
return {"message": "AI 모델 서빙 API에 오신 것을 환영합니다. /docs 로 이동하여 API 문서를 확인하세요."}
# api.py에서 정의한 라우터를 앱에 포함
# prefix="/api/v1"을 설정하여 모든 관련 엔드포인트가 이 경로 하위에 위치하도록 함
app.include_router(api.router, prefix="/api/v1", tags=["Iris Prediction"])
# 이 파일이 직접 실행될 때 uvicorn 서버를 시작합니다.
# 터미널에서 `python main.py`를 실행하거나,
# `uvicorn part_8_fastapi_project.main:app --reload` 명령어로 실행할 수 있습니다.
if __name__ == "__main__":
uvicorn.run(
"part_8_fastapi_project.main:app",
host="0.0.0.0",
port=8000,
reload=True
)
\ No newline at end of file
fastapi
uvicorn
pydantic
scikit-learn
numpy
\ No newline at end of file
# schemas.py
# API의 요청(Request) 및 응답(Response) 데이터 형식을 정의합니다.
from pydantic import BaseModel
from typing import List, Optional
class IrisInput(BaseModel):
"""붓꽃 예측을 위한 입력 데이터 형식"""
sepal_length: float
sepal_width: float
petal_length: float
petal_width: float
class Config:
# Pydantic 모델이 API 문서에 예시로 보일 때 사용될 값
json_schema_extra = {
"example": {
"sepal_length": 5.1,
"sepal_width": 3.5,
"petal_length": 1.4,
"petal_width": 0.2
}
}
class IrisPrediction(BaseModel):
"""붓꽃 예측 결과 형식"""
species_name: str
prediction: int
class ModelInfo(BaseModel):
"""현재 로드된 모델의 정보를 담는 형식"""
name: str
version: str
description: str
\ No newline at end of file
# Dockerfile
# 1. 베이스 이미지 설정
# 공식 Python 3.9 슬림 버전을 사용하여 이미지 크기를 최적화합니다.
FROM python:3.9-slim
# 2. 작업 디렉터리 설정
# 컨테이너 내에서 작업이 수행될 기본 경로를 설정합니다.
WORKDIR /app
# 3. 환경 변수 설정
# 파이썬이 .pyc 파일을 생성하지 않도록 하고, 버퍼링을 비활성화하여 로그가 즉시 출력되도록 합니다.
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# 4. 의존성 설치
# 먼저 의존성 정의 파일만 복사하여 설치합니다.
# 이렇게 하면 소스 코드가 변경되어도 의존성이 동일한 경우 Docker 캐시를 활용하여 빌드 속도를 높일 수 있습니다.
COPY requirements.txt .
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir -r requirements.txt
# 5. 애플리케이션 코드 복사
# 로컬의 app 디렉터리에 있는 모든 소스 코드를 컨테이너의 /app/app 디렉터리로 복사합니다.
COPY ./app /app/app
# 6. 포트 노출
# 애플리케이션이 컨테이너의 8000번 포트에서 실행될 것임을 명시합니다.
EXPOSE 8000
# 7. 서버 실행 명령어
# Gunicorn을 사용하여 FastAPI 애플리케이션을 실행합니다.
# -w 4: 4개의 워커 프로세스를 사용합니다. (CPU 코어 수에 따라 조절)
# -k uvicorn.workers.UvicornWorker: Uvicorn 호환 워커 클래스를 사용합니다.
# app.main:app: app/main.py 파일의 app 인스턴스를 의미합니다.
# -b 0.0.0.0:8000: 모든 네트워크 인터페이스의 8000번 포트에 바인딩합니다.
CMD ["gunicorn", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "app.main:app", "-b", "0.0.0.0:8000"]
\ No newline at end of file
# This file makes the 'app' directory a Python package.
\ No newline at end of file
# app/api.py
from fastapi import APIRouter, HTTPException
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
import numpy as np
from . import schemas
# Model Preparation
iris = load_iris()
X = iris.data
y = iris.target
model = DecisionTreeClassifier(max_depth=3, random_state=42)
model.fit(X, y)
model_info = {
"name": "Iris Species Predictor",
"version": "1.0",
"description": "A simple Decision Tree classifier for Iris species."
}
print(f"'{model_info['name']}' model is ready.")
# API Router
router = APIRouter()
@router.get("/model", response_model=schemas.ModelInfo)
async def get_model_info():
"""Returns information about the loaded machine learning model."""
return model_info
@router.post("/predict", response_model=schemas.IrisPrediction)
async def predict_species(iris_input: schemas.IrisInput):
"""
Predicts the species of an Iris flower based on its features.
- **Input**: Four features of the Iris flower (JSON).
- **Output**: Predicted species name and class index (JSON).
"""
try:
input_data = np.array([[
iris_input.sepal_length,
iris_input.sepal_width,
iris_input.petal_length,
iris_input.petal_width
]])
prediction_value = model.predict(input_data)
predicted_class_index = int(prediction_value[0])
predicted_species_name = iris.target_names[predicted_class_index]
return schemas.IrisPrediction(
species_name=predicted_species_name,
prediction=predicted_class_index
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
\ No newline at end of file
# app/main.py
import uvicorn
from fastapi import FastAPI
from . import api
app = FastAPI(
title="Production-Ready AI Model API",
description="A production-ready API for serving ML models using FastAPI and Docker.",
version="2.0.0"
)
@app.get("/")
async def root():
return {"message": "Welcome to the Production-Ready AI API. See /docs for documentation."}
app.include_router(api.router, prefix="/api/v1", tags=["Iris Prediction"])
# Note: The uvicorn.run() part is typically removed for production,
# as the server will be started by a process manager like Gunicorn or Uvicorn directly
# from the command line, as defined in the Dockerfile.
# We keep it here for consistency in the course material.
if __name__ == "__main__":
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True, app_dir="/app")
\ No newline at end of file
# app/schemas.py
from pydantic import BaseModel
from typing import List, Optional
class IrisInput(BaseModel):
sepal_length: float
sepal_width: float
petal_length: float
petal_width: float
class Config:
json_schema_extra = {
"example": {
"sepal_length": 5.1,
"sepal_width": 3.5,
"petal_length": 1.4,
"petal_width": 0.2
}
}
class IrisPrediction(BaseModel):
species_name: str
prediction: int
class ModelInfo(BaseModel):
name: str
version: str
description: str
\ No newline at end of file
# docker-compose.yml
version: '3.8'
services:
# 서비스 이름 (임의로 지정 가능)
fastapi-service:
# 빌드 컨텍스트: 현재 디렉터리(.)의 Dockerfile을 사용하여 이미지를 빌드
build: .
# 컨테이너 이름
container_name: production_api_server
# 포트 매핑: 호스트의 8000번 포트를 컨테이너의 8000번 포트와 연결
ports:
- "8000:8000"
# 재시작 정책: 컨테이너가 예기치 않게 종료될 경우 항상 다시 시작
restart: always
# 환경 설정 (필요시 추가)
# environment:
# - KEY=VALUE
\ No newline at end of file
# requirements.txt
fastapi
uvicorn
# Gunicorn is a popular choice for running python web applications in production
gunicorn
scikit-learn
numpy
\ 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