{
"cells": [
{
"cell_type": "markdown",
"id": "65432e41",
"metadata": {},
"source": [
"# MLOps with SageMaker Pipelines\n",
"---\n",
"\n",
"## Prerequisites\n",
"---\n",
"\n",
"본 모듈은 여러분이 SageMaker와 SageMaker Pipelines에 대한 기본 컨셉을 알고 있다고 가정합니다. 만약 기본 컨셉에 대한 이해와 step-by-step 핸즈온이 필요하면 아래 링크들을 통해 세션 시청 후, 핸즈온을 해 보시는 것을 권장드립니다.\n",
"\n",
"- SageMaker Pipelines 세션 (AWS Builders 300)\n",
" - Part 1: https://www.youtube.com/watch?v=7IL_0-OjZWk\n",
" - Part 2: https://www.youtube.com/watch?v=z_l2aNJswWQ\n",
"- SageMaker Pipelines Step-by-step 핸즈온\n",
" - 입문 과정: https://github.com/gonsoomoon-ml/SageMaker-Pipelines-Step-By-Step\n",
" - (optionally) 고급 과정 1: https://github.com/gonsoomoon-ml/SageMaker-Pipelines-Step-By-Step/tree/main/phase01\n",
" - (optionally) 고급 과정 2: https://github.com/gonsoomoon-ml/SageMaker-Pipelines-Step-By-Step/tree/main/phase02\n",
"\n",
"\n",
"## Introduction\n",
"---\n",
"\n",
"본 모듈에서는 SageMaker Pipelines를 사용하여 간단한 머신 러닝 파이프라인을 구축합니다. SageMaker Pipelines은 re:Invent 2020 서비스 런칭 이후 지속적으로 업데이트되고 있으며, 2021년 8월 업데이트된 주요 기능인 Lambda Step을 사용하면 호스팅 엔드포인트 모델 배포를 비롯한 서버리스 작업들을 쉽게 수행할 수 있습니다. 또한 캐싱(caching) 기능을 사용하면 모든 파이프라인을 처음부터 재시작할 필요 없이 변경된 파라메터에 대해서만 빠르게 실험해볼 수 있습니다. Lambda Step과 캐싱에 대한 자세한 내용은 아래 링크들을 참조해 주세요.\n",
"\n",
"### References \n",
"- SageMaker Pipelines SDK: https://docs.aws.amazon.com/sagemaker/latest/dg/pipelines-sdk.html\n",
"- Caching Pipeline Steps: https://docs.aws.amazon.com/sagemaker/latest/dg/pipelines-caching.html\n",
"- AWS AIML Blog: Use a SageMaker Pipeline Lambda step for lightweight model deployments: https://aws.amazon.com/de/blogs/machine-learning/use-a-sagemaker-pipeline-lambda-step-for-lightweight-model-deployments/\n",
"\n",
"### Note\n",
"- 본 노트북을 실행하려면 `AmazonSageMakerFullAccess`와 `AmazonSageMakerPipelinesIntegrations` policy를 추가해야 합니다.\n",
"- 빠른 핸즈온을 위해 1,000건의 샘플 데이터와 1 epoch으로 전처리 및 훈련을 수행합니다. 사전에 이미 파인튜닝이 완료된 모델을 훈련하므로 높은 정확도를 보입니다."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0819eac9",
"metadata": {},
"outputs": [],
"source": [
"import boto3\n",
"import os\n",
"import numpy as np\n",
"import sagemaker\n",
"import sys\n",
"import time\n",
"\n",
"import sagemaker\n",
"import sagemaker.huggingface\n",
"from sagemaker.huggingface import HuggingFace, HuggingFaceModel\n",
"\n",
"from sagemaker.workflow.parameters import ParameterInteger, ParameterFloat, ParameterString\n",
"\n",
"from sagemaker.lambda_helper import Lambda\n",
"\n",
"from sagemaker.sklearn.processing import SKLearnProcessor\n",
"from sagemaker.huggingface.processing import HuggingFaceProcessor\n",
"\n",
"from sagemaker.processing import ProcessingInput, ProcessingOutput\n",
"from sagemaker.workflow.steps import CacheConfig, ProcessingStep\n",
"\n",
"from sagemaker.inputs import TrainingInput\n",
"from sagemaker.workflow.steps import TrainingStep\n",
"\n",
"from sagemaker.processing import ScriptProcessor\n",
"from sagemaker.workflow.properties import PropertyFile\n",
"from sagemaker.workflow.step_collections import CreateModelStep, RegisterModel\n",
"\n",
"from sagemaker.workflow.conditions import ConditionLessThanOrEqualTo,ConditionGreaterThanOrEqualTo\n",
"from sagemaker.workflow.condition_step import ConditionStep\n",
"from sagemaker.workflow.functions import JsonGet\n",
"\n",
"from sagemaker.workflow.pipeline import Pipeline, PipelineExperimentConfig\n",
"from sagemaker.workflow.execution_variables import ExecutionVariables"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5e7a9f4a",
"metadata": {},
"outputs": [],
"source": [
"sess = sagemaker.Session()\n",
"region = sess.boto_region_name\n",
"\n",
"# sagemaker session bucket -> used for uploading data, models and logs\n",
"# sagemaker will automatically create this bucket if it not exists\n",
"sagemaker_session_bucket=None\n",
"if sagemaker_session_bucket is None and sess is not None:\n",
" # set to default bucket if a bucket name is not given\n",
" sagemaker_session_bucket = sess.default_bucket()\n",
"\n",
"role = sagemaker.get_execution_role()\n",
"sagemaker_session = sagemaker.Session(default_bucket=sagemaker_session_bucket)\n",
"\n",
"print(f\"sagemaker role arn: {role}\")\n",
"print(f\"sagemaker bucket: {sagemaker_session.default_bucket()}\")\n",
"print(f\"sagemaker session region: {sagemaker_session.boto_region_name}\")"
]
},
{
"cell_type": "markdown",
"id": "2373108d",
"metadata": {},
"source": [
"\n",
"
\n",
"\n",
"## 1. Defining the Pipeline\n",
"---\n",
"\n",
"### 1.1. Pipeline parameters\n",
"\n",
"기본적인 파이프라인 파라메터들을 정의합니다. 자세한 내용은 아래 링크를 참조해 주세요.\n",
"\n",
"References: \n",
"- 개발자 가이드: https://docs.aws.amazon.com/sagemaker/latest/dg/build-and-manage-parameters.html"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8aa70056",
"metadata": {},
"outputs": [],
"source": [
"# S3 prefix where every assets will be stored\n",
"s3_prefix = \"hf-kornlp-mlops-demo\"\n",
"\n",
"# s3 bucket used for storing assets and artifacts\n",
"bucket = sagemaker_session.default_bucket()\n",
"\n",
"# aws region used\n",
"region = sagemaker_session.boto_region_name\n",
"\n",
"# base name prefix for sagemaker jobs (training, processing, inference)\n",
"base_job_prefix = s3_prefix\n",
"\n",
"# Cache configuration for workflow\n",
"cache_config = CacheConfig(enable_caching=True, expire_after=\"7d\")\n",
"\n",
"# package versions\n",
"transformers_version = \"4.11.0\"\n",
"pytorch_version = \"1.9.0\"\n",
"py_version = \"py38\"\n",
"\n",
"model_id_ = \"daekeun-ml/koelectra-small-v3-nsmc\"\n",
"tokenizer_id_ = \"daekeun-ml/koelectra-small-v3-nsmc\"\n",
"dataset_name_ = \"nsmc\"\n",
"\n",
"model_id = ParameterString(name=\"ModelId\", default_value=model_id_)\n",
"tokenizer_id = ParameterString(name=\"TokenizerId\", default_value=tokenizer_id_)\n",
"dataset_name = ParameterString(name=\"DatasetName\", default_value=dataset_name_)"
]
},
{
"cell_type": "markdown",
"id": "11ca239e",
"metadata": {},
"source": [
"### 1.2. Processing Step\n",
"\n",
"빌트인 `SKLearnProcessor`를 통해 전처리 스텝을 정의합니다. \n",
"\n",
"최근 PyTorch, TensorFlow, MXNet, XGBoost, Hugging Face도 빌트인으로 지원되기 시작했습니다. `HuggingFaceProcessor` 사용 예시는 아래 코드 snippet을 참조해 주세요. 단, `HuggingFaceProcessor`는 현 시점(2022년 1월)에서는 GPU 인스턴스만 지원하기 때문에 GPU 리소스가 필요하지 않은 경우는 `SKLearnProcessor` 사용을 권장드립니다.\n",
"\n",
"\n",
"```python\n",
"from sagemaker.huggingface.processing import HuggingFaceProcessor\n",
"\n",
"hf_processor = HuggingFaceProcessor(\n",
" instance_type=processing_instance_type, \n",
" instance_count=processing_instance_count,\n",
" pytorch_version=pytorch_version,\n",
" transformers_version=transformers_version,\n",
" py_version=py_version,\n",
" base_job_name=base_job_prefix + \"-preprocessing\",\n",
" sagemaker_session=sagemaker_session, \n",
" role=role\n",
")\n",
"\n",
"```\n",
"\n",
"References: \n",
"- AWS AIML Blog: https://aws.amazon.com/ko/blogs/machine-learning/use-deep-learning-frameworks-natively-in-amazon-sagemaker-processing/\n",
"- 개발자 가이드: https://docs.aws.amazon.com/ko_kr/sagemaker/latest/dg/build-and-manage-steps.html#step-type-processing"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9b557d4c",
"metadata": {},
"outputs": [],
"source": [
"processing_instance_type = ParameterString(name=\"ProcessingInstanceType\", default_value=\"ml.c5.xlarge\")\n",
"processing_instance_count = ParameterInteger(name=\"ProcessingInstanceCount\", default_value=1)\n",
"processing_script = ParameterString(name=\"ProcessingScript\", default_value=\"./pipeline_src/processing_sklearn.py\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fca79d88",
"metadata": {},
"outputs": [],
"source": [
"processing_output_destination = f\"s3://{bucket}/{s3_prefix}/data\"\n",
"\n",
"sklearn_processor = SKLearnProcessor(\n",
" instance_type=processing_instance_type, \n",
" instance_count=processing_instance_count,\n",
" framework_version=\"0.23-1\", \n",
" base_job_name=base_job_prefix + \"-preprocessing\",\n",
" sagemaker_session=sagemaker_session, \n",
" role=role\n",
")\n",
"\n",
"step_process = ProcessingStep(\n",
" name=\"ProcessDataForTraining\",\n",
" cache_config=cache_config,\n",
" processor=sklearn_processor,\n",
" job_arguments=[\"--model_id\", model_id_,\n",
" \"--tokenizer_id\", tokenizer_id_,\n",
" \"--dataset_name\", dataset_name_,\n",
" \"--transformers_version\", transformers_version,\n",
" \"--pytorch_version\", pytorch_version\n",
" ],\n",
" outputs=[\n",
" ProcessingOutput(\n",
" output_name=\"train\",\n",
" destination=f\"{processing_output_destination}/train\",\n",
" source=\"/opt/ml/processing/train\",\n",
" ),\n",
" ProcessingOutput(\n",
" output_name=\"validation\",\n",
" destination=f\"{processing_output_destination}/test\",\n",
" source=\"/opt/ml/processing/validation\",\n",
" ),\n",
" ProcessingOutput(\n",
" output_name=\"test\",\n",
" destination=f\"{processing_output_destination}/test\",\n",
" source=\"/opt/ml/processing/test\",\n",
" ) \n",
" ],\n",
" code=processing_script\n",
")"
]
},
{
"cell_type": "markdown",
"id": "374fcff8",
"metadata": {},
"source": [
"### 1.3. Model Training Step\n",
"\n",
"이전 랩에서 진행한 훈련 스크립트를 그대로 활용하여 훈련 스텝을 정의합니다. SageMaker Pipelines에 적용하기 위해 워크플로 파라메터(`ParameterInteger, ParameterFloat, ParameterString`)도 같이 정의합니다.\n",
"\n",
"훈련, 검증 및 테스트 데이터에 대한 S3 경로는 이전 랩처럼 수동으로 지정하는 것이 아니라 체인으로 연결되는 개념이기에, 아래 예시처럼 전처리 스텝 결괏값(`step_process`)의 프로퍼티(`properties`)를 참조하여 지정해야 합니다.\n",
"```python\n",
"\"train\": TrainingInput(\n",
" s3_data=step_process.properties.ProcessingOutputConfig.Outputs[\"train\"].S3Output.S3Uri\n",
")\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "090c1e17",
"metadata": {},
"source": [
"#### Training Parameter"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "122934e0",
"metadata": {},
"outputs": [],
"source": [
"# training step parameters\n",
"training_entry_point = ParameterString(name=\"TrainingEntryPoint\", default_value=\"train.py\")\n",
"training_source_dir = ParameterString(name=\"TrainingSourceDir\", default_value=\"./pipeline_src\")\n",
"training_instance_type = ParameterString(name=\"TrainingInstanceType\", default_value=\"ml.p3.2xlarge\")\n",
"training_instance_count = ParameterInteger(name=\"TrainingInstanceCount\", default_value=1)\n",
"\n",
"# hyperparameters, which are passed into the training job\n",
"n_gpus = ParameterString(name=\"NumGPUs\", default_value=\"1\")\n",
"epochs = ParameterString(name=\"Epochs\", default_value=\"1\")\n",
"seed = ParameterString(name=\"Seed\", default_value=\"42\")\n",
"train_batch_size = ParameterString(name=\"TrainBatchSize\", default_value=\"32\")\n",
"eval_batch_size = ParameterString(name=\"EvalBatchSize\", default_value=\"64\") \n",
"learning_rate = ParameterString(name=\"LearningRate\", default_value=\"5e-5\") \n",
"\n",
"# model_id = ParameterString(name=\"ModelId\", default_value=model_id_)\n",
"# tokenizer_id = ParameterString(name=\"TokenizerId\", default_value=tokenizer_id_)\n",
"# dataset_name = ParameterString(name=\"DatasetName\", default_value=dataset_name_)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "13e920d1",
"metadata": {},
"outputs": [],
"source": [
"hyperparameters = {\n",
" 'n_gpus': n_gpus, # number of GPUs per instance\n",
" 'epochs': epochs, # number of training epochs\n",
" 'seed': seed, # seed\n",
" 'train_batch_size': train_batch_size, # batch size for training\n",
" 'eval_batch_size': eval_batch_size, # batch size for evaluation\n",
" 'warmup_steps': 0, # warmup steps\n",
" 'learning_rate': learning_rate, # learning rate used during training\n",
" 'tokenizer_id': model_id, # pre-trained tokenizer\n",
" 'model_id': tokenizer_id # pre-trained model\n",
"}\n",
"\n",
"chkpt_s3_path = f's3://{bucket}/{s3_prefix}/sm-processing/checkpoints'"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ca26c59e",
"metadata": {},
"outputs": [],
"source": [
"huggingface_estimator = HuggingFace(\n",
" entry_point=training_entry_point,\n",
" source_dir=training_source_dir,\n",
" base_job_name=base_job_prefix + \"-training\",\n",
" instance_type=training_instance_type,\n",
" instance_count=training_instance_count,\n",
" role=role,\n",
" transformers_version=transformers_version,\n",
" pytorch_version=pytorch_version,\n",
" py_version=py_version,\n",
" hyperparameters=hyperparameters,\n",
" sagemaker_session=sagemaker_session, \n",
" disable_profiler=True,\n",
" debugger_hook_config=False,\n",
" checkpoint_s3_uri=chkpt_s3_path,\n",
" checkpoint_local_path='/opt/ml/checkpoints'\n",
")\n",
"\n",
"step_train = TrainingStep(\n",
" name=\"TrainHuggingFaceModel\",\n",
" estimator=huggingface_estimator,\n",
" inputs={\n",
" \"train\": TrainingInput(\n",
" s3_data=step_process.properties.ProcessingOutputConfig.Outputs[\n",
" \"train\"\n",
" ].S3Output.S3Uri\n",
" ),\n",
" \"test\": TrainingInput(\n",
" s3_data=step_process.properties.ProcessingOutputConfig.Outputs[\n",
" \"test\"\n",
" ].S3Output.S3Uri\n",
" ),\n",
" },\n",
" cache_config=cache_config,\n",
")"
]
},
{
"cell_type": "markdown",
"id": "4672da51",
"metadata": {},
"source": [
"### 1.4. Model evaluation Step\n",
"\n",
"훈련된 모델의 성능을 평가하기 위해 추가 `ProcessingStep`을 정의합니다. 평가 결과에 따라 모델이 생성, 등록 및 배포되거나 파이프라인이 중단됩니다.\n",
"평가 결과는 `PropertyFile`에 복사되며, 이는 이후 `ConditionStep`에서 사용됩니다."
]
},
{
"cell_type": "markdown",
"id": "033e3baf",
"metadata": {},
"source": [
"#### Evaluation Parameter"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "066f7855",
"metadata": {},
"outputs": [],
"source": [
"evaluation_script = ParameterString(name=\"EvaluationScript\", default_value=\"./pipeline_src/evaluate.py\")\n",
"evaluation_instance_type = ParameterString(name=\"EvaluationInstanceType\", default_value=\"ml.m5.xlarge\")\n",
"evaluation_instance_count = ParameterInteger(name=\"EvaluationInstanceCount\", default_value=1)"
]
},
{
"cell_type": "markdown",
"id": "2ed23c7d",
"metadata": {},
"source": [
"#### Evaluator"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e5b02295",
"metadata": {},
"outputs": [],
"source": [
"!pygmentize ./pipeline_src/evaluate.py"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4c78e4a7",
"metadata": {},
"outputs": [],
"source": [
"script_eval = SKLearnProcessor(\n",
" framework_version=\"0.23-1\",\n",
" instance_type=evaluation_instance_type,\n",
" instance_count=evaluation_instance_count,\n",
" base_job_name=base_job_prefix + \"-evaluation\",\n",
" sagemaker_session=sagemaker_session,\n",
" role=role,\n",
")\n",
"\n",
"evaluation_report = PropertyFile(\n",
" name=\"HuggingFaceEvaluationReport\",\n",
" output_name=\"evaluation\",\n",
" path=\"evaluation.json\",\n",
")\n",
"\n",
"step_eval = ProcessingStep(\n",
" name=\"HuggingfaceEvalLoss\",\n",
" processor=script_eval,\n",
" inputs=[\n",
" ProcessingInput(\n",
" source=step_train.properties.ModelArtifacts.S3ModelArtifacts,\n",
" destination=\"/opt/ml/processing/model\",\n",
" )\n",
" ],\n",
" outputs=[\n",
" ProcessingOutput(\n",
" output_name=\"evaluation\",\n",
" source=\"/opt/ml/processing/evaluation\",\n",
" destination=f\"s3://{bucket}/{s3_prefix}/evaluation_report\",\n",
" ),\n",
" ],\n",
" code=evaluation_script,\n",
" property_files=[evaluation_report],\n",
" cache_config=cache_config,\n",
")"
]
},
{
"cell_type": "markdown",
"id": "751c529d",
"metadata": {},
"source": [
"### 1.5. Register the model\n",
"\n",
"훈련된 모델은 모델 패키지 그룹(Model Package Group)의 모델 레지스트리(Model Registry)에 등록됩니다. 모델 레지스트리는 SageMaker Pipelines에서 소개된 개념으로, 기존 SageMaker 모델과 다르게 모델 버전 관리가 가능하며 승인 여부를 지정할 수 있습니다. 모델 승인은 `ConditionStep`의 조건을 만족할 때에만 가능하게 할 수 있습니다. (예: 정확도가 80% 이상인 경우에만 모델 배포)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "43fa9f81",
"metadata": {},
"outputs": [],
"source": [
"model = HuggingFaceModel(\n",
" model_data=step_train.properties.ModelArtifacts.S3ModelArtifacts,\n",
" role=role,\n",
" transformers_version=transformers_version,\n",
" pytorch_version=pytorch_version,\n",
" py_version=py_version,\n",
" sagemaker_session=sagemaker_session,\n",
")\n",
"model_package_group_name = \"HuggingFaceModelPackageGroup\"\n",
"step_register = RegisterModel(\n",
" name=\"HuggingFaceRegisterModel\",\n",
" model=model,\n",
" content_types=[\"application/json\"],\n",
" response_types=[\"application/json\"],\n",
" inference_instances=[\"ml.m5.xlarge\", \"ml.g4dn.xlarge\"],\n",
" transform_instances=[\"ml.m5.xlarge\", \"ml.g4dn.xlarge\"],\n",
" model_package_group_name=model_package_group_name,\n",
" approval_status=\"Approved\",\n",
")"
]
},
{
"cell_type": "markdown",
"id": "f013220f",
"metadata": {},
"source": [
"### 1.6. Model Deployment\n",
"\n",
"\n",
"`LambdaStep`에서 파생된 커스텀 단계 `ModelDeployment`를 생성합니다. LambdaStep에서 정의한 Lambda 함수를 통해 호스팅 리얼타임 엔드포인트를 배포합니다."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4d4287e9",
"metadata": {},
"outputs": [],
"source": [
"!pygmentize pipeline_utils/deploy_step.py"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "198b4e35",
"metadata": {},
"outputs": [],
"source": [
"# custom Helper Step for ModelDeployment\n",
"from pipeline_utils.deploy_step import ModelDeployment\n",
"\n",
"# we will use the iam role from the notebook session for the created endpoint\n",
"# this role will be attached to our endpoint and need permissions, e.g. to download assets from s3\n",
"sagemaker_endpoint_role=sagemaker.get_execution_role()\n",
"model_name = f\"{model_id_.split('/')[-1]}-{time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime())}\"\n",
"\n",
"step_deployment = ModelDeployment(\n",
" model_name=model_name,\n",
" registered_model=step_register.steps[0],\n",
" endpoint_instance_type=\"ml.m5.xlarge\",\n",
" sagemaker_endpoint_role=sagemaker_endpoint_role,\n",
" autoscaling_policy=None,\n",
")"
]
},
{
"cell_type": "markdown",
"id": "522b1961",
"metadata": {},
"source": [
"### 1.7. Condition for deployment\n",
"\n",
"`ConditionStep`을 통해 모델 평가 결과를 검사합니다. 정확도가 일정 이상일 때(accuracy > 0.8) 모델 등록 및 배포 파이프라인을 진행합니다."
]
},
{
"cell_type": "markdown",
"id": "f8fa04aa",
"metadata": {},
"source": [
"#### Condition Parameter"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2c909b5c",
"metadata": {},
"outputs": [],
"source": [
"threshold_accuracy = ParameterFloat(name=\"ThresholdAccuracy\", default_value=0.8)"
]
},
{
"cell_type": "markdown",
"id": "0d72fb7d",
"metadata": {},
"source": [
"#### Condition"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ac86f2e4",
"metadata": {},
"outputs": [],
"source": [
"cond_gte = ConditionGreaterThanOrEqualTo(\n",
" left=JsonGet(\n",
" step_name=step_eval.name,\n",
" property_file=evaluation_report,\n",
" json_path=\"eval_accuracy\",\n",
" ),\n",
" right=threshold_accuracy,\n",
")\n",
"\n",
"step_cond = ConditionStep(\n",
" name=\"CheckHuggingfaceEvalAccuracy\",\n",
" conditions=[cond_gte],\n",
" if_steps=[step_register, step_deployment],\n",
" else_steps=[],\n",
")"
]
},
{
"cell_type": "markdown",
"id": "107f4353",
"metadata": {},
"source": [
"
\n",
"\n",
"## 2. Pipeline definition and execution\n",
"\n",
"---\n",
"\n",
"모든 스텝을 정의하였다면 파이프라인을 정의합니다. \n",
"\n",
"파이프라인 인스턴스는 이름(`name`), 파라메터(`parameters`), 및 스텝(`steps`)으로 구성됩니다. \n",
"- 파이프라인 이름: (AWS 계정, 리전) 쌍 내에서 고유해야 합니다 \n",
"- 파라메터: 스텝 정의에 사용했던 모든 파라메터들을 파이프라인에서 정의해야 합니다. \n",
"- 스텝: 리스트 형태로 이전 스텝들을 정의합니다. 내부적으로 데이터 종속성을 사용하여 각 스텝 간의 관계를 DAG으로 정의하기 때문에 실행 순서대로 나열할 필요는 없습니다."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d106b946",
"metadata": {},
"outputs": [],
"source": [
"pipeline = Pipeline(\n",
" name=f\"HuggingFaceDemoPipeline\",\n",
" parameters=[\n",
" model_id,\n",
" tokenizer_id, \n",
" dataset_name,\n",
" processing_instance_type,\n",
" processing_instance_count,\n",
" processing_script,\n",
" training_entry_point,\n",
" training_source_dir,\n",
" training_instance_type,\n",
" training_instance_count,\n",
" evaluation_script,\n",
" evaluation_instance_type,\n",
" evaluation_instance_count,\n",
" threshold_accuracy,\n",
" n_gpus,\n",
" epochs,\n",
" seed,\n",
" eval_batch_size,\n",
" train_batch_size,\n",
" learning_rate,\n",
" ],\n",
" steps=[step_process, step_train, step_eval, step_cond],\n",
" sagemaker_session=sagemaker_session,\n",
")"
]
},
{
"cell_type": "markdown",
"id": "1ee8e759",
"metadata": {},
"source": [
"#### Check the pipeline definition\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "81b33f4d",
"metadata": {},
"outputs": [],
"source": [
"import json\n",
"\n",
"definition = json.loads(pipeline.definition())\n",
"definition"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "68ee82c4",
"metadata": {},
"outputs": [],
"source": [
"pipeline.upsert(role_arn=role)"
]
},
{
"cell_type": "markdown",
"id": "a842507d",
"metadata": {},
"source": [
"#### Run the pipeline\n",
"\n",
"파이프라인을 실행합니다."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d751e8f4",
"metadata": {},
"outputs": [],
"source": [
"execution = pipeline.start()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a94710df",
"metadata": {},
"outputs": [],
"source": [
"execution.describe()"
]
},
{
"cell_type": "markdown",
"id": "0cd45ec5",
"metadata": {},
"source": [
"파이프라인 실행이 완료될 때까지 기다립니다. SageMaker Studio 콘솔을 통해 진행 상황을 확인할 수도 있습니다."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "db156269",
"metadata": {},
"outputs": [],
"source": [
"execution.wait()"
]
},
{
"cell_type": "markdown",
"id": "a7636b5a",
"metadata": {},
"source": [
"실행된 스텝들을 리스트업합니다."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1a55513c",
"metadata": {},
"outputs": [],
"source": [
"execution.list_steps()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "07587974",
"metadata": {},
"outputs": [],
"source": [
"time.sleep(30) # give time to catch up"
]
},
{
"cell_type": "markdown",
"id": "2bcf73d8",
"metadata": {},
"source": [
"
\n",
"\n",
"## 3. Getting predictions from the endpoint\n",
"---\n",
"\n",
"파이프라인의 모든 단계가 정상적으로 실행되었다면 배포된 엔드포인트를 통해 실시간 추론을 수행할 수 있습니다."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a6052b87",
"metadata": {},
"outputs": [],
"source": [
"from sagemaker.huggingface import HuggingFacePredictor\n",
"from IPython.core.display import display, HTML\n",
"\n",
"endpoint_name = model_name\n",
"hf_predictor = HuggingFacePredictor(endpoint_name,sagemaker_session=sagemaker_session)\n",
"\n",
"def make_endpoint_link(region, endpoint_name, endpoint_task):\n",
" endpoint_link = f'{endpoint_task} Review Endpoint' \n",
" return endpoint_link \n",
"\n",
"# check if endpoint is up and running\n",
"endpoint_link = make_endpoint_link(region, endpoint_name, '[Deploy model using SageMaker Pipelines]')\n",
"display(HTML(endpoint_link))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "601ab5f8",
"metadata": {},
"outputs": [],
"source": [
"# example request, you always need to define \"inputs\"\n",
"data = {\n",
" \"inputs\": [\n",
" \"정말 재미있습니다. 세 번 봐도 질리지 않아요.\",\n",
" \"시간이 아깝습니다. 다른 영화를 보세요.\"\n",
" ]\n",
"}\n",
"hf_predictor.predict(data)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e75c1857",
"metadata": {},
"outputs": [],
"source": [
"data = {\n",
" \"inputs\": [\n",
" \"10점 만점에 1점만 줄께요.\",\n",
" \"내용이 너무 아른거려서 잠을 이룰 수가 없었어요. 감동의 향연!\",\n",
" \"액션광이기에 내용을 기대했지만 앙꼬없는 찐빵이다\"\n",
" ]\n",
"}\n",
"hf_predictor.predict(data)"
]
},
{
"cell_type": "markdown",
"id": "312a6272",
"metadata": {},
"source": [
"
\n",
"\n",
"## Clean up\n",
"---\n",
"\n",
"과금을 방지하기 위해 사용하지 않는 리소스를 삭제합니다. 아래 코드셀은 Lambda 함수와 엔드포인트를 삭제합니다. "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "68935160",
"metadata": {},
"outputs": [],
"source": [
"sm_client = boto3.client(\"sagemaker\")\n",
"\n",
"# Delete the Lambda function\n",
"step_deployment.func.delete()\n",
"\n",
"# Delete the endpoint\n",
"hf_predictor.delete_endpoint()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "conda_pytorch_latest_p37",
"language": "python",
"name": "conda_pytorch_latest_p37"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}