はじめに
麻雀の点数計算は面倒です。符と翻を数え、親か子か、ツモかロンかで表を引く。覚えていても間違えますし、間違えるとそのあとのカラオケ代が変わります。
牌を写真に撮って点数を出すサービスはすでにありましたが、対局中に使うと、撮って、認識させて、間違っていたら直す、という手順が毎回挟まります。欲しかったのは、手牌にスマホを向けておくだけで点数まで進んでくれるものでした。それで、カメラを向けるだけで手牌・副露・ドラを読み取り、点数計算まで進むWebアプリ「mjtensu」を作りました。
この記事は、作り始めに要求をどう置き、そこから構成と評価をどう決めたかの全体像です。モデルの軽量化や評価基盤などの詳細は別の記事に分けていて、最後に一覧を置いています。
目次
- 「向けておくだけ」を時間と操作数に置き直す
- カメラ画像を外に出さないために、モデルを3つに分ける
- 評価を学習時の数字からiPhone実機まで広げる
- 増え続ける実験をあとから追えるようにする
- 速くしたら今度は確定が早すぎた
1. 「向けておくだけ」を時間と操作数に置き直す
「向けておくだけ」では、どこまで作れば完成か決まりません。そこでまず時間に置き直し、アプリを開いてから点数が出るまで20秒以内、そのうち認識に使えるのは約3秒、と見積もりました。どちらも体感で置いた仮の数字です。
配布はPWAにしました。ネイティブアプリのほうが作りやすい面はありますが、App Storeで公開し続けるには年に1.5万円ほどかかり、需要も分からない個人開発で払う理由が薄かったからです。
ここまでを、確かめられる要求4つにまとめました。
| 要求 | 具体化 | 確認方法 |
|---|---|---|
| 撮影操作をなくす | シャッターを押さず、向けている間ずっと認識する | 画面の流れに撮影の操作がない |
| 入力の手間を減らす | 手牌・副露・ドラを1画面で読み、安定したら自動で次へ進む | 認識画面から条件確認まで操作なしで進む |
| ストア公開を不要にする | ホーム画面に追加できるPWAにする | iPhoneのSafariで開き、ホーム画面に追加できる |
| 対局中に待たせない | iPhone上で認識を回し続け、約3秒に収める | iPhone 13の実機で認識1回の時間を測る |
コードは生成AIに書かせていて、自分が持っているのは要求、方式、実験計画、評価基準、採否の判断です。実写の撮影とアノテーションも自分でやりました。
2. カメラ画像を外に出さないために、モデルを3つに分ける
認識はサーバに送らず、ブラウザの中で完結させています。向けている間ずっと認識を回すので、毎回の通信待ちを入れたくなかったし、卓や周りが映った画像を外に送り続けたくもなかったからです。その代わり、モデルの大きさとiPhone上の速さに厳しい制約がかかります。
既存サービスのひとつ、RiichiCamの旧ブラウザ版は、牌の位置と種類を1つのモデルでまとめて出す構成で、モデルは約76.8MBありました1。いまのRiichiCamは、ブラウザ内の推論をやめてサーバに送る構成に変わっています2。
mjtensuでは、これを役割ごとに3つのモデルに分けました。1つにまとめると、位置のずれと種類の取り違えが同じモデルの中で混ざり、どちらが悪いのか切り分けにくいからです。分類器の2つは「回転同変CNN」という、牌が回転していても同じ答えを返すように作られたモデルです。
カメラ映像
↓ 手牌・ドラ・副露の枠だけを320×320の1枚にまとめる
検出器(NanoDet) : 牌の位置を探す
↓ 牌を1枚ずつ切り出す
牌種分類器 : 34種類を見分ける
赤5分類器 : 赤5かどうかを見分ける
↓ 3回続けて同じなら確定
点数計算
| モデル | ファイルサイズ |
|---|---|
| 検出器(NanoDet) | 4,734,123 bytes |
| 牌種分類器 | 522,705 bytes |
| 赤5分類器 | 662,382 bytes |
| 合計 | 5,919,210 bytes |
合計は約5.9MBで、旧RiichiCamのモデルの約14分の1です3。2つの分類器は最初はこの何倍もあり、作りながら削ってきました。
3. 評価を学習時の数字からiPhone実機まで広げる
画像認識は、学習時の数字が良くても使ってみると壊れます。検出器は静止画では評価値が良かったのに、動画で回すと1枚の牌に枠を何重にも出したり、背景に小さな枠を出したりしましたし、4筒を2筒2枚として拾ったこともありました。
そこで評価は、モデル単体から少しずつ外側へ広げています。
| どこで見るか | 確かめること |
|---|---|
| モデル単体 | 検出・分類の正解率 |
| 実際の動画 | 枠の重複、背景の誤検出、フレーム間のぶれ |
| ONNXに書き出した後 | 書き出し前と同じ答えを返すか、推論ライブラリでの速さ |
| iPhone実機 | 本番の端末で認識を回し続けられるか |
ただ、一番外側のiPhoneでの計測はよく途中で落ちたので、しばらくは手元のPCで測った速さで代用していました。あとで同じモデルをiPhoneで測ると、PCでは1.8倍遅かったモデルが、iPhoneでは1割遅いだけでした。これに気づくまで、PCの数字でモデルの候補を狭めていたことになります。
4. 増え続ける実験をあとから追えるようにする
実験の投入をAIに任せると、条件の少しずつ違う学習が短時間で何十本も増えます。どのモデルをどの条件で学習し、どう評価したのかをまとめて残しておかないと、あとで比べられませんし、アプリに載っているモデルがなぜそれなのかも分からなくなります。
そこで、実験の条件と結果は機械が読める形式で、何を調べて何を判断したかは文章で、と分けて残しています。文章の調査記録だけで、いまは40件を超えました。
5. 速くしたら今度は確定が早すぎた
認識に使えるのは約3秒と見積もっていましたが、いまの認識は1回120〜140msほどで4、3回続けば確定するので、処理だけなら0.4秒ほどで揃います。すると今度は、カメラの位置を合わせている途中でも同じ結果が3回続き、合わせ終わる前に確定してしまうようになりました。
いまは暫定で認識の間に50msの待ちを入れ、確定までを約0.5秒にしています。50msに根拠はないので、次のどれかで作り直すつもりです。
| 案 | 決めるために測るもの |
|---|---|
| 最低表示時間を設ける | 位置合わせにかかる時間の分布 |
| カメラ位置が合っていることも確定条件にする | 位置ずれの判定基準と、その誤判定率 |
| 確定前に視覚的なフィードバックを出す | 確定前に操作が止まる頻度 |
おわりに
要求を時間と操作数に置き直したことで、ブラウザ内で完結させる、役割ごとにモデルを分ける、iPhone実機で測る、という方針がほぼ決まりました。その結果、20秒以内を目標に始めたアプリが、いまは速すぎて困っています。
それぞれの詳細は、次の記事に書いています。
- スマホのカメラで麻雀の手牌を読み取るWebアプリを作った: アプリの使い方と、苦手なこと
- 同じ回転同変CNNから、別々の形に落ち着いた2つの分類器: 2つの分類器をどう軽くしたか
- 実験の数字を覚えていなくても、過去のモデルと比べられるようにする: 4章の記録の残し方
- 同じONNXモデルでも、PCとiPhoneでは速さの傾向がまるで違うらしい: 3章のPCとiPhoneの差
