はじめに
- ローカル環境のDockerコンテナからSageMakerの学習ジョブをlocalモードで実行したときのメモ。
動機
- ローカルにGPUを積んでいるマシンが一応あるので、最初はローカルで学習を回して様子を見つつ、いける!となったら並行に学習ジョブを回すため&学習結果を管理するためにSageMakerを使いたかった。
前提
- SageMakerのトレーニングジョブをlocalモードで実行する際には、docker-composeによって作成されたdockerコンテナ上で実行される。
構築手順
- requirements.txt準備
requirements.txt
jupyter==1.0.0
opencv-python==4.0.1.24
pillow==6.2.0
docker-compose==1.24.1
awscli==1.16.279
boto3==1.10.15
sagemaker==1.43.4.post1
papermill==1.2.1
- Dockerfile準備
Dockerfile
FROM 520713654638.dkr.ecr.ap-northeast-1.amazonaws.com/sagemaker-pytorch:1.1.0-cpu-py3
ARG PYTHON_PASS=/usr/bin/python3.6
ENV GIT_SSL_NO_VERIFY=1
# apt install
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
git \
vim \
groff-base # awscli
# pip install
COPY requirements.txt /tmp/
RUN $PYTHON_PASS -m pip install --upgrade pip && \
$PYTHON_PASS -m pip install -r /tmp/requirements.txt
# install docker
RUN curl https://get.docker.com | sh
# make dir
RUN mkdir -p /opt/config \
/opt/data/raw \
/opt/data/interim \
/opt/data/processed \
/opt/data/external \
/opt/features \
/opt/logs \
/opt/models \
/opt/notebooks \
/opt/reports \
/opt/scripts \
/opt/utils
# cd
WORKDIR /opt
# expose port
EXPOSE 8888
- コンテナ起動
run.sh
# !/bin/bash
# usage
SCRIPT_FILE=`basename $0`
function usage()
{
echo "usage: ${SCRIPT_FILE} docker/nvidia-docker" 1>&2
}
# arguments
if [ $# -ne 1 ]; then
usage
exit 1
fi
DOCKER_CMD=$1
# constant
SCRIPT_DIR=$(cd $(dirname $0); pwd)
LOG_FILE=${SCRIPT_DIR}/../logs/docker.log
CONTAINER_NAME=sagemaker_pytorch_1_1_0_local
CONTAINER_IMAGE=sagemaker_pytorch_1_1_0_local
HOST_PORT=28888
CONTAINER_PORT=8888
# log
function log() {
local fname=${BASH_SOURCE[1]##*/}
echo "$(date '+%Y-%m-%dT%H:%M:%S') ${PROCNAME} (${fname}:${BASH_LINENO[0]}:${FUNCNAME[1]}) $@" | tee -a ${LOG_FILE}
}
# main
log "info start script"
log "info CONTAINER_NAME: ${CONTAINER_NAME}, CONTAINER_IMAGE: ${CONTAINER_IMAGE}, HOST_PORT: ${HOST_PORT}, CONTAINER_PORT: ${CONTAINER_PORT}"
${DOCKER_CMD} run --name ${CONTAINER_NAME} \
--privileged \
--entrypoint bash \
-v $(pwd)/../config:/opt/config \
-v $(pwd)/../data:/opt/data \
-v $(pwd)/../features:/opt/features \
-v $(pwd)/../logs:/opt/logs \
-v $(pwd)/../models:/opt/models \
-v $(pwd)/../notebooks:/opt/notebooks \
-v $(pwd)/../reports:/opt/reports \
-v $(pwd)/../scripts:/opt/scripts \
-v $(pwd)/../utils:/opt/utils \
-p ${HOST_PORT}:${CONTAINER_PORT} \
-it ${CONTAINER_IMAGE}
if [ $? -gt 0 ]; then
log "error docker run"
fi
コンテナ起動
$ docker build ./ -t sagemaker_pytorch_1_1_0_local
$ run.sh nvidia-docker
- 学習ジョブ実行
pytorch_tutorial_cifar10_sagemaker.ipynb
# データ準備
import sagemaker
sagemaker_session = sagemaker.Session()
bucket = sagemaker_session.default_bucket() # ex. 'sagemaker-us-east-2-xxxxxxxxxxxx'
role = sagemaker.get_execution_role() # ex. arn:aws:iam::xxxxxxxxxxxx:role/service-role/...
# We use the sagemaker.Session.upload_data function to upload our datasets to an S3 location.
# The return value inputs identifies the location -- we will use this later when we start the training job.
inputs = sagemaker_session.upload_data(path='../data/raw', bucket=bucket, key_prefix='data/raw/cifar10') # ex. s3://sagemaker-us-east-2-xxxxxxxxxxxx/data/raw/cifar10
# インスタンスタイプ設定
import subprocess
instance_type = 'local'
# instance_type = 'ml.m5.large'
if subprocess.call('nvidia-smi') == 0:
## Set type to GPU if one is present
instance_type = 'local_gpu'
print("Instance type = " + instance_type)
# 学習コンテナ起動
from sagemaker.pytorch import PyTorch
# estimator
hyper_param = {
'workers': 2,
'epochs':2,
'batch_size': 4,
'lr': 0.001,
'momentum': 0.9,
}
cifar10_estimator = PyTorch(entry_point='../models/cifar10_sagemaker.py',
hyperparameters=hyper_param,
role=role,
framework_version='1.1.0',
train_instance_count=1,
train_instance_type=instance_type)
cifar10_estimator.fit(
inputs=inputs,
)
ハマったこと
はじめは、 docker run 時に -v /var/run/docker.sock:/var/run/docker.sock によってソケットをマウントし、ホストの Docker エンジンを用いて Docker コンテナを起動しようとした。が、失敗した。(下記エラー)
No such file or directory: '/opt/ml/input/config/resourceconfig.json'
どうやら、トレーニングジョブの実行に必要な /opt/ml/input/config/resourceconfig.json は、トレーニングジョブ開始を指示するコンテナ内で作成されるようで、localモードにて開始するコンテナでは、 /opt/ml/input/ に /tmp 配下の一時ディレクトリをマウントするが、ホストのDockerエンジンを用いてDockerコンテナを起動するために、ホストの /tmp 配下の一時ディレクトリをマウントすることとなり、結果として、トレーニングジョブ開始を指示するコンテナ内に作成された resourceconfig.jsonを取得できず、エラーが発生しているらしい。
よって、今回は上記のようにDockerコンテナ内で実行されるDockerエンジンを利用した。