SageMaker를 통해 모델을 배포해보기 전 배포 단계에서는 어떤 과정들이 포함되는 지와 알아야 할 개념들에 대해 정리해보자.
배포 단계에서는 1)추론 요구 사항을 식별하고, 해당 요구 사항에 따라 적절한 2)엔드포인트 유형을 선택하며, 3)엔드포인트를 구성하고 생성하는 과정들이 포함된다.
1) 추론 요구 사항 식별
이 단계에서는 몇가지 질문을 통해 모델이 실제 환경에서 어떤 방식으로 활용될지를 파악한다. 이 과정에서 추론 요구사항을 정확하게 파악해야 비용도 절감하고 성능도 높일 수 있다.
- 예측 요청의 빈도와 패턴
먼저, 예측 요청이 얼마나 자주 발생할지에 대해 파악해야 한다. 하루에도 수천 건의 요청이 들어오는 실시간 서비스인지, 아니면 하루에 한두 번 정도 예측을 수행하는 간헐적인 작업인지에 따라 배포 방식은 달라진다. 요청이 자주 발생하고 응답 시간이 중요한 경우라면 실시간 추론 환경이 필요하며, 반대로 요청 빈도가 낮고 응답 지연이 허용되는 상황이라면 서버리스 추론이나 비동기 추론이 더 적합할 수 있다. - 데이터 처리 단위: 단일 예측 vs 배치 예측
다음으로 고려할 요소는 예측을 수행할 데이터의 단위이다. 사용자의 요청 한 건에 대해 한 줄의 데이터를 처리하는 단일 예측이 필요한 경우도 있고, 수천 혹은 수백만 개의 데이터 포인트에 대해 한꺼번에 예측해야 하는 대규모 배치 처리일 수도 있다. 이와 같은 차이는 실시간 추론과 배치 변환 중 어떤 추론 방식을 선택할지 결정하는 중요한 기준이 된다. - 페이로드의 크기와 특성
추론에 사용될 입력 데이터, 즉 페이로드의 크기 또한 중요한 고려사항이다. 페이로드가 단순한 수치형 값 몇 개로 구성된 짧은 문자열이라면 처리 속도와 메모리 사용에 큰 부담이 없겠지만, 이미지, 텍스트, 혹은 고용량 센서 데이터와 같이 크기가 큰 페이로드의 경우에는 네트워크 대역폭과 인프라 자원에 대한 요구 수준이 높아지므로 그에 맞는 환경 구성이 필요하다. - 예측 결과 응답 시간 요구 사항
생성된 예측 결과가 얼마나 빠르게 사용자에게 전달되어야 하는지도 중요한 판단 요소다. 사용자가 웹 인터페이스나 챗봇을 통해 바로 예측 결과를 확인해야 하는 실시간 응답 상황인지, 아니면 예측 결과를 파일로 저장한 후 후속 처리에서 활용하는 방식인지에 따라 추론 방식은 동기 또는 비동기 중에서 선택하게 된다.
2)엔드포인트 유형 선택
먼저 sagemaker 에서 제공하는 엔트포인트 유형부터 알아보자!
| 엔드포인트 유형 | 워크로드 | 주요 특징 | 사례 |
| 실시간 추론 (Real-time Inference) |
• 빠른 응답이 필요한실시간/대화형 서비스 • 예측 요청이 지속적으로 발생 |
• 상시 실행되는 완전관리형 엔드포인트 • Auto Scaling 지원 • 낮은 지연 시간(ms~s 수준) |
• 웹 애플리케이션 • 챗봇 • 실시간 추천 API |
| 서버리스 추론 (Serverless Inference) |
• 요청 빈도가 낮고트래픽이 불규칙함 • 콜드 스타트 허용 가능 |
• 요청 시 자동으로 인프라 할당 • 유휴 시 비용 없음 • 최대 60초 응답 제한 |
• 이벤트 기반 알림 • 테스트/개발 환경 • 간헐적 API 호출 |
| 비동기 추론 (Asynchronous Inference) |
• 예측 시간이 길거나 페이로드 크기가 큼 • 결과를 나중에 받아도 됨 |
• 요청을 대기열에 넣고 비동기 처리 • 결과는 S3에 저장 • 인프라 자동 축소로 비용 절감 |
• 이미지 분류 • 대용량 문서 처리 • 비실시간 사용자 예측 |
| 배치 변환 (Batch Transform) |
• 전체 데이터셋을 한 번에 예측 • 실시간 응답 불필요 |
• 실시간 엔드포인트 없이 동작 • 결과는 S3에 저장 • 병렬 처리로 고속 실행 가능 |
• 정기 리포트 생성 • 과거 로그 예측 • 모델 검증 및 평가 |
# 서버리스(Serverless)란 무엇이며, 서버리스와 실시간 추론은 무슨 차이가 있는지?
AWS에서 서버리스는 개발자가 서버를 직접 만들거나 관리하지 않아도, aws가 필요한 작업을 실행해주는 방식이다.
서버가 아예 없는 건 아니지만, 서버를 켜고 끄는 일은 aws가 자동으로 처리해주기 때문에, 예측 요청이 들어오면 필요한 만큼 서버가 잠깐 켜지고, 처리가 끝나면 자동으로 꺼진다. 그래서 서버리스는 예측 요청이 자주 오지 않거나, 테스트처럼 가끔 실행할 작업에 잘 맞는 방법으로 비용 절약도 가능하다.
반면에 실시간 추론은 서버가 항상 켜진 상태로 예측 요청이 들어오면 바로 응답할 수 있도록 항상 대기하고 있는 방식이다. 이 방식은 응답 속도가 중요하거나 요청이 자주들어오는 경우에 적합하다. 하지만 서버가 항상 실행 중이기 때문에 예측 요청이 없어도 인스턴스가 유지되면서 비용이 계속 발생한다. 핵심 차이점은 서버리스는 필요할 때만 서버를 켜고, 실시간 추론은 항상 서버를 켜두는 구조라는 것!
# 비동기식 추론이란?
먼저, 동기식은 요청 후 결과를 기다리는 방식이고, 비동기식은 요청 후 기다지 않고 결과를 나중에 받아보는 방식이다.
그래서 비동기식 추론은 예측 요청을 보낸 뒤 결과를 기다리지 않고 나중에 확인할 수 있는 방식이다. 사용자는 예측 요청을 보내고 나서 다른 작업을 계속 할 수 있으며, sagemaker는 백그라운드에서 예측을 수행한 후, 결과를 s3에 저장해둔다.
예를 들어, 아래와 같은 상황으로 설명할 수 있다.
# 비동기식 추론 요청
sm_runtime.invoke_endpoint_async(
EndpointName='my-endpoint',
InputLocation='s3://mybucket/input.csv',
OutputLocation='s3://mybucket/output/'
)
# 결과를 기다리지 않고 바로 다음 코드 실행 가능
print("예측 요청은 처리 중이고, 다음 코드 실행 가능.")
보통 endpoint에 요청을 보내면, 해당 코드가 실행을 마칠 때까지 다음 코드를 실행할 수 없는데 이런 경우가 코드 실행을 멈춘 상태로 결과를 기다리는 동기식 추론 방식이다. 하지만 위에 처럼 비동기식 추론 요청 코드를 실행하면, 결과를 기다리지 않고 바로 아래있는 코드를 실행할 수 있다. 다음 코드가 실행되었지만 예측은 처리되고 있는 상태인 것이다.
3)엔드포인트를 구성하고 생성

엔드포인트를 구성하고 생성하는 단계까지의 구조는 위와 같은 아키텍처를 갖는다.
이제 실습을 통해서 위 과정을 확인해보면..
모델 학습을 마쳤던 저번 실습에 이어서 학습으로 생성된 artifact 파일을 사용해서 배포하는 과정을 실습한다. sagemaker 를 통해 엔드포인트를 구성하고 배포하여 새로운 데이터로 엔드포인트를 테스트한다.

sagemaker studio 주피터 노트북에서 실습 진행하며 s3에 저장해 놓은 데이터와 연동하여 진행한다.
1. SageMaker 세션 및 클라이언트 설정
import boto3
import pandas as pd
import sagemaker
import time
from sklearn.metrics import confusion_matrix, f1_score, classification_report
# SageMaker 세션 및 클라이언트 설정
role = sagemaker.get_execution_role()
region = boto3.Session().region_name
sess = boto3.Session()
sm = sess.client('sagemaker')
sm_runtime = sess.client("sagemaker-runtime")
s3_client = boto3.client("s3")
SageMaker에서 모델을 예측에 활용하려면 먼저 세션을 설정해야 한다. 세션은 코드와 AWS 서비스 사이를 이어주는 연결로, 계정과 권한 정보를 포함해 각 서비스가 요청을 인식할 수 있도록 한다.
세션이 준비되면 서비스별 클라이언트를 생성한다. SageMaker 클라이언트는 모델 생성과 엔드포인트 설정을, SageMaker Runtime 클라이언트는 추론 요청을, S3 클라이언트는 데이터 입출력을 담당한다. 서비스마다 역할이 다르기 때문에 별도의 클라이언트를 사용해야 한다.
2. 테스트 데이터 준비
prefix = 'scripts/data'
# 테스트 데이터 다운로드
s3_client.download_file(bucket, f'{prefix}/test/adult_data_processed_test.csv', 'adult_data_processed_test.csv')
df = pd.read_csv('adult_data_processed_test.csv')
df.head()
모델 추론을 진행하기 위해 먼저 S3에 저장된 테스트 데이터를 로컬 환경으로 불러온다. 위 코드에서는 S3 버킷 내 지정된 경로에 있는 adult_data_processed_test.csv 파일을 현재 실행 중인 환경에 다운로드하고 데이터를 불러온다.

# 첫 번째 컬럼을 레이블로 저장 후 제거 → CSV 저장
df_labels = df.iloc[:, 0]
df.drop(df.columns[0], axis=1).to_csv('adult_data_processed_test_no_target.csv', index=False, header=False)
저장할 때 header=False 옵션을 지정한 이유는, 추론 요청 시 모델이 열 이름이 아닌 입력값만 받아야 하기 때문이다.
저장한 데이터는 이후 예측 요청 단계에서 한 줄씩 읽어 엔드포인트에 전달하게 된다.
3. 모델 아티팩트 업로드 및 모델 생성
s3_client.upload_file("model.tar.gz", bucket, f"{prefix}/models/model.tar.gz")
# 모델 이름 생성
create_date = time.strftime("%Y-%m-%d-%H-%M-%S")
model_name = f"income-model-{create_date}"
# XGBoost 컨테이너 이미지 URI 가져오기
container = sagemaker.image_uris.retrieve(region=region, framework='xgboost', version='1.5-1')
# SageMaker 모델 생성
sm.create_model(
ModelName=model_name,
ExecutionRoleArn=role,
PrimaryContainer={
'Image': container,
'ModelDataUrl': f's3://{bucket}/{prefix}/models/model.tar.gz',
}
)
모델을 예측에 활용하려면 먼저 학습이 끝난 모델 파일(model.tar.gz)을 S3에 업로드해야 한다. 이 파일은 학습 과정에서 저장된 모델 아티팩트로 SageMaker가 실제 추론에 사용하게 된다.
업로드 후에는 모델 이름을 생성하고, 사용할 컨테이너 이미지를 지정한다. 이번에는 XGBoost 프레임워크 버전 1.5–1의 컨테이너 URI를 불러와 모델과 연결한다. 이어서 sm.create_model() 함수를 호출하면 SageMaker에 새로운 모델 리소스가 등록해 추론 가능한 모델 객체로 인식하도록 한다.
4. 엔드포인트 설정
# 엔드포인트 설정 이름 생성 (생성 시간을 기반으로 이름 설정)
endpoint_config_name = f"income-model-real-time-endpoint-{create_date}"
# 인스턴스 타입 설정 (ml.m5.xlarge는 중간 수준의 성능을 가진 인스턴스)
instance_type = 'ml.m5.xlarge'
# 캡처 샘플링 비율 설정 (입력/출력 데이터 중 몇 %를 저장할지, 0~100 사이 값)
initial_sampling_percentage = 25
# 캡처할 데이터 유형 설정: Input (입력), Output (예측 결과)
capture_modes = ["Input", "Output"]
# 엔드포인트 설정 생성
endpoint_config_response = sm.create_endpoint_config(
EndpointConfigName=endpoint_config_name, # 엔드포인트 구성 이름
ProductionVariants=[
{
"VariantName": "variant1", # 프로덕션 변형 이름
"ModelName": model_name, # 앞서 생성한 SageMaker 모델 이름
"InstanceType": instance_type, # 사용할 인스턴스 유형
"InitialInstanceCount": 1 # 시작 시 실행할 인스턴스 수
}
],
DataCaptureConfig={ # 데이터 캡처 구성
'EnableCapture': True, # 데이터 캡처 활성화 여부
'InitialSamplingPercentage': initial_sampling_percentage, # 샘플링 비율
'DestinationS3Uri': f's3://{bucket}/data-capture', # 캡처 데이터 저장 위치
'CaptureOptions': [ # 캡처할 방향 설정 (입력/출력/둘 다 가능)
{"CaptureMode": capture_mode} for capture_mode in capture_modes
]
}
)
모델을 배포하기 전에 먼저 엔드포인트 설정을 만들어야 한다. 이 설정은 모델이 어떤 환경에서 실행될지 정의하는 단계다.
설정 항목에는 사용할 인스턴스 유형 , 인스턴스 개수, 그리고 데이터 캡처 옵션이 포함된다. 데이터 캡처는 예측 요청과 응답을 일정 비율로 저장하는 기능으로, 추후 모델의 동작을 검증하거나 재학습에 활용할 수 있다.
이번에는 sm.create_endpoint_config() 함수를 사용해 엔드포인트 설정을 생성했고, 여기에는 모델 이름과 실행 환경, 그리고 입력,출력 데이터를 25% 비율로 S3에 저장하도록 지정했다.
5. 엔드포인트 생성
# 엔드포인트 이름 설정
endpoint_name = f"{endpoint_config_name}-name"
# 엔드포인트 생성 요청
sm.create_endpoint(
EndpointName=endpoint_name,
EndpointConfigName=endpoint_config_name
)
response = sm.describe_endpoint(EndpointName=endpoint_name)
status = response["EndpointStatus"]
# 상태 출력
print(f"엔드포인트 상태: {status}")
엔드포인트 설정이 준비되면 실제 예측 요청을 처리할 수 있도록 엔드포인트를 생성해야 한다. 이 단계에서는 sm.create_endpoint() 함수를 호출해 모델과 엔드포인트 설정을 연결하고, 지정된 인스턴스에서 실시간 추론이 가능하도록 리소스를 띄운다.
엔드포인트는 생성 직후 Creating 상태에서 시작해 준비가 완료되면 InService 상태로 전환된다. sm.describe_endpoint()를 통해 현재 상태를 확인할 수 있으며, 이 값이 InService여야 예측 요청을 정상적으로 처리할 수 있다.

코드 상으로 엔드포인트를 삭제할 수도 있고, 위 창에서 바로 삭제할 수도 있다. 켜두는 것 만으로도 비용이 나가므로 사용하지 않는다면 꼭 삭제해야한다.
6. 엔드포인트 호출 및 예측 수행
runtime = boto3.client("sagemaker-runtime")
predictions = []
start = time.time()
# 각 행을 엔드포인트에 예측 요청
with open("adult_data_processed_test_no_target.csv", "r") as f:
for row in f:
payload = row.strip()
response = runtime.invoke_endpoint(
EndpointName=endpoint_name,
ContentType="text/csv",
Body=payload
)
result = float(response["Body"].read().decode("utf-8"))
predictions.append(int(result >= 0.5)) # 임계값 0.5 기준 이진 분류
end = time.time()
print(f"Inference 완료. 소요 시간: {end - start:.2f}초")
엔드포인트가 서비스 상태(InService)가 되면 실제 데이터로 추론을 수행할 수 있다. 이때는 sagemaker-runtime 클라이언트를 사용해 invoke_endpoint() 메서드를 호출한다.
예제 코드에서는 테스트 데이터에서 레이블을 분리한 뒤, 입력 데이터(adult_data_processed_test_no_target.csv)를 한 줄씩 읽어 엔드포인트에 전송했다. 모델은 각 행에 대해 예측 확률을 반환하고, 이 값을 임계값 0.5 기준으로 0 또는 1로 변환하여 분류 결과를 얻는다.
위에서는 test 데이터의 크기가 (5046, 14) 였는데 이 정도의 데이터가 추론되기에 55초 정도 소요되었다.
7. 성능 평가
# 혼동 행렬 계산
cf_matrix = confusion_matrix(df_labels, pred_np)
# 히트맵으로 표시 (숫자만 출력)
sns.heatmap(cf_matrix, annot=True, fmt="d", cmap="Blues")
plt.xlabel("예측값")
plt.ylabel("실제값")
plt.title("Confusion Matrix")
plt.show()

성능까지 확인해보면, 클래스 1이 f1 score 기준으로 0.91 의 안정적인 성능을 보이고 있고 전체 성능도 86% 정도로 나쁘지 않은 것을 확인할 수 있다. 하지만 불균형 데이터의 숙제인 소수 클래스가 다수의 비해 성능이 떨어지기 때문에 여전히 개선해야 하는 점이 보인다.
참고 자료:
AWS Skill Builder
skillbuilder.aws
추론 컨테이너 이미지 - Amazon SageMaker AI
이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.
docs.aws.amazon.com
'AWS' 카테고리의 다른 글
| [AWS] AWS Certified Machine Learning – Specialty 취득 후기 (0) | 2025.10.21 |
|---|---|
| [AWS] Amazon SageMaker 사용해 모델 튜닝 및 하이퍼파라미터 최적화하기 (0) | 2025.08.24 |
| [AWS] Amazon SageMaker를 사용한 모델 학습 및 리포트 해석하기 (0) | 2025.08.24 |
| [AWS] SageMaker Data Wrangler를 사용해 데이터 처리하기 (0) | 2025.08.20 |
| [AWS] ML 수명 주기(ML Lifecycle)와 MLflow (0) | 2025.08.01 |