typst-llm.md (11610B)
1 # 想定読者 2 3 この記事の想定読者は以下の人です.専門用語に関しては,検索すれば出てくるものとして,こちらで注釈を付けることはしません.誤用などあればコメント下さい. 4 5 - ローカルLLMの開発の経験のある人 6 - LLMのファインチューニングの知識がある人 7 8 # はじめに 9 10 本記事は,ローカル環境でLLMを動かし,物理学実験のレポートを提出前にレビューするアプリケーションを作ってみた備忘録です. 11 最終的な目標は,Typstで書かれた物理学実験のレポートに対し,教員から提示されるであろう指摘事項を前もって指摘してくれることです. 12 なお,当該リポジトリは私の書いた実験レポートそのものが含まれる学習データがありますので,Private Repositoryになっています. 13 公開できる部分は公開したいのですが,記事に書き込んでしまうと冗長なのと,Geminiに同じことを頼んだら,同じようなコードが返ってくると思いますので,擬似コードだけ置いておきます. 14 学習に使用したデータはレポート2本とその指摘事項です.圧倒的に少ないですね. 15 16 ## 初期計画と環境コンテキスト 17 18 プロジェクト開始時の主要な計画と環境は以下の通りです. 19 20 ### 動作環境 21 | 項目 | 詳細 | 22 | :--- | :--- | 23 | OS | Windows 11 | 24 | CPU | AMD Ryzen 9 3900XT (12コア/24スレッド) | 25 | GPU | NVIDIA GeForce RTX 3060 | 26 27 ### モデルと手法 28 | 項目 | 詳細 | 29 | :--- | :--- | 30 | ベースモデル | Mistral 7B (GGUF 形式) | 31 | ファインチューニング | QRoLA | 32 33 34 # 仮実装 35 ## 環境構築 36 37 とりあえず初期計画のために環境を整えます. 38 どっかでPythonのパッケージマネージャーとしてRust製の`uv`ってのが巷で流行っているという話を聞いたので,今回は`uv`を使います. 39 それにしてもRust製のPythonパッケージマネージャーなんて,もはやRustにしちまえよって感じですけどね.学習コストが高いんでね. 40 環境構築は備忘録的に書いた`README.md`の中身を掲示して置くことで代替とします. 41 ```Markdown 42 # Prepare Python 43 ## create venv 44 ### install uv 45 `pip install uv` 46 ### create .venv 47 `uv venv .venv` 48 ## activate venv 49 `source .venv/bin/activate` 50 if you use windows powershell, use `.\.venv\Scripts\activate.ps1` 51 52 ## install requirements 53 `uv pip install -r requirements.txt` 54 55 ## setting for cuda 56 please make sure you have cuda installed and set the environment variable CUDA_HOME to the path of your cuda installation. 57 check for it can do with `nvcc --version` 58 and install pytorch for your cuda version. 59 for example nvcc version is 13.0 60 `uv pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu130 --reinstall` 61 And then, check this python env can use cuda with `python gpu_check.py` 62 63 ## set API key for gemini(only need to use structuring-training-data) 64 `export GEMINI_API_KEY=your_api_key` 65 if you use windows powershell, use `$env:GEMINI_API_KEY="あなたのAPIキー"` 66 ``` 67 厳密にはMarkdownのベストプラクティスには従ってないですが,許してください.読めりゃ,わかりゃいいんですよ. 68 なぜかGPUに対応したPyTorch等が入らなくて,なんでだろうなとか思ってたら,そもそもPCに`cuda`がインストールされてませんでした. 69 ## 学習用データ 70 71 自分の書いたレポートとそれについた指摘事項を統合して学習データにします. 72 指摘事項とそれに当たっている部分を抜き出してセットにして入れるといいみたいなのですが,そのJSONを書くのがめんどくさかったので,GeminiのAPIを叩いてJSONを返してもらってます. 73 74 次に,まとめられたJSONとレポート本体を合体させ,さらに合体した各レポートのセットを一つのjsonlファイルに合体させます. 75 レポートを連番にして,連番毎にレポートのtypstファイルと指摘事項のtxtファイルを学習用データのディレクトリに入れて,それを読むようにすれば,学習用データが多くなっても安心です. 76 77 ## 学習 78 79 いよいよ学習です. 80 学習プログラムの入力はjsonlで出力はアダプターのアセット達です. 81 それぞれ設定値です. 82 83 | パラメータ名 | 値 | 84 | :--- | :--- | 85 | **ベースモデル** | `Mistral-7B-Instruct-v0.2` | 86 | **量子化 (4bit)** | `load_in_4bit=True` | 87 | **量子化タイプ** | `bnb_4bit_quant_type="nf4"` | 88 | **LoRA R (ランク)** | `16` | 89 | **LoRA Alpha** | `32` | 90 | **バッチサイズ** | `1` | 91 | **勾配蓄積** | `4` | 92 | **学習率** | `2e-4` | 93 | **最大ステップ数** | `50` | 94 | **FP16** | `True` | 95 96 ## GGUF化 97 98 先程の出力をllama.cppでRoLAしたモデルを読み込むために,GGUF化します. 99 Gitのサブモジュールとして,llama.cppをクローンして,リポジトリのルートでこのコマンドを叩けばできます. 100 ``` 101 python vendor/llama.cpp/convert_hf_to_gguf.py mistral_typst_merged --outfile mistral_typst_merged.f16.gguf --outtype f16 102 ``` 103 (`mistral_typst_merged`はモデルのディレクトリ,`mistral_typst_merged.f16.gguf`は出力です) 104 105 ## 量子化 106 107 リソースバカ食いの可能性を危惧して,モデルを量子化します. 108 ただ,何故かllama.cppの量子化が上手く動かなかったので,公式ビルドを落としてきてバイナリを叩いて量子化しました. 109 110 ## APIサーバー 111 112 何をトチ狂ったのか,私はこの推論をAPIサーバーにしようと考えて,PythonでAPIサーバーを立て始めました. 113 もともとはフロントエンドアプリをつけて,APIだけを自宅サーバーに立てて叩きたいなと思っていた名残です. 114 名残を実装に反映してしまうのがGeminiの悪い癖ですね.自分は間違わないと思っているのか,モジュールテストとかをしない方向で動いているように見えます. 115 冗談はさておき,このAPIサーバー,とても重大な欠陥がありました. 116 モデルがJSONでない形式で返してきたときにパースエラーが起きるんです. 117 APIの行き帰りは厳格にJSONでなければなりませんが,量子化したモデルにそれをやらすのもそもそも無理があります. 118 良く見てみると,トランスフォーマー型らしいと言えばそうなのですが,一行一行に対して支離滅裂な指摘事項が挙げられていて,到底設定したいた`max_tokens`では足りずにパースエラーを起こしていました. 119 120 ## 仮実装で露呈した問題点 121 122 - JSON形式の破壊 123 - 量子化の問題 124 - CPU推論 125 126 です.次の章から順番に説明と施した対策を挙げていきます. 127 128 # JSON形式 129 130 そもそもモデルに(それも量子化した)JSONを書かせるなんてエラーの元ですし,APIにしたいなら,出てきたテキストをそのままJSONにぶち込むように変更すればいいので,JSON形式で出力させるようなプロンプト(システムイントロダクション)は削除しました. 131 そしてAPIサーバーを立てて,それを叩くpythonを作ってとやっているのが無駄なので,モデルを直接読み込んでtypstファイルをぶち込むようなpythonプログラムを書きました. 132 133 # QLoRAの問題 134 135 JSON問題が解決しても,回答の長さが`max_tokens`を軽々と突破する問題は依然として存在しました. 136 そこで,私は諦めて量子化されていないf16のモデルを使いました. 137 するとどうでしょう.10行程度のリストに収まりました. 138 139 # CPU推論 140 141 推論を動かしていると,CPUとDRAMの使用率が最大に張り付きます.当然ですね.f16なLLMをローカルで動かしているのですから. 142 問題はそこではなくて,GPUを使ってくれないという点です. 143 私が1年前くらいに奮発して買ったGDDDR5が12GBも積まれているRTX3060をせっかく搭載しているというのに,一個も使わないんです. 144 QLoRAではバイナリのバージョンを揃えてインストールしたので,llama.cppでも同様のことをしようと思ってやりました. 145 参考にさせていただいた記事です. 146 https://zenn.dev/hellohazime/articles/ccd01c2df0b5c3 147 でも,インストールに失敗しました. 148 仕方ないので,環境変数による強制ビルドをしました. 149 ```PowerShell 150 $env:CMAKE_ARGS='-DGGML_CUDA=ON -DCMAKE_CUDA_COMPILER="C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v13.0/bin/nvcc.exe" -DCUDA_TOOLKIT_ROOT_DIR="C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v13.0" -DCUDA_ARCHITECTURES=native' 151 $env:FORCE_CMAKE=1 152 uv pip install -r requirements.txt --no-cache-dir 153 ``` 154 これでも失敗しました. 155 エラーログに`Use GGML_CUDA instead` 156 って書いてあったので,次の記事を参考にmakeの環境変数を書き換えしました. 157 https://qiita.com/Nikeri/items/27490eb865c42803d14c 158 それでもエラーは止まりません. 159 ``` 160 No CUDA toolset found. 161 ``` 162 意味がわかりません.ご丁寧にnvcc.exeのパスを入れてるのに,無いとか言われるんですからもうどうしようもないです. 163 今は諦めてCPUで推論を回してますが,時間と電気代がかかるのでぜひともやめてほしいところです. 164 Gemini君が言うにはDLL地獄という状態らしくて,もう手が付けられないです. 165 166 # 今後への課題 167 168 現状の問題点は以下の2つです. 169 - CPUで推論している 170 - レビューの品質が低い 171 172 前者については前章で述べたので後者について述べます. 173 レビュー品質が低い原因は色々と考えられます. 174 当初は50ステップとしていたLoRAですが,25ステップのあたりでlossが0.1412とかまで下がってるので,過学習が疑われます. 175 25ステップにすると,ファジーさはだいぶ弱まりましたが,全体的に当たらない指摘をしている部分が多いです. 176 開発途中に教員のレビューを受けたレポートが一本増えたので学習用データに追加してみましたが,反応は芳しくないです. 177 他の人のレポートを学習用データとして入れればもっと良いのですけどね. 178 179 # まとめ 180 181 レポートのレビューをするLLMをLoRAで作るには,まだ超えなければならい壁が幾つもあるように思います. 182 私のこれも到底,学科の仲間には見せることができない出来栄えですからね. 183 人間の脳も大概,説明可能性に欠けていると思うのですが,それを補おうとしてきた科学とそこから生まれたそれに矛盾する再現性のない深層学習. 184 その表層にちょっとでも触れることができたかなと思います. 185 皆さんはくれぐれも,これを応用して,教科書の内容からレポートを生成しようなんて思わないでくださいね. 186 科学の自壊が進んでしまわないように.