در دنیای یادگیری ماشین، زمانی می‌توان گفت یک مدل ارزش واقعی دارد که بتواند در اختیار کاربران قرار گیرد. این کار معمولاً با ساخت یک API انجام می‌شود تا برنامه‌های دیگر بتوانند از مدل استفاده کنند. در این آموزش، گام به گام یاد می‌گیریم چگونه یک FastAPI machine learning API امن بسازیم که از احراز هویت JWT، اعتبارسنجی ورودی و محدودسازی نرخ درخواست‌ها پشتیبانی کند و در نهایت با Docker به‌صورت قابل استقرار درآید.

چرا FastAPI بهترین گزینه برای API های یادگیری ماشین است

FastAPI یکی از سریع‌ترین و مدرن‌ترین فریمورک‌های پایتون است. پشتیبانی از async/await، مستندسازی خودکار و سازگاری با تایپ‌هینت‌ها باعث شده برای ساخت API امن یادگیری ماشین ایده‌آل باشد. سرعت بالا و سادگی آن، زمان توسعه و نگهداری را به‌طور چشمگیری کاهش می‌دهد.

مرحله 1: آموزش و ذخیره مدل یادگیری ماشین

ابتدا یک مدل ساده بر پایه داده‌های معروف Iris ایجاد می‌کنیم. مدل را با RandomForestClassifier آموزش داده و سپس آن را ذخیره می‌کنیم تا در برنامه اصلی بارگذاری شود.

📄 فایل: app/model.py

import pickle
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
# تابع آموزش مدل
def train_model():
iris = load_iris()
X, y = iris.data, iris.target
clf = RandomForestClassifier()
clf.fit(X, y)# ذخیره مدل به صورت فایل pickle
with open(“app/model.pkl”, “wb”) as f:
pickle.dump(clf, f)if __name__ == “__main__”:
train_model()

اجرای این فایل باعث ایجاد مدل ذخیره‌شده‌ی model.pkl در مسیر app/ می‌شود.

مرحله 2: پیاده‌سازی منطق پیش‌بینی

اکنون ماژولی برای بارگذاری مدل و انجام پیش‌بینی می‌سازیم.

📄 فایل: app/predict.py

import pickle
import numpy as np
# بارگذاری مدل ذخیره شده
with open(“app/model.pkl”, “rb”) as f:
model = pickle.load(f)# تابع پیش‌بینی
def make_prediction(data):
arr = np.array(data).reshape(1, –1)
return int(model.predict(arr)[0])

تابع make_prediction() یک لیست شامل 4 عدد می‌گیرد و کلاس گل مورد نظر را پیش‌بینی می‌کند.

مرحله 3: اعتبارسنجی ورودی با Pydantic

ورودی کاربران باید بررسی شود تا داده‌های نادرست وارد مدل نشود.

📄 فایل: app/validation.py

from pydantic import BaseModel, field_validator
from typing import List
class PredictionInput(BaseModel):
data: List[float] @field_validator(“data”)
@classmethod
def check_length(cls, v):
if len(v) != 4:
raise ValueError(“data must contain exactly 4 float values”)
return vclass Config:
json_schema_extra = {
“example”: {
“data”: [5.1, 3.5, 1.4, 0.2]
}
}

به کمک Pydantic مطمئن می‌شویم که کاربر دقیقاً چهار عدد ارسال کرده است.

مرحله 4: افزودن احراز هویت JWT

برای جلوگیری از دسترسی غیرمجاز از JWT استفاده می‌کنیم.

📄 فایل: app/jwt.py

import jwt
import os
from datetime import datetime, timedelta
from fastapi import HTTPException, status, Depends
from fastapi.security import OAuth2PasswordBearer
SECRET_KEY = os.getenv(“SECRET_KEY”, “mysecretkey”)
ALGORITHM = “HS256”
ACCESS_TOKEN_EXPIRE_MINUTES = 30
oauth2_scheme = OAuth2PasswordBearer(tokenUrl=“token”)def create_access_token(data: dict, expires_delta: timedelta = None):
expire = datetime.utcnow() + (expires_delta or timedelta(minutes=15))
to_encode = data.copy()
to_encode.update({“exp”: expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)def verify_token(token: str = Depends(oauth2_scheme)):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
return payload
except jwt.PyJWTError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=“Invalid token”,
)

این فایل شامل توابع ساخت و بررسی توکن JWT است.

مرحله 5: محدودسازی نرخ درخواست‌ها

برای جلوگیری از overload شدن سرور از Rate Limiting استفاده می‌کنیم.

📄 فایل: app/rate_limit.py

import time
from fastapi import Request, HTTPException
from starlette.middleware.base import BaseHTTPMiddleware
class RateLimitMiddleware(BaseHTTPMiddleware):
def __init__(self, app, throttle_rate: int = 60):
super().__init__(app)
self.throttle_rate = throttle_rate
self.request_log = {}async def dispatch(self, request: Request, call_next):
client_ip = request.client.host
now = time.time()# حذف لاگ‌های قدیمی‌تر از ۶۰ ثانیه
self.request_log = {
ip: [t for t in times if t > now – 60]
for ip, times in self.request_log.items()
}

ip_history = self.request_log.get(client_ip, [])
if len(ip_history) >= self.throttle_rate:
raise HTTPException(status_code=429, detail=“Too many requests”)

ip_history.append(now)
self.request_log[client_ip] = ip_history

return await call_next(request)

این کد باعث می‌شود هر IP در هر دقیقه حداکثر تعداد مشخصی درخواست ارسال کند.

مرحله 6: ترکیب همه اجزا در FastAPI

اکنون تمام قسمت‌ها را در فایل اصلی ترکیب می‌کنیم.

📄 فایل: app/main.py

from fastapi import FastAPI, Depends
from app.predict import make_prediction
from app.jwt import verify_token, create_access_token, ACCESS_TOKEN_EXPIRE_MINUTES
from app.rate_limit import RateLimitMiddleware
from app.validation import PredictionInput
from datetime import timedelta
app = FastAPI()# افزودن Rate Limiting برای هر IP
app.add_middleware(RateLimitMiddleware, throttle_rate=5)@app.get(“/”)
def root():
return {“message”: “Welcome to the Secure Machine Learning API”}

@app.post(“/token”)
def login():
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(data={“sub”: “user”}, expires_delta=access_token_expires)
return {“access_token”: access_token, “token_type”: “bearer”}

@app.post(“/predict”)
def predict(input_data: PredictionInput, token: str = Depends(verify_token)):
prediction = make_prediction(input_data.data)
return {“prediction”: prediction}

مرحله 7: Dockerfile برای استقرار

فایل: Dockerfile

FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install –upgrade pip && pip install –no-cache-dir -r requirements.txtCOPY ./app ./appCMD [“python”, “-m”, “uvicorn”, “app.main:app”, “–host”, “0.0.0.0”, “–port”, “8000”]

فایل: requirements.txt

scikit-learn
numpy
python-dotenv
pyjwt
fastapi
uvicorn
pydantic
starlette

مرحله 8: اجرای Docker

docker build -t secure-ml-api .
docker run -p 8000:8000 secure-ml-api

سپس API در آدرس http://localhost:8000 در دسترس است.

مرحله 9: تست API

ابتدا توکن JWT را دریافت کنید:

curl -X POST http://localhost:8000/token

سپس از آن برای پیش‌بینی استفاده کنید:

curl -X POST http://localhost:8000/predict \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{"data": [5.1, 3.5, 1.4, 0.2]}'

پاسخ مشابه زیر خواهد بود:

{"prediction": 0}

جمع بندی

ساخت API امن یادگیری ماشین شامل آموزش مدل، تعریف مسیرهای پیش‌بینی، احراز هویت JWT، اعتبارسنجی داده‌ها و محدودسازی نرخ است. در نهایت، Docker محیطی استاندارد برای استقرار آن فراهم می‌کند. این روش باعث می‌شود مدل یادگیری ماشین شما نه تنها دقیق، بلکه قابل اعتماد و آماده برای استفاده در دنیای واقعی باشد.