회사에서 AWS를 활용하여 엣지 디바이스에서 AI 모델을 구동하는 프로젝트를 준비하고 있다는 소식을 들었다. 이에 앞서 개인적으로 학습 겸 테스트를 진행해보고 그 과정을 기록하고자 한다. 이 글에서는 AWS의 대표적인 엣지 컴퓨팅 서비스인 AWS IoT Greengrass V2를 활용하여 Raspberry Pi 5에서 ML 모델을 구동하는 전체 과정을 다룬다. SageMaker에서 모델을 학습하고 최적화하는 과정부터, Greengrass를 통해 라즈베리파이에 모델을 배포하고 추론하는 과정까지 실습 위주로 설명하겠다.
Architecture
모델 훈련
- SageMaker에서 MXNet을 이용한 classification 모델 훈련을 진행한다.
SageMaker Neo를 통한 엣지 디바이스 최적화
1. SageMaker Neo를 사용하여 ML 모델 최적화 및 S3에 저장한다.
반드시 데이터 입력 형상과 프레임 워크 설정은 좀 전에 모델 학습할 때와 동일한 상태로 넣어준다.
import boto3
import time
# SageMaker 클라이언트 생성
sagemaker_client = boto3.client('sagemaker', region_name='ap-northeast-2')
# 컴파일 작업의 이름 설정
compilation_job_name = 'my-coco-model-compilation'
print(f'Compilation job for {compilation_job_name} started')
# IAM 역할의 ARN (SageMaker와 S3에 접근할 수 있어야 함)
role_arn = '[your_sagemaker_s3_arn]'
# 컴파일할 모델의 S3 위치
s3_input_location = 's3://[your_s3_bucket_address]/output/model.tar.gz'
# 컴파일된 모델을 저장할 S3 위치
s3_output_location = 's3://[your_s3_bucket]/compiled-model/'
# 데이터 입력 형상 설정
data_shape = '{"data": [128, 3, 224, 224]}'
# 프레임워크 설정 (예: 'TENSORFLOW', 'PYTORCH 등')
framework = 'MXNet'
# 타겟 디바이스 설정 (Raspberry Pi 5환경이였지만 해당 디바이스 목록이 없어 rasp4b로 대체)
target_device = 'rasp4b'
# SageMaker Neo 컴파일 작업 생성
response = sagemaker_client.create_compilation_job(
CompilationJobName=compilation_job_name,
RoleArn=role_arn,
InputConfig={
'S3Uri': s3_input_location,
'DataInputConfig': data_shape,
'Framework': framework.upper()
},
OutputConfig={
'S3OutputLocation': s3_output_location,
'TargetDevice': target_device
},
StoppingCondition={
'MaxRuntimeInSeconds': 900 # 최대 컴파일 시간 설정
}
)
# 컴파일 작업 상태 확인
while True:
response = sagemaker_client.describe_compilation_job(CompilationJobName=compilation_job_name)
status = response['CompilationJobStatus']
if status == 'COMPLETED':
print('Compilation completed successfully!')
break
elif status == 'FAILED':
raise RuntimeError('Compilation failed')
else:
print('Compiling ...')
time.sleep(30)
2. 테스트 할 이미지를 저장한다.
- 테스트를 위해 구글에서 비행기 사진 한 장과 자전거 사진 두 장을 다운로드 해서 로컬 환경(’/home/admin/Desktop/download-img’)에 저장해두었다.
Greengrass 설정
1. 환경 설정
1-1) AWS IoT GreengrassCore 소프트웨어를 실행하는 데 필요한 Java 런타임을 설치한다.
sudo apt install default-jdk
1-2) 설치가 완료되면 다음 명령을 실행하여 자바가 라즈베리 파이에서 실행되는지 확인한다.
java -version
1-3) 라즈베리 파이에서 커널 파라미터 설정하기
1-3-1) /boot/cmdline.txt 파일을 엽니다. 이 파일은 Raspberry Pi 부팅 시 적용할 Linux 커널 매개변수를 지정한다.
sudo nano /boot/cmdline.txt
1-3-2) /boot/cmdline.txt파일에 다음 커널 파라미터가 포함되어 있는지 확인 후 없다면 다음 매개변수와 값을 포함하도록 txt 파일 업데이트 하기
cgroup_enable=memory cgroup_memory=1 systemd.unified_cgroup_hierarchy=0
1-3-3) boot/cmdline.txt파일을 업데이트한 경우 Raspberry Pi를 재부팅하여 변경 사항을 적용하기
sudo reboot
2. Raspberry pi에 Greengrass Core V2 설치
콘솔과 CLI 설치가 있는데 필자는 CLI 설치를 통해 진행했다. 콘솔로 설치하고 싶다면 공식 홈페이지를 참고히면 된다.
2-1) 홈 디렉터리로 전환한다.
cd ~
2-2) 코어 디바이스에서 AWS IoT Greengrass Core 소프트웨어인 greengrass-nucleus-latest.zip 파일을 다운로드한다.
curl -s <https://d2s8p88vqu9w66.cloudfront.net/releases/greengrass-nucleus-latest.zip> > greengrass-nucleus-latest.zip
2-3) AWS IoT GreengrassCore 소프트웨어를 디바이스의 폴더에 압축을 풉니다.
unzip greengrass-nucleus-latest.zip -d *GreengrassInstaller* && rm greengrass-nucleus-latest.zip
Greengrass를 구성요소 개발
Greengrass의 모든 구성요소는 recipe와 artifacts로 구성된다.
- 레시피(recipe)
- Greengrass 컴포넌트 명세 파일
- 메타데이터 정의
- 구성 매개 변수, 구성요소 종속성, 수명 주기 및 플랫폼 호환성 지정
- JSON 또는 YAML 형식으로 정의 가능
- 아티팩트(artifacts)
- 스크립트
- 컴파일된 코드
- 정적 리소스 및 구성요소가 사용하는 기타 모든 파일 등등
여기에서는 CLI를 사용하여 Greengrass 구성요소를 배포하는 방법으로 진행할 것이다. Console을 통한 배포 방법은 공식 문서를 참조하면 된다.
1. 레시피와 아티팩트를 위한 하위 폴더가 있는 컴포넌트
mkdir -p ~/greengrassv2/{recipes,artifacts} cd ~/greengrassv2
2. 텍스트 편집기를 사용하여 recipe.json 생성
nano recipes/com.example.NeoInference-1.0.0.json
3. recipe.json에 들어갈 내용
{
"RecipeFormatVersion": "2020-01-25",
"ComponentName": "com.example.NeoInference",
"ComponentVersion": "1.0.0",
"ComponentType": "aws.greengrass.generic",
"ComponentDescription": "My first Greengrass component.",
"ComponentPublisher": "Ranna",
"Manifests": [
{
"Platform": {
"os": "linux"
},
"Name": "Linux",
"Lifecycle": {
"Install": {
"Script": "pip3 install dlr pillow numpy || true && aws s3 cp s3://[your_s3_bucket]/compiled-model/ /home/admin/neo-ai-dlr/python/dlr_model --recursive"
},
"Run": {
"Script": "python3 {artifacts:path}/inference.py /home/admin/Desktop/download-img/airplane.jpeg /home/admin/Desktop/download-img/bicycle.jpg /home/admin/Desktop/download-img/bicycle2.jpg"
}
},
"Artifacts": [
{
"Uri": "s3://[your-greengrass-s3-bucket]/artifacts/com.example.NeoSageMaker/1.0.0/inference.py",
"Digest": "[your digest]", //sha256sum inference.py를 하면 digest가 나옵니다.
"Algorithm": "SHA-256",
"Unarchive": "NONE",
"Permission": {
"Read": "OWNER",
"Execute": "NONE"
}
}
]
}
],
"Lifecycle": {}
}
4. 아티팩트를 위한 폴더를 생성한다.
4-1) 아티팩트 폴더 경로는 레시피에 지정된 구성 요소 이름(ComponentName)과 버전(ComponentVersion)을 포함해야 한다.
mkdir -p artifacts/com.example.NeoInference/1.0.0
5. 텍스트 편집기를 사용하여 NeoInference 구성 요소에 대한 Python 스크립트 아티팩트 파일을 만든다.
nano artifacts/com.example.NeoInference/1.0.0/inference.py
6. python 스크립트 작성(inference.py)
데이터 입력 크기를 본인의 상황에 맞게 넣어야 된다. 또한 이미지 크기 조정과 형식 변환 코드에 틀린 것은 없는지 잘 살펴봐야 된다. 만약 이것 때문에 에러가 발생하게 되면 코드를 수정하고 다시 배포해야 하는 상황이 반복될 수 있다.
from dlr import DLRModel
import numpy as np
from PIL import Image as PILImage
import os
# DLR 모델 로드
model_path = '/home/admin/neo-ai-dlr/python/dlr_model'
device = 'cpu'
model = DLRModel(model_path, device)
# 클래스 이름 정의 (모델이 예측하는 클래스)
classes = ['Person', 'Bicycle', 'Car', 'Motorcycle', 'Airplane']
# 모델이 기대하는 입력 크기
batch_size = 128
image_height, image_width = 224, 224
# 이미지 처리 및 추론
for file_name in image_files:
try:
# 이미지를 열고, 크기 조정 및 형식 변환
pil_image = PILImage.open(file_name).resize((image_width, image_height))
x = np.array(pil_image).astype('uint8')
x = np.transpose(x, (2, 0, 1)) # (Height, Width, Channels) -> (Channels, Height, Width)
x = np.expand_dims(x, axis=0) # (1, 3, 224, 224)
# 배치 크기에 맞춰 복제
x = np.repeat(x, batch_size, axis=0) # (128, 3, 224, 224)
# 모델 추론 실행
out = model.run(x)
# 결과 출력
results = out[0][0] # 첫 번째 배치의 결과만 사용
print(f"Results for {file_name}:")
for idx, class_name in enumerate(classes):
print(f'{class_name}: {float(results[idx]):.6f}')
print("\n")
except Exception as e:
print(f"Error processing {file_name}: {str(e)}")
7. 로컬에서 AWS IoT Greengrass CLI를 사용하여 Greengrass 코어 디바이스의 구성요소를 코어에 배포한다.
sudo /greengrass/v2/bin/greengrass-cli deployment create \
--recipeDir ~/greengrassv2/recipes \
--artifactDir ~/greengrassv2/artifacts \
--merge "com.example.NeoInference=1.0.0"
8. AWS IoT Greengrass Core 소프트웨어는 구성 요소 프로세스의 stdout을 폴더의 logs 로그 파일에 저장한다. 다음 명령을 실행하여 NeoInference구성 요소가 실행되고 메시지를 인쇄하는지 확인한다.
sudo tail -f /greengrass/v2/logs/com.example.NeoInference.log
실행결과
'Cloud&Infra > AWS' 카테고리의 다른 글
Raspberry Pi와 AWS Service를 활용한 실시간 얼굴 인식 시스템 구축하기 - Part 2: Rekognition 기반 얼굴 인식 구현 (2) | 2024.11.24 |
---|---|
Raspberry Pi와 AWS Service를 활용한 실시간 얼굴 인식 시스템 구축하기 - Part 1: 인프라 설정 (2) | 2024.11.09 |
Amazon Cognito 자격 증명 풀로 S3 파일 접근하기 (1) | 2024.03.13 |
S3 데이터를 RDS(Aurora MySQL) 클러스터로 로드하기 (1) | 2024.02.17 |
AWS QLDB와 Node.js 연결: 단계별 실습 (1) | 2023.05.14 |