S3クローンMinioを使って、自前MicroServices用データストレージを構築する


Minio

Minioという、S3のクローンサービスがある。Goで書かれたAWSのS3のオープンソースクローンで、API互換のあるすごいプロダクトだ。Minioの起動時のヘルプに書かれている説明が非常にわかりやすいので、そのまま引用する。

Minio – Cloud Storage Server for Micro Services.

S3は使いたいが、個人プロダクトだからそんな派手な利用をするわけではないし、そんなちまちましたことでS3の料金をシミュレーションしてわざわざ胃を傷めたくないので、何かしらいい感じのクローンが無いかと思って探していたところ、普通に[s3 互換][検索]でぐぐったら上の方にこのエントリが出てきたので、早速試してみた。

なお、Minioはサーバー版のDLページに移動すると書いてあるが、「Minio server is under active development. Do not deploy in production.」とのこと。確かに、コミット履歴を見てみると、そこそこの勢いで更新され続けている。自分は単なる自分用のしょうもないサービスのストレージに使いたかっただけなので問題ないが、素直にプロダクション環境に使いたいなら、S3を使ったほうが良さそう。あるいは、S3でCI回すのがコスト的にキツイ時の代替手段程度だろう。

起動

ダウンロードページにも書いてあるが、非常に簡単。

Goで書かれているので、単体のバイナリとして配布されているのが嬉しい。

ただ、上の方法だとhelpが表示されるだけなので、実際に起動するときは

の様に、serverコマンドとオブジェクトを保存するディレクトリを指定する必要がある。

起動すると、Minio内でAWSのaccess_key_idとsecret_access_keyとして扱える値が表示される。

素晴らしく簡単。

Webコンソール

Minioを起動すると、デフォルトでは9000ポートでサービスが起動し、同時に9001ポートでWebUIでMinioを操作できるコンソールが起動する。

ローカルで起動しているなら、http://localhost:9001にアクセスし、Minioの起動時に表示されたaccess_key_idとsecret_access_keyを入力すると、BucketやObjectを作って遊べるWebUIが提供される。

これを触っているだけでもそこそこおもしろいので、SDKからアクセスして挙動を試すために、いくつかBucketやObjectを登録しておくと良い。

Screenshot from 2016-03-07 02:41:51

 

とりあえず、テスト用にDownloadのフォルダにあったMemtestとUnetbootinを適当にぶん投げてみた。(どうして自分はUbuntuを使っているのに、rpmのファイルがDownloadに入っていたのだろう……?)

Rubyからのアクセス

素直に、Amazonが公式で用意している aws-sdk gem を使用する。

aws-sdk自体は、AWSの他のサービスのAPIも全て含んでいて、AWSを普通に使う分には申し訳ないのだが、今回のようにS3クローンのみを使うにはかなり巨大なコードベース、かつコードもあんまり読みやすくないので、正直なところ使いたくなかったが、他のS3に特化したgemではAWS4-HMAC-SHA256、通称V4と呼ばれる方式に対応しているものが見つけられず、かつMinioはこのV4を要求する。そのため、公式のSDKを使うのが最も手っ取り早いようである。もしかしたら、Minioの設定でV4をオフに出来るのかも知れないが、調べるのが面倒で調べていない。

なんらかの任意の方法でaws-sdkをインストールするが、とりあえずbundlerとpryを使って簡単にテストするには、次のようなコードが一番楽だと思う。

見づらい、が。

Aws::Credentialsクラスをわざわざ作っているが、どうせS3の機能しか使わないので、Aws::S3::Clientを作るときに直接指定しても良いかも知れない。

重要なのは、Aws::S3::Clientをnewするときに、endpointというオプションで ‘http://localhost:9000’ というアドレスを指定しているところで、これがAWSの繋ぎ先を変更し、ローカルのMiniに向けているところである。

また、おそらくURIを構築するときに何かあるのだろうが、force_path_styleオプションをtrueにしないと、Objectの取得が getaddrinfo: Name or service not known というエラーで終了してしまう。

そして作成されたクライアントに対してlist_bucketsのメッセージを送ると、先ほどWebUIで適当に作ったBucketsが返される。

list_objectでObjectの一覧の取得にも成功しているし、get_objectで、指定したローカルファイルにオブジェクトをコピーすることもできた。もちろん、MD5を取ってみたが、元のファイルと一致している。

すごいぞMinio

ざっと触ってみたが、個人ユースのS3を使っているプロダクトのバックエンドをまるっと置き換えても、そこそこ使えそうな雰囲気が素敵だ。

何より、最近はDockerを使ったり、作ってるものをなるべくポータブルにするように心がけていたりするので、何かしら永続的なストレージが必要だけど、S3ほど大げさなものは必要ないという場合にはとても強力な選択肢になりそうだ。

すべての機能は試していないが、Rubyのaws-sdkのgemでそこそこ動くので、他の言語に用意されているS3用のクライアントでも、比較的簡単に切り替えが出来るような気がする。これはかなり嬉しいことで、開発中は適当にMinioを使って、プロダクションにのせるときにS3に変更したい時も、ライブラリ構成を変更せずに、設定一つで切り替えられてしまうということだ。

とりあえず、目下は自分のしょうもないプロダクトのバックエンドに使ってみるのと、このブログもDocker上で動いているので、ファイルストレージをMinioに変更してスケールが出来るようにしてみたい。


カテゴリー: Linux, Ruby | コメント / トラックバック: 0個

ConoHaちゃんが好きすぎるので、WebAPIを叩くためのGemを(途中まで)作ってみた


この記事は、ConoHaちゃん Advent Calendar の22日目です

TL;DR

ConoHaちゃんが、普通にクラウドサービス的に使えて便利な上にマスコットは清楚かわいいしWebAPIも用意されていてプログラマフレンドリーだし、好きすぎるからAPI用のRubygemを途中まで作ったけどいろいろ大変だった話。

ConoHaちゃん

このはちゃんは、昔は一応VPSサービスと言っていましたが、リニューアル後はクラウドと名乗っています。フルSSDが使えて転送量は定額、そして一番小さなインスタンスだと国内で(たぶん)一番安い料金設定がステキです。

このはちゃんとの出会いは、丁度いまの会社に入った時に、同僚の人たちに「このサービスのキャラかわいいよ」と教えてもらったことに始まります。確かにキャラが可愛かったことと、サービスとしても気軽にサーバーを借りられて、しかも転送量が一定であること、さらに結構頻繁にイベントや勉強会をやっていて、そこでクーポンをばらまいてくれるというどの辺が清楚なのかわからないところが好きで、いまでは自分で何かするときにはとりあえずこのはちゃんのサーバーで検証してたりします。先日、別のAdvent Calendar に書いた「Deep learning でニコ生監視システム」にも、ConoHaちゃんのサーバーを使っています。

ちなみに、1年くらいはもらったクーポンで運用できてましたが、最近は普通に課金しまくってます。

ConoHaAPI

このはちゃんには、OpenStackに準拠した(らしい、実は私はよくわかってない)WebAPIが用意されていて、ほぼすべての操作をAPI経由で実行できます。できますが、APIの数がかなり多いのと、クエリをビルドするのが結構たいへんなので、これはライブラリ書くしかないなと思ってGemにしました。

conoha_api

Usage

問題点

conoha-apiは、以前に作ったGorakuと同様に、Octokitを参考に作られています。が、このはちゃんのAPIは、GithubやChinachuと違い、サービスごとにAPIのエンドポイントが変わります。たとえば、VMを操作するCompute Serviceと、アカウント情報を管理するAccount Service、アクセスの認証を得る Identity Serviceは、全部APIのホストが違います。ただパスが違うだけだったら良いんですが、普通にホスト名レベルで違います。最初は面倒だな程度に思っていましたが、実装を進めていくうちにいろんな問題にぶち当たりました。

ConohaApi::Clientのモジュールたち

ConohaAPIへのアクセスは、ConohaApi::Connectionモジュールに書かれたrequestメソッドから、Sawyerのラッパーを経由して行われます。そして各APIのエンドポイントは、ConohaApi::Clientクラスの名前空間の下にある、各サービス名に対応したモジュールに定義されています。たとえば、Computeサービスであれば、ConohaApi::Client::Computeモジュールにエンドポイントとメソッドとクエリが記述されています。

ここで問題になるのは、各モジュールでアクセスするホストが違うということです。OctokitやGorakuであれば、ConnectionモジュールをClientクラスにincludeし、Connectionクラスに定義されたget, put, post, patch, delete メソッドを呼び出すことで単一のエンドポイントに統一的にAPIにアクセス出来るのですが、conoha-apiの場合は、APIの定義されたモジュールごとに、ホストを切り替えなくてはいけません。

とりあえず、まずは各サービスのモジュールに、エンドポイントを定義して、呼びだされたモジュールごとにホストを切り替えたSawyerオブジェクト(agentという名前で定義して、requestの中から呼び出されます)の向け先を変えようと思っていました。ですが、ある程度実装を進めたときに、問題にぶち当たりました。

  1. Identity Service でアクセストークンを取得するときに、各サービスのエンドポイントが提示される
  2. ライブラリとしての使い勝手を考えた時、Identity Serviceへのアクセスは暗黙的に行われるべき

1つ目の問題点は、各モジュールにホストをハードコートできないということです。Identity Service にアクセスした時に取得する情報こそ真に信じるべき情報であって、エンドポイントの情報はハードコートされるべきではないからです。これに関しては、Identity Service にアクセスした時に、各エンドポイントの情報を保持することで対応は出来ました。Clientクラスが持っているクラス変数に、各モジュールの名前をキーにしたハッシュマップを用意し、その中にIdentity Service にアクセスした時の情報を保持しておきます。そして、各サービスのモジュールからメソッドをコールした時、Clientクラスはそのメソッドをスタックコールから確認し、そのモジュール名に対応したエンドポイントをクラス変数から引くようにしました。

更に大きな問題は、2つ目の問題でした。例えば、conoha-apiをrequireして、VMを立ち上げるためにComputeサービスにアクセスするために、わざわざClientオブジェクトを作成して、authを行う、という2ステップは行いたくありません。普通は、Clientオブジェクトを作成して、Computeサービスのメソッドをそのまま呼び出します。そうしたとき、Computeサービスが利用しているConnectionモジュールのAgentは、リクエストがあったときにまず認証情報があるかを内部的に確認します。そして、ない場合はIdentity Serviceにアクセスして、トークンを取得し、そして何事もなかったかのようにCompute Service のメソッドを呼び出します。こうすると、ユーザーが明示的にauth処理を行うこと無くライブラリを使えます。

ここで問題になるのは、実際にAPIを呼び出しているのはComputeモジュールなのに、内部で必要な通信はIdentity Serviceということです。ということは、1つ目の問題を解決した「呼び出し元のモジュールによってホストを変える」作戦だと、微妙にうまく行かなくなります。Connection#requestメソッドが複数回コールされた時、微妙に整合性がとれなくなります。

最初は、Connection#requestがコールされた時に、現在のagentをtmp変数に保持して、新しくagentを取得し、最終的にtmpに戻すという方法をとりました。しかし、これではrequestの中で使用されるagentメソッド自体に、自分がどこに接続されているかの情報を渡す必要があり、agentを毎回新しく作成しなさなくてはならないという、やや微妙な実装になりました。インスタンス変数自体にその情報を持っても良いのですが、少なくとも自分が書いたコードでは、なんだか複雑な見た目になってイマイチだと感じました。

そこで、Connectionクラスのインスタンス変数に、次に繋ぎたいエンドポイントをスタックとして所持することによって、この問題はひとまず回避しました。requestがコールされた時、スタックトレースからServiceのつなぎ先を取得しスタックに積み、agentメソッドがこのスタックを参照してSawyerオブジェクトを切り替えることで、コネクションのプーリングが可能になりました。スタックにすることによって、agentもconnectionも複雑な処理や見た目を持つこと無く、比較的わかりやすく書けたと思います。

もちろん、これはベストプラクティスとは思えないので、今後改良の余地はありますが、ひとまずこのように対応しました。

最大の問題点

Connectionモジュールの問題を解決すると、今度はまた別の問題が出てきました。ConoHaAPIは、数が多すぎることです……

数字の問題

ConoHaAPIは、かなりの数があります。Connectionの問題を解決したら、あとはAPIの仕様に沿って機械的にガーッとエンドポイントを定義していくだけなのですが、それでも大量のリクエストJSONの作成や、例外処理、デフォルト挙動の定義など、かなり時間のかかる作業です。

そのため、一旦公開するバージョンはv0.1.0として、Identity Service と Compute Serviceの一部を実現した形になりました。理由は、Identity Service と Compute Serviceさえ実現できれば、最低限のVMの操作を行えるからです。これ以上の各サービスは、順次時間と必要を見て実装していこうと思います。

お金の問題

ライブラリを作った以上、テストをしないわけにはいきません。

が、このはちゃんがいくらリーズナブルとはいえ、VMを落としたり立ち上げたりしてたら、まあそこそこのお金になることは想像できます。今のところ、かかっているお金は数十円ですが、これから先各サービスを実装していくうえで、金銭的な負担はまあまあのものになりそうな気がしています。

これに関しては、モチベーションだけではなく、財布的な意味でも辛いので、ConoHaAPIのサンドボックス環境ができるか、あるいは勉強会でクーポンをもらうまでは、あまり積極的に開発に臨めないかも知れません。

今後

とりあえず、他のAdvent Calendar のネタにした、Deep Learning でニコ生を完全監視システムを、API経由でぱぱっと立ち上げられるくらいには、ライブラリと周辺ツールを整備させていきたいと思います。

あと、すごくこのはちゃんのカレンダー欲しいです。今年の分は勉強会に行ったらもらえてすごくハッピーだったんだけど、リニューアル後はなんかあまり勉強会が開かれて無くて、このはちゃんと触れ合う機械が少なくて正直しょんぼりしています。


カテゴリー: Ruby, プログラミング, ポエム | コメント / トラックバック: 0個

ゲームプラットフォームとしてのSlack


この記事は、 Slack Advent Calendar の19日目です。

Slackは、ゲームプラットフォームだ

最近、よくSlackをチームのチャットツールだと誤解されている方をお見受けしますが、皆本質を見誤っていると言わざるを得ません。Slackがチャットツールではなく、ゲームプラットフォームだという理由は、次の点から明らかです。

  • Emojiという美麗なグラフィックのアセッツ、しかもどれだけ登録しても無料
  • Emojiのサイズが統一的で、ドットとしての役割も果たす
  • テキストベースの複雑なコマンドも入力可能なコントローラ
  • ユーザー識別も可能なので、複数のコントローラでマルチプレイも可能
  • 画面描写がシンプルなので、難しいことを考えずにただ更新前と更新後の画面を用意するだけ
  • あといろいろと

以上のように、Slackがゲームプラットフォームだということは疑いようのない事実ですが、その反面ゲームプラットフォームとしてはやや機能が不足していると思われる面も少なくありません

  • 音を鳴らせない
  • FPSが低い
  • Directなんとかとまではいかないものの、なんか微妙に不便でよくわからないAPI
  • あといろいろ

まあなんというか、Slackはゲームプラットフォームなのに割とゲームを作る能力としては低いです。むしろ最近は、副産物としてのチャットツールの方を成長させようと躍起になり、ゲームプラットフォームとしての本分を忘れ去っているように見えます。

Slack Game

そんなSlackを、ゲームプラットフォームとして活用するために足りないのは何かと考えたところ、どうやら啓蒙活動が足りないように思えました。そう、Slackをゲームプラットフォームとして便利に利用するフレームワークが無いのです。

そこで、作りました。

slack-game

Slack上でゲームを作ることを支援する、RubyGemです。

How to use

とりあえず、手っ取り早く説明するために、デフォルトでデモとして入っているライフゲームを動かします。

lifegame

なんとなく、雰囲気はつかめてもらえたのでは無いでしょうか?

次に、最も簡単なサンプルをGistに用意しました。SlackGameのgemの中に用意されている、Demoというゲームを解説するために、適当に作りました

コード自体はこんな感じ

 

簡単な解説も付け加えておきます

  • SlackGame::Controllerクラスを継承して、commandに識別子と正規表現を渡す
    • 正規表現にマッチするmessageが入力されると、識別子がControllerに記憶される
    • takeメソッドを使って、その識別子を取り出す
  • SlackGame::Canvasクラスを継承して、dotに識別子と、その識別子に対応するemojiを渡す
    • Canvasクラスは、NxMのドットマトリクスを持っていて、drawメソッドでemojiの文字列に変換できる
    • それを、Slackに書き出すことで、NxMのドットのキャンバスを作成する
    • ENV[‘DEFAULT_SPACE’]に設定したものが、デフォルトの空白emojiになる
  • 適当なクラス内で、先に作ったControllerとCanvasをインスタンス化する
    • main_loopメソッドで、Controller.takeを呼び出し、入力されたコマンドを得る
    • コマンドに対応し、Canvasを操作し、再描写する

このデモでは、l(left), r(right), u(up), d(down)の入力をSlackへの入力から取得し、キャラクターを動かして画面を再描写する簡単なゲームです

このように、SlackGameを使うことで、ドットを使った簡単なゲームを作成することが可能です。

免責

SlackGameは、基本的にSlackAPIを連打します。RateLimitに引っかかってなにか泣きを見ても、私は一切の責任を負いません。

言い訳

1ヶ月ほど前に、お酒を飲みながら作ったコードなので、いろいろと内部は綺麗ではありません。あまり参考になるコードは無いと思います。

これからは心を入れ替えて、真面目にコードを整備するので、いつの日かきちんとしたコードになると思います。

他の頭おかしい方々

Vim scriptによるゲームの新アーキテクチャの考察


カテゴリー: 未分類 | コメント / トラックバック: 0個

Deep learning で、全ニコ生番組をリアルタイムで監視するシステム作ってみた


この記事は、ドワンゴAdvent calendar(表)の15日目の記事です

ドワンゴでエンジニアをしている @kinoppyd です

TL;DR

ニコ生を監視し、新しく始まったユー生を定期的に視聴し続け、Deep learning Framework の Caffe を使って画像認識し、何が放送されているのかをリアルタイムに知るシステムを作りました。

注意:この記事の中で使っているニコ生へのアクセス方法に関しては、すべてGoogle検索で分かる範囲の情報を使っています。開発者として知っている情報は一切使っていないことを明言しておきます。また、そこそこの数のリクエストを飛ばすので、真似してニコ生側から垢BANされたとしても、一切の責任を負うことはできません。

何の話か

弊社では、なんか人工知能のラボが立ち上がるくらい、人工知能や Deep learning への関心を高めています。毎日サラッとみんなDLの話をしているのに、私自身はDLをまだ利用したことが無かったので、体験してみたくなって作ったという話です。

残念ながら、DLにあまり造詣が無いので、DLの仕組みやチューニングの話は、この記事ではトピックに上がりません。

ともあれ、DLといえば画像認識の話をよく聞きます。画像に何が映っているのかを、かなり高い精度で理解することが出来るデモを幾つか見たこともあります。そこで、生放送のようなリアルタイム性の高いサービスをリアルタイムに画像認識し、何が映っているのかをリアルタイムに認識させるのは面白いんじゃないか? そうだ、せっかくだし今やってる番組全部解析させてみればいいかな、と思ってこのシステムを作ってみました。

建前

画像認識を使ってニコ生の全放送を監視することによって、ニコ生では今何がトレンドで、どういう放送が人気を集めるかということを可視化して分析するツールが作りたかった。

本音

猫が出てくる生放送をすぐに知りたいんだよおおおおお仕事中に猫の映像を見てなごみたいんだよおおおおおお

構成

構成図は、なんかごちゃごちゃしてますがこんな感じです

niconama-watcher.001

流れとしては、ユーザーがブラウザで見るニコ生のストリームを直接CLIで受け取りながら、ffmpegを使ってストリームのスクリーンショットを取得し、それをCaffeで画像認識した結果を取得します。

各パーツはそれぞれ Docker で構築されていて、ストリーム監視とキャプチャ作成に関しては、WebAPIのリクエスト経由で、都度Dockerコンテナを立ち上げて処理をしています。

Docker

各部分は微妙にセットアップが曲者揃いのソフトウェアばかりなので、それぞれDockerを使ってセットアップしました。

このうち、Caffeとffmpegに関しては、すでにImageが提供されているので、docker pull してくるだけで利用できます。ストリームを取得してくる部分に関しては、Ubuntuの公式イメージをベースに、自作のスクリプトをGistに置いてDockerfileに取得してきたり、必要なツールを入れたりしたものをbuildしています。

Caffe

画像認識に特化したDeep learning framework と聞いています。正直、まだはじめて日が浅いため、全く見識はありません。

今回の画像認識は、リファレンスの学習済みモデルを使用しました。分類とかはかなりイマイチですが、他の学習済みモデルを入れて動作確認する時間が無かったこと、猫を探すだけならリファレンスでも足りるだろうということで、そのままです。

Dockerを使って、既に構築済みの Caffe 環境をそのまま手に入れられますが、なんか古いみたいでいろいろと手を入れる必要がありました。Yahoo!の記事をベースに参考にしつつ、そのサポートという形で複数の記事を参照しました。

Caffeで手軽に画像分類

Caffeで機械学習 -1- リファレンスモデルを使って画像をカテゴリ分類

『Caffeで手軽に画像分類』が手軽にできない。

OSX10.10でCaffeをインストール、リファレンスモデルで画像を分類

本当であれば、このすごいエントリを見て感化されたので Google Cloud Vision API を心の底から使いたかったのですが、一週間ほど前に利用申請を出しても今日の今日まで完全にガン無視されてしまったので、泣く泣く自前で Caffe のサーバーを立てて使います。Cloud Vision API を使ってみたかった……。Cloud Vision API を本当に使ってみたかったから、残念で仕方ない。悲しい。つらい。

ffmpeg

ニコ生は、Flashを使ったFLV形式で放送を配信しているので、それをキャプチャするためにffmpegを使いました。これも普通にセットアップするのは面倒ですが、Dockerを使ってコマンドを実行するごとにコンテナを立ち上げれば非常に簡単に使えました。

ひとつはまった点として、ドキュメントのとおりにキャプチャを作成すると、引数の順番の関係で一度flvを再エンコードしたうえでキャプチャを生成するので、非常に遅くなるということでした。下記のQiita記事を参考に、リアルタイムで切り抜けるようになりました。

FFmpegことはじめ

ニコ生を監視し続ける部分

ここに関しては、いくらGoogle検索で集められる情報とはいえ、あまりおおっぴらに書くものでも無いので割愛します。ただ、安定して動かなくて困ったという感想だけ。

Sinatra+Unicorn

それぞれのDockerを制御するために、WebAPIを用意しました。リクエストを受け取りDockerを起動させるものや、起動しているDockerの中でなにか処理をしたりと様々ですが、それぞれの受け口をすべてをSinatra+Unicornで手っ取り早く用意しました。Sinatraは、単一機能の簡単な処理をするAPIなどを作るときに、非常に簡単に記述できます。Unicornを使っているのは、複数のWorkerを手軽に立てたかったからです。

  • ニコ生番組のIDを受け取り、監視用のDockerを起動するAPI
  • ニコ生番組のIDと秒数を受け取り、ストリームの指定の秒数をキャプチャするDockerを起動するAPI
  • 画像を受け取り、Caffeで画像認識を行った結果を返すAPI

以上の3つを作成しました。番組の監視とキャプチャは、Dockerコンテナを起動することが目的なので、Dockerのホスト側で動かしています。それに対して、Caffeの画像認識は、既に起動しているDockerのコンテナ内で、画像を受け取り認識するために動作しています。

Ansible

各サーバーのプロビジョニングには、Ansibleを使用しました。基本的に、サーバー側での作業はDockerをインストールして、イメージをビルド、あとはUnicornを走らせる環境を用意するだけなので、シングルファイルのPlaybookで十分足ります

全生放送を監視する関係上、番組を監視する部分にトラフィックがかかるため、今回は10台の監視サーバーを用意しました。そしてそれに合わせて、毎秒大量の画像認識のクエリが発行されるため、Caffeのサーバーはコアとメモリの大きめのものを2台用意して、中で複数台のコンテナを立てて、画像を受け取り分析しています。

ConoHa

インフラストラクチャには、このはちゃんを使用しました。なんでかっていうと、このはちゃんのファンだからです。本来ならば、AWSのGPU付きサーバーを借りるのがベストだとは思いますが、トラフィックの料金の見積もりが微妙に心もとなかったのと、学習済みモデルを使うので別にGPU使うほどでは無いだろう、というのが理由です。ただ、やはり学習済みモデルを使っても、画像認識にはかなりの時間がかかったので、素直にAWS借りておけばよかったと後悔しました。

実行

実際には、このシステムで1日中ずっとニコ生に張り付き続けていると、普通に攻撃していると受け取られてBANされかねないので、30分だけ全番組監視システムを作動させてみました。また、毎秒のキャプチャを解析していると全然マシンリソースが足りないので、5秒に1回に設定しています。とはいえ、同時に数百の番組の1シーンを解析すると、それでも5秒程度のインターバルでは足りないと思いますが……

ニコ生では、だいたいピーク時間で2000番組前後のユーザー生放送が同時に放送されていますが、そのうちシステムを起動した時間以降にスタートした番組を監視します。

結果

大変悲しいことに、猫は見つかりませんでした……

一応、猫と判定された画像は2枚あったのですが、ポケモンのプレイ画面とFPSのやたらブレた画面で、一体何がどういう理由で猫と判定されたのかは不明です。

正直、1枚くらい猫が見つかってくれると思っていたので、悲しい気持ちでいっぱいです。

とはいえ、猫が見つからなかっただけでは結果としてアレなので、大量の画像認識の中で一体何が最も多く検知されたのかを見ていきたいと思います。

以下が、 Caffe のリファレンスモデルを使ってニコ生をリアルタイム監視した結果、最も多く得られたクラスの上位です

420 web site, website, internet site, site
370 scoreboard
166 bubble
110 toyshop
107 television, television system

1位の Web Site というのは、だいたいデスクトップをキャプチャした放送や、ゲーム配信で多く見られました。どうやら、画面を操作するためのアイコンがやメニューが並んでいる様子が、ブラウザに見えるようです。

2位の Scoreboard も同様に、ゲームのリザルト画面や、普通のゲームの画面のがチョイスされていました。おそらく、数字が規則的に並んでいるためにスコアボードと判定されたのだと思います。面白いところでは、麻雀のゲーム画面がスコアボードと判定されていました。

3位の Bubble はなんだかよくわかりませんでしたが、なんか丸っぽい線が多く現れている画像に多かったです。PS4の配信禁止中の画像なんかは、だいたいこれに引っかかっていました。

4位以下は、正直もうなんだかよくわかりません。

また、 Caffe は画像認識をした結果、マッチ率のようなものを%で出してくれるのですが、これもほぼ頻出上位とかぶっていて、微妙でした。

感想

ニコ生を Deep learning してみた結果、とりあえずゲーム配信がすごく多いというのはわかりました。キャプチャした画像を並べて観ているだけで、ああゲームばっかりだ、という感じです。PS4配信などで簡単にニコ生で放送できる手軽さが影響しているのかも知れないし、もともとそうだったのかも知れませんがよくわかりません。

技術的な感想。

大量のコンテナを立ててみたけれど、やっぱり Caffe で画像認識するところがものすごい詰まります。このボトルネックに引っ張られて、数百番組のリアルタイムの監視とは程遠い速度でした。数十程度ならリアルタイムで監視出来ると思うので、実用的には Caffe を動かすマシンに GPU を使い、もっと後ろに大量に並べるべきかなと思います。また、ニコ生を監視する部分も全然足りてませんでした。1サーバー数十番組くらいイケるかと思いましたが、裏の画像認識部分が詰まっていたので、引っ張られて監視部分も完全に詰まってました。

Ansible+Docker構成なので、横にブン並べるだけであれば札束で殴ることも可能です。ですが、そうすると今度は全体を制御する部分にものすごい負荷がかかります。今回は、各APIをコントロールしていたのは手元のホストマシンで、Rubyで書いたスクリプトで大量のスレッドを生成して各監視サーバーにクエリを投げて回してました。実際に数百番組を同時に監視するのであれば、やはりメッセージキューイング等の非同期クラスタで本格的な対応が必要だと思います。

膨大な情報量に対して、多少こちらの準備が甘かったため、やや残念な結果に終わってしまいましたが、まともなジョブ管理と札束があれば、意外と実用的に全ニコ生監視システムが作れそうな実感はありました。

ソース類に関しては、4日ほどで作ったためかなり荒削りなところが多いことと、普通に公開するとやっぱり怒られそうな気がするので、ある程度整備したうえで問題なければ後日に公開しようと思います。

ひとまず、 Deep learning に触れてみるという目的を達成したので、満足しました。


カテゴリー: Debian, Linux, Ruby, プログラミング, ポエム | コメント: 2 件

劇場版ガールズ&パンツァーを観てきた


神だった

これはすごい、最初から全力の、最後まで総力戦って感じだ。もう1回、いやもう何度か観なくては……


カテゴリー: 未分類 | コメント / トラックバック: 0個