gpt-ossをOpenShift AIで実行する

 こんにちは、レッドハットでソリューションアーキテクトをしている石川です。米国時間の8月5日にOpenAI社がgpt-ossというオープンモデルをリリースしました。OpenAIにとってChatGPTが公開されて以降では初めてとなるオープンモデルの発表となり、大きな反響を呼んでいます。これらのモデルは自身のローカルPCや、サーバー環境にダウンロードし、実行可能であることから、これまでクラウド上で提供されるAIの利用が難しかった環境でも利用が可能です。 本ブログ記事ではgpt-ossをOpenShift AI上で実行し、その実態を確認してみたいと思います。

公開されたモデルについて

 モデルの詳細についてはOpenAIがブログを公開しているため、ここではいくつか気になった部分を取り上げます。 今回公開されたのはgpt-oss-120bとgpt-oss-20bという二つのモデルです。パラメーターサイズはそれぞれ約1170億と210億となっており、用途や利用するGPUのスペックに合わせてモデルを選択することができます。モデルのアーキテクチャとしてはDeepSeekやQwen3などと同様にMixture of Experts(MoE)が採用されており、推論時にアクティブとなるパラメーターは全体の一部のみとなるため、推論を高速に実行できます。
 興味深いのが公開されたモデルがMXFP4という形式で既に量子化済みのモデルであるということです。MXFP4はOpen Compute Projectの中で定義されている4bitのデータ形式です。4bitで表現される数値ブロック32個ごとに、8bitのスケーリングファクターが存在することで、量子化前の数値との誤差を低減しています。これによりGPUにモデルをロードする際に必要なVRAM容量を抑えつつ、モデルのデグレードを防いでいます。
 今回公開されたモデルにはApache 2.0ライセンスが適用されています。モデルのトレーニング時のコードや、学習の段階で利用したデータについての情報は公開されていないことから、open source initiatveが公開するOpen Source AIの定義には合致していませんが、オープンウェイトモデルとして利用の自由度は高く、ファインチューニングを行う方法なども公開されています。

実行環境の準備

OpenShiftクラスタの準備

 gpt-ossを実行する環境として、AWS上にROSA HCPクラスタを構築し、必要なOperatorのインストールを行います。クラスタの構築方法に関しては本記事の中では紹介しないため、公式ドキュメントや、こちらのブログ記事などを参照ください。

 ROSAクラスタが構築できたら、MachinePoolとしてg6e.12xlargeインスタンスを追加します。このインスタンスタイプにはNVIDIA L40S GPUが4枚搭載されており、今回ホストするgpt-oss-120bに対して十分なVRAM容量を確保できます。

# MachinePoolの追加
$ rosa create machinepool --cluster={クラスタ名} --name=gpu --replicas=1 --instance-type=g6e.12xlarge

 なお東京リージョンにおいて、このインスタンスのオンデマンド料金は$15.21742/hourとなるため、利用時のコストには注意してください。

Operatorのインストール

 OpenShiftクラスタでLLMを実行するために必要な以下のOperatorをインストールします。
 (1) Node Feature Discovery Operator
 (2) NVIDIA GPU Operator
 (3) OpenShift AI Operator

 (1)(2)をOpenShiftコンソールのOperatorHubからインストールし、設定します。これらのOperatorの設定方法について、以前のブログに記載しているためこちらを参照してください。

 (3)のOpenShift AI Operatorについて、以前は推論時のためのコンポーネントであるKServeを利用するため、Service Mesh Operatorや、Serverless Operatorのインストールが必須となっていました。しかし、現行のOpenShift AI v2.22では、これらを利用しないKServeのStandardモードがサポートされ、追加のOperatorをインストールすることなく、LLMの推論が実行できるようになっています。(Service Mesh、Serverlessを利用するデプロイパターンは、Advancedモードとして継続してサポート。)
docs.redhat.com  本記事ではStandardモードでのデプロイを行うよう、Operatorを設定します。

 OperatorHubで「OpenShift AI」を検索し、インストールします。stableチャネルから、現行の最新バージョンである2.22.1を選択します。その他の設定は全てデフォルトのままとします。  OpenShift AIではOperatorのインストール時に行う初期設定をDSCInitializationというカスタムリソースで管理しています。デフォルトではServiceMeshを利用するよう設定されるため、以下のコマンドを実行し、ServiceMeshを利用しない設定に変更します。

# DSCInitializationの変更
$ oc patch dscinitialization default-dsci --type='json' --patch '[{"op": "replace", "path": "/spec/serviceMesh/managementState", "value": "Removed"}]'

 続いてOpenShift AIのDataSciencrClusterカスタムリソースを作成します。以下の通り設定を行います。

apiVersion: datasciencecluster.opendatahub.io/v1
kind: DataScienceCluster
metadata:
  name: default-dsc
  labels:
    app.kubernetes.io/created-by: rhods-operator
    app.kubernetes.io/instance: default-dsc
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/name: datasciencecluster
    app.kubernetes.io/part-of: rhods-operator
spec:
  components:
    codeflare:
      managementState: Managed
    kserve:
      nim:
        managementState: Managed
      rawDeploymentServiceConfig: Headed #①
      serving:
        ingressGateway:
          certificate:
            type: OpenshiftDefaultIngress
        managementState: Removed #②
        name: knative-serving
      managementState: Managed
    modelregistry:
      registriesNamespace: rhoai-model-registries
      managementState: Removed
    feastoperator:
      managementState: Removed
    trustyai:
      managementState: Managed
    ray:
      managementState: Managed
    kueue:
      managementState: Managed
    workbenches:
      workbenchNamespace: rhods-notebooks
      managementState: Managed
    dashboard:
      managementState: Managed
    modelmeshserving:
      managementState: Managed
    llamastackoperator:
      managementState: Removed
    datasciencepipelines:
      managementState: Managed
    trainingoperator:
      managementState: Managed
  • ①: .spec.kserve.rawDeploymentServiceConfigをHeadedに変更。
  • ②: .spec.kserve.serving.managementStateをRemovedに変更

 これらの設定を行うことで、KServe利用時にServiceMeshやServerlessのカスタムリソースを使わずに、OpenShiftのデフォルトリソースであるRouteとServiceを介して推論エンドポイントを公開できます。

AcceleratorProfileの作成

 OpenShift AIコンソールからGPUを利用するためのリソースとして、AcceleratorProfileを作成します。

$ cat << EOF | oc apply -f -
apiVersion: dashboard.opendatahub.io/v1
kind: AcceleratorProfile
metadata:
  name: nvidia-gpu
  namespace: redhat-ods-applications
spec:
  description: ''
  displayName: NVIDIA GPU
  enabled: true
  identifier: nvidia.com/gpu
  tolerations: []
EOF

モデルの準備とカスタムランタイムの登録

モデルファイルのダウンロード

 OpenShift AIでgpt-ossをデプロイするため、Hugging Faceからモデルファイルをダウンロードします。OpenShift AIの標準的なモデルデプロイでは、オブジェクトストレージにモデルファイルを配置しておき、デプロイするタイミングでファイルを取得するという方法を取ります。以前のブログではこの方法でモデルをデプロイしました。 今回はあらかじめPVにモデルファイルをダウロードし、それをアタッチすることでモデルをデプロイします。こちらの方法ではオブジェクトストレージを使わずにモデルをデプロイできます。

以下のコマンドで利用するプロジェクト、PVCを作成します。

# プロジェクトの作成
$ oc new-project llm-serving --display-name='LLM Serving'

$ oc label namespace llm-serving opendatahub.io/dashboard=true

# PVCの作成
$ cat << EOF | oc apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: model-store
  namespace: llm-serving
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 200Gi
EOF

 Hugging FaceのOpenAIのリポジトリからモデルをダウンロードするためのPodを作成し、PVCをアタッチします。ここで利用するコンテナイメージには、huggingface_hubライブラリをあらかじめインストールしており、そちらを使ってモデルファイルをPVにダウンロードします。環境変数として設定しているHF_REPO_IDの値を変えることで、別のリポジトリからモデルをダウンロードすることも可能です。

# リポジトリの指定
$ export HF_REPO_ID=openai/gpt-oss-120b

# モデルファイルのダウンロード
$ cat << EOF | oc create -f -
apiVersion: v1
kind: Pod
metadata:
  generateName: hf-download-model-
  labels:
    name: hf-download-model
spec:
  volumes:
    - name: model-store
      persistentVolumeClaim:
        claimName: model-store
  restartPolicy: Never
  initContainers:
    - name: fix-volume-permissions
      image: quay.io/quay/busybox:latest
      command: ["sh", "-c"]
      args: ["mkdir -p /mnt/models/$HF_REPO_ID && chmod -R 777 /mnt/models"]
      volumeMounts:
        - mountPath: "/mnt/models/"
          name: model-store
  containers:
    - name: download-model
      imagePullPolicy: IfNotPresent
      image: quay.io/jishikaw/huggingface-hub:latest
      command: ["sh", "-c"]
      args: ["hf download --local-dir=/mnt/models/$HF_REPO_ID --exclude=/original/ $HF_REPO_ID"]
      volumeMounts:
        - mountPath: "/mnt/models/"
          name: model-store
EOF

カスタムランタイムの登録

 この記事を書いている2025年8月13日時点では、OpenShift AIにデフォルトで包含されているvLLMのバージョンがgpt-ossに対応していません。そのためDockerHubで提供されるOSS版の最新イメージをカスタムランタイムとして登録します。この手順は今後のOpenShift AIのアップデートでvLLMのバージョンが上がり、gpt-ossに正式に対応すれば不要となります。

 OpenShift AIコンソールを開き、Settings -> Serving runtimesから、新しいカスタムランタイムを登録します。

 以下の通り設定してください。
・Select the model serving platforms this runtime supports: Single-model serving platform
・Select API protocol this runtime supports: REST 

apiVersion: serving.kserve.io/v1alpha1
kind: ServingRuntime
metadata:
  annotations:
    opendatahub.io/recommended-accelerators: '["nvidia.com/gpu"]'
    opendatahub.io/runtime-version: v0.10.2.dev2
    openshift.io/display-name: Latest OSS vLLM
    opendatahub.io/apiProtocol: REST
  labels:
    opendatahub.io/dashboard: "true"
  name: vllm-cuda-runtime-copy
spec:
  annotations:
    prometheus.io/path: /metrics
    prometheus.io/port: "8080"
  containers:
    - args:
        - --port=8080
        - --model=/mnt/models
        - --served-model-name={{.Name}}
      command:
        - vllm
        - serve
      env:
        - name: VLLM_ATTENTION_BACKEND
          value: TRITON_ATTN_VLLM_V1
        - name: HOME
          value: /tmp/vllm
        - name: HF_HOME
          value: /tmp/hf_home
      image: vllm/vllm-openai:gptoss
      name: kserve-container
      ports:
        - containerPort: 8080
          protocol: TCP
  multiModel: false
  supportedModelFormats:
    - autoSelect: true
      name: vLLM

モデルのデプロイ

 OpenShift AIコンソールのData science projectsから、先ほど作成したLLM Servingプロジェクトを開きます。Modelsタブを開き、Single model servingを選択してください。Deploy modelから以下の通り設定を行います。

・Model deployment name: gpt-oss-120b
・Serving runtime: Latest OSS vLLM
・Number of model server replicas to deploy: 1
・Model server size: CUSTOM
 ・CPUs requested: 1
 ・CPU limit: 6
 ・Memory requested: 1
 ・Memory limit: 30
・Accelerator: NVIDIA GPU
 ・Number of accelerators: 4
・Model route: チェック入れる
・Token authentication: チェック不要
・Connection type: URI -v1
・Connection name: gpt-oss-120b
・URI: pvc://model-store/openai/gpt-oss-120b
・Additional serving runtime arguments:
 ・--tensor-parallel-size=4

 デプロイ状況については以下のコマンドでログを確認できます。

# デプロイログ確認
$ oc logs -f deployment/gpt-oss-120b-predictor

 INFO: Application startup complete.というログが確認できれば、起動は完了です。OpenShift AIコンソールからAPIアクセスのためのエンドポイントを確認できます。

モデルの実行とベンチマーキング

 デプロイしたモデルをOpen WebUIを使って呼び出します。OpenShiftへのOpen WebUIのデプロイ方法、設定方法については以前のブログの"モデルの実行"セクションを参照してください。  チャットを実施してみたところ、日本語でのやり取りに関しても問題なく実行できます。

 デプロイしたモデルに対し、GuideLLMを利用してパフォーマンスのベンチマークを実行します。GuideLLMはvLLMプロジェクトの中で開発されている、モデルのベンチマークツールです。OpenAI互換のAPIを提供する推論エンジンであればvLLM以外でも利用することができます。

 Pythonの実行環境に以下のコマンドでツールをインストールし、実行します。

# ツールのインストール
$ pip install guidellm

# ベンチマークの実行
$ guidellm benchmark \
  --target "https://gpt-oss-120b-llm-serving.apps.rosa.mycluster3.uwl9.p3.openshiftapps.com" \
  --processor openai/gpt-oss-120b \
  --rate-type concurrent \
  --rate 200 \
  --max-seconds 60 \
  --data "prompt_tokens=512,output_tokens=256"

 --targetで指定するAPIのエンドポイントは、自身の環境に合わせ設定してください。この設定では同時接続数を200とし、入力トークンが512、出力トークンが256となるリクエストを60秒間でどれだけ処理できるか計測します。結果は以下の通りです。

 Out Tok/secは一秒間あたりの平均出力トークン数、Tot Tok/secは一秒間あたりの平均入出力トークン数を表します。それぞれ1820.0、9094.1という結果となりました。
 TTFT(ms)は最初のトークン出力までの時間、ITL(ms)は最初のトークンを除いた平均トークン出力時間を表します。TTFTやITLが遅延すると、チャットなどのアプリを利用する際にユーザー体験が低下します。今回の結果では、TTFT、ITL共に99パーセンタイルでの結果が1秒未満であるため、大きな遅延は発生していないと見ることができます。
 トークン入出力のベンチマーク結果と、利用しているAWSのGPUインスタンス料金から1Mトークンあたりの費用を計算することができます。

出力トークン:
(1000000 / (1820 x 3600) ) * 15.21742 ≒ 2.32

入力トークン:
(1000000 / ( (9094.1 - 1820) * 3600) ) * 15.21742 ≒ 0.58

 計算の結果、1Mあたりの出力コストは$2.32、入力コストが$0.58となりました。この値は常に十分なトークン入出力が発生することを前提としているため、単純な比較はできませんが、gpt-oss-120bと同等のモデルであるgpt4o-miniをクラウドで利用する際の1Mトークンあたりのコストが、出力$4.40、入力$1.10であることを考えると、悪くない結果だと言えるのではないでしょうか。

まとめ

 本記事ではgpt-ossをOpenShift AI上でホストし、モデルのベンチマークを実行しました。これだけの性能のモデルが公開され、誰でも自由に使うことができるということに対して改めて大きな驚きを覚えます。今後も引き続きLLMの動向や、関連するオープンソースの動向をウォッチし、情報発信をしていきたいと思います。

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。