Post

프로젝트 2주차 요약

Mlflow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
	apiVersion: apps/v1
	kind: Deployment
	metadata:
	name: mlflow
	spec:
	replicas: 1
	selector:
		matchLabels:
		app: mlflow
	template:
		metadata:
		labels:
			app: mlflow
		spec:
		nodeSelector:
			type: "mlops"  # 여기서 레이블 지정 
		containers:
			- name: mlflow
			image: bitnami/mlflow:latest
			ports:
				- containerPort: 8080  
			command: ["mlflow", "server", 
						#"--backend-store-uri", "postgresql://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@postgres:5432/mlops",  # PostgreSQL URI, 실험, 모델, 매트릭 저장
						"--default-artifact-root", "$(MLFLOW_S3_ARTIFACT_ROOT)",  # S3 버킷 경로
						"--host", "0.0.0.0", 
						"--port", "8080"]  # MLflow 서버 내부 컨테이너 연결 포트
			env:
				- name: POSTGRES_USER
				valueFrom:
					secretKeyRef:
					name: workflow
					key: POSTGRES_USER  # PostgreSQL 사용자
				- name: POSTGRES_PASSWORD
				valueFrom:
					secretKeyRef:
					name: workflow
					key: POSTGRES_PASSWORD  # PostgreSQL 비밀번호
				- name: AWS_ACCESS_KEY_ID
				valueFrom:
					secretKeyRef:
					name: workflow
					key: AWS_ACCESS_KEY_ID
				- name: AWS_SECRET_ACCESS_KEY
				valueFrom:
					secretKeyRef:
					name: workflow
					key: AWS_SECRET_ACCESS_KEY
				- name: MLFLOW_S3_ARTIFACT_ROOT
				valueFrom:
					secretKeyRef:
					name: workflow
					key: MLFLOW_S3_ARTIFACT_ROOT
			resources: # 제한 안하면 주황줄 끄임
				requests:
				memory: "512Mi"  # 요청 메모리
				cpu: "500m"      # 요청 CPU
				limits:
				memory: "1Gi"    # 제한 메모리
				cpu: "1"         # 제한 CPU

	---
	apiVersion: v1
	kind: Service
	metadata:
	name: mlflow
	spec:
	type: NodePort 
	ports:
		- port: 8080    # 클러스터 내부 포트
		targetPort: 8080
		nodePort: 30003  # 클러스터 외부 접근 포트
	selector:
		app: mlflow

S3 연결

export MLFLOW_S3_ARTIFACT_ROOT=s3://team06-mlflow-feature(연결할 버킷 이름)

쿠버 삭제하고 다시 설치하면 사라지는 설정이므로 다시 입력이 필요함

  • S3 연결을 위해 AWS 액세서 ID, key 포함한 secret 생성

    1
    
      kubectl create secret generic 지정한이름 --from-env-file=.env
    

DB(Postgresql) 연결

1
"--backend-store-uri", "postgresql://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@postgres:5432/mlops"

postgresql:// : postgre 쓰겠다고 명시하는 부분

/mlops : DB 이름 지정

Mlflow 시각화, 성능 테스트, 모델 레지스트리 및 배포 자동화

Tracking API

  • mlflow.start_run(): 이 함수를 통해 새로운 실행(run)을 함.   훈련 중에 사용한 하이퍼파라미터, 훈련 데이터, 모델 아키텍처   등의 정보를 기록 가능함.

  • mlflow.log_metric(): 훈련 중에 얻은 성능 지표(예: 정확도, 손실 값)를 기록. 여러 지표를 기록해서 모델의 성능을 종합적으로 평가할 수 있음.

  • mlflow.log_artifact(): 훈련된 모델 파일, 그래프, 데이터 시각화등을 이 함수로 저장 가능함. 

모델 레지스트리

1
2
3
# 모델 레지스트리에 등록
model_uri = f"runs:/{mlflow.active_run().info.run_id}/{model_path}"
mlflow.register_model(model_uri, "IrisModel")

테스트용으로 만든 간단한 모델의 코드 일부.

같은 이름으로 모델을 지정하면 mlflow가 자동으로 버저닝을 해준다.

FastAPI

  • mlflow: 10.103.73.87

mlflow service에서 지정된 클러스터 ip. mlflow service를 삭제하지 않는 이상 ip는 고정됨.

아래는 FastAPI앱 코드 전문

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import mlflow
import mlflow.pyfunc
import numpy as np

app = FastAPI()

# MLflow tracking URI 및 실험 설정
mlflow.set_tracking_uri("http://10.103.73.87:8080")  # service cluster ip
mlflow.set_experiment("testjun")  # 실험 이름으로 변경

class InputData(BaseModel):
	model_name: str  # 모델 이름 추가
	version: int     # 모델 버전 추가
	features: list

@app.post("/predict")
def predict(data: InputData):
	try:
		# 모델 URI 설정 (모델 이름과 버전)
		model_uri = f"models:/{data.model_name}/{data.version}"  # 동적으로 모델 URI 생성
		model = mlflow.pyfunc.load_model(model_uri)  # 모델 로드
		
		# 입력 데이터 형태 변경
		features = np.array(data.features).reshape(1, -1)
		
		# 예측 수행
		prediction = model.predict(features)
		
		# 결과 반환
		return {
			"prediction": int(prediction[0])
		}
	except ValueError:
		raise HTTPException(status_code=400, detail="잘못된 입력 데이터입니다. 입력을 확인하세요.")
	except Exception as e:
		raise HTTPException(status_code=500, detail=str(e))

모델 URI 설정 할 때 주의사항

설정 방법

1
model_uri = f"models:/{data.model_name}/{data.version}"

웹에서의 url은 아래와 같은데

1
http://3.39.68.171:30003/#/models/IrisModel/versions/2

모델 이름과 버전 숫자 사이에 versions라는 경로가 존재하지만 API 호출 할 때는 넣으면 경로 오류가 생긴다.

이유는 mlflow 모델 URI가 아래 형식을 따르기 때문.

1
models:/<model_name>/<version>

고로 url에서 보이는 경로는 모델을 보여주기 위한 ui 요소일 뿐 API 호출과는 별개의 것이다.

실행 명령어 및 사용법

서버 실행 명령어

1
2
3
4
uvicorn test_api:app --host 0.0.0.0 --port 8000 --reload

# 백그라운드 실행
nohup uvicorn test_api:app --host 0.0.0.0 --port 8000 --reload &

접속 url

1
2
#인스턴스1 공인 아이피
http://3.39.68.171:8000/docs

사용법

1
2
3
4
5
6
7
{
"model_name": "모델 이름",
"version": 버전,
"features": [
	넣을 값
]
}

인스턴스 내부 python 라이브러리 목록 자동갱신

  • 코드 전문

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
      from importlib.metadata import distributions
      import sys
    
      # 현재 파이썬이 설치된 경로
      sys.path.append('/home/ubuntu/.pyenv/shims/python3')
    
      # 현재 설치된 패키지 메타데이터를 반환 패키지 이름을 키로, 버전을 값으로 가지게 됨
      installed_packages = {dist.metadata['Name']: dist.version for dist in distributions()}
    
      # requirements.txt 파일 경로를 설정
      requirements_file = '/home/ubuntu/yeardream-miniproject/instance1/crontab/requirements.txt'
    
      # w 쓰기 모드로 설치된 버전을 설정한 형식으로 저장
      try:
    		
          with open(requirements_file, 'w') as f:
              for package, version in installed_packages.items():
                  f.write(f"{package}=={version}\n")
          print(f"{requirements_file}가 성공적으로 업데이트되었습니다.")
      except Exception as e:
          print(f"오류 발생: {e}")
    

importlib.metadata: 이 모듈은 Python 패키지의 메타데이터에 접근할 수 있게 해준다.

crontab을 이용한 라이브러리 목록 업데이트 자동화

1
30 17 * * * /home/ubuntu/.pyenv/shims/python3 /home/ubuntu/yeardream-miniproject/instance1/crontab/update_requirements.py >> /home/ubuntu/yeardream-miniproject/instance1/crontab/logs/requirements/req_log_$(date +%Y-%m-%d).log 2>&1

하루에 한 번만 오후 5시 30분에 실행하게 설정.

파이썬 파일로 작성했기 때문에 실행하기 위해 파이썬 인터프리터 경로를 지정해줌.

나머지는 지정한 경로에 그날 날짜를 이름으로 한 log 파일이 생성되게 설정함.

쿠버네티스 마스터 노드에 워커 join 오류

1
2
3
4
error execution phase preflight: [preflight] Some fatal errors occurred:
	[ERROR FileAvailable--etc-kubernetes-kubelet.conf]: /etc/kubernetes/kubelet.conf already exists
	[ERROR Port-10250]: Port 10250 is in use
	[ERROR FileAvailable--etc-kubernetes-pki-ca.crt]: /etc/kubernetes/pki/ca.crt already exists

파일 다 삭제해주고 kubelt이 사용중인 포트를 내려도 해결이 안됨.

이 오류가 일어나는 경우는 크게 두 가지다.

  1. 이전에 쿠버네티스 클러스터의 일부로 설정되다 제거된 노드를 재추가하려 할 때.

  2. 노드에 쿠버네티스를 설치하는 과정에서 실패하거나 중단된 후 재시도하려 할 때.

여러가지 해결책이 존재했지만 실제로 유효했던건 아래 명령어다.

1
sudo kubeadm reset

현 노드의 쿠버 관련 설정을 모두 지워주는 명령어다.

이후 다시 join을 시도하면 정상적으로 실행된다.

에러 핸들링 추가

This post is licensed under CC BY 4.0 by the author.