1. FastAPI
FastAPI는 Python으로 웹 API를 빠르고 쉽게 개발할 수 있도록 도와주는 웹 프레임워크.
Python 3.6 버전부터 지원하며, Type Annotation 방식을('@') 사용함.
비동기 서버 게이트웨이 인터페이스 (ASGI; Asynchronous Server Gateway Interface) 서버 프레임워크를
기반으로 구축되어 빠른 속도와 비동기 처리, 자동 스웨거(Swagger) 기능을 지원함.
관련내용 웹사이트
1-07 안녕하세요 파이보
* `[완성 소스]` : [https://github.com/pahkey/fastapi-book/tree/v1.07](https://github.com/pahkey/fastapi…
wikidocs.net
특징:
1) 빠른 속도: FastAPI는 CPython 기반의 특정 최적화 기법을 사용하여 높은 성능을 제공함.
2) 사용하기 쉬운 API: FastAPI는 직관적인 구문과 타입 힌트를 통해 빠르게 API를 작성할 수 있도록 도와줌.
3) 비동기 지원: 비동기 프로그래밍을 통해 I/O 바운드 작업에서 더 높은 처리량을 달성할 수 있음.
4) 자동 문서화: 자동으로 API 엔드포인트를 문서화하여 API의 사용 방법을 쉽게 확인할 수 있도록 함.
6) 통합성: 기존 코드를 재사용하면서도 빠르게 API를 개발할 수 있음.
라이브러리 vs 프레임워크 1) Framework(프레임워크) 프레임워크는 뼈대나 기반구조를 뜻하고, 제어의 역전 개념이 적용된 대표적인 기술. 소프트웨어에서의 프레임워크는 'SW의 특정 문제를 해결하기 위해서 상호 협력하는 클래스와 인터페이스의 집합' 이라 할 수 있으며, 완성된 어플리케이션이 아닌 프로그래머가 완성시키는 작업을 해야합니다. 객체 지향 개발을 하게 되면서 통합성, 일관성의 부족이 발생되는 문제를 해결할 방법중 하나라고 할 수 있습니다. 프레임워크의 특징: 특정 개념들의 추상화를 제공하는 여러 클래스나 컴포넌트로 구성되어 있음. 추상적인 개념들이 문제를 해결하기 위해 같이 작업하는 방법을 정의함. 컴포넌트들은 재사용이 가능함. 높은 수준에서 패턴들을 조작화 할 수 있음. 2) 라이브러리(Library) 라이브러리는 단순 활용가능한 도구들의 집합을 의미. 즉, 개발자가 만든 클래스에서 호출하여 사용, 클래스들의 나열로 필요한 클래스를 불러서 사용하는 방식을 취하고 있음. 3) 차이점 제어 흐름에 대한 주도성이 누구에게/어디에 있는가, 즉 어플리케이션의 Flow(흐름)를 누가 쥐고 있느냐에 달려 있음. 프레임워크는 전체적인 흐름을 스스로가 쥐고 있으며 사용자는 그 안에서 필요한 코드를 짜 넣음. 반면에 라이브러리는 사용자가 전체적인 흐름을 만들며 가져다 쓰는 것이라고 할 수 있음. 다시 말해, 라이브러리는 라이브러리를 가져다가 사용하고 호출하는 측에 전적으로 주도성이 있으며 프레임워크는 그 틀안에 이미 제어 흐름에 대한 주도성이 내재(내포)하고 있음. 프레임워크는 가져다가 사용한다기보다는 거기에 들어가서 사용한다는 느낌/관점으로 접근할 수 있음. |
// 터미널에 작성
pip install fastapi
2. Uvicorn
ASGI(Asynchronous Server Gateway interface) 서버의 일종.
비동기처리를 지원하며, 높은 성능을 발휘할 수 있음.
FastAPI뿐만 아니라 Node와도 함께 사용할 수 있는 모듈.
멀티스레드 방식보다 더욱 빠른 속도를 보장.
Swagger와 같은 API 문서 자동화 기능을 제공.
API 개발시 생산성을 높일 수 있음.
pip install "uvicorn[standard]"
app.py 파일에 정의된 ASGI 웹 애플리케이션을 실행함.
코드 변경 시 자동으로 서버를 다시 시작함
앞의 'app'은 파일명으로, 임의로 변경이 가능함
uvicorn app:app --reload
정상적인 실행 상태
from fastapi import FastAPI
import torch
import torch.nn as nn
import torch.optim as optim
app = FastAPI()
@app.get("/")
def index():
return {"index": "Hello FastAPI"} # 출력은 중괄호
@app.get("/math/sum")
def math_sum(num1:int, num2:int):
return {"result":num1+num2}
3. FastAPI + Uvicorn으로 Serving
<model.py> 파일
import torch
import torch.nn as nn
import torch.optim as optim
x_train = torch.FloatTensor([[73, 80, 75],
[93, 88, 93],
[89, 91, 90],
[96, 98, 100],
[73, 66, 70]])
y_train = torch.FloatTensor([[152], [185], [180], [196], [142]])
model = nn.Linear(3, 1)
optimizer = optim.SGD(model.parameters(), lr=0.00001)
epochs = 1000
for epoch in range(epochs + 1):
y_pred = model(x_train)
loss = nn.MSELoss()(y_pred, y_train)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if epoch % 100 == 0:
print(f'Epoch {epoch}/{epoch} Loss:{loss:.6f}')
torch.save(model.state_dict(), 'model.pth')
<app.py> 파일
import torch
import torch.nn as nn
from fastapi import FastAPI, Request
app = FastAPI()
model = nn.Linear(3, 1)
model.load_state_dict(torch.load('model.pth'))
model.eval()
@app.post("/predict/")
async def predict(request: Request):
data = await request.json()
data = data["data"]
x_test = torch.FloatTensor(data)
y_pred = model(x_test)
return {
"pred": y_pred.tolist()
}
Postman으로 확인
자동 스웨거(Swagger): 자동 스웨거 기능은 API 개발 시 자동으로 API 문서를 생성하는 기능을 말함. 스웨거는 OpenAPI Specification을 기반으로 API 문서를 작성하는 도구로서, API의 사용 방법과 엔드포인트들에 대한 정보를 사람이 읽을 수 있는 형식으로 제공함. 자동 스웨거 기능을 사용하면 API를 설계하고 구현하는 동시에, 해당 API에 대한 문서화 작업을 수동으로 처리하지 않아도 됨. API 개발자가 API의 엔드포인트, 인풋과 아웃풋의 형식, 파라미터, 요청과 응답의 예시 등을 코드와 주석으로 작성하면, 자동 스웨거 기능이 이 정보들을 수집하여 API 문서를 자동으로 생성함. |
FastAPI의 자동스웨거 기능을 통해 제공되는 API 문서
문서에서 server 테스트가 가능 → Postman에서의 확인이 따로 필요 없다는 장점이 있음
127.0.0.1:8000/docs 입력 시 확인이 가능함
맨 처음 'Hello FastAPI'를 입력했을 때의 '/'에 대한 API를 불러옴
자동으로 json 형태의 응답으로 리턴함.
<참고>
4. Flask로 Serving
<model.py> 파일
import torch
import torch.nn as nn
import torch.optim as optim
x_train = torch.FloatTensor([[73, 80, 75],
[93, 88, 93],
[89, 91, 90],
[96, 98, 100],
[73, 66, 70]])
y_train = torch.FloatTensor([[152], [185], [180], [196], [142]])
model = nn.Linear(3, 1)
optimizer = optim.SGD(model.parameters(), lr=0.00001)
epochs = 1000
for epoch in range(epochs + 1):
y_pred = model(x_train)
loss = nn.MSELoss()(y_pred, y_train)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if epoch % 100 == 0:
print(f'Epoch {epoch}/{epoch} Loss:{loss:.6f}')
torch.save(model.state_dict(), 'model.pth')
<app.py> 파일
from flask import Flask, request, jsonify
import torch
import torch.nn as nn
app = Flask(__name__)
model = nn.Linear(3, 1)
model.load_state_dict(torch.load('model.pth'))
model.eval()
@app.route('/predict', methods=['POST'])
def predict():
data = request.json['data']
x_test = torch.FloatTensor(data)
y_pred = model(x_test)
return jsonify(y_pred.tolist())
if __name__ == '__main__':
app.run(debug=True)