GDC Sandbox に TimesFM をデプロイする

Google Research の TimesFM モデルは、多くの実世界のデータセットから数十億のタイムポイントで事前にトレーニングされた時系列予測用の基盤モデルです。そのため、多くのドメインにわたる新しい予測データセットに適用できます。

このチュートリアル ガイドでは、GDC Sandbox に TimesFM をデプロイする方法について説明します。このガイドの目的は次のとおりです。

  • TimesFM を実行する Docker コンテナを作成します。
  • GDC Sandbox AI Optimized SKU で提供される GPU を使用してコンテナをデプロイする。
  • シンプルな HTTP リクエストを使用して TimesFM 関数を呼び出します。

始める前に

GDC Sandbox の GPU は org-infra クラスタに含まれています。

  • 組織のインフラストラクチャ クラスタに対してコマンドを実行するには、クラスタを操作するで説明されているように、org-1-infra クラスタの kubeconfig があることを確認します。

    • gdcloud コマンドラインで構成と認証を行う。
    • 組織インフラストラクチャ クラスタの kubeconfig ファイルを生成し、そのパスを環境変数 KUBECONFIG に割り当てます。
  • ユーザーにプロジェクト sandbox-gpu-projectsandbox-gpu-admin ロールが割り当てられていることを確認します。デフォルトでは、このロールは platform-admin ユーザーに割り当てられます。platform-admin としてログインし、次のコマンドを実行して、他のユーザーにロールを割り当てることができます。

    kubectl --kubeconfig ${KUBECONFIG} create rolebinding ${NAME} --role=sandbox-gpu-admin \
    --user=${USER} --namespace=sandbox-gpu-project
    
  • Artifact Registry の使用の説明に従って Artifact Registry リポジトリを設定し、アーティファクト レジストリにイメージを push および pull できるようにログインしてください。

TimesFM モデルをデプロイする

デプロイは、特定のコンポーネントまたはサービスを定義する Kubernetes 構成ファイル(YAML マニフェスト)のセットによってオーケストレートされます。

  1. 時系列予測を行う predict 関数と、テストデータに基づいて可視化を生成する timeseries 関数を含む、flask ベースの Python スクリプト app.py を作成します。

      from flask import Flask, jsonify, request
      import numpy as np
      import pandas as pd
      from sklearn.preprocessing import StandardScaler
    
      # Initialize Flask application
      app = Flask(__name__)
    
      # Sample route to display a welcome message
      @app.route('/')
      def home():
          return "Welcome to TimesFM! Use the API to interact with the app."
    
      # Example route for predictions (TimesFM might do time-series forecasting or music recommendations)
      @app.route('/predict', methods=['POST'])
      def predict():
          data = request.get_json()
    
          # Ensure the data is in the right format
          if 'features' not in data:
              return jsonify({'error': 'No features provided'}), 400
    
          # For this example, assume 'features' is a list of numbers that need to be scaled
          features = data['features']
          features = np.array(features).reshape(1, -1)
    
          # Dummy model: Apply standard scaling (you would use an actual model here)
          scaler = StandardScaler()
          scaled_features = scaler.fit_transform(features)
    
          # You would normally load your model here (e.g., using pickle or joblib)
          # For simplicity, let's just return the scaled features as a placeholder for prediction
          result = scaled_features.tolist()
    
          return jsonify({'scaled_features': result})
    
      # Example of a route for data visualization or analysis
      @app.route('/timeseries', methods=['GET'])
      def timeseries_analysis():
          # Generate a dummy time series data (replace with actual data)
          time_series_data = pd.Series(np.random.randn(100), name="Random Data")
    
          # Example analysis: compute simple moving average
          moving_avg = time_series_data.rolling(window=10).mean()
    
          return jsonify({
              'time_series': time_series_data.tolist(),
              'moving_average': moving_avg.tolist()
          })
    
      # Run the app
      if __name__ == '__main__':
          app.run(debug=True, host='0.0.0.0', port=5000)
    
  2. timesfm がインストールされ、アプリを呼び出す Dockerfile を作成します。

     # Use a base image with Python installed
     FROM python:3.11-slim
     # Set the working directory inside the container
     WORKDIR /app
     # Copy the requirements.txt (if any) and install dependencies
     COPY requirements.txt .
     RUN pip install --no-cache-dir numpy pandas timesfm huggingface_hub jax pytest flask scikit-learn
    
     # Copy the rest of the code into the container
     COPY . .
    
     # Expose the necessary port (default 5000 or whatever your app uses)
     EXPOSE 5000
    
     # Define the entrypoint for the container
     CMD ["python", "app.py"] # Replace with the correct entry script for TimesFM
    
  3. Docker イメージをビルドして、Artifact Registry リポジトリにアップロードします。

    docker build -t timesfm .
    docker tag timesfm "REGISTRY_REPOSITORY_URL"/timesfm:latest
    docker push "REGISTRY_REPOSITORY_URL"/timesfm:latest
    

    次のように置き換えます。

    • REGISTRY_REPOSITORY_URL: リポジトリの URL。
  4. Docker 認証情報を保存する Secret を作成します。

    
    export SECRET="DOCKER_REGISTRY_SECRET"
    export DOCKER_TEST_CONFIG=~/.docker/config.json 
    kubectl --kubeconfig ${KUBECONFIG} create secret docker-registry ${SECRET} --from-file=.dockerconfigjson=${DOCKER_TEST_CONFIG} -n sandbox-gpu-project
    

    次のように置き換えます。

    • DOCKER_REGISTRY_SECRET: シークレットの名前。
  5. timesfm をデプロイするファイル timesfm-deployment.yaml を作成します。

    timesfm サーバーのデプロイでは、1 つの GPU がリクエストされます。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: timesfm-deployment
      namespace: sandbox-gpu-project
      labels:
        app: timesfm
    spec:
      replicas: 1 # You can scale up depending on your needs
      selector:
        matchLabels:
          app: timesfm
      template:
        metadata:
          labels:
            app: timesfm
        spec:
          containers:
          - name: timesfm
            image: REGISTRY_REPOSITORY_URL/timesfm:latest
            ports:
            - containerPort: 5000
            resources:
              requests:
                nvidia.com/gpu-pod-NVIDIA_H100_80GB_HBM3: 1  # Request 1 GPU
              limits:
                nvidia.com/gpu-pod-NVIDIA_H100_80GB_HBM3: 1  # Limit to 1 GPU
            env:
            - name: ENV
              value: "production"
          imagePullSecrets:
          - name: docker-registry-secret
    

    次のように置き換えます。

    • REGISTRY_REPOSITORY_URL: リポジトリの URL。
    • DOCKER_REGISTRY_SECRET: Docker シークレットの名前。
  6. timesfm サーバーを内部的に公開するファイル timesfm-service.yaml を作成します。

    apiVersion: v1
    kind: Service
    metadata:
      name: timesfm-service
    spec:
      selector:
        app: timesfm
      ports:
        - protocol: TCP
          port: 80 # External port exposed
          targetPort: 5000 # Internal container port for Flask
      type: LoadBalancer # Use NodePort for internal access
    
  7. マニフェストを適用します。

    kubectl --kubeconfig ${KUBECONFIG} apply -f timesfm-deployment.yaml
    kubectl --kubeconfig ${KUBECONFIG} apply -f timesfm-service.yaml
    
  8. TimesFM Pod が実行されていることを確認します。

    kubectl --kubeconfig ${KUBECONFIG} get deployments timesfm-deployment -n sandbox-gpu-project
    kubectl --kubeconfig ${KUBECONFIG} get service timesfm-service -n sandbox-gpu-project
    
  9. 外部 IP アドレスからのインバウンド トラフィックを許可するプロジェクト ネットワーク ポリシーを作成します。

    kubectl --kubeconfig ${KUBECONFIG} apply -f - <<EOF
    apiVersion: networking.global.gdc.goog/v1
    kind: ProjectNetworkPolicy
    metadata:
      namespace: sandbox-gpu-project
      name: allow-inbound-traffic-from-external
    spec:
      policyType: Ingress
      subject:
        subjectType: UserWorkload
      ingress:
      - from:
        - ipBlock:
            cidr: 0.0.0.0/0
    EOF
    
  10. 次のコマンドを実行して、TimesFM サービスの外部 IP を特定します。この値は、後のステップで TIMESFM_END_POINT に代入するので、メモしておいてください。

      kubectl --kubeconfig ${KUBECONFIG} get service timesfm-service \
            -n sandbox-gpu-project -o jsonpath='{.status.loadBalancer.ingress[*].ip}'
    

サービスをテストする。

  1. 予測を取得するには、curl コマンドを使用してサービスにデータを送信します。TIMESFM_END_POINT は、サービスのアドレスと特徴の入力値に置き換えます。これにより、app.py で定義された predict 関数が呼び出され、入力データに対して操作が実行され、JSON 形式で返されます。

    curl -X POST http://TIMESFM_END_POINT/predict -H "Content-Type: application/json" -d '{"features": [1.2, 3.4, 5.6]}'
    
  2. /timeseries に curl リクエストを送信して、ランダムに生成されたデータを使用したデータ可視化の例を確認します。これにより、app.py で定義された時系列関数が呼び出され、ランダムな時系列が生成され、移動平均分析が実行されます。

    curl http://TIMESFM_END_POINT/timeseries