AWS CDK で SageMaker の サーバレス推論エンドポイントを作成する
はじめに
CDK も SageMaker もさっぱりわからない状態から、なんとなく触れるようになるまでの備忘録です。
Lambda から SageMaker のリアルタイムエンドポイントを呼び出して利用できるようにすることを目指します。
AWS CDK
AWS Cloud Development Kit
AWSのリソースをソースコードで管理できるようになります。
CloudFormation を通してデプロイを行うため、リソースの確認・破棄、エラー時のロールバックなどが簡単に行えます。
Terraform と比較される記事をよく見かけました。
Terraform
- HashiCorp が提供するオープンソースツール
- AWS CLI を利用してリソースを操作
- 細かい制御が可能 で、デプロイ速度も速い
- 記述量が多くなりがち
AWS CDK
- AWS が提供するフレームワーク
- CloudFormation を経由してリソースを作成
- コード量は少なくシンプル に書ける
- デプロイ速度は遅くなりやすい
SageMaker
Amazon SageMaker
機械学習モデルの構築・学習・デプロイなどを一貫して行えるサービスです。
様々な機能が提供されていますが、今回は Hugging Face で公開されているモデルをそのまま使ってサーバレス推論エンドポイントを作成します。
環境
- wsl
- aws cli と aws cdk がインストール済み
- AWS アカウントの認証情報が設定済み
$ aws --version
aws-cli/2.25.13 Python/3.12.9 Linux/5.15.167.4-microsoft-standard-WSL2 exe/x86_64.ubuntu.24
$ cdk --version
2.1020.2 (build cf35f57)
$ aws configure list
Name Value Type Location
---- ----- ---- --------
profile <not set> None None
access_key ******************** shared-credentials-file
secret_key ******************** shared-credentials-file
region ap-northeast-1 config-file ~/.aws/config
CDK のプロジェクトを作成する
CDK の基本的な操作については、こちらのワークショップで一通り触りました。
ワークスペースの作成とプロジェクトの初期化を行います。
言語は typescript を指定します。
他の言語も使用できますが、 TypeScript で書かれた事例や記事が多いので、よほど強いこだわりがなければ TypeScript でいいみたいです。
$ mkdir cdk-sagemaker-training
$ cd cdk-sagemaker-training/
$ cdk init --language typescript
Applying project template app for typescript
# Welcome to your CDK TypeScript project
This is a blank project for CDK development with TypeScript.
The `cdk.json` file tells the CDK Toolkit how to execute your app.
## Useful commands
* `npm run build` compile typescript to js
* `npm run watch` watch for changes and compile
* `npm run test` perform the jest unit tests
* `npx cdk deploy` deploy this stack to your default AWS account/region
* `npx cdk diff` compare deployed stack with current state
* `npx cdk synth` emits the synthesized CloudFormation template
Executing npm install...
npm warn deprecated inflight@1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
npm warn deprecated glob@7.2.3: Glob versions prior to v9 are no longer supported
✅ All done!
NOTICES (What's this? https://github.com/aws/aws-cdk/wiki/CLI-Notices)
34892 CDK CLI will collect telemetry data on command usage starting at version 2.1100.0 (unless opted out)
Overview: We do not collect customer content and we anonymize the
telemetry we do collect. See the attached issue for more
information on what data is collected, why, and how to
opt-out. Telemetry will NOT be collected for any CDK CLI
version prior to version 2.1100.0 - regardless of
opt-in/out. You can also preview the telemetry we will start
collecting by logging it to a local file, by adding
`--unstable=telemetry --telemetry-file=my/local/file` to any
`cdk` command.
Affected versions: cli: ^2.0.0
More information at: https://github.com/aws/aws-cdk/issues/34892
If you don’t want to see a notice anymore, use "cdk acknowledge <id>". For example, "cdk acknowledge 34892".
作成が完了しました。
バージョンの警告は今回無視します。
最後に CDK CLI の通知が出ています。
毎回出るとうっとうしいので cdk acknowledge 34892
を実行し、このワークスペースでは非表示になるようにします。(この設定は cdk.context.json
に追記されます。)
$ tree -I 'node_modules' --dirsfirst
.
├── bin
│ └── cdk-sagemaker-training.ts
├── lib
│ └── cdk-sagemaker-training-stack.ts
├── test
│ └── cdk-sagemaker-training.test.ts
├── README.md
├── cdk.context.json
├── cdk.json
├── jest.config.js
├── package-lock.json
├── package.json
└── tsconfig.json
上記のようなディレクトリが作成されました。( node_modules は割愛します)
バージョンが異なると生成物が異なるようで、古い記事では全く違うものが生成されていました。
bin/cdk-sagemaker-training.ts
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { CdkSagemakerTrainingStack } from '../lib/cdk-sagemaker-training-stack';
const app = new cdk.App();
new CdkSagemakerTrainingStack(app, 'CdkSagemakerTrainingStack', {
/* If you don't specify 'env', this stack will be environment-agnostic.
* Account/Region-dependent features and context lookups will not work,
* but a single synthesized template can be deployed anywhere. */
/* Uncomment the next line to specialize this stack for the AWS Account
* and Region that are implied by the current CLI configuration. */
// env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
/* Uncomment the next line if you know exactly what Account and Region you
* want to deploy the stack to. */
// env: { account: '123456789012', region: 'us-east-1' },
/* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */
});
最上位で呼ばれるファイルです。
一般的には bin フォルダの中にはこのファイルが1つだけ置かれるみたいです。
ここでは cdk.App
のインスタンスを作成し、それに紐づくスタックのインスタンスを作成します。
スタックのインスタンス1つにつき、CloudFormation のスタックが1つ生成されます。
lib/cdk-sagemaker-training-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
// import * as sqs from 'aws-cdk-lib/aws-sqs';
export class CdkSagemakerTrainingStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// The code that defines your stack goes here
// example resource
// const queue = new sqs.Queue(this, 'CdkSagemakerTrainingQueue', {
// visibilityTimeout: cdk.Duration.seconds(300)
// });
}
}
スタックを定義するためのファイルです。
cdk.Stack
を継承したクラスを定義します。
この中に AWS のリソースを定義していきます。
test/cdk-sagemaker-training.test.ts
テストコードを書くことができます。
今回は使用しません。
cdk.json
CDK の設定ファイルです。
アプリの起動方法、フラグ、設定値などを記述します。
リソースを作成する際の初期値や、スタックに渡す値を設定できるようです。
例えば以下の設定にすると、すべての新規 S3 バケットのパブリックアクセスがデフォルトでブロックされます。
{
"context": {
"@aws-cdk/aws-s3:publicAccessBlockedByDefault": true
}
}
詳細は公式ドキュメントで確認できます
デプロイしてみる
最小限の状態でデプロイを行います。
まず bin/cdk-sagemaker-training.ts
の env を設定している1行のコメントを解除します。
こうすることで、スタックの作成時に、AWS CLI のデフォルトのアカウント情報が参照されます。
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { CdkSagemakerTrainingStack } from '../lib/cdk-sagemaker-training-stack';
const app = new cdk.App();
new CdkSagemakerTrainingStack(app, 'CdkSagemakerTrainingStack', {
/* If you don't specify 'env', this stack will be environment-agnostic.
* Account/Region-dependent features and context lookups will not work,
* but a single synthesized template can be deployed anywhere. */
/* Uncomment the next line to specialize this stack for the AWS Account
* and Region that are implied by the current CLI configuration. */
env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
/* Uncomment the next line if you know exactly what Account and Region you
* want to deploy the stack to. */
// env: { account: '123456789012', region: 'us-east-1' },
/* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */
});
lib/cdk-sagemaker-training-stack.ts
の queue を作成しているコメントと import コメントを解除します。
これで1つの AWS SQS が作成されるはずです。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as sqs from 'aws-cdk-lib/aws-sqs';
export class CdkSagemakerTrainingStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// The code that defines your stack goes here
// example resource
const queue = new sqs.Queue(this, 'CdkSagemakerTrainingQueue', {
visibilityTimeout: cdk.Duration.seconds(300)
});
}
}
CDK を動かす下準備として cdk bootstrap
を実行します。
これを実行すると CDK を動かすために必要な S3 Bucket や IAM Role が作成されます。
この環境では既に作成済みなのでその旨が出力されました。
$ cdk bootstrap
⏳ Bootstrapping environment aws://***/ap-northeast-1...
Trusted accounts for deployment: (none)
Trusted accounts for lookup: (none)
Using default execution policy of 'arn:aws:iam::aws:policy/AdministratorAccess'. Pass '--cloudformation-execution-policies' to customize.
✅ Environment aws://***/ap-northeast-1 bootstrapped (no changes).
cdk deploy
を使ってデプロイします。
cdk deploy
を実行すると以下の処理が行われます。
- コードをもとに CloudFormation テンプレートを作成
- デプロイ済みの既存のスタックがあれば、作成されたテンプレートとの差分を表示
- CloudFormation をデプロイ
個別の処理を実行するコマンドもあります。
テンプレートの作成のみを行いたい場合 → cdk synth
デプロイ済みの既存のスタックとローカルのテンプレートの差分を確認したい場合 → cdk diff
詳細は cdk
で確認できます。
$ cdk deploy
✨ Synthesis time: 19.86s
CdkSagemakerTrainingStack: start: Building CdkSagemakerTrainingStack Template
CdkSagemakerTrainingStack: success: Built CdkSagemakerTrainingStack Template
CdkSagemakerTrainingStack: start: Publishing CdkSagemakerTrainingStack Template (***-ap-northeast-1)
CdkSagemakerTrainingStack: success: Published CdkSagemakerTrainingStack Template (***-ap-northeast-1)
CdkSagemakerTrainingStack: deploying... [1/1]
CdkSagemakerTrainingStack: creating CloudFormation changeset...
✅ CdkSagemakerTrainingStack
✨ Deployment time: 46.48s
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:***:stack/CdkSagemakerTrainingStack/***
✨ Total time: 66.35s
完了しました。
ワークスペースに生成された cdk.out
を確認します。
ここにはソースをもとに作成された CloudFormation のテンプレートが格納されます。
例えば、cdk.out/CdkSagemakerTrainingStack.template.json
の中には、 sqs を作成するための記述があります。
{
"Resources": {
"CdkSagemakerTrainingQueue842D76D3": {
"Type": "AWS::SQS::Queue",
"Properties": {
"VisibilityTimeout": 300
},
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete",
"Metadata": {
"aws:cdk:path": "CdkSagemakerTrainingStack/CdkSagemakerTrainingQueue/Resource"
}
},
・・・
}
}
実行されたスタックを CLI から確認してみます。
$ aws cloudformation describe-stacks --query "Stacks[?StackName=='CdkSagemakerTrainingStack']"
[
{
"StackName": "CdkSagemakerTrainingStack",
・・・
"StackStatus": "CREATE_COMPLETE",
・・・
}
]
SQS が作成されていることも確認します。
$ aws sqs list-queues
{
"QueueUrls": [
"https://sqs.ap-northeast-1.amazonaws.com/***/CdkSagemakerTrainingStack-CdkSagemakerTrainingQueue***"
]
}
AWS のコンソールからも確認できます。
動くことを確認したので、SQSの記載を削除しデプロイします。
lib/cdk-sagemaker-training-stack.ts
のクラスの中身をすべて削除します。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class CdkSagemakerTrainingStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
}
}
$ cdk deploy
・・・
✨ Total time: 84.98s
aws sqs list-queues
を実行し、先ほど作った SQS が表示されないことを確認します。
SageMaker 推論エンドポイントの作成
lib/cdk-sagemaker-training-stack.ts
を以下のように書き換えます。
cdk-sagemaker-training-stack.ts
import * as cdk from 'aws-cdk-lib';
import { aws_iam, aws_sagemaker } from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class CdkSagemakerTrainingStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// 実行ロール
const executionRole = new aws_iam.Role(this, 'SagemakerExecutionRole', {
assumedBy: new aws_iam.ServicePrincipal('sagemaker.amazonaws.com'),
managedPolicies: [
aws_iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEC2ContainerRegistryReadOnly'),
aws_iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSageMakerFullAccess'),
],
});
// 推論コンテナ 環境変数
const containerEnvironment: { [key: string]: string } = {
HF_MODEL_ID: "intfloat/multilingual-e5-base",
HUGGINGFACE_HUB_CACHE: '/opt/ml/tmp',
}
// 推論コンテナ イメージURI
const imageUri = "354813040037.dkr.ecr.ap-northeast-1.amazonaws.com/tei-cpu:2.0.1-tei1.2.3-cpu-py310-ubuntu22.04"
// 推論コンテナ 設定
const container: aws_sagemaker.CfnModel.ContainerDefinitionProperty = {
environment: containerEnvironment,
image: imageUri,
};
// 推論モデル
const model = new aws_sagemaker.CfnModel(this, 'TextEmbeddingModel', {
executionRoleArn: executionRole.roleArn,
primaryContainer: container,
});
model.node.addDependency(executionRole);
// 推論エンドポイント 設定
const endpointConfiguration = new aws_sagemaker.CfnEndpointConfig(this, 'TextEmbeddingEndpointConfig', {
productionVariants: [
{
variantName: "AllTraffic",
modelName: model.attrModelName,
serverlessConfig: {
maxConcurrency: 10,
memorySizeInMb: 6144
}
}
]
});
endpointConfiguration.node.addDependency(model);
// 推論エンドポイント
const endpoint = new aws_sagemaker.CfnEndpoint(this, 'TextEmbeddingEndpoint', {
endpointConfigName: endpointConfiguration.attrEndpointConfigName,
endpointName: 'TextEmbedding',
});
endpoint.node.addDependency(endpointConfiguration);
}
}
// 実行ロール
const executionRole = new aws_iam.Role(this, 'SagemakerExecutionRole', {
assumedBy: new aws_iam.ServicePrincipal('sagemaker.amazonaws.com'),
managedPolicies: [
aws_iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEC2ContainerRegistryReadOnly'),
aws_iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSageMakerFullAccess'),
],
});
モデルの作成や実行を行うロールを作成します。
Sagemaker と ECR の権限を付与します。
// 推論コンテナ 環境変数
const containerEnvironment: { [key: string]: string } = {
HF_MODEL_ID: "intfloat/multilingual-e5-base",
HUGGINGFACE_HUB_CACHE: '/opt/ml/tmp',
}
// 推論コンテナ イメージURI
const imageUri = "354813040037.dkr.ecr.ap-northeast-1.amazonaws.com/tei-cpu:2.0.1-tei1.2.3-cpu-py310-ubuntu22.04"
// 推論コンテナ 設定
const container: aws_sagemaker.CfnModel.ContainerDefinitionProperty = {
environment: containerEnvironment,
image: imageUri,
};
// 推論モデル
const model = new aws_sagemaker.CfnModel(this, 'TextEmbeddingModel', {
executionRoleArn: executionRole.roleArn,
primaryContainer: container,
});
model.node.addDependency(executionRole);
ここでは推論で使うモデルやコンテナを指定します。
今回は日本語の文字列の埋め込みを行うエンドポイントを作成しようと思います。
モデルは intfloat/multilingual-e5-base を使いました。
コンテナは、Hugging Face が公開している、Text Embeddings Inference(TEI) を使用します。
TEI はスペックに応じた複数のコンテナイメージを公開しています。
インスタンスタイプに応じたイメージを選択する必要があります。
SDKを使うと簡単にイメージURIが取得できます。
from sagemaker.huggingface import get_huggingface_llm_image_uri
# retrieve the image uri based on instance type
def get_image_uri(instance_type):
key = "huggingface-tei" if instance_type.startswith("ml.g") or instance_type.startswith("ml.p") else "huggingface-tei-cpu"
return get_huggingface_llm_image_uri(key, version="1.2.3")
モデルによっては対応していない場合があるので注意が必要です。
このコンテナは Rust を用いて書かれているので、日本語の形態素解析に mecab 、 fugashi といった python のモジュールが追加で必要なモデルの場合などは利用が難しいです。
他にも aws が公開しているコンテナを使う方法や、カスタムイメージを使う方法もあります。
-
HF_MODEL_ID: "intfloat/multilingual-e5-base",
モデルを指定します。 -
HUGGINGFACE_HUB_CACHE: '/opt/ml/tmp',
コンテナ内でキャッシュを保存するパスを変更します。書きこみ権限の関係でデフォルトの設定だとエラーになります。 -
model.node.addDependency(executionRole);
依存関係の指定。executionRole が作成されてから model を作成します。
// 推論エンドポイント 設定
const endpointConfiguration = new aws_sagemaker.CfnEndpointConfig(this, 'TextEmbeddingEndpointConfig', {
productionVariants: [
{
variantName: "AllTraffic",
modelName: model.attrModelName,
serverlessConfig: {
maxConcurrency: 10,
memorySizeInMb: 6144
}
}
]
});
endpointConfiguration.node.addDependency(model);
// 推論エンドポイント
const endpoint = new aws_sagemaker.CfnEndpoint(this, 'TextEmbeddingEndpoint', {
endpointConfigName: endpointConfiguration.attrEndpointConfigName,
endpointName: 'TextEmbedding',
});
endpoint.node.addDependency(endpointConfiguration);
モデルをもとにエンドポイントを作成します。
-
variantName: "AllTraffic",
慣例名。1つのエンドポイントに複数のモデル(バリアント)を紐づける場合には一意になるように任意の値を設定します。今回は1つしか紐づけないので AllTraffic で問題ありません。 -
serverlessConfig
サーバレスエンドポイントにする場合に指定します。
もしサーバレスではない普通のインスタンスのエンドポイントを作成する場合はこの代わりに、InstanceType
、InitialInstanceCount
を設定する必要があります。
maxConcurrency
: 最大同時実行数
memorySizeInMb
: メモリサイズ(MB)
cdk deploy
で実行します。
完了まで数分かかりました。
$ cdk deploy
・・・
✨ Total time: 200.96s
作成されたエンドポイントを実際に動かして確認してみます。
$ jq -nc --arg t 'CDKとSageMakerの練習' '{inputs:$t}' > payload.json
$ aws sagemaker-runtime invoke-endpoint \
--endpoint-name TextEmbedding \
--content-type application/json \
--accept application/json \
--body fileb://payload.json \
output.json
# サーバレスエンドポイントのためコールドスタートが発生し、初回実行時は数十秒かかります。
{
"ContentType": "application/json",
"InvokedProductionVariant": "AllTraffic"
}
$ cat output.json | jq .
[
[
0.014250721,
0.040402036,
-0.018678946,
・・・
ベクトルが作成されました。
Lambdaから呼び出して使う
2単語の類似度を比較する Lambda を作成します。
Lambda の処理を記述するためのファイルを作成します。
$ mkdir lambda
$ touch ./lambda/handler.ts
追加のモジュールをインストールします。
$ npm i @aws-sdk/client-sagemaker-runtime
added 84 packages, and audited 419 packages in 7s
40 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
$ npm i -D @types/aws-lambda esbuild
added 3 packages, and audited 422 packages in 4s
40 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
lambda/handler.ts
に以下を記述します。
handler.ts
import { Handler } from "aws-lambda";
import { SageMakerRuntimeClient, InvokeEndpointCommand } from "@aws-sdk/client-sagemaker-runtime";
// SageMaker クライアント
const client = new SageMakerRuntimeClient();
// コサイン類似度計算
function cosineSimilarity(vecA: number[], vecB: number[]): number {
const dot = vecA.reduce((sum, a, i) => sum + a * vecB[i], 0);
const normA = Math.sqrt(vecA.reduce((sum, a) => sum + a * a, 0));
const normB = Math.sqrt(vecB.reduce((sum, b) => sum + b * b, 0));
return dot / (normA * normB);
}
// SageMakerへ推論リクエスト
async function getTextEmbeddingsBatch(texts: string[]): Promise<number[][]> {
const inputs = texts.map(t => `query: ${t}`); // multilingual-e5 が指定するフォーマットに合わせる
const command = new InvokeEndpointCommand({
EndpointName: process.env.ENDPOINT_NAME!,
ContentType: "application/json",
Accept: "application/json",
Body: JSON.stringify({ inputs }),
});
const res = await client.send(command);
const payload = await res.Body?.transformToString();
if (!payload) throw new Error("レスポンスが空です");
const parsed = JSON.parse(payload);
if (!Array.isArray(parsed) || !Array.isArray(parsed[0])) {
throw new Error("レスポンスが [[...]] 形式ではありません");
}
return parsed as number[][];
}
// Lambda ハンドラ
export const handler: Handler = async (event) => {
const body = typeof event.body === "string" ? JSON.parse(event.body) : event;
const { word1, word2 } = body;
if (!word1 || !word2) {
return { statusCode: 400, body: "word1 と word2 は必須項目です" };
}
// 単語の埋め込みと類似度計算
const [vec1, vec2] = await getTextEmbeddingsBatch([word1, word2]);
const similarity = cosineSimilarity(vec1, vec2);
return {
statusCode: 200,
body: JSON.stringify({ similarity }),
};
};
lib/cdk-sagemaker-training-stack.ts
に以下を追加します。
cdk-sagemaker-training-stack.ts
import path from 'path';
・・・
// Lambdaの作成
const fn = new NodejsFunction(this, "EmbedLambda", {
entry: path.join(__dirname, "..", "lambda", "handler.ts"),
runtime: aws_lambda.Runtime.NODEJS_20_X,
memorySize: 512,
timeout: cdk.Duration.minutes(5),
bundling: {
forceDockerBundling: false,
},
environment: {
ENDPOINT_NAME: endpoint.attrEndpointName,
},
});
// Lambdaのロググループをスタック削除時に削除
fn.logGroup.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY)
// Lambdaの実行ロールにSageMakerエンドポイントの呼び出し権限を付与
fn.addToRolePolicy(
new aws_iam.PolicyStatement({
actions: ["sagemaker:InvokeEndpoint"],
resources: [
cdk.Stack.of(this).formatArn({
service: "sagemaker",
resource: "endpoint",
resourceName: endpoint.attrEndpointName,
}),
],
})
);
// 関数URL
const fnUrl = fn.addFunctionUrl({
authType: aws_lambda.FunctionUrlAuthType.NONE,
cors: {
allowedOrigins: ["*"],
allowedMethods: [aws_lambda.HttpMethod.ALL],
},
});
// 関数URLを出力
new cdk.CfnOutput(this, "EmbedLambdaUrl", {
value: fnUrl.url,
});
再度デプロイします。
$ cdk deploy
・・・
Outputs:
CdkSagemakerTrainingStack.EmbedLambdaUrl = https://***.lambda-url.ap-northeast-1.on.aws/
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:***:stack/CdkSagemakerTrainingStack/***
✨ Total time: 31.61s
作成された関数URLが出力されます。
いくつか試してみます。
$ curl -X POST \
-H "Content-Type: application/json" \
-d '{"word1": "朝からずっと天気が崩れていて洗濯物が干せなくて困っている。", "word2": "災害級の強い雨が明日の夕方から降るらしい。"}' \
https://***.lambda-url.ap-northeast-1.on.aws/ \
-w "\n"
{"similarity":0.888046462909359}
$ curl -X POST \
-H "Content-Type: application/json" \
-d '{"word1": "朝からずっと天気が崩れていて洗濯物が干せなくて困っている。", "word2": "雲ひとつない青空が広がり散歩するのに気持ちの良い天気だ。"}' \
https://***.lambda-url.ap-northeast-1.on.aws/ \
-w "\n"
{"similarity":0.8557268751866666}
$ curl -X POST \
-H "Content-Type: application/json" \
-d '{"word1": "朝からずっと天気が崩れていて洗濯物が干せなくて困っている。", "word2": "AIの進化によって多くの仕事が自動化される一方で、新しい産業や職業も生まれている。"}' \
https://***.lambda-url.ap-northeast-1.on.aws/ \
-w "\n"
{"similarity":0.7852773422952674}
それらしい類似度が出てくれました。
サーバエラーが出た時は、aws コンソールの Lambda のテストタブからテストを行うと、詳細なエラーログが確認できます。
リソースの削除
cdk destroy
を実行してスタックを削除します。
$ cdk destroy
Are you sure you want to delete: CdkSagemakerTrainingStack (y/n)? y
CdkSagemakerTrainingStack: destroying... [1/1]
✅ CdkSagemakerTrainingStack: destroyed
完了しました。コンソールからも確認します
ほとんどのリソースは自動で削除されますが、一部のリソースは削除されずに残ることがあります。
ロググループや S3 の Bucket が残りがちです。
今回は Lambda のロググループをスタックの削除と同時に削除する設定にしていたので、全てのリソースが削除されました。
残ったリソースがある場合は手動で削除します。
おわりに
CloudFormation のテンプレート直書きと比べて、記述量の少なさとコード補完が使えることに感動しました。
リソースをコンストラクトとして切り出し、複数ファイルに分割して整理することもできるみたいですが、いまいち使いこなせていません。
SageMaker については本来の強みを全く生かせていないので他の機能も試してみたいです。