LINE の日本語言語モデル「japanese-large-lm（ジャパニーズ ラージ エルエム）」を M2 Mac で動かしてみる

LINE が日本語言語モデル「japanese-large-lm（ジャパニーズ ラージ エルエム）」を公開してくれました。  
LINE Engineering Blog: [36億パラメータの日本語言語モデルを公開しました](https://engineering.linecorp.com/ja/blog/3.6-billion-parameter-japanese-language-model)

> ライセンスは商用利用も可能なApache License 2.0としましたので、研究者の方だけではなく、企業の方にも様々な用途でご利用頂けます。  

太っ腹ですね。  
Hugginface Hub で公開していたので、M2 Mac でも動かせるか試してみました。

# 実行環境
* 筐体: MacBook Air 2022
* チップ: Apple M2
* メモリ: 24 GB
* macOS: Ventura 13.4.1 (c)
* Python: 3.9.16
* PyTorch: torch==2.1.0.dev20230814

# 事前準備
Apple シリコン搭載モデルでは CUDA は使用できません。  
MPS で実行するには PyTorch の Nightly ビルドが必要でした。  
Nightly ビルドは次のコマンドでインストールできます。

```sh
$ pip install --upgrade --no-deps --force-reinstall --pre torch torchvision --index-url https://download.pytorch.org/whl/nightly/cpu
```

ちなみに PyTorch 2.0.1 で実行したときに出るエラーメッセージは次のものでした。  
```sh
RuntimeError: MPS does not support cumsum op with int64 input
```

さらにちなみに、MPS でなく CPU を使おうとしてもエラーになりました。  
モデルの指定時のオプション `torch_dtype=torch.float16` を消すと動かせました。  
```sh
RuntimeError: "LayerNormKernelImpl" not implemented for 'Half'
```

# 実際に動かしたコード
ほぼ文頭の Blog のエントリーの通りなんですが、一部修正しました。  
```python
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline, set_seed


model = AutoModelForCausalLM.from_pretrained("line-corporation/japanese-large-lm-3.6b", torch_dtype=torch.float16)
tokenizer = AutoTokenizer.from_pretrained("line-corporation/japanese-large-lm-3.6b", use_fast=False)

# *** 変更ここから ***
# generator = pipeline("text-generation", model=model, tokenizer=tokenizer, device=0)
# MPS を指定する
device = torch.device('mps')
generator = pipeline("text-generation", model=model, tokenizer=tokenizer, device=device)
# set_seed(101)
# *** 変更ここまで ***
   
text = generator(
    "おはようございます、今日の天気は",
    max_length=30,
    do_sample=True,
    pad_token_id=tokenizer.pad_token_id,
    num_return_sequences=5,
)
 
for t in text:
  print(t)
```

# 得られた結果
次のような結果が返ってきました。  
無事動いてくれました。  
generator() の実行時間は 11.849 秒でした。

```sh
{'generated_text': 'おはようございます、今日の天気は、曇り。雨は降っていませんが、どんよりとした曇り空です。 気温は25°C、少し蒸し暑い'}
{'generated_text': 'おはようございます、今日の天気は雨です。今朝も30度を超えていました、湿度は70%近く、不快指数は80超です、'}
{'generated_text': 'おはようございます、今日の天気は曇り、雨は降らなそうです。 昨日よりの雨で、田んぼの水位が上がり、流された草の種も'}
{'generated_text': 'おはようございます、今日の天気は。 昨晩、飲み過ぎで起きたのは8時半過ぎ、二度寝して9時前に起床した。 1週間ぶり'}
{'generated_text': 'おはようございます、今日の天気は雪模様、、、、、。 積もっていそうだ。 さて、昨日は、... 666回'}
```

ちなみに 1.7 B 版も動かしました。  
こちらは generator() の実行時間は 9.323 秒でした
```sh
{'generated_text': 'おはようございます、今日の天気は、曇り。雨かもですね。昨日は、仕事の関係で、少し遅くなる為、夜ご飯を食べれませんでした。なので、昨日食べた'}
{'generated_text': 'おはようございます、今日の天気は雨です。 でも昨日は30度近くまで 気温があがりましたね。 この時期、昼間は半袖が 着れます'}
{'generated_text': 'おはようございます、今日の天気は曇り、雨は降らなそうです。 昨日、今日と大阪城ホールのコンサートでした。 今日もたくさんのお客様にお越し頂きました'}
{'generated_text': 'おはようございます、今日の天気は。 昨晩、飲み過ぎで起きたのは8時半過ぎ、その後風呂に入り、ビールをのみ。'}
{'generated_text': 'おはようございます、今日の天気は雪模様、、、、気温も-13°Cと寒い。 今日は、朝から、S君が来てくれました。'}
```

お酒飲み過ぎがちなのは筆者の何らかの情報を少し不思議な力で読み取っているからか……。

# もう少し触ってみる
## 文字数を増やす
3.6 B モデルで 30 文字の制限を 200 文字に延ばしてみました。   
メモリ不足のエラーで落ちてしまいました。
```sh
RuntimeError: MPS backend out of memory (MPS allocated: 7.58 GB, other allocations: 19.61 GB, max allowed: 27.20 GB). Tried to allocate 10.08 MB on private pool. Use PYTORCH_MPS_HIGH_WATERMARK_RATIO=0.0 to disable upper limit for memory allocations (may cause system failure).
```

エラーメッセージの通り環境変数を設定して再実行してみたら、無事動作しました。  
実行時間は 111.472 秒でした。  
30 文字のときに対して 10 倍くらい時間がかかりました。
Transformer を使った文章生成では、末尾の単語から次の単語の生成を行うことを繰り返します。  
文章が長くなるほど多く生成を繰り返すことになるので、この動作は想定の範囲内でしょう。  
```sh
{'generated_text': 'おはようございます、今日の天気は晴れ です。 さて今日の朝は、先日の日曜日ですが 、 娘の所へ行って来ました。 この所の急激な冷え込みでしたが、 日中は太陽 も射し良いお天気で...\nこんにちは、今日の天気は晴れ です。 先日、 娘の所に行った時に お花 が、 咲いていたので撮って来ました。 キンポウゲ科キンポウゲ属 の多年草の 『 トリカブト 』 になります...\nこんにちは、今日の天気は晴れ です。 昨日の夜から天気は下り坂で 、 朝9時ころには雨 が降ってきました。 今日は天気は下り坂ですが、 今日も お花の紹介 をしたいと思います。...'}
{'generated_text': 'おはようございます、今日の天気は晴れですね、今日の話題は「私の履歴書」、私の履歴書(31)「出光佐三さん」についてお話を致します。出光佐三さんは明治40年、鹿児島県出身。帝国大学を出て実業家に。そして出光興産の創業者出光佐三さんの半生について、私なりにお話をさせて頂きます。\n出光佐三さんは鹿児島県の生れですが、幼時から父出光を「おやじ」と呼び、尊敬し、その意志を継ごうと勉学に励んだということです。小学校4年生の時、学校で行われた写生大会で、出光佐三さんは当時流行っていた石炭業を題材に、1時間かけて写生したそうです。その絵が入選すると、それを持ち帰れたということですが。\nその後、佐三さんは小学校5年生の時、「出光商会」に勤め、それから中学を出て、中学浪人を3年間も経験、働きづめの人生が始まります。この時の経験が今の出光の原点'}
{'generated_text': 'おはようございます、今日の天気は雪。\n\n で、今日のテーマですがズバリ「私流の年賀状」です。\n\n と言うのも、年賀状で知り合った友人から、こんな文章で手紙が届いたのです。内容は、毎年年賀状のやり取りをしていた友人が病気で入院して、年賀状のやり取りが出来なくなっているので、何か年賀状の代わりになる物を送ろうと言う事です。\n 私としては、正直「何で年賀状がいいのに手紙なの?」と疑問に思っていました。だから、「何で手紙なの?」と聞いたのですが、返って来た答えが「年賀状のやり取りを止めた人の中には、年賀状が来ないので、もう私のことを忘れられてるんじゃないかと不安に思う人も居ると聞いたし、私も年賀状が来なくなると淋しくなるから」と言うのです。\n\n 確かに、その友人の気持ちは分かります。私だって、年賀状でやり取りをしていた友人が病気になって入院して、年賀状が来なくなると本当に心配になります。だって、それまで本当に仲が良かった友達なのですから・・・\n\n そこで私は手紙ではなく、その友人が今まで使っていた物より一回り大きいサイズの手紙用の'}
{'generated_text': 'おはようございます、今日の天気は曇です、最高気温は31度です 。 風は涼しいですので、過ごし易いです、昨日も涼しかったので、体調が よかったです 体調がいいと、活動的になります。 今日の花に、花の名前を教えて、くださ~い。 花の名前は分かりません、撮影 2016.9.29 撮影 posted by けいこ at 13:18| Comment(0) | TrackBack(0) | 日記 今日の花に、花の名前を教えて、くださ~い。 おはよう、今日の天気は雨です、最高気温は27度です 。 風は涼しいですので、過ごし易いです、昨日も涼しかったので、 体調がよかったです 体調がいいと、活動的になります。 今日の花に、花の名前を教えて、くださ~い。 花の名前は分かりません、撮影 2016.9.28 撮影 posted by けいこ at 09:38|'}
{'generated_text': 'おはようございます、今日の天気は晴れ。 気温も上がっていい天気に。 気温は高めなんだろうけど。 風が冷たかった。 風が冷たいとやっぱり春という気がしないので。 暖かくなってほしいな。 花粉も飛んでるみたいだし。 花粉症の人は大変だろうなぁ。 僕は花粉症ではないので。 そういう苦労もないのですが。 暖かくなってくると春だなと思う。 やっぱり暖かい方が好きだなぁ。 今日はこれからちょっと出かけるので。 いつもよりは時間があるので。 のんびりとしています。 ここのところ時間がなくて。 毎日慌ただしい生活をしていたので。 今日はゆったりと。 したいんだけど。 なかなか時間が作れないんだよなぁ。 時間が出来たら。 のんびりできるんだけどね。 のんびりとする時間が取れるかな。 最近は時間が無くて。 1日の中で。 ゆっくりする時間がない。 休みもあんまり無いので。 疲れも溜まるんだろうなぁ。 たまにはのんびりしたい。 ゆっくりする時間が取れると良いんだけど。 今はあんまり取れそうに無いなぁ。 そんな感じで。 今日はこれから外出。 のんびりできると良いなぁ。 今日はいい天気で'}
```

3行目の出力結果ですが、`posted by けいこ at 13:18| Comment(0)...`という記述が見られます。  
Web で収集したデータをクリーニングして学習データとしているとのことなので、誰かのブログのエントリーを学習したときのゴミのようです。  
（ちなみに Wikipedia さんによるとトリカブトはキンポウゲ科トリカブト属だそうです）

300 文字に延ばしたところ、メモリ不足で OS が落ちました。

## ベースのテキストを少し変えてみる
少しベースのテキストを変えて生成してみました。  
```python
text = generator(
    "台風の強い風で庭のプランターが倒れちゃった。週末は",
    max_length=200,
    do_sample=True,
    pad_token_id=tokenizer.pad_token_id,
    num_return_sequences=5,
)
```

```sh
{'generated_text': '台風の強い風で庭のプランターが倒れちゃった。週末はベランダの掃除かな。'}
{'generated_text': '台風の強い風で庭のプランターが倒れちゃった。週末はお天気いいみたいだからベランダの植え替えしなくちゃ。昨日は10時から17時までの長丁場。休憩をはさんで3回お茶を淹れたけど、ほとんど飲まずじまい。途中でちょっと口をつけたらすごくおいしかったんだけどね。 午前中は新人さんと2人でお仕事。新人さんが2歳2か月、私が38歳。年齢的には私の方が2つ下なんですが、私よりもずっとしっかりしているので、頼りになります。その方のお子さんは6歳と2歳。お子さんたちの年齢差にびっくりしちゃった。 10時半には休憩して、11時15分にランチ。その後15分に1回お茶を飲んでおしゃべり。やっぱり疲れたなぁ。 お茶は、昨日も今日も2回も淹れたけど、あまり飲まなかったなぁ。そのせいか、ちょっと風邪気味。まだのどの痛みはないけど鼻づまり&鼻水。'}
{'generated_text': '台風の強い風で庭のプランターが倒れちゃった。週末は台風の強風で、せっかく咲いた花も、台風で倒れてしまっていたので、今日、家の周りを見て回りました。 プランターごと、倒れていました。 お花が倒れていたから、花びんに挿しておくことにしました。 大きな鉢植えとミニバラです。 ミニバラは、蕾がやっと咲きそうだから、もう少しかな? もうしばらくしたら、植え替えてあげよう。 今日は、とっても暑くて、汗がダラダラでした。 お昼前から夕方まで、庭にいたけれど、蚊が寄ってくるから、あまり庭では、のんびりできません。 お花を買ってきて、家に入ると、家も暑くて、なかなかエアコンが効きません。 庭に出て、草取りしたりしたら、汗が出て、エアコンのきいた部屋に入ると、涼しくて、扇風機があればいいけれど、エアコンだけだと寒い。 なので、エアコンがきいている部屋に、また庭に戻り、草取りして、今度は、蚊との戦いでした。 夕食の準備の前に、プランターを片付けることにしました。 玄関'}
{'generated_text': '台風の強い風で庭のプランターが倒れちゃった。週末は、お花たちにお水をあげないとね。今日は、台風一過で暑くなるみたいね。みなさん、お気を付けくださいね。ご訪問をありがとうございます。1日1回、下の応援バナーをポチっと 押していただけると、とても励みになります。応援、よろしくお願いします。にほんブログ村 みなさん、こんばんは。今日の夕ご飯は、お肉とお野菜の炒め物と、お味噌汁だよ。お味噌汁は、豚肉と玉ねぎ、豆腐で、味噌味で作ったよ。炒め物は、豚肉とキャベツ、なす、えのきで炒めた。豚肉、キャベツ、なす、えのきの炒め お肉は、しょうが焼きにする予定だったけど、豚肉がちょっとしかなかったから、 急遽、豚肉とキャベツ、なす、えのきを使ったよ。いつも、しょうが焼きとか、とんかつとかをするときに、多めにお肉を買って、 それを冷凍保存しておくんだよ。そうすると、急にトンカツが食べたいって思った時に作れるからね。しょうが焼きとか、とんかつとか、揚げものやお肉を使ったメニューの時は'}
{'generated_text': '台風の強い風で庭のプランターが倒れちゃった。週末はまた台風が来るらしいので飛ばされないように補強。庭の多肉がまた増えたな~。'}
```

にほんブログ村に豚肉が大好きな人がいるようです。  

## 少しフォーマルな文章にしてみる
少しフォーマルな文章も試してみました。

```python
text = generator(
    "ガムテープを買ったのにセロテープが届きました！返品します！\n\n佐藤様\nお世話になっております。\n商品の配送に誤りがあり、誠に申し訳ありませんでした。",
    max_length=200,
    do_sample=True,
    pad_token_id=tokenizer.pad_token_id,
    num_return_sequences=5,
)
```

```sh
{'generated_text': 'ガムテープを買ったのにセロテープが届きました！返品します！\n\n佐藤様\nお世話になっております。\n商品の配送に誤りがあり、誠に申し訳ありませんでした。\n現在、正しいものを配送中です。\n到着まではしばらくお待ちください。\nご迷惑おかけしまして誠に申し訳ございませんでした。\n何かございましたら、ご遠慮なくご連絡ください。\n今後とも、よろしくお願いいたします。\n\n\n\n\nというメールだったんですが、\n謝罪文の中に\n\n「誠に申し訳ありませんでした」\nとあるのは日本語として正しいのでしょうか?\n\n\n謝罪文の\n「申し訳ございませんでした」が常用されると思うのですが・・。\n\n\n\n\nちなみにこのメールを受け取ったのは昨日です。\n\n正しいも誤っているも、もう相手に届かないのでどうでもいいのですが、\n\nなぜ謝罪文の中に「誠に申し訳ありませんでした。」が入っていたのか気になります。\n\n\n\n\nよろしくお願いいたします。\nA: ごめんなさい。という日本語はありませんが、\n日本語には「すみません」「すみませんのございます」など\n「すみません」は多数あり、\n\n「申し訳ございませんでした」   \n「'}
{'generated_text': 'ガムテープを買ったのにセロテープが届きました！返品します！\n\n佐藤様\nお世話になっております。\n商品の配送に誤りがあり、誠に申し訳ありませんでした。\n返品について、返品理由とともに下記までご返送をお願い致します。\n\n返品先住所:*******************\n商品:*******************\n返品商品名:*******************\n\n◆以下、キャンセルと返品の方法\nhttp://www.mr-bike.com/maintenance-c-28.html\n\n◆返品の理由:\n1. 運送上の不備(誤配)\n2. 間違ったものが届いた\n3. 注文した物と届いた物が違った\n4. 注文時に間違った\n    ( 3,000円で頼んだはずが、2,500円だった。)\n5. 間違って頼んだ物を返品したい。\n6. 商品が気に入らない。\n\n◆返品後について:\n1. 注文した日に商品を発送している。\n      ↓ 注文時'}
{'generated_text': 'ガムテープを買ったのにセロテープが届きました！返品します！\n\n佐藤様\nお世話になっております。\n商品の配送に誤りがあり、誠に申し訳ありませんでした。\n\nつきましては、下記2点のご対応を頂きたく、ご連絡いたしました。\nご都合の良いお時間をご連絡頂けますでしょうか?\nどうぞよろしくお願いいたします。\n\n ・ガムテープのお届け\n (宛名:株式会社○○ ○○宛) \n ・弊社からのご返金\n ・商品代金、送料(830円×商品発送数)、消費税=合計金額\n\n ・1、お支払方法\n    振込みもしくは商品代引き(1,080円-830円=470円)\n    いずれの場合でも返金は振込み。代引の場合は商品代金のみ返金。\n    商品はヤマト便にて着払い、もしくは弊社指定の宅配業者にて\n    返品。(返品送料はお客様負担)\n ・2、返品連絡先\n    電話番号'}
{'generated_text': 'ガムテープを買ったのにセロテープが届きました！返品します！\n\n佐藤様\nお世話になっております。\n商品の配送に誤りがあり、誠に申し訳ありませんでした。\n下記のとおり、ご対応と返金処理を進めております。\nお手数ですが、ご入金の際は下記の返金口座番号まで\nご入金下さいますようお願い申し上げます。\n\n返金口座番号:○□□□-○○○○ 返金金額:○○○円\n\n※返金処理には4~6営業日ほどかかります。\n\n返金期日経過後は、返金処理ができなくなりますので\nお早めにご入金くださいますようお願いいたします。\n\n \n\n 投稿者:佐藤\n\n 投稿日:2015年 6月28日(日)00時27分41秒 \n\n \n\nお世話になっております。\nご入金頂きました商品配送いたしました。\n\n商品:ガムテープ\nご注文番号:xxxxxxxxxxxxx\n\n \n\n 投稿者:森川\n\n 投稿日:2015年 5月31日(日)06時0'}
{'generated_text': 'ガムテープを買ったのにセロテープが届きました！返品します！\n\n佐藤様\nお世話になっております。\n商品の配送に誤りがあり、誠に申し訳ありませんでした。\n下記のメールに誤りがあることをご報告させていただき、至急正しい商品を発送いたしますのでご安心くださいませ。\n\n※商品到着予定日:1月24日 到着済み \n\n今回の注文ですが、2020年に販売し今年また販売した商品で、商品の品質に問題はないと思うのですが、いかがでしょうか?\n\n何卒ご検討のほど、よろしくお願い申し上げます。\n\n株式会社SinJapan\n担当:Sin Japan 福田 博之\nカスタマーサービス:xxxx@yyy.com\n\n\n        \n\n\t\t\t          \n\n\t\t\t\t        \n\n        \n\n\t\t\n\n\t\n\t\n\tこの投稿はお客様より対応「good」の評価を頂きました!\n\t2022/01/15 23:12:12\n\tガムテープを買ったのにセロテープが届きました!'}
```

なんとなくそれっぽい文章が生成されています。  
料金の記載や手続き方法などが生成されました。  
メールを書くときの参考に……なんていうときに使えたりして。  

批判的な雰囲気のものもあります。  
個人ブログなどでは批判のほうが取り上げられやすい印象がありますので、学習データのバイアスが気になるところです。  
（この印象もバイアスかもしれません） 
口座番号など個人情報はマスクされているみたいですね。

# 終わりに
使うのは本当に簡単です。  
Hugginface 使ったことがあればすぐに使えるでしょう。  
また、このモデルの生成する文章は AI っぽくなく自然に思えるものが多い印象を受けました。  

問題はビジネス実装するときのエラーやトラブルの対策でしょうか。  
今回みたいにフリーフォーマットな文章がベースになると、想定しない結果が返ってくることもあります。  
（LINE のモデルがどうこうではなく、汎用化された機械学習モデル全般の課題）  

お試しした範囲ではブログのエントリーにくっついたゴミが出てきました。  
このようなゴミはどうやって除去すれば良いのか……。  
ある程度は正規表現パターンで置換したりできそうですが、イタチごっこですね。  

ブログのエントリー末尾にはこのような記載もありました。

> また、これらのモデルについて、指示文に対して適切な出力を行えるようにチューニング（Instruction tuning）したモデルを近日中に公開予定です。続報は@LINE_DEVをフォローしてお待ち下さい。

どのような使い方を想定しているか、チューニング方法は、といったところ、これからどんな発展があるか楽しみですね。