사용자의 모델을 ThanoSQL에서 사용하기¶
- 튜토리얼 난이도: ★★☆☆☆
- 읽는데 걸리는 시간: 10분
- 사용 언어: SQL (50%), Python (50%)
- 실행 파일 위치: tutorial/thanosql_ml/udm_tutorial.ipynb
- 참고 문서: Beans 데이터 세트
튜토리얼 소개¶
해당 기능은 유료 버전에서 원할하게 작동합니다.
ThanoSQL에서는 사용자가 만들거나 가지고 있는 모델에 대하여 ThanoSQL 워크스페이스와 데이터베이스에 올리고 예측에 사용할 수 있는 기능을 제공하고 있습니다.
본 튜토리얼에서는
👉 beans 데이터 세트는 우간다의 농업 연구를 담당하는 국가 기관인 국립 작물 자원 연구소(NaCRRI)와 협력하여 Makerere AI 연구소가 우간다의 여러 지역에서 현장에서 촬영한 잎 이미지입니다. 데이터는 총 3개의 클래스로 구성되어 있습니다. 2개의 질병 클래스와 건강 클래스이고, 질병은 각각 세균모무늬병(Angular leaf spot)과 콩 녹병(Bean rust)입니다. 본 튜토리얼에서는 이미지 분류 모델을 학습시켜서 사용자 모델을 만든 후 ThanoSQL에 올리고 예측해 봅니다.
#. 파이썬을 이용한 데이터 세트 및 모델 준비¶
데이터 세트 준비¶
데이터 다운로드 및 압축풀기¶
import os
from shutil import unpack_archive
from urllib.request import urlretrieve
url = "https://storage.googleapis.com/ibeans"
for split in ["train", "validation", "test"]:
urlretrieve(f"{url}/{split}.zip", f"{split}.zip")
unpack_archive(f"{split}.zip", ".")
os.remove(f"{split}.zip")
패키지 설치¶
!pip install torch torchvision
from torch.utils.data import DataLoader
from torchvision import transforms as T
from torchvision.datasets import ImageFolder
data_transforms = {
"train": T.Compose(
[
T.RandomResizedCrop(224),
T.RandomHorizontalFlip(),
T.ToTensor(),
T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
]
),
"validation": T.Compose(
[
T.Resize(224),
T.CenterCrop(224),
T.ToTensor(),
T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
]
),
}
image_datasets = {
split: ImageFolder(split, data_transforms[split])
for split in ["train", "validation"]
}
dataloaders = {
split: DataLoader(image_datasets[split], batch_size=8, shuffle=split == "train")
for split in ["train", "validation"]
}
dataset_sizes = {split: len(image_datasets[split]) for split in ["train", "validation"]}
모델 준비¶
모델 학습 코드 작성하기¶
import time
import copy
import torch
def train_model(model, criterion, optimizer, num_epochs=3):
start_time = time.time()
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
best_model_weights = copy.deepcopy(model.state_dict())
best_acc = 0.0
for epoch in range(num_epochs):
print(f"Epoch {epoch}/{num_epochs - 1}")
print("-" * 10)
# 각 에폭(epoch)은 학습 단계와 검증 단계를 갖습니다.
for phase in ["train", "validation"]:
if phase == "train":
model.train()
else:
model.eval()
running_loss = 0.0
running_corrects = 0
for inputs, labels in dataloaders[phase]:
inputs = inputs.to(device)
labels = labels.to(device)
# 매개변수 경사도를 0으로 설정
optimizer.zero_grad()
# 순전파
# 학습 단계에서만 연산 기록을 추적
with torch.set_grad_enabled(phase == "train"):
outputs = model(inputs)
preds = torch.argmax(outputs, dim=1)
loss = criterion(outputs, labels)
# 학습 단계인 경우에만 역전파
if phase == "train":
loss.backward()
optimizer.step()
# 통계
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels.data)
epoch_loss = running_loss / dataset_sizes[phase]
epoch_acc = running_corrects / dataset_sizes[phase]
print(f"{phase} Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}")
# 모델의 정확도가 기존의 최고 정확도보다 높다면 저장
if phase == "validation" and epoch_acc > best_acc:
best_acc = epoch_acc
best_model_weights = copy.deepcopy(model.state_dict())
print()
time_elapsed = time.time() - start_time
print(f"Training complete in {time_elapsed // 60:.0f}m {time_elapsed % 60:.0f}s")
print(f"Best val Acc: {best_acc:4f}")
# 가장 나은 모델 가중치를 불러옴
model.load_state_dict(best_model_weights)
return model
모델 불러오기¶
mobilevit v2를 사용합니다. 작고 가볍지만 정확도는 높아 빠른 튜토리얼에 적합합니다.
model = torch.hub.load("rwightman/pytorch-image-models", "mobilevitv2_050", pretrained=True, num_classes=3)
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
criterion = torch.nn.CrossEntropyLoss()
모델 훈련 및 저장¶
trained_model = train_model(model, criterion, optimizer, num_epochs=1)
Epoch 0/0 ---------- train Loss: 0.5792 Acc: 0.8153 validation Loss: 0.1912 Acc: 0.9323 Training complete in 0m 58s Best val Acc: 0.932331
torch.save(trained_model, "trained_model.pth")
ThanoSQL에 입력할 데이터프레임 생성¶
import numpy as np
import pandas as pd
test_dataset = ImageFolder("test", data_transforms["validation"])
data = np.stack([img.numpy() for img, _ in test_dataset])
df = pd.DataFrame(pd.Series(data.tolist()), columns=["image"]) # column 이름을 "image"로 지정해야 합니다.
df.to_pickle("test_data.pkl")
0. 데이터 세트 준비¶
ThanoSQL의 쿼리 구문을 사용하기 위해서는 ThanoSQL 워크스페이스에서 언급된 것처럼 API 토큰을 생성하고 아래의 쿼리를 실행해야 합니다.
%load_ext thanosql
%thanosql API_TOKEN=<발급받은_API_TOKEN>
데이터 세트 준비¶
%%thanosql
COPY beans_test
OPTIONS (if_exists='replace')
FROM 'test_data.pkl'
Success
쿼리 세부 정보
- "COPY" 쿼리 구문을 사용하여 데이터베이스에 저장 할 테이블명을 지정합니다.
- "OPTIONS" 쿼리 구문을 통해 COPY에 사용할 옵션을 지정합니다.
- "if_exists": 동일 이름의 테이블이 존재하는 경우 처리하는 방법 설정. 오류 발생, 기존 테이블에 추가, 기존 테이블 대체 (str, optional, 'fail'|'replace'|'append', default: 'fail')
1. 데이터 세트 확인¶
본 튜토리얼을 진행하기 위해 ThanoSQL 워크스페이스 데이터베이스에 저장되어 있는 beans_test 테이블을 사용합니다. 아래의 쿼리 구문을 실행하고 테이블의 내용을 확인합니다.
%%thanosql
SELECT *
FROM beans_test
LIMIT 5
image | |
---|---|
0 | [[[-0.028684020042419434, -0.04580877348780632... |
1 | [[[-0.0629335269331932, -0.0629335269331932, -... |
2 | [[[1.9577873945236206, 1.8721636533737183, 1.7... |
3 | [[[0.21106265485286713, 0.0569397434592247, -0... |
4 | [[[-1.3815395832061768, -1.432913899421692, -1... |
데이터 테이블 이해하기
beans_test 테이블은 아래와 같은 정보를 담고 있습니다.
- image: numpy 형식으로 저장한 이미지
2. 사용자 모델 업로드¶
이전 단계에서 파이썬을 이용하여 사용자가 만든 모델을 아래의 쿼리 구문을 실행하여 beans_mobilevit이라는 이름의 모델을 업로드합니다.
%%thanosql
UPLOAD MODEL beans_mobilevit
OPTIONS (
framework='pytorch',
overwrite=True
)
FROM 'trained_model.pth'
Success
쿼리 세부 정보
- "UPLOAD MODEL" 쿼리 구문을 사용하여 beans_mobilevit이라는 모델을 업로드 시킵니다.
- "OPTIONS" 쿼리 구문을 통해 모델 업로드에 사용할 옵션을 지정합니다.
- "framework": 모델의 프레임워크 (str, default: 'pytorch')
- "overwrite": 동일 이름의 모델이 존재하는 경우 덮어쓰기 가능 여부 설정. True일 경우 기존 모델은 새로운 모델로 변경됨 (bool, optional, True|False, default: False)
현재 ThanoSQL은 pytorch 형식의 모델만 지원합니다.
3. 사용자 모델을 사용하여 예측¶
이전 단계에서 업로드한 사용자 모델을 사용해 콩의 클래스를 예측해 봅니다.
%%thanosql
PREDICT USING beans_mobilevit
OPTIONS (
result_col='predicted'
)
AS (
SELECT *
FROM beans_test
ORDER BY RANDOM()
LIMIT 5
)
image | predicted | |
---|---|---|
0 | [[[-0.7821731567382812, -0.9362959265708923, -... | [0.464764267206192, 2.2284131050109863, -2.832... |
1 | [[[0.7248052358627319, 0.8104289770126343, 0.8... | [-0.7518391609191895, 2.296389102935791, -1.67... |
2 | [[[0.1083141341805458, 0.31381115317344666, 0.... | [2.892843008041382, -1.4041131734848022, -1.36... |
3 | [[[-0.23418104648590088, -0.38830381631851196,... | [-1.4550528526306152, 2.636288642883301, -1.30... |
4 | [[[-1.809658408164978, -1.689785122871399, -1.... | [-1.589335560798645, -0.9054973125457764, 2.46... |
쿼리 세부 정보
- "PREDICT USING" 쿼리 구문을 사용하여 beans_mobilevit 모델을 예측에 사용합니다.
- "OPTIONS" 쿼리 구문을 통해 예측에 사용할 옵션을 지정합니다.
- "result_col": 데이터 테이블에서 예측 결과를 담을 컬럼 이름 (str, optional, default: 'predict_result')
pred_df = _ # 가장 마지막에 사용된 객체를 불러옵니다.
pred_df["predicted"] = pred_df["predicted"].apply(np.argmax)
pred_df["predicted"] = pred_df["predicted"].apply(test_dataset.classes.__getitem__)
pred_df
image | predicted | |
---|---|---|
0 | [[[-0.7821731567382812, -0.9362959265708923, -... | bean_rust |
1 | [[[0.7248052358627319, 0.8104289770126343, 0.8... | bean_rust |
2 | [[[0.1083141341805458, 0.31381115317344666, 0.... | angular_leaf_spot |
3 | [[[-0.23418104648590088, -0.38830381631851196,... | bean_rust |
4 | [[[-1.809658408164978, -1.689785122871399, -1.... | healthy |
4. 튜토리얼을 마치며¶
이번 튜토리얼에서는 사용자 정의 모델을 ThanoSQL에 올린 후 beans 데이터 세트를 사용하여 사용자 모델을 예측에 사용해 보았습니다. 해당 튜토리얼을 참고하여 다양한 모델들을 ThanoSQL에 올리고 사용할 수 있습니다.
나만의 서비스를 위한 모델 배포 관련 문의
ThanoSQL을 활용해 나만의 모델을 만들거나, 나의 서비스에 적용하는데 어려움이 있다면 언제든 아래로 문의주세요😊
사용자 정의 모델 구축 관련 문의: contact@smartmind.team