ラベル MLX の投稿を表示しています。 すべての投稿を表示
ラベル MLX の投稿を表示しています。 すべての投稿を表示

2025年5月13日火曜日

M1 MacBookAir で mlx 上で stable diffusion を実行する

M1 MacBookAir で mlx 上で stable diffusion を実行する

概要

例のごとく mlx-examples を使います

環境

  • M1 MacBookAir (CPU8, GPU7)
  • Python 3.12.9
  • mlx-examples 977cd30242b9891c306ef23ba925553104eb4f0c

動かす方法

基本はクローンして pip install して python で実行するだけです

  • git clone https://github.com/ml-explore/mlx-examples.git
  • cd mlx-examples
  • cd stable_diffusion
  • pyenv local 3.12.9
  • python -m venv .venv
  • pip install -r requirements.txt
  • python txt2image.py "A photo of an astronaut riding a horse on Mars." --n_images 4 --n_rows 2

だいたい1枚の生成で1分から2分ほどで完了します

オプション

  • n_images -> 1枚の画像内に何枚の絵を生成するか
  • n_rows -> 何行で表示するか、n_images=4 で n_rows=2 だと上下に2枚ずつ生成される、1枚の絵だけ生成したい場合は n_images も n_rows も 1 にする
  • negative_prompt -> ネガティブプロンプトを指定します

生成される画像のサイズは528x528になります

使用しているモデル

txt2image.py では stabilityai/sdxl-turbo を使っているようです
モデルを変更したい場合は好きなモデルをダウンロードして model オプションを指定するか直接ファイルを編集しても OK です

初回はモデルのダウンロードが走り15GBほどダウンロードするのでディスクに注意しましょう

最後に

過去に sd-webuisd-webui-forge のやり方を紹介しましたが Apple Sillicon の GPU をフルで使いたいならやはり mlx を使った方法が一番かもしれません

参考サイト

2025年4月25日金曜日

OpenSora を M2 Mac 上で動作させる方法

OpenSora を M2 Mac 上で動作させる方法

概要

OpenSora はテキスト -> 動画が生成できるオープンソースのモデルです
内部的に xformers を使っているためデフォルトの状態で Mac で使うのはかなり大変です

今回はMLX を使って動作させる方法があるのでその方法を紹介します

環境

  • macOS 15.4.1
  • OpenSora 1.2
  • Python 3.10.12
    • mlx 0.25.0

注意点

今回紹介する記事では OpenSora のバージョンが 1.2 になっています
最新バージョンは 2.0 でまだ MLX では 2.0 に対応していないので注意しましょう
頑張れば 2.0 に対応することもできると思います

OpenSora のサンプルコードのクローン

  • git clone https://github.com/awni/mlx-examples.git
  • cd mlx-examples
  • git switch open_sora

プロジェクト初期化

  • pyenv local 3.10.12
  • python -m venv .venv
  • source .venv/bin/activate
  • pip install -r requirements.txt
  • pip install protobuf sentencepiece

コード修正

一部動作しないので手動で書き換えます

  • vim utils/video_io.py
diff --git a/open_sora/utils/video_io.py b/open_sora/utils/video_io.py
index e18635c..cceb725 100644
--- a/open_sora/utils/video_io.py
+++ b/open_sora/utils/video_io.py
@@ -28,7 +28,7 @@ def save_video(x, save_path=None, fps=8):
 
         for img in x:
             frame = av.VideoFrame.from_ndarray(img, format="rgb24")
-            frame.pict_type = "NONE"
+            frame.pict_type = 0
             for packet in stream.encode(frame):
                 container.mux(packet)

生成

  • python generate.py --prompt "A beautiful smile girl" --resolution 240p

初回はモデルのダウンロードがあるので時間がかかります
全部で 10GB ほどあるので注意しましょう

  • cd .cache/huggingface/hub/models--mlx-community--OpenSora-VAE-v1.2

できたもの

やはり人間は苦手なのかもです
マシンスペックがそもそも低いのもありますが各種チューニング (フレームレートやプロンプトなど) をしっかりやれば OpenSora1.2 でもいい動画が作れるのかもです

最後に

MLX を使って M2 Mac 上で OpenSora を動作させてみました
バージョンが古いので精度的には微妙な感じはします
そのうち本体にマージされて 2.0 対応されれば精度も上がるかもしれません

参考サイト

2024年5月31日金曜日

ツイート情報を LoRA に学習させるためのフォーマットに変換する

ツイート情報を LoRA に学習させるためのフォーマットに変換する

概要

過去に mlx で LoRA 学習をしました今回はツイートのアーカイブデータを学習させられるように加工してみました

環境

  • macOS 11.7.10
  • Python 3.11.6

準備

  • pip install pandas scikit-learn

サンプルコード

基本的な作成の流れは前回と同じです
成果物も json ファイル 3 つになります

ツイートのアーカイブ情報にはいろいろありますが今回は full_text のみ学習させます

命令も単純に「ツイートして」にしていますが本来であれば時刻やそのツイートに関するコンテキストも命令に与えたほうがいいです

import json
from io import StringIO

import pandas as pd
from sklearn.model_selection import train_test_split

# tweets.js を読み込んでツイート情報を辞書に変換
tweets = []
with open("./tweets.js", mode="r") as f:
    for tweet in json.loads(f.read().replace("window.YTD.tweets.part0 = ", "")):
        t = {
            "full_text": tweet["tweet"]["full_text"],
            "created_at": tweet["tweet"]["created_at"],
        }
        tweets.append(t)

# JSONデータをPandas DataFrameに読み込む
df = pd.read_json(StringIO(json.dumps(tweets)))
pd.set_option("display.max_colwidth", 1000)
pd.set_option("display.max_rows", 1000)

# リンクを含むツイートは削除
df = df[~df["full_text"].str.contains("https://")]

print(df.head(100))

# テキスト長が短い学習データTOP1300をデータセットとして扱う
# 学習に時間がかかる場合もしくはメモリを使いすぎる場合は ascending=True にして短い順にするか 1300 の数を小さくすること
df["length"] = df.full_text.str.len()
df = df.sort_values(by="length", ascending=False)
df = df.head(1300)

# データフレームをシャッフル
df = df.sample(frac=1).reset_index(drop=True)

# validとtest用のデータを100件ずつ取り出し、残りをtrainに分割
valid_df, remaining_df = train_test_split(df, test_size=len(df) - 100, random_state=42)
test_df, train_df = train_test_split(
    remaining_df, test_size=len(remaining_df) - 100, random_state=42
)


# ヘルパー関数:データフレームを新しい形式でJSON Linesファイルに変換
def df_to_jsonl(df, file_name):
    with open(file_name, "w", encoding="utf-8") as file:
        for _, row in df.iterrows():
            formatted_data = {"text": f"USER:ツイートして ASSISTANT:{row['full_text']}"}
            file.write(json.dumps(formatted_data, ensure_ascii=False) + "\n")


# 各データセットを対応するJSON Linesファイルに変換
df_to_jsonl(train_df, "./train.jsonl")
df_to_jsonl(valid_df, "./valid.jsonl")
df_to_jsonl(test_df, "./test.jsonl")

トラブルシューティング

pandas を使う場合は pipenv 配下だとエラー (Segmentation fault) になります
なので pip でインストールしてその配下で使いましょう

最後に

次回はこのデータを使って MLX + LoRA をしてみたいと思います

2024年5月25日土曜日

M2 mac mini 上で mlx を使って LoRA Fine-Tuning をしてみる

M2 mac mini 上で mlx を使って LoRA Fine-Tuning をしてみる

概要

前回の Google Colab 上で動作させたコードを mlx 化して M2 mac mini 上で動作させてみました

環境

  • macOS 14.5
  • Python 3.10.12
  • mlx 0.13.1
  • mlx-example 69700d84

準備

  • pyenv install 3.10.12

プロジェクトセットアップ

  • git clone https://github.com/ml-explore/mlx-examples.git
  • cd mlx-examples/lora
  • pyenv local 3.10.12
  • pip install -r requirements.txt

モデルのコンバート

LLaMA ベースの日本語モデル elyza/ELYZA-japanese-Llama-2-7b-instruct を更に safetensors 化したモデルを使います

  • python convert.py --hf-path 4bit/ELYZA-japanese-Llama-2-7b-instruct -q --q-bits 4

コンバートしたモデルは mlx_model 配下に作成されます

  • ls -1 mlx_model
config.json
model.safetensors
model.safetensors.index.json
special_tokens_map.json
tokenizer.json
tokenizer_config.json

データセットのコンバート

データセットのフォーマットが少し独自なので変換する必要があります

ここから databricks-dolly-15k-ja-ojousama.json をダウンロードし ojousama ディレクトリ配下に保存します

こちらのスクリプトを拝借して test.json, valid.json, test.json を作成します

  • pip install pandas scikit-learn
  • vim data_convert.py
import json

import pandas as pd
from sklearn.model_selection import train_test_split

# 元のサンプルデータのファイルパス
input_json_file = "./ojousama/databricks-dolly-15k-ja-ojousama.json"

# JSONデータをPandas DataFrameに読み込む
df = pd.read_json(input_json_file)

# ターゲットをclosed_QAとopen_QAに絞る
df = df[(df.category == "closed_qa") | (df.category == "open_qa")].reset_index(
    drop=True
)

# テキスト長が短い学習データTOP1300をデータセットとして扱う
# 学習に時間がかかる場合もしくはメモリを使いすぎる場合は ascending=True にして短い順にするか 1300 の数を小さくすること
df["length"] = df.instruction.str.len() + df.output.str.len()
df = df.sort_values(by="length", ascending=False)
df = df.head(1300)

# データフレームをシャッフル
df = df.sample(frac=1).reset_index(drop=True)

# validとtest用のデータを100件ずつ取り出し、残りをtrainに分割
valid_df, remaining_df = train_test_split(df, test_size=len(df) - 100, random_state=42)
test_df, train_df = train_test_split(
    remaining_df, test_size=len(remaining_df) - 100, random_state=42
)


# ヘルパー関数:データフレームを新しい形式でJSON Linesファイルに変換
def df_to_jsonl(df, file_name):
    with open(file_name, "w", encoding="utf-8") as file:
        for _, row in df.iterrows():
            formatted_data = {
                "text": f"USER:{row['instruction']} ASSISTANT:{row['output']}"
            }
            file.write(json.dumps(formatted_data, ensure_ascii=False) + "\n")


# 各データセットを対応するJSON Linesファイルに変換
df_to_jsonl(train_df, "./ojousama/train.jsonl")
df_to_jsonl(valid_df, "./ojousama/valid.jsonl")
df_to_jsonl(test_df, "./ojousama/test.jsonl")
  • python data_convert.py

で各種 json ファイルができれば OK です

ls -1 ojousama
databricks-dolly-15k-ja-ojousama.json
test.jsonl
train.jsonl
valid.jsonl

学習させるデータ量について

完結に言うと

  • 文章をたくさん学習させたほうがいいがメモリが足らなくなる
  • 文章が短いと短い文章しか生成してくれなくなるがメモリは少なくて済む

という感じなのでデータセットを作成する際に以下のように文章の長さと文章数を調整すると良いです

# 質問+解答の長さを length というフィールドに登録
df["length"] = df.instruction.str.len() + df.output.str.len()
# 文章が長い順にソート
# df = df.sort_values(by="length", ascending=False)
# 質問+解答の長さが200文字以上400文字以下のみ抽出、この条件で734件で14GBほどメモリ消費
filterd_df = (df["length"] >= 200) & (df["length"] <= 400)
df = df.loc[filterd_df]
# あとはここを調整、1300以下ならそのままで OK
df = df.head(1300)

Fine-Tuning

  • python lora.py --model mlx_model --data ojousama --train --iters 600

iters で学習回数を指定できます
その他学習時のパラメータは python lora.py --help で確認できますが TrainingArguments で指定可能なパラメータすべてを指定できるわけではないようです

結果は以下の通りでだいたい5時間ほどかかりました (学習させるデータを短い版にすると1時間ほどで完了しました)
adapters.npz という numpy ベースのファイルができれば OK です

動作確認: 推論

  • python lora.py --model mlx_model --adapter-file adapters.npz --prompt "USER:日本の首都は? ASSISTANT:"

結果

Loading pretrained model
Total parameters 1055.199M
Trainable parameters 2.097M
Loading datasets
Generating
USER:日本の首都は? ASSISTANT:ワタクシ思いますの、 東京は、日本の首都ですわ 
ξ゚⊿゚)ξ
==========

使用したモデル

使用したデータセット

最後に

M2 mac mini 上で LLaMA ベースの日本語モデルを LoRA Fine-Tuning してみました
スクラッチではないので細かいところまで手は届きませんが性能的にはこれで十分かなと思います
また mlx に対応しておりフルに GPU を使って学習してくれるので Apple Sillicon 上でもそれなりのスピードが出せます
やはり M2 上では mlx が必須のようです

過去にいろいろな webui 系のツールを試してみましたがそれらも mlx に対応してくれると Apple Sillicon 上でも機械学習がやりやすくなるのかなと思いました

参考サイト

2024年1月31日水曜日

Python の oepnai-whisper で Speech-to-text したので結果のメモ

Python の oepnai-whisper で Speech-to-text したので結果のメモ

概要

M2 mac mini 上で openapi-whisper を動かして音声解析してみました
音声ファイルが大きい場合は素直に mlx 経由で実行しましょう

環境

  • macOS 14.2.1 (M2 pro mac mini)
  • Python 3.11.6
  • openai-whisper 1.1.10
  • MLX 0.0.10

インストール

  • pipenv install openai-whisper

サンプルコード

import whisper

# モデルは large を使用
model = whisper.load_model("large")
# 解析
result = model.transcribe("/path/to/audio.m4a")
# ファイル書き出し
with open("result.txt", mode="w") as f:
    f.write(result["text"])

使用モデル

  • large
  • ファイルサイズ 2.88G

音声ファイル

  • m4a ファイル
  • サイズは 45.41MB
  • ビットレート 64kbps

解析時間

  • 不明 (かなりかかりそうなので途中でやめて mlx 形式にしました)

MLX 経由で実行する

以下は MLX を使って whisper を動作させる方法です
こちらを参考に設定していきます

clone

  • git clone https://github.com/ml-explore/mlx-examples.git

初期化

  • cd mlx-examples/whisper
  • brew install ffmpeg
  • pipenv install -r ./requirements.txt

モデルのコンバート

pytorch で作成された whisper のモデルを mlx で使用可能なモデルに変換します
もしかすると hugging face の MLX Community を使えば自分でコンバートする必要はないかもです

  • pipenv run python convert.py --torch-name-or-path large --mlx-path mlx_models/large
[INFO] Loading
[INFO] Saving

生成されるファイルは以下のとおりです

tree mlx_models
mlx_models
└── large
    ├── config.json
    └── weights.npz

2 directories, 2 file

スクリプト作成

  • vim app.py
import whisper

# 生成したモデルと音声ファイルを指定して解析
result = whisper.transcribe(
    "/path/to/audio.m4a", path_or_hf_repo="mlx_models/large", verbose=True
)

# ファイル書き出し
with open("result.txt", mode="w") as f:
    f.write(result["text"])

ここで import している whisper.transcribe は mlx-examples が独自で修正している transcribe.py になります
なので path_or_hf_repo というパラメータが指定できます

実行

  • pipenv run python app.py

今回の場合成功すれば result.txt にテキスト情報がそのまま保存されます

解析時間

  • 約1時間

GPU はほぼフルで使っていました
スペックによってはさらに速くなるかなと思います

最後に

mlx + whisper で M2 mac mini 上で音声解析してみました
精度はかなりいいので Google の Speech-to-text レベルのものがローカルで動作するようになります
スペックの低いマシンではかなり時間がかかるのでそれなりのスペックのマシン特に GPU のあるマシンを使って解析することをオススメします

また mlx を使うことで GPU をフルに使って解析するので時間も短縮できます

language='ja' というキーワード引数を指定しなくても自動で日本語だと判断してくれましたが入れてもいいのかもしれません
verbose=True を指定すると自動検出した言語を print デバッグしてくれるので試しに入れてみてもいいのかもしれません
また verbose=True は解析の経過も表示してくれるのでファイルが大きい場合は入れたほうがいいかなと思います

参考サイト