近況報告

生存してます。最近色々インプットしまくることに時間を取ってる結果、アウトプットが死んでいました。記憶がまだあるうちにまとめて書いておきます。

MLCTで登壇しました

前回も登壇させてもらっていたMLCTのパネリストとして登壇させてもらいました。お声がけいただいた@hurutoriyaさんに感謝。

テーマは「アンチパターン」。SNS共有厳禁なので詳しくは書けないですが、大雑把にはこんな感じでした*1

  • 5年前はあまり当たり前でなかった機械学習の運用知見、少しずつ業界でノウハウが溜まってきている
    • 特に打ち合わせしてたわけではないですが、こういう感じでやっています、というのが各社結構似ていた
  • 機械学習単独の話題、というよりソフトウェアエンジニアリングを当たり前にやっていく

Mackerel Drink Up #9 Tokyoで登壇しました

Mackerelのdrinkupで最近の機能リリース3本のうちの一つということで7月末に正式リリースをしたロール内異常検知についてお話しさせて頂きました。スライドの内容としては新しい内容は特にないですが、自分がメインで作った機能がこうして世の中に出て、ユーザーさんに使ってもらってフィールドバックをもらって、という場があるのはありがたいですね。

もちろん、これまでも機能開発自体には携わってきていたわけですが、プロトタイプから大体担当していたものだけあって思い入れが結構大きいのかなと思います。OSSやSaaSで異常検知エンジンはぼちぼち出てき始めている中で、以下のようなことを考えながら作っていました。

  • Mackerelの特徴をどう生かして機能をデザインするか
    • ロール内異常検知単体で存在するわけではない。Mackerelというサービスの中でどういう問題を解決するものなのか、既存の機能とどう補完し合うものなのか
      • 機械学習で全ての問題を解決しようとしない
    • アラートや障害対応する人との関わり方。人間をどうサポートするか
  • MLOps的な観点、メンテナンス性、コスト

首都大で非常勤講師を担当しました

学生時代からお世話になっている首都大の小町さんからお声がけいただいて、非常勤講師として講義を担当させてもらいました。一人一日 * 4日のうちの一人として担当しましたが、他の講師の方(Amazon 荒木さん @ar1 / クックパッド伊藤さん @takahi_i / PFN 小嵜さん @smly)が豪華だったのでこれはヤバイな...と思いながら頑張って資料を作っていました。

大学での講義(しかも実習)自体が初めてだったため、どれくらいうまくできたかは謎だったのですが、感想をパラパラ読ませてもらった限りではなかなか好評だったようでよかったです。とはいえ、学生さんの色んな手元環境を想定しきれていなくて本質的でないところに時間を割かせてしまったりした箇所もあったので、また機会があれば資料もブラッシュアップしていきたいなと思います。

データ基盤構築活動をやってます

今期(8月)からチーム内のデータ基盤構築をやり始めました。データ基盤、いつか関わってみたいと思ってはいたものの知識は特にない初心者でした。あれこれ勉強すべく、都内での出張タイミングで色んな勉強会に顔を出させてもらったり、社外の人や社内の経験のある人にひたすら知見を聞くということをやってました。例えばここ。

技術的なことはもちろん、データ基盤をどうやって使ってもらうかが不安だったため、どういった工夫をされているか着手前に聞けたのはとても役に立ちました。ある程度運用が上手くいき始めたらこれもどこかで発表したいですね。異常検知と違ってデータ基盤は各社やっていると思うので、目新しさはあまりないかもしれませんが...。

  • チームKPIを出すための業務フロー可視化 / フロー整備
    • スクリプト化 / 自動化
  • 何を出すべきか、その意図は何かチーム内関係者にひたすらヒアリング
  • BigQueryを中心にデータ基盤構築を考えていたため、Embulk / Digdagを使ってデータ転送
  • BigQueryにデータが入り始めた段階で、Data Studioを使ってプロトタイプ的なダッシュボードをいくつか作った
    • 「みんなこれを見ようぜ」という完成系を一気に作る、というよりはBigQuery経由するとこういうことできますよ、というのをチームメンバーに少しでも思ってもらえれば、という意識が強い
      • BigQueryだけ用意しても何ができるか分からんと思うので、各職種の人に響きそうかなと思うダッシュボードのプロトタイプをがっと作った
      • 作り込み自体は必要な人がやれるように、後述しているようなサポートを意識
    • Data Studioは細かいところでは微妙(ヒストグラム書けないとか)だと思いつつ、初手で運用の手間のかかるものを増やしたくなかったので採用
  • CREがやりたいと思っている分析をスムーズにやれるようにしたかったので、Mackerelを題材にしたSQL100本ノックを作る
  • 社内の他チームでもデータ分析をやり始めたチームがあった && 結構同じようなことをやっている / 困っていたので、社内勉強会を開始
    • 参加者の半分近くがエンジニア以外の職種の方。エンジニアのみでやっていても仕方ない領域なので、ありがたい...
    • これも数回回してみたらどこかにアウトプットしたい

やっていきます。

*1:このくらいの粒度での共有はOKと確認いただいてます

Twitter検索結果の語義曖昧性を解消するsaba_disambiguatorのアップデートを行ないました

タイトルだけ見ると何のこっちゃという感じですが、前提としてはこんな感じです。

今回はこのツールのアップデートに関する話です。

apexからAWS SAMへ

リリースした当初はAWS公式のcli経由でのdeployツールは(確か)存在しておらず、apexを使っていました。

便利に使わせてもらっていたのですが、今年の夏にNo longer maintainedとなってしまっており、AWS SAMに移行しました。

AWS公式である安心感やCloudFormationっぽい形で必要なIAMやCloudWatch Eventも一緒に管理できてよいですね。

TweetをBigQueryに転送できるように

Slackでサービスに関する言及が流れてくるのはよいのですが、使っているうちに例えばこんな欲が出てきます。

  • サービスへの言及数が最近多い気がする。先月と比べるとどうなんだろう
  • この機能要望多い気がするけど、定量的に見るとどうなんだろう
  • 今月よく言及されていたBlogのリストをピックアップしたいけど、Slackの履歴を一月分遡るのダルいな...

定期的に手動で集計するのは手間なので、よしなに分析できるようにBigQueryに転送する機能を追加しました。

BigQueryに送っておくと、例えばこういったことがData Studioで分析 / 可視化できます。

Tweetの一覧が簡単に遡れます。meetup開催直後の期間に絞ったり、ユーザーを絞ったりすることも簡単です。Data Studioは画像のURLを書いておくと画像も表示できるので、アイコンも表示されて便利ですね。

Tweet一覧

時系列で言及数の推移を見ることができます。11/6が特に多いですが、ダッシュボードで調べたところ、プレスリリースが出た日でした。

言及数の推移

どういうブログに関しての言及数が多いんだろうというのもすぐ分かります。

言及数が多いURL一覧

dependabotの導入

利用しているライブラリのアップデートは定期的にやっていきたいですね。dependabotが便利なので、導入しました。それをやるためにGo Modulesもちゃんと使うようにしました。

PR: このツールのアップデートは業務時間を使って行なわれました

saba_disambiguatorのようなちょっとしたNLPツール、サーバー監視を支えるための機械学習を使ったロール内異常検知などを開発しています。ご応募お待ちしております。

はてなで一緒に働きませんか?

最近の砂場活動その13: Vue.js + Nuxt.jsで構築したアプリケーションをTypeScript化する

趣味プロジェクトであるML-Newsのフロントを整備したのは約一年前。その頃はVue.jsのTypeScript対応も微妙な時期(?)だった。

ちょいちょいTypeScriptサポート対応したよという声も(個人的に)見るようになった気がして、自分もやってみることにした。趣味プロジェクトのように忙しいときは結構触らない期間があるプロジェクトでは、型が分かったりlinterで怒ってくれるサポートがあるのはありがたいのである(普段はScala / Golan /Python with mypyで生活しているので)。

やったこと

困ったこと

導入するためにちょい困ったりはしたけど、得られた恩恵のほうが大きいかなという印象です。

Nuxt.jsビギナーズガイド―Vue.js ベースのフレームワークによるシングルページアプリケーション開発

Nuxt.jsビギナーズガイド―Vue.js ベースのフレームワークによるシングルページアプリケーション開発

最近の砂場活動その12: Data Studioを使ってGoogle Analyticsと任意のデータを紐付けてデータ分析する

仕事でデータ分析をやる機運が高まっていて、Google Data Studioをぼちぼち使っていこうとしてる。仕事のデータは分析する前のデータパイプラインなどあれこれ考える必要があるので、ひとまず趣味プロジェクトのML-Newsを題材にして遊んでみる。こういうときに雑に遊べる砂場プロジェクトは最高。

Data Studioの大雑把な概念

Data Source

Data StudioにはData Sourceという概念がある。Data Sourceは名前の通りデータソースで分析をかける対象データを指す。例えば

  • Google Spreadsheet
  • Google Analitics
  • BigQuery
  • Cloud Spanner
  • Search console

などなど様々なものをデータソースとして指定できる。手元のcsvをアップロードするFile Uploadなどもある。

Reports / Explore

同じようにグラフが書けて似ているなって感じだけど、こういう使い分けかな。

  • Reports: みんなで定期的に見るダッシュボードを整理する用
  • Explore: データ分析担当者が探索的に条件等を指定して分析速度重視でやる用

綺麗にやるのは後でやるとして、Data Studioで何ができるか知りたいので、Exploreを先に触った。ここでは中心となるData SourceをGoogle Analyticsとする。

ページタイトル毎のPVなどをテーブルに吐き出したりグラフに描画できて、便利は便利であるけど、これ単独ではGoogle Analyticsでできることとあまり変わらない。ちょいちょい触った結果、威力を発揮しそうなのは複数のデータソースを統合する時かなと思った。SQLでいうjoinを相当ができると思うとよい。

複数のData Sourceを統合して分析

ML-NewsのURIはこういう感じになっていて、以下の数字の箇所がDB内のexample_idというものに対応している。

このexample_idに関連するtweet一覧やブコメ一覧をDBの中に持っている。ちなみにDBではtweetのスキーマを以下のように持っている。

go-active-learning=> \d tweet
                                             Table "public.tweet"
      Column       |            Type             |                         Modifiers
-------------------+-----------------------------+------------------------------------------------------------
 id                | integer                     | not null default nextval('tweet_id_seq'::regclass)
 example_id        | integer                     | not null default nextval('tweet_example_id_seq'::regclass)
 created_at        | timestamp without time zone | not null
 id_str            | text                        | not null
 full_text         | text                        | not null
 favorite_count    | integer                     | not null
 retweet_count     | integer                     | not null
 lang              | text                        | not null
 screen_name       | text                        | not null
 name              | text                        | not null
 profile_image_url | text                        | not null
 label             | integer                     | not null default 0
 score             | double precision            | not null default 0.0
Indexes:
    "tweet_pkey" PRIMARY KEY, btree (id)
    "example_id_id_str_idx_tweet" UNIQUE, btree (example_id, id_str)
    "example_id_idx_tweet" btree (example_id)
Foreign-key constraints:
    "tweet_example_id_fkey" FOREIGN KEY (example_id) REFERENCES example(id) ON DELETE CASCADE

よって、example_idを軸にjoinしてあげれば、PVと言及があるtweet数などの関係を解析することができる。これはあくまで一つの例であって、他にも例えば

  • 顧客の満足度(別のアンケートが手元にある想定)とWebサイト上での使われ方(Google Analiticsが持ってる)
  • 顧客毎の売り上げとWebサイト上での使われ方(Google Analiticsが持ってる)

といったことが業務関連だとできそう。

複数のData Sourceを統合するにはData SourceをBlended Dataというものにする必要がある。

tweetの元データはAWS上のRDSに存在する。業務で真面目にやる場合は何らかのデータパイプラインを組んでBigQueryに定期的に流す、といったことが必要になる(この辺はあまり詳しくない...)と思う。しかし、今回はアドホックな分析がしたいだけなので雑にやる。

  • SQLを叩いてcsvとして手元に落としてくる
  • そのcsvをData Sourceの一つとして選択できるFile Upload経由でGCSに保持

雑にこういった感じのコマンドでcsvにする。

psql -U postgres -h hogehoge -d go-active-learning -p 5431 -F "," -A --pset footer -c 'SELECT example_id, favorite_count, retweet_count, screen_name FROM tweet;' > tweets.csv

統合されたData Sourceの完成系はこういう感じになる。Join keysを元にどう繋ぐかを決定する。統合後に分析対象としたいものはDimensionsMetricsに入れておく。左側がGoogle Analitics、右側がDBから抽出したcsvをData Sourceに指定したもの。

Google Analitics側はどの情報を元にexample_idとすればよいか当然知らないので、指定する必要がある。Google Analiticsのデータソースは、関数を使って自分が必要な列を持たせることができる。今回必要な情報はPage Pathというところにあるので、それを正規表現を使って抽出する。

Google Analiticsで持っている各行のデータには今回の解析の対象外(個別のページではなくカテゴリ別のページ、など)としたいものも存在する。そういったものはFilterを使って抽出する。今回はPathの情報とタイトルの情報を使ってフィルターを書いた。

あとは分析しまくる

ここまでくれば後は簡単。やりたい分析をやるだけ。棒グラフや散布図を書いて自分が欲しい情報を抽出してくればよい。Google Analiticsだけで分からない分析の例として、Page Viewsとretweetされた数の総数の関係を散布図で書いてみた。

各点のページタイトルもしゅっと分かるので、深掘りなどもすぐできる。といっても深掘りするのもめちゃくちゃ簡単で、散布図中の深掘りしたい点をクリックしてやると他のテーブルや図もその条件に勝手に絞ってくれる。

感想

Data Studioを使ってみる前はデータソースをあれこれ指定してダッシュボードで可視化できる君くらいに思っていたが、join相当のことができると知って印象ががらっと変わった。join keysのことを意識しつつ、何らかの形でデータソースに上げることができれば分析可能になるので、エンジニアとしては(ひとまず)データを上げるところまでを考えれば使ってもらえる形にできる。分析者視点としてはデータソースにまで上がっていれば、複数のデータソースを統合してより詳細な分析をExploreでアドホックにやったり、みんなで見るダッシュボードを整備するといったことができる。かなり便利であることが分かったので、もっと使い込んでみようと思います。

参考

Machine Learning Casual Talks #10でMackerelのロール内異常検知について発表しました

メルカリさんのオフィスで開かれたMachine Learning Casual Talks (MLCT) #10に「教師なし学習によるMackerelの異常検知機能について 〜設計/運用/評価の観点から〜」というタイトルで登壇してきました。

MLCTは機械学習をサービスで運用していく知見を共有する勉強会です。YouTube等で動画配信を積極的にしてくださっていて、はてなの京都オフィスでも鑑賞会と称してランチタイムに同僚と発表を見させてもらっていました。普段から勉強させてもあっていた勉強会に、登壇という形でちょっとはお返しできているとうれしいです。登壇させて頂き、ありがとうございました!

私の発表資料はこちらです。スライド46枚ありますが、発表は15分だったので本番はこれの短縮バージョンで発表させてもらいました。

f:id:syou6162:20190530065428j:plain

‪@chezou‬さんのこういうTweetもありましたが、開発者の僕自身結構胸熱(?)で、発表の見所としてはMackerelというプロダクトの概念にフィットするものを、運用が大変にならないようにいかにシンプルに作るか、というところです。具体的にはこういう感じ。

  • どの単位で異常検知モデルを作るか
    • 全体で一つだと大きすぎる、ホストに一つだと細かすぎる
    • Mackerelというサービスの根幹にある「ロール」という概念をうまく利用する
      • ロールは例えば、はてなブログのDBサーバーというようなグルーピングのことです
    • 異常検知のために特別な設定をしてもらうというより、Mackerelの概念に沿って使ってもらえば、異常検知も自然とうまく動作するような設計を目指した
    • プロダクトが先、機械学習が後
  • ホストを異常と判定したときに、その根拠をどうやって提示するか
    • 世の中的には、ブラックボックスのモデルを人間が解釈可能な近似したモデルを用意する(例: LIME)のが主流になりつつある
    • しかし、運用観点では管理しないといけない機械学習モデルが増えて厳しい。予測のlatencyの増加という観点からも望ましくない
    • 異常判定に使っている混合ガウス分布の条件付き確率分布を計算し、どのメトリックが異常かを判定している
      • 混合ガウス分布は性質のよい確率モデルがベースにあるので、条件付き確率も閉じた形で書き表わせる
      • 根拠提示用にもう一つモデルを用意する必要がない
    • 混合ガウスを使っていたとしても、混合数が大きかったり次元数が高いとlatencyなどの観点では厳しいが、ここでも「ロールに対してモデルを作る」ということが効いてくる
      • ロール内では状態数はそこまで多くならないので、混合数はそこまで大きくする必要がない
      • 判定に必要な次元数を抑えるため、ドメインエキスパート(つまり監視のプロである社内のSRE)にどの特徴量は削っても監視には影響なさそうかヒアリングしにいった
  • 誤検知を防ぎたいが、教師なしであるモデルの挙動を人間の直感とどう合わせるか
    • ほぼ動きがないメトリックがほんの少し動いた場合、モデルは異常と判定するが人間はそれを誤報と感じる
    • なるべく人間の直感に合うように振る舞わせたいが、教師ラベルを整備して制御といったことは教師なしではできない...
    • 混合ガウス分布を選択したことがここで生きる
    • 混合ガウス分布は由緒正しき(?)確率的生成モデルであるので、分散の事前分布に「memoryで全体のX%くらい変動するのはまあありえるよね」といった人間のドメイン知識を埋め込む
  • 継続的な改善
    • 自動で取れる数値はダッシュボードにまとめているが、手動でのアノテーションでのシステム評価にそれなりに力を入れている
    • ほぼ全ての異常検知によるアラートに目を通し、正しいアラートか誤報かのアノテーションをしている
      • 誤報率を時系列でトラッキング
    • 誤報の中でカバレッジの大きいものに関しては改善の施策を実施、施策の実施後には再度アノテーションをして実際に改善しているか確認、というのをひたすら繰り返している

発表に対する反応

合わせて読みたい

超交流会に登壇しました

ハカルスの染田さんと同僚のid:daiksyさんと一緒に登壇(パネルディスカッション)してきました。アルゴリズムがどうこうというより、実際にユーザに使ってもらえるプロダクト・サービスにするのはどうすればよいか、それを運用していくために必要な苦労・工夫などざっくばらんに話しました。立ち見(座り見?)が出たり、パネル後も質問してくださる方がいらっしゃるなど、大変盛り上がってよかったです。

アジェンダとしては以下のものを用意していたのですが、時間内ではとても語り切れなかったので、続きはMACHINE LEARNING Meetup KANSAI #5で!!!

  • 技術的話題
    • 機械学習の精度どこまでやる?
    • ノートブックのレビューってどうしてる?
    • 精度 vs 解釈性
  • 運用的話題
    • アプリケーションチームとの境界、役割分担
    • 引き継ぎ/ドキュメント化
    • アノテーションのルールの運用
  • ビジネス的話題
    • リリース日どう決めてる?
    • コストと儲かり

Splatoon2のウデマエがやっとXに到達した

一番好きなルールのガチエリアでウデマエXに到達したので、結構うれしい。

記録ではSplatoon2でS+に到達したのは約一年半前ということなので、ウデマエXに上がるのに大分苦戦したことが分かる。なお、ガチヤグラとガチホコのウデマエは当時と一緒というのが笑うポイントです。

デュアルスイーパーカスタムとか他のブキもあれこれ使ったけど、最終的にSplatoon 1の頃から愛用していたわかばシューターが一番成績がよいというのも面白い。打ち合いは苦手な一方、デスせず塗ることやボムでのキルは得意という自分の性質を生かそうとすると、わかばシューターを選ぶのは納得感はある。

ウデマエXに上がるまでにやったこと

当たり前のことを当たり前にやると、少なくともガチエリアに関してはウデマエXには行けた。

  • うまい人の動画を見る
    • 例: https://www.youtube.com/watch?v=NnL4qaijaQ0
      • この方の解説動画は多分全部かつ何回も見て参考にさせてもらいました
    • エイムがはちゃめちゃうまい人の動画は真似できないので、立ち回りがうまい人の動画を見つけて参考にするのがよかった
  • 味方と相手の編成をしっかり確認する
    • 味方に塗り要因が全然いないからキルより塗りを優先しようとか、編成事故で相手にしか長射程がいないのに何も考えないと一方的にキルされるので、ボムの牽制を意識的に多めにしようといったことを意識する
    • 余裕があれば敵のギアも見ておく。イカニンジャがいるとかステジャンがいると頭に入れておくと、多少は警戒できる
  • スペシャルはとにかく味方と合わせる
    • Splatoon 2では1の頃と比べるとスペシャルが弱くなっているので、一人で打開しに行くのは無謀
    • カウント取り替えすまで多少時間がかかっても、味方の復帰を待ってからスペシャルを吐くようにしよう。打開の成功の確率がぐっと上がる
    • わかばのスペシャルはアーマーなので、自分がリードしているときは無闇にスペシャルを使わず、敵のマルチミサイルやハイパープレッサーに対してカウンター気味に発動すると味方の生存率が高まって敵の打開を阻止しやすい
  • 立ち回りでカバーできないところはギアでカバー
    • 自分の場合、どうしても長射程に対してメインを使って距離を詰めるというのが下手でカバーしきれなかった
    • サブ性能アップを積んでボムの飛距離を伸ばし、長射程がいても対抗できるようになり、目に見えて成績が上がった
  • 常に味方と敵の生存人数を確認する
    • 勝ってても味方が2人落ちたから少し前線を下げようとか、敵が3落ちしたから一気に前線を上げようといったことを考える
  • 暇があったらとにかくマップを見る
    • マップのインクの動きで裏取りにきてるなとか、味方はこっちから打開しようとしているから合わせようとか相手の姿を目視する前にできることはたくさんある
    • サウンドプレイとかは自分はうまくできなかった
  • 味方のカバーをなるべく早くする
    • S+の上位になってくると、とにかくカバーが早い。味方が仕留め損なった敵をボムで追撃するとかそういったことをやって、局所的に数的優位な状況を作り出す
    • 一人で無双はできるものじゃないので、ツーマンセルを組んで動くようなイメージ
  • 壁は左に置く
    • イカちゃんは右利き。相手と対面する場合は壁を左に置いておくと一方的に有利に射撃することができる