0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

自動再投入シェルスクリプト

Last updated at Posted at 2025-09-03

はじめに

卒業研究中に作成した「自動再投入シェルスクリプト」の備忘録です.

研究内容

現在の研究テーマは、Detection Transformer (DETR) 系検出器を用いた小型物体検出の精度向上です.

  • 実行環境は大学のGPGPUサーバ(SLURMを利用)
  • このサーバではジョブの最大実行時間が24時間に制限
  • 長時間学習が必要なDETRを実行する際,途中から再開できる仕組みが必要

スクリプトの詳細

  • detr_checkpoint.sh: SLURM を使って DETR の学習を1回実行 するスクリプト
  • auto_continue_detr.sh: detr_checkpoint.sh自動で繰り返し実行・監視 し、失敗時もチェックポイントから再開するスクリプト
detr_checkpoint.sh
#!/bin/bash
#SBATCH --job-name=detr-checkpoint
#SBATCH --partition="パーティション名"
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=16
#SBATCH --gpus-per-task=4
#SBATCH --mem=512G
#SBATCH --time=24:00:00
#SBATCH --output=slurm-%j.out
#SBATCH --container="コンテナ名"
#SBATCH --mail-type=END,FAIL
#SBATCH --mail-user="メールアドレス"

cd /detr/detr

# 出力ディレクトリの設定
OUTPUT_DIR="/root/detr/output/CheckPoints$(date +%Y%m%d_%H%M%S)"
mkdir -p $OUTPUT_DIR

echo "=== DETR Training Started ==="
echo "Job ID: $SLURM_JOB_ID"
echo "Output Directory: $OUTPUT_DIR"
echo "Start Time: $(date)"

# 最新のチェックポイントを確認
RESUME_OPTION=""
# 過去の出力ディレクトリから最新のチェックポイントを検索
LATEST_CHECKPOINT=$(find /root/detr/output/CheckPoints* -name "checkpoint.pth" 2>/dev/null | sort -r | head -1)

if [ -n "$LATEST_CHECKPOINT" ]; then
    RESUME_OPTION="--resume $LATEST_CHECKPOINT"
    echo "最新のチェックポイントから再開: $LATEST_CHECKPOINT"
else
    echo "新規トレーニングを開始"
fi

echo "=== Training Parameters ==="
echo "Epochs: 500"
echo "Batch Size: 8"
echo "Learning Rate: 1e-4"
echo "Resume Option: $RESUME_OPTION"
echo "=============================="

# バックグラウンドでDETRトレーニングを実行
python -m torch.distributed.launch --nproc_per_node=4 --use_env main.py \
  --coco_path /root/data/coco \
  --output_dir $OUTPUT_DIR \
  --epochs 500 \
  --batch_size 8 \
  --lr 1e-4 \
  --lr_backbone 1e-5 \
  --weight_decay 1e-4 \
  --num_workers 2 \
  $RESUME_OPTION &

TRAIN_PID=$!

# SIGTERM/SIGINTを受信した時の処理
cleanup() {
    echo "=== 終了信号を受信 ==="
    echo "トレーニングプロセス (PID: $TRAIN_PID) に終了信号を送信中..."
    kill -TERM $TRAIN_PID 2>/dev/null
    
    # プロセスが終了するまで待機(最大60秒)
    local count=0
    while kill -0 $TRAIN_PID 2>/dev/null && [ $count -lt 60 ]; do
        sleep 1
        count=$((count + 1))
    done
    
    # まだ動いている場合は強制終了
    if kill -0 $TRAIN_PID 2>/dev/null; then
        echo "強制終了中..."
        kill -KILL $TRAIN_PID 2>/dev/null
    fi
    
    echo "=== チェックポイント確認 ==="
    if [ -f "$OUTPUT_DIR/checkpoint.pth" ]; then
        echo "チェックポイントが保存されています: $OUTPUT_DIR/checkpoint.pth"
        ls -la $OUTPUT_DIR/checkpoint.pth
    else
        echo "警告: チェックポイントファイルが見つかりません"
    fi

    echo "=== 終了処理完了 ==="
    exit 0
}

# シグナルハンドラーを設定
trap cleanup SIGTERM SIGINT

# トレーニングプロセスの完了を待機
wait $TRAIN_PID
EXIT_CODE=$?

echo "=== Training Completed ==="
echo "Exit Code: $EXIT_CODE"
echo "End Time: $(date)"

# 実行結果の確認
if [ $EXIT_CODE -eq 0 ]; then
    echo "トレーニングが正常に完了しました"
else
    echo "トレーニングでエラーが発生しました (Exit Code: $EXIT_CODE)"
fi

# 最終的なチェックポイントの確認
echo "=== Final Checkpoint Status ==="
if [ -f "$OUTPUT_DIR/checkpoint.pth" ]; then
    echo "最終チェックポイント: $OUTPUT_DIR/checkpoint.pth"
    ls -la $OUTPUT_DIR/checkpoint.pth
else
    echo "チェックポイントファイルが見つかりません"
fi

# ディスク使用量の確認
echo "=== Disk Usage ==="
du -sh $OUTPUT_DIR
echo "=================="

auto_continue_detr.sh
#!/bin/bash
# auto_continue_detr.sh

SCRIPT_NAME="detr_checkpoint.sh"
MAX_JOBS=10
CURRENT_JOB=1

echo "=== DETR継続実行スクリプト ==="
echo "最大ジョブ数: $MAX_JOBS"
echo "開始時刻: $(date)"

while [ $CURRENT_JOB -le $MAX_JOBS ]; do
    echo ""
    echo "=== ジョブ $CURRENT_JOB/$MAX_JOBS を投入 ==="

    # ジョブを投入し、ジョブIDのみを抽出
    SBATCH_OUTPUT=$(sbatch --parsable $SCRIPT_NAME 2>&1)
    
    if [ $? -eq 0 ]; then
        # 出力から数字のみを抽出(ジョブID)
        JOB_ID=$(echo "$SBATCH_OUTPUT" | grep -o '[0-9][0-9]*' | tail -1)
        
        if [ -n "$JOB_ID" ]; then
            echo "ジョブ ID: $JOB_ID が投入されました"
            echo "sbatch出力: $SBATCH_OUTPUT"
        else
            echo "エラー: ジョブIDの抽出に失敗しました"
            echo "sbatch出力: $SBATCH_OUTPUT"
            exit 1
        fi
    else
        echo "エラー: ジョブの投入に失敗しました"
        echo "sbatch出力: $SBATCH_OUTPUT"
        exit 1
    fi

    # ジョブの状態を監視
    echo "ジョブ $JOB_ID の実行を監視中..."

    # 初期状態確認
    while true; do
        JOB_EXISTS=$(squeue -j $JOB_ID 2>/dev/null | grep "$JOB_ID" | wc -l)
        if [ $JOB_EXISTS -eq 0 ]; then
            echo "ジョブ $JOB_ID がキューから消えました"
            break
        fi
        
        # 5分間隔でステータスを表示
        JOB_STATUS=$(squeue -j $JOB_ID --format="%T" --noheader 2>/dev/null | tr -d ' ')
        if [ -n "$JOB_STATUS" ]; then
            echo "$(date): ジョブ $JOB_ID - ステータス: $JOB_STATUS"
        fi
        sleep 300
    done

    # ジョブの最終状態を確認
    echo "ジョブ $JOB_ID が終了しました。最終状態を確認中..."
    sleep 10  # saccctの情報が更新されるまで少し待機

    # sacctでジョブの状態を確認(数値のジョブIDを使用)
    JOB_STATE=$(sacct -j $JOB_ID --format=State --noheader 2>/dev/null | tail -1 | tr -d ' ')
    echo "最終状態: $JOB_STATE"

    # チェックポイント確認関数
    find_latest_checkpoint() {
        find /root/detr/output/CheckPoints* -type f -name "checkpoint.pth" 2>/dev/null | sort -r | head -1
    }

    case $JOB_STATE in
        "COMPLETED")
            echo "🎉 トレーニングが正常に完了しました!"

            LATEST_OUTPUT=$(ls -td /root/detr/output/CheckPoints* 2>/dev/null | head -1)
            if [ -n "$LATEST_OUTPUT" ]; then
                echo "最終出力ディレクトリ: $LATEST_OUTPUT"
                echo "最終結果:"
                ls -la "$LATEST_OUTPUT/"
            fi
            exit 0
            ;;

        "TIMEOUT" | "CANCELLED" | "FAILED" | "NODE_FAIL" | "OUT_OF_MEMORY")
            echo "⚠️ ジョブが $JOB_STATE しました。チェックポイントから継続実行を試みます..."

            LATEST_CHECKPOINT=$(find_latest_checkpoint)
            if [ -n "$LATEST_CHECKPOINT" ]; then
                echo "チェックポイントが見つかりました: $LATEST_CHECKPOINT"
            else
                echo "チェックポイントが見つかりません。実行を中止します。"
                exit 1
            fi
            ;;

        "")
            echo "❓ ジョブ状態が取得できませんでした。手動で確認してください。"
            echo "ジョブ ID: $JOB_ID"
            
            # チェックポイントの存在確認
            LATEST_CHECKPOINT=$(find_latest_checkpoint)
            if [ -n "$LATEST_CHECKPOINT" ]; then
                echo "チェックポイントが見つかりました: $LATEST_CHECKPOINT"
                echo "継続実行を試みます..."
            else
                echo "チェックポイントが見つかりません。実行を中止します。"
                exit 1
            fi
            ;;

        *)
            echo "❓ 不明な状態: $JOB_STATE"
            echo "チェックポイントの存在を確認中..."

            LATEST_CHECKPOINT=$(find_latest_checkpoint)
            if [ -n "$LATEST_CHECKPOINT" ]; then
                echo "チェックポイントが見つかりました: $LATEST_CHECKPOINT"
            else
                echo "チェックポイントが見つかりません。実行を中止します。"
                exit 1
            fi
            ;;
    esac

    # 次のジョブまで少し待機
    echo "30秒後に次のジョブを投入します..."
    sleep 30

    CURRENT_JOB=$((CURRENT_JOB + 1))
done

echo "⚠️  最大ジョブ数に達しました。トレーニングが完了していない可能性があります。"
echo "最新のチェックポイントを確認してください:"
find /root/detr/output/CheckPoints* -name "checkpoint.pth" 2>/dev/null || echo "チェックポイントが見つかりません"

detr_checkpoint.shとauto_continue_detr.shを作成し,以下の通り実行権限を付与する.

bash
chmod +x detr_checkpoint.sh
chmod +x auto_continue_detr.sh

実行権限を付けたら,以下のコマンドでバックグラウンド実行します.

bash
nohup ./auto_continue_detr.sh > auto_continue.log 2>&1 &

実行状況のログは auto_continue.log に保存されるので,進捗やエラーを確認できます.

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?