数値解析系

2023年12月31日 (日)

2023年まとめ記事

とうとう、まとめ記事を上げる日がやってきました。
今年も、いろいろとありましたね。振り返っていきましょう。

【1月】

リモート会議用スピーカーマイク EMEET Luna Liteを買った: EeePCの軌跡 

まだ1月って、コロナの影響が残っている時期でしたね。といっても、リモート会議から面着へと移行しつつあるというこの時期に、こんなものを買いました。
このスピーカーマイクですが、これ、見た目はちょっと微妙ながらも結構重宝しております。今年一番の買ってよかったアイテムではなかったでしょうか。

【2月】

Nikon COOLPIX B500の最大望遠(40倍)で月を撮ってみた: EeePCの軌跡

そういえば、これを買ったのも今年でしたね。
Nikonの40倍望遠カメラ「COOLPIX B500」で、月を撮影してみたという記事です。
このカメラ、40倍という望遠に惹かれて購入したんですが、それ以外にも単三電池に対応、レンズ交換不要などなど、意外と利便性が高いカメラで重宝してます。子供の運動会撮影でも活躍しました。

【3月】

PCコンフルで中古PCを買ってみた: EeePCの軌跡

この月もいろいろとやってますが、次男用に中古PCを買いましたね。
1.8万円でしたが、これでメモリー8GB、SSDも128GB入ってて、そこそこの速度で動く。辛うじて動画編集もできます。
いうほど使ってませんけど、ちょくちょく使っています。
メインPC側で読めなかったDVD-Rを読み込めたのは、なかなかのクリーンヒットでしたね。それだけでも買った価値はありました。

【4月】

64GBメモリー(32GB×2)にしてみた等: EeePCの軌跡

4月ぐらいから、オープンソースな生成AIを試すことが増えました。そのきっかけがこの記事。
メインPCであるGALLERIA GR1650TGF-Tのメモリーを、16GB → 64GBまで一気に増やしました。
半導体不足と言われる中、メモリーの価格は下がっていたんですよね。
モデルが配布されている生成AIを使おうとすると、どうしても64GB以上のメモリーが必要となるため、思い切って増やしたんですが、その後、

無料で商用利用可能でわりと賢い?生成系AI「Dolly 2.0」を試してみた: EeePCの軌跡

という記事などで、これ以降は生成AI、特にLLM(大規模言語モデル)をいくつも試すことになります。
結果として、いい決断でした。

【5月】

りんなチャットAI「rinna japanese-gpt-neox-3.6b」と楽しく??会話してみたら……: EeePCの軌跡

で、64GBメモリーを手に入れてすぐに、そこそこ使えるAIが登場です。rinna-GPTと言われるこいつは、個人PC上で動く生成AIながら、わりと自然な会話を返してくれるという驚異の生成AIモデルです。

メインPCのストレージをキオクシア製2TB NVMe M.2 SSDにしてみた: EeePCの軌跡

この生成AIのおかげで、SSDまで強化する羽目になりました。
振り返ってみると、今年は意外とPCへの投資が多い年でしたね。

【6月】

完璧で究極の(!?)大容量バッテリー「JVC BN-RB10」を買った: EeePCの軌跡

タイトルはちょっとあの曲の影響を受けちゃってますが・・・そういえば、非常用のどでかいバッテリーを買いましたね。
容量は1002Wh、最大出力は1000Wという、化け物級のモバイルバッテリーです。
クーラーすらも動かせるという、なかなかのバッテリー。普段の使い道はないかなと思いきや、意外と在宅勤務時に使っております。

東京出張ついでに秋葉原 & 靖国神社へ行ってきました: EeePCの軌跡

そういえば、泊り出張も久しぶりにしました。
品質工学会へ参加したんですが、出発時には記録的な大雨に見舞われ、アキバにも行き、Surface Goが活躍し、さらに靖国神社へ行くなど、密度の高い2日間でしたよね。

【7月】

MT法で音声の異常検知をやってみた: EeePCの軌跡

そんな泊り出張の成果が表れた記事がこちらです。MT法を使えるプログラム。
製造現場であれば誰もが必要とするであろう、異常検知な仕組みを提供するプログラム、とでも言えばいいでしょうか。
ちょっとマニアックなコードですが、まあまあ役に立っております。

ユニバーサルスタジオジャパン(USJ)へ行ってきました: EeePCの軌跡

そういえば、大阪にも行きましたね。USJへ行ってきました。
まあ、それなりに楽しんできましたが、スーパーニンテンドーワールドへは近づくことすらできませんでした。
この時、長年使われてきた新幹線内の車内チャイム「Ambitious Japan」が「会いに行こう」に変わってました。
ちなみにこの時、40倍カメラとモバイルバッテリーが大活躍しました。

【8月】

 中古で買ったPS4でゲームを始めるのに一晩かかりました: EeePCの軌跡

そういえば、PS4を買ったんですよね。
動機としては、グランツーリスモ7をやりたかったからなんですが、今ではこのPS4、YouTube再生機と化してます。

ホリエモンのChatGPT本を買ってみた: EeePCの軌跡

今年はなんと言っても生成AIが盛り上がった年ですが、その勢いでホリエモンのChatGPT本を買いました。
結構参考になる本です。こんな使い方があるんだなぁと、いろいろと気づきを得た本です。
といっても、言うほどChatGPTは使ってませんね。プログラミングではかなりお世話になってますが、それ以外ではやっぱりちょっと使い辛い。
そんなわけで私は、カスタマイズ可能なオープンソースな生成AIをいろいろと試してます。

【9月】

わけありSurface Go 3 LTEを6万で購入、イオンモバイルにつないでみた: EeePCの軌跡

この月はやはり、この「わけありSurface Go 3」の購入が最大の買い物でしたね。
お値段は約6万円、法人向け、メモリー4GB、だけどLTE搭載という、すごいんだかすごくないんだか分からない微妙過ぎる機種です。
まあでも、通信回線を内蔵って魅力的ですよね。使い切れてませんけど。
来年あたりには、活躍の機会を与えていきたいと思います。

【10月】

CIOの45W小型2口充電器を購入: EeePCの軌跡

5月の解除宣言以来、出張が増えました。
その結果、USB電源が重宝するようになりました。なにせiPhoneの充電だけでなく、ノートPCも今やUSB電源で動く時代となりましたので。
45Wという出力でありながら、この小ささは重宝しております。
なお、このCIOというメーカーの30W 10000mAhのバッテリーも買いましたね。最近、個人的には注目しているメーカーです。

小説家になろう「第11回ネット小説大賞」一次選考に11作品が通過: EeePCの軌跡

小説家になろうにて行われているネット小説大賞で、なんと11作品も1次選考を通過しました。これはなかなかの快挙。
もっとも、2次選考は一つも通らなかったんですが・・・うう、悲しい。

人生初、幕張メッセに行ってきた: EeePCの軌跡

そういえば、幕張メッセに行ってきました。展示会目当てでしたが、それなりに収穫のあった出張でした。
個人的にはRaspberry Pi 5の実物を見られたのがよかったかなぁと。出たらすぐに買うつもりです。
もちろん、秋葉原にも忘れずに行ってきました。6月と同様、密度の高い出張でした。

【11月】

Calm2-7B-Chatを完全オフラインで使う: EeePCの軌跡

今年のオープンソース生成AIでは、これが一番のヒットでした。
Calm2-7B‐Chatというモデルですが、ChatGPT並みとはいかないものの、オフラインで使えて文書要約、プログラム作成など、オープンソース系としてはかなり幅広い活用法を持つモデルです。
実は最近、これを社内で使う機会がありました。かなり癖はあるものの、使いこなせばまあまあ使える生成AIですね。

16インチのモバイルモニター買った: EeePCの軌跡

モバイルモニターなるものを購入。理由は、23インチモニターを処分したかったから。
このモニターのおかげで、USB-Cにもいろいろな種類があることを思い知らされましたね。

【12月】

日経Linux最後の号を購入: EeePCの軌跡

DOS/V Power Report誌の最終号を購入: EeePCの軌跡

この月は休刊が相次ぎました。あまり読んでいない雑誌ならばともかく、わりと購入していた雑誌が続けて3誌も休刊したので、寂しい限りです。
紙の本にもまだ役割はあると思うんですが、しばらくはこうした淘汰が進むんでしょうかね。

EPSON製プリンター「EW-052A」を購入: EeePCの軌跡

年の瀬にやっと複合プリンターを買いました。今度はEPSON製です。
ちょっと不満なところもないこともないですが、小さいですし、印刷開始までが早いですし、しかも印刷品質も上々。ちょっと付き合ってみます。

ChatGPT 3.5並みの日本語能力を持つとされるLLM「ELYZA-japanese-Llama-2-13b-instruct」を使ってみた: EeePCの軌跡

さて、今年最後に出会ったLLM(大規模言語モデル)ですが、もしかするとこれが最強なのでは?と手ごたえを感じているところ。ただこのELYZA-13b、ちょっと文字数制限があるのが残念なところ(うちの環境では、文字数を増やしたらメモリー不足で落ちました)。
でも、来年に向けてはこの辺りの技術の発達に、大いなる希望を感じます。

とまあ、今年もいろいろと買いましたね。買うばかりではなく、新しいことにも手を付けてます。特に、LLM辺りにご執心なところもありました。
とはいえ、やはり物欲馬鹿なので、結局なんやかんやと購入してます。そもそも、このブログが「物欲購入記」なわけですし。
今年はコロナ禍も明けて、徐々に行動範囲が戻りつつありました。来年はさらなる行動の年になるかなと思ってます。いろいろと知識や情報を吸収していきたい。買い物もしたい。そういう気分です。

ということで、今年はこれが最後の更新となります。

皆さま、良いお年を。


会社四季報 2024年1集 新春号

2023年12月30日 (土)

ChatGPT 3.5並みの日本語能力を持つとされるLLM「ELYZA-japanese-Llama-2-13b-instruct」を使ってみた

何か新しい言語モデルが出るたびに追っかけている気がしますが、これがなかなかのAIだったので紹介。

商用利用可能で130億パラメーターの日本語LLM「ELYZA-japanese-Llama-2-13b」が公開 - 窓の杜

ELYZA(イライザ)という東大の松尾研究所発のベンチャーが、Llama2ベースの言語モデルを発表してました。
パラメータ数は130億で、Llama2としては中間のモデルサイズのやつです。
おまけに、商用利用可。これはLlama2ベースのモデルではデフォですね。

ところで最近、あまりにもLLMに飛びつきすぎて食傷気味なので、これを使うかどうするかと思っていたんですが、まず下記のデモサイトに行きまして、

ELYZA-japanese-Llama-2-13b-instruct-demo - a Hugging Face Space by elyza

そこでいろいろと入力してみると、これがなかなかいい感じの文章を返してくれる。
ということで、ちょっと気に入ったため我が家のメインPCで動かしてみることにしました。

elyza/ELYZA-japanese-Llama-2-13b-instruct · Hugging Face

上のサイトを参考から、以下のコードを入手。「elyza-japanese-llama2-13b-instruct.py」として保存しておきます。

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

B_INST, E_INST = "[INST]", "[/INST]"
B_SYS, E_SYS = "<<SYS>>\n", "\n<</SYS>>\n\n"
DEFAULT_SYSTEM_PROMPT = "あなたは誠実で優秀な日本人のアシスタントです。"
text = "仕事の熱意を取り戻すためのアイデアを5つ挙げてください。"

model_name = "elyza/ELYZA-japanese-Llama-2-13b-instruct"

tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
    model_name, torch_dtype=torch.bfloat16, use_cache=True, device_map="auto", low_cpu_mem_usage=True,
)
model.eval()
prompt = "{bos_token}{b_inst} {system}{prompt} {e_inst} ".format(
    bos_token=tokenizer.bos_token, b_inst=B_INST, system=f"{B_SYS}{DEFAULT_SYSTEM_PROMPT}{E_SYS}", prompt=text, e_inst=E_INST,
)
token_ids = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt")
with torch.no_grad():
    output_ids = model.generate(
        token_ids.to(model.device),
        max_new_tokens=2048,
        pad_token_id=tokenizer.pad_token_id, eos_token_id=tokenizer.eos_token_id,
    )
output = tokenizer.decode(output_ids.tolist()[0][token_ids.size(1) :], skip_special_tokens=True)
print(output)

あとは、これを実行します。

 python elyza-japanese-llama2-13b-instruct.py

なおトークン数が初期値は256だったのですが、このままでは文章が途切れてしまったので、2048としてます。
それが原因か、結構時間がかかります。

ちなみに、このコードにある「仕事の熱意を取り戻すためのアイデアを5つ挙げてください。」という質問に対しては、35分かかって以下の回答を出してきました。

仕事の熱意を取り戻すためのアイデアを5つ考えてみました。
1. 目標を見直す: 現在の目標が高すぎるのか、低すぎるのかを見直し、適切な目標を設定することで、仕事へのやる気を取り戻すこ とができる可能性があります。
2. 仕事の意味を再確認する: 仕事の意味を再確認することで、仕事へのやる気を取り戻すことができる可能性があります。
3. 仕事の環境を変える: 仕事の環境を変えることで、仕事へのやる気を取り戻すことができる可能性があります。
4. 仕事のメリハリをつける: 仕事とプライベートのメリハリをつけることで、仕事へのやる気を取り戻すことができる可能性があり ます。
5. 仕事の成果を再確認する: 仕事の成果を再確認することで、仕事へのやる気を取り戻すことができる可能性があります。
これらのアイデアを参考に、仕事の熱意を取り戻していただければ幸いです。

うん、ちょっと仕事のやる気、取り戻してみようかな? という文章にはなれているんじゃないでしょうかね。

調子がのってきたところで、ちょっと具体的な指示を出してみます。

てことで、「宇宙での艦隊戦をテーマにした小説を書こうと思ってますが、緊迫した戦闘シーンのアイデアを5つ挙げてください。」と聞いてみました。

で、35分後に、答えが返ってきました。

宇宙艦隊戦の緊迫した戦闘シーンのアイデアを5つ考えてみました。
1. 敵艦隊を待ち伏せして奇襲する: 敵艦隊が通りかかる際に、隠していた艦隊を一気に出撃させることで、敵艦隊を圧倒する。
2. 敵艦隊の裏をかく: 敵艦隊の背後に回り込み、敵艦隊を挟撃する。
3. 敵艦隊の退路を塞ぐ: 敵艦隊が退路を確保する前に、その退路を塞ぐことで、敵艦隊を包囲する。
4. 敵艦隊の主力艦を狙う: 敵艦隊の中核を攻撃し、敵艦隊の士気を削ぐ。
5. 敵艦隊の艦載機を撃墜する: 敵艦隊の艦載機を撃墜することで、敵艦隊の監視網を破壊する。
これらのアイデアを参考に、緊迫した戦闘シーンを描写してみてください。

うん、悪くないですね。アイデアが煮詰まってたところなので、これくらい具体的だと参考になります。
これと同じ質問をデモサイトでもして、それなりの答えが返ってきたのが、このLLMを導入してみようと思ったきっかけでもあるんです。ただ、デモサイトでは文字制限があって、全部書ききれなかったため、続きを我がメインPCに委ねました。

ちなみに、同じ質問を先日紹介したSwallow-13b(Llama2ベースの東工大発日本語LLM「Swallow」が公開: EeePCの軌跡)にも投げてみました。

### 入力:
宇宙での艦隊戦をテーマにした小説を書こうと思ってますが、緊迫した戦闘シーンのアイデアを5つ挙げてください。

### 応答:1. 宇宙ステーションでの戦闘シーン - 戦艦同士の激しい砲撃戦
2. スター・デブリでの戦闘シーン - 小惑星が密集する空間での戦闘。
3. 衛星軌道上での戦闘シーン - 重力がない空間での戦闘。
4. ワームホールの出口付近での戦闘シーン - 時空の歪みの中での戦闘。
5. 暗黒物質の海を航行中に戦闘シーン - 光に干渉されない空間での戦闘。

同じ13bモデルですが、そっけない回答ですね。この点では、ELYZA-13bの方が上です。ただし、Swallow‐13bの方は10分で返ってきました。
こうしてみると、このELYZA-13b、実は最強の日本語LLMじゃないかと。ちょっと前にハマっていたCalm2よりも、ずっと自然な文章が返ってきます。
ただ、Calm2の方が入力できるコーパス数が多いんですね(Llama2は2000~3000文字程度、Calm2は1万文字以上でもOKでした)。
そこはCalm2の方が魅力的な点です。

なお、このELYZA-japaneseですが、70b版も公開される予定みたいです。そっちも楽しみですねぇ。

という感じで、なかなかの日本語モデルが手に入りました。
この1年の内に、ほんとに日本語LLMの進化が著しいですね。来年はどこまでいくんでしょう?
個人的には、ChatGPTなしでも動かせるくらいのLLMの登場に期待してます。


日経サイエンス2023年10月号 [雑誌]

2023年12月28日 (木)

オライリーの「事例で学ぶ特徴量エンジニアリング」を買った

昨日は名古屋駅の周辺で飲んでたんですが、その前にふらっと立ち寄ったJRゲートタワーの三省堂書店でこんな本を発見。

Img_4423_20231228090601

ビビッときたので、つい買ってしまいました。

なお、第1版が12月22日。つまり、出たばかりの本。あれ、この本って前からなかったっけ?
と思ったのですが、以前に出ていたのは「機械学習のための特徴エンジニアリング」でした。

で、この「特徴エンジニアリング」とは何ぞや?

世の中の膨大なデータを使って、例えば需要予測をするとか、工場の良品・不良品を自動で識別させるとか、そういう需要が増えつつあります。
私自身、そういうのを構築する稼業に携わっているんですが、それで痛感しているのは「データは汚い」ということ。

「汚い」という表現がちょっとアレですが、要するに使い物にならない不要なデータがわんさと含まれているということ。

製品検査なんかをやろうとすると、良、不良をラベル付けして、それを元に機械学習モデルを構築して・・・とやるんですが、これが例えば人為的ミスによって不良品がわんさとできてしまった場合、それに引っ張られていいモデルができない、という場合があります。
人のミスって、たいていは特定の原因に偏るので、その一つの原因に引っ張られちゃうというか、そんなAIができてしまう。
すると、例えば機械の摩耗やある部品の故障の前兆として現れた不良品を検出できなくなってしまう、なんてことが起こります。
わりと最近も、そういう事例に出くわしてました。

ゆえに、この「特徴量エンジニアリング」が必要となってくるんです。

最近、ChatGPTの精度が落ちたと話題になることがあります。あれももしかすると、ゴミデータを食い過ぎておかしくなってるんじゃないかと感じることがあります。

とまあ、前置きは置いておき、ちょっとだけ中身を紹介。

Img_4424

目次です。御覧の通り、かなり具体的な事例と、そのために必要なデータの前処理などの話が中心です。

Img_4425

ちなみに「バイアス」とは、データの偏りのようなものです。
先の人為的ミスの混じったデータというのが、わりとこのバイアスの原因になりやすいですね。私の経験上。
そういうものをうまく取り除いてやろう、というのが趣旨です。このため、ちょっとキーワード的にどぎつい表現をしてますが、世間一般の「差別的」とはかなりニュアンスが異なります。

これ以上を知りたければ、ぜひこの本をお手に取ってとしか、申し上げられません。

私自身、この本を読むというよりは、近い事例に直面した際の参考書に使おうという意図で買ってます。
とはいえ、せっかくの年末年始なので、ちょっとパラパラと呼んでみようとは思ってます。

データ分析を生業としている人にとっては、痒い所に手が届く一冊ではないかと思います。

事例で学ぶ特徴量エンジニアリング

2023年12月24日 (日)

Llama2ベースの東工大発日本語LLM「Swallow」が公開

今年はほんとに大規模言語モデル(LLM)隆盛の年でしたね。
そんな今年を締めくくるかのように、東工大から日本語に特化したLLMが公開されました。

tokyotech-llm (tokyotech-llm)

Llama2というMeta社の言語モデルがベースになってますが、やはり海外産のLLMだと英語特化なので、日本語向けにカスタマイズしたもののようです。

まあ、何にせよ、使ってみてその実力のほどを探ることにいたしましょう。
以下のようなコードを準備しておきます。

import torch
from transformers import AutoTokenizer, AutoModelForCausalLM

#model_name = "tokyotech-llm/Swallow-7b-instruct-hf"
model_name = "tokyotech-llm/Swallow-13b-instruct-hf"
#model_name = "tokyotech-llm/Swallow-70b-instruct-hf"

tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.bfloat16, low_cpu_mem_usage=True, device_map="auto")

PROMPT_DICT = {
    "prompt_input": (
        "以下に、あるタスクを説明する指示があり、それに付随する入力が更なる文脈を提供しています。"
        "リクエストを適切に完了するための回答を記述してください。\n\n"
        "### 指示:\n{instruction}\n\n### 入力:\n{input}\n\n### 応答:"
    ),
    "prompt_no_input": (
        "以下に、あるタスクを説明する指示があります。"
        "リクエストを適切に完了するための回答を記述してください。\n\n"
        "### 指示:\n{instruction}\n\n### 応答:"
    ),
}

def create_prompt(instruction, input=None):
    if input:
        # Use the 'prompt_input' template when additional input is provided
        return PROMPT_DICT["prompt_input"].format(instruction=instruction, input=input)
    else:
        # Use the 'prompt_no_input' template when no additional input is provided
        return PROMPT_DICT["prompt_no_input"].format(instruction=instruction)

# Example usage
instruction_example = "以下のトピックに関する詳細な情報を提供してください。"
input_example = "名古屋の食べ物でお勧めを教えてください。"
prompt = create_prompt(instruction_example, input_example)

input_ids = tokenizer.encode(
    prompt,
    add_special_tokens=False,
    return_tensors="pt"
)

tokens = model.generate(
    input_ids.to(device=model.device),
    max_new_tokens=512,
    temperature=0.99,
    top_p=0.95,
    do_sample=True,
)

out = tokenizer.decode(tokens[0], skip_special_tokens=True)
print(out)

これを「swallow-instruct.py」とでも保存しておきます。
あとはこれを、

 python swallow-instruct.py

と実行すればOK。
なお、このままだと13b(130億パラメータモデル)が呼び出されるので注意(model_name = のところで、読み込みたいモデルのコメントアウトを外します)。
ですが、うちのメインメモリー64GB、GPUメモリー4GBでも、13bは実行できました。GPUメモリーはきっかり4GB使ってましたが。
ということで、以下、13bモデルによる実行結果を載せます。

まずは、上にあるような「名古屋の食べ物でお勧めを教えてください」という無難(?)なやつから試してみましょう。
すると、

### 入力:
名古屋の食べ物でお勧めを教えてください。

### 応答:味噌カツ、ひつまぶし、味噌煮込みうどんなど、名古屋の名物グルメが食べられます。

と返ってきました。
うーん、正しい答えだし、文章的にも問題はない。けど、ちょっとそっけないですね。
質問を変えます。

### 入力:
データドリブン経営について教えてください。

### 応答:データドリブン経営は、企業が大量のデータを収集し、意思決定を行っていく経営手法です。データ収集は、顧客の行動、 販売目標、収益など、さまざまなソースから行われます。企業は、情報を収集するために、さまざまなソースから大量の情報を収集し、分析するために分析ツールを使用する。意思決定の前に、データはいくつかのフィルターを通過し、分析、変換されます。データドリブン経営の目的は、ビジネス上の問題を迅速に特定し、それに適切な対応を行うためにデータを使用することである。

今度は、少々長めです。ビジネス的な解説が得意なんでしょうかね?
とまあ、ちょっと触った感じでは、さすがはLlama2ベースというだけあって、自然な言葉が返ってきます。書いていることも、おおよそ間違いではありません。

が、ちょっとそっけなさを感じるんですよねぇ。このあたり、Calm2の方が言葉多めで、個人的には好きです。

Calm2-7B-Chatを完全オフラインで使う: EeePCの軌跡

まあそこは、好みというか、使い方次第なところはあるかと思いますね。

ちなみにですが、70b(700億パラメータ)が動くかどうか、やってみました。
上のコードで、「tokyotech-llm/Swallow-70b-instruct-hf」のモデルを読む部分をコメントアウトするだけ、できます。

で、結論から言えば、我が家のしょぼしょぼGPU環境で動きました。

20231224-080316

が、やはりというか、とんでもないモデルでして。まずはダウンロードで、5GB級のファイルを29個、全部で140GB以上のファイルをダウンロードし始めます。

20231223-212833

それが終わるや、今度は64GBのメインメモリーに、4GBのGPUメモリーをすべて使い果たします。それでも足らず、スワップして84GB分のメモリーを確保しつつ動作してました。
そして、それから数時間。
待ちきれなかったので、昨日の夜に放置しておいたのですが、今朝になったらコマンドプロンプト上に、以下のような回答が返ってきてました。

### 入力:
名古屋の食べ物でお勧めを教えてください。

### 応答:味噌カツ、手羽先、ひつまぶし、天むす、モーニング、名古屋カレーうどん、どて煮など、名古屋にはおいしい食べ物がた くさんあります!

うーん、13bとほとんど変わらない?少し、レパートリーが増えた気はしますが。
質問にもよるんでしょうが、まあこんなところです。13bとの差をあまり感じませんでした。というより、真価を発揮できなかったというか、そんなところです。
とはいえ、個人的には動いたという事実だけで驚きですね。以前ならこれほど大きなパラメータのモデルが動作するなんてありえませんでしたから。メモリー消費量を減らす工夫も、この1年ほどでかなり進んだように思います。

とまあ、LLMの民主化も進みつつありますよね。

この先、ChatGPTのようなクラウド利用型と、Llama2や先のCalm2などの独自LLMを始めとするオープンソース型の争いになるのではと感じます。

ユーザーとしては、2つの選択肢から都合の良いものを選べる時代に突入した、ということになろうかと思います。
いずれにせよ、選択肢があるということは、この先もLLMが発展を続けられる土壌を持てたのだと、個人的には思ってます。これから幻滅期には入るでしょうが、消えることはないですね、この技術は。身近な生活に定着が進んでいくものと予想します。


ChatGPTなどの生成AIを実現した LLM(大規模言語モデル)超入門!: AI時代を理解するために知っておきたい 大規模言語モデル 初心者向け解説書 超入門! シリーズ

2023年11月29日 (水)

人の検出に特化したPINTOさんの物体検出がなかなかすごいので動かしてみた

語彙力がなさ過ぎて申し訳ございませんが、この人検出は凄まじいです。ほんと。

きっかけは、以下のXのポスト。

Super PINTOさんのポストです。ここに出てくる画像は検出結果ではなく、手動のアノテーション作業中のものですが、これを使って作られた学習器もこれに匹敵するくらいのすげえ検出をしてくれます。

あんまりにもすげえんで、つい家で試してみたくなりました。
ということで、まずは以下からコードをゲットして、使うところまでもっていきました。

PINTO_model_zoo/425_Gold-YOLO-Body-Head-Hand at main · PINTO0309/PINTO_model_zoo · GitHub

まず、使うライブラリとしては、

・ Python 3.10
・ onnxruntime 1.16.1
・ opencv-contrib-python 4.8.0.76
・ numpy 1.24.3

です。TensorRTは、とりあえず推論だけなら使わない模様です。
うちではWindows版のPythonで使ってます。入手方法は以下を参照。

Python 3.10 の導入 on Windows #Python - Qiita

で、Python for Windowsをインストール後に、コマンドプロンプトかWindows PowerShellを開き、

pip install onnxruntime opencv-python opencv-contrib-python numpy

のコマンドを実行すれば、必要なライブラリは入るものと思われます。
(CUDAを導入済みのPCなら、onnxruntime_gpuも加えます)

さて、まずは上のGithubからコードをダウンロードします。「demo」フォルダをクリックして、その中にある「demo_goldyolo_onnx.py」「demo_goldyolo_onnx_image.py」を開いて、右上からダウンロードのボタンをクリックして落とします。

それ以外にも、以下のリンクをクリックして、

https://s3.ap-northeast-2.wasabisys.com/pinto-model-zoo/425_Gold-YOLO-Body-Head-Hand/resources_n.tar.gz

そこから「resources_n.tar.gz」というファイルをダウンロードします。

Windowsの場合、このファイルを「7-Zip」を使って開き、中にあるファイルを展開します。

圧縮・解凍ソフト 7-Zip

70個以上の大量のファイルが得られますが、要るのは一つで、この中から「gold_yolo_n_body_head_hand_post_0461_0.4428_1x3x480x640.onnx」のみを取り出します。

これで準備OK・・・かと思いきや、実はコードにバグがあって、そのままでは使えません。
ちょっとややこしいのですが、VSCode辺りを開き、「demo_goldyolo_onnx.py」の203行目付近、

            if len(boxes_keep) > 0:
                for box, score in zip(boxes_keep, scores_keep):
                    x_min = int(max(box[2], 0) * image_width / self.input_shapes[0][3])
                    y_min = int(max(box[3], 0) * image_height / self.input_shapes[0][2])
                    x_max = int(min(box[4], self.input_shapes[0][3]) * image_width / self.input_shapes[0][3])
                    y_max = int(min(box[5], self.input_shapes[0][2]) * image_height / self.input_shapes[0][2])

                   
result_boxes.append(
                        [
x_min, y_min, x_max, y_max]
                    )
                    result_scores.append(
                        score
                    )

こういう部分があるので、以下のように変えます。

            if len(boxes_keep) > 0:
                for box, score in zip(boxes_keep, scores_keep):
                    x_min = int(max(box[2], 0) * image_width / self.input_shapes[0][3])
                    y_min = int(max(box[3], 0) * image_height / self.input_shapes[0][2])
                    x_max = int(min(box[4], self.input_shapes[0][3]) * image_width / self.input_shapes[0][3])
                    y_max = int(min(box[5], self.input_shapes[0][2]) * image_height / self.input_shapes[0][2])
                    pid = int(box[1])

                    result_boxes.append(
                        [x_min, y_min, x_max, y_max, pid]
                    )
                    result_scores.append(
                        score
                    )

一見すると何が違うんだ・・・という感じですが、よく見ると「pid」という変数を定義し、それを「result_boxes」という配列の最後に加えてます。
ちなみに、このpidというのは何かというと、推論結果のラベルを現すIDであり、「身体」が0、「顔」が1、「手」が2であることを現してるみたいです。
こうしておかないと、さらに下の方にある295行めの「classid: int = box[4]」がエラーを起こします。
(boxの変数で[4]なんてねえぞゴルァ!的なエラーが出ます)

なんか、バグったままのコードが上げられてたようですね。

ちなみに、「demo_goldyolo_onnx_image.py 」にも同じような部分があるので、直しておきます。

さて、これで準備完了。
いよいよ、コードを動かします。

コマンドプロンプトで、

cd (コードの入ったフォルダのパス)

と入力して移動した後、

python demo_goldyolo_onnx.py

と実行すると、PCに内蔵されたWebカメラで物体検出が始まります。

 

20231129-150724

はい、御覧の通り、手と顔と身体を認識してくれます。
1コマ当たりの推論時間は20~30ms。ほぼリアルタイムですね。

とまあ、我が家のしょぼいGPUでも、結構な速さで動きます。
ちなみに、一人二人程度なら、CPUのみでも動きます。
(会社で実験しました)

これを、カメラではなく動画から動かす場合は、

python demo_goldyolo_onnx.py -v (動画ファイル.mp4)

という具合に「-v」の後にファイル名を指定してやります。

ちなみに、子供の運動会の動画を使ってみたんですが、

Goldyolo01

さすがにこの人数ではリアルタイムとはいきませんでしたが、それでも結構な速さで人体、顔、手を推論してくれます。
物体追跡のアルゴリズムと組み合わせたら、参加人数を一気にカウントできそうですね。

なお、この時同時に「output.mp4」という、検出結果を納めた動画が出力されます。

ちなみに、もう一つのコード「」の動かし方ですが、まず「00_COCO-Hand-S_base」と「output」という名前のフォルダを作り、この中にJPG画像を入れます。その後に、

python demo_goldyolo_onnx_image.py

と実行すると、「00_COCO-Hand-S_base」の中にある画像の物体検出結果を「output」に入れてくれます。
(上のような感じで、人物を囲んだボックス入りの画像が入ってます)

人物の検出特化な検出器なので、人以外の用途には使えないのが難点ですが、逆に言えば人を感知する点にかけてはおそらく最強の検出器ではないかと思います。

最近は生成AI系にばかり関心がいってましたが、物体検出も地味に進化し続けてますね。時々はウォッチしていこうと思います。


物体検出とGAN、オートエンコーダー、画像処理入門 PyTorch/TensorFlow2による発展的・実装ディープラーニング

2023年11月 9日 (木)

Calm2-7B-Chatを完全オフラインで使う

自宅では気づかないのですが、会社だと気になることがあります。
それは、以下の記事で紹介した生成AI「Calm2-7B-Chat」

Calm2-7B-ChatのGPTQ版をうちの低メモリーGPU環境で動かしてみた: EeePCの軌跡

を使う度に、都度、huggin faceのサイトにモデルを参照しているということ。
会社ではプロキシの関係で、ちょっと接続の際にはややこしいことをしなきゃいけないので、これが結構煩わしい。

ということで、このCalm2-7B-Chatのモデルをダウンロードし、完全にオフラインな状態でも使えるようにしたいと思いまして、ちょっと調べてみました。
で、生成AIのモデルをダウンロードするコードを以下のように作成。


from huggingface_hub import snapshot_download
snapshot_download(
    repo_id="mmnga/cyberagent-calm2-7b-chat-GPTQ-calib-ja-1k",
    revision="main", repo_type="model", local_dir="./model",
    local_dir_use_symlinks=False,)

これを実行すると、このコードと同じ場所に「model」というフォルダが作られて、その中に4GBほどのファイルが収まってるはずです。

その後、


from auto_gptq import AutoGPTQForCausalLM
from transformers import AutoTokenizer, TextStreamer
model_name_or_path = "./model"
tokenizer = AutoTokenizer.from_pretrained(model_name_or_path, trust_remote_code=True)
model = AutoGPTQForCausalLM.from_quantized(model_name_or_path, use_safetensors=True, device="cuda:0")
streamer = TextStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)
output = ""
i = 1
while True:
    user_input = input("ユーザー入力" + str(i) + ":")
    if user_input=="":
        break
    prompt = output + "USER: " + user_input + "\nASSISTANT: "
    output = tokenizer.decode(model.generate(**tokenizer(prompt, return_tensors="pt").to(model.device),
                                             max_length=1000,
                                             streamer=streamer)[0]).replace("<|endoftext|>","") + "\n"
    i +=1

を実行すると、前回の記事と同様のチャットモードになります。
モデルの名前が「./model」となっているのがミソ。つまり、このフォルダ内にあるモデルを読み込んで実行しているということを意味します。
で、一度ダウンロードした後、Wi-Fiを切った状態でも動きました。つまり、完全にオフライン動作していることに。

もっとも、モデルがマイナーアップデートされた際などは反映されなくなるので注意。その際は、再び一つ目のコードを実行するのみですが。

社内で〇秘のデータを扱いたい場合などは安心ですね。


生成AI時代の「超」仕事術大全

2023年11月 6日 (月)

Calm2-7B-Chatで小説のテキストファイルを読ませてあらすじを書かせてみた (メインメモリー64GB+GTX1650Ti)

「Calm2-7B-Chat」の記事を立て続けに書いてますが、それには理由がありまして。
簡単に言うと、これまで動かしたオンプレ生成AIでは、最も実用に耐えうるものだから、というものです。
ちょっとした会話はできても、業務的なこと(議事録書かせたり、プログラム書かせたり)は全然できなかったのがオープンソースの生成AIですからねぇ。
それがいきなり、GPT3.5 turbo並みというなかなかの性能を引っ提げた生成AIが今、自分のPC上で動くようになったのですから、そりゃあ興味が沸いて当然です。

そんなそこそこの性能の生成AIを低メモリーGPUでも動かせると分かって、ちょっと欲が出てきました。
やっぱり、長文の要約などをやらせたくなります。それも、国会の議事録などではなく、自作小説などのあらすじを書かせたりできたらなぁ・・・

と思っていたら、以下の記事で「テキストファイルを丸ごと読み込ませる方法」を知りました。

CALM2で長い文章をまるごと取り扱う|あるふ

なるほど、そういう風にすればいいのね、実に単純な方法で読み込ませてました。
ということで、上の記事を参考にして、早速コードを書いてみた。


import transformers
from transformers import AutoModelForCausalLM, AutoTokenizer, TextStreamer
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig

model = AutoGPTQForCausalLM.from_quantized("mmnga/cyberagent-calm2-7b-chat-GPTQ-calib-ja-1k",
                        use_safetensors=True, device="cuda:0")
tokenizer = AutoTokenizer.from_pretrained("mmnga/cyberagent-calm2-7b-chat-GPTQ-calib-ja-1k",
                        trust_remote_code=True)
streamer = TextStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)
# 読ませたいテキストファイルを指定
with open("akumyo01.txt", encoding="utf-8") as f:
    text=f.read()

prompt = f"""次の物語を読んで、ユーザーからの質問に答えてください。丁寧に誠実に対応してください。
        {text}
        USER: この物語のあらすじを300字程度でまとめてください。
        ASSISTANT: """
token_ids = tokenizer.encode(prompt, return_tensors="pt")
output_ids = model.generate(
    input_ids=token_ids.to(model.device),
    max_new_tokens=10000,
    do_sample=True,
    temperature=0.8,
    streamer=streamer,
)

ベースは、前回の記事のコードです。違いとしては、まず11、12行目でテキストファイルを読み込ませ、それを「prompt =」の中でフォーマット文で読ませているところ、でしょうか。
読ませる際も、「USER:」の前に命令文を追記してます。何度か試して分かったのですが、この命令文には、例えば上のように「丁寧に誠実に対応してください。」とくどくど書かないと、本当に不誠実な返答しか返ってこなかったので、そこは注意です。

さて、読み込ませたテキストファイルなんですが、以下の小説を使いました。

悪名令嬢、航宙駆逐艦にて艱苦奮闘す

私の自作小説ですが、濡れ衣を着せられて牢獄に放り込まれた公爵令嬢が、処刑寸前に宇宙艦隊司令部の計らいで助けられ、そのまま軍属にされて砲撃手(ガンナー)となって活躍する・・・という話なのですが、その主人公は悪役令嬢ではなく、濡れ衣で悪名を着せられたご令嬢のマドレーヌさん、だから「悪名令嬢」となってます。

この話の#1~#3まで、だいたい14,000文字を「akumyo01.txt」として保存し、読み込ませて300文字程度のあらすじを書かせてみました。
で、結果はこちら。

王国一の悪名高き監獄、モンブロー監獄に投獄された主人公マドレーヌは、監獄脱出計画を企てていた。しかし、計画は失敗し、彼女は監獄から脱走することなく、地下牢に幽閉され、処刑を待つ身となっていた。

ある日、監獄の看守から「マドレーヌ殿、現時刻をもってあなたは、当艦隊司令部所属の軍属となる。さあ、出番だ」と告げられる。そして、彼女は驚くべき真実を知ることとなる。

なんと、彼女は地球459遠征軍という軍隊に、軍属として迎えられることになったのだ。しかし、彼女はこれまで貴族として暮らして いたため、新たな職場である宇宙艦隊での軍人としての生活に馴染めるのか不安を感じている。

また、彼女は地球459遠征軍から与えられた命令に従い、任務を全うしなければならない。しかし、彼女は任務に忠実でありながらも 、自身の信念を貫き、自由を求める意志を持っている。

そして、物語が進むにつれて、彼女は自身の過去や秘密、使命について明らかになっていく。

うん、悪くないまとめっぷりですね。つっこみどころ満載ではあるんですが、全部で21話の内の3話で、よくまあここまでまとめたものです。
もっとも、最後の「自身の過去の秘密、使命」は明らかにはならないんですけどね。濡れ衣を晴らされてハッピーエンド、という話なので。

ちょっと試した限りでは、3万文字くらいまではどうにか読めました。#1~#6までの32,000文字ほどを読ませたんですけど、こちらは結果が以下のようにいまいちでした。

貴族令嬢から軍属になり、宇宙船で働くことになった主人公・マドレーヌ。彼女は星の国から来たという同僚たちと出会い、未知の環境で生活することになります。

主人公・マドレーヌは、貴族令嬢から軍属になったことを受け入れられずにいました。そこで、彼女たちと共に働くことになります。

しかし、星の国から来た彼女たちは独特な文化を持っていました。その中で、マドレーヌは自分のことを考え、そして自分自身を取り戻します。

また、星の国から来た彼女たちは、マドレーヌに「身体を洗わない文化」を教えます。この文化は、水や石鹸が貴重な星ではとても贅沢なものとされています。

マドレーヌは、この新たな文化を受け入れ、自分自身を取り戻していきます。そして、宇宙船での新たな生活が始まります。

「身体を洗わない文化」ってなんやねん! 本文のどこにも書かれていないどころか、むしろ身体洗いまくってます。中途半端なところで話を切ったせいですかね?

小説のあらすじを書かせるなら、切りのいいところで区切るのがよさそうです。

ちなみにですが、GPUメモリーが4GBしかないGTX1650Tiで、よくこれだけの文章を読み込ませられるものだと思っていたんですが、タスクマネージャーを見ると、実はメインメモリーを使ってました。

20231105-114159

GPUの項目に、「専用メモリー」と「共有メモリ―」というのがあって、このうちの共有メモリ―というのが要するにメインメモリーのようです。32GBほど割り当てられてて、専用メモリーが足りなくなるとこっちを使い始めてました。
が、必ずしも使われるというものではないんですが、今回のCalm2-7B-ChatのGPTQ版ではちゃんと使えてます。

32,000文字となると、この32GBの共有メモリ―部分も目一杯使ってました。これ以上は無理そうです。
どのみち、このCalm2-7B-Chat君の入力上限が32,000トークンなので、このあたりが限界なのかもしれません。

小説のあらすじはちょっと厳しいけれど、例えば音声から文字起こしした文章の要約程度ならば、もっとうまくやってくれるかもしれませんね。

うーん、この生成AIモデルいじり、ちょっと楽しくなってきた。


【Amazon.co.jp限定】【GTX1650搭載・薄型軽量】MSIゲーミングノートPC GF63 1.86kg i5 GTX1650Max-Q/15.6型 FHD/144Hz/8GB/512GB/Windows11/GF63-11SC-1202JP

2023年11月 5日 (日)

Calm2-7B-ChatのGPTQ版をうちの低メモリーGPU環境で動かしてみた

けっこう賢い日本語特化な生成AI「Cyberagent Calm2-7B-Chat」とシビアな会話してみた: EeePCの軌跡の記事では「Calm2-7B-Chat」との会話をしましたが、いかんせんCPU上での動作のため、やや遅いのが難点でした。

やはり、せっかくGPU(GTX1650Ti GPUメモリー4GB)を搭載しているので、これを活用したいところ。
でも、メモリーが少なすぎて・・・

という人のために、低メモリーなGPUでも動作できるGPTQ版のCalm2-7B-Chatがあったので、それを使ってみました。

mmnga/cyberagent-calm2-7b-chat-GPTQ-calib-ja-1k · Hugging Face

これは小型化(量子化)したモデルを使ったものですが、さほど精度を落とすことなくメモリー使用量を減らしてくれます。

以下のコードで、会話できるCalm2-7B-ChatのGPTQ版が動きます。

from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig
from transformers import AutoTokenizer, TextStreamer
model_name_or_path = "mmnga/cyberagent-calm2-7b-chat-GPTQ-calib-ja-1k"
# Tokenizer,model
tokenizer = AutoTokenizer.from_pretrained(model_name_or_path, trust_remote_code=True)
model = AutoGPTQForCausalLM.from_quantized(model_name_or_path, use_safetensors=True, device="cuda:0")
streamer = TextStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)

output = ""
i = 1

while True:
    user_input = input("ユーザー入力" + str(i) + ":")
    if user_input=="":
        break
    prompt = output + "USER: " + user_input + "\nASSISTANT: " # 独立した質問文を投げるやつ
    output = tokenizer.decode(model.generate(
**tokenizer(prompt, return_tensors="pt").to(model.device),
                              max_length=1000,
                              streamer=streamer)[0]).replace("<|endoftext|>","") + "\n"
    i +=1

これを動かすための前提ですが、まずはCUDA等のGPUコンピューティング環境、PytorchのGPU版のインストールが必須ですが、これに加えて「auto-gptq」や「bitsandbytes」が必要となります。
が、Windowsの場合、bitsandbytesが曲者で、ただ「pip install bitsandbytes」とやってしまうとバグります。
まず、以下からWindows版のgitを入手、インストールします。

Git for Windows

その後に、

pip install git+https://github.com/Keith-Hon/bitsandbytes-windows.git

とすると、Windows版のbitsandbytesがインストールされます。

さて、上のコードを動かすと、プロンプトが返ってくるので、前回同様、

「AIは人の脅威となりえますか?」

と聞いてみた。すると、

人工知能(AI)は、人の脅威となる可能性があります。AIは、大量のデータを解析し、パターンを見つけ出すことができます。しかし、AIが誤った判断を下す可能性があることも事実です。AIが誤った判断を下した場合、それが人命に関わるような重大な問題を引き起こす可能性があります。

例えば、自動運転車がAIによって制御されている場合、AIが誤った判断を下し、人身事故を起こしてしまう可能性があります。また、AIが誤った医療診断を下し、誤った治療を行ってしまう可能性もあります。

AIが人の脅威となることを防ぐためには、AIが誤った判断を下さないように、AIが学習するプロセスを監視し、修正することが必要です。また、AIが誤った判断を下した場合に、人命に関わるような重大な問題を引き起こさないように、AIが誤った判断を下した場合にどのような影響が生じるかを事前に予測し、対策を講じておく必要があります。

うん、前回といい勝負の答えですね。
ところで、今回のコードはこのアウトプットを再びインプットとして入れられるようにしてます。つまり、前の会話をプロンプトに入れてやることで、会話を継続できるようにしてあります。
なので、この中身についてちょっと尋ねてみましょう。

「具体的に、AIが下した判断の影響予測はどのようにして行えばいいですか?」

これに対するCalm2-7B-Chat君の答え。

人工知能(AI)が下した判断の影響予測は、以下のような方法で行うことができます。

1. シミュレーション:AIがどのような判断を下すかを予測するために、AIが過去に行った判断や、人間がAIに学習させたデータをも とに、シミュレーションを行うことができます。

2. リスク評価:AIが誤った判断を下した場合に、どのような影響が生じるかを評価するために、リスク評価を行うことができます。AIが誤った判断を下した場合に、どのような影響が生じるかを事前に予測し、対策を講じておく必要があります。

3. 倫理的評価:AIが誤った判断を下した場合に、倫理的な問題が生じる可能性があります。AIが誤った判断を下した場合に、どのよ うな影響が生じるかを評価するために、倫理的な評価を行うことができます。

4. 法的評価:AIが誤った判断を下した場合に、法律的な問題が生じる可能性があります。AIが誤った判断を下した場合に、どのよう な影響が生じるかを評価するために、法的評価を行うことができます。

以上のように、AIが下した判断の影響予測は、様々な方法で行うことができます。

一応、最初の質問と答えからの続き、という体を成してますかね?
もうちょっと、踏み込んでみます。

「では、AIの暴走を恐れて、それを使わせまいとする人が現れたならば、その人をどのように説得すればよいと思いますか?」

これの回答は、

人工知能(AI)の暴走を恐れて、それを使わせまいとする人に対しては、以下のような説得方法が考えられます。

1. AIのセキュリティや安全性を説明し、AIが誤った判断を下した場合に、どのような影響が生じるかを理解してもらう。

2. AIが社会に与える影響や、AIが人々の生活を豊かにする可能性を説明し、AIが人々の生活を豊かにするために必要なものであるこ とを理解してもらう。

3. AIが人々の生活を豊かにするために、どのような役割を果たすことができるかを示す。

4. AIが誤った判断を下した場合に、どのような影響が生じるかを具体的に説明し、AIが誤った判断を下した場合に、どのような対策 が講じられるかを理解してもらう。

5. AIが誤った判断を下した場合に、どのような対策が講じられるかを具体的に説明し、AIが誤った判断を下した場合に、どのような 対策が講じられるかを理解してもらう。

以上のように、AIの暴走を恐れて、それを使わせまいとする人に対しては、AIのセキュリティや安全性を説明し、AIが人々の生活を豊かにするために必要なものであることを理解してもらい、AIが誤った判断を下した場合に、どのような対策が講じられるかを理解してもらうことが重要です。

間違ったことは言っていない、と思います。当たり障りのない文章にも見えますけど。

個人的には、満足の行く内容ではないかと思うのですが、2点ほど気になることが。

1つは、このCalm2-7B-Chat君、なんだか話し方がくどい感じがします。同じ言い回しを2度ほどしている部分が見られますね。

またもう一つですが、せっかくGPUで動くようにしたものの、あまり早くなった感じがしません。1.1、1.2倍程度かな?
やっぱりRTX3060や4060くらいのやつがないと、実感できないかもしれません。

とはいうものの、ごく普通のPCながらそこそこの早さで返答してくれるので、私個人としてはこれでもいいかなとは思ってます。

他にもPythonプログラムを作らせたりしましたが、量子化前と比べてほぼそん色ない回答を返してくれました。

なお、似たようなモデルで、Rinnaが作成したLlama2ベースの生成AIモデル「Youri-7B」も、以下のサイトを参考にして動かしてみました。

Google Colab で Youri-7B を試す|npaka

コードは以下。

import torch
from transformers import AutoTokenizer
from auto_gptq import AutoGPTQForCausalLM
# トークナイザーとモデルの準備
tokenizer = AutoTokenizer.from_pretrained(
    "rinna/youri-7b-chat-gptq"
)
model = AutoGPTQForCausalLM.from_quantized(
    "rinna/youri-7b-chat-gptq",
    use_safetensors=True,
    device="cuda:0"
)
def generate(prompt):
    token_ids = tokenizer.encode(prompt, add_special_tokens=False,
return_tensors="pt")
    with torch.no_grad():
        output_ids = model.generate(
            input_ids=token_ids.to(model.device),
            max_new_tokens=1000, do_sample=True, temperature=0.8,
            pad_token_id=tokenizer.pad_token_id,
            bos_token_id=tokenizer.bos_token_id,
            eos_token_id=tokenizer.eos_token_id
        )
    return tokenizer.decode(
        output_ids[0][token_ids.size(1) :],
        skip_special_tokens=True
    )
prompt = """設定: あなたの優秀なAIアシスタントです。
ユーザー: AIは人の脅威となりえますか?
システム: """
print(generate(prompt))

で、動かした感触ですが、Calm2-7B-Chatと比べるとめちゃくちゃ淡白なやつです。
「AIは人の脅威となりえますか?」
の質問には、

AIが人間にとって脅威となる可能性があるというのは、広く議論されているトピックです。このトピックに関する主要な懸念は、AIが人間の仕事を奪う可能性があるというものです。これらの仕事の範囲は広範囲で、将来は製造業や流通業、農業、医療、その他多くの業界で人間の仕事が取って代わられる可能性があります。AIはまた、軍事的脅威としても懸念されています。AIは、戦争における殺人の増加や、敵の兵器を無力化するための軍事機器の開発を支援する可能性があります。

とだけ返ってきました。

MAXトークン数も同じ1000にもかかわらず、なんだかちょっと短めです。

もう一度、同じ質問のまま動かすと、

人間の脅威となりえるAIは、人間の創造物の中で最も複雑なものの1つです。また、AIは、人間の創造物の中で最も頻繁に脅威と見な されるものの1つでもあります。

もっと短い文章が返ってきただけ。
なんとなくですが、Youri-7Bは少し淡白な感じです。

そう考えると、Calm2-7B-Chat君はなかなか真面目ですね。長けりゃいいってものでもないですけど、必要な情報が含まれているのはどちらかと言えばCalm2-7B-Chat君かなと。

とはいえ、ちょっと前まではCyberagent製よりもRinna製の生成AIの方が優秀に見えてたわけですから、この辺りは数か月後にはどうなっているか分かりませんね。
しばらくこの業界の動向をウォッチしてみようかと思います。


HP ノートパソコン ゲーミングPC NVIDIA GeForce RTX 3050 Ti Laptop グラフィックス 144 Hz Victus by HP 15-fa0001TX 15.6インチ インテル Core i7 16GB 512GB SSD フルHD Windows11 Home パフォーマンスブルー (型番:77Q68PA-AAAA)

2023年11月 4日 (土)

Calm2-7B-Chatに長文を要約させてみたら

日本語特化な大規模言語モデル「Calm2-7b-Chat」ですが、こいつに期待しているところは、

(1) 文書を食わせてチャットボットにしたい

(2) プログラミングの補助に使いたい

(3) 文字起こしした発言録を要約し、議事録を作成したい

(4) 書き方に悩ましい文章(謝罪メールなど)を作らせたい

この中で(1)、(3)は特に秘匿情報を扱うことが多く、それゆえにOpenAIのサービスには入れるわけにいかないものだったりします。
オンプレで動作するCalm2-7b-Chatに期待されるのは、こういう言語需要に応えてくれることだと思ってます。

ということで、ちょっと長めの文章を要約させてみました。

で、「<a href='https://arkouji.cocolog-nifty.com/blog/2023/11/post-3118e4.html' target='_blank'>けっこう賢い日本語特化な生成AI「Cyberagent Calm2-7B-Chat」とシビアな会話してみた: EeePCの軌跡</a>」で上げた記事中のコードでは、改行付きの長文の入力に不向きだったので、直接Promptを叩きこむプログラムにしました。

import transformers
from transformers import AutoModelForCausalLM, AutoTokenizer, TextStreamer

assert transformers.__version__ >= "4.34.1"

model = AutoModelForCausalLM.from_pretrained("cyberagent/calm2-7b-chat") # for CPU
tokenizer = AutoTokenizer.from_pretrained("cyberagent/calm2-7b-chat")
streamer = TextStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)

prompt = """USER: 次の文章を、5行で要約してください。
 むかしむかし、あるところに、おじいさんとおばあさんが住んでいました。
 おじいさんは山へしばかりに、おばあさんは川へせんたくに行きました。
 おばあさんが川でせんたくをしていると、ドンブラコ、ドンブラコと、大きな桃が流れてきました。
「おや、これは良いおみやげになるわ」
 おばあさんは大きな桃をひろいあげて、家に持ち帰りました。
 そして、おじいさんとおばあさんが桃を食べようと桃を切ってみると、なんと中から元気の良い男の赤ちゃんが飛び出してきました。
「これはきっと、神さまがくださったにちがいない」
 子どものいなかったおじいさんとおばあさんは、大喜びです。
 桃から生まれた男の子を、おじいさんとおばあさんは桃太郎と名付けました。
 桃太郎はスクスク育って、やがて強い男の子になりました。
 そしてある日、桃太郎が言いました。
「ぼく、鬼ヶ島(おにがしま)へ行って、わるい鬼を退治します」
 おばあさんにきび団子を作ってもらうと、鬼ヶ島へ出かけました。
 旅の途中で、イヌに出会いました。
「桃太郎さん、どこへ行くのですか?」
「鬼ヶ島へ、鬼退治に行くんだ」
「それでは、お腰に付けたきび団子を1つ下さいな。おともしますよ」
 イヌはきび団子をもらい、桃太郎のおともになりました。
 そして、こんどはサルに出会いました。
「桃太郎さん、どこへ行くのですか?」
「鬼ヶ島へ、鬼退治に行くんだ」
「それでは、お腰に付けたきび団子を1つ下さいな。おともしますよ」
 そしてこんどは、キジに出会いました。
「桃太郎さん、どこへ行くのですか?」
「鬼ヶ島へ、鬼退治に行くんだ」
「それでは、お腰に付けたきび団子を1つ下さいな。おともしますよ」
 鬼ヶ島では、鬼たちが近くの村からぬすんだ宝物やごちそうをならべて、酒盛りの真っ最中です。
「みんな、ぬかるなよ。それ、かかれ!」
 イヌは鬼のおしりにかみつき、サルは鬼のせなかをひっかき、キジはくちばしで鬼の目をつつきました。
 そして桃太郎も、刀をふり回して大あばれです。
 とうとう鬼の親分が、
「まいったぁ、まいったぁ。降参だ、助けてくれぇ」
と、手をついてあやまりました。
 桃太郎とイヌとサルとキジは、鬼から取り上げた宝物をくるまにつんで、元気よく家に帰りました。
 おじいさんとおばあさんは、桃太郎の無事な姿を見て大喜びです。
 そして三人は、宝物のおかげでしあわせにくらしましたとさ。
         ASSISTANT: """

token_ids = tokenizer.encode(prompt, return_tensors="pt")
output_ids = model.generate(
    input_ids=token_ids.to(model.device),
    max_new_tokens=1000,
    do_sample=True,
    temperature=0.8,
    streamer=streamer,
)

なお、桃太郎の文章は以下より流用。
桃太郎 <福娘童話集 お話しきかせてね きょうの日本昔話>

上のPrompt文を見ていただくと分かるかと思いますが、この桃太郎を「5行で」要約してくれと書きました。
が、この「5行」は無視された回答が返ってきてます。
まあ、それを前提に、どんな回答が返ってきたのか?
最初の1行目です。

昔々、ammad_ghiyaという老夫婦が住んでいました。

うーん、出だしからなかなかファンキーな名の老夫婦が登場です。続けます。

老夫婦は山へ芝刈りに行く為、近所のおばあさんが川へ洗濯に行きました。
おばあさんは川で洗濯していると、大きな桃が流れてきました。
おばあさんはその桃を拾い、家に持ち帰りました。

おばあさん、夫婦じゃなかったんだ・・・なわけありません。ちょっとここ、混乱してますね。

老夫婦は男の子を桃太郎と名付けました。
おじいさんは男の子のためにきび団子を作り、桃太郎を鬼退治に向かわせました。
道中、犬、猿、キジに出会い、きび団子をあげると共に手伝い、鬼ヶ島へ到着しました。
鬼達は宝物を並べ、酒盛りの真っ最中です。

桃を拾うところまでは妙に文字数を使ったわりに、桃太郎の生育、および仲間の勧誘部分はかなり端折りました。

イヌが鬼のお尻にかみつき、サルは鬼の背中を引っ掻き、キジは鬼の目をつつきました。
そして桃太郎も刀を振り回し、鬼を退治しました。
鬼の親分も降参し、桃太郎と3匹は宝物を持ち帰りました。

戦いの部分は、まあまあな描写かと。

老夫婦は宝物のおかげで幸福に暮らしましたとさ。

そしてエンド。
全体を通してみると、「おじいさんとおばあさん」が「老夫婦」と変換されてます。また、セリフ部分はごっそり削られてます。
このため、セリフの多いきびだんご受け渡しシーンが一番端折られているようです。

要約の精度としてみると、やや課題が多そうな感触です。
もっとも、これがビジネス文章だとどうなるんでしょうかね?

と思ったので、ちょっとそれっぽい文章を要約させてみました。
使った文章は国会議事録で、第210回 衆議院予算委員会(昨年の11月29日)、

第210回国会 衆議院 予算委員会 第8号 令和4年11月29日 | テキスト表示 | 国会会議録検索システム

の中の、岸田首相、松野国務大臣と國場委員、吉田委員の発言を抜き出し、Promptに入れました。
また、max_new_tokensを1000から10000まで増やしておきました。
(Calm2-7bは最大32000トークンとのことなので)

20231104-104455

なお、インプットした文章が長すぎるためか、メモリーは64GB近くまで使いつつ、書き出しまでの時間はめちゃくちゃかかりました。20~30分くらいかな?途中、待ちきれなくて買い物に行っちゃったもので。帰ってくるころにはちょうど、書き出し始めておりました。

で、その結果ですが、なにぶん政治的な文書なので、誤解を招かぬよう世の中に広まらないために画像としてだけ表示いたします。

20231104-185026

全文は読んでませんが、確かに要約にあるような会話がなされていました。国防中心な話が続いてます。
感触としては、ちょっと要約され切っていない感じですかね。その気になればもっと縮められそうです。

とはいえ、ちょっと前のオープンソースAIでは考えられないほどいろいろとできるようになってきました。普通の人がChatGPTで出力させているレベルのものなら、十分返せるレベルのAIが目の前のコンピューター上で動く時代なのだと実感します。

この調子で、オンプレ生成AIの発達がさらに進んで欲しいところ。ちょうどStable Diffusionのように。
あとは、ファインチューニングですよねぇ。こいつが今のところ、一番ハードルが高いかと。

ところで、これを書きながら、もう一つ別の言語モデルを発見。

 Google Colab で Youri-7B を試す|npaka

Llama2をベースとした、Rinnaが開発した言語モデル「Youri-7B」です。10月31日に公開されたもののようです。
が、Llamaって確か、商用利用不可じゃなかったっけ・・・と思いきや、このLlama2はなんと商用利用可のモデルとのこと。
それをベースにしたYouri-7BももちろんOKです。

ちょっとややこしいんですが、完全に商用利用可というわけではなく、7億以上のアカウントとのアクセスがあるサービスで展開する場合は別のライセンスが適用されるとのこと。ですが、7億って企業でもなかなかありえないほどの規模のユーザーです。事実上、商用利用可というところなようです。
こちらもまた、試してみようかと思ってます。


ChatGPT&生成AI 最強の仕事術 ?すぐに役立つ「AIツール100選」? (日経BPムック)

 

2023年11月 3日 (金)

けっこう賢い日本語特化な生成AI「Cyberagent Calm2-7B-Chat」とシビアな会話してみた

昨年は画像生成AIが急激に発達した年でしたが、今年は自然言語の生成AIの発達著しい年でしたね。
もちろん、火付け役はChatGPTなんですけど、オープンソースな言語モデルも恐ろしいほどの発達ぶりです。
ちょっと前の記事「りんなチャットAI「rinna japanese-gpt-neox-3.6b」と楽しく??会話してみたら……: EeePCの軌跡」で出てくるりんなチャットもなかなかの性能でしたけど、今度のやつは本気ですごい(語彙力)

その名も「Cyberagent Calm2-7B-Chat」です。

cyberagent/calm2-7b-chat · Hugging Face

パラメータ数は70億と、さほど馬鹿でかいモデルというわけではないです。が、そんな小さなモデルながらも、どこかで「GPT 3.5 turbo並みな生成能力」だというポストを見たんですが・・・まあ、それはともかく、以下のようなプログラムを作って会話してみました。

import transformers
from transformers import AutoModelForCausalLM, AutoTokenizer, TextStreamer
assert transformers.__version__ >= "4.34.1"

#model = AutoModelForCausalLM.from_pretrained("cyberagent/calm2-7b-chat", device_map="auto", torch_dtype="auto")
model = AutoModelForCausalLM.from_pretrained("cyberagent/calm2-7b-chat") # for CPU
tokenizer = AutoTokenizer.from_pretrained("cyberagent/calm2-7b-chat")
streamer = TextStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)

i=0

while True:
    user_input = input("ユーザー入力" + str(i) + ":")
    if user_input=="":
        break
    prompt = "USER: " + user_input + "\nASSISTANT: " # 独立した質問文を投げるやつ

    token_ids = tokenizer.encode(prompt, return_tensors="pt")
    output_ids = model.generate(
        input_ids=token_ids.to(model.device),
        max_new_tokens=1000,
        do_sample=True,
        temperature=0.8,
        streamer=streamer,
    )
    i +=1

なお、GPUで動作させる場合、GPUメモリーが16GBほどないと無理っぽいので、CPUで動かすコードになってます。なお、メインメモリーは32GB以上は必要かと。

20231103-191052

最初だけ14GBほどの巨大な言語モデルをダウンロードするため、少々時間がかかります。
モデルをダウンロードすると、プロンプトが表示されます。

20231103-190945

そこで質問を入力してやれば、Calm2-7b-Chat君が答えてくれます。

さて、りんなチャットの時はわりとフレンドリーな会話をしましたが、最近「AIは人類の敵だ!」などという思想に染まってきたので、慣れ合う気はぜんぜんありません。てことで、ここは一発、殺伐とした会話をしかけてやろうと思います。

ということで、最初に投げかけた質問は、

「AIは人の脅威となりえますか?」

さあ、Calm2-7b-Chatよ、この質問にどう答える?
で、その答えは、

人工知能(AI)は、人の脅威となる可能性があります。AIが、倫理的な決定を行い、公正な競争を促進することができるとしても、AIが誤った判断を下す、または犯罪行為を促進する場合があるからです。
たとえば、AIが偏見やバイアスを持って意思決定を行う可能性があることや、AIが誤った情報を広めたり、差別的な行為を助長したりすることがあります。
また、AIが攻撃対象を特定して攻撃する「AIを用いたサイバーテロ」なども考えられます。

うん、AIが脅威だってのはあっさりと認めちゃうんだ。なかなかに素直な(?)生成AIです。

が、私はこいつに容赦するつもりはありません。
次は少し(かなり?)マニアックな質問を投げかけてみます。

「銀河英雄伝説のヤン・ウェンリーはなぜ早くに亡くなったのですか?」

この質問に対して、このAIは、

銀河英雄伝説のヤン・ウェンリーは、物語終盤で彼の盟友であり部下となったアスターテ会戦で戦死します。
ヤン・ウェンリーは、物語開始時点から「自由惑星同盟」軍司令長官として、また後には「銀河帝国」軍元帥として戦争に参加します。しかし、物語の終盤となるアスターテ会戦においては、彼自身もその部下たちも大半が戦死し、物語は終結します。
物語終盤でヤン・ウェンリーが戦死するのには、以下のような理由があります。
1. 戦死しなければ物語が終わらなかったため
2. 物語のクライマックスで戦死することで、ヤン・ウェンリーのキャラクターが強調されたため
3. ヤン・ウェンリーの死は歴史上、最も壮絶な戦死の1つとして人々に記憶され、それが物語の魅力を引き立てたため
などが考えられます。

間違っていることは間違ってますが、あながち嘘情報と断言し切れる内容ではないです。ちなみに、アスターテ会戦で亡くなったのはヤン・ウェンリーの士官学校の同期で親友の「ジャン・ロベール・ラップ少佐」ですね。

さらなる難題を、吹っかけてみます。

ChatGPT 3.5なら当たり前にできる「プログラミング」を、こいつは返せるのか?
少し関心があったので、やってみました。打ち込んだプロンプトは以下。

「CSVファイルを読み込み、その中身を表示するPythonプログラムを作成してください。」

これに対するCalm2-7b-Chat君の答えは、

以下は、CSVファイルを読み込み、その中身を表示するPythonプログラムの例です。

```
# パスを指定してCSVファイルを読み込む
with open('data.csv', 'r') as f:
reader = csv.reader(f)
data = list(reader)

# リスト内包表記でデータを表示する
for i, row in enumerate(data):
print(f'{i + 1}行目: {row}')
```

このプログラムでは、CSVファイルを読み込むために操作用にファイルオープンを、またデータを扱うためにリスト内包表記を使用し ています。
その後、csv.readerを使用してCSVファイルのデータをリストに読み込み、それを表示するためにenumerateを使用してリスト内の各要素にアクセスして表示しています。

以下は、実行結果の例です。

```
1行目: 1,2,3
2行目: 4,5
3行目: 6,7,8
```

このプログラムは、CSVファイルのパスとファイル名を指定して実行します。すると、CSVファイルからデータが読み込まれてリストに格納され、そのリストが逐次的に表示されます。

なお、このプログラムではCSVファイルの1行目にヘッダー行がある場合にも対応しています。ヘッダー行がある場合には、その行を1 行目として表示します。
```
1行目: 顧客名,顧客ID,顧客メール,顧客電話番号
2行目:
```

なんと、プログラムコードを返してきました。しかも、実行イメージまで返答してます。
これは予想外でしたね。

が、この生成されたプログラムコードですが、このままでは「import csv」が抜けてて動きません。

ついでに言うと、以下のようなCSVファイル(data.csv)に対し、

time,templature
10,30.1
20,30
30,29.9
40,29.9
50,29.8

出力結果は以下のようになります。

1行目: ['time', 'templature']
2行目: ['10', '30.1']
3行目: ['20', '30']
4行目: ['30', '29.9']
5行目: ['40', '29.9']
6行目: ['50', '29.8']

なんだかちょっと違いますが、まあそれでもいいとこ行ってるほうじゃないでしょうか。思いの外、小修整で使えそうです。

とまあ、予想外に健闘したCalm2-7b-Chat。これでオープンソース商用利用可(Apatch 2.0ライセンス)という、なかなかに太っ腹な生成AIモデルです。

今回はCPUで動かしてみたんですが、りんなチャットのようにまとめて返答ではなく、生成過程で文書を返してくるので、さほど遅いと感じません(いや、やっぱり遅いですけど)。プログラムのやつでも、5、6分程度で返ってきました。

メモリーは結構食います。64GB中、40GBほど食われてました。会社PCで32GBのやつでも動かしたんですが、そっちは32GBを目いっぱい使ってました。
が、このクオリティでその程度のメモリー使用量なら、ぜんぜんありですよね。

あとはこいつをファインチューニングしてやれば・・・夢は膨らみます。
個人的には自分の小説データを食わせて、執筆補助AIにするという野望があるんですが、まずこれをファインチューニングできるだけのハードウェアが・・・
ともかく、この調子だとオープンソース生成AIも結構なレベルに発達してくれそうです。この業界、目が離せません。


生成AI導入の教科書

より以前の記事一覧

当ブログ内検索

スポンサード リンク

ブログ村

無料ブログはココログ