Snowpark Container Services에서 모델 제공

참고

이 기능은 AWS 및 Azure 상업 리전에서 사용 가능합니다. 정부 리전에서는 사용할 수 없습니다.

참고

이 항목에 설명된 Snowpark Container Services (SPCS)에서 모델을 실행하는 기능은 snowflake-ml-python 버전 1.8.0 이상에서 사용할 수 있습니다.

Snowflake Model Registry 를 사용하면 Model Serving을 통해 웨어하우스(기본값)에서 모델을 실행하거나 Snowpark Container Services(SPCS) 컴퓨팅 풀에서 모델을 실행할 수 있습니다. 웨어하우스에서 모델을 실행하면 사용할 수 있는 모델의 크기와 종류에 몇 가지 제한이 있습니다(특히, Snowflake conda 채널에서 제공되는 패키지로 종속성을 충족할 수 있는 Small~Medium 크기의 CPU 전용 모델).

Snowpark Container Services(SPCS)에서 모델을 실행하면 이러한 제한이 완화되거나 완전히 제거됩니다. Python Package Index(PyPI) 또는 기타 소스에서 제공하는 패키지를 포함하여 원하는 모든 패키지를 사용할 수 있습니다. Large 모델은 분산 클러스터 GPUs 상에서 실행할 수 있습니다. 사용자는 Docker나 Kubernetes와 같은 컨테이너 기술에 대해 전혀 몰라도 됩니다. Snowflake Model Serving이 모든 세부 사항을 처리합니다.

핵심 개념

Snowflake Model Serving 추론 아키텍처의 간략한 개요는 다음과 같습니다.

Snowpark Container Services 아키텍처의 모델 추론

아키텍처의 주요 구성 요소는 다음과 같습니다.

  • 추론 서버: 모델을 실행하고 예측을 제공하는 서버입니다. 추론 서버는 여러 추론 프로세스를 사용하여 노드의 기능을 최대한 활용할 수 있습니다. 모델에 대한 요청은 메모리 부족 상태를 피하기 위해 유입 요청 큐를 관리하여 서버에서 과부하가 발생하면 클라이언트를 거부하는 수신 제어를 통해 전송됩니다. 현재 Snowflake는 모든 유형의 모델에 대해 추론을 실행할 수 있는 단순하고 유연한 Python 기반 추론 서버를 제공합니다. Snowflake는 향후에 특정 모델 유형에 최적화된 추론 서버를 제공할 계획입니다.

  • 모델별 Python 환경: 종속성을 다운로드하고 모델을 로드하는 데 필요한 시간 등 모델을 시작할 때 지연 시간을 줄이기 위해 Snowflake는 특정 모델의 종속성을 캡슐화하는 컨테이너를 빌드합니다.

  • 서비스 함수: 웨어하우스에서 실행 중인 코드에서 추론 서버와 통신하기 위해, Snowflake Model Serving은 모델과 동일한 서명을 갖지만 대신 외부 함수 프로토콜 을 통해 추론 서버를 호출하는 함수를 빌드합니다.

  • 수신 엔드포인트: Snowflake 외부의 애플리케이션이 모델을 호출할 수 있도록 Snowflake Model Serving은 공용 인터넷에 액세스할 수 있는 선택적 HTTP 엔드포인트 를 프로비저닝할 수 있습니다.

어떻게 작동하나요?

다음 다이어그램은 Snowflake Model Serving이 웨어하우스 또는 SPCS에서 모델을 배포하고 서비스하는 방법을 보여줍니다.

Snowpark Container Services에서 모델 배포

이와 같이, SPCS 배포 경로는 웨어하우스 배포 경로보다 더 복잡하지만, 모델과 해당 종속성이 있는 컨테이너 이미지를 구축하고 모델을 실행하는 추론 서버를 생성하는 등 Snowflake Model Serving이 모든 작업을 자동으로 수행합니다.

전제 조건

시작하기 전에 다음이 있는지 확인하십시오.

컴퓨팅 풀 만들기

Snowpark Container Services(SPCS)는 컴퓨팅 풀에서 컨테이너 이미지를 실행합니다. 적합한 컴퓨팅 풀이 아직 없으면 다음과 같이 생성합니다.

CREATE COMPUTE POOL IF NOT EXISTS mypool
    MIN_NODES = 2
    MAX_NODES = 4
    INSTANCE_FAMILY = 'CPU_X64_M'
    AUTO_RESUME = TRUE;
Copy

유효한 인스턴스 패밀리 목록은 패밀리 이름 테이블 을 참조하십시오.

모델을 실행할 역할이 컴퓨팅 풀의 소유자이거나 풀에 대한 USAGE 또는 OPERATE 권한이 있는지 확인합니다.

이미지 리포지토리 만들기

Snowflake Model Serving은 모델과 해당 종속성을 보관하는 컨테이너 이미지를 빌드합니다. 이 이미지를 저장하려면 이미지 리포지토리가 필요합니다. 아직 없다면 다음과 같이 생성합니다.

CREATE IMAGE REPOSITORY IF NOT EXISTS my_inference_images
Copy

소유하지 않은 이미지 리포지토리를 사용하려는 경우 컨테이너 이미지를 빌드할 역할에 리포지토리에 대한 READ, WRITE, SERVICE READ 및 SERVICE WRITE 권한이 있어야 합니다. 다음과 같이 이러한 권한을 부여합니다.

GRANT READ ON IMAGE REPOSITORY my_inference_images TO ROLE myrole;
GRANT WRITE ON IMAGE REPOSITORY my_inference_images TO ROLE myrole;
GRANT SERVICE READ ON IMAGE REPOSITORY my_inference_images TO ROLE myrole;
GRANT SERVICE WRITE ON IMAGE REPOSITORY my_inference_images TO ROLE myrole;
Copy

필수 권한

모델 서비스는 Snowpark Container Services 에서 실행됩니다. Model Serving을 사용하려면 사용자에게 다음 권한이 필요합니다.

  • 서비스가 실행될 컴퓨팅 풀 의 USAGE 또는 OWNERSHIP.

  • READ, WRITE, SERVICE READ, SERVICE WRITE 의 4가지 권한을 모두 갖춘 이미지 리포지토리. 사용자가 이미지 리포지토리를 소유한 경우 모든 권한이 자동으로 부여됩니다.

  • Model Serving에 수신 엔드포인트가 필요한 경우 사용자는 계정에 대해 BIND SERVICE ENDPOINT 권한이 있어야 합니다.

  • 모델 소유자만 모델을 Serving에 배포할 수 있습니다. 비소유자가 추론에 액세스할 수 있도록 하려면 소유자가 서비스를 배포한 다음 서비스 역할을 INFERENCE_SERVICE_FUNCTION_USAGE 에 부여하여 서비스 함수를 공유하고 ALL_ENDPOINTS_USAGE 를 부여하여 수신 엔드포인트를 공유해야 합니다.

제한 사항

Snowpark Container Services에서 서비스하는 모델에는 다음과 같은 제한이 적용됩니다.

  • 모델 소유자만 모델을 Snowpark Container Services에 배포할 수 있습니다.

  • 컴퓨팅 클러스터의 크기는 자동으로 조정되지 않습니다. ALTER SERVICE myservice MIN_INSTANCES = n 을 사용하여 런타임 시에 인스턴스 수를 수동으로 변경할 수 있습니다. 일부 경우, 이로 인해 기존 노드가 실패합니다.

  • 서비스 및 컴퓨팅 풀의 확장 속도가 예상보다 느립니다.

  • 수신이 활성화된 추론 서비스는 일시 중단할 수 없습니다.

  • 이미지 빌드 소요되는 시간이 1시간을 초과하면 실패합니다.

  • 테이블 함수는 지원되지 않습니다. 일반 함수가 없는 모델은 현재 Snowpark Container Services에 배포할 수 없습니다.

모델을 SPCS에 배포하기

새 모델 버전을 기록 (reg.log_model 사용)하거나 기존 모델 버전에 대한 참조를 획득 (reg.get_model(...).version(...))합니다. 두 경우 모두에서 ModelVersion 오브젝트를 참조합니다.

모델 종속성 및 적합성

모델의 종속성은 웨어하우스에서 실행할 수 있는지, SPCS 서비스에서 실행할 수 있는지 또는 둘 다에서 실행할 수 있는지에 따라 결정됩니다. 필요한 경우, 의도적으로 종속성을 지정하여 해당 환경 중 하나에서 모델을 실행할 수 없도록 할 수 있습니다.

Snowflake conda 채널은 웨어하우스에서만 사용할 수 있으며 웨어하우스 종속성에 대한 유일한 소스입니다. 기본적으로 SPCS 모델에 대한 conda 종속성은 conda-forge에서 종속성을 가져옵니다.

모델 버전을 기록하면 모델의 conda 종속성은 Snowflake conda 채널에 대해 검증됩니다. 모델의 모든 conda 종속성이 해당 위치에서 사용 가능한 경우 해당 모델은 웨어하우스에서 실행할 수 있는 것으로 간주됩니다. 또한 서비스를 생성할 때까지는 확인되지 않지만 모든 종속성을 conda-forge에서 사용할 수 있는 경우 SPCS 서비스에서 실행할 수 있습니다.

PyPI 종속성으로 기록된 모델은 SPCS에서 실행해야 합니다. 1개 이상의 PyPI 종속성을 지정하는 것은 모델을 웨어하우스에서 실행할 수 없게 만드는 한 가지 방법입니다. 모델에 conda 종속성만 있는 경우 다음 예제와 같이 명시적 채널(conda-forge도 가능)을 사용하여 1개 이상을 지정하십시오.

# reg is a snowflake.ml.registry.Registry object
reg.log_model(
    model_name="my_model",
    version_name="v1",
    model=model,
    conda_dependencies=["conda-forge::scikit-learn"])
Copy

SPCS 배포 모델에 대해, conda 종속성이 있는 경우 먼저 설치한 다음 pip 를 사용하여 모든 PyPI 종속성을 conda 환경에 설치합니다.

서비스를 만듭니다.

SPCS 서비스를 생성하고 여기에 모델을 배포하려면 다음 예제와 같이 모델 버전의 create_service 메서드를 호출합니다.

# mv is a snowflake.ml.model.ModelVersion object
mv.create_service(service_name="myservice",
                  service_compute_pool="my_compute_pool",
                  image_repo="mydb.myschema.my_image_repo",
                  ingress_enabled=True,
                  gpu_requests=None)
Copy

create_service 의 필수 인자는 다음과 같습니다.

  • service_name: 생성할 서비스의 이름입니다. 이 이름은 계정 내에서 고유해야 합니다.

  • service_compute_pool: 모델을 실행하는 데 사용할 컴퓨팅 풀의 이름입니다. 컴퓨팅 풀은 기존에 있어야 합니다.

  • image_repo: 컨테이너 이미지를 저장하는 데 사용할 이미지 리포지토리의 이름입니다. 리포지토리가 이미 있어야 하며 사용자에게 SERVICE WRITE 권한(또는 OWNERSHIP)이 있어야 합니다.

  • ingress_enabled: True이면 HTTP 엔드포인트를 통해 서비스에 액세스할 수 있습니다. 엔드포인트를 생성하려면 사용자에게 BIND SERVICE ENDPOINT 권한이 있어야 합니다.

  • gpu_requests: GPU의 개수를 지정하는 문자열입니다. CPU 또는 GPU에서 실행할 수 있는 모델의 경우 이 인자에 따라 모델이 CPU에서 또는 GPUs에서 실행될지가 결정됩니다. 모델이 CPU에서만 실행할 수 있는 알려진 유형(예: scikit-learn 모델)인 경우, GPUs가 요청되면 이미지 빌드가 실패합니다.

새 모델을 배포하는 경우 CPU 기반 모델은 서비스를 만드는 데 5분, GPU 기반 모델은 10분이 걸릴 수 있습니다. 컴퓨팅 풀이 유휴 상태이거나 크기 조정이 필요한 경우 서비스를 만드는 데 시간이 더 오래 걸릴 수 있습니다.

이 예제에서는 필수적이고 가장 일반적으로 사용되는 인자만 보여줍니다. 전체 인자 목록은 ModelVersion API 참조 섹션을 참조하십시오.

기본 서비스 구성

기본적으로 Inference Server는 대부분의 사용 사례에 적합한 사용하기 쉬운 기본값을 사용합니다. 해당 설정은 다음과 같습니다.

  • 작업자 스레드 수: CPU 기반 모델의 경우 서버는 CPU의 두 배에 워커 프로세스 하나를 더한 수를 사용합니다. GPU 기반 모델은 1개의 워커 프로세스를 사용합니다. create_service 호출에서 num_workers 인자를 사용하여 이를 재정의할 수 있습니다.

  • 스레드 안전: 일부 모델은 스레드에 안전하지 않습니다. 따라서 서비스는 각 워커 프로세스에 대해 별도의 모델 복사본을 로드합니다. 이로 인해 대규모 모델의 경우 리소스 고갈이 발생할 수 있습니다.

  • 노드 활용: 기본적으로 하나의 추론 서버 인스턴스는 실행 중인 노드의 모든 CPU 및 메모리를 요청하여 전체 노드에 요청합니다. 인스턴스별 리소스 할당을 사용자 지정하려면 cpu_requests, memory_requests, gpu_requests 등의 인자를 사용합니다.

  • 엔드포인트: 추론 엔드포인트의 이름은 추론 이며 포트 5000을 사용합니다. 이들은 사용자 지정할 수 없습니다.

  • 자동 일시 중단: 추론 서비스는 수신 엔드포인트가 없는 경우 30분 동안 활동이 없으면 자동 일시 중단됩니다. 일시 중단된 서비스는 요청을 받으면 자동으로 재개됩니다.

컨테이너 이미지 빌드 동작

기본적으로 Snowflake Model Serving은 모델을 실행하는 데 사용되는 것과 동일한 컴퓨팅 풀을 사용하여 컨테이너 이미지를 빌드합니다. 이 추론 컴퓨팅 풀로 인해 이 작업에 대해 과부하가 발생할 수 있습니다(예: 컨테이너 이미지 빌드에 GPUs가 사용되지 않음). 대부분의 경우 이는 컴퓨팅 비용에 큰 영향을 미치지 않지만, 우려되는 경우 image_build_compute_pool 인자를 지정하여 이미지 빌드에 덜 강력한 컴퓨팅 풀을 선택할 수 있습니다.

create_service 는 멱등 함수입니다. 여러 번 호출한다고 해서 매번 이미지 생성이 트리거되는 것은 아닙니다. 그러나 컨테이너 이미지는 종속 패키지의 취약점 수정 등 추론 서비스가 업데이트될 때 다시 빌드될 수 있습니다. 이 경우 create_service 는 자동으로 이미지 재구성을 트리거합니다.

참고

Snowpark ML 모델링 클래스 를 사용하여 개발된 모델은 GPU 가 있는 환경에는 배포할 수 없습니다. 해결 방법으로 네이티브 모델을 추출하여 배포할 수 있습니다. 예:

# Train a model using Snowpark ML
from snowflake.ml.modeling.xgboost import XGBRegressor
regressor = XGBRegressor(...)
regressor.fit(training_df)

# Extract the native model
xgb_model = regressor.to_xgboost()
# Test the model with pandas dataframe
pandas_test_df = test_df.select(['FEATURE1', 'FEATURE2', ...]).to_pandas()
xgb_model.predict(pandas_test_df)

# Log the model in Snowflake Model Registry
mv = reg.log_model(xgb_model,
                   model_name="my_native_xgb_model",
                   sample_input_data=pandas_test_df,
                   comment = 'A native XGB model trained from Snowflake Modeling API',
                   )
# Now we should be able to deploy to a GPU compute pool on SPCS
mv.create_service(
    service_name="my_service_gpu",
    service_compute_pool="my_gpu_pool",
    image_repo="my_repo",
    max_instances=1,
    gpu_requests="1",
)
Copy

사용자 인터페이스

배포된 모델은 Model Registry Snowsight UI 에서 관리할 수 있습니다. 자세한 내용은 모델 추론 서비스 섹션을 참조하십시오.

SPCS에 배포된 모델 사용하기

모델 메서드는 SQL, Python 또는 HTTP 엔드포인트를 사용하여 호출할 수 있습니다.

SQL

Snowflake Model Serving은 모델을 SPCS에 배포할 때 서비스 함수를 생성합니다. 이러한 함수는 SQL에서 SPCS 컴퓨팅 풀에서 실행되는 모델로 연결되는 가교의 역할을 합니다. 모델의 각 메소드마다 1개의 서비스 함수가 생성되며, service_name!method_name 같은 이름이 지정됩니다. 예를 들어, 모델에 PREDICTEXPLAIN 이라는 2개의 메서드가 있고 MY_SERVICE 라는 서비스에 배포되는 경우 결과 서비스 함수는 MY_SERVICE!PREDICTMY_SERVICE!EXPLAIN 입니다.

참고

서비스 함수는 서비스 내에 포함되어 있습니다. 이러한 이유로 서비스 함수는 단일 액세스 제어 지점, 즉 서비스만을 갖습니다. 단일 서비스 내에서 각 함수에 대해 서로 다른 액세스 제어 권한을 가질 수 없습니다.

모델의 SQL 형식 서비스 함수를 호출하려면 다음과 같은 코드를 사용합니다.

-- See signature of the inference function in SQL.
SHOW FUNCTIONS IN MODEL my_native_xgb_model VERSION ...;

-- Call the inference function in SQL following the same signature (from `arguments` column of the above query)
SELECT MY_SERVICE!PREDICT(feature1, feature2, ...) FROM input_data_table;
Copy

Python

메서드가 실행될 서비스를 지정하는 service_name 인자가 포함된 모델 버전 오브젝트의 run 메서드를 사용하여 서비스의 메서드를 호출합니다. 예:

# Get signature of the inference function in Python
# mv is a snowflake.ml.model.ModelVersion object
mv.show_functions()
# Call the function in Python
service_prediction = mv.run(
    test_df,
    function_name="predict",
    service_name="my_service")
Copy

service_name 인자를 포함시키지 않으면 모델이 웨어하우스에서 실행됩니다.

HTTP 엔드포인트

수신이 활성화된 상태로 서비스를 배포하면 서비스를 호출할 수 있는 HTTP 엔드포인트가 생성됩니다. SHOW ENDPOINTS IN SERVICE 명령을 사용하여 엔드포인트를 찾을 수 있습니다.

SHOW ENDPOINTS IN SERVICE my_service;
Copy

ingress_url 열을 기록해 둡니다. 이 열은 random_str-account-id.snowflakecomputing.app 과 유사해야 합니다. DNS 이름 제한 사항 이 적용됩니다. URL 에서 메서드 이름의 밑줄(_)은 대시(-)로 바뀝니다(예: predict_proba 의 URL 은 url/predict-proba 임).

사용자는 프로그래밍 방식으로 공용 엔드포인트를 사용하여 서비스를 호출할 수 있습니다. 애플리케이션은 키 페어 인증 을 사용하여 공용 엔드포인트에 대한 요청을 인증합니다. 키 페어에서 JSON 웹 토큰(JWT)을 생성하고, JWT 토큰을 Snowflake와 OAuth 토큰으로 교환한 다음, OAuth 토큰을 사용하여 서비스의 공용 엔드포인트에 대한 요청을 인증합니다. 예는 프로그래밍 방식으로 공용 엔드포인트에 액세스하기 섹션을 참조하십시오.

필수 데이터 형식에 대한 자세한 내용은 원격 서비스 입력 및 출력 데이터 타입 섹션을 참조하십시오.

모델 서비스 HTTP 엔드포인트 사용과 관련한 예제는 GPU 기반 추론을 위한 Hugging Face 문장 변환기 배포하기 섹션을 참조하십시오.

서비스 관리하기

Snowpark Container Services는 서비스 관리를 위한 SQL 인터페이스를 제공합니다. 다른 SPCS 서비스를 관리할 때와 마찬가지로 Snowflake Model Serving에서 생성한 SPCS 서비스에도 DESCRIBE SERVICEALTER SERVICE 명령을 사용할 수 있습니다. 예를 들어 다음을 할 수 있습니다.

  • 서비스의 MIN_INSTANCES 및 기타 속성 변경하기

  • 서비스 삭제

  • 다른 계정에 서비스 공유

  • 서비스 소유권 변경(새로운 소유자는 모델에 액세스할 수 있어야 함)

참고

서비스 소유자가 어떤 이유로든 기본 모델에 대한 액세스 권한을 상실하면 다시 시작한 후 서비스가 작동을 멈춥니다. 작동 멈춤은 다시 시작할 때까지 계속 유지됩니다.

재현성과 디버깅 가능성을 보장하기 위해 기존 추론 서비스의 사양을 변경할 수 없습니다. 하지만 사용자는 사양을 복사하고 사용자 지정한 다음, 사용자 지정 사양을 사용하여 모델을 호스팅하는 자체 서비스를 생성할 수 있습니다. 하지만 이를 통해 기본 모델이 삭제되는 것을 방지할 수는 없습니다. 또한 계보 를 추적하지 않습니다. Snowflake Model Serving이 서비스를 생성하도록 허용하는 것이 가장 좋습니다.

서비스 일시 중단

서비스 함수를 통해 SQL 에서만 서비스를 사용하는 경우 ingress_enabled 매개 변수를 True로 설정하지 마십시오. 수신을 활성화한다는 것은 수신되는 HTTP 요청에 응답할 수 있도록 서비스가 항상 실행 상태를 유지해야 함을 의미합니다. 수신이 활성화되지 않은 경우, 추론 서비스는 30분 동안 활동이 없으면 자동으로 일시 중단되고 요청을 받으면 자동으로 재개됩니다.

서비스를 수동으로 일시 중단하려면 ALTER SERVICE 명령을 사용합니다.

ALTER SERVICE my_service SUSPEND;
Copy

새로운 요청을 받으면 서비스가 자동으로 재개되는 경우 예약 및 시작 지연이 발생할 수 있습니다. 스케줄링 지연은 컴퓨팅 풀의 가용성에 따라 달라지며, 시작 지연은 모델의 크기에 따라 달라집니다.

모델 삭제하기

서비스에서 사용 중인 모델 또는 모델 버전(실행 중 또는 일시 중단)은 삭제할 수 없다는 제한이 있지만, SQL 인터페이스 또는 Python API를 사용하여 평소와 같이 모델 및 모델 버전을 관리할 수 있습니다. 모델이나 모델 버전을 삭제하려면 먼저 서비스를 삭제하십시오.

이 예에서는 이미 컴퓨팅 풀과 이미지 리포지토리를 만들고 필요에 따라 권한을 부여했다고 가정합니다. 자세한 내용은 전제 조건 섹션을 참조하십시오.

CPU 기반 추론을 위한 XGBoost 모델 배포하기

다음 코드는 SPCS에서 추론을 위해 XGBoost 모델을 배포한 다음 배포된 모델을 추론에 사용하는 주요 단계를 보여줍니다. 이 예제에 대한 노트북은 사용 가능합니다.

from snowflake.ml.registry import registry
from snowflake.ml.utils.connection_params import SnowflakeLoginOptions
from snowflake.snowpark import Session

from xgboost import XGBRegressor

# your model training code here output of which is a trained xgb_model

# Open model registry
reg = registry.Registry(session=session, database_name='my_registry_db', schema_name='my_registry_schema')

# Log the model in Snowflake Model Registry
model_ref = reg.log_model(
    model_name="my_xgb_forecasting_model",
    version_name="v1",
    model=xgb_model,
    conda_dependencies=["scikit-learn","xgboost"],
    sample_input_data=pandas_test_df,
    comment="XGBoost model for forecasting customer demand"
)

# Deploy the model to SPCS
model_ref.create_service(
    service_name="forecast_model_service",
    service_compute_pool="my_cpu_pool",
    image_repo="my_image_repo",
    ingress_enabled=True)

# See all services running a model
model_ref.list_services()

# Run on SPCS
model_ref.run(pandas_test_df, function_name="predict", service_name="forecast_model_service")

# Delete the service
model_ref.delete_service("forecast_model_service")
Copy

이 모델은 수신이 활성화되어 있으므로 HTTP 엔드포인트를 다음과 같이 호출할 수 있습니다.

import json
import numpy as np
from pprint import pprint
import requests
import snowflake.connector

# Generate headers including authorization.
# This example uses session token authorization. Ideally key-pair authentication is used for API access.
def initiate_snowflake_connection():
    connection_parameters = SnowflakeLoginOptions("connection_name")
    connection_parameters["session_parameters"] = {"PYTHON_CONNECTOR_QUERY_RESULT_FORMAT": "json"}
    snowflake_conn = snowflake.connector.connect(**connection_parameters)
    return snowflake_conn

def get_headers(snowflake_conn):
    token = snowflake_conn._rest._token_request('ISSUE')
    headers = {'Authorization': f'Snowflake Token=\"{token["data"]["sessionToken"]}\"'}
    return headers

headers = get_headers(initiate_snowflake_connection())

# Put the endpoint url with method name `predict`
# The endpoint url can be found with `show endpoints in service <service_name>`.
URL = 'https://<random_str>-<organization>-<account>.snowflakecomputing.app/predict'

# Prepare data to be sent
data = {"data": np.column_stack([range(pandas_test_df.shape[0]), pandas_test_df.values]).tolist()}

# Send over HTTP
def send_request(data: dict):
    output = requests.post(URL, json=data, headers=headers)
    assert (output.status_code == 200), f"Failed to get response from the service. Status code: {output.status_code}"
    return output.content

# Test
results = send_request(data=data)
pprint(json.loads(results))
Copy

GPU 기반 추론을 위한 Hugging Face 문장 변환기 배포하기

다음 코드는 HTTP 엔드포인트를 포함한 Hugging Face 문장 변환기를 학습시키고 배포합니다.

이 예제에는 문장 변환기 패키지, GPU 컴퓨팅 풀, 이미지 리포지토리가 필요합니다.

from snowflake.ml.registry import registry
from snowflake.ml.utils.connection_params import SnowflakeLoginOptions
from snowflake.snowpark import Session
from sentence_transformers import SentenceTransformer

session = Session.builder.configs(SnowflakeLoginOptions("connection_name")).create()
reg = registry.Registry(session=session, database_name='my_registry_db', schema_name='my_registry_schema')

# Take an example sentence transformer from HF
embed_model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')

# Have some sample input data
input_data = [
    "This is the first sentence.",
    "Here's another sentence for testing.",
    "The quick brown fox jumps over the lazy dog.",
    "I love coding and programming.",
    "Machine learning is an exciting field.",
    "Python is a popular programming language.",
    "I enjoy working with data.",
    "Deep learning models are powerful.",
    "Natural language processing is fascinating.",
    "I want to improve my NLP skills.",
]

# Log the model with pip dependencies
pip_model = reg.log_model(
    embed_model,
    model_name="sentence_transformer_minilm",
    version_name="pip",
    sample_input_data=input_data,  # Needed for determining signature of the model
    pip_requirements=["sentence-transformers", "torch", "transformers"], # If you want to run this model in the Warehouse, you can use conda_dependencies instead
)

# Force Snowflake to not try to check warehouse
conda_forge_model = reg.log_model(
    embed_model,
    model_name="sentence_transformer_minilm",
    version_name="conda_forge_force",
    sample_input_data=input_data,
    # setting any package from conda-forge is sufficient to know that it can't be run in warehouse
    conda_dependencies=["sentence-transformers", "conda-forge::pytorch", "transformers"]
)

# Deploy the model to SPCS
pip_model.create_service(
    service_name="my_minilm_service",
    service_compute_pool="my_gpu_pool",  # Using GPU_NV_S - smallest GPU node that can run the model
    image_repo="my_image_repo",
    ingress_enabled=True,
    gpu_requests="1", # Model fits in GPU memory; only needed for GPU pool
    max_instances=4, # 4 instances were able to run 10M inferences from an XS warehouse
)

# See all services running a model
pip_model.list_services()

# Run on SPCS
pip_model.run(input_data, function_name="encode", service_name="my_minilm_service")

# Delete the service
pip_model.delete_service("my_minilm_service")
Copy

SQL 에서 다음과 같이 서비스 함수를 호출할 수 있습니다.

SELECT my_minilm_service!encode('This is a test sentence.');
Copy

마찬가지로 HTTP 엔드포인트를 다음과 같이 호출할 수 있습니다.

import json
from pprint import pprint
import requests

# Put the endpoint url with method name `encode`
URL='https://<random_str>-<account>.snowflakecomputing.app/encode'

# Prepare data to be sent
data = {
    'data': []
}
for idx, x in enumerate(input_data):
    data['data'].append([idx, x])

# Send over HTTP
def send_request(data: dict):
    output = requests.post(URL, json=data, headers=headers)
    assert (output.status_code == 200), f"Failed to get response from the service. Status code: {output.status_code}"
    return output.content

# Test
results = send_request(data=data)
pprint(json.loads(results))
Copy

GPU 기반 추론을 위한 PyTorch 모델 배포하기

GPU 추론을 위해 PyTorch 딥러닝 추천 모델(DLRM)을 훈련시키고 SPCS에 배포하는 예제는 이 빠른 시작 을 참조하십시오.

모범 사례

이미지 리포지토리 공유하기

여러 사용자 또는 역할이 동일한 모델을 사용하는 것은 일반적입니다. 단일 이미지 리포지토리를 사용하면 이미지를 한 번만 빌드하여 모든 사용자가 재사용할 수 있어 시간과 비용을 절약할 수 있습니다. 리포지토리를 사용할 모든 역할에는 리포지토리에 대한 SERVICE READ, SERVICE WRITE, READ, WRITE 권한이 필요합니다. 종속성을 업데이트하기 위해 이미지를 다시 빌드해야 할 수 있으므로 쓰기 권한을 유지해야 하며, 이미지를 처음 빌드한 후에는 취소하지 마십시오.

추론 서비스 크기 조정하기

Snowpark Container Services 자동 크기 조정은 매우 보수적이며 대부분의 ML 워크로드에 대해 충분히 빠르게 확장하거나 축소하지 않습니다. 따라서 Snowflake는 일반적인 워크로드에 필요한 성능을 얻기 위해 MIN_INSTANCES 및 MAX_INSTANCES를 모두 같은 값으로 설정하고 이 값을 선택하는 것을 권장합니다. 다음과 같은 SQL을 사용합니다.

ALTER SERVICE myservice
    SET MIN_INSTANCES = <new_num>
        MAX_INSTANCES = <new_num>;
Copy

동일한 이유로, 처음에 Python API를 사용하여 서비스를 생성할 때 create_service 메서드는 max_instances 만 허용하고 min_instances 에는 동일한 값을 사용합니다.

노드 유형 및 인스턴스 수 선택하기

모델이 메모리에 들어갈 수 있는 가장 작은 GPU 노드를 사용하십시오. 더 큰 GPU 노드에서 num_workers 를 늘리는 것과 반대로 인스턴스 수를 늘리는 방식으로 크기를 조정합니다. 예를 들어, 모델이 GPU_NV_S (Azure의 경우GPU_NV_SM) 인스턴스 유형에 맞는 경우 더 큰 GPU 인스턴스에서 gpu_requestsnum_workers 를 조합하여 사용하는 대신 gpu_requests=1 를 사용하고 max_instances 를 늘려 확장합니다.

웨어하우스 크기 선택하기

웨어하우스가 클수록 더 많은 병렬 요청이 추론 서버로 전송됩니다. 추론은 비용이 많이 드는 작업이므로 가능하면 작은 규모의 웨어하우스를 사용하십시오. Medium보다 큰 웨어하우스 크기를 사용하면 쿼리 성능이 가속화되지 않고 추가 비용이 발생합니다.

문제 해결하기

SPCS 배포 모니터링하기

다음 SQL 쿼리를 사용하여 실행 중인 서비스를 검사하여 배포를 모니터링할 수 있습니다.

SHOW SERVICES IN COMPUTE POOL my_compute_pool;
Copy

다음의 두 작업이 시작됩니다.

  • MODEL_BUILD_xxxxx: 이름이 충돌하는 것을 방지하기 위해 이름의 마지막 글자는 무작위로 지정됩니다. 이 작업은 이미지를 빌드하고 이미지가 빌드된 후 종료됩니다. 이미지가 이미 있으면 작업을 건너뜁니다.

    이 로그는 패키지 종속성 충돌과 같은 문제를 디버깅하는 데 유용합니다. 이 작업의 로그를 보려면 아래 SQL를 실행하고 마지막 문자를 동일하게 사용해야 합니다.

    CALL SYSTEM$GET_SERVICE_LOGS('MODEL_BUILD_xxxxx', 0, 'model-build');
    
    Copy
  • MYSERVICE: create_service 에 대한 호출에 지정된 서비스 이름입니다. 이 작업은 MODEL_BUILD 작업이 성공하거나 건너뛰면 시작됩니다. 이 작업의 로그를 보려면 아래 SQL을 실행합니다.

    CALL SYSTEM$GET_SERVICE_LOGS('MYSERVICE', 0, 'model-inference');
    
    Copy

    빌드 작업 또는 서비스가 삭제되어 SYSTEM$GET_SERVICE_LOG 에서 로그를 사용할 수 없는 경우 이벤트 테이블 (활성화된 경우)에서 로그를 확인할 수 있습니다.

    SELECT RESOURCE_ATTRIBUTES, VALUE
    FROM <EVENT_TABLE_NAME>
    WHERE true
        AND timestamp > dateadd(day, -1, current_timestamp())  -- choose appropriate timestamp range
        AND RESOURCE_ATTRIBUTES:"snow.database.name" = '<db of the service>'
        AND RESOURCE_ATTRIBUTES:"snow.schema.name" = '<schema of the service>'
        AND RESOURCE_ATTRIBUTES:"snow.service.name" = '<Job or Service name>'
    AND RESOURCE_ATTRIBUTES:"snow.service.container.instance" = '0'  -- choose all instances or one particular
    AND RESOURCE_ATTRIBUTES:"snow.service.container.name" != 'snowflake-ingress' --skip logs from internal sidecar
    ORDER BY timestamp ASC;
    
    Copy

패키지 충돌

서비스 컨테이너에 설치되는 패키지는 두 가지 시스템, 즉 모델 자체와 추론 서버에 의해 결정됩니다. 모델의 종속성으로 인한 충돌을 최소화하기 위해 추론 서버에는 다음 패키지만 필요합니다.

  • gunicorn<24.0.0

  • starlette<1.0.0

  • uvicorn-standard<1.0.0

위와 함께 모델 종속성이 사용자가 사용하는 pip 또는 conda 에 의해 해결되어야 합니다.

모델에 conda_dependenciespip_requirements 가 모두 설정되어 있는 경우 conda를 통해 다음과 같이 설치됩니다.

채널:

  • conda-forge

  • nodefaults

:종속성

  • all_conda_packages

  • pip:
    • all_pip_packages

Snowflake는 컨테이너 이미지를 빌드할 때 conda-forge 에서 Anacaonda 패키지를 가져오는데, 이는 Snowflake conda 채널은 웨어하우스에서만 사용할 수 있고 defaults 채널은 자동 빌드 중에는 불가능한 Anaconda 사용 약관에 동의해야 하기 때문입니다. defaults 등의 채널에서 패키지를 가져오려면 defaults::pkg_name 과 같이 채널 이름과 함께 각 패키지를 지정합니다.

참고

conda_dependenciespip_requirements 를 모두 지정하면 두 종속성 세트가 호환되지 않더라도 컨테이너 이미지가 성공적으로 빌드되므로 결과 컨테이너 이미지가 예상대로 작동하지 않을 수 있습니다. Snowflake는 conda_dependencies 또는 pip_requirements 중 하나만 사용할 것을 권장합니다.

서비스 메모리 부족

일부 모델은 스레드에 안전하지 않으므로 Snowflake는 각 작업자 프로세스에 대해 모델의 복사본을 별도로 메모리에 로드합니다. 이로 인해 워커의 수가 많은 대규모 모델의 경우 메모리 부족 조건이 발생할 수 있습니다. num_workers 를 줄여보십시오.

쿼리 성능이 만족스럽지 않음

일반적으로 추론은 추론 서비스의 인스턴스 수에 따라 병목 현상이 발생합니다. 모델을 배포할 때 max_instances 에 대한 더 높은 값을 전달해 보십시오.

서비스 사양 변경 불가

모델 빌드 및 추론 서비스의 사양은 ALTER SERVICE를 사용하여 변경할 수 없습니다. TAG, MIN_INSTANCES 등의 특성만 변경할 수 있습니다. 그러나 이미지가 이미지 리포지토리에 게시되어 있으므로 사양을 복사하고 수정한 후 수동으로 시작할 수 있는 새 서비스를 생성할 수 있습니다.

패키지를 찾을 수 없음

이미지 빌드 단계에서 모델 배포에 실패했습니다. model-build 로그에 따르면 요청된 패키지를 찾을 수 없습니다. (이 단계에서는 패키지가 conda_dependencies 에 언급된 경우 기본적으로 conda-forge 를 사용합니다.)

다음과 같은 이유로 패키지 설치가 실패할 수 있습니다.

  • 패키지 이름 또는 버전이 잘못되었습니다. 패키지의 철자와 버전을 확인합니다.

  • 요청하신 패키지 버전이 conda-forge 에 없습니다. 버전 사양을 제거하여 conda-forge 에서 사용 가능한 최신 버전을 얻거나 pip_requirements 를 대신 사용할 수 있습니다. 사용 가능한 모든 패키지를 여기 에서 찾아볼 수 있습니다.

  • 때로는 특별 채널(예: pytorch)에서 제공하는 패키지가 필요할 수 있습니다. 종속성에 channel_name:: 접두사를 추가합니다(예: pytorch::torch).

Huggingface Hub 버전 불일치

Hugging Face 모델 추론 서비스가 오류 메시지와 함께 실패할 수 있습니다.

ImportError: huggingface-hub>=0.30.0,<1.0 is required for a normal functioning of this module, but found huggingface-hub==0.25.2

이는 transformers 패키지가 huggingface-hub 에 올바른 종속성을 지정하지 않고 대신 코드를 체크인하기 때문입니다. 이 문제를 해결하려면 모델을 다시 로그하고 이번에는 conda_dependencies 또는 pip_requirementshuggingface-hub 의 요구 사항 버전을 명시적으로 지정합니다.

CUDA 가 활성화된 상태에서 torch가 컴파일되지 않음

이 오류의 일반적인 원인은 conda_dependenciespip_requirements 를 모두 지정했기 때문입니다. 패키지 충돌 섹션에서 언급했듯이, conda 는 컨테이너 이미지를 빌드하는 데 사용되는 패키지 관리자입니다. Anaconda는 conda_dependenciespip_requirements 의 패키지를 함께 확인하지 않으며 conda 패키지를 우선시합니다. 이로 인해 conda 패키지가 pip 패키지와 호환되지 않는 상황이 발생할 수 있습니다. conda_dependencies 가 아니라 pip_requirements 에서 torch 를 지정했을 수 있습니다. 종속성을 conda_dependencies 또는 pip_requirements 로 통합하는 것이 좋습니다. 이것이 가능하지 않다면 conda_dependencies 에서 가장 중요한 패키지를 지정하는 것이 좋습니다.