2018年の目標1: 自分の砂場を作る

2018年の個人目標の一つ。もう一月が終わろうとしている...。

やりたいこと/目的意識

ミドルウェア/インフラで見れる範囲を少しずつ増やしていく/理解を深めていく。仕事で実際使っているっていうのもあるし、インフラ方面への理解を深めたいって気持ちが強い。苦手意識を少しでも減らしていきたいし、この辺含めてもう少しチームの戦力になりたい(今はあまりにも無力...)。

お題

題材としてはgo-active-learning。今はcliアプリになっていて、機械学習っぽいエントリを推薦してmarkdownに吐き出すという手抜き構成。自分が継続的に使っていたり、愛着がないとなかなかやる気にならない性格だけど、去年それに該当するようなものを書いていた自分good job。データ収集のクローラや格納先のElasticsearchなども去年から稼動している。

これをあれこれミドルウェアを使いつつ、ひとまずwebアプリ化。できてきたらmaster/slave構成にしたり、webサーバー/アプリサーバー/dbサーバーの同居をやめるとか色々やってみる。自分の用途的にはそうなっている必要は全くないが、ミドルウェア/インフラ回りで自分で構築してぶっ壊せる砂場を作りたい。同僚が似たような活動をやっていて、それの真似とも言える。

詳細

具体的にはこの辺が遊び要素かなって思ってる。大して難しいことはやるわけではない。

  • キャッシュにredis
    • 今はバイナリのファイルをローカルに持ってる。書き込みとか毎回やってると大変なので、適当にバッファリングしながらやってる
  • 学習データの管理
    • ぽすぐれ。テーブル構造はシンプル
    • やればいいだけ
    • master/slave構成やレプリケーション回りって実際どんな感じになっているかを知る
  • nginx
    • 自分のお手頃webアプリを作ると、ローカルで済ませるかherokuくらいしかやってなかった
    • バックエンド複数立てて割り振るとか、設定周りとかログ周りを一通りやってみれるようにする
    • 複数台構成。リクエストの割り振りとかあれこれ実験してみる

あとはこれらのprovisioningもできるようにする。前期に少しansible入門していたので、これを使う。cloudformationとかも使って楽をしたい。複数台立てたり、Amazon Elasticsearch Searviceへの通信とかもあるので、ネットワーク周りを含めて考えたい。

Clojureの思い出

ふと思い立ったので、記憶から忘却される前に書いてみようと思います。もう2年くらい書いてないけど、4年ほど仕事で使っていました。その期間はコード書くときはほとんどClojureだったので、まあまあヘビーに使っていたと思います。

前提

メリット/デメリットはコンテキストによるだろうと思うので、どんな感じで使ってたかを書いておきます。

  • 機械学習/自然言語処理の研究開発用途
    • 最近だとPython一択になりつつありますが、数年前はまだそうでもなかった
  • プロダクションに使われるわけではなく、論文を書くための実験や同僚に見てもらうためのデモを時々作ったりする用途
  • 最終成果物はコードではなく論文で評価されるので、メンテナンス性よりも素早くアイディアを実現させること優先
  • チームではなく基本的に一人でコードを書く文化だったので、自分のパフォーマンスがmaxになる言語だったら何でもいい
    • チームのメンバー数 = チームで使われる言語数という感じで、C++、 Python、Java、Matlab、Perl、Ruby、Allegro Common Lispなど統一感は全くない

Clojureを使うようになったきっかけ

  • 大学院時代、機械学習/自然言語処理の研究をやるのにC++で書いていた
    • ベイズを中心にやっていてMCMCなどでパフォーマンスが必要なことが多かった
    • 人類(少なくとも私)にはC++は早かったのじゃ...という気持ちになった
  • 他の言語に乗り換えたい
  • PythonやScalaが選択肢にあったが、普通の言語っぽいし(??)、もっと刺激が欲しいという気持ちが勝って、ClojureやHaskellが選択肢にあった
    • 修論前に現実逃避できるおもちゃが欲しかったのかもしれない...
    • とはいえ、既存の構文解析器もシームレスに使えないと研究に支障が出るということでClojureを選択した
    • 関数型、マクロなど自分がこれまで経験したことがないパラダイムだったので、面白そうだったり、実際面白くて役に立った
    • Haskellの本も読んだけど、Clojureを書くうえでかなり参考になりました

ここがよかった、Clojure

Clojureに限らない話が多いですが、書いていて気持ちよかった点をいくつか。

Immutableな世界

Clojureをやる前はC++をやっていて、思わぬ副作用で苦しんだ時もありました。Clojureはimmutableなデータ構造が前提なので、コードを書くときに考えればよいスコープがすごく狭く済むことが多く、脳内のメモリも少なく済み、テストも書きやすかったです。

リスト系関数の充実

Lisp系の言語なので、リストに対して何らかの処理を数珠つなぎのようにやることが多かったです。その際にthreadingマクロが役に立ちました。

mapの中にあるような関数が充実していて、coreにある関数で大体どうにかなる安心感はよかったです。Linux的(パイプをつないで小さい関数で加工していく)というか、小さい関数をthreadingでつないでいけばいいんだ、というのは他の言語を書くときにも役に立っているなーと思います。小さくimmutable前提の関数をたくさん書いていくので、テストもしやすい作りに自然となっていきました。

困ったときにはJavaに逃げられる

Clojureはパッケージが結構充実してるので、特にデモ環境とか試してもらうためのcli/apiを作るための道具は探すと結構あってそこまで困りませんでした(compojureとか使っていた)。機械学習の最適化などでマニアックなことをしようとすると流石にClojureだけでは厳しくなりますが、JavaのライブラリもClojureの中でそこまで違和感なく使えます。つまりmavenにあればなんとか出来る安心感。英文からの特徴量抽出にStanford ParserBerkeley Parserを使いましたが、両方ともJavaで書かれていてかなり恩恵を受けました。liblinearなどの大抵の分類器もJavaにならあるので、自分に必要なところだけ書けばいい。

また、パフォーマンスで困ったらJavaの配列に逃げらるので、これまた助かりました。JavaっぽいところはClojure likeに使えるようなマクロを用意してラップして使ってました。

マクロ

数年前はまだ人間が特徴量抽出を行なっていた時代だったので(冗談です)、構文木から様々な特徴量を人間がテンプレートとして書いていました。特徴量抽出は似たようなコードが並びがちですが、そういったときにマクロを使って似てるけど微妙に違う関数を自動で大量に生成する、といった用途で使っていました。係り受け解析器での例をいくつか挙げておきます。

乱用は厳禁ですが、便利だし、コード生成は脳汁が出ますね...。チーム開発で乱用されたら殴りたくなるとは思う。

Deployが容易

手元のMacで書いて、計算サーバーで実行というときに環境の差異があるとイライラしますね。今ならDockerやpyenvなどあるので事情が大分違いそうですが、当時はこの辺りをほとんど知りませんでした。Clojureなら成果物をjarファイルにまとめてサーバーにscpすれば動いてくれるので、deploy回りで困ることが少なかったのはよかったです。

並列処理が容易

機械学習をやる上で大量のデータを早く処理したいことは多々あったので、Clojureが並列処理が得意というのには助けられました。(map hoge list)のように書いていた箇所を(pmap hoge list)に変えればいいだけということも多く、とにかくお手軽でした。研究所時代は24コア/メモリが1TBのマシンも普通に使えたので、とにかく富豪的に解決すればいいやろという環境であったことも書き添えておきます。

ClojureScript面白い

研究やっているとjsを書く機会はほぼ皆無ですが、デモ環境を作っているときにjsっぽいことが書けるとUIがちょっとリッチになります。とはいえ、デモ環境のためだけにjsの学習コストを払いたくない(それをやるなら論文もう一本書きたい)...というときにClojureScriptを見かけました。いわゆるAltJsでフロントエンドまで含めてClojureで完結するのは結構面白かったです。サーバーサイドの関数を使い回せたりするのは用途よってはよいかもしれません。

ここが辛いよ、Clojure

書いていた当時に辛かったこと、今チーム開発でClojureを書くとしたら辛いだろうなと思うことが混在しています。

コード上で型が分からない

最近はScalaやGolangを書くことが多いですが、変数や引数に型があることでレビュー/コードリーディングでとても助かっています。Typed Clojureはありましたが、ディファクトになりきれていないように見えました。最近だとcoreに入っているようなので、事情が違うのかもしれません。

とはいえ、型の記述が必須だと当時はプロトタイプ書くのに邪魔だと思って選ばなかったかなと思うので、難しいところですね。

パフォーマンスチューニング

パフォーマンスでつらくなったらJavaに逃げられるとは言え、なるべくJavaは書かずにClojureで済ませたいものです。ボトルネックの箇所のみJavaで書くことにしたいですが、Clojureでのパフォーマンスチューニングは結構難しかったです。プロファイラをかけて、どの関数が重くなっているか目星を付けたいときにコンパイル元のどのClojureの関数に対応しているかがよく分からないことがあり難儀した記憶があります。マイナーな言語なので、パフォーマンスチューニングの事例が調べてもあまり出てこなかったというのもあるかもしれません。

ちょっとしたcliアプリが書きにくい

起動してしばらく使うようなアプリはよいのですが、jqのようにちょっとしたcliアプリを書きたくなることはよくありますが、Clojureは起動に時間がかかるためこういった用途では積極的には採用しにくかったです。この用途は今だったら完全にGolangで書いてしまうなぁ。

再帰をよく使う

慣れれば特に難しくはないけれど、慣れるまではちょっと困る人も多そう(再帰で書ききれないので、transientで逃げるとか)。チーム開発をやる場合には他の言語と比べると導入が大変だったり、慣れている人が少ないといったことがあるかもしれません。自分の場合はThe Little Schemerを読んで練習したりしていました。

プログラミングClojure 第2版

プログラミングClojure 第2版

mackerel-agentでChromeのタブが吹き飛ぶ悲劇を防ごう

この記事は、Mackerel Advent Calendar 2017の6日目の記事です。昨日はid:myfinderさんによるMackerel思い出話でした。今日は小ネタです!!!

ブラウザのタブを閉じない人間の習慣

全国のブラウザのタブを閉じない皆さん、こんにちは。私もブラウザ(Chrome)のタブを閉じれない人間です。以下のようにコンテキスト毎にウィンドウを新しく作って調べものをするので、タブの数も軽く50個を越えることがよくあります。

  • コードを書くための調べものウィンドウAでタブを開きまくる
  • 調査タスクを頼まれたので、ウィンドウBでタブを開きまくる
  • 少し休憩ではてブを見るために(??)ウィンドウCでタブを開きまくる

悲劇は突然やってきます。Chromeの調子悪いなと思ったら固まり強制終了、フォームに長い文章などを書いていた日にはもう今日の営業は終了してビールでも飲みたい気分になります。お疲れ様でした。

mackerel-agentで悲劇を防ごう

悲劇を防ぐには今いくつタブを開いているか数えればよいですが、こういうことは裏側で勝手にやっておいて欲しいものです。そんなことをお手軽にやってくれるプラグインがmackerelにはあります。

起動しているプロセスの数が閾値を上回ったら通知を飛ばすことができます。補足しておくと、通常の用途としてはデーモンのようなプロセスが起動しているかを監視したい場合によく使われます。以下の設定の例では、開いているタブが50個を上回ったらwarning、70個を上回ったらcriticalのアラートが飛びます(slack等への通知は別途行ないましょう)。

[plugin.checks.chrome]
command = "/path/to/check-procs -p Chrome -w 50 -c 70"

余談ですが、Chromeはタブ毎にプロセスになっているので、check-procsでの監視が可能です。他のブラウザでもいい感じにできる方法があったら教えてください。

以下は「タブを開きすぎだぞ」という通知がslackにきたので、しぶしぶタブを閉じていく様子です。

f:id:syou6162:20171127194140p:plain

mackerel-agentのactionオプションを使うと、一定個数以上タブを開いていたら強制的にChromeのプロセスを殺すといったこともできますが、それはそれで悲劇が起きそうなので今回はやめておきます。

明日のアドベントカレンダーはid:astjさんです!

マージン最大化近傍法の読書メモ

社内で異常検知本の輪講を進めています。今回は近傍法による異常検知。一年くらいに一人で読んだときのメモはこちら。慣れない人は途中で出てくる劣モジュラの概念や勾配の導出が大変かなと思ったので、メモ書きしておきます。

劣勾配/劣勾配法

目的関数が連続で微分可能な関数の場合、SGDなどによって最適化が可能な場合がある。しかし、微分可能でない点を含む場合(機械学習の文脈ではヒンジ損失やL1正則化項など、様々なところで目にする)、単純な勾配法は使えない。しかし、勾配の概念を拡張した劣勾配法で最適化を行なえる場合がある。

連続で凸な関数fがあったときに、任意の\mathbf{x} \in \mathbf{R}^Mに対して

f(\mathbf{x}) \geq f(\mathbf{a}) + \mathbf{g}(\mathbf{x} - \mathbf{a})

を満たすような\mathbf{g} \in \mathbf{R}^M\mathbf{x} = \mathbf{a}におけるfの劣勾配という。勾配は一つの値であるが、劣勾配は条件を満たすものが複数存在することがあるので、値ではなく集合として与えられる。1次元で書くと分かりやすいが、右辺が傾きgで、点(a, f(a))を通る直線であり、左辺はそれより等しいか上にいるという条件を表わしている(fが微分可能で等号が成立している場合、いわゆる接線の方程式ってやつになってますね)。

図は劣勾配と劣微分の定義と意味 - 具体例で学ぶ数学より引用。f(x)よりも下にくるような直線は何本でも引けるため、劣勾配は集合というわけである。この劣勾配を使ってSGDのように最適化を行なうことを劣勾配法と呼ぶ。劣勾配を使って勾配法を行なった場合にも勾配法と似たような収束の議論ができる(参考リンク)。

目的関数の勾配

発表資料をWebに上げてくださっている方がすでにいらっしゃるので、そこを参考にしながら輪講を進めている。

42ページから勾配の導出の説明がされているが、本に書いてあるように行列のTraceの微分を使うともっとすっきりと書けるので、その方法についてメモしておく。\frac{\partial \text{Tr}(AB)}{\partial A} = B^Tというよく知られた関係を使う。これ自体は丁寧に書きくだすと簡単に導出できます。z = x_i - x_jとおいて、z^T M z = \text{Tr}(M z z^T)が分かると勾配の式が大体出てくる。一般の式で示すのは若干面倒だけど、2x2くらいのサイズの行列で示してみると雰囲気が分かる。手書きが汚ないけど、こんな感じじゃ。元論文のAppendixを見るのもいいかもしれない。

異常検知と変化検知 (機械学習プロフェッショナルシリーズ)

異常検知と変化検知 (機械学習プロフェッショナルシリーズ)

AWS Lambda上で鯖(Mackerel)の曖昧性問題を機械学習で解決しよう

この記事は、はてなエンジニア Advent Calendar 2017の1日目の記事です。

サービスに関連する言及のみを観測したい

こんにちは。Mackerelチームでアプリケーションエンジニアをやっているid:syou6162です。サービスを運営していると、サービスに関するtweetをslackに流して定期的に観測しているといった方は多いと思います。観測するモチベーションは様々ですが

  • サービスの不具合に一早く気が付ける
    • もちろんテストや動作確認はやっているのが前提だと思いますが、それでも気づけないものも出てきます
  • 新しい機能を出した際にユーザーの反応が直に見れるため、開発者としてはモチベーションが上がる
    • 問い合わせまではないが、どういう機能要望などがあるか知ることができる

などが挙げられると思います。

問題点

Mackerelチームでもサービスに関するtweetを定期的に観測しています。余談ですが、Mackerelはサーバー(鯖)の監視/管理のサービスで、鯖の英語からMackerelというサービス名になっています。この名前ゆえに「サービスに関連するtweetのみ」を観測するというのが難しくなっています。

  • 魚の鯖に関するtweetが混じる
    • slackのチャンネルが鯖の飯テロ状態になるときがある
    • 最近だとローソンの燻製さばサンドが人気で困ります
      • 当然ながら燻製さばサンドに罪はありません
  • mackerelは多様な連語がある
    • mackerel skyやholy mackerelなど

少し脱線しますが、このエントリの内容を社内の技術勉強会で紹介したところ、イカリングにもいくつかの曖昧性があることを教えてもらいました。こういった曖昧性はサービスに特有の問題ですが、それ以外にも以下のような問題があります。こちらは他のサービス運営者で困っている方も多いのではないでしょうか。

  • ユーザー名にサービス名が入っている方のtweetが混じる
  • meetupなどのイベントが盛り上がりトレンドに入ると、公式のハッシュタグに関係ない内容を混ぜてくるspammerに遭遇する場合がある

以上のようなサービスに関連しないtweetを除外するために、これまではfluentdのfilterに正規表現を頑張って書いていました。しかし、ルールの整備は大変で段々と古びていきます。また、fluentdの障害とサービスの障害の時間が被ると、障害時のユーザーの反応が分からないといった問題点もあります。

解決方法

こういった背景から、サーバーレス(AWS Lambda)で機械学習を使ってMackerelのサービスに関連するtweetのみをSlackに定期的に流すコードを書きました。

sabaとついていますが、検索クエリと教師データ(自分の場合は秋の夜長に600件ほどアノテーションしました)を変えてあげれば他のものでも動くと思います。AWS Lambda上で動作するため、サーバーを用意する必要なく簡単に始められますし、fluentdが万が一障害の場合も問題なく動きます。

工夫点

tweetのjsonから特徴量を作り、平均化パーセプトロンで分類しているだけなので、機械学習的な面白みはほとんどありません。しかし、AWS Lambdaで動作させるための工夫が多少あるので、紹介します。

軽量な形態素解析器を使う

自然言語処理といえば最近ではPython一色になりつつあります。はてなでも機械学習関連のプロジェクトではPythonを使うことが増えてきています。日本語を扱う自然言語処理ではMeCabを扱うことが多いですが、Lambda上でMeCabを動かすのは一手間必要なようです。

サイドプロジェクトでやろうと思ったため、もっと手間をかけずお手軽にやろうということもあり、PythonではなくGo言語を使うことにしました。Go言語での形態素解析器ではkagomeがあり、apexを使うとkagomeも含んだシングルバイナリでAWS Lambdaまで送り込めるので便利です。これで一件落着かと思いきや、AWS Lambdaにはアップロードできるパッケージのサイズ制限(50Mb)があり、kagomeを含めてビルドしたバイナリは56Mbで少し足が出てしましました。どうしたものか困っていたところ、kagomeの作者の@ikawahaさんにIPADicのみのコンパクトなバージョンがあることを教えていただきました(kagomeのAWS Lambdaでの実績解除:tada:)。

こちらを使うとバイナリのサイズが20Mb程度まで小さくなったため、AWS Lambdaへのデプロイも問題なくできました。高精度に動くリッチなモデルに注意が行きがちですが、高速に動く/消費リソースが少ないモデルも実世界では重要ですね。

軽量かつシンプルな分類器を使う

はてな社内でも深層学習の手法であるCNNやLSTMをベースにした分類手法の実験を行なっています。今回の用途の場合、深層学習を用いると学習後のモデルサイズが大きくなりがちという問題点があります(もちろん、パラメータをスパースにしてモデルをコンパクトにするという研究も多数行なわれています)。今回は古典的な教師あり学習の方法の一つである平均化パーセプトロンを用いました。自前でtweetを600件ほどアノテーションを行ない交差検定で実験した結果、十分な精度が出ていると判断したためこれ以上複雑な方法を取るのはやめました(関連エントリ)。

学習した重みベクトルはgo-bindataを使ってGoのコードに変換します。Goのコードに変換できればシングルバイナリにしやすいので、deployが簡単です。deployはapexを使ってapex deployで簡単にdeployできます。

AWS Lambda上での動作の監視を行なう

Mackerelチームに所属しているので完全に宣伝ですが、MackerelではAWSインテグレーションによりLambdaのメトリックを取得したり、それを元に監視/アラートの通知といったことが簡単にできます。是非使ってみてください!

おわりに

SNS上での自社サービスの言及を必要なものだけにフィルタリングして継続的に観察する仕組みについて簡単に紹介しました。細かいところではありますが、ユーザーの声を取り込みつつサービスをよりいいものにしていきたいですね。

明日のアドベントカレンダーはid:y_uukiさんです!

Multi-task Multi-modal Models for Collective Anomaly Detectionを読んだ

勤労に感謝しながら読みました(論文, スライド)。いい論文をありがとうございます。

概要

基本的にはSparse Gaussian Markov Random Field Mixtures for Anomaly Detection(ICDM 2016)の素直な拡張だと思います。式は少しゴツいですが、拡張を順番に追っていくと大丈夫。拡張のされ方は以下のようになっています。

  • 次元数がある程度高いような場合、どの事例が外れ値か分かるだけでは不十分。どの次元がいつもと異なる動きをしているか教えて欲しい
    • Gaussian Markov Random Field(GMRF)
  • GMRFだけではシステムが状態を一つしか取らないような状況にしか対応できない。昼/夜、停止中/運転中/高速を運転中などいくつかの状態を通常状態として取り得る場合にも対応したい
    • Gaussian Markov Random Field Mixtures
    • ICDM 2016
  • システムの状態がいくつかある状態を仮定しつつ、それぞれの情報源(この論文ではタスクと読んでいます)の特性をモデルに反映させたい
    • ICDM 2017。この論文です
    • 例: 車の状態といっても運転手によってdriving conditionはかなり変わる
    • 例: 学生でも学校によって特性が異なる、その特性をモデルに反映したい
    • 例: 同じはてなのWebサービス(昼と夜でアクセスパターンが異なるなどの特徴がある)といっても、はてなブックマーク、はてなブログ、カクヨムではそれぞれ異なった特性がある。それらを反映したい
      • 自分で勝手に想定した例です

それぞれのタスクの特性をモデルに反映させたい場合、各タスク毎にGaussian Markov Random Field Mixturesのモデルパラメータを推定するというのは一つの手です。しかし、モデル一個当たりに使用できる学習データの量は減ってしまします。学習データの量を増やすために特性を反映させず一個のモデルを作る方法もありますが、全体としてぼやけた推定になってしまいます。この論文ではいわゆるマルチタスク学習を用いて、様々な学習データを使えるうまみを利用しつつ、それぞれのタスクの特徴を反映させる手法を提案しています。

この手法が効きそうなMotivating exampleが挙げられていて、これを見るのが分かりやすかったです。図は論文のFigure 2から引用しました。1次元でタスクが2つあるようなケースです。タスク1、タスク2ともに大きな山が二つあるようなmulti-modalityがある分布になっていますが、それぞれの山の尖り方は異なっています。

f:id:syou6162:20171123013356p:plain

単純なマルチタスク学習(MTL)ではmulti-modalityを反映できず、ぼやけた分布になってしまいます。混合ガウス分布(GMM)では二つの山こそ表現できていますが、それぞれのタスクの山の尖り方は反映できていません。今回の提案手法(MTL-MM)ではmulti-dalityを反映しつつ、それぞれの山の尖り方もかなり反映できています。事例x毎にタスクのラベルsが付いているという状況は割とあるので、現実的な問題設定でもいけそうです。

モデル化: Multi-task sparse GGM mixture

マルチタスク間の共通点や相違点を反映しつつ、どの変数が異常か見て分かりやすく(=結果がスパースになっている)なるようなモデルをベイズ流の生成モデルで記述していきます。モデル化はICDM 2016の論文とそこまで違いはありません。クラスタ毎に考えていた潜在変数がクラスタ/タスク毎に考えるようになったくらいが変更点でしょうか。結果がスパースになるように事前分布にはラプラス分布を組み込んでいきます。

モデルパラメータの推定

式は結構ゴツいですが、ICDM 2016のときと同様に変分ベイズを使い、近似しつつ変分下限を最大化していきます。やり方は大体同じですが、潜在変数z^sに対するパラメータ\pi^sの(スパースになる)解き方が二通り紹介されています。

一つ目は従来からあるような変分ベイズの流儀で進めていく方法。関連度自動決定の枠組みで結果がスパースになってくれるというやつです。しかし、今回の定式化の場合、目的関数に\log \pi^s_kという項が入っており、スパースになる(\pi^s_k = 0)とこの項がマイナス無限大になってしまい都合がよくありません。論文ではヒューリステックを使って解決する方法が述べられています。

二つ目は\pi^sにl0ノルムに相当するような事前分布(これも結果はスパースになる)を考えて、目的関数を書き換えるという方法です。この目的関数はconvex mixed-integer programming (MIP)の形式になっています。基本的には汎用ソルバーに投げて解くのかなと思っていたのですが、論文では頑張ってアルゴリズムを導出していました(ごつかったので詳細は追ってない...)。ここまで頑張ってconvex mixed-integer programmingを解く必要はあるのか(関連度自動決定+ヒューリステックでもよさそう?)と思って論文を読み進めていたところ、6.1章の実験で頑張ったほうがよい解が得られたと書いてあったので御利益はあるようでした。

モデルパラメータが推定できれば、あとは簡単です。モデルは基本的にはGaussian Markov Random Field Mixturesなので、ある事例が異常かの判定は負の対数尤度を計算すればよいだけですし、ある事例のある次元が異常かどうかはGaussian Markov Random Field Mixturesならば簡単に計算できます(条件付き確率が簡単な形になるため)。詳しくは異常検知本を読みましょう。

実験

ここではLondon SchoolのデータセットとAnuran Calls(カエルの鳴き声?)のデータセットで提案手法と既存手法の精度比較が行なわれていました。どちらのデータセットでも提案手法が結構なマージンで勝っていましたが、データセットはどちらも元々異常検知でよく使われるデータセットというわけではなく、実験の状況設定がいいものなのかは自分には判断しかねるという感想でした(しかし、マルチタスクの設定になっている異常検知用のデータセットは今のところないと思うので、仕方なさそう)。

2017年の振り返り技術編

ふと思いたったので書く。2016年は自然言語研究者からWeb系エンジニアになったということで、今振り返ってもキャッチアップで精一杯だったなーと思うが、2017年は去年よりは慣れたこともあり、もう少し自分にとって新しいことに取り組めたかなーと思う。といっても、XXXやり始めたという内容のほとんどが仕事で必要だったという理由なので、Mackerelチームで働くための基礎体力が本当になかったんだなと改めて痛感している(なぜはてなに入社できたのか謎)。飽きる暇もなく勉強の毎日です。来年はもう少し狭く深く掘り進めていきたいかな。

Go言語やり始めた

仕事でGo言語をやる必要があって勉強し始めたのが今年の初めだった。A Tour of Goを最初にやったけど、実際に手を動かしてレビューで見てもらったほうが早いなと思って、MackerelのグラフアノテーションをmkrでできるようにPRを出したのが初めだったと思う。

書き始めた最初はsortやるにもあれこれやんないといけないし、かっこよく書けないなーと思っていた。しかし、慣れてくるととにかく素朴に書くのがいい文化であることが分かってきて、慣れるとそれはそれでよいもんだということが分かってきた。最近では一番好きになった言語かもしれない。mattn/memoのソースコードを読んで小さいPRを出したり、中規模なものではSlackで能動学習をできるようなアプリケーションを書いたり、係り受け解析器、エントリ推薦を書いたりした。このくらいの規模をいくつか書くと大分慣れることができた。go routineはまだ使いこなせているとは言えない。

Goはcliアプリをさっと書けて、シングルバイナリで簡単に使ってもらえるのが最高だということが分かって以降、Mackerelのプラグインを作りまくったりしていた。Goの練習に丁度いいと思うので、どんどん書いて欲しい。

勢い余って他の人のプラグインのmkr plugin install対応活動もやっていた(しゅっとmerge & releaseしてもらってありがとうございました)。

Pythonやり始めた

こちらも今さら感がある。去年は仕事の機械学習のコードはPerlで書いていたけれど、今年はPythonで書く仕事がきた。Python自体は遠い昔書いていた時代があったので、大きな戸惑いは特になかった。scikit-learnやjupyterがあって、便利な世の中になっていた(激しく今さら感)。githubやgithub enterprizeがipynb対応していて、プロトタイプや調査結果の共有に便利。はてなのインターンの機械学習講義も今年からついにPythonにしました、講師を担当していた。

一方で機械学習以外ではGoがよかったこともあって、趣味ではあまりPythonのコードを書く機会がなかった。色んな環境でさっと使ってもらえることを考えるとpyenvでpython3.6をインストールしてもらって、pipでライブラリをインストールしてもらって...というを考えると面倒で、この辺はGoがいいなと思う。

異常検知やり始めた

書籍での勉強は昨年末に始めたけど、今年は手を動かして社内の多次元の時系列データでの異常検知のプロトタイプやproductionのコードを書いたりしていた。異常検知、教師なしがdefaultなので難しいだろうなと思っていたけど、予想通り簡単ではなかった。現場的には誤検知をどうやって抑えればいいか、どういうデータにはどういう手法ならばいいかのノウハウを少しずつ貯めていってという感じだった。中間アウトプットとしてMackerelのチェック監視で異常検知を行なうものを出したりしていた(これはさすがにGoじゃなくてPython)。

論文もちまちまと読んでいた。異常検知回りは問題設定でまだまだやられていないことも多いので、論文読んでて楽しいですね。

一般の機械学習や深層学習はそこかしこで勉強会やコミュニティが存在するけど、異常検知peopleはどこに行くと会えるんでしょうか。

深層学習やり始めた

仕事で現状必要になっているわけではないが、これからどう向きあっていくかを含めて色々試している。深層学習の本は山ほど出ているので、それで勉強しつつkerasで手を動かして感覚を掴んだりしていた。LSTMやCNNを使って社内の既存タスクを解き直してみたが、多少精度は上がるものの劇的というほどではなかった。これまで社内で取り扱っていなかった生成系のタスクや画像系の問題について面白い(かつお金にもなるような)問題を探っていく試行錯誤がもう少し必要そう。画像系は教師データと大量の計算機リソースが必要だと思っていたが、転移学習をベースにすれば全く手が出ないなんてことはなかった。とはいえ、深層学習に関係なく、社内のコーパスを含めたリソースは今後も定期的に整備していきたい。

AWSやり始めた

これも仕事で必要だった。MackerelのAWS/AzureのIntegrationをやっているにも関わらずcloudほとんど自分では使ったことがなく、仕事でもLambdaやDynamodb、EC2を使っていなかった。これはどう考えてもまずい、と思って趣味で動かしていたElasticsearchをAWS Elasticsearch Serviceに引っ越ししたり、Mac Miniで動かしていたクローラーをEC2に引っ越ししたりすることから始めた(これはraspberry piを買ったので、今はやめた)。Jenkinsで動かしていたいくつかのJobをAWS Lambdaで動かすようにした。

仕事でやるような規模のものは趣味の範囲では無理なので、この辺で得た知見をベースに仕事でも生かしていきたいなという感じ。

Docker&Ansible始めた

これも仕事で。最初はすでに存在するdocker imageをdocker runしかやっていなかったけど、Dockerfile書いたり、composeが何者か分かってきた。簡単なやつではあるけど、自分でよく使いそうなものはDocker Hubに置いたりしていた。

Ansibleは自分のクローラーのコードや環境設定をEC2でバチっとやりたかったので、少し勉強した。sshしてあれこれやらなくていいのは便利ですね。EC2だと環境作っては壊してというのがお手軽にできる。mackerel agentのcheck監視の設定で細かいところに手が届かなかったのでPull Request送ったりしていた。

IDEに魂を売った

これは仕事じゃなくて趣味。去年までは頑張ってScalaをEmacs(ensime)で書いていたんだけど、いよいよ辛くなってきた。これはEmacsに固執している場合じゃないと思って、IntelliJ IDEAを使い始めた。変数の型が分かったり、関数の定義元にさくさく飛べるので、大分効率が上がった。メモリがっつり持っていかれるのが痛いけど、これは諦めた。IntelliJ IDEAが便利だったので、Python(PyCharm)やGo(Goland)を書くのもIDEを使うようになってしまった。

Emacsで書くものがmarkdownだけになってしまったので、気分転換がてらvimに乗り換えをした。今のところそんなに困っていない。左手が楽になった。なお、SKKはまだ捨てれていない。多分捨てられない。

プログラミング言語Go (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)

プログラミング言語Go (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)