動画の機械学習についておべんきょ
「ゲームのプレイ動画を分析したいなー」
でも全部の動画を自分の目で見て、分析するなんて、、、大変やん、、、
ってことで、動画の分析を機械学習で出来ないかなーということを調べる。
具体的に
最終的には対人ゲーでやりたいけど、ひとまずPvEでやる。
PvEでもPvPでも最終的な目標は成功・勝利すること。
成功・勝利するためにはどのような行動が適切で、どのような行動が不適切か、というのを分析したい。
こんな感じかな~と想像すると、
動画から行動を抽出する → 行動の有無・多少を集計 → 集計結果と結果の関連性を分析
になると思ってる
つまり、
動画から抽出したい行動の選択 → 動画に対して行動の抽出の機械学習 → 学習した分析器による行動の集計 → 集計結果とゲームの結果の関連性の機械学習 → 動画で行なった行動の評価
という流れになるはず
数値だけの教師あり機械学習は聞きかじった情報が少なからずあるけれど、
動画から行動の抽出なんてのは全然知らないので、そのことをしっかり調べていきたい。
深層学習による AI 実況プレイ動画生成
画像認識/動作認識/物体検出を用いた画面認識
知りたかったことドンピシャに試している研究があった
画像認識は CNN(Convolutional Neural Network)というモデル
動作認識は LRCN(Long-term Recurrent Convolutional Network)というモデル
物体検出は SSD(Single Shot Multibox Detector)というモデル
どれも知らないので、とりあえず画像認識から順番に調べていきたい
Convolutional Neural Networkとは何なのか - Qiita
CNNはその名の通り通常のNeural NetworkにConvolutionを追加したもの
基礎としてNNがある。
NNはぼんやり知識で知ってる程度なので、知識が必要そうならあとで掘る
画像上にフィルタと呼ばれる小領域をとり、これを1つの特徴量として圧縮します。
領域をスライドさせながら繰り返していきます。
画質を落とし、粗く特徴を掴もうということかな?
フィルタを使った「畳み込む」という処理は、具体的には「フィルタ内の画像のベクトル」と「畳み込みに使用するベクトル」との間の掛け算、内積になります。
画像のベクトルは、どこからどこに線が引かれているか。という情報なんだろうと。
畳み込みに使用するベクトルはどのようなものを与えるのか分からないけど、
方向性の分かるものだったら良いんじゃないかなーと。
その内積なので、二つのベクトルが同じ方向を向いたらどれくらいの強さかーってことかな。
畳み込み層を通常のNeural Network同様、活性化関数でつないでいったものがConvolutional Neural Networkとなります
活性化関数は数値が一定以上なら有効、そうでないなら無効という切り分けをするための関数だったと記憶してる
弱いベクトルはその時点で捨てられ、強いベクトルはより強く次のノードに届けられる。
こっから先はNNと同じで学習し、最後に新たな画像を与えると結果が得られるって感じかな?
NNもぼんやりになってるから、後から調べよう。
とりあえず、CNNの畳み込みがどういうものか、畳み込み以外はNNと変わらないということが分かった。
LRCNによる参照点に依存した動作の認識
LRCN は,二種類のニューラルネットワークから構成されるディープニューラルネットワークである
1 つ目は,Convolutional Neural Network
2 つ目は,Long Short-Term Memory
CNNは上で確認した、画像認識の畳み込みNN。
Long Short-Term Memory は初めて聞くので、確認が必要。
長・短期記憶 - Wikipedia
LSTMは(画像といった)単一のデータ点だけでなく、(音声あるいは動画といった)全データ配列を処理できる。
つながった手書き文字認識や音声認識といった課題に適用可能
LSTMネットワークは時系列データに基づく分類、処理、予測によく適している
仕組みまでは分からないけど、連続する情報を持ち続けるのかなーみたいな印象。
【物体検出】SSD(Single Shot MultiBox Detector)の解説
画像内に犬が2匹以上いた場合は対応できなくなってしまいます
あーそうか
どの物体に対して検知するかを正しく振り分けられないと、
全然違う物体を勝手に判定して、勝手に学習するかもしれないってことか
とりあえず出来そうなことを考えてみる
難しいモデルとかを先に知ったところでどうすればいいのか分からないので、
動画中にある文字の認識からやっていきたい
ゲーム画面にはいくつもの文字情報がある
とくに残り時間を表す数字とか、目標の達成度合いを表す数字とか、
文字情報じゃなくても、特定の位置に特定のアイコンが表示されることで、どういった状態かも分かるはず
これらは前後の状態にかかわらず、今時点の情報なので、画像認識で解決できるだろうという予想
OCR
文字認識の代表的なモデルがOCRらしい。
ニューラルネットワークとか関係なく、わりと古くからある手法な感じはする
ただ古いOCRの識字率はあまりよろしくなく、ニューラルネットワークがブレイクスルーさせちゃった技術のひとつなんかな
画像から文字を抽出する方法は調べればいくらでも出てきそう
動画から画像の抽出
ゲームプレイ動画は何らかの方法で保存されている前提で進める
手元にあるのはmkv形式のファイルやから、そこから画像データを取り出すことを考える
ただこのとき、1フレームずつ全部画像データとして取り出すのは数が多すぎる上に、
処理するときに時間を無駄にしそうやから、ある程度間隔をあけて画像化することが出来たらいいなーって感じ
実際に手を動かしたときの履歴はこっちに出した
画像からテキストデータの抽出
学習済みのモデルを使えば、テキストデータの抽出自体はそんなに難しくないんじゃないかなーとは思ってる
もしフォントとか演出の影響で抽出が上手くできない場合は、学習データを作って流し込むことも検討したい
このあたりができそうなものをGoとPythonで探す
もしOpenCVにそのあたりの機能が存在するなら、それを利用する
ってことで、画像データからテキストデータを抽出する方法について調べていく
モデルとしてはOCRってのは知ってるけど、それをどうやって利用するかを学ぶ感じ
追加の知識として、画像からテキストを取り出す際に、
テキストの位置を取り出すこともできる
このテキストの位置をバウンディボックスというらしい
画像から文字が存在しそうな範囲を特定し、そこからテキストデータを取り出すって感じなのかも
また、特定のゲームの画面から読み取る場合、独自のフォントや独自の演出があったりすることから、
ある程度追加学習可能なツールを使う必要がある
この追加学習のことをファインチューニングというらしい
これらを踏まえて、一番出てくるのが Tesseract ってツール
次いで EasyOCR と EAST が出てくる
TesseractはGoのラッパーもあり、いろんな言語から利用することが容易そう
残りの2つはPythonからの利用は容易なものの、それ以外の言語からは一癖も二癖もある感じ
場合によっては利用が難しいかも
ってことで、TesseractをGoとPythonから使って、ゲームの特定の画面から文字を抽出してみる
Tesseractをインストール
下記記事に切り出した
ここまでのコマンドで何枚かゲームの画面を読み込んだけど、全然文字認識はできなかった
ここからできることは大きく二つ
画像を加工して認識しやすくする
追加学習させて精度をあげる
ってことで、これらについて調べていく
画像の加工と変換
動画から画像を抜き出したままだと文字認識精度が低い
ってことで、いくつか画像の変換をしてみる
PythonでもGoでも叩くのはほとんど同じだとは思うけど、
両方でどんなコードかは書いていってみる
グレースケール変換
コントラストを強調することで、文字の境界を分かりやすくする目的で、
グレースケールに変換する
code:mvk_gray.py
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
code:mvk_gray.go
grayImg := gocv.NewMat()
gocv.CvtColor(img, &grayImg, gocv.ColorBGRToGray)
二値化
グレースケールだけだとまだカラフルなんだそうなので、
黒白にしちゃいましょーってやつ
code:mvk_binary.py
_, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)
code:mvk_binary.go
binaryImg := gocv.NewMat()
gocv.Threshold(grayImg, &binaryImg, 0, 255, gocv.ThresholdBinary|gocv.ThresholdOtsu)
ノイズ除去
ガウスぼかし、モルフォージ処理がいいらしい
ってことでとりあえずガウスぼかし
code:mvk_blur.py
blur = cv.GaussianBlur(binary, (5, 5), 0)
code:mvk_blur.go
blurImg := gocv.NewMat()
gocv.GaussianBlur(binaryImg, &blurImg, image.Point{X: 5, Y: 5}, 0, 0, gocv.BorderDefault)
ってことで、before after
https://scrapbox.io/files/67a2f3be39f8065bc5b64480.jpg
https://scrapbox.io/files/67a2f3cb437457f4f0eb25d5.jpg
多少精度はあがったけど、それ用の単語が含まれていなかったりもあって、
まだまだ精度は低そう
blur > binary >>>>>> gray > original
ってな感じでした
とはいえ、精度が足りないので、追加学習も試してみる
Tesseractの追加学習
Tesseractの追加学習について調べて実践してみる
ちょっと調べた感じ、簡単にぴゃーっとできるもんではなさそう
順番に必要な作業を学んでいかないといけないなー
フォントがある場合はフォントを使えばいいみたいなんやけど、
ゲームのフォントは公開されていないことが多いので、
実際のゲームの画面から取り出すことを考える
また、決まった位置に決まった文字が出るとは限らないと思うから、
ゲーム画面から特定の位置だけを抽出するってこともしない
以上を踏まえたうえで、必要なのが下記
画像(TIFF形式、 *.tif)
テキスト情報 *.txt
ボックス情報 *.box
これを作っていく
ただ、全部手動だと大変なので、いったんtesseractで画像から各情報を取り出して、
それを正しい値に書き換えていきたいなーと思う
でもそれをテキストの修正だけだと大変なので、うまくGUIでできないかなーと思ってる
ChatGPTなんかでそれ用のツールがないか聞いたけど、それ用のはないって言われた!
っていうのも、pythonを使えば比較的容易にできるからっぽい?
なんかこんなのがほしいなーの漠然としたイメージは、
ウィンドウの左側に読み込んでる動画の指定されたフレームの画像が出て、
画像の下側にはフレームを進めたり戻したりするUIがあって、
画像にはその時点のTesseractで出したボックスが描画されてて、
右側にボックスの位置とテキストが出て、
右側のボックスを選択してテキストを修正したりできて、
あとはボックスを追加したり削除したりできてーみたいなのを想像してる
ってことで、これらをgoとpythonでやってみる
Python
しらべたらtkinterが良く引っかかるので、これを使うことにする
AIに色々ききながら
動画から指定したフレームのオリジナルの画像と、読み取りやすいように二値化した画像と、
それに対してOCRした結果を出すGUIを作った
https://scrapbox.io/files/67a768f5adfdda9bbe30bde5.png
ここまではデータを取得して表示するだけなので、
tkinterの大雑把な使い方を理解すれば実現できた
ここからが大変そうで、OCRのボックスを画像に重ねて表示し、
ボックスとテキストを修正し、学習用ファイルに吐き出す必要がある
修正する機能とかも追加したもの
https://scrapbox.io/files/67ab51abab391926ba1e45c7.png
色々試したけど、その途中を丁寧に書くのがめんどくさかったのでGUIができましたよってことで
これを使って修正後のバウンディングボックス情報を学習データとして出力するか、
もしくは学習させる機能の追加を進める
いくつか学習用のファイルを作ったけど、何度も全部にボックスを付けるのが結構大変
一度出力したboxファイルを読み込みなおしたい
ってことで、boxファイルをドラッグアンドドロップしたら、その中身をボックステーブルに並べる機能を追加する
と思って調べたら、tkinter自体にはドラッグアンドドロップされたときの挙動はないっぽい
ただ、それを可能にしたtkinterdnd2っていうラッパー的なのがあるみたいなので、これを試してみる
あとはボックスの量が大量になることがあるから、それをスクロールできるようにもしないと
この辺の便利機能は学習データを作りながらやっていくとして、
いくつか学習データができたので、実際に学習させる方法を確認していく
windowsに必要なインストールはここに書いてそう
tesseractをinstallして、pathを通す
これはここまでで終わってるはず
python 3のインストール
これも終わってるはず
git bashのインストール
Git SCM to Windowsって書かれてる
wingetのinstall
$ winget --version
v1.9.25200
既に入ってた
$ winget install ezwinports.make
ターミナルの再起動が必要
$ make --version
GNU Make 4.4.1
Built for Windows32
Copyright (C) 1988-2023 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ winget install wget
ターミナルの再起動が必要
$ wget --version
GNU Wget 1.21.4 built on mingw32.
環境のセットアップは以上
次にtesstrainを取得する
といっても、これはインストーラーだったりがあるわけじゃなくて、
githubのrepositoryをcloneしてくるか、zipでダウンロードして任意のディレクトリに展開するだけ
分かりやすい場所に展開できればいいので、tesseractディレクトリ配下に、tesstrainディレクトリを作って設置した
展開したtesstrainディレクトリで make help したらコマンドの詳細が出る
$ make help
You are using make version: 4.4.1
Targets
unicharset Create unicharset
charfreq Show character histogram
lists Create lists of lstmf filenames for training and eval
training Start training (i.e. create .checkpoint files)
traineddata Create best and fast .traineddata files from each .checkpoint file
proto-model Build the proto model
tesseract-langdata Download stock unicharsets
evaluation Evaluate .checkpoint models on eval dataset via lstmeval
plot Generate train/eval error rate charts from training log
clean-box Clean generated .box files
clean-lstmf Clean generated .lstmf files
clean-output Clean generated output files
clean Clean all generated files
Variables
TESSDATA Path to the directory containing START_MODEL.traineddata
(for example tesseract-ocr/tessdata_best). Default: C:/tesseract/tesstrain/usr/share/tessdata
MODEL_NAME Name of the model to be built. Default: foo
DATA_DIR Data directory for output files, proto model, start model, etc. Default: data
LANGDATA_DIR Data directory for langdata (downloaded from Tesseract langdata repo). Default: data/langdata
OUTPUT_DIR Output directory for generated files. Default: data/foo
GROUND_TRUTH_DIR Ground truth directory. Default: data/foo-ground-truth
WORDLIST_FILE Optional Wordlist file for Dictionary dawg. Default: data/foo/foo.wordlist
NUMBERS_FILE Optional Numbers file for number patterns dawg. Default: data/foo/foo.numbers
PUNC_FILE Optional Punc file for Punctuation dawg. Default: data/foo/foo.punc
START_MODEL Name of the model to continue from (i.e. fine-tune). Default:
PROTO_MODEL Name of the prototype model. Default: data/foo/foo.traineddata
TESSDATA_REPO Tesseract model repo to use (_fast or _best). Default: _best
MAX_ITERATIONS Max iterations. Default: 10000
EPOCHS Set max iterations based on the number of lines for the training. Default: none
DEBUG_INTERVAL Debug Interval. Default: 0
LEARNING_RATE Learning rate. Default: 0.002
LANG_TYPE Language Type - Indic, RTL or blank. Default: ''
PSM Page segmentation mode. Default: 13
RANDOM_SEED Random seed for shuffling of the training data. Default: 0
RATIO_TRAIN Ratio of train / eval training data. Default: 0.90
TARGET_ERROR_RATE Default Target Error Rate. Default: 0.01
LOG_FILE File to copy training output to and read plot figures from. Default: data/foo/training.log
ドキュメントを読んでいると、どうも.boxファイルよりも、.gt.txtと画像ファイルが必要な感じがある
.boxファイルが作れるので、画像のどの位置にどのテキストなのかは把握できているため、
.gt.txtとその画像をついでに吐き出すようにする
更に読み進めてみると、.boxから.gt.txtを作ること自体が目的だったので、
であれば最初から.boxファイルを作るのではなく、.gt.txtファイルと画像を作ったほうがいいっぽい
ってことで、何時間かかけて、ゲーム画面から文字部分を抜き出して学習データを作った
合計12000ファイルを超えているから、6000パターンはありそう
これを使って、学習させてみる
オプションから必要になる設定を確認しておく
MODEL_NAME モデルの名前、つけないと分からなくなる
START_MODEL fine tuneするときに元にするモデル、だいたいは日本語なのでjpnをもとにすることになりそう
DATA_DIR 各種データを格納するディレクトリ、デフォルトは data なので、作業ディレクトリに data を作っておけばいいはず
OUTPUT_DIR 出力用ディレクトリ、学習後のデータとかもここに出るはず、デフォルトは DATA_DIR/MODEL_NAME
GROUND_TRUTH_DIR 学習用データディレクトリ、デフォルトは OUTPUT_DIR-ground-truth
TESSDATA traineddataの位置、デフォルトで ./usr/share/tessdata になっているから、これを変えないとtraindataを見に行けない
ってことなので、
$ make training MODEL_NAME=jpn-splatoon3 START_MODEL=jpn TESSDATA="../tessdata_best" DATA_DIR="./data" GROUND_TRUTH_DIR="./data/gt" LANG_TYPE=jpn FINETUNE_TYPE=Impact MAX_ITERATIONS=1
MAX_ITERATIONS=1 はテスト的に実行するためにつけてる
これをしておかないと、がっつり学習のためのループがまわって、かなりの時間がかかっちゃって、
本当に正しく動くのかの確認ができるのが遅れてしまう
エラーになった
tesstrainの使い方とか、取得の仕方を間違ってるのかも
最新版がいいのか、リリース版がいいのか、
そもそもtesseractとのバージョンがあってるのかなどなども確認が必要そう
tesstrainのreleaseタグがついてるのも、
tesstrainのmainブランチのも上手く動かない…
windowsでのtesseractのinstallerにはトレーニングツールも含まれているっぽい
tesstrainとかとってこなくても、必要なコマンドが分かれば何も入れずにできるんじゃないか?
調べてると、単語リストを作るってのが出てきた
確かに、特定のゲームに特化させるなら、それもやらないとやなー
色々調べたけど、学習はうまくいかなかった!
ってことで出来ることとしては、
動画のどの部分を切り取るかを最初に決める
その部分を文字の読み取りやすいように画像変換する
単語が珍しい場合は単語リストを使う
って感じなんかな
特殊フォントの時にどうするのかは今回は解決できなかった
他にやりたいことがなくなったときに改めて挑戦するつもりで!
更新履歴
2022/08/30 かきはじめ
2025/01/23 再開 (2年以上寝かせてたのか…