カタカタログ

いろんなことを書いていきます

ホロライブのファンアートからホロライブっぽい画像を生成する

概要

  • Twitterに上がっているホロライブのファンアートを元にホロライブっぽい画像を生成したよ
  • あるホロライブメンバーっぽさを付与した画像も生成できるよ

分かる人向け概要

  • StyleGAN2でホロライブっぽい画像を生成するモデルを作って遊んでみたよ

成果物

生成したホロライブっぽい画像

f:id:yaagrng:20210214130719p:plain

白金ノエルさんから不知火フレアさんに変化させた画像

f:id:yaagrng:20210214131058p:plain



はじめに

ホロライブとは、カバー株式会社が運営するVTuber事務所ホロライブプロダクションのうちの女性VTuberグループです。 ホロライブには多数のメンバーが所属しており、YouTubeをメインにライブ配信等を行なっています。 最近は様々な企業とコラボをしており、活躍の場を広げています。

www.lawson.co.jp

ホロライブのメンバーは各々Twitterアカウントを持っており、メンバーに関係するハッシュタグが設定されています。 下記の表は、一部のメンバーの用途ごとのハッシュタグです。

メンバー 実況 創作
ときのそら #ときのそら生放送 #soraArt
ロボ子さん #ロボ子生放送 #ロボ子Art
さくらみこ #みこなま #miko_Art
星街すいせい #ほしまちすたじお #ほしまちぎゃらりー

など

創作タグは、そのメンバーに関係する作品が投稿されるときに付けられるタグです。 多くの場合イラストが投稿されており、メンバーの様々な魅力を見ることができます。

創作タグからイラストを持ってくることができ、イラストが十分な量あるならば、でぃーぷらーにんぐ*1で新しいイラストを生成できるのでは?

そうしてホロライブのファンアートからホロライブっぽい画像を生成する試みが始まりました。

使用技術

  • GAN

GANは生成モデルの一種でありGenerative Adversarial Network(敵対的生成ネットワーク)の略です。

GANは、生成ネットワークと識別ネットワークから成ります。

生成ネットワークの目標は、本物と遜色ない偽物を作り出すことです。 一方、識別ネットワークの目標は、提示された物が生成ネットワークが作り出したものか否かを判別することです。

生成ネットワークは識別ネットワークを騙そうと学習し、識別ネットワークは生成ネットワークに騙されないように学習していきます。

初めは両者とも未熟のため、生成ネットワークの生成能力と識別ネットワークの識別能力は大したことはないのですが、お互いに学習を重ねることで、生成ネットワークはより精巧な偽物を生成できるようになり、識別ネットワークはより正確な判別ができるようになっていきます。

以上がGANの概略ですが、より詳しい説明が必要な場合はネットの海をあたってください。

使用データ

ホロライブっぽい子のイラストを生成したいため、Twitterに上げられているホロライブのファンアートを"本物"のデータとして使用しました。

今回はホロライブJPのメンバーのみを対象とし、3972枚の顔画像データを"本物"データとして学習に使用しました。

結果

ホロライブっぽい画像生成

ランダムに生成したホロライブっぽい画像が以下になります。

f:id:yaagrng:20210214130719p:plain

ホロライブを知らない人でも、可愛らしいイラストが生成されているのがみて取れるかと思います。 また、ホロライブを知っている人は、「あーこれはあの子かー」ということが分かると思います。

ホロライブメンバーの混ぜ合わせ

ホロライブメンバー2人間の遷移

前節ではランダムに画像を生成しましたが、ホロライブメンバーAの画像とホロライブメンバーBの画像を生成するベクトルを特定し、それらのベクトル間を適当に繋ぐことでホロライブメンバーAの画像からホロライブメンバーBの画像へ遷移することができます。

下の画像はホロライブプロダクションの所属タレントページから取得した百鬼あやめさんの顔画像(左)と、学習したモデルからその画像を生成した画像(右)です。

f:id:yaagrng:20210214125843p:plain:w256f:id:yaagrng:20210214125847p:plain

"本物"データにタレントページの画像は使用していないため、完全に再現はできませんが、それなりに近い画像が生成できています。

上記のように、生成したい画像を生成するベクトルを見つけ、2つのベクトル間をいい感じに繋ぐことで、2つの画像をそれなりに自然に繋ぐことができます。 そのようにして、あるメンバーからあるメンバーへの遷移させた結果が以下です。

白金ノエルさん - 不知火フレアさん

f:id:yaagrng:20210214131058p:plain

猫又おかゆさん - 戌神ころねさん

f:id:yaagrng:20210214131105p:plain

兎田ぺこらさん - さくらみこさん

f:id:yaagrng:20210214131118p:plain

湊あくあさん - 紫咲シオンさん

f:id:yaagrng:20210214131112p:plain

ホロライブメンバーっぽさの付与

今回使用したGAN*2では画像に別の画像の"ぽさ"を付与することができます。

下の画像は、ランダムな画像に潤羽るしあさんっぽさを付与した画像です。

f:id:yaagrng:20210214131822p:plain

髪色やテイストが画像ごとに異なりますが、全体として潤羽るしあさんっぽさが残っています。

次の画像は、ホロライブJPメンバーに別のホロライブJPメンバーの"ぽさ"を付与したものです。

f:id:yaagrng:20210214134548p:plain

行方向は顔の形や髪型などの全体的な特徴を"ぽさ"として反映し、列方向は髪の色や目の色などの部分的な特徴を"ぽさ"として反映しています。

例えば、3行目の黒髪の子(大神ミオさん)を行方向に見ると、全体としては大神ミオさんっぽさを残しつつ、列方向のメンバーの"ぽさ"が反映されているのが分かるかと思います。

さいごに

今回はホロライブのファンアートからホロライブっぽい画像を生成するモデルを作成し、ランダムに画像を生成したり、特徴を混ぜ合わせたりして遊んでみました。

モデルの作成にあたり、Twitterに上がっているホロライブのファンアートを使用させていただきました。ファンアートを上げてくださっている皆さま、誠にありがとうございます。

番外: ホロライブENメンバーの生成

"本物"データとして使用していないホロライブENメンバーを生成した結果が以下になります。

f:id:yaagrng:20210214140448p:plainf:id:yaagrng:20210214140515p:plainf:id:yaagrng:20210214140508p:plainf:id:yaagrng:20210214140500p:plainf:id:yaagrng:20210214140453p:plain

分からなくはないですが、いまいちですね。

*1:私は雰囲気でディープラーニングをやっている

*2:StyleGAN2を用いています

beatmania IIDX 進捗報告 2020年11月

はじめに

この記事は2020年10月にbeatmania IIDXを再開した私の月一回の進捗報告記事です。

進捗のほかに感想も書いていきます。

はじめます宣言の記事はこちら

yaagrng.hatenablog.com

最新の進捗の記事はこちら

yaagrng.hatenablog.com

進捗

BMS

項目 前月記録 今月記録
旧発狂段位 発狂八段 発狂八段
現行発狂段位 発狂八段 発狂八段
リコメンド ★20.88 ★21.44
リアランプ状況 記録
前月記録 f:id:yaagrng:20201102102104p:plain:w500
今月記録 f:id:yaagrng:20201130193710p:plain:w500

beatmania IIDX

項目 前月記録 今月記録
☆12 AAA率 7.3% 12.7%
☆12 AAA曲数 27曲 47曲

やったこと

発狂難易度表のハード埋め 以上

感想

リコメンドは前月からあまり差分がありませんが、 これは復帰によるボーナスタイムが終わりに近づいているのに加え、 11月の前半はリアルが忙しくてあまりビートできていなかったためです。 上達するには、ビートの質を上げることはもちろんのこと、時間を確保することが大事ですね。

11月は★20以上をあまり触れていなく鍵盤力が付いたとは言えない1か月となったので 12月は積極的に★20以上を触っていこうと思います。

現時点で、所持している★16が全ハード(★16以下の難しめの曲をハードできているので恐らく★16まで全ハード)、 ★17・★18はハードでいい勝負ができて、★19から実力不足で押せないといった感じです。

ちなみに発狂九段に受からないのはひつぎの所為です。

ACの方ですが、BMSで上げた地力をACにうまく転換できていません。 BMSのEASY判定に慣れすぎてACのピカグレ幅に入れられていないのが原因なような気がしています。 ACやる時間を増やして判定に慣らしていく作業が別途必要になりますね。

beatmania IIDXの譜面からのスコア分布推定

目次

TL; DR

譜面からスコア分布をそこそこの精度で推定することが可能になりました。 これにより、譜面が分かれば以下のようなことが推定できるようになりました。

  • その譜面の平均スコア
  • その譜面の全一スコア
  • その譜面でAAAを出したときの譜面内順位 など

RootageのSP皆伝がHEROIC VERSEのSP☆12をプレイした場合の譜面ごとのスコア分布の推定と、HEROIC VERSE SP皆伝の☆12の実際のスコア分布の比較結果が以下です。

drive.google.com

また、HEROIC VERSEのSP皆伝が2020年11月13日時点でBISTROVERで初収録されたSP☆12をプレイした場合のスコア分布の推定結果が以下です。

f:id:yaagrng:20201116110758j:plain:w325 f:id:yaagrng:20201116110803j:plain:w325

推定のために使用したコードは以下です。

beatmania IIDXの譜面からスコア分布を学習 · GitHub

推定手法の概要

プレイヤーのスコア分布は次の3ステップで推定します。

  1. スコア分布が既知の譜面のスコア分布をGMM(Gaussian Mixture Model)で推定する
  2. (入力, 出力) = (譜面, GMMのパラメータ)とするニューラルネットワークを作成し、既知の譜面とそのGMMのパラメータを学習データとしてニューラルネットワークを学習させる
  3. スコア分布が未知の譜面をニューラルネットワークに入力し、GMMのパラメータを得て、未知の譜面のスコア分布をGMMで表現する

各ステップについて詳しく説明します。

スコア分布が既知の譜面のスコア分布をGMMで推定する

beatmania IIDX公式をクロールするなどによって、ある譜面のプレイヤーのスコアを入手することができます。 そのようにして入手した譜面ごとのプレイヤーのスコア分布をGMMで推定します。

GMMは以下の数式で表現されます。


f(x)=\sum_i \pi_i N(x ; \mu_i, \sigma_i^ 2)

例えば、AA(ANOTHER)をプレイしたRootage SP皆伝のスコア分布をクラスタ数5のGMMで推定した結果が以下になります。

f:id:yaagrng:20201113134939j:plain

実際の分布とGMMで推定した分布がほとんど重なっていることが分かります。

このときのGMMのパラメータが以下になります。

パラメータ クラスタ1 クラスタ2 クラスタ3 クラスタ4 クラスタ5
 \pi_i 0.009858056 0.2790408 0.3222654 0.1348045 0.2540312
 \mu_i 0.5092048 0.820139 0.8618256 0.8988133 0.9384592
 \sigma_i^ 2 0.05378421 0.003740659 0.00112172 9.947421e-05 0.0004654172

(入力, 出力) = (譜面, GMMのパラメータ)とするニューラルネットワークを作成する

未知の譜面に対してGMMのパラメータを推定するために、(入力, 出力) = (譜面, GMMのパラメータ)とするニューラルネットワークを作成します。

譜面の符号化

ニューラルネットワークに譜面を入力するにあたり、譜面を数値で表現する必要があります。 本手法では、譜面を4分の4拍子換算で1小節を96個に分割し、それぞれのタイミングで降ってくるノートとBPMを要素にもつ系列データとして符号化しました。鍵盤の符号化は以下の通りです。

ノートあり ノートなし CN, HCN, BSS
1 0 0.5

例として、Almagestの61小節目(TexTage様より引用)の先頭16分は次のように符号化されます。

f:id:yaagrng:20201113123715j:plain

各行が96分間隔の系列を表します。 各行の要素は、1から7要素目までが1鍵盤から7鍵盤にあたり、8要素目がスクラッチ、9要素目がBPMです。

ニューラルネットワークの作成

スコア分布が既知の譜面に関して、符号化された譜面とGMMのパラメータの組が揃ったので、これを学習データとしてニューラルネットワークを学習させます。

ニューラルネットワークには、系列データを扱うLSTMを使用しました。

スコア分布が未知の譜面のスコア分布を求める

学習済みのニューラルネットワークに、スコア分布が未知の譜面を入力し、GMMのパラメータを得ます。 得たGMMのパラメータを使ってスコア分布をGMMで表現します。

実験

Rootage収録のSP☆12の譜面、およびRootage SP皆伝のスコアデータから、HEROIC VERSE初収録のSP☆12のSP皆伝のスコア分布を推定する実験を行いました。

推定のために使用したRootageのスコアデータは、Rootage稼働終了時点のデータを、実際の分布を確認するために使用したHEROIC VERSEのスコアデータは、HEROIC VERSE稼働終了時点のデータを使用しています。

推定結果と実際の分布を比較した結果は以下です。

drive.google.com

全一、皆伝平均、AAA順位割合、MAX-順位割合の推定値と実際の値との絶対誤差の平均は以下です。

項目 絶対誤差の平均
全一 0.57ポイント
皆伝平均 0.91ポイント
AAA順位割合 3.07ポイント
MAX-順位割合 0.87ポイント

今回の実験では、全一は真の全一から平均して0.57ポイント(スコアレートで0.57%)の誤差で推定されました。 AAA順位割合は真のAAA順位割合から平均して3.07ポイントの誤差で推定されました。 他も同様となります。

正直、誤差の測定方法がこれでよいのか分かりませんがとりあえずで算出しています。

BISTROVER☆12のスコア分布推定

HEROIC VERSE SP皆伝の☆12スコアデータから、2020年11月13日時点でBISTROVERで初めて収録された☆12のSP皆伝のスコア分布を推定した結果が以下です。

f:id:yaagrng:20201116110758j:plain f:id:yaagrng:20201116110803j:plain

誤差含めて点数に直すと以下だそうです。

譜面 全一 皆伝平均
Arabian Rave Night(L) 3753点~3776点 3211点~3280点
お米(L) 3789点~3814点 2935点~3004点

さいごに

ある程度の精度で譜面からスコア分布を推定することができたので、次はWebサービス化しようと考えています。それなりに時間がかかると想定されるので、サービス公開までは下記のアカウントから推定結果を発信します。

twitter.com

実は精度改善のために前回の記事のときのコードからいくつかアップデートをしているのですが、内容を書くと煩雑になりそうなので詳細はこっちのアカウントで呟くかもしれません。

最後に、本記事を書くにあたってスコアデータを提供してくださった方々、また、譜面データを提供してくださっているTexTage様、ありがとうございました。

beatmania IIDXの新しいスコア指標の提案 #3

目次

はじめに

本記事は下記記事の差分です。

yaagrng.hatenablog.com

提案手法の着想および内容は下の記事に書かれているので、未読の方はこちらから読まれることをおすすめします。

yaagrng.hatenablog.com

今回でようやくそれらしい結果が出たので、私が所持している最新データSINOBUZでの実験はここまでになります。

以降では前回からの差分と、結果を示します。

前回からの差分

  1. 損失関数の変更
  2. プログラムのバグ修正
  3. 出力値の変更
  4. ネットワーク構成の変更

損失関数の変更

前回、損失関数にKL-ダイバージェンスを使うように変更しましたが、計算の過程で誤差が計算できなくなり、学習を進めることができなくなったため、MAE(Mean Absolute Error: 平均絶対誤差)に変更しました。

このネットワークで求めたい値は0から1の範囲であり、MSE(Mean Square Error: 平均二乗誤差)を使うと誤差が過剰に小さくなってしまうためMAEを使用しました。

プログラムのバグ修正

これまでのグラフがステップ関数っぽくなってた大体の原因

前回まで、標準偏差を学習させてたと思っていましたが、実は分散を学習していました。

分散(分散の値は1以下)を標準偏差だと思って、推定分布を作成していたため、標準偏差が本来より小さい値で分布を作成することになってしまい、ステップ関数に近づいていました。

グラフ作成の際のバグを修正しました。

出力値の変更

このネットワークの出力は、混合ガウス分布に混ざっている各ガウス分布の重み・平均値・分散です。このうち、分散は小さいもので10のマイナス4乗のオーダーとなっていました。この値は小さすぎて、この値を出力するように学習させるのは困難でした。

そのため、分散を100倍にした値を出力するように変更しました。

この変更は学習にかなり効きました。

ネットワーク構成の変更

上記の修正・変更の後は、損失を少なくするハイパーパラメーターを探す旅に出ました(辛い)。

いろいろ試した結果、以下の構成が暫定で最良でした。

f:id:yaagrng:20201106001140p:plain

重み・平均値・分散を並列に学習させ、最後に結合して出力しています。

実際のコードは以下を参照してください。

github.com

実験結果

対象: SINOBUZ時点の☆12 255譜面

訓練データ: 225譜面

バリデーションデータ: 25譜面

テストデータ: 5譜面(AA, Confiserie, DIAMOND CROSSING, Snake Stick, ICARUS)

各譜面の推定結果と実際の分布のグラフ:

f:id:yaagrng:20201106000808j:plain:w300 f:id:yaagrng:20201106000811j:plain:w300 f:id:yaagrng:20201106000813j:plain:w300f:id:yaagrng:20201106000820j:plain:w300f:id:yaagrng:20201106000816j:plain:w300

完全に一致とまではいきませんが、譜面から推定したにしてはそこそこの結果になったのではないでしょうか。 新曲が登場した時に、この譜面はこんなスコア分布になりそう、という速報としてはそれなりに使えそうです。

ちなみに、推定結果同士の分布の比較は以下になります。

f:id:yaagrng:20201106084407j:plain

ちゃんと譜面ごとに違う分布が作成されていますね。

次にスコア指標値を見ていきます。推定した各譜面の歴代・AAA・皆伝平均でのスコア指標値は以下になります(歴代と皆伝平均のスコアは2020年11月4日時点のBPI ManagerでのBPI 100と0のスコア*1を使用しています)。

曲名 歴代 AAA 皆伝平均 指標値(歴代) 指標値(AAA) 指標値(皆伝平均)
AA 3650 3261 3164 99.75 67.02 52.64
Confiserie 3609 3259 2842 99.90 89.21 41.41
DIAMOND CROSSING 3146 2818 2459 99.98 82.21 30.58
Snake Stick 2838 2573 2183 99.99 96.35 47.88
ICARUS 2556 2313 1982 99.98 92.02 37.83

ここで指標値の解釈のおさらいです。

スコア指標値の解釈は、ある譜面のスコア指標値がx点なら、その譜面で上位(100-x)%相当のスコアを保持している、という解釈になります。

SINOBUZ時代にSnake StickをAAA出すと当時の皆伝たちの上位4%になるの本当か??と思いましたが、実際のデータで確認したところAAAは当時の皆伝たちの上位2%くらいでした。意外に合ってるのかもしれません。

指標値を出したところで、この指標値の活用方法を考えてみましょう。例えばConfiserieでAAAが出た人は、Confiserieで上位約11%相当のスコアを保持しているので、他の似たような譜面でも上位11%相当のスコアが出せそうです。この人がスコアを伸ばすとするなら、同系統の譜面で指標値が89.21に満たない譜面をプレイすると、スコアの伸びが期待できます。

さいごに

前々からの念願だった、譜面からのスコア分布作成が叶いました。 よりあてはまりの良い構成を探すこともできますが一旦の区切りです。調査の中でネットワークを自動で構築するAutoMLが引っかかったので可能ならそのうち試してみたいです。

今回でSINOBUZのデータでの分析は終了になりますが、今後やりたいことは以下の通りです。

  1. IIDX 26, 27のデータを手に入れる
  2. ネットワーク version Rootageを作成し、IIDX 27で追加された譜面のスコア分布をどれだけ推定できるか実験する
  3. ネットワーク version HEROIC VERSEを作成し、IIDX 28で追加された譜面のスコア分布を推定して、分布の公開およびスコア指標値の算出をできるようにする

1が一番しんどいですね。API公開はよ。 2は最悪やらないでもいいですが、精度を確認するためにもやっておきたいタスクです。 3はWebサービスを作る必要がありそうです。時間がかかりそうなので、サービスが完成するまでは分布を推定したらtwitterなどで取り急ぎ分布を投稿という形になりそうです。

さいごになりますが、第一の記事を公開してから、リツイートやいいね等でレスポンスをしてくださった方々、大変モチベになりました。また、手法にアドバイスや別の視点をくださった方々、貴重な知見をくださり本当にありがとうございました。

*1:BPI Managerで実際に使われているデータは知りませんが、BPIの定義ではBPI 100が歴代、0が皆伝平均です

beatmania IIDXの新しいスコア指標の提案 #2

目次

はじめに

本記事は以下の記事からの差分です。

yaagrng.hatenablog.com

まだ実用に耐えず、改良が必要です。

前回からの差分

前回からの差分は以下です。 以降の章で差分内容を解説します。

  1. ネットワーク構成の見直し
  2. 損失関数の見直し
  3. 譜面エンコードの見直し
  4. ネットワークへの入力の見直し

モデルそのものの見直しが多いです。 モデルのコードは以下を参照してください。

github.com

ネットワーク構成の見直し

以下のようにネットワーク構成を見直しました。

前回のネットワーク構成

f:id:yaagrng:20201103112005p:plain

今回のネットワーク構成:

f:id:yaagrng:20201103162000p:plain

前回のネットワーク構成は、混合ガウスモデルの重み係数の累計が1にならない構成でしたが、今回はactivation_2でSoftmax関数を入れて重み係数の累計が1になるように変更しました。ちなみに、activation_3は値を0から1に納めるためにsigmoid関数です。

また、入力の次元数が変更されていますが、これは譜面エンコードの見直しとネットワークへの入力の見直しで次元数が変わったためです。

あとなんとなくLSTMを3層から6層に変えています。

損失関数の見直し

前回の損失関数: MSE

今回の損失関数: KL-ダイバージェンス

前回の損失関数には思考停止でMSEを使っていましたが、今回は確率分布の類似度を測るKL-ダイバージェンスを損失関数にしました。

混合ガウスモデルのKL-ダイバージェンスは以下の記事を参考にしました。下記の記事中のVariational Approximationを実装し、損失関数に設定しました。

repose.hatenadiary.jp

譜面エンコードの見直し

前回の譜面エンコード: 1時刻17次元(1~7鍵盤、SC、1~7CN、BSSBPM)

今回の譜面エンコード: 1時刻9次元(1~7鍵盤+CN、SC+BSSBPM/100)

前回の譜面エンコードでは、鍵盤とCNを分けてエンコードしていましたが、下記の記事を参考に、鍵盤を1、CNを0.5として次元を削減しました。また、BPMを100で割っています。

asari-saminun.hatenablog.com

ネットワークへの入力の見直し

前回のネットワークへの入力: 1時刻あたり17次元

今回のネットワークへの入力: 1時刻あたり9*96次元

譜面エンコードでも参考にした弐寺の譜面レベル推論モデルの記事を参考に、入力を96分単位から4/4拍子換算での1小節分に変更しました。

実験

対象: SINOBUZ時点の☆12 255譜面

訓練データ: 225譜面

バリデーションデータ: 25譜面

テストデータ: 5譜面(AA, Confiserie, DIAMOND CROSSING, Snake Stick, ICARUS)

結果

学習曲線:

f:id:yaagrng:20201103160533p:plain

バリデーションデータで最もlossの少ない46 epoch目でテストデータを予測した結果:

f:id:yaagrng:20201103160709j:plain

全譜面に同じ結果を返していますね。使えません。

ちなみに、訓練データに対してlossが少ない学習状態でテストデータを予測した結果が以下です。

f:id:yaagrng:20201103160844j:plain

譜面ごとに推定結果がばらけます。

グラフをよくみるとステップ関数っぽくなっているのがわかると思います。このまま学習を続けると、どんどんステップ関数に近づいていきます。これはガウス関数の分散が0に近づいていることと同じであり、最終的にKL-ダイバージェンスが計算できなくなり学習を続けることができなくなります。

なぜステップ関数っぽくなるのかを考えて修正する必要がありそうです。

beatmania IIDX 進捗報告 2020年10月

はじめに

この記事は2020年10月にbeatmania IIDXを再開した私の月一回の進捗報告記事です。

進捗のほかに感想も書いていきます。

はじめます宣言の記事はこちら

yaagrng.hatenablog.com

最新の進捗の記事はこちら

yaagrng.hatenablog.com

進捗

BMS

項目 前月記録 今月記録
旧発狂段位 NO DATA 発狂八段
現行発狂段位 NO DATA 発狂八段
リコメンド NO DATA ★20.88
リアランプ状況 記録
前月記録 NO DATA
今月記録 f:id:yaagrng:20201102102104p:plain:w500

beatmania IIDX

項目 前月記録 今月記録
☆12 AAA率 NO DATA 7.3%
☆12 AAA曲数 NO DATA 27曲

やったこと

鍵盤を押す力を付けるためにBMSを主にやっていました。ACでのスコア狙いは週に1回だけでした。 BMSは以下のように進めていました。

  1. ★1から★14あたりまで1曲ずつ新規ハード埋め
  2. ★15付近をハード挑戦
  3. 下位の★でFAILEDになっている曲をハード再挑戦

1はアップです。手が温まってきたら2で強いハードランプを付けにいきます。3は挑戦時に地力が足りなかったものを後から掃除しにいくターンです。 BMSの難易度表は曲数が多いので、1曲を粘着するよりも、ダメだったらほかの曲を触って地力を上げてから再び殴りに行くほうが効率が良いと思っています。

BMSでも光らせる練習として、スコアが狙える難易度帯(★1から★8あたり)ではスコアを狙っています。

感想

今月は鍵盤を叩けば叩くほど成果が出る時期だったのでとにかく楽しかったです。

今月の実力向上論に関しては、beatmaniaから離れてた人はとりあえず鍵盤黙って叩いてくださいとだけですかね。すぐにボーナスタイムは終了すると思うので、そこからどうやって実力を向上させるかを真面目に考えていくことになるかと思います。

再開した当初は★10でヒイヒイ言っていましたが、10日ほど経つと★14ハードが適正、★18の図書室のエルザがなんとかハードできるくらいまで持ってくることができました。旧段位も始めこそ六段のメイドさんで落ちていましたが、1週間後にはメイドさんハードできていたのでとにかく鍵盤叩きましょう。

本家のAAA埋めの方も、BMSで体力付けるまではBeat Radiance†ですら一度AAAを逃すくらいでしたが、ある程度体力が付いてからは、AAを始めとする所謂普通の☆12の乱打譜面ならAAAを出せるようになってきました。

このゲームは成長が伸び悩んでからが勝負なので、とっとと伸びるところまで伸ばして苦しいゾーンに突入していきたいですね。新規AAAが出るのはいつになるでしょうか。

成長記録ですが、BMSは発狂段位、リコメンド、クリアランプ状況を、beatmania IIDXはAAA率とAAA曲数を毎月末時点で記録していこうと思います。クリア(BMS)とスコア(beatmania IIDX)とがどのような塩梅で上がっていくのかを記録できていればいいですね。

そういえば発狂BMS、段位のコース変わっていたんですね。途中まで知らなくて旧段位をやっていました。Stair wayには旧段位で段位が反映されていますが、LR2のマイページは旧段位では反映されないんですね。せっかくなので段位は旧段位とGENOSIDE 2018段位の両方をやっていこうと思っています。ということは発狂皆伝でラブジャスを2回抜ける必要があるのか...

復帰してから知ったことつながりで、stella難易度表というものがあることを新たに知りました。聞くところによると難易度表の★20以上をより細分化した難易度表だとか。以前、BMSをやりこんでいた時は★21以上の曲数が少なく、発狂十段からの練習の幅が狭かったのですが、stella難易度表があれば練習譜面に困らなそうですね。ある程度の曲は導入したので今後利用する機会が来ると思います。

これからもがんばるぞー

beatmania IIDXの新しいスコア指標の提案

目次

はじめに

beatmania IIDXのスコア指標を新たに考えてみたので、その構想と現時点での実験結果を書き記します。

実験結果はあまりよい結果にはならなかったので、「すぐに使える新しいスコア指標完成したって?!」と思った方の期待には応えられません。

研究途中のスコア指標の進捗報告という感じでお読みください。

注意事項

私は統計学および深層学習に関するプロフェッショナルではないため、言葉使いや手法の扱いなどの観点で誤用している可能性があります。その点、ご留意の上でお読みください。

なぜ新しいスコア指標を作ろうと思ったか

一言で言うと、BPIが破壊され始めてきたためです。

有名なスコア指標の一つにBPIがあります。 BPIは皆伝平均を0点、歴代スコアを100点としたスコア指標になります。BPIを求めるために必要な変数が皆伝平均と歴代スコアと指標を測定したいスコアの3つだけなので、比較的容易に計算することができ便利な指標です。

一方でBPIには問題点があります。それは、歴代スコアが更新されると自分の腕前が変わっていないにも関わらずBPIの値が落ちてしまうことです。 BPIのコンセプトを考えると仕様通りの挙動なのかもしれませんが、自分の腕前の変化に関わらずBPIの値が落ちてしまうのは腑に落ちないところがあります。 また、歴代スコアがおかしなことになると、一般人のBPIの値に多大な影響を与えます。最近ではEXUSIAのMAX-10が騒がれました。

上記のBPIの問題点を解消できるような新たなスコア指標を作れないかと思い、取り組んでみました。

新しいスコア指標のコンセプト

新しいスコア指標のコンセプトは『理論値は100点』です。

本記事で提案するスコア指標は、EXスコアレートが100%(理論値)なら100点、0%なら0点で、その間をいい感じに結ぶスコア指標になります。

BPIは歴代スコアとの相対的な指標だったために、歴代スコアが凄まじいスコアに更新されるとBPIが破壊される可能性を残していました。これを回避するために理論値を100点とする指標を作成します。

新しいスコア指標の構想

最も単純なスコア指標は、そのスコアがプレイヤー中の上位何%にあたるかから求めることでしょう。 例えば、全一なら最上位なのでスコア指標は100点で、スコアが0点なら最下位なのでスコア指標は0点になります。 これを元に新しいスコア指標を構築していきます。

ある譜面の全プレイヤーのスコアデータが手元にあるとします。 ここから、横軸をスコアレート、縦軸を累積プレイヤー数としたグラフを作成すると、下のようになります。

f:id:yaagrng:20201029113612j:plain

あるスコアレートで上位何番目かの計算は、総プレイヤー数からそのスコアレートまでの累積人数を引けば求められます(上図の赤矢印線)。 指標的には0から100の範囲で表せると分かりやすいので、割合を求めて100を掛ければ良いでしょう。

一見良さそうですが、問題点が2つあります。

  1. 全一のスコアレートが100%でなくとも、全一のスコアでスコア指標が100点となってしまう
  2. 1つの譜面のスコア指標を計算するために全プレイヤーのその譜面のスコアデータが必要となり、計算コストが高すぎる

これらを解消するために以下を実施します。

まず、1点目の問題ですが、これは、全プレイヤーのスコアデータから各譜面のスコアレートの確率分布を推定することで解消します。

次に、2点目の問題ですが、これは、確率分布のパラメーターを全プレイヤーのスコアデータからではなく、譜面から推定することによって解消します。

雑に絵を描くと下のような感じになります。

f:id:yaagrng:20201029115712j:plain

雑な絵の補足説明です。

  1. 全プレイヤーのスコアデータから譜面ごとのスコアレートの確率分布のパラメーターを推定します
  2. 入力データを譜面、出力データをその譜面の確率分布のパラメーターとなるような関数を学習するために、正解データを手順1で推定したパラメーターとして学習します
  3. 学習した関数を用いて譜面ごとの確率分布のパラメーターを求めます(新しい譜面もこの関数に入力して確率分布のパラメーターを求められます)

以上のようにして、譜面ごとのスコアレートの確率分布を推定します。 後は始めに説明したとおり、推定した累積人数からそのスコアレートが上位何%にあたるかを求め、それをスコア指標値に換算します。

ちゃんと書くと以下のように求めます。 スコアレートxのスコア指標値は、スコアレートの確率密度関数をf(x)、その累積分布関数をF(x)としたとき、(F(x) - F(0))/(F(1) - F(0)) * 100点となります。 F(0)を引いている部分は、確率密度関数の定義域が負の無限大から正の無限大までで定義されているのを補正しています。

スコア指標値の解釈は、ある譜面のスコア指標値がx点なら、その譜面で上位(100-x)%相当のスコアを保持している、という解釈になります。

譜面ごとのスコアレートの確率分布の推定

確率分布の推定には混合ガウスモデルを使用します。 混合ガウスモデルは、複数のガウス分布を様々な重みで足し合わせることで、分布を表現できるモデルです。

以下のサイトが直感的に理解できるかもしれません。

aizine.ai

混合ガウスモデルのパラメータは、混ぜ合わせるガウス分布の数をn個としたとき、ガウス分布の重み付け係数n個、ガウス分布の平均値n個、ガウス分布の分散n個の合計3n個となります。

譜面ごとにこの3n個のパラメーターを推定し、譜面ごとのスコアレートの確率分布を推定します。

パラメーター推定の際には、その譜面をプレイしている全プレイヤーのスコアデータを使用します。

譜面から確率分布のパラメーターの推定

譜面から確率分布のパラメーターを推定するのにはLSTM(Long Short Term Memory)を使用します。 LSTMは時系列データを扱うことのできるニューラルネットワークのひとつです。

以下の動画でなんとなく理解できるかもしれません。

www.youtube.com

譜面データを時系列データとして入力し、確率分布のパラメーターを出力するニューラルネットワークを構築します。 入力は譜面を96分まで識別できる粒度に分割し、各時刻で叩く鍵盤とそのときのBPMを与えます。

例えば、下の画像はAA[ANOTHER]の先頭1小節目です。

f:id:yaagrng:20201029004152p:plain

これの1拍目を時系列データに起こすと以下のようになります。

1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154

各行が1時刻になります。各時刻あたり17要素あり、1要素目から7要素目までが1鍵盤から7鍵盤、8要素目がスクラッチ、9要素目から15要素目までが1鍵盤から7鍵盤のCNまたはHCN、16要素目がBSS、17要素目がBPMに対応しています。

要素について説明したところで内容を少し読み解いていきましょう。 まず1行目ですが、1時刻目、すなわち譜面の先頭で1,3,5,7鍵盤をBPM154で叩いていることが読めると思います。 その6時刻後(7行目)に2鍵盤を叩いています。この時系列データは96分を識別できる粒度で作成しているため、1時刻進むごとに"96分"分譜面が進みます。今回は6時刻分進んでいるので96÷6=16で1時刻目から"16分"分譜面が進んだところで2鍵盤を叩いていると解釈できます。 実際の譜面を見てみると、1,3,5,7鍵盤から2鍵盤へは16分の譜面になっていることが分かります。

このように1譜面分符号化したものをニューラルネットワークへの入力にします。 正解のパラメーターは、事前に混合ガウスモデルで推定したものを与え、学習を行います。

何をやっているのかというと、ニューラルネットワークに譜面を擬似的にプレイさせて、実際のプレイヤーたちが作るスコアの分布を再現させようとしています。

学習の結果、新規の譜面に対しても、確率分布のパラメーターを出力するニューラルネットワークが構築されることになります。

実験

以上が理論で以下は実験です。

私の手元にある最新のデータが、SINOBUZ終了時点での皆伝取得者と忍者ランク100位以上のプレイヤーの☆12のスコアデータのため、これを使います。

譜面ごとのスコアレートのヒストグラムと、推定した分布が以下になります。

drive.google.com

混ぜたガウス分布の数は、いろいろ試した結果5個にしました。例として記事では2譜面だけ取り上げます。

AAの推定分布(赤線)と実際の分布(黒線) f:id:yaagrng:20201029002251p:plain

Go Beyond!!の推定分布(赤線)と実際の分布(黒線) f:id:yaagrng:20201029002428p:plain

AAのような一般的な譜面はかなり精度が高いと思います。Go Beyond!!のようなハード落ちなどが多そうな譜面は低スコアレート帯では若干精度が落ちていますが、スコアレートが60%を超えてくると実際の分布とほぼ重なります。

全体として、推定した分布が実際の分布にいい精度で沿っているのが見て取れると思います。

次にニューラルネットワークによる譜面からパラメーターの推定の実験です。 特徴の異なる以下の譜面をテストデータとしました。

  • AA (一般的☆12)
  • Confiserie (発狂)
  • DIAMOND CROSSING (チャージ)
  • Snake Stick (皿)
  • ICARUS (ソフラン)

上記以外の譜面をトレーニングデータとしました。 学習にかなり時間がかかるため、とりあえずミニバッチサイズを10、エポック数を5でニューラルネットワークを学習させました。 そのニューラルネットワークによるパラメーターで描画したスコア分布が以下になります。

f:id:yaagrng:20201029150044j:plain:w300 f:id:yaagrng:20201029150049j:plain:w300 f:id:yaagrng:20201029150057j:plain:w300 f:id:yaagrng:20201029150106j:plain:w300 f:id:yaagrng:20201029150112j:plain:w300

学習が足りないのか、そもそも構築が悪いのか精度がとても悪いです。すべての譜面でグラフの形がほぼ同じになっているので、譜面に対して分布を学習できたという感じがしません。

さいごに

混合ガウスモデルでのパラメーター推定まではいい感じでしたが、ニューラルネットワークによる譜面からのパラメーター推定が残念な結果になりました。 深層学習に詳しくないため、とりあえずで実装して学習してくれないかなあと思ってやってみましたが、そう甘くないですね。お勉強しなくては。 ニューラルネットワークの譜面の学習は裏で回しつつ、問題点があれば潰していこうと思います。

使用したコードや材料はgithubに置いておいたので、弄ってみたい方はどうぞ。 また、深層学習有識ニキ/ネキから精度改善のためのアドバイスをいただけると嬉しいです。

github.com

HEROIC VERSEの皆伝とスコアラーのスコアデータが手に入れば、そのデータでやってみたいですが、SINOBUZのときに収集するのが相当骨が折れたのであまりやりたくありません。どなたかください。 弐寺の分析をするたびに、KONAMIの課金プランにビートアナリストコースを作って、データに自由にアクセスできるようにしてくれと思いますが需要が低すぎますね。