加藤純一クローンAIプロジェクトその1 データ収集システムとプロトタイプ

加藤純一さんの雑談データから人格のクローンとなるようなAIを作り、最終的には雑談配信ができてしまうことを目標にしています。
データ作成やGPU計算などの協力者も欲しいですが、SNSは特にやっておらず、Youtube向けに動画編集する時間もないので、ひと段落する度にQiitaにアウトプットして存在感を示したいと思います。AIの出力結果を意識的に紹介したいと思いますので、技術に興味のない方もAIの成長を楽しんでもらえればと思います。
やったこと・次やること・課題点のフォーマットでお届けします。このシリーズは[「加藤純一クローンAI」タグ](https://qiita.com/tags/%e5%8a%a0%e8%97%a4%e7%b4%94%e4%b8%80%e3%82%af%e3%83%ad%e3%83%bc%e3%83%b3ai)をつけますので、バックナンバーはそちらから確認できるようにします。

## やったこと
### データ収集システム

* [工作グランプリ](https://www.youtube.com/watch?v=sGyNAR7EN4s)にて[KATO DB](https://huggingface.co/spaces/konbraphat51/Kato-DB)を紹介していただきました。
UIがゴミでした。悲しい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/74094b7e-3570-4916-7147-0813925522cd.png)

* 動画取得→AI書き起こし→データ整理のワークフローを自動化したシステムです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/04301d82-44d7-ec16-c35b-c14699d3b576.png)
Githubレポジトリ：https://github.com/konbraphat51/kato_db

* GPUフル稼働でも加藤さんの雑談をフルカバーするのはまだまだです。加藤さんの雑談アーカイブ動画は2800点ほどあり、現在1000点処理できている段階です。GPUが過労で寿命が縮まっていないか心配。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/22be9610-e6f4-67e0-235a-2604baa6ae3a.png)



### プロトタイプAI作成
下記に記録したAIを遊べるgoogle colabを用意しています。手順を書いていますのでプログラミング全く知らない人もご体験いただけます：https://colab.research.google.com/drive/1QsJN50wvLEJx04P4XaBtsKqx1q3532OU#scrollTo=FtlRxOVMCk-5

サイバーエージェント社が開発した日本語LLM「Open-CALM」のファインチューニングが自分のGPUで可能か+どこまで喋れるかを調査する目的で、プロトタイプAIを急造しました。コードは汚くて見せられたものではありません。

※ファインチューニング = 加藤純一の思想・口調・知識を取り込む、真似る

#### 僕のPC性能
CPU: 13世代intel i7
GPU: GeForce RX4070 12GB
メモリ: 16GB

#### プロトタイプ1号：そのままファインチューニング
##### 手法
[水色桜さんの記事](https://qiita.com/Mizuiro__sakura/items/058d2590d31e9f8aeeaa)に従って、`small`, `medium`モデルに関してファインチューニングしました。

課題設定を単純化するために、
>入力：Q.（主語）についてどう思う？A.
>出力：Q.（主語）についてどう思う？A. (AI出力文章)
というように入力を「どう思う？」に固定しています。

データセットは、キーセンテンス抽出ライブラリRAKEを使用して、雑談データの各文章のキーセンテンスを主語に設定し、その文章を出力とするデータセットを用意しています。発言は2015年のものからランダムに。

transformersライブラリの`Trainer`クラスに、データセットとして入力文章を`inputs_id`、出力文章を`labels`に指定して学習。

データ30点で1時間ほどかかりました。`large`モデルは、メモリ不足により対応不可能でした。

##### 結果
入力：「加藤純一についてどう思う？」

`small`モデル：
>Q:加藤純一についてどう思う? A. A A加藤の加藤純な行いつも加藤加藤明治清介行行清一の行って加藤清明戦の行感感ただいつもナベヘリ高山について行てな球感高山の加藤加藤だよ明治加藤遣一のあの加藤錦の加藤の加藤慶平加藤慶平は加藤アル之原加藤承平明治の加藤舜

>Q:加藤純一についてどう思う? A. A A加藤の加藤ねえの加藤でそれで私は則一の純一郎と加藤加藤一のべた清一の伊藤加藤平一のシャネルと東平加藤なんで加藤でいい。純な加藤で加藤基一のクロード加藤だよこれルネなる加藤恭一のユニクロ加藤慶一のジム浩一郎の加藤加藤清一の加藤の加藤だよ加藤くん

だめですね。さすがに`small`モデルでは無理でしょう。それとOpen-CALMの元データの片鱗が出てきています。ファインチューニングのデータ数30では仕方ないか。

`medium`モデル：
>Q:加藤純一についてどう思う? A. やってる加藤がちょっとブサイクで見んないね A。ブサメンと加藤のどっちがブサなの Aとった加藤ちょっとブスだね Aがしたの加藤ちょっとね。ちょっとねぇねぇちょっとちょっとちょっとな加藤とどっちのがブサタねぇちょっとのブッサねぇどっちの加藤ブッサンねぇもうちょっと

>Q:加藤純一についてどう思う? A. 全然面白くなかった。 A1.ちょっと面白くない A2.別に面白くはない A3.面白いのかな A4.でもちょっと面白く見れる A5.ちょっとな A6.面白くねぇ A7.なんかちょっとちょっとちょっとい A8.何も面白くなねぇ Bingo1がちょっとおもしろかった

このモデルはなぜか「加藤純一」が嫌っていて面白いです。本家から口の悪さだけを覚えたのでしょうか。日本語文法はあっています。勝手に新しい回答形式を生み出したのはデータ数が少ないからでしょうか。

#### プロトタイプ2号：int8量子化
偶然[masashi-aiさんの記事](https://qiita.com/masashi-ai/items/df9b81908d7d7639b7fb)を見つけ、なんとモデルをパラメーターがfloat32のところをint8で計算すると空間計算量が1/4倍になるという。
計算精度が「少し」落ちるらしいが、どこかで大規模機械学習に計算精度はあまりいらないという論文を読んだ気がするので（ソースを思い出せない）、精度ぐらい別にいいだろという判断で、ファインチューニング時、出力時の`from_pretrained()`関数の`load_int8`パラメーターを`true`に。

すると`large`, `1b`, `3b`モデルのファインチューニングに成功。

ところが、出力時に行列計算関係のエラーが発生。2回試し、2回とも異なる行列計算エラーが発生しました。
>Given normalized_shape=[x], expected input with shape [x, x], but got input of size[x, x, x, x]

数値は覚えていないが、このようなエラーと、もう一方もなにかやらかしていました。（記録を取っていなかった...orz）

自分のコードに悪さが見当たらなかったので、別のint8を使える手段を講じます。

#### プロトタイプ3号：LoRAファインチューニング（失敗）
とりあえず動くことが保証されている事例を取り込もうという判断から、[npakaさんの記事](https://note.com/npaka/n/na5b8e6f749ce)を取り込みました。
LoRAファインチューニングを行うことにより、さらにGPUメモリ使用量を抑えることができるとのことです。int8量子化もできる。

すると`3b`モデルも成功。しかし、、、

>Q:加藤純一についてどう思う? A.アニメについて棒について王について割について偽についてについて返信について今について最について米について運動会について風呂について名前について以上について毎日について気についてクラスについて後についてアニメことについてどうアニメ今返信名前ことについてについて編集についてパソコンについて就職活動について種についてみんなについてことについて返信返信今編集後今.について上層

明らかに何かがおかしい。`1b`, `large`モデルも試したところこのような「自分が質問する側だと勘違いしている」+「暴走」している出力文が出てきました。困ったなあ。

#### プロトタイプ4号：LoRAファインチューニング（成功）
いろいろ考えて自分のソースコード見返してたら、そういえば、どうして`labels`に出力文を入れているのだろう？
という疑問から、入力文/出力文に分けることをせず、試しに`inputs_id`に出力してほしい文を入れたデータセット変数を`trainer`に与えてみました。（`labels`は無し）
実は、[Hugging Faceのcausallmファインチューニングの記事](https://huggingface.co/docs/transformers/tasks/language_modeling)でもそのような実装になっています。

すると
`2023年3b`:
>Q:加藤純一についてどう思う? A.だったらさ、もうさみんなさAmazon.comってサイト見てるんだね、マジで見られてる感じする? 村上感じじゃない?加藤そうなんですよ、めっちゃ見られています、今。 夕方の5時ぐらいに見られてます、Amazonパパラッチされてます。夕日のモーメント的に撮られました。モ

`2015年1b`:
>Q:加藤純一についてどう思う? A.お前ニンジャやめちゃいなよマジでキングダム見なよ絶対見なきゃだめだぞお前の人生においてやつれるんだよ俺の人生でニンジャー見るから人生で絶対見たほうがいいやつれちゃうんだよだからニンジャーズ見て人生最低の人生送るんだよ人生でもやつれたんじゃやばいんだよ絶対絶対見て今度からやつれてるんじゃ

ある程度一貫性を持ってまともに喋れるようになりました。話題も口調も加藤純一っぽい。質問にちゃんと答えられていないのは、たぶんデータセットがちゃんと答えていない仕様だったからでしょうか？急造なので...

ChatGPTのファインチューニングは質問+回答文という形で別々にデータを与えるので、transformersのLMもそうかなと思っていたのですが、一つの文字列（`"Q.質問A.回答"`)からファインチューニングできるんですね。

`inputs_id`だけのデータで動いたことについて、1号機で紹介した水色桜さんの記事のように`inputs_id`と`labels`が完全に誤りだったということとは思ってはいません。というのも、一号機はちゃんと喋れていましたので... 原因がよくわからない。

## 次やること
簡易的なファインチューニングで口調を学習できることが分かったので、少し長めに喋らせる、雑談させてみたいと思います。
アイデアが1つありまして、
**最初の一言を人工的に与えて、あとはAIモデルその続きを考えさせる。それが終わると、その結果をAIに与え、その続きを考えさせる、という再帰的出力**
を試したいと思います。

そのために、学習データとしては2通り仮説を試したく、
* 雑談データ全文をそのまま学習データに与える
タイプと、
* 前後につながる2文のセットを与え、どんな文章が連続するか学習させる。
タイプ

を試したいと思います。

あと、サイバーエージェント`Open-CALM-7b`, Stability社`Japanese Stable LM`、松尾豊研究室`weblab-10b`に手を出してみたい（GPUは耐えられるかな？）

本当は強い（メモリが大きい）GPUを持っている協力者がいれば学習を依頼したい気持ちがありますが、そのためには自分で結果を出して信頼を勝ち取る必要があるため、地道にやってみます。

## 現在の課題
* 工作グランプリでもそのせいでゴミっぽく見えた原因として、書き起こし精度が最善とは言い難いです。例えばよく登場する配信者「もこう」さんは「モコ」とかに書き起こされ、検索しても0件ヒットです。今開発しているこのAIも知識は完全に書き起こしデータに依存するので、<strong>この書き起こし精度がプロジェクト全体のボトルネックになっています。</strong>
書き起こしAIにOpenAI社の「Whisper」の`large-v2`モデルを使用していますが、こちらをファインチューニングする必要があるものと考えています。
文字ベースのデータでも出来るという情報もありますが、できれば音声+文字データでファインチューニングした方がよさそう、しかしデータがない。誰か手動書き起こしデータ作りしてほしいものです；；（時間がない）