RHEL AIであそぼ！ on AWS

# 本記事について
この記事では、AWS上でRHEL AIをセットアップし、以下一通りの機能が利用できるようになるまでを解説します。

- モデルのダウンロード
- モデルのサーブと推論（チャット）
- モデルのカスタマイズ（ファインチューニング）
- カスタマイズしたモデルをアップロード

基本的にはRHEL AIの公式ドキュメントを逐次参照しつつ、補足説明しながら初心者でもすぐにモデルのカスタマイズを実行できるよう、丁寧に説明します。

:::note warn
RHEL AIにおけるモデルのカスタマイズにおいては、新しい知識およびスキルの獲得が可能です。ただし、本記事では簡単にモデルのカスタマイズを体験するため、知識トレーニングのみを行います。
:::

# RHEL AIについて
いきなりセットアップを始める前に、まずはRHEL AIについて簡単に説明します。

## RHEL AIとは？
RHEL AIは、高度な知識や技術がなくとも、すぐに生成AIの利用を始めることができるアウト・オブ・ボックスな「ハイブリッドクラウドAI OS」です。生成AIの推論・学習に必要なオープンソースのソフトウェアをすべて揃え、あらゆるプラットフォームの上で利用できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/db5b2153-c6d8-4637-9d53-d8d9918334a2.png)

RHEL AIにはオープンソースLLMである「**IBM Granite**」が最初から搭載されており、後述のInstructLabによる操作やカスタマイズが可能です。こうしたLLMの実行環境をまるっとパッケージングし、**どこでも、すぐに、同じように、生成AIの利用やカスタマイズが可能**なのです。勿論、Red Hatによるサポートの元利用できます。

RHEL AIは簡単なコマンド操作によって、LLMのサービングやチャットが開始できます。さらに、企業や個人が有している固有の知識を使って、モデルのカスタマイズを実施できます。カスタマイズしたモデルを評価したりもできます。勿論、カスタマイズ後のモデルとチャットすることも可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/53ba74a1-f650-49c2-a6f0-0e2f7b21048e.png)

### 対応プラットフォーム
2025年3月時点で最新の「RHEL AI 1.4」現在対応しているプラットフォームは以下の通りです。
- ベアメタルサーバ
- Amazon Web Service
- IBM Cloud
- Microsoft Azure
- Google Cloud Platform

RHEL AIはそれぞれのプラットフォームごとのOSイメージが提供されます。

:::note 
AWSおよびAzureについてはマーケットプレイスからの利用も可能です。これによりセットアップ手順を大幅に簡略化し、RHEL AIを従量課金で利用することができます。
- [AWS Marketplace](https://aws.amazon.com/marketplace/pp/prodview-ymlols4ldtldu)
- [Azure Marketplace](https://azuremarketplace.microsoft.com/ja-jp/marketplace/apps/redhat.rh-rhel-ai?tab=overview)

また、Red HatとDellおよびLenovoの戦略的提携により、両者のサーバに最初からインストールされた状態で利用することも可能です。
- [Red Hat 認定パートナーから購入する](https://www.redhat.com/ja/technologies/linux-platforms/enterprise-linux/ai/how-to-buy)
>Red Hat は、AI ハードウェアの主要プロバイダーと提携し、各社のシステム上で Red Hat Enterprise Linux AI のテストと検証を継続的に行っています。
:::

### RHEL AIに含まれるコンポーネント
RHEL AIは、冒頭に示したような様々な生成AIに対する操作をコマンドのみで可能としています。しかし、その裏には様々なオープンソースのソフトウェアが連携して動いています。それが以下になります。

|ソフトウェア|詳細|
|---|---|
|InstructLab|LLMの効率的なトレーニング方法「LAB」に基づき、マルチフェーズトレーニングを実行するためツール。難しい知識は不要で、ilabコマンドを使って全ての操作が可能。|
|deepspeed|Neural NetworkやLanguage Modelのトレーニングと推論を効率化するためのライブラリ。分散トレーニングやモデル圧縮、メモリ最適化をサポートする。|
|Pytorch|ディープラーニングモデルの構築やトレーニングに広く使われるオープンソースの機械学習ライブラリ。|
|vLLM|最適化された推論エンジンを提供する。LLMの推論速度を向上させることを目的としている。主に大量の並列リクエストに対し、CPUおよびGPUを高効率で活用可能。|
|各アクセラレータ用Driver|NVIDIA、AMD、IntelのGPU製品に対応したDriver。|

:::note
RHEL AIに含まれるコンポーネントの詳細は[公式ドキュメント](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux_ai/1.4)を御覧ください。
:::

こうした各種のライブラリやソフトウェアについての高度な知識がなくとも、すべてを`ilab`コマンドで簡単に操作できるのが、RHEL AIの最大のメリットです。

### 代表的なコマンド
RHEL AIの主要なコンポーネントであるInstructLabによって利用可能な`ilab`コマンドラインインターフェース（CLI）は、生成AIのサービング、推論、カスタマイズといったライフサイクルを管理するためのコマンド一式が揃っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/569de74a-af6e-4fe2-b187-a91aa282bd36.png)

これまでは、モデルのカスタマイズは非常に高度な知識やツールの理解が不可欠でしたが、これすら`ilab`コマンド一発で実施できるようになっています。

### RHEL AIが解決する「学習データ用意のハードル」
モデルのカスタマイズとは、元の生成AIモデルのパラメータ（重み）に対して意味のある変化を加えることを指します。そのためには、大量かつ高品質なデータが必要です。データの品質がどれほど高くても、量が不足していれば十分な効果は得られません。逆に、大量のデータがあっても、その質が低く誤りを含んでいると、モデルのパラメータが意図しない方向に変化し、期待したカスタマイズの結果が得られない可能性があります。

それを解決するのがInstructLabの合成データ生成（Synthetic Data Generation, SDG）です。SDGおよびその後のモデルトレーニングのプロセスは、概ね以下のとおりです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/96cb20a0-fa05-4c3b-b4c8-031fe12962c2.png)
出典：[How InstructLab’s synthetic data generation enhances LLMs](https://www.redhat.com/en/blog/how-instructlabs-synthetic-data-generation-enhances-llms)

1. 人間が新しい知識の元ネタ（Q&Aファイル＆参照ドキュメント）を用意
1. その元ネタを使って教師モデルが大量の類似データを合成する
1. 合成したデータの品質を確認し、品質の良いものだけを残す
1. 品質の良い大量の合成データを用いてモデルをトレーニングする

この一連の手法は、MIT-IBM Watson AI LabとIBM Research の共同研究として発表された論文がもとになっています。この論文で提唱される手法「LAB」をソフトウェアとして実装したものが「InstructLab」なわけです。

:::note
詳しい解説は[Red Hatのブログ](https://www.redhat.com/ja/blog/how-instructlabs-synthetic-data-generation-enhances-llms)を参照いただくことをお勧めします。また、論文の内容にご興味のある方は以下をご参照ください。
[LAB: Large-Scale Alignment for ChatBots](https://arxiv.org/abs/2403.01081)
:::



# 作業端末とAWS環境の準備
本記事では、公式ドキュメントの手順に従ってAWS上にRHEL AIインスタンスを起動します。なお、前提として以下2点は完了しているものとします。
1. AWSアカウントを作成し、作業端末のターミナルでAWS CLIが利用できること
1. Red Hatアカウントを作成済みで、RHEL AIの有効なサブスクリプションを有していること

それでは早速やっていきましょう〜！

## 本記事における環境情報ならびにRHEL AIのバージョン
今回RHEL AIを構築・実行する環境の情報は以下のとおりです。
- **作業環境**
    - 端末：MacBook Air（Appleシリコンモデル）
    - ターミナル：Macのデフォルトのターミナル
    - 利用するCLI：AWS、Terraform
- **AWS**
    - リージョン：東京
    - アベイラビリティゾーン：ap-northeast-1a
- **RHEL AI**
    - バージョン：1.4
    - 利用するEC2インスタンスタイプ：[p4d.24xlarge](https://aws.amazon.com/jp/ec2/instance-types/p4/)

## 作業ディレクトリの準備
今回は作業端末のホームディレクトリ配下に`rhelai`というディレクトリを作成しました。作業端末内で作成する必要があるファイル一式は、すべてこのディレクトリに作ることとします。また、`~/rhelai`内にTerraform関連のファイルを置くための`terraform`というディレクトリを作成しました。

```sh
username@local-machine ~ % mkdir -p rhelai/terraform && cd rhelai
```

## なにはともあれRHEL AIのOSイメージをダウンロード
後ほど使うRHEL AIのOSイメージですが、約47GBほどあり、ダウンロード時間が非常に長くかかることが想定されます。この記事を読んで色々設定する時間を有効活用するためにも、あらかじめダウンロードしておきましょう。

まずは[RHEL AIのOSイメージダウンロードサイト](https://access.redhat.com/downloads/content/932/ver=1.4/rhel---9/1.4/x86_64/product-software)にアクセスします。今回はAWS環境でRHEL AIを起動するので、ファイル名に**aws**と入っているRAWファイル（拡張子は`.raw`）を`~/rhelai`にダウンロードしてください。

![スクリーンショット 2025-03-04 21.47.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/70ab8416-ff2b-4abf-9e09-a56a1ed4e650.png)

## Resource Quota引き上げ申請
今回使う予定のインスタンスタイプ「p4d.24xlarge」は事前にリソースクォータ引き上げの申請が必要です。そのため、以下のURLから引き上げ申請しておきます。

http://aws.amazon.com/contact-us/ec2-request

リクエスト内容にはこんな感じで入れておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/d2cb9f12-286d-48e2-b5c2-f309edbe42e3.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/ee8eadc0-56b8-444d-89c5-28c52671729a.png)

右下の「送信」を押して、リソースクォータ上限申請が受領されるまで待ちましょう。待つ間にAWS環境の構築を進めます。

## AWS環境の構築
今回はRHEL AI用のインスタンス及び踏み台サーバを用意し、以下のような構成で環境を構築します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/1fc00f4b-bcae-4506-a4ad-acc1d7689840.png)


この構成は、よくある踏み台サーバ経由のアクセス構成です。RHEL AIインスタンスには直接作業環境やその他ネットワークからアクセスできず、必ず踏み台サーバを経由する必要があります。これによりRHEL AIインスタンスへのアクセスのセキュリティを確保します。また、RHEL AIがインターネット上からモデルやコードをダウンロードするためのNATゲートウェイを設けています。なお、NATゲートウェイにはElasteic IPが関連づけられています。

今回はRHEL AIインスタンス以外のリソースはTerraformでデプロイします。必要に応じてリージョンやAZは変更して構いません。

「GUIで構築したいよ！」という方は、[こうしたサイト](https://nishinatoshiharu.com/private-ec2-setting/)を参考に構築していただければ幸いです。

## 踏み台サーバ用のキーペアの作成とダウンロード
Terraformの実行前に、事前に踏み台サーバ用のキーペア「bastion-key」を作成しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/c0dbd8f0-3ad1-4826-a62e-8e1966e12d55.png)

`bastion-key.pem`は`~/rhelai/terraform`内にダウンロードしておきましょう。

## terraformファイルの作成と実行
`~/rhelai/terraform`に移動し、お好きなエディタを用いて以下に示すterraformファイル「aws-vpc-setup.tf」を作成します。

```sh
username@local-machine rhelai % cd terraform
```

```aws-vpc-setup.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1" # 東京リージョン
}

resource "aws_vpc" "rhelai_vpc" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "rhelai-vpc"
  }
}

resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.rhelai_vpc.id

  tags = {
    Name = "rhelai-igw"
  }
}

resource "aws_subnet" "subnet_public" {
  vpc_id                  = aws_vpc.rhelai_vpc.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "ap-northeast-1a"
  map_public_ip_on_launch = true

  tags = {
    Name = "rhelai-subnet-public"
  }
}

resource "aws_subnet" "subnet_private" {
  vpc_id            = aws_vpc.rhelai_vpc.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = "ap-northeast-1a"

  tags = {
    Name = "rhelai-subnet-private"
  }
}

resource "aws_eip" "nat_eip" {
  domain = "vpc"

  tags = {
    Name = "rhelai-nat-eip"
  }
}

resource "aws_nat_gateway" "nat" {
  allocation_id = aws_eip.nat_eip.id
  subnet_id     = aws_subnet.subnet_public.id

  tags = {
    Name = "rhelai-natgw"
  }
}

resource "aws_route_table" "rt_public" {
  vpc_id = aws_vpc.rhelai_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.igw.id
  }

  tags = {
    Name = "rhelai-rt-public"
  }
}

resource "aws_route_table_association" "public_assoc" {
  subnet_id      = aws_subnet.subnet_public.id
  route_table_id = aws_route_table.rt_public.id
}

resource "aws_route_table" "rt_private" {
  vpc_id = aws_vpc.rhelai_vpc.id

  route {
    cidr_block     = "0.0.0.0/0"
    nat_gateway_id = aws_nat_gateway.nat.id
  }

  tags = {
    Name = "rhelai-rt-private"
  }
}

resource "aws_route_table_association" "private_assoc" {
  subnet_id      = aws_subnet.subnet_private.id
  route_table_id = aws_route_table.rt_private.id
}

resource "aws_security_group" "bastion_sg" {
  name        = "bastion-sgr"
  description = "Allow SSH from anywhere"
  vpc_id      = aws_vpc.rhelai_vpc.id

  ingress {
    description = "SSH from anywhere"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = { Name = "bastion-sgr" }
}

resource "aws_security_group" "rhelai_sg" {
  name        = "rhelai-sgr"
  description = "Allow SSH only from bastion"
  vpc_id      = aws_vpc.rhelai_vpc.id

  ingress {
    description     = "SSH from bastion only"
    from_port       = 22
    to_port         = 22
    protocol        = "tcp"
    security_groups = [aws_security_group.bastion_sg.id]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = { Name = "rhelai-sgr" }
}

resource "aws_instance" "bastion" {
  ami                    = data.aws_ami.rhel9.id
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.subnet_public.id
  vpc_security_group_ids = [aws_security_group.bastion_sg.id]
  key_name               = "bastion-key"

  tags = { Name = "bastion" }
}

data "aws_ami" "rhel9" {
  most_recent = true
  owners      = ["309956199498"] # AWS公式RHEL

  filter {
    name   = "name"
    values = ["RHEL-9.*x86_64*"]
  }
}

```

ファイルを作成したら、`terraform`コマンドを実行（途中で`yes`を入力してください）、リソースを作成しましょう。

```sh
username@local-machine terraform % terraform plan
username@local-machine terraform % terraform apply
```

リソースが作成されるまでしばし待ちます。

## RHEL AIインスタンス用のキーペア作成と踏み台サーバのセットアップ
さて、リソース作成が終わったら、RHEL AIインスタンスにアクセスするためのキーペア「rhelai-key」を作成しましょう。そして、これを踏み台サーバに転送しておきます。`rhelai-key.pem`が`~/rhelai`内にダウンロードされている状態を前提に、以下のコマンドを実行します。

```sh
## ~/rhalaiに作業ディレクトリを移動します
username@local-machine terraform % cd ..

## 踏み台サーバ用のキーペアの権限を読み取り専用に変更しておきます
username@local-machine rhelai % chmod 400 ./terraform/bastion-key.pem

## rhelai-key.pemを踏み台サーバに転送します
username@local-machine rhelai % scp -i ./terraform/bastion-key.pem rhelai-key.pem  ec2-user@<ご自身の踏み台サーバのパブリック IPv4 DNS>:~/
rhelai-key.pem                 　　　　　　　　　　　　 100% 1674   100.8KB/s   00:00
```

無事に`rhelai-key.pem`が転送できたか、踏み台サーバにSSHして確認しましょう。

```sh
username@local-machine rhelai % ssh -i ./terraform/bastion-key.pem ec2-user@<ご自身の踏み台サーバのパブリック IPv4 DNS>
```

SSH接続できたら、踏み台サーバ内で以下のコマンドを実行しておきます。

```sh
## rhelai-key.pemがあるか確認
[ec2-user@<踏み台サーバのIPアドレス> ~]$ ls
rhelai-key.pem

## 先ほどと同様に読み取り専用に変更しておきます
[ec2-user@<踏み台サーバのIPアドレス> ~]$ chmod 400 rhelai-key.pem
```

お疲れ様でした！これでRHEL AIインスタンスを起動するための事前準備が完了しました！

# RHEL AIの構築
それではさっそくRHEL AIを触れるようにしていきましょう！とはいえ、作業は以下の通り、[公式ドキュメント - Chapter 3. Installing RHEL AI on AWS](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux_ai/1.4/html/installing/installing_on_aws#converting_image_to_ami)を参考にコマンドをポチポチやっていくだけです。

## Converting the RHEL AI image to an AWS AMI
以下の様な流れで、ダウンロード済みのRHEL AIのディスクイメージをAmazon マシンイメージ (AMI) に変換していきます。
1. S3バケットを作成する
1. バケットにRHEL AIディスクイメージをアップロードする
1. S3バケットの内容を元にAMI（スナップショット）を作る

以下の作業は全て作業端末の`~/rhelai`にて実施します。

### 各種の環境変数を設定
```sh
export BUCKET=<custom_bucket_name>
export RAW_AMI=nvidia-bootc.ami
export AMI_NAME="rhel-ai"
export DEFAULT_VOLUME_SIZE=1000
```

:::note warn
`<custom_bucket_name>`はグローバルユニークな名称にする必要があります。なんらかお好きな名前を設定してください。
:::

### S3バケット作成
```sh
aws s3 mb s3://$BUCKET
```

### 信頼ポリシーの作成
```sh
printf '{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "vmie.amazonaws.com" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals":{ "sts:Externalid": "vmimport" } } } ] }' > trust-policy.json
```
`trust-policy.json` は AWS IAM ロールの信頼ポリシー (Trust Policy) を定義するJSONファイルです。このファイルを使用して、特定の AWS サービスやユーザーが、その IAM ロールを引き受け (assume) できるように設定します。

### IAM Role及びロールポリシーの作成
```sh
aws iam create-role --role-name vmimport --assume-role-policy-document file://trust-policy.json
```
```sh
printf '{ "Version":"2012-10-17", "Statement":[ { "Effect":"Allow", "Action":[ "s3:GetBucketLocation", "s3:GetObject", "s3:ListBucket" ], "Resource":[ "arn:aws:s3:::%s", "arn:aws:s3:::%s/*" ] }, { "Effect":"Allow", "Action":[ "ec2:ModifySnapshotAttribute", "ec2:CopySnapshot", "ec2:RegisterImage", "ec2:Describe*" ], "Resource":"*" } ] }' $BUCKET $BUCKET > role-policy.json
```

`role-policy.json` は IAM ロールにアタッチする権限ポリシー (Role Policy) を定義する JSON ファイルです。IAM Trust Policy (`trust-policy.json`) が “誰が” ロールを引き受けることができるかを定義するのに対し、Role Policy (`role-policy.json`) は “そのロールが何を実行できるか” を定義します。

### バケットにポリシーを付与

```sh
aws iam put-role-policy --role-name vmimport --policy-name vmimport-$BUCKET --policy-document file://role-policy.json
```

ここまでで、必要なS3バケットの作成と設定が完了します。`ls`コマンドを打って、以下の様に必要なファイルたちが用意されているか確認しておきましょう。

```sh
ls
rhelai-key.pem					terraform
rhel-ai-nvidia-aws-1.4-1739122616-x86_64.raw	role-policy.json				trust-policy.json
```

こんな感じならばOKです。

### ディスクイメージをアップロード
以下のコマンドで、事前にダウンロードしておいたRHEL AIのディスクイメージをS3バケットにアップロードします。
```sh
aws s3 cp rhel-ai-nvidia-aws-1.4-1739122616-x86_64.raw s3://$BUCKET/$RAW_AMI
```
:::note warn
47GBのファイルをアップロードする都合、場合によっては数時間かかりますので、ご飯を食べたり寝たりして、しばし待ちます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/149eb4aa-e046-4209-ae8c-4aef032bbf06.png)

:::

### AMIの作成
ディスクイメージがアップロードし終わったら、以下の通りコマンドを実行していきます。
```sh
printf '{ "Description": "my-image", "Format": "raw", "UserBucket": { "S3Bucket": "%s", "S3Key": "%s" } }' $BUCKET $RAW_AMI > containers.json
```

```sh
task_id=$(aws ec2 import-snapshot --disk-container file://containers.json | jq -r .ImportTaskId)
```
これらのコマンドでは、S3バケットにアップロードしておいたディスクイメージ（RAWファイル）の情報を`containers.json`というファイルに記載します。その内容に従ってディスクイメージをEC2スナップショットとしてインポートします。そのインポートタスクID（`task_id`）を取得しています。

インポートタスクが完了すると、AWSマネジメントコンソールで作成されたスナップショットが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/c35723c1-af22-41c4-9d24-1c8bd7cd036b.png)

### スナップショットの設定
以下のコマンドにて、スナップショットにタグつけ等の設定を行っていきます。
```sh
snapshot_id=$(aws ec2 describe-import-snapshot-tasks | jq -r '.ImportSnapshotTasks[] | select(.ImportTaskId=="'${task_id}'") | .SnapshotTaskDetail.SnapshotId')
```

```sh
aws ec2 create-tags --resources $snapshot_id --tags Key=Name,Value="$AMI_NAME"
```

### スナップショットからAMIを作成しタグを設定
```sh
ami_id=$(aws ec2 register-image  \
    --name "$AMI_NAME" \
    --description "$AMI_NAME" \
    --architecture x86_64 \
    --root-device-name /dev/sda1 \
    --block-device-mappings "DeviceName=/dev/sda1,Ebs={VolumeSize=${DEFAULT_VOLUME_SIZE},SnapshotId=${snapshot_id}}" \
    --virtualization-type hvm \
    --ena-support \
    | jq -r .ImageId)
```

```sh
aws ec2 create-tags --resources $ami_id --tags Key=Name,Value="$AMI_NAME"
```

お疲れ様でした。ここまででRHEL AIインスタンスを起動するためのAMIの準備が完了しました。

## Deploying your instance on AWS using the CLI
ようやくRHEL AIインスタンスの起動です。まず、RHEL AIインスタンスを建てるために必要な情報を確認しておきます。必要な情報は以下です。
### AMI ID
先程作成したAMIの識別子です。AWSマネジメントコンソールで確認可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/06684a5e-5d3b-4dd2-86a1-aa83ea3c1f4d.png)

### セキュリティグループID
RHEL AIインスタンスを参加させるセキュリティグループ（**Security Group #2**）のIDです。事前に作成しておいたものを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/1a6b7f84-cfb8-487f-aef9-add3d20e6b07.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/33983178-b168-4395-bd46-0d866863399e.png)


### サブネットID
RHEL AIを参加させるプライベートサブネットのIDを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/f9e0119e-6b00-4172-af49-16c35cc37741.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/b132e055-a850-4891-944d-440315b21dcb.png)

それぞれ必要なパラメータが確認できたら、環境変数として設定します。

### 環境変数を設定

```
instance_name=rhel-ai-instance
ami=<AMI ID>
instance_type=p4d.24xlarge
key_name=rhelai
security_group=<セキュリティグループID>
subnet=<サブネットID>
disk_size=3072
```

:::note
RHEL AIの[推奨ディスクサイズ](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux_ai/1.4/html/getting_started/hardware_requirements_rhelai#amazon-web-services-aws)が「3TB」となっているので、`disk_size`は3072GB（=3TB）とします。
:::

### インスタンスの起動
以下のコマンドでインスタンスを起動しましょう！
```sh
aws ec2 run-instances \
    --image-id $ami \
    --instance-type $instance_type \
    --key-name $key_name \
    --security-group-ids $security_group \
    --subnet-id $subnet \
    --block-device-mappings DeviceName=/dev/sda1,Ebs='{VolumeSize='$disk_size'}' \
    --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value='$instance_name'}]'
```

お疲れ様でした。起動完了までしばらく待ちます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/15d8686d-e1b1-44ac-808a-a4b0fe20dbbf.png)

起動完了を確認できたら、次に進みましょう。

# RHEL AIの初期設定
それではRHEL AIが利用できるように環境設定していきます。

## RHEL AIインスタンスにログイン
踏み台サーバから以下のコマンドでRHEL AIにログインしてください。

```sh
ssh -i rhelai-key.pem cloud-user@<RHEL AIインスタンスのプライベートIPアドレス>
```

:::note warn
RHEL AIの初期ユーザは`cloud-user`です。`ec2-user`では認証に失敗するので注意です。
:::

## Red Hat Subscription Manager登録
以下のコマンドでRHSM登録します。登録しないと`ilab`コマンドが使えませんので、必ず登録してください。

```sh
sudo rhc connect --organization <ORG_ID> --activation-key <ACTIVATION_KEY>
```

:::note 
|パラメータ|内容|
|---|---|
|`<ORG_ID>`|Red Hat Accountが所属する組織のID|
|`<ACTIVATION_KEY>`|RHELのサブスクリプションを有効化するために作成するキー|

どちらの内容についても、[ハイブリッドクラウドコンソールのアクティベーションキー作成画面](https://console.redhat.com/insights/connector/activation-keys) から確認できます。

![スクリーンショット 2025-02-22 1.26.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/5e909a4a-9022-4c09-a74b-4bf1cc5b7f96.png)

アクティベーションキーを作成したら、その名称を`<ACTIVATION_KEY>`に入れてください。
:::

## InstructLab環境の初期化
以下のコマンドでInstructLab実行環境を初期化し、セットアップします。

```sh
ilab config init
```

:::note 
もしインスタンスのGPU環境を自動認識しない場合は、**[9] NVIDIA A100 X8**を手動で設定してあげます。

```sh
ilab config init

----------------------------------------------------
         Welcome to the InstructLab CLI
  This guide will help you to setup your environment
----------------------------------------------------
...
First, please select the hardware vendor your system falls into
[0] NO SYSTEM PROFILE
[1] NVIDIA
Enter the number of your choice [0]: 1 ##NVIDIAを選択してください
You selected: NVIDIA
Next, please select the specific hardware configuration that most closely matches your system.
[0] NO SYSTEM PROFILE
[1] NVIDIA L4 X8
[2] NVIDIA L40S X4
[3] NVIDIA L40S X8
[4] NVIDIA H100 X4
[5] NVIDIA H100 X2
[6] NVIDIA H100 X8
[7] NVIDIA A100 X4
[8] NVIDIA A100 X2
[9] NVIDIA A100 X8 ##p4d.24xlargeはこちらです
Enter the number of your choice [hit enter for hardware defaults] [0]: 9
...
--------------------------------------------
    Initialization completed successfully!
  You're ready to start using `ilab`. Enjoy!
--------------------------------------------
```
:::

## Red Hatのモデルレジストリにログインしておく
この後LLMをダウンロードするのですが、ダウンロード元であるレッドハットのレジストリ（`registry.redhat.io`）にログイン（`skopeo login`）しておく必要があります。

```sh
skopeo login registry.redhat.io
Username: <ご自身のRed Hatアカウントのユーザ名>       
Password: <ご自身のRed Hatアカウントのパスワード>
Login Succeeded!
```

:::note 
実はモデルのダウンロード`ilab model download`コマンドは裏で`skopeo`コマンドを叩いてイメージのコピーを行っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/8caca8a9-829f-4881-98e3-ac057e8d6532.png)

「Skopeo」はレジストリ間のイメージコピーツールで、Red Hatが主導して開発しているOSSです。詳細は[こちら](https://www.redhat.com/ja/topics/containers/what-is-skopeo)。なお、「Skopeo」とはギリシャ語で「見る、調べる、検討する）」という意味だそうです。
:::

おめでとうございます！これでRHEL AIのセットアップは完了です。

# モデルをダウンロードし推論を実行
さっそくモデルをダウンロードして推論させてみましょう。

## ダウンロード可能なモデル一覧
RHEL AIでは複数のモデルが用意されていますが、それらには以下の種類が存在します。
|種類|用途|詳細|具体的なモデル|
|---|---|---|---|
|Base Model|カスタマイズ|InstructLabによるカスタマイズ対象の生徒モデル。IBM＆Red HatによってApache 2.0ライセンで提供されるGranite基盤モデル。パラメータは軽量（7b〜8b程度）だが、最低限の一般教養は有している。|`granite-7b-starter`<br>`granite-8b-starter-v1`<br>`granite-3.1-8b-starter-v1`|
|LAB fine-tuned Granite model|推論|チャット用途に特化させてFT済みの推論特化モデル。|`granite-7b-redhat-lab`<br>`granite-8b-lab-v1`<br>`granite-3.1-8b-lab-v1`|
|Granite fine-tuned code model|推論|コード生成に特化させてFT済みの推論特化モデル。|`granite-8b-code-instruct`<br>`granite-8b-code-base`
|Teacher/critic model|カスタマイズ|合成データ生成（SDG）を行う主体。SDの生成・評価を行う。mixtralベースのモデル。|`mixtral-8x7b-instruct-v0-1`|
|Evaluation judge model|カスタマイズ|トレーニング結果の評価を行うモデル。Prometheusベースのモデル。|`prometheus-8x7b-v2-0`|
|LoRA Adapter|カスタマイズ|SDGの際に利用できるLoRA（Low Rank Adaptation）知識・スキル毎アダプタ|`skills-adapter-v3 `<br>`knowledge-adapter-v3`|

::: note warn
RHEL AI 1.4でダウンロード可能なモデル一覧およびGA状況は[公式ドキュメント - Downloading Large Language models](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux_ai/1.4/html-single/building_and_maintaining_your_rhel_ai_environment/index#download_models)をチェックしてください。
:::

## モデルをダウンロード
以下のコマンドで、Granite 3ベースの生徒モデル `granite-8b-starter-v1`をダウンロードしてみましょう。こいつは生徒モデルとしてカスタマイズ対象となるモデルです。とはいえ、最低限のビジネス文脈の知識は有しています。

```sh
ilab model download --repository docker://registry.redhat.io/rhelai1/granite-8b-starter-v1 --release latest
```

ダウンロードが終わると自動的にモデルリストが表示されると思いますが、もし手動でモデルリストを確認したい場合は、`ilab model list`で確認できます。

```sh
ilab model list
+-----------------------------------+---------------------+---------+
| Model Name                        | Last Modified       | Size    |
+-----------------------------------+---------------------+---------+
| models/granite-8b-starter-v1  | 2025-03-07 06:56:36 | 15.2 GB |
+-----------------------------------+---------------------+---------+
```

こんなに簡単にLLMをダウンロードできました！ダウンロードされたモデルは`~/.cache/instructlab/models/`に保存されます。

## モデルをサーブする
次は、ダウンロードしたモデルを推論可能な状態にします。これを「モデルをサーブする」と言います。以下のコマンドで、ダウンロードしたモデルのパスを指定し、モデルをサーブしましょう。

```sh
ilab model serve --model-path ~/.cache/instructlab/models/granite-8b-starter-v1
```

サーブコマンド`ilab model serve`を実行すると、モデルデータをメモリに読み込み、vLLMのログが出力されます。APIエンドポイントが払い出されるまで少し待ちましょう。

```sh
ilab model serve --model-path ~/.cache/instructlab/models/granite-8b-starter-v1
...
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO 03-07 08:31:46 metrics.py:449] Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 0.0 tokens/s, Running: 0 reqs, Swapped: 0 reqs, Pending: 0 reqs, GPU KV cache usage: 0.0%, CPU KV cache usage: 0.0%.
...
```

出力されたログから、RHEL AIのローカルループバックアドレス（`localhost`）の8000番ポートで推論エンドポイントが提供されていることが分かります。

## モデルとチャットする
`ilab model serve`を実行すると、フォアグラウンドでログが出力されますので、モデルとのチャットは別のターミナルウィンドウから行います。そちらもRHEL AIにSSHで接続しておいてください。

以下のコマンドでモデルとチャットするモードに切り替えます。
```sh
ilab model chat --model ~/.cache/instructlab/models/granite-8b-starter-v1
```

コマンドが実行されると、ターミナルでチャットウィンドウが開きます。
```sh
ilab model chat --model ~/.cache/instructlab/models/granite-8b-starter-v1
╭───────────────────────────────────────────────────────────────────── system ─────────────────────────────────────────────────────────────────────╮
│ Welcome to InstructLab Chat w/ GRANITE-8B-STARTER-V1 (type /h for help)                                                                      │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
>>>                                                                                                                                     [S][default]
```

何か会話してみましょう。試しに金利と債権価格の関係ついて聞いてみます。

```sh
## 金利と債権価格の関係について簡潔におしえてくれますか？
>>> Can you tell me about the relationship between interest rate and bond price in shortly?                           [S][default]
╭──────────────────────────────────────────────────── granite-8b-starter-v1 ─────────────────────────────────────────────────────╮
│ Sure, I'd be happy to explain the relationship between interest rate and bond price!                                           │
│                                                                                                                                │
│ A bond is a type of investment that allows an entity (like a government or a company) to borrow money from investors. In       │
│ exchange for the loan, the entity agrees to pay the investors a certain amount of interest (the "coupon rate") over a          │
│ specified period (the "term"). At the end of the term, the entity also agrees to pay back the initial amount borrowed (the     │
│ "face value").                                                                                                                 │
│                                                                                                                                │
│ The relationship between interest rate and bond price is known as an inverse relationship. This means that when interest rates │
│ rise, bond prices fall, and when interest rates fall, bond prices rise.                                                        │
│                                                                                                                                │
│ To understand why this is the case, let's think about what happens when interest rates rise. When interest rates rise, new     │
│ bonds with higher coupon rates become available. Investors who already own bonds with lower coupon rates may not want to hold  │
│ onto them, because they can now get a better deal by buying new bonds. As a result, these investors may sell their old bonds   │
│ on the market, which can drive down the price of those bonds.                                                                  │
│                                                                                                                                │
│ On the other hand, when interest rates fall, new bonds with lower coupon rates become available. Investors who already own     │
│ bonds with higher coupon rates may be willing to hold onto them, because they are still getting a good deal compared to the    │
│ new bonds that are available. As a result, these investors may not sell their old bonds on the market, which can drive up the  │
│ price of those bonds.                                                                                                          │
│                                                                                                                                │
│ Another way to think about the relationship between interest rate and bond price is to consider the present value of a bond.   │
│ The present value of a bond is the amount of money that an investor would need to invest today in order to receive a stream of │
│ future cash flows (the interest payments and the face value) that is equivalent to the bond's cash flows.                      │
│                                                                                                                                │
│ When interest rates rise, the present value of a bond decreases, because the investor can earn a higher return by investing in │
│ other assets. When interest rates fall, the present value of a bond increases, because the investor can earn a lower return by │
│ investing in other assets.                                                                                                     │
│                                                                                                                                │
│ In summary, the relationship between interest rate and bond price is an inverse one. When interest rates rise, bond prices     │
│ fall, and when interest rates fall, bond prices rise. This is because when interest rates rise, new bonds with higher coupon   │
│ rates become available, which can make older bonds with lower coupon rates less attractive to investors. Conversely, when      │
│ interest rates fall, new bonds with lower coupon rates become available, which can make older bonds with higher coupon rates   │
│ more attractive to investors.                                                                                                  │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────── elapsed 3.599 seconds ─╯                                     
```

英語で聞いたので英語で回答が出力されました。Google翻訳で和訳した結果は以下です。

:::note
RHEL AIは日本語のプロンプトに対応はしているものの、まだまだ成長途中です。暖かく見守ってあげてください。
:::

>はい、金利と債券価格の関係を喜んでご説明いたします。
>
>債券は、政府や企業などの組織が投資家から資金を借り入れることを可能にする投資の一種です。融資と引き換えに、組織は投資家に一定期間（「期間」）にわたって一定の利子（「クーポン レート」）を支払うことに同意します。期間の終了時に、組織は当初借り入れた金額（「額面」）を返済することにも同意します。
>
>金利と債券価格の関係は、逆相関として知られています。つまり、金利が上昇すると債券価格は下がり、金利が下がると債券価格は上がります。
>
>なぜそうなるのかを理解するために、金利が上昇すると何が起こるかを考えてみましょう。金利が上昇すると、より高いクーポン レートの新しい債券が利用可能になります。すでにより低いクーポン レートの債券を所有している投資家は、新しい債券を購入することでより有利な条件を得ることができるため、その債券を保持したくないかもしれません。その結果、これらの投資家は古い債券を市場で売却する可能性があり、その債券の価格が下がる可能性があります。
>
>一方、金利が下がると、より低いクーポン レートの新しい債券が利用可能になります。より高いクーポン レートの債券をすでに所有している投資家は、利用可能な新しい債券と比較してまだお得なので、それらを保持しようとする可能性があります。その結果、これらの投資家は古い債券を市場で売却しない可能性があり、その債券の価格が上がる可能性があります。
>
>金利と債券価格の関係について考える別の方法は、債券の現在価値を考慮することです。債券の現在価値とは、債券のキャッシュ フローに相当する将来のキャッシュ フロー (利払いと額面価格) の流れを受け取るために投資家が今日投資する必要がある金額です。
>
>金利が上昇すると、債券の現在価値は減少します。これは、投資家が他の資産に投資することでより高い収益を得ることができるためです。金利が下がると、債券の現在価値は上がります。これは、投資家が他の資産に投資することで、より低い収益を得ることができるためです。
>
>要約すると、金利と債券価格の関係は逆の関係です。金利が上がると債券価格は下がり、金利が下がると債券価格は上がります。これは、金利が上がると、より高いクーポン レートの新しい債券が利用可能になり、より低いクーポン レートの古い債券が投資家にとって魅力的でなくなる可能性があるためです。逆に、金利が下がると、より低いクーポン レートの新しい債券が利用可能になり、より高いクーポン レートの古い債券が投資家にとって魅力的になる場合があります。

いいですね。金利の上下と債権価格の上下が逆の関係にあることを簡潔かつわかりやすく解説できており、妥当な回答だと思います。次は"テーパリング"について聞いてみましょう。

```sh
## テーパリングとはなんですか？
>>> What is tapering?                                                                                                 [S][default]
╭──────────────────────────────────────────────────── granite-8b-starter-v1 ─────────────────────────────────────────────────────╮
│ Tapering refers to the gradual reduction of a medication's dosage over a period of time, rather than stopping abruptly. This   │
│ approach is often used when a person has been taking a medication for an extended period and needs to discontinue or reduce    │
│ the dose to avoid adverse side effects or health risks.                                                                        │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────── elapsed 0.453 seconds ─╯
```

ほう。医療分野における回答が帰ってきました。内容を和訳してみると以下です。

>漸減とは、突然薬を中止するのではなく、一定期間にわたって徐々に薬の投与量を減らすことを指します。この方法は、長期間薬を服用していて、副作用や健康リスクを避けるために服用を中止したり、投与量を減らしたりする必要がある場合によく使用されます。

Taperingの直訳は「先細り」あるいは「漸減」ですが、一般的には`granite-8b-starter-v1`が回答しているように、医療分野において「徐々に投薬料を減らす治療方針」が該当します。しかし、実は私が意図した回答は違っています。

こんな質問をしてみます。

```sh
## 金融政策の文脈ではどうでしょうか？
>>> How about in context of monetary policy?                                                                          [S][default]
╭──────────────────────────────────────────────────── granite-8b-starter-v1 ─────────────────────────────────────────────────────╮
│ Tapering is a strategy employed in monetary policy by central banks to gradually reduce their purchases of financial assets,   │
│ such as government bonds. This approach is typically implemented after a period of quantitative easing, during which the       │
│ central bank has been actively buying securities to inject money into the economy.                                             │
│                                                                                                                                │
│ The primary objective of tapering is to normalize monetary policy without causing sudden market disruptions. By gradually      │
│ reducing the pace of asset purchases, the central bank can signal its intention to improve economic conditions and allow       │
│ financial market participants to adjust their strategies accordingly.                                                          │
│                                                                                                                                │
│ It is important to note that tapering does not necessarily mean an increase in interest rates. Instead, it is a transition     │
│ phase in monetary policy, aiming to maintain a balance between supporting economic growth and managing inflationary pressures. │
│                                                                                                                                │
│ In summary, tapering is a strategic approach in monetary policy where a central bank gradually reduces its purchases of        │
│ financial assets, typically after a period of quantitative easing, to normalize monetary conditions and allow market           │
│ participants to adjust their strategies.                                                                                       │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────── elapsed 1.404 seconds ─╯
```
>テーパリングとは、中央銀行が国債などの金融資産の購入を徐々に減らすために金融政策で採用している戦略です。このアプローチは通常、中央銀行が経済に資金を注入するために証券を積極的に購入していた量的緩和期間の後に実施されます。
>
>テーパリングの主な目的は、突然の市場の混乱を引き起こすことなく金融政策を正常化することです。資産購入のペースを徐々に減らすことで、中央銀行は経済状況を改善する意図を示し、金融市場参加者がそれに応じて戦略を調整できるようにします。
>
>テーパリングは必ずしも金利の上昇を意味するわけではないことに注意することが重要です。むしろ、経済成長の支援とインフレ圧力の管理のバランスを維持することを目的とした金融政策の移行段階です。
>
>要約すると、テーパリングは金融政策における戦略的アプローチであり、通常は量的緩和期間の後に中央銀行が金融資産の購入を徐々に減らして金融状況を正常化し、市場参加者が戦略を調整できるようにします。

ほ〜。すばらしいですね。まさに欲しかった回答でした。Graniteは8 Billion（80億）パラメータの比較的小規模な言語モデルですが、金融をはじめとしたビジネス分野に絞って事前学習を実施しているとされており、そういった観点では十分な推論性能と正確性を期待することができます。

:::note
[ビジネスのためのAIを構築： IBMの基盤モデル「Granite」](https://jp.newsroom.ibm.com/2023-09-12-Blog-Building-AI-for-business-IBM-Granite-foundation-models)
:::



では最後は「iPhone 16 Pro」について聞いてみましょう。

```sh
## 私たちはいつからiPhone 16 Proを購入できますか？
>>> When can we buy the iPhone 16 Pro?                                                                                     [S][default]
╭─────────────────────────────────────────────────────── granite-8b-starter-v1 ───────────────────────────────────────────────────────╮
│ As of now, Apple has not officially announced the release date for the iPhone 16 Pro. However, based on past trends, we can expect  │
│ the new iPhone to be released in the fall of the year following its announcement. Therefore, the iPhone 16 Pro is likely to be      │
│ available for purchase in the fall of 2023. Please note that this is an estimate and the actual release date may be subject to      │
│ change.                                                                                                                             │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────── elapsed 0.597 seconds ─╯
```

回答の和訳結果は以下のとおりです。
>現時点では、AppleはiPhone 16 Proの発売日を公式に発表していません。しかし、過去の傾向からすると、新型iPhoneは発表された翌年の秋に発売されると予想されます。そのため、iPhone 16 Proは2023年秋に購入可能になる可能性が高いです。これは推定であり、実際の発売日は変更される可能性があることに注意してください。

おっと、iPhone 16 Proの発売日の情報は持っていないそうです。それもそのはず、`granite-8b-starter-v1`が事前学習を実施された時期には、おそらくまだiPhone 16シリーズが発表すらされていないタイミングだからです。


# モデルのカスタマイズに挑戦
さて、RHEL AIの醍醐味は、誰でも簡単にモデルカスタマイズを実行できることです。カスタマイズによって追加可能なのは「スキル」と「知識」です。

スキルとは「翻訳する」や「文章を要約する」といったことを指します。今回は簡単にモデルカスタマイズを行うため、「知識」のみを追加します。今はRHEL AIが持っていない知識を新たに追加し、回答できる内容を増やします。

今回は簡単に知識追加の効果を見るため、RHEL AIが知らない内容（iPhoen16 Proの詳細）を追加してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/c9ab3d2e-ebbf-410b-b581-de35fbf2be4a.png)
出典：https://www.apple.com/jp-edu/shop/buy-iphone/iphone-16-pro

## 固有知識ファイルを作成
さっそくiPhone 16 Proについての知識ファイルを作成し、`granite-8b-starter-v1`に学習させてみましょう。「固有知識ファイル」は`qna.yaml`という名称で作成したファイルにて定義します。このファイルの定義は[公式ドキュメント](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux_ai/1.4/html-single/creating_skills_and_knowledge_yaml_files/index#knowledge_yaml_example)に記載の通りなのですが、ざっくり言うと、以下のような構成で作成する必要があります。
- とある知識について、5つ以上の**Context**（文脈）を定義する
- それぞれの**Context**を文章で書く。ただし、500token以内に収める必要がある
- 各**Context**ごとに最低3つの**Qestion & Answer**セットを文章で書く
- それぞれの**Question**は、必ず**Context**の文章を読めば回答できる**Answer**である必要がある

私が今回[iPhone 16 ProのWikipedia](https://ja.wikipedia.org/wiki/IPhone_16_Pro)を見ながら作成してみたqan.yamlを示します。

```yaml
version: 3
domain: Technology
document_outline: |
  The Information about the iPhone 16 Pro series including the hardware spec, camera features, chipset espec and color lineup.
created_by: Masaki Oomura
seed_examples:
  - context: |
      The iPhone 16 Pro and iPhone 16 Pro Max are smartphones developed and marketed by Apple Inc.
      Alongside the iPhone 16 and iPhone 16 Plus, they form the eighteenth generation of the iPhone,
      succeeding the iPhone 15 Pro and iPhone 15 Pro Max, and were announced on September 9, 2024,
      and released on September 20, 2024. The iPhone 16 Pro and iPhone 16 Pro Max include a larger
      6.3-inch and 6.9-inch display, a faster processor, upgraded wide and ultra-wide cameras,
      support for Wi-Fi 7, larger batteries, and come pre-installed with iOS 18 (operating system).
    questions_and_answers:
      - question: |
          What generation of iPhone is the iPhone 16 Pro?
        answer: |
          The iPhone 16 Pro is the 18th generation iPhone.
      - question: |
          When was the iPhone 16 Pro announced?
        answer: |
          The iPhone 16 Pro was announced on September 9, 2024.
      - question: |
          When was the iPhone 16 Pro released?
        answer: |
          The iPhone 16 Pro was released on September 20, 2024.
      - question: |
          What is the display size of the iPhone 16 Pro?
        answer: |
          The display size of the iPhone 16 Pro is 6.3 inches.
      - question: |
          What OS is pre-installed on the iPhone 16 Pro?
        answer: |
          The OS pre-installed on the iPhone 16 Pro is iOS 18.
      - question: |
          What Wi-Fi standard does the iPhone 16 Pro support?
        answer: |
          The Wi-Fi standard supported by the iPhone 16 Pro is Wi-Fi 7.
  - context: |
      The iPhone 16 Pro models continue the edge-to-edge display design but
      introduce thinner display borders, giving them the thinnest borders of
      any Apple product to date; iPhone 16 Pro and iPhone 16 Pro Max feature
      larger 6.3-inch and 6.9-inch Super Retina XDR OLED displays, respectively,
      with iPhone 16 Pro Max offering the largest iPhone display ever.
      Both models have always-on 13:6 aspect ratio displays,
      with 460 ppi density from a 2622 × 1206 (Pro) and 2868 × 1320 (Pro Max) resolution.
      Both are 120 Hz, HDR10, with 1000 nits brightness typical and 2000 nits at peak.
    questions_and_answers:
      - question: |
          What does the iPhone 16 Pro display have?
        answer: |
          The iPhone 16 Pro display has the thinnest borders ever on an Apple product and features a Super Retina XDR OLED display.
      - question: |
          What is the aspect ratio of the iPhone 16 Pro display?
        answer: |
          The iPhone 16 Pro display has an aspect ratio of 13:6.
      - question: |
          What is the resolution of the iPhone 16 Pro display?
        answer: |
          The iPhone 16 Pro display has a resolution of 2622 x 1206 and a density of 460 ppi.
      - question: |
          What is the peak brightness of the iPhone 16 Pro display?
        answer: |
          The peak brightness of the iPhone 16 Pro display is 2000 nits.
  - context: |
      The iPhone 16 Pro models are powered by the Apple A18 Pro chip,
      manufactured using the second-generation 3-nanometer process (TSMC N3E),
      which delivers significant performance improvements, especially in AI-related tasks.
      The chip features a 6-core CPU, 6-core GPU, and 16-core Neural Engine,
      accelerating machine learning features at a rate of 35 trillion operations
      per second and enabling seamless integration of Apple Intelligence features.
      Both models offer 8 GB of memory and storage options ranging from 128 GB (256 GB for the Pro Max) to 1 TB.
    questions_and_answers:
      - question: |
          What chip is in the iPhone 16 Pro?
        answer: |
          The chip in the iPhone 16 Pro is the Apple A18 Pro chip manufactured using the second-generation 3-nanometer process (TSMC N3E).
      - question: |
          What are the specs of the chip in the iPhone 16 Pro?
        answer: |
          The chip in the iPhone 16 Pro has a 6-core CPU, 6-core GPU, and a 16-core Neural Engine to accelerate machine learning functions at a speed of 35 trillion operations per second.
      - question: |
          How much memory does the iPhone 16 Pro have?
        answer: |
          The iPhone 16 Pro has 8GB of memory.
  - context: |
      Both Pro models come in four colors, the new Desert Titanium,
      Natural Titanium, White Titanium and Black Titanium, offering a lightweight,
      scratch-resistant exterior. The Desert Titanium color replaced the
      Blue Titanium color used on the iPhone 15 Pro and iPhone 15 Pro Max.
    questions_and_answers:
      - question: |
          What colors is the iPhone 16 Pro available in?
        answer: |
          The iPhone 16 Pro comes in four colors.
      - question: |
          What are the new colors introduced in the iPhone 16 Pro?
        answer: |
          The new color introduced with the iPhone 16 Pro is Desert Titanium.
      - question: |
          What iPhone 15 Pro color does the new iPhone 16 Pro color "Desert Titanium" replace?
        answer: |
          The new iPhone 16 Pro color "Desert Titanium" replaces the Blue Titanium color available on the iPhone 15 Pro.
  - context: |
      All models in the iPhone 16 series, including the iPhone 16 Pro,
      come with a new button called Camera Control. This button is located
      on the right side of the device and allows users to open the camera app,
      switch between various camera controls and functions, and take photos and videos.
      This button can distinguish between a light press and a hard press.
      Pressing the button once opens the camera app. Pressing twice lightly
      opens a small menu with various camera controls such as zoom and tone,
      and pressing once firmly takes a photo. If the user holds down for a few seconds, the video starts.
    questions_and_answers:
      - question: |
          What new buttons does the iPhone 16 Pro‌ have?
        answer: |
          The iPhone 16 Pro‌ has a camera control button.
      - question: |
          What does the camera control button do?
        answer: |
          The camera control button can open the camera app, toggle between different camera controls and functions, and take photos and videos.
      - question: |
          Which side of the device is the iPhone 16 Pro camera control button on?
        answer: |
          The iPhone 16 Pro camera control button is on the right side of the device.
document:
  repo: https://gitlab.com/masaki-oomura/rhel-ai-knowledge-file-sample.git
  commit: 44e362276fffe7f2a87e077ae1fd6c190d9af0fc
  patterns:
    - iphone16_press_release.md
    - iphone16pro_apple_wiki.md

```

このような形で、iPhone 16 Proに関する知識をいくつかの**Context**（概要/ディスプレイ/ハードウェアスペック/カメラ/カメラコントロールボタン）に分解し、それぞれの**Context**に関する説明文を自然言語で記載します。さらに、それぞれの**Context**の内容に閉じて回答（**Answer**）できる質問（**Question**）を記載します。この**Question & Answer**と**Context**の関係を押さえておきましょう。**Context**に示した文章を読んでも回答できないような**Question**を書いてはいけません。

また、**Question**はかならず一文で完結する文章で記載する必要があります。例えば、「**iPhone 16 Proのカメラコントロールボタンはデバイスのどちら側についていますか？**」という**Question**に対する**Answer**として、OK/NGの例は以下のとおりです。

- **OK**: iPhone 16 Proのカメラコントロールボタンはデバイスの右側についています。
- **NG**: 右側です。


この`qna.yaml`の内容に加え、さらに追加の知識文書を参照させることができます。この追加の知識文書はGitリポジトリにアップロードしておく必要があります。

>[Chapter 2. Adding knowledge to your taxonomy tree](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux_ai/1.4/html-single/creating_skills_and_knowledge_yaml_files/index#adding_knowledge)
>For Red Hat Enterprise Linux AI version 1.4 general availability, your data must be hosted in a Git repository.
>
>Hosting your knowledge files on your local system is currently not supported on RHEL AI version 1.4.

RHEL AI 1.4においては、知識文書は文章のみ対応しており、画像は非対応です。
>[2.2. Creating a knowledge markdown file](https://www.apple.com/jp/newsroom/2024/09/apple-debuts-iphone-16-pro-and-iphone-16-pro-max/)
>All documents must be text, images are not currently supported.

追加文書は`.pdf`および`.md`の2種類の拡張子に対応しています。複数の追加文書を格納できますが、その場合はすべて同じ拡張子のファイルで統一する必要があります。

```yaml
...
document:
  repo: https://gitlab.com/masaki-oomura/rhel-ai-knowledge-file-sample.git
  commit: 1ca615bccf48b66c86afea0897972af26fabf2d9
  patterns:
    - iphone16_press_release.md
    - iphone16pro_apple_wiki.md
```

`document.commit`の値には追加文書を格納しているGitリポジトリのコミットハッシュ値を記載しましょう。

なお、今回は`iphone16_press_release.md`と`iphone16pro_apple_wiki.md`いうマークダウン形式のファイルを用意しました。前者は[Appleの公式サイト](https://www.apple.com/cm/newsroom/2024/09/apple-debuts-iphone-16-pro-iphone-16-pro-max/)でダウンロード可能なプレスリリース文書を貼り付けています。後者は[Apple wiki](https://theapplewiki.com/wiki/Main_Page/ja)というAppleファンが有志で運営しているサイトの[iPhone 16 Proのwiki](https://theapplewiki.com/wiki/IPhone_16_Pro)から文章を拝借してきました。


# taxonomyにファイルを追加
taxonomyにディレクトリを追加し、そこに私が事前に作成しGitリポジトリに置いてある`qna.yaml`を格納します。

```sh
## taxonomyにディレクトリを追加
mkdir -p ~/.local/share/instructlab/taxonomy/knowledge/technology/smartphone/apple/iphone16pro

## curlコマンドを使ってqna.yamlをダウンロード
curl -L -o ~/.local/share/instructlab/taxonomy/knowledge/technology/smartphone/apple/iphone16pro/qna.yaml https://gitlab.com/masaki-oomura/rhel-ai-example/-/raw/main/qna.yaml
```

以下のコマンドを使って`qna.yaml`のバリデーションチェックが可能です。

```sh
ilab taxonomy diff
```

実はRHEL AIには事前にサンプルのtaxonomyディレクトリが作られ、`qna.yaml`がいくつか格納されています。

```sh
compositional_skills/grounded/linguistics/inclusion/qna.yaml
compositional_skills/grounded/linguistics/writing/rewriting/qna.yaml
compositional_skills/linguistics/synonyms/qna.yaml
knowledge/arts/music/fandom/swifties/qna.yaml
knowledge/science/animals/birds/black_capped_chickadee/qna.yaml
knowledge/company/apple/product/iphone16pro/qna.yaml ##今回用意したqna.yaml
Taxonomy in /var/home/cloud-user/.local/share/instructlab/taxonomy is valid :)
```

スキルと知識についてそれぞれサンプルファイルが用意されているのですが、今回は「iPhone 16 Proに関する知識のみ」を用いてなるべく短時間でSDGを行いたいので、申し訳ないですがサンプルは削除しておきます。以下のコマンドで削除しておきます。

```sh
rm ~/.local/share/instructlab/taxonomy/compositional_skills/grounded/linguistics/inclusion/qna.yaml
rm ~/.local/share/instructlab/taxonomy/compositional_skills/grounded/linguistics/writing/rewriting/qna.yaml
rm ~/.local/share/instructlab/taxonomy/compositional_skills/linguistics/synonyms/qna.yaml
rm ~/.local/share/instructlab/taxonomy/knowledge/arts/music/fandom/swifties/qna.yaml
rm ~/.local/share/instructlab/taxonomy/knowledge/science/animals/birds/black_capped_chickadee/qna.yaml
```

:::note
サンプルのKnowledgeファイルは、それぞれテイラースウィフトの熱心なファンを表すスラング「スウィフティーズ」と、「アメリカコガラ」というマイナーな鳥についての知識ファイルです。
:::

再度、`ilab taxonomy diff`コマンドで知識ファイルがiPhone 16 Proに関するものだけ存在しているか確認しておきます。

```sh
ilab taxonomy diff
knowledge/company/apple/product/iphone16pro/qna.yaml 
Taxonomy in /var/home/cloud-user/.local/share/instructlab/taxonomy is valid :)
```

大丈夫そうですね。では、SDGを開始する前に、教師モデルとSDG用のLoRAアダプタをダウンロードしておきます。

:::note warn
**よくある`qna.yaml`ファイルのバリデーションエラー**

1. 行末に余分なスペースが入ってしまっている。
    ```sh
    ERROR 2025-03-19 02:20:21,273 instructlab.schema.taxonomy:134: var/home/cloud-user/.local/share/instructlab/taxonomy/knowledge/technology/smartphone/apple/iphone16pro/qna.yaml:86:83 trailing spaces (trailing-spaces)
    ```
2. 最終行に空の行を設けていない
    ```sh
    ERROR 2025-03-19 02:24:43,300 instructlab.schema.taxonomy:134: var/home/cloud-user/.local/share/instructlab/taxonomy/knowledge/technology/smartphone/apple/iphone16pro/qna.yaml:130:32 no new line character at the end of file (new-line-at-end-of-file)
    ```
:::

## 教師モデルとRoLAアダプタをダウンロード
先ほどモデルをダウンロードしたコマンドを用いて、教師モデル「`mixtral-8x7b-instruct-v0-1`」とSDGを行うために必要な追加のRoLAアダプタをダウンロードしておきます。

:::note
LoRAアダプタについては、[こちらの記事](https://qiita.com/masaki-oomura/items/6bdf101a6043316635eb)をご覧いただければ幸いです。
:::

```sh
## 教師モデルをダウンロード
ilab model download --repository docker://registry.redhat.io/mixtral-8x7b-instruct-v0-1 --release latest

## RoLAアダプタをダウンロード（知識トレーニング用のみ）
ilab model download --repository docker://registry.redhat.io/knowledge-adapter-v3 --release latest
```

教師モデルは90GB近くあるため、結構時間がかかります。しばらくお茶をするなり別の作業をするなりしましょう。

## SDGの前にディレクトリをクリーンアップしておく
この後実行するSDGによって生成されるデータは`~/.local/share/instructlab/datasets/`内に保存されます。なお、すでにサンプルファイルを用いて生成されたデータが存在するので、こちらは申し訳ないですがすべて削除して綺麗にしておきます。

```sh
rm -rf ~/.local/share/instructlab/datasets/*
ls ~/.local/share/instructlab/datasets/
##何も表示されなければOK
```

## 合成データ生成（Synthetic Data Generation, SDG）
SDGは非常に簡単なコマンドで実行可能です。

```sh
ilab data generate
```

:::note
上記コマンドを実行すると教師モデルがサーブされ、SDGのプロセスが開始されます。この時、SDGコマンドにオプションをつけて`ilab data generate --enable-serving-output`とすると、vLLMのログも確認することができます。また、`ilab data generate -dt`とすれば、SDGをバックグランドで実行し、引き続きターミナルを使うことができます。
:::

以下のような完了メッセージが出れば、SDG成功です。

```sh
...
INFO 2025-03-19 05:10:58,870 instructlab.sdg.datamixing:215: Mixed Dataset saved to /var/home/cloud-user/.local/share/instructlab/datasets/2025-03-19_045125/knowledge_train_msgs_2025-03-19T04_52_59.jsonl
...
ᕦ(òᴗóˇ)ᕤ Data generate completed successfully! ᕦ(òᴗóˇ)ᕤ
```

## SDGで生成されたデータを確認
先ほどのSDG完了ログにも表示されているとおり、合成データは`~/.local/share/instructlab/datasets/`内に作成されたディレクトリ内に保存されます。なお、ディレクトリ名称はタイムスタンプとなっていますので、環境やSDG完了時刻によって異なります。この中に`.jsonl`形式で保存されます。

`cat`や`tail`コマンドで中身を見ることが可能です。例えば以下のような要素を確認することができます。

```json
{"messages":[{"content":"","role":"system"},{"content":"
\nSiri becomes more natural, flexible, and deeply integrated into the system experience with a brand-new design. With richer language-understanding capabilities, Siri follows along when users stumble over their words and maintains context from one request to the next. Users can type to Siri at any time, and switch fluidly between text and voice as they accelerate everyday tasks. Siri also now has extensive product knowledge to answer thousands of questions about features on iPhone and other Apple devices. With onscreen awareness, Siri understands and takes action with users\u2019 content, in addition to taking hundreds of new actions in and across Apple and third-party apps. And while using iOS 18 features like Siri and Writing Tools, users will also be able to easily access ChatGPT from OpenAI.\n\n# **Better for the Environment**\n\niPhone 16 Pro and iPhone 16 Pro Max are designed with the environment in mind. As part of Apple 2030, the company\u2019s ambitious goal to be carbon neutral across its entire carbon footprint by the end of this decade, Apple is prioritizing renewable electricity in manufacturing, and investing in wind and solar projects around the world to address the electricity used to charge all Apple products, including the iPhone 16 lineup. Today, all Apple facilities run on 100 percent renewable electricity \u2014 including the data centers that power Apple Intelligence.\n\nTo achieve Apple 2030, the company is also designing products with recycled and renewable materials. iPhone 16 Pro and iPhone 16 Pro Max feature more than 25 percent recycled content overall, including 100 percent recycled aluminum in the internal structural frame and 80 percent or more recycled steel across multiple components. The battery is made with 100 percent recycled cobalt and \u2014 in a first for iPhone \u2014 over 95 percent recycled lithium.4 The iPhone 16 Pro lineup also meets Apple\u2019s high standards for energy efficiency, and is free of mercury and PVC. The packaging is entirely fiber-based, bringing Apple closer to its goal of removing plastic from its packaging by next year.\n\n# **Pricing and Availability**\n\nWhen will the iPhone 16 Pro and iPhone 16 Pro Max be available for pre-order and in stores?\n
\nThe iPhone 16 Pro and iPhone 16 Pro Max will be available for pre-order beginning Friday, September 16, 2023, and in stores beginning Friday, September 23, 2023.\n\n","role":"pretraining"}],"metadata":"{\"sdg_document\": \"Siri becomes more natural, flexible, and deeply integrated into the system experience with a brand-new design. With richer language-understanding capabilities, Siri follows along when users stumble over their words and maintains context from one request to the next. Users can type to Siri at any time, and switch fluidly between text and voice as they accelerate everyday tasks. Siri also now has extensive product knowledge to answer thousands of questions about features on iPhone and other Apple devices. With onscreen awareness, Siri understands and takes action with users\\u2019 content, in addition to taking hundreds of new actions in and across Apple and third-party apps. And while using iOS 18 features like Siri and Writing Tools, users will also be able to easily access ChatGPT from OpenAI.\\n\\n# **Better for the Environment**\\n\\niPhone 16 Pro and iPhone 16 Pro Max are designed with the environment in mind. As part of Apple 2030, the company\\u2019s ambitious goal to be carbon neutral across its entire carbon footprint by the end of this decade, Apple is prioritizing renewable electricity in manufacturing, and investing in wind and solar projects around the world to address the electricity used to charge all Apple products, including the iPhone 16 lineup. Today, all Apple facilities run on 100 percent renewable electricity \\u2014 including the data centers that power Apple Intelligence.\\n\\nTo achieve Apple 2030, the company is also designing products with recycled and renewable materials. iPhone 16 Pro and iPhone 16 Pro Max feature more than 25 percent recycled content overall, including 100 percent recycled aluminum in the internal structural frame and 80 percent or more recycled steel across multiple components. The battery is made with 100 percent recycled cobalt and \\u2014 in a first for iPhone \\u2014 over 95 percent recycled lithium.4 The iPhone 16 Pro lineup also meets Apple\\u2019s high standards for energy efficiency, and is free of mercury and PVC. The packaging is entirely fiber-based, bringing Apple closer to its goal of removing plastic from its packaging by next year.\\n\\n# **Pricing and Availability**\", \"domain\": \"astronomy\", \"dataset\": \"document_knowledge_qa\", \"raw_document\": \"Siri becomes more natural, flexible, and deeply integrated into the system experience with a brand-new design. With richer language-understanding capabilities, Siri follows along when users stumble over their words and maintains context from one request to the next. Users can type to Siri at any time, and switch fluidly between text and voice as they accelerate everyday tasks. Siri also now has extensive product knowledge to answer thousands of questions about features on iPhone and other Apple devices. With onscreen awareness, Siri understands and takes action with users\\u2019 content, in addition to taking hundreds of new actions in and across Apple and third-party apps. And while using iOS 18 features like Siri and Writing Tools, users will also be able to easily access ChatGPT from OpenAI.\\n\\n# **Better for the Environment**\\n\\niPhone 16 Pro and iPhone 16 Pro Max are designed with the environment in mind. As part of Apple 2030, the company\\u2019s ambitious goal to be carbon neutral across its entire carbon footprint by the end of this decade, Apple is prioritizing renewable electricity in manufacturing, and investing in wind and solar projects around the world to address the electricity used to charge all Apple products, including the iPhone 16 lineup. Today, all Apple facilities run on 100 percent renewable electricity \\u2014 including the data centers that power Apple Intelligence.\\n\\nTo achieve Apple 2030, the company is also designing products with recycled and renewable materials. iPhone 16 Pro and iPhone 16 Pro Max feature more than 25 percent recycled content overall, including 100 percent recycled aluminum in the internal structural frame and 80 percent or more recycled steel across multiple components. The battery is made with 100 percent recycled cobalt and \\u2014 in a first for iPhone \\u2014 over 95 percent recycled lithium.4 The iPhone 16 Pro lineup also meets Apple\\u2019s high standards for energy efficiency, and is free of mercury and PVC. The packaging is entirely fiber-based, bringing Apple closer to its goal of removing plastic from its packaging by next year.\\n\\n# **Pricing and Availability**\", \"dataset_type\": \"base_document\"}","id":"69b39212-27af-426a-b303-c47401574c58"}
```

なんじゃこりゃ！？という感じなのですが、ざっくり言うとこれらのデータセットには、AIの学習用データとしての会話の流れが記録されています。これらは教師モデルがSDGの元ネタとして利用している`qna.yaml`や追加で提供した知識文書（`iphone_16_series.md`と`iphone16pro_apple_wiki.md`）から合成されたデータセットです。


## 作成された合成データを使って新しい知識を学習
先ほど確認した合成データを利用して、生成AIをトレーニングしましょう。今回は新しい知識のみを獲得することを目的としており、スキルの体得は行いません。特定の知識ファイルを参照してモデルのトレーニングを実行します。また、トレーニング対象のモデルは`granite-8b-starter-v1`です。以下のコマンドを実行しましょう。

```sh
ilab model train --model-path ~/.cache/instructlab/models/granite-8b-starter-v1 --data-path ~/.local/share/instructlab/datasets/<TIMESTAMP>/knowledge_train_msgs_<TIMESTAMP>.jsonl
```

モデルトレーニングが完了すると以下のようなログが出力されます。
```sh
Model saved in /var/home/cloud-user/.local/share/instructlab/checkpoints/hf_format/samples_<NUMBER>
...
Operation completed successfully! 🎉
Waiting for process to exit, 60s...
```

## カスタマイズされたモデルたち一覧を確認
RHEL AIはモデルトレーニングのパイプラインを実行するなかで複数のチェックポイントを作成してくれます。[公式ドキュメント](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux_ai/1.4/html-single/generating_a_custom_llm_using_rhel_ai/index#train_and_eval)で紹介されているマルチフェーズトレーニング（知識＋スキルのトレーニング）においては、まず知識についてトレーニング行い（Phase1）、作成された複数のチェックポイントを評価し、最もスコアの高いものをスキルトレーニング段階（Phase2）で採用する旨が記載されています。

>RHEL AI can use your taxonomy tree and synthetic data to create a newly trained model with your domain-specific knowledge or skills using multi-phase training and evaluation. You can run the full training and evaluation process using the synthetic dataset you generated. The LAB optimized technique of multi-phase training is a type of LLM training that goes through multiple stages of training and evaluation. In these various stages, RHEL AI runs the training process and produces model checkpoints. The best checkpoint is selected for the next phase. This process creates many checkpoints and selects the best scored checkpoint. This best scored checkpoint is your newly trained LLM.
>
>The entire process creates a newly generated model that is trained and evaluated using the synthetic data from your taxonomy tree.

以下のコマンドで、「追加知識のみ」を用いてカスタマイズされたモデルの複数のチェックポイントを確認してみます。

```sh
ls /var/home/cloud-user/.local/share/instructlab/checkpoints/hf_format
```

すると、複数のチェックポイントが確認できます。これらはエポック数に対応しています。
```sh
samples_1142  samples_1528  samples_1912  samples_2288  samples_6481  samples_378  samples_765
```
## MMLU_BRANCH benchmarkによる評価
今回は新しい知識のみを使ってモデルトレーニングを行ったので、これらチェックポイントの作成のみが行われており、評価はされていません。そこで、手動で評価してあげる必要があります。今回は[MMLU](https://en.wikipedia.org/wiki/MMLU)をベースにしつつ、SDGによって作成されたトレーニングデータがベースモデルにどれだけ影響を与えたのか？をスコアリングするコマンドを利用します。

```sh
ilab model evaluate --benchmark mmlu_branch \
--model ~/.local/share/instructlab/checkpoints/hf_format/samples_<NUMBER> \
--judge-model ~/.cache/instructlab/models/prometheus-8x7b-v2-0 \
--base-model ~/.cache/instructlab/models/granite-8b-starter-v1 \
--tasks-dir ~/.local/share/instructlab/datasets/<TIME_STAMP_DIR>/node_datasets_<TIME_STAMP_TASK> 
```

ここで`<NUMBER>`はチェックポイントファイル「`samples_`」の後に続くランダム数字です。また、`<TIME_STAMP_DIR>`は、SDGが完了した際にログに出力されたタイムスタンプであり、ディレクトリ名です。本記事の環境では「`2025-03-19_045125`」になります。このディレクトリ内にさらに`node_datasets_<TIME_STAMP_TASK>`というディレクトリが作成されます。確認してみましょう。

```sh
ls -l ~/.local/share/instructlab/datasets/2025-03-19_045125 
...
drwxr-xr-x. 2 cloud-user cloud-user       4096 Mar 19 05:09 node_datasets_2025-03-19T04_52_59
...
```

この記事の環境では`node_datasets_2025-03-19T04_52_59`がディレクトリ名であり、`<TIME_STAMP_TASK>`は`2025-03-19T04_52_59`ということになります。

さて、試しに、「samples_1142」について評価してみます。

```sh
ilab model evaluate --benchmark mmlu_branch \
--model ~/.local/share/instructlab/checkpoints/hf_format/samples_1142 \
--judge-model ~/.cache/instructlab/models/prometheus-8x7b-v2-0 \
--base-model ~/.cache/instructlab/models/granite-8b-starter-v1 \
--tasks-dir ~/.local/share/instructlab/datasets/2025-03-19_045125/node_datasets_2025-03-19T04_52_59
```
評価が完了すると、以下のような出力が表示されます。
```sh
...
# KNOWLEDGE EVALUATION REPORT

## BASE MODEL (SCORE)
/var/home/cloud-user/.cache/instructlab/models/granite-8b-starter-v1 (0.59/1.0)

## MODEL (SCORE)
/var/home/cloud-user/.local/share/instructlab/checkpoints/hf_format/samples_1142 (0.61/1.0)

### IMPROVEMENTS (0.0 to 1.0):
1. knowledge_technology_smartphone_apple_iphone16pro: 0.59 -> 0.61 (+0.02)
INFO 2025-03-19 06:04:07,971 instructlab.model.evaluate:448: 
ᕦ(òᴗóˇ)ᕤ Model evaluate with MMLUBranch completed! ᕦ(òᴗóˇ)ᕤ
```

ベースモデルとトレーニング後のモデルでの評価結果（スコア）が両方示されています。このような形でベースモデルからの変化について定量的に評価できます。

:::note
`node_datasets_<TIME_STAMP_TASK>`内に作成されている例題ファイルの中身を少しみてみましょう。以下のコマンドで例題ファイルの存在を確認し、さらにその中身を見てみます。

```sh
## ディレクトリの中身を確認
ls -l ~/.local/share/instructlab/datasets/2025-03-19_045125/node_datasets_2025-03-19T04_52_59
...
-rw-r--r--. 1 cloud-user cloud-user  742200 Mar 19 05:09 mmlubench_knowledge_technology_smartphone_apple_iphone16pro.jsonl
```

`mmlubench_knowledge_technology_smartphone_apple_iphone16pro.jsonl`というJSONLファイルが存在します。これが例題（クイズ）ファイルです。中身を見てみます。

```sh
## 例題ファイルの中身を確認
cat ~/.local/share/instructlab/datasets/2025-03-19_045125/node_datasets_2025-03-19T04_52_59/mmlubench_knowledge_technology_smartphone_apple_iphone16pro.jsonl
```
すると、膨大なJSONLファイルの中身が表示されます。これらが例題の連なりです。わかりやすい部分を抜粋してみてみます。

```json
{
  "document": "- iCloud+ plans start at 50GB for $0.99 (U.S.) per month and offer up to 12TB for $59.99 (U.S.) per month, providing additional storage to keep files, photos, videos, and more safe in the cloud, accessible across devices, and easy to share with others. iCloud+ also gives access to premium features, including Private Relay, Hide My Email, Custom Email Domains, and HomeKit Secure Video support.\n\n- Customers who purchase iPhone 16 Pro and iPhone 16 Pro Max will receive three free months of Apple Music, Apple Arcade, and Apple Fitness+ with a new subscription.\n\nAbout Apple\n\n- Apple revolutionized personal technology with the introduction of the Macintosh in 1984. Today, Apple leads the world in innovation with iPhone, iPad, Mac, AirPods, Apple Watch, and Apple Vision Pro. Apple’s six software platforms — iOS, iPadOS, macOS, watchOS, visionOS, and tvOS — provide seamless experiences across all Apple devices and empower people with breakthrough services including the App Store, Apple Music, Apple Pay, iCloud, and Apple TV+. Apple’s more than 150,000 employees are dedicated to making the best products on earth and to leaving the world better than we found it.\n\n- The display has rounded corners that follow a beautiful curved design, and these corners are within a standard rectangle. When measured as a standard rectangular shape, the screen is 6.27 inches (iPhone 16 Pro) or 6.85 inches (iPhone 16 Pro Max) diagonally. Actual viewable area is less.\n\n- Apple’s satellite features are included for free for two years starting at the time of activation of a new iPhone 14 or later. For Emergency SOS via satellite availability, visit support.apple.com/en-us/HT213426. Messages via satellite will be available in the U.S. and Canada in iOS 18. SMS availability will depend on carrier. Carrier fees may apply. Users should check with their carrier for details. Roadside Assistance via satellite is currently available in the U.S. with AAA and Verizon Roadside Assistance, and is launching in the U.K. with Green Flag this fall. Participating roadside assistance providers may charge for services, and iPhone users who are not members can take advantage of their roadside assistance services on a pay-per-use basis. Apple’s satellite services were designed for use in open spaces with a clear line of sight to the sky. Performance may be impacted by obstructions such as trees or surrounding buildings. Emergency SOS Live Video will be available in the U.S. in iOS 18.",
  ...
  "mmlubench_question": "What features does iCloud+ provide in addition to storage?",
  "mmlubench_answer": "A) Private Relay, Hide My Email, Custom Email Domains, and HomeKit Secure Video support",
  "dataset_type": "mcq_qa",
  "answer": 0,
  "choices": [
    "Private Relay, Hide My Email, Custom Email Domains, and HomeKit Secure Video support",
    "Free access to Apple Music, Apple Arcade, and Apple Fitness+",
    "Rounded-corner display design",
    "Satellite communication features"
  ],
  "question": "What features does iCloud+ provide in addition to storage?"
}
```

`"document": `のバリューには`iphone16_press_release.md`の一部が抜粋されています。この内容をもとに、新しく**Question**が作成され、`"mmlubench_question":`のバリューに「**What features does iCloud+ provide in addition to storage?（ストレージに加えてiCloud+ が提供する追加機能はどれか？）**」が入っていますね。これに対する回答の選択肢（`"choices": `）として以下が作成されています。

```
- [0] Private Relay, Hide My Email, Custom Email Domains, and HomeKit Secure Video support
- [1] Free access to Apple Music, Apple Arcade, and Apple Fitness+
- [2] Rounded-corner display design
- [3] Satellite communication features
```

なお、番号は筆者で振りました。さて、このクイズ、Appleファンの方なら愚問ですわね。2と3は論外です。1については「[Apple One](https://www.apple.com/jp/apple-one/)」の説明です。これはいい引っ掛け問題ですが、生粋のAppleファンである私は騙されませんよ！

正解は「`"mmlubench_answer":`」のバリューに入れ込まれている「`Private Relay, Hide My Email, Custom Email Domains, and HomeKit Secure Video support`」です。これを選択肢の番号で表現すると「`"answer": 0`」です。

という、感じで例題クイズが`node_datasets_<TIME_STAMP_TASK>`には大量に作成され、これを使ってMMLUベースの評価が行われます。
:::


## 複数のチェックポイントを自動的に評価する
さきほどのように手作業でひとつひとつのチェックポイントを評価してもよいのですが、それはなかなか手間になります。そのため、以下のようなスクリプトを組みました。このスクリプトで順繰りに評価を行い、最後に評価結果一覧を出力してもらうようにしました。

```trained-model-evaluate.sh
#!/bin/bash

# Ensure the script runs with UTF-8 encoding to prevent garbled characters
export LC_ALL=C.UTF-8
export LANG=C.UTF-8

# Paths
CHECKPOINT_DIR="/var/home/cloud-user/.local/share/instructlab/checkpoints/hf_format/"
TASKS_DIR="/var/home/cloud-user/.local/share/instructlab/datasets/<TIME_STAMP_DIR>/node_datasets_<TIME_STAMP_TASK> "
BASE_MODEL="/var/home/cloud-user/.cache/instructlab/models/granite-8b-starter-v1"
JUDGE_MODEL="/var/home/cloud-user/.cache/instructlab/models/prometheus-8x7b-v2-0"

# Variable to store results
RESULTS=()

# Loop through all sample directories
for SAMPLE in $(ls "$CHECKPOINT_DIR" | grep '^samples_[0-9]\+$'); do
    echo "Evaluating: $SAMPLE"

    # Temporary file to store output
    TEMP_FILE=$(mktemp)

    # Execute evaluation and store output in a temporary file
    ilab model evaluate --benchmark mmlu_branch --model "$CHECKPOINT_DIR/$SAMPLE" --judge-model "$JUDGE_MODEL" --base-model "$BASE_MODEL" --tasks-dir "$TASKS_DIR" | tee "$TEMP_FILE"

    # Wait until the last line contains "Model evaluate with MMLUBranch completed!"
    while ! tail -n 1 "$TEMP_FILE" | grep -q "Model evaluate with MMLUBranch completed!"; do
        sleep 1
    done

    # Extract the score after the condition is met
    SCORE=$(grep "## MODEL (SCORE)" -A1 "$TEMP_FILE" | tail -n 1 | awk '{print $2}')

    # Store the result
    RESULTS+=("$SAMPLE: $SCORE")

    # Delete the temporary file
    rm "$TEMP_FILE"
done

# Display the results
echo -e "\nFinal Results:"
for RESULT in "${RESULTS[@]}"; do
    echo "$RESULT"
done
```

:::note warn
`<TIME_STAMP_DIR>`と`<TIME_STAMP_TASK>`にはご自身の環境の値を入力してください。
:::

上記の内容でファイルを作成します。

```sh
## nanoエディタを開く
nano trained-model-evaluate.sh

## 上記内容をコピペして保存（ctrl+Oで保存、ctrl+xでエディタ終了）

## ファイルの権限変更
chmod +x trained-model-evaluate.sh

## スクリプトを実行する
 ./trained-model-evaluate.sh
```

評価が完了した結果は以下のとおりでした。

```sh
Final Results:
samples_1142: (0.61/1.0)
samples_1528: (0.61/1.0)
samples_1912: (0.62/1.0)
samples_2288: (0.67/1.0)
samples_6481: (0.68/1.0)
samples_378: (0.6/1.0)
samples_765: (0.61/1.0)
```

ここから、MMLU_BRANCH benchmarkによる評価では「samples_6481」がもっとも高いスコアを記録していることがわかります。というわけで、こいつをサーブして推論させてみましょう！

## 推論実行

```sh
## カスタマイズしたモデルをサーブ
ilab model serve --model-path ~/.local/share/instructlab/checkpoints/hf_format/samples_6481/
```
:::note warn
なお、[公式ドキュメント](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux_ai/1.4/html-single/generating_a_custom_llm_using_rhel_ai/index#serving_the_new_model)にも記載されていますが、チェックポイントディレクトリ名の最後に必ず`/`を忘れずにつけましょう。
:::

サーブが完了したら、先ほどベースモデル`granite-8b-starter-v1`とチャットした時と同様、カスタマイズしたモデルを選択して`ilab model chat`を実行します。

```sh
## カスタマイズしたモデルとチャット
ilab model chat --model ~/.local/share/instructlab/checkpoints/hf_format/samples_6481
```

:::note
チャットする際のモデルのPATH指定では末尾に`/`は要りません。
:::

```sh
╭──────────────────────────────────────────────────────────── system ────────────────────────────────────────────────────────────╮
│ Welcome to InstructLab Chat w/ SAMPLES_6481 (type /h for help)                                                                 │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
>>>                                                                           [S][default]
```
カスタマイズしたモデルとチャットできるようになりました。早速質問してみます。

```sh
## 私たちはいつからiPhone 16 Proを購入できますか？
>>> When can we buy the iPhone 16 Pro?                                                                                     [S][default]
╭─────────────────────────────────────────────────────────── samples_6481 ────────────────────────────────────────────────────────────╮
│ The iPhone 16 Pro is available for pre-order starting on Friday, September 13, 2024, and it will be released on Friday, September   │
│ 20, 2024. You can pre-order the iPhone 16 Pro through the Apple Store, carrier websites, and select retailers.                      │
│                                                                                                                                     │
│ If you have any other questions about the iPhone 16 Pro or any other topic, please feel free to ask. I'm here to help.              │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────── elapsed 0.667 seconds ─╯
```

和訳した結果は以下です。
>iPhone 16 Pro は、2024 年 9 月 13 日金曜日から予約注文が可能になり、2024 年 9 月 20 日金曜日に発売されます。iPhone 16 Pro は、Apple Store、キャリアの Web サイト、一部の小売店で予約注文できます。
>
>iPhone 16 Pro やその他のトピックについてご質問がある場合は、お気軽にお問い合わせください。お手伝いさせていただきます。


今度は正しく回答できました。`qna.yaml`あるいは参考ドキュメントにて提供した情報をもとに、回答できています。先ほど例題で見た内容も聞いてみましょう。

```sh
## ストレージに加えてiCloud+ が提供する追加機能はどれか？
>>> What features does iCloud+ provide in addition to storage?                                                             [S][default]
╭─────────────────────────────────────────────────────────── samples_6481 ────────────────────────────────────────────────────────────╮
│ iCloud+ provides several features in addition to storage, including Private Relay, Hide My Email, Custom Email Domains, and HomeKit │
│ Secure Video support. Private Relay encrypts internet traffic and hides the user's IP address, while Hide My Email creates unique,  │
│ random email addresses to protect privacy. Custom Email Domains allow users to use their own domain name for iCloud email, and      │
│ HomeKit Secure Video support enables secure video storage and access for HomeKit-compatible security cameras.                       │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────── elapsed 0.623 seconds ─╯
```

回答を和訳してみると以下のような内容です。
>iCloud+ は、ストレージに加えて、プライベートリレー、メールの非表示、カスタムメールドメイン、HomeKit セキュアビデオのサポートなど、いくつかの機能を提供します。プライベートリレーはインターネットトラフィックを暗号化し、ユーザーの IP アドレスを非表示にします。一方、メールの非表示は、プライバシーを保護するために一意のランダムなメールアドレスを作成します。カスタムメールドメインを使用すると、ユーザーは iCloud メールに独自のドメイン名を使用できます。また、HomeKit セキュアビデオのサポートにより、HomeKit 対応のセキュリティカメラの安全なビデオストレージとアクセスが可能になります。

概ね正しい内容に思われます。知識文書として提供した`iphone16_press_release.md`に含まれる内容をもとにiCloud+で提供されるいくつかの機能と、具体的な内容について説明してくれています。

このように、自然文で作成した`qna.yaml`や追加で用意した文書を使って誰でも簡単にモデルをカスタマイズし、基盤モデルに新しい知識を教え込むことが可能です。

# モデルをアップロード
最後は、カスタマイズしたモデルをレジストリにアップロードしてみます。今回はS3とHuggingFaceの両方を試してみます。

## S3にアップロード
Amazon S3はRHEL AIが対応しているモデルレジストリのひとつです。非常に簡単なコマンド一発でアップロード可能ですので、さっそくやってみます。

### AWS CLIのセットアップ
RHEL AIからS3にモデルをアップロードするためにはAWS CLIを利用できる必要があります。以下の手順にて、RHEL AIのユーザ`cloud-user`でAWSコマンドを利用できるようにします。

```sh
## AWS CLIのダウンロード
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"

## zipを解凍
python3 -m zipfile -e awscliv2.zip .

## インストーラの権限変更
chmod -R +x ~/aws

## CLI本体を格納するディレクトリおよびバイナリのシンボリックリンクを格納するディレクトリを作成
mkdir -p ~/.local/bin ~/.local/aws-cli

## インストーラを実行し、シンボリックリンクも作成
~/aws/install --install-dir ~/.local/aws-cli --bin-dir ~/.local/bin

## PATHを通す
echo 'export PATH=$HOME/.local/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

## AWSコマンドが実行できるか確認
aws --version
```

これでRHEL AIインスタンスでAWSコマンドを利用できるようになりました。さっそくAWSのクレデンシャル情報を登録します。

```sh
## AWS CLIにアカウント情報を登録
aws configure

AWS Access Key ID [None]: ## AWSアクセスキーをコピペ
AWS Secret Access Key [None]: ## AWSクライアントキーをコピペ
Default region name [None]: ## 特に設定不要、Enterを押す
Default output format [None]: ## 特に設定不要、Enterを押す
```

これでS3にモデルをアップロードできるようになりました。[公式ドキュメントのコマンド](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux_ai/1.4/html/building_and_maintaining_your_rhel_ai_environment/managing_download_models#managing_download_models)を参考に、アップロードしてみます。

```sh
## 環境変数の設定
MODEL_PATH=/var/home/cloud-user/.local/share/instructlab/checkpoints/hf_format/samples_6481
BUCKET_NAME=<ご自身が作成したS3バケット名>

## S3バケットに自分がカスタマイズしたモデルをアップロード
ilab model upload --model $MODEL_PATH --destination $BUCKET_NAME --dest-type s3
```

AWSマネジメントコンソールでS3バケットの中身を確認してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/81a3e83c-c2fa-4d0d-a628-e20f9e385fbc.png)

無事に.safetensorファイルを含めたモデルデータの一式がアップロードできました。

## Hugging Faceにアップロード
次はHuggingFaceにモデルをアップロードしてみましょう。

### HFトークンの作成
HuggingFaceのマイページにて、HFトークンを作成します。

![スクリーンショット 2025-03-24 13.05.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/30f1f919-9b63-46ef-9cb9-13d988304f1f.png)

「+ Create new token」をクリックします。

![スクリーンショット 2025-03-24 13.07.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/34407a87-a3c7-49b2-ac65-dcafbafba85c.png)

トークンタイプ（権限）を「Write（書き込み）」とし、適当なトークン名を入力、「Create token」をクリックします。

![スクリーンショット 2025-03-24 13.09.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/f90fd1a5-7472-4248-90f1-08efa8ffb633.png)

`hf_hogehoge`をコピーします。

### リポジトリの作成
次に、モデルをアップロードするためのリポジトリを作成します。

![スクリーンショット 2025-03-25 15.29.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/0b2631c1-0868-43ff-887c-f7c43a36753e.png)


アカウントアイコンをクリックしてメニューを開く、「New Model」をクリックします。Model name欄に適当な内容を入力します。今回はお試し用なので、Privateなリポジトリ＆ライセンスは「Unlicense」とします。必要な内容を入力したら「Create model」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/89615c07-b76d-4869-800c-ec4d8eefffc0.png)

レポジトリ名（ユーザ名/モデル名）を確認しておきます。

### モデルをアップロード
以下のgitコマンドで自身のHuggingFaceアカウントのレジストリにモデルをアップロードします。

```sh
## 環境変数の設定
MODEL_PATH=/var/home/cloud-user/.local/share/instructlab/checkpoints/hf_format/samples_6481
HF_TOKEN=<先ほどコピーしたHFトークン>
USER_NAME=<ご自身のHuggingFaceユーザ名>
MODEL_NAME=<先ほど設定したModel name>

## HuggingFaceのリポジトリをクローン
git clone https://$USER_NAME:$HF_TOKEN@huggingface.co/$USER_NAME/$MODEL_NAME
cd $MODEL_NAME

## Git LFS を有効化（.safetensorsをLFS管理）
git lfs install
git lfs track "*.safetensors"

## モデルファイルをリポジトリにPush
cp $MODEL_PATH/* .
git add .

## 容量が多いのでgit addが完了するまで少し時間がかかります。

git commit -m "upload modelfiles"
git push origin main
```

しばらく待つとターミナルに成功のログが出ます。HuggingFaceのコンソール画面を更新すると、モデルがアップロードできていることを確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/08ba9e49-491f-48c0-9f52-72cbd917d75d.png)


# おわりに
以上、非常に駆け足でしたが、RHEL AIを用いて以下について実験してみました。
- モデルのダウンロード
- モデルのサーブと推論（チャット）
- モデルのカスタマイズ（ファインチューニング）
- カスタマイズしたモデルをアップロード

モデルのカスタマイズについては、`qna.yaml`をもっと改善することで、より確からしい、望ましいモデルカスタマイズが可能になるはずです。また、知識文書についてもマークダウンによる見出しや強調をもっと工夫して使うことで、より高い学習効果を得ることも可能でしょう。

さらに、`ilab model train`コマンドにおいても、まだいくつかのオプションを試す機会があります。例えば[`--num-epochs <EPOCH_NUMBE>`というオプション](https://www.redhat.com/en/blog/instructlab-tutorial-installing-and-fine-tuning-your-first-ai-model-part-2)は、明示的にエポック数を設定可能なものです。デフォルトでは7エポックしか回されなかったトレーニングについて、任意の回数を指定できます。より大きなエポック数を指定することで、最適な繰り返し回数を探ることも可能でしょう。

::: note warn
エポック数は多ければ多いほど良いというものでもありません。あまりに多すぎると過学習の懸念が出てきます。
:::

## 「おらがAI」をみんなで育てよう
RHEL AIはまだまだ進化中のプロダクトではありますが、こんなに簡単に誰でもモデルカスタマイズが試せるということをわかっていただければ幸いです。データサイエンティストのみならず、現場の従業員の方が持つ固有の知識を自社の生成AIに注ぎ込み、みんなで「おらがAI」を育てることができる、そんな可能性がRHEL AIにはあるのです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/c0cce587-ec17-4192-81c7-821b89fb71ec.png)


おしまい