2024年6月26日水曜日

mlx-examples の LoRA を使って kakakikikeke っぽいツイートを自動生成してみた

mlx-examples の LoRA を使って kakakikikeke っぽいツイートを自動生成してみた

画像生成は stable-diffusion を使いました
音声生成は RVC を使いました
今回は文章生成をします

環境

  • macOS 14.5
  • Python 3.10.12
  • mlx-examples 69700d84

学習データの作成

Twitter のアーカイブデータを使います
アーカイブデータ内に tweets.js というツイートを管理しているファイルがあるのでそこから学習データとテストデータと評価データを作成します

学習させるツイートの元では 3 万件ほどありますが全部は学習させません
本当は全部学習させたいのですがマシンのスペックも考慮して 1300 件にしています
テストと評価データはそれぞれ 100 件ずつです

wc -l my_tweet/*
     100 my_tweet/test.jsonl
    1100 my_tweet/train.jsonl
     100 my_tweet/valid.jsonl
    1300 total

このデータセットの量でだいたい 1 時間ほどで LoRA を生成できるので 3 万件学習させても 4 日ほどあれば終わるかもしれません

学習データ作成スクリプト

以下 tweets.js を解析して学習データを作成するための Python スクリプトです
pandas と scikit-learn が必要になります
json ファイルを解析するだけなので pandas も scikit-learn もなしで解析することもできます

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)
print(len(df.index))

# データフレームをシャッフル
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")

最終的には3つのファイルが作成できればいいので解析方法はおまかせします

ベースモデル

学習させるデータが日本語なのでベースモデルも日本語に特化したものを使ったほうがいいです
今回は https://huggingface.co/4bit/ELYZA-japanese-Llama-2-7b-instruct を使いました
また mlx は専用のフォーマットにモデルをコンバートする必要があるのでモデルをダウンロードしたら mlx-examples に含まれる convert.py を使って変換します

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

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

学習

生成した学習データと変換した ELYZA のベースモデルを使って LoRA アダプタを生成します

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

反復数も学習時間に影響するためあまり大きくすると学習時間が増えるので注意してください
600 回と 1300 件の学習データで約 1 時間で終了しました

推論

あとはテストします

  • 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:iot_device には iot_device って何だよ、デバイス�も実装したいというときはどうすればいんだろうか。ま�、ros bond とかと同じ�じかな、デバイスに�する
  定を管理するクラスを作るだけだよな

何度か生成してみます

Loading pretrained model
Total parameters 1055.199M
Trainable parameters 2.097M
Loading datasets
Generating
USER:ツイートして ASSISTANT:10.5 10.6 10.7 、、、、10.9 10.10 10.11 を使うために 10 にしてるのか。ios の場合は 10.12 とかだからちゃんとやってるな、という�じ
==========
Loading pretrained model
Total parameters 1055.199M
Trainable parameters 2.097M
Loading datasets
Generating
USER:ツイートして ASSISTANT:airplay の機�ってどこの�品があるんだろうか。これから発表していくためにはコンテナに入れておかないとダメなのだろうか。����も����も結果は同じという
  とを�り返していく
==========
Loading pretrained model
Total parameters 1055.199M
Trainable parameters 2.097M
Loading datasets
Generating
USER:ツイートして ASSISTANT:その google colaboratory だとあるスクリプトをコードで����すか、、、コードの�分ってやつですが、、、そのためにコードの変更�所を����のがいいんだけ
  そのためにもしくは使えるのが
==========

この文字化けは何とかならないのだろうか、、

おまけ: 文字化け対策

てっとり早く対応する場合は生成されたいろいろ弄る前のトークンを最後に print すれば OK です

git diff
diff --git a/lora/lora.py b/lora/lora.py
index a90eda7..411f558 100644
--- a/lora/lora.py
+++ b/lora/lora.py
@@ -312,6 +312,7 @@ def generate(model, prompt, tokenizer, args):
             skip = len(s) - 1
     print(tokenizer.decode(tokens)[skip:], flush=True)
     print("=" * 10)
+    print(f"{s} \n\n")
     if len(tokens) == 0:
         print("No tokens generated for this prompt")
         return

文字化け対策して10個生成してみました

結局その一緒に遊ぶやつとセットにしないとダメなんですか。通信量かかりますが gps ロガーつけている状態じゃないとダメなんですか。そういうわけだからバックグラウンドでおいておいておけばいくらか 

customerservice ルートにログインしたときに dns コマンドによってクラスタの dns サービスを停止していたため、ルートからクラスタにリクエストが行けなくなっていたようだな。対応はわかっているけど now  

docker-compose 使うときは pod とか swarm とかクラスタとか pod とか svc とか nil じゃないという感じのものを指定しないといけないんだけどなー、、、どうすればいいかなー、、、なんかいなくてないのだろうか、、、 

docker-compose の場合、ローカルの machine 名の前に 0 をつけてくればどこでもインストールできるようになったのかな、、docker の proxyswarm とかはプロキシの指定が必要とか面倒だからなー。salt の場合のマシン名でコ 

docker-compose とか YouTube とかで配布するのに役立っているのがコンテナってやつとかパブリッシュなのにコンテナが必要だとか結構あるのかな、コンテナのためのコンテナってのがあるけどどういうことなんだろう 

自前の処理って製品の説明書?移行前のデータをどこまでコピーするのかとかは援助しないかな。そういう時には「自前の処理」という概念がないから。そもそも仕様がわからんわけ 

ブログから個人サイトのための micro-flutter を作るってなると github を使ってできない理由はないだろうけど、blog を用意するとなってみんなが悩むのは同じで、その問題を解決するためにサービスがいくつ 

windows 折りたたみ式のマウスって結局何がいいんだろうか。マウスとして普通の押し出し式のもがいいから私が把持って操作したい、そして折りたたんで持ち歩きたいっていうのが気持ちだった 

確かに android 12 が 2020 年 9 月というのはかなり早い感じ。アップグレードのスケジュールはかなりの傾向があるような気がする。だけどいろいろと理由はあるんだろうか。最終的には google 

iPhone の時のプライスタグが貼り付けできないのか、実は AppStore のプライスタグが使えないのか。 tinder は使っているのにおかしい、とか思う人は apple の審査厨になっているから 

考察: 学習させるデータの修正

今回は「ツイートして」という質問に対して適当にサンプルしたツイートを学習させています
コンテキストも何もない状態の質問なので本当にランダムなツイートを生成してしまいます

ツイートする場合には本来ある程度のコンテキストが含まれていることがあり例えば梅雨の時期だったら雨に関するツイートをしたりだとか WWDC が Google I/O が開催される時期なので Apple や Google に関するツイートをしたりします
なので学習させるデータの質問にコンテキストを持たせることができれば特定の事柄や事象、特定の言葉を含んだツイートを生成することができます

単純に「ツイートして」という質問を学習させるのではなく「6月の雨に関するツイートをして」という感じで質問をカスタムできれば生成する際にも6月の雨に関するツイートを生成することができます
実際に生成する際の質問も「ツイートして」だけではなくテンプレートなどを使って「X月のYYYに関するツイートをして」という感じで自動で X, Y を埋めるようにすればコンテキストを持たせた文章を生成することができると思います

時期に関しては tweets.js に含まれているので簡単に学習データに含ませることができそうですが「YYY に関する」の部分はそう簡単にはいきません
例えばツイート情報を形態素解析してもっとも頻出している単語を YYY に設定することができそうですがそれだけだと正確なコンテキスト情報としては少し甘い気がします
ツイートに「Apple」や「Google」など特定の単語が含まれていれば問題ないですがそうでないツイートもたくさんあり単純のカウントではダメなケースがあります
なのでちゃんとやるのであれば例えばツイートの種類のようなものを判定する必要があるかなと思っており例えば「こんにちわ」や「ねる」「はぁー」みたいな文章ではなく短い単語のみのツイートはコンテキストなしという分類にし特定のコンテキストなり得る単語を含むツイートはコンテキストありとしてその場合は形態素解析を使ってそのツイート内に出現する特徴語を抽出してそれを「YYYに関する」の部分に設定すればそれっぽいコンテキストにはなるかなと思います

このあたりはツイートの自動タグ付けやネガポジ判定のような世界になってくるので論文を漁れば手法は死ぬほど出てくると思います

という感じで学習させるデータをもう少し工夫できれば完全ランダムなツイートしか生成しない問題を解決できるかなと思っています

最後に

まだまだ改善の余地はありそうですが自分っぽいツイートをする流れはだいたい把握できました
あとは学習データを修正したり生成時のプロンプトを変更すればもっと自然なツイートになるかなと思います

これまで画像、音声とやってきましたが文章生成が一番たいへんなイメージです
「自然な」日本語にするのがすごい難しいです

2024年6月15日土曜日

iOS 版ドラゴンクエスト7をプレイしたのでメモ

iOS 版ドラゴンクエスト7をプレイしたのでメモ

変数が表示されないバグとかどうでもいいのでとにかく急に落ちるのを何とかしてほしい

環境

  • iPhone14 (iOS )
  • iOS 版 DQ7 1,220円 (2021年に購入)

プレイ時間

  • 約100時間
  • そのうち10時間くらいはカジノの自動化で放置していた

ゲームの進行について

  • 全体的にマリベルのイオ系が強すぎる
  • 全体的にボスはせいけんづき+バイキルトが強すぎる
  • 主人公とガボはしばらくブーメランで大丈夫
  • ボスは「ぼうぎょ」x3、マリベルのルカニで二段階下げてからガンガンで大体勝てる
  • 行ったり来たりが辛い
  • 後半は正直どこに行けばいいのかわからないことが多いので素直に攻略サイトを見たほうがいい
  • とうぞくのはなでは見つからないアイテムはレミラーマをしないと発見できない、レミラーマはちいさなメダル目的
  • ダンジョンの地図がデフォルトで使えるのはいい
  • 石版交換でメタル系が出る石版を手に入いれれば序盤から楽にクリアできてしまう
  • 上級職で覚えたじゅもんや特技や上級職を辞めると忘れてしまう、おそらくリメイク版での仕様
  • 主人公もガンガンいこうぜとかできると楽だった

オルゴデミーラ討伐時点でのレベル

  • ダークパレスに行ける段階で石版をやり込んだのでレベルは60を超えていた
  • プレイ時間は50時間程度
  • 風のアミュレットを使ってそのままクリア
  • じゅくれんどは基本職が8割、上級職が2割くらい終わっている状態

神さま討伐時点でのレベル

  • この時点でのプレイ時間は100時間程度
  • じゅくれんどは基本職、上級職がカンストで特級職もほぼ終わっている状態
  • やりすぎた
  • 4精霊も同じレベルで状態でクリア
  • Lv99 スライムマジュラの地図がラスボス

ゲームの操作について

  • 画角が狭すぎる、調整できない、ゆえに周りを確認しづらい
  • 3D酔いしそう
  • ツボやタンスを調べるときに村人が近くにいると割りづらい
  • 序盤のカラーストーン採掘場の石の操作が難しすぎる
  • ちいさなメダル数や熟練度の数を確認するときに変数が展開されずに変数名が出るバグがある

レベル上げ

  • クリアするだけなら基本はやる必要なし、普通に進行していればそれなりのレベルになる
  • やるなら石版交換のメタルダンジョンでまじんぎり
  • 熟練度上げを優先しないと先に Lv99 になってしまうので経験値がもったいないことになる

熟練度

  • 自作の石版なら何でも OK

最強パーティ

  • しんぴのよろいが装備できるのでガボを抜いたパーティがよさそう

やりこみ要素

  • ちいさなメダル
  • モンスターパーク (いいモンスター石版集め
    • はやぶさのくつ (スタンプ150
    • レアアイテム (ボス敵ドロップ
  • モンスター職
  • レベル99
  • じゅくれんど

アイテム、お金稼ぎ

  • 石版でタルが大量に出るフィールド (カラーストーン採掘場の入口、どっかの塔の入口) があるのでそこでタルを割って即帰宅を繰り返す

カジノコイン稼ぎ

  • 昔作った自動タップくんを使って 100 コインスロットで一日回せば勝手に MAX までいってくれる

種稼ぎ

  • やってないがモンスターを倒すしかなさそう

モンスター石版について

  • 強いボスだとレアアイテムをドロップすることがある
  • 同じ名前の地図は一度クリアするとレアアイテムはドロップしないっぽい
    • -> あくまでも確率だから周回していれば落ちるっぽい
    • 自分が生成した石版でサタンメイルがボスの地図を何回も周回したら何回も「真しんぴのよろい」が手に入ったので運次第
  • Lv99 の人が作っている地図は基本長い
  • Lv99 の人が作っている地図でもボスが弱いことがある
  • 連れて行ったモンスターが作成された石版に出現する
  • 先頭に設定したモンスターがボスになる
  • 詳しくはこのあたりを参照

最後に

石版のせいでゲーム性が崩壊しているので石版を利用はほどほどにしましょう