tag:blogger.com,1999:blog-29472171677254566762024-03-07T12:34:00.398+09:00blog.k11i.biz技術系日々の雑多メモAnonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.comBlogger55125tag:blogger.com,1999:blog-2947217167725456676.post-1293923282659485122016-04-29T23:15:00.002+09:002016-04-29T23:15:19.107+09:00「詳解 Apache Spark」を共著で執筆しました (ので、みなさんぜひご購入ください!)<h2>はじめに</h2>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhdQhRuB0EldXcgmxBVHu8TJpW6K8LiSZmxBKl2DV2gT6q9oAccKF65w__OZFZYQHZIrE_DssyNkk4YUrM6stS3rd7tmn7ipXHZWATXiWsJdYJb2svpUY0jgo-AIcrvc-N0ODwG2obt0C4/s1600/DSC_0003.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhdQhRuB0EldXcgmxBVHu8TJpW6K8LiSZmxBKl2DV2gT6q9oAccKF65w__OZFZYQHZIrE_DssyNkk4YUrM6stS3rd7tmn7ipXHZWATXiWsJdYJb2svpUY0jgo-AIcrvc-N0ODwG2obt0C4/s400/DSC_0003.JPG" /></a></div>
<p>
昨年の秋ごろから、リクルートテクノロジーズの石川有さんらとともに共著で執筆していた「<a href="http://www.amazon.co.jp/dp/4774181242">詳解 Apache Spark</a>」 が遂に本日 4/29 に、技術評論社より発売となりました!
なお、発売に先立って出版社および共著陣より献本させていただいた方々から、ありがたいことに書評や感想をいただいております。ぜひご購入の際の参考にしていただければと思います。
</p>
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">豊富な具体例,DataFrameの詳細な説明,Spark1.6で導入された機能の説明,統一感のある文体・構成など,データ解析者にも得るものの多い素晴らしい書籍でした! / [書評][Spark]詳解Apache Spark <a href="https://t.co/EwB56q5Tfz">https://t.co/EwB56q5Tfz</a></p>— sfchaos (@sfchaos) <a href="https://twitter.com/sfchaos/status/724235605207592962">2016年4月24日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">『詳解 Apache Spark』読み始めましたが本当に良い本ですね。「データ分析者向け」の本として非常に勉強になる本だと思います。</p>— Think more, try less (@Keiku) <a href="https://twitter.com/Keiku/status/723836353511714816">2016年4月23日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">「詳解 Apache Spark」ご恵贈いただきました!(・∀・) 読み始めていますが、実践的で、また要所要所に図が散りばめられていてわかりやすいです(*´ω`*)<a href="https://t.co/ogsgQX1JC7">https://t.co/ogsgQX1JC7</a> <a href="https://t.co/cTAzZ4BFAS">pic.twitter.com/cTAzZ4BFAS</a></p>— まつけん (@Kenmatsu4) <a href="https://twitter.com/Kenmatsu4/status/724955464975286272">2016年4月26日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">「詳解Apache Spark」を献本いただいた。ありがとうございます!やっぱGraphXの章が一番興味あるね!コードがたくさん載っているのはとても良い。 <a href="https://t.co/6fFnN5mLfR">pic.twitter.com/6fFnN5mLfR</a></p>— нiяоко iп пеtщоякs (@millionsmile) <a href="https://twitter.com/millionsmile/status/725661845529317376">2016年4月28日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>
また、Amazon では <a href="http://www.amazon.co.jp/dp/B01EW6S6QM">Kindle 版も発売開始になった</a> ようです。ですので、普段使いには物理書籍を、外出時には Kindle 版をご利用いただければと思います。
</p>
<h2>担当の「第 7 章 MLlib」について</h2>
<p>
書籍内ではあまり明確に謳ってはいないのですが、僕が担当した MLlib の章はデータ分析者だけではなく Web エンジニアを想定読者と考えています。仮に機械学習にあまり詳しくない方が読んだとしても、MLlib を利用するのに必要最低限の知識が獲得できつつ、MLlib を使ったアプリケーション開発ができるようになるであろう内容の構成としています。
</p>
<p>
章の前半では、RDD や DataFrame で表現されたデータに対して、MLlib の各機能 (特徴抽出や機械学習アルゴリズム、交差検証、評価メトリクスなど) を適用する説明に重点を置いた解説をしています。後半では、機械学習によって問題解決をするアプリケーションの開発イメージを掴むことを目的に、パブリックなデータセットを用いた具体例を提示しています。
<p>
<p>
紙面の都合もあり、機械学習の各種アルゴリズムの解説を事細かに網羅的に書くことは叶いませんでしたが、具体例で取り上げたアルゴリズムについては、そこそこ丁寧に説明をしました (したつもりです)。Spark 上で、より高度な機械学習の活用をしたいのであれば本書とあわせて、オライリー社の「Spark による実践データ解析」の書籍も読むのがいいでしょう。
</p>
<p>
また私の担当章以外も、GraphX や Spark Streaming など、MLlib の章以上に読み応えのある内容が盛りだくさんですので、このゴールデンウィークの勉強時間のお供にぜひ、本書をご購入いたければと思います。
</p>
<h2>おまけ</h2>
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">詳解 Apache Sparkの献本を正座して待ち続けている</p>— やまかつ (@yamakatu) <a href="https://twitter.com/yamakatu/status/719836696376795136">2016年4月12日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">おかしい…おれの元には詳解 Apache Sparkがいつまでたっても献本されないのだが…</p>— やまかつ (@yamakatu) <a href="https://twitter.com/yamakatu/status/723864153471864832">2016年4月23日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">「詳解Apache Spark」の献本を正座して待ち続けている</p>— やまかつ (@yamakatu) <a href="https://twitter.com/yamakatu/status/725664720703774720">2016年4月28日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-62247318717120423162016-03-08T01:16:00.001+09:002016-09-27T02:57:06.778+09:00OS X で XGBoost & xgboost4j をビルドする手順 2016-03-07 版<p>
<b>追記: 2016-09-27</b> 最新のビルド手順は <a href="http://k11i.biz/blog/2016/09/27/how-to-build-xgboost-on-osx/">こちら</a> に記載しています。
</p>
<hr/>
<p>いつのまにやら XGBoost のビルド手順が変更されていたので、メモしておきます (と言っても、 <a href="https://github.com/dmlc/xgboost/blob/master/doc/build.md">Installation guide</a> に書いていることをほとんどそのまま日本語に直しただけですけどね)。</p>
<h2 id="リポジトリの-clone">リポジトリの clone</h2>
<p>手元に XGBoost の git リポジトリが存在しない場合は、以下のコマンドで submodule 含めて clone してしまいましょう。</p>
<pre class="prettyprint"><code class="language-bash hljs ">git clone --recursive https://github.com/dmlc/xgboost</code></pre>
<p>もし手元にリポジトリが存在する場合は、 <code>git pull</code> したのちに</p>
<pre class="prettyprint"><code class="language-bash hljs ">git submodule init
git submodule update</code></pre>
<p>として、submodule を手元に持ってきます。</p>
<h2 id="xgboost-のビルド">XGBoost のビルド</h2>
<p>clone したリポジトリに <code>cd</code> して、次の作業をします。</p>
<h3 id="マルチスレッド非対応版で構わない場合">マルチスレッド非対応版で構わない場合</h3>
<p>単に</p>
<pre class="prettyprint"><code class="language-bash hljs ">cp make/minimum.mk ./config.mk
make -j4</code></pre>
<p>とすれば OK です。</p>
<h3 id="マルチスレッド対応版が欲しい場合">マルチスレッド対応版が欲しい場合</h3>
<p>Installation guide 曰く、マルチスレッド (OpenMP) 対応した XGBoost をビルドするには、OpenMP-enabled なコンパイラである gcc-5.x.x が必要になるとのことです。なのでまず先に、 Homebrew で gcc をインストールしておきます (時間がかかるので、お茶でも飲んで待ちましょう)。</p>
<pre class="prettyprint"><code class="language-bash hljs ">brew install gcc --without-multilib</code></pre>
<p>なお、Homebrew で gcc-5.x.x をインストールしても <code>gcc</code> のコマンドが置き換わるわけではなく、 <code>gcc-5</code> という名前でインストールされることに注意が必要です。そのため、Installation guide の手順をなぞっただけではマルチスレッド対応版の XGBoost をビルドすることはできません。</p>
<p>ここでは、Installation guide にある <code>make/config.mk</code> を単に <code>cp</code> する手順の代わりに、同ファイルで定義している <code>CC</code> および <code>CXX</code> をそれぞれ <code>gcc-5</code>, <code>g++-5</code> に置き換えてコピーし、<code>make</code> する手順を紹介します。</p>
<pre class="prettyprint"><code class="language-bash hljs ">cat make/config.mk | sed <span class="hljs-operator">-e</span> <span class="hljs-string">'s/# export CC = gcc/export CC = gcc-5/'</span> | sed <span class="hljs-operator">-e</span> <span class="hljs-string">'s/# export CXX = g++/export CXX = g++-5/'</span> >./config.mk
make -j4</code></pre>
<h1 id="xgboost4j-のビルド">xgboost4j のビルド</h1>
<p>xgboost4j のビルドについては、<a href="http://blog.k11i.biz/2015/10/xgboost-java-wrapper-os-x.html">以前の手順</a> よりハマりどころがなくなって楽になりました。詳しい手順は <a href="https://github.com/dmlc/xgboost/blob/master/doc/jvm/index.md">doc/jvm/index.md</a> に書かれているとおりですが、ここでは次のように <code>mvn package install</code> して、ローカルの maven リポジトリにインストールしてしまいます (spark の依存が入っているため、最初の <code>mvn install</code> の実行でかなり時間がかかります。二杯目のお茶でも飲んで、待ちましょう)。</p>
<pre class="prettyprint"><code class="language-bash hljs "><span class="hljs-built_in">cd</span> jvm-packages
./create_jni.sh
mvn package install</code></pre>
<p>以上で xgboost4j のビルドは完了です。</p>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-37201217291432634672016-02-09T02:39:00.000+09:002016-02-09T02:44:01.072+09:00エンジニアと機械学習、そして自分自身の振り返り ( #CROSS2016 に登壇しました)<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_B4bLeEIP275CYc9xbyjzLlJjiBJrwUi0LMLq2_zXn_sBtUYE9WDR86gRYf1xmSkDBCOCoMSGK8t5_X9DqPjoGutB8ebF0kS5u0KMorfYd2wM6O3C0iJtG23k0dBxPiSB-U-8RpnsX08i/s1600/DSC_0028.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_B4bLeEIP275CYc9xbyjzLlJjiBJrwUi0LMLq2_zXn_sBtUYE9WDR86gRYf1xmSkDBCOCoMSGK8t5_X9DqPjoGutB8ebF0kS5u0KMorfYd2wM6O3C0iJtG23k0dBxPiSB-U-8RpnsX08i/s320/DSC_0028.JPG" /></a></div>
<p>2/5 (金) に開催された CROSS 2016 の「<a href="http://2016.cross-party.com/program/x1">おーい、いそのー、エンジニアにとっての機械学習について考えようぜー!</a>」というセッションにパネラーとして登壇してきました。セッションの内容はリンク先からの引用になりますが、</p>
<blockquote>
<p>「機械学習は興味あるが、身に付けるためには何が必要?」 <br>
「機械学習を学ぶためにはいったい何からはじめればいい?」 <br>
「機械学習を身に付けたとして、その先のエンジニアとしてのキャリアはどうなる?」 <br>
と思ってる、そこのアナタ。 <br>
本セッションでは、機械学習や統計はもともと専門じゃないけど気がついたらバリバリ使ってた、そんなエンジニア連中が以下について語ります。 <br>
・エンジニアが機械学習を身に付けるために必要なこと <br>
・どのように機械学習を学ぶのが効率的か <br>
・エンジニアのキャリアパスとして考えた時、機械学習はどうなのか</p>
</blockquote>
<p>というものでした。</p>
<p>当日は会場の音響の状況的に聞こえづらいところもあったかと思うので、僕がお話した内容(伝えたかったこと)+αをざっとまとめておきます。</p>
<h2 id="エンジニアが機械学習を身に付けるには何が必要か">エンジニアが機械学習を身に付けるには何が必要か?</h2>
<p>まず最初は「エンジニアが機械学習を身に付けるために必要なこと」について議論しました。</p>
<p>そもそも、エンジニアにとって「機械学習を身に付ける」とはどういうことなのか、その点について共通認識がないままトピックが設定され議論をしていましたが、エンジニアと機械学習の関わり方には、主に以下の 2 つのタイプがあるんじゃないかと僕は考えています。</p>
<ul>
<li><strong>機械学習を利用する人</strong> :既存の機械学習のフレームワークやライブラリを用いる、またそれをアプリケーションに組み込んで利用する</li>
<li><strong>機械学習を実装する人</strong> :既存の機械学習フレームワークなどには存在しない新しいアルゴリズムを実装する、もしくは特定のアプリケーションに最適化した形で既存のアルゴリズムを再実装する</li>
</ul>
<p>前者のタイプであれば、機械学習の各種アルゴリズムがどのように動作するのか? というような、アルゴリズムに対するそこそこの理解が最低限必要になるかと思います。加えて、特徴エンジニアリング的な知識も必要になるかな… と、セッションを終えた後に議論を振り返っていて思ったのでした。</p>
<p>一方で後者のタイプであれば、機械学習アルゴリズムに対する深い理解が必要なのはもちろんのこと、アルゴリズムやデータ構造、時間・空間計算量などのある程度高水準なコンピューターサイエンスの知識、それと統計学の知識が必要になると考えています。また僕自身の経験から、微積や線形代数などの高校・大学レベルの数学の知識があると何かと助かるんじゃないかと思っています。その他には、英語力をつけておくと、最新の英語論文を読んでそれを実装したりもできていい感じです。</p>
<p>このトピックの僕の意見をまとめると、</p>
<ul>
<li>機械学習を利用する人:機械学習アルゴリズムに対する知識や特徴エンジニアリングの知識を身につけるべき</li>
<li>機械学習を実装する人:上記に加えてコンピューターサイエンスや統計学、数学力、英語力を身につけるべき</li>
</ul>
<p>となります。</p>
<h2 id="機械学習を効率的に学習するにはどうしたらよいか">機械学習を効率的に学習するにはどうしたらよいか?</h2>
<p>次のトピックは「どのように機械学習を学ぶのが効率的か」でした。</p>
<p>これは僕自身の経験にもよるのですが、何よりも「仕事で機械学習を使わざるを得ない状況に身をおく」ことが一番効率的に機械学習を学べると実感しています。加えて言うと「機械学習の師匠」と呼べるような、理論面でも実活用面でも秀でた人物のそばで機械学習を利用する仕事ができるとベストだと思います(僕がいまいる会社がまさにそのような、理想的な状況にあるわけです)。</p>
<p>もちろん、そんな恵まれた状況に誰しもが巡り合えるわけではないことは重々承知していますが、本気で機械学習のお仕事をする覚悟があれば、転職をするのもありだと僕は考えています。ただし、転職をするにも多少なりとも機械学習の知識が必要になることもあるかと思います。そのような場合には、TokyoWebmining や TokyoR などの機械学習系の勉強会に顔を出したり、各種書籍の読書会に参加して発表するのが次善の策と言えるでしょう。</p>
<h2 id="エンジニア機械学習のキャリアパス">エンジニア+機械学習のキャリアパス</h2>
<p>続いてのトピックは「エンジニアのキャリアパスとして考えた時、機械学習はどうなのか(機械学習を身につけることによって得られるリターンはいかほどか)」でした。</p>
<p>ここでいう「リターン」とは給与などのことを指すとして、現時点において機械学習を利用できるレベルのエンジニアの給与水準は、他の一般的なエンジニアの給与水準よりは幾分高いのではないかと推測しています。また、機械学習を実装できるレベルのエンジニアともなれば、相当な高水準の給与を得ているのではないでしょうか。</p>
<p>これは別に、機械学習の世界でだけ言えることではなくて、世間一般的に言えることなんじゃないかと思います。つまり、専門的かつ高度な技術・知識を持っていれば、給与水準は自ずと高くなるはずです。</p>
<p>ただその一方で、「機械学習を利用するエンジニア」の給与水準が今後も幾分高い水準を保てるかと言うと、僕は No だと考えています。現時点でも既に、Python 界隈は機械学習関連の機能が充実して使いやすくなってきているようですし、また Spark の MLlib が登場したことによって、一般的なエンジニアが機械学習を利用するまでのハードルが相当低くなっている = 技術コモディティ化が進んでいると思っています。この傾向は今後も継続して進んでいくものでしょうし、そうなるとただ単に「機械学習を扱える」だけのエンジニアの価値は並のエンジニアとさほど変わらなくなるでしょう。</p>
<p>また、機械学習が活用できるシチュエーションは、現実世界にはそう多くはない、ということにも注意が必要です。今は「人工知能」などのキーワードに引っ張られる形で機械学習も世間的に盛り上がっているようではありますが、この盛り上がりが落ち着いたときに、どれだけ「機械学習」が必要とされる仕事があるのか… というのを考えると、そう多くはないのでは? というのは想像に難くないかと思います。つまりは、機械学習を活用する仕事 = 需用が少なく、一方で供給 = 機械学習を扱えるエンジニアが多いと需給的には買い手市場となり、結果として給与水準が並のエンジニアとそう変わらない状況も生じるのではないかと思います。まあ、これはちょっと悲観的過ぎる推測でしたが…</p>
<p>そのため、機械学習を利用できるだけではなく、必要とあらば機械学習のアルゴリズムを実装できるぐらいのスキルがなければ中長期的にみて見合うリターンは見込めない、というのが僕の意見になります。というか、これは機械学習に限ったことじゃないですね… スペシャリスト的な働き方を目指すのであれば、それぐらいの覚悟がなければダメですよね。</p>
<h2 id="機械学習を業務で扱うその苦労">機械学習を業務で扱う、その苦労</h2>
<p>最後のトピックは「業務で大変だったこと、それをどう乗り越えたか」でした。</p>
<p>一般的にソフトウェア開発では、その品質を高めるために手動もしくは自動でのテストをするわけですが、機械学習においては知ってのとおり、手動や自動の議論以前に、そもそもテストを適用すること自体がそう簡単なことではありません。そのため、機械学習を組み込んだアプリケーションがあったとして、そのアプリケーションの実行結果がなんとも思わしくない結果が得られた場合、機械学習アルゴリズムにおける精度の制約なのか、それとも実装上の不具合なのかを切り分けることは困難な問題になります。</p>
<p>実際に僕も、この切り分けが困難な問題に何度も直面し、そのたびにつらみを感じてきました。そのため、今では機械学習の実装に対してできるかぎり自動テストを適用し、「実装上の不具合」を回避するように心がけるようにしています。</p>
<p>参考: <a href="https://speakerdeck.com/komiya_atsushi/ji-jie-xue-xi-falsetesutozi-dong-hua-kotohazime-number-mlct-machine-learning-casual-talks-number-1">機械学習のテスト自動化コトハジメ #MLCT Machine Learning Casual Talks #1 // Speaker Deck</a></p>
<h2 id="自分自身の振り返り">自分自身の振り返り</h2>
<p>こんな感じで、当日のセッションでは識者ぶってお話をしてきました。でも今の僕は、「機械学習 黒帯」みたいなものを名乗るにはまだほど遠いところにいると思っています(<del>「黒帯」とかただただ恥ずかしいだけだし、</del>名乗りたいとは思っていません)。引き続き学習あるのみ、です。</p>
<p>そして、ふといままでの自分のキャリアを振り返ってきたときに、今となっては何の役に立たない残念な技術をいったいどれほど学習 = 貴重な時間を投資してきてしまったんだろうか… とも思いました。これまでの経験上、ソフトウェアエンジニアを続けている限りは「コンピューターサイエンス」を除いて廃れない技術はない、と僕は考えているので、機械学習もまたいつか廃れる日が来るのかもしれません。でもその日が来るまではしばらく、もうちょっと機械学習に投資してみようかな、と思っています。</p>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com1tag:blogger.com,1999:blog-2947217167725456676.post-84778083665251774032016-01-15T00:09:00.000+09:002016-01-15T02:34:48.340+09:00弊社主催のイベント #SmartTechNight で、広告の配信最適化について喋りました<p>
僕は最近こんなお仕事をしているんですよー、という意味をこめて喋りました。
機械学習だけが「アドテク」じゃない。最適化も重要なんだよ、という気持ちで。
</p>
<p>
<iframe src="//www.slideshare.net/slideshow/embed_code/key/uWHjwPw24G2GMj" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/smartnews/smartnews-technight-vol5-smartnews-ads-smartnews-ads" title="SmartNews TechNight Vol.5 : SmartNews Ads の配信最適化の仕組みはどうなってるの? (エンジニア / SmartNews Ads : 小宮 篤史)" target="_blank">SmartNews TechNight Vol.5 : SmartNews Ads の配信最適化の仕組みはどうなってるの? (エンジニア / SmartNews Ads : 小宮 篤史)</a> </strong> from <strong><a href="//www.slideshare.net/smartnews" target="_blank">SmartNews, Inc.</a></strong> </div>
</p>
<p>
よろしければ、こちらも合わせて御覧ください。
<ul>
<li><a href="http://www.slideshare.net/smartnews/smartnews-technight-vol5-smartnews-ads">SmartNews Ads 大図解</a></li>
<li><a href="http://www.slideshare.net/smartnews/smartnews-technight-vol5-smartnews-adserver">SmartNews AdServer 解体新書 / ポストモーテム</a></li>
<li><a href="http://www.slideshare.net/smartnews/smartnews-technight-vol5-ad-data-engineering-in-practice-smartnews-ads">Data Engineering in practice: SmartNews Ads 裏の DMP System</a></li>
</ul>
</p>
<p>
プレゼンテーションに盛り込む内容について、細かいことを言わない上司に恵まれているので、僕が担当している・していたお仕事の特に興味深そうなところをほぼすべてを余すことなくしたためた資料です。
遡ること 1 年半前、広告について何も知らなかった僕は必死の思いで関連文献を読み漁っていたわけですが、当時にこれくらい充実した資料があれば、もっと楽して開発できたのになあ、と資料を作りながら思ったのでした。
ですので、この資料が他の誰かの助けになれば幸いです。
</p>
<p>
そして、こういう話題であーでもないこーでもないと盛り上がれる仲間が欲しいです!
応募は <a href="http://about.smartnews.com/ja/careers/">こちら</a> からお気軽に☆
応募するのはまだちょっと踏ん切りが付かないけど、広告システムやその分析について議論してみたい! という方がいましたら僕宛にコンタクトください。
</p>
<p>
今日の反省点:Space cats や Shibe のネタスライドは受けがよくない。
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihb-moukaEyXinN2_pupqxUJSvxpkRpxrp8WQilqVZgUsFbCSsPQSGQkss63qycUBnp_rDEzn-Nsxt2DDnwBf-mL4-E1uP45VAkgPG1sCw53jGFWkOYscug1bEyU3iF6OXIZYGexk3yYGb/s1600/9k%253D.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihb-moukaEyXinN2_pupqxUJSvxpkRpxrp8WQilqVZgUsFbCSsPQSGQkss63qycUBnp_rDEzn-Nsxt2DDnwBf-mL4-E1uP45VAkgPG1sCw53jGFWkOYscug1bEyU3iF6OXIZYGexk3yYGb/s320/9k%253D.jpg" /></a></div>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com4tag:blogger.com,1999:blog-2947217167725456676.post-1359992558937833642015-12-12T16:54:00.000+09:002015-12-12T17:23:36.727+09:00Spark/MLlib 向けに、評価メトリクスとして Logarithmic loss (LogLoss) を利用する Evaluator を実装してみた<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhH8s-ggRvhGwXVn1ujG86qV9rRAgBMtSSSm24mcW4ZE3RCysT4r70cOhj6VAK8A-3bqIRWR0BSM7mHr7sn5hs2_fnMJMPdkjUBwTTxxGXXac2TeqxYcKExNPqdNA1MA94ZcQl1Lea39lTt/s1600/Screen+Shot+2015-12-12+at+16.42.29.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhH8s-ggRvhGwXVn1ujG86qV9rRAgBMtSSSm24mcW4ZE3RCysT4r70cOhj6VAK8A-3bqIRWR0BSM7mHr7sn5hs2_fnMJMPdkjUBwTTxxGXXac2TeqxYcKExNPqdNA1MA94ZcQl1Lea39lTt/s320/Screen+Shot+2015-12-12+at+16.42.29.png" /></a></div>
<p>
ロジスティック回帰を使って確率を予測したいときに「評価メトリクスとして使いたいのは AUC (areaUnderROC) じゃなくて Logarithmic loss (LogLoss) なんだよ!」と常々思っているのですが、現在の MLlib には二値分類 (<code>BinaryClassificationEvaluator</code>) 、多クラス分類 (<code>MulticlassClassificationEvaluator</code>)、回帰 (<code>RegressionEvaluator</code>) 用の <code>Evaluator</code> 実装しか用意されていなかったので、ついカッとなって実装してしまった次第です。
</p>
<script src="https://gist.github.com/komiya-atsushi/716b8413c40735711ce2.js"></script>
<p>
これくらいの機能は標準で取り揃えていてもいいんじゃないかと思うんだけどなあ…
</p>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-87307404835969565382015-11-08T21:09:00.002+09:002016-03-08T01:17:06.209+09:00xgboost4j より数千倍速く predict できる Pure Java な XGBoost 互換の予測器を作ってみた<h2><a id="TLDR_0"></a>TL;DR</h2>
<p>XGBoost で構築した予測モデルを Java から利用したい、それも特徴ベクトルが一つ一つ、任意のタイミングで与えられるような <strong>オンライン環境下</strong> で <strong>リアルタイムな予測</strong> を実現するために利用したい、という目的を叶えるためのモジュールを作りました。</p>
<ul>
<li>Github: <a href="https://github.com/komiya-atsushi/xgboost-predictor-java">komiya-atsushi/xgboost-predictor-java</a></li>
<li>Bintray: <a href="https://bintray.com/komiya-atsushi/maven/xgboost-predictor/view">xgboost-predictor</a></li>
</ul>
<p>(XGBoost の凄さとか XGBoost そのものの使い方とか GBDT/GBRT の解説は本エントリにはありませんので、そのような情報を求めている方は他のブログエントリを読まれることをおすすめします。)</p>
<h2><a id="xgboost4j__10"></a>xgboost4j という選択肢</h2>
<p>Java から XGBoost を利用しようとすると、<a href="http://www.task-notes.com/entry/20151024/1445655600">XGBoostをJavaのwrapperを使用して実行する - TASK NOTES</a> にあるように、DMLC が提供している <a href="https://github.com/dmlc/xgboost/tree/master/java">xgboost4j</a> を利用する手段がすでに存在しています。ただ、この xgboost4j をオンライン予測に適用する場合、下記に挙げるようないくつかの懸念があります。</p>
<ul>
<li>XGBoost の Java wrapper でしかないので、オンライン予測の目的で利用をするにはインタフェースがちょっと使いづらい
<ul>
<li>大量の特徴ベクトルを入力して一括予測するようなバッチ処理に適したインタフェースになっている</li>
</ul>
</li>
<li>LIBSVM フォーマットじゃないデータを入力するのに手間がかかる
<ul>
<li>特に疎な特徴ベクトルを <code>DMatrix</code> で表現するのが面倒</li>
</ul>
</li>
<li>JNI 由来のオーバーヘッドが気になる
<ul>
<li>予測処理などが C++ で書かれているので高速処理が期待できる一方で、特徴ベクトルを一つ一つ与えて予測させる場合、ネイティブコードの呼び出しにかかるオーバーヘッドが全体のパフォーマンスに大きな影響を与えそう</li>
</ul>
</li>
<li>どこの Maven repository にもアップロードされていないので、自前で <code>mvn install</code> する必要がある
<ul>
<li>OS X で開発をしている場合、ネイティブライブラリをビルドするのも一苦労 (<a href="http://blog.k11i.biz/2015/10/xgboost-java-wrapper-os-x.html">参考</a>)</li>
</ul>
</li>
</ul>
<h2><a id="Pure_Java__24"></a>Pure Java での予測を実現する</h2>
<p>そういうわけで、</p>
<ul>
<li>速度性能がオンラインでの利用に耐えうる水準で</li>
<li>そこそこ使いやすいインタフェースで</li>
<li>ネイティブコードを必要としない (= Pure Java な)</li>
</ul>
<p>XGBoost 互換な予測器を作って <a href="https://bintray.com/bintray/jcenter">jCenter</a> で公開しました。</p>
<ul>
<li>Github: <a href="https://github.com/komiya-atsushi/xgboost-predictor-java">komiya-atsushi/xgboost-predictor-java</a></li>
<li>Bintray: <a href="https://bintray.com/komiya-atsushi/maven/xgboost-predictor/view">xgboost-predictor</a></li>
</ul>
<h2><a id="_38"></a>使い方</h2>
<p><a href="https://github.com/komiya-atsushi/xgboost-predictor-java#getting-started">README.md</a> にもサンプルコード込みで使い方を書いていますので、合わせてご参照ください。</p>
<p>なお、タイトルでも「予測器」と明言しているとおり、学習 (training) 機能については割りきって一切実装をしていません (モデルの構築をオンラインですることは流石にないと思うので)。
そのため学習データを用意し、XGBoost を CLI で直接実行、もしくは Python や R のラッパーを経由するなどして別途モデルの構築を事前に済ませておく必要があります。</p>
<p>学習済みのモデルが用意できたら、そのモデルを <code>new Predictor("/path/to/model-file")</code> としてロードします。
予測をするには <code>Predictor#predict()</code> のメソッドを呼び出します。</p>
<p>予測の際の入力となる特徴ベクトルは、<code>FVec</code> インタフェースのオブジェクトとして表現する必要があります。
基本はお手持ちのデータの形式に合わせて <code>FVec</code> インタフェースを実装したクラスを用意していただくことになりますが、配列や <code>Map</code> でデータが表現されている場合には、以下のユーティリティメソッドを利用することができます。</p>
<ul>
<li>double の配列で表現された密な特徴ベクトルで → <code>FVec.Transformer#fromArray()</code> で <code>FVec</code> オブジェクトに変換できます</li>
<li>特徴量のインデックスと値の対を表現した <code>Map</code> オブジェクト → <code>FVec.Transformer#fromMap()</code> で <code>FVec</code> オブジェクトに変換できます</li>
</ul>
<p>また GBDT/GBRT のモデルを特徴ベクトルの変換に利用することを目的に、(分類・回帰の結果を出力するのではなく) GBDT/GBRT の各ツリーにおいて辿り着いたリーフのノード番号を出力する <code>Predictor#predictLeaf()</code> メソッドも用意されています。</p>
<h2><a id="_57"></a>ベンチマーク</h2>
<p>元々このモジュールを作った動機の一つとして、オンライン利用に耐えうる速度性能で予測をしたい、という目的があったので xgboost4j と合わせてベンチマークをとってみました。
ベンチマーク計測の詳細は <a href="https://github.com/komiya-atsushi/xgboost-predictor-benchmark">こちら</a> のプログラムにあるとおりです。</p>
<table>
<thead>
<tr>
<th>機能</th>
<th style="text-align:right">xgboost-predictor</th>
<th style="text-align:right">xgboost4j</th>
<th style="text-align:right">性能比</th>
</tr>
</thead>
<tbody>
<tr>
<td>モデルの読み込み</td>
<td style="text-align:right">49017.60 ops/s</td>
<td style="text-align:right">39669.36 ops/s</td>
<td style="text-align:right">1.24</td>
</tr>
<tr>
<td>単一の特徴ベクトルでの予測</td>
<td style="text-align:right">6016955.46 ops/s</td>
<td style="text-align:right">1018.01 ops/s</td>
<td style="text-align:right">5910.48</td>
</tr>
<tr>
<td>複数の特徴ベクトルの予測</td>
<td style="text-align:right">44985.71 ops/s</td>
<td style="text-align:right">5.04 ops/s</td>
<td style="text-align:right">8931.47</td>
</tr>
<tr>
<td>リーフノードの出力</td>
<td style="text-align:right">11115853.34 ops/s</td>
<td style="text-align:right">1076.54 ops/s</td>
<td style="text-align:right">10325.53</td>
</tr>
</tbody>
</table>
<p>結果は上記のとおり、</p>
<ul>
<li>予測処理は 1ms 以下で処理できている</li>
<li>xgboost4j と比較して約 6,000 倍近い速度性能がでている (要は xgboost4j よりも十分速い)</li>
</ul>
<p>となります。Pure Java にしただけで xgboost4j との性能差がこんなに出るものなのか… とちょっと不思議ではありますが、今回のベンチマークの計測に利用したテストデータは人工的に生成されたものなので、その影響があるのかもしれません。
そのため、実世界のデータを与えた場合にはまた違った結果になる可能性がありますのでご注意ください。</p>
<h2><a id="_78"></a>制限</h2>
<p>現時点の xgboost-predictor は、モデルとしては “gbtree” のみをサポートしています。また目的関数は “binary” および “multi” のみのサポートとなります。
(“gblinear” や他の目的関数のサポートについては、必要そうであれば対応する予定です。)</p>
Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com5tag:blogger.com,1999:blog-2947217167725456676.post-91667902645976222972015-10-29T02:22:00.000+09:002016-09-27T02:57:23.022+09:00XGBoost の Java wrapper を OS X でビルドするときに気をつけるべきたった二つのこと<p>
<b>追記: 2016-09-27</b> 最新のビルド手順は <a href="http://k11i.biz/blog/2016/09/27/how-to-build-xgboost-on-osx/">こちら</a> に記載しています。
</p>
<hr/>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLnYKK_u14bocx18Gg7-Drk48l7qv6eS6pn2in-rZR0-vE6ypmuv0a-wgLLg1kq3qWtEsGzeQPBQK91ahjrz7dSeNfsKRDf0-KkECFGBRh3QHmKYy2AJztf8z90JXJKDSDF93oANAzHaU0/s1600/xgboost.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLnYKK_u14bocx18Gg7-Drk48l7qv6eS6pn2in-rZR0-vE6ypmuv0a-wgLLg1kq3qWtEsGzeQPBQK91ahjrz7dSeNfsKRDf0-KkECFGBRh3QHmKYy2AJztf8z90JXJKDSDF93oANAzHaU0/s200/xgboost.png" /></a></div>
<p>なんで Java から XGBoost を扱いたいのかはさておき、概ね <a href="http://www.task-notes.com/entry/20151024/1445655600">XGBoostをJavaのwrapperを使用して実行する - TASK NOTES</a> こちらのサイトの解説どおりではあるのですが、OS X で素直に java/create_wrap.sh を叩いてビルドしようとすると</p>
<pre><code>$ ./create_wrap<span class="hljs-class">.sh</span>
build java wrapper
clang-omp++ -Wall -O3 -msse2 -Wno-unknown-pragmas -funroll-loops -fopenmp -fPIC -fPIC -shared -o java/libxgboostjavawrapper<span class="hljs-class">.so</span> java/xgboost4j_wrapper<span class="hljs-class">.cpp</span> wrapper/xgboost_wrapper<span class="hljs-class">.cpp</span> updater<span class="hljs-class">.o</span> gbm<span class="hljs-class">.o</span> io<span class="hljs-class">.o</span> subtree/rabit/lib/librabit<span class="hljs-class">.a</span> dmlc_simple<span class="hljs-class">.o</span> -pthread -lm -I/Library/Java/JavaVirtualMachines/jdk1.<span class="hljs-number">8.0</span>_66.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/jdk1.<span class="hljs-number">8.0</span>_66.jdk/Contents/Home/include/linux -I./java
In file included from java/xgboost4j_wrapper<span class="hljs-class">.cpp</span>:<span class="hljs-number">15</span>:
/Library/Java/JavaVirtualMachines/jdk1.<span class="hljs-number">8.0</span>_66.jdk/Contents/Home/include/jni<span class="hljs-class">.h</span>:<span class="hljs-number">45</span>:<span class="hljs-number">10</span>: fatal error: <span class="hljs-string">'jni_md.h'</span> file not found
<span class="hljs-id">#include</span> <span class="hljs-string">"jni_md.h"</span>
^
</code></pre>
<p>みたいなエラーが出てしまうはずです。</p>
<p>この問題の対処法は実に簡単で、xgboost リポジトリのトップディレクトリ配下にある <a href="https://github.com/dmlc/xgboost/blob/7b25834667019e4d301fddc6e1002888b7951e5f/Makefile#L8">Makefile の 8行目を</a></p>
<pre><code>before: <span class="hljs-keyword">export</span> JAVAINCFLAGS = -I<span class="hljs-envvar">${JAVA_HOME}</span>/<span class="hljs-keyword">include</span> -I<span class="hljs-envvar">${JAVA_HOME}</span>/<span class="hljs-keyword">include</span>/linux -I./java
after : <span class="hljs-keyword">export</span> JAVAINCFLAGS = -I<span class="hljs-envvar">${JAVA_HOME}</span>/<span class="hljs-keyword">include</span> -I<span class="hljs-envvar">${JAVA_HOME}</span>/<span class="hljs-keyword">include</span>/darwin -I./java
</code></pre>
<p>と書き換えるだけ、です。</p>
<p>続いて、java/xgboost4j ディレクトリ配下で <code>mvn package</code> コマンドを実行して jar ファイルを生成しようとしてみると、今度は</p>
<pre><code>-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running org.dmlc.xgboost4j.BoosterTest
Oct <span class="hljs-number">29</span>, <span class="hljs-number">2015</span> <span class="hljs-number">2</span>:<span class="hljs-number">51</span>:<span class="hljs-number">55</span> AM org.dmlc.xgboost4j.DMatrix <clinit>
SEVERE: load native library failed.
Oct <span class="hljs-number">29</span>, <span class="hljs-number">2015</span> <span class="hljs-number">2</span>:<span class="hljs-number">51</span>:<span class="hljs-number">55</span> AM org.dmlc.xgboost4j.DMatrix <clinit>
SEVERE: java.io.FileNotFoundException: File /lib/libxgboostjavawrapper.dylib was not found inside JAR.
Tests run: <span class="hljs-number">1</span>, Failures: <span class="hljs-number">0</span>, Errors: <span class="hljs-number">1</span>, Skipped: <span class="hljs-number">0</span>, Time elapsed: <span class="hljs-number">0.121</span> sec <<< FAILURE!
testBoosterBasic(org.dmlc.xgboost4j.BoosterTest) Time elapsed: <span class="hljs-number">0.063</span> sec <<< ERROR!
java.lang.UnsatisfiedLinkError: org.dmlc.xgboost4j.wrapper.XgboostJNI.XGDMatrixCreateFromFile(Ljava/lang/String;I[J)I
at org.dmlc.xgboost4j.wrapper.XgboostJNI.XGDMatrixCreateFromFile(Native Method)
at org.dmlc.xgboost4j.DMatrix.<init>(DMatrix.java:<span class="hljs-number">62</span>)
at org.dmlc.xgboost4j.BoosterTest.testBoosterBasic(BoosterTest.java:<span class="hljs-number">75</span>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...
</code></pre>
<p>と、test フェーズでこけてしまうかと思います。これは native ライブラリの拡張子が <code>.so</code> となってしまっているのが原因なので、これは <a href="https://github.com/dmlc/xgboost/blob/master/java/create_wrap.sh#L12">create_wrap.sh の 12 行目</a> の移動先ファイル名を明示的に <code>libxgboostjavawrapper.dylib</code> と指定するか、もしくはすでに移動先にある native ライブラリの拡張子を <code>.so</code> から <code>.dylib</code> に書き換えてやれば OK です。</p>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-33338649071829145622015-10-17T15:27:00.001+09:002015-10-17T15:27:29.067+09:00よりコンパクトな Bloom filter 的なものを探して<p>Approximate membership query (AMQ) が実現できるデータ構造としてそれなりに広く使われていそうな <a href="https://ja.wikipedia.org/wiki/%E3%83%96%E3%83%AB%E3%83%BC%E3%83%A0%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF">Bloom filter</a> ですが、機能性を高めたバリエーションはそこそこ存在する一方で、空間効率を追求した・コンパクトなバリエーションはあんまり見つからないものです。</p>
<p>ここ最近、ふとデータ構造熱が高まってきたこともあったので、オリジナルの Bloom filter よりもコンパクトに表現できる代替データ構造を探してメモしてみました。</p>
<h2 id="compressed-bloom-filters">Compressed bloom filters</h2>
<p>空間効率を追求するといっても、転送・永続化している状態での空間効率なのか、それともルックアップ可能な状態においての空間効率なのかで全然違うわけですが、この <a href="http://www.eecs.harvard.edu/~michaelm/NEWWORK/postscripts/cbf2.pdf">Compressed Bloom Filters</a> は前者の転送時・永続化時の空間効率を選択したバリエーションです。</p>
<p>端的に言えば、Bloom filter のビット列における 0 と 1 の出現確率はランダム (1/2 = 0.5) というわけではなく偏りが生じることがあるため、算術符号で符号化すればよりコンパクトになるじゃん、というものです。
ただ、この圧縮はあくまでも転送・永続化時のことしか考えていないようで、Bloom filter が素早くルックアップできる状態にあるためには結局復号した状態で保持する以外に他ないようです。</p>
<h2 id="golomb-compressed-sequence-or-golomb-code-sets">Golomb-Compressed Sequence (or Golomb-code sets)</h2>
<p><a href="http://algo2.iti.kit.edu/singler/publications/cacheefficientbloomfilters-wea2007.pdf">Cache-, Hash- and Space-Efficient Bloom Filters</a> という論文で、Space-Efficient な手法として提案されている approximate membership query を提供するデータ構造です (Bloom filter と同じ機能を提供しているが、厳密には Bloom fitler ではない)。</p>
<p>要素のハッシュ値を算出するところまでは Bloom filter と同じですが、そのハッシュ値を</p>
<ol>
<li>昇順ソートして</li>
<li>そのソート順における、左に隣接する値との gap を求めて</li>
<li>その gap を Golomb 符号で符号化</li>
</ol>
<p>することで、Bloom filter よりもコンパクトな表現を実現しています (ハッシュ値は一様分布しているものとして、そのハッシュ値の gap をとると幾何分布になり、幾何分布に従う数値を符号化するには Golomb 符号が都合いい、ということ)。</p>
<p>この方式でのルックアップ操作は、あるハッシュ値が Golomb-Compressed Sequence に含まれるか否かだけを探索により判定すればいいので、Bloom filter のようなビット列への複数回のランダムアクセスは生じません。
とは言えど、この圧縮表現のままでは効率的なランダムアクセスが実現できないため、</p>
<ol>
<li>ハッシュ空間を大きさ $I$ の空間に分割して</li>
<li>その分割された空間ごとに Golomb 符号化をし</li>
<li>ルックアップの際はハッシュ値から探索先のハッシュ空間を絞り込んでから逐次 Golomnb 符号を復号する</li>
</ol>
<p>ことで、復号にかかる時間効率を高められるようにしています。 $I$ を大きくすれば大きくするほど、空間効率がよくなるが探索効率は悪くなり、 $I$ を小さくすると空間効率は悪くなるが探索効率が上がる、というトレードオフの関係になっています。</p>
<h2 id="cuckoo-filter">Cuckoo filter</h2>
<p><a href="https://www.cs.cmu.edu/~dga/papers/cuckoo-conext2014.pdf">Cuckoo Filter: Practically Better Than Bloom</a> では、Cuckoo hashing を利用して、approximate membership query を提供するデータ構造を提案しています。</p>
<p>Cuckoo hashing の詳細説明は <a href="http://www.slideshare.net/kumagi/hopscotch-hashing/17">kumagi 先生の資料</a> に譲るとして、Cuckoo filter では要素から $f$ ビットのフィンガープリント (ハッシュ値の一つだと考えれば OK) と、2 つのハッシュ値を算出し、 Cuckoo hashing に利用します。より具体的には、2 つのハッシュ値を配列で表現されるバケット (複数のフィンガープリントを記録できる入れ物) のインデックス決定に利用し、フィンガープリントをそのバケットに追記する、という使い方になります。</p>
<p>この Cuckoo filter で使われる 2 つのハッシュ関数はちょっとだけ特殊で、$h_1(x) = hash(x), h_2(x) = h_1(x) \oplus hash(x's fingerprint)$ となっています。つまりは、フィンガープリントと一方のハッシュ値がわかっていれば $h_1(x)$ と $h_2(x)$ を算出することができるわけです。</p>
<p>パラメータとしてはフィンガープリントを表現するビット数や、バケットの大きさ (異なるフィンガープリントを格納できる個数)、バケット数と、ちょっと多めなのが気になりますが空間効率も参照性能も Bloom filter より良さそうです。</p>
<p>さて今回はこのぐらいにして、Golomb-Cmpressed Sequence あたりを実装してみようかな…</p>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-24680763403462032122015-10-01T01:32:00.000+09:002015-10-01T01:32:11.641+09:00SCIP を使って最適化問題を解いてみる<p>最適化問題、とりわけ線形計画問題が気になり始めるお年頃になってきたので、 <a href="http://scip.zib.de/">SCIP</a> というソルバーを使ってみましたよ、というメモ。</p>
<h2 id="">インストール</h2>
<p>まずは手元にある MBP に、 <a href="http://qiita.com/mpkato/items/7ed8a2c60785bf3adfd8">SCIPをMacにインストール - Qiita</a> の手順を参考にインストールを試してみる。ところが、</p>
<pre><code>src/rational.h:32:10: fatal error: 'gmp.h' file not found
</code></pre>
<p>などの gmp.h がない旨のコンパイルエラーが発生してしまう状況に遭遇してインストールできない。
なので、ひとまず <code>make GMP=false</code> としてお茶を濁すことしてみる (GMP を要求するのは ZIMPL らしく、かつその機能を利用することは今のところはないので)。</p>
<h2 id="_1">インタラクティブシェル</h2>
<p>ビルド後の scip のバイナリ <code>scip-X.X.X/bin/scip</code> を立ち上げるとインタラクティブシェルが立ち上がる。</p>
<h3 id="read">read: 問題を記述したファイルを読み込む</h3>
<p>ひとまず適当な問題をソルバーで解かせてみようと思い、<a href="http://www.fujilab.dnj.ynu.ac.jp/lecture/system2.pdf">講義テキストらしきもの (PDF)</a> を参考に、最適化問題を記述した LP ファイル (sample.lp) を作ってみる。</p>
<pre><code>maximize
400 x1 + 300 x2
subject to
60 x1 + 40 x2 <= 3800
20 x1 + 30 x2 <= 2100
20 x1 + 10 x2 <= 1200
end
</code></pre>
<p>このファイルを scip のインタラクティブシェル上で読み込んでみる。読み込みには <code>read</code> コマンドを利用する。</p>
<pre><code>SCIP> read /path/to/sample.lp
read problem </path/to/sample.lp>
============
original problem has 2 variables (0 bin, 0 int, 0 impl, 2 cont) and 3 constraints
</code></pre>
<p>2 つの変数、3 つの制約条件、と出力がでて、ちゃんと読み込めたようだ。</p>
<h3 id="optimize">optimize: 最適化問題を解く</h3>
<p>読み込んだ問題を実際に解いてみよう。問題を解くには <code>optimize</code> コマンドを利用する。</p>
<pre><code>SCIP> optimize
feasible solution found by trivial heuristic after 0.0 seconds, objective value 0.000000e+00
presolving:
(round 1, fast) 0 del vars, 0 del conss, 0 add conss, 4 chg bounds, 0 chg sides, 0 chg coeffs, 0 upgd conss, 0 impls, 0 clqs
presolving (2 rounds: 2 fast, 1 medium, 1 exhaustive):
0 deleted vars, 0 deleted constraints, 0 added constraints, 4 tightened bounds, 0 added holes, 0 changed sides, 0 changed coefficients
0 implications, 0 cliques
presolved problem has 2 variables (0 bin, 0 int, 0 impl, 2 cont) and 3 constraints
3 constraints of type <linear>
Presolving Time: 0.00
transformed 1/1 original solutions to the transformed problem space
time | node | left |LP iter|LP it/n| mem |mdpt |frac |vars |cons |cols |rows |cuts |confs|strbr| dualbound | primalbound | gap
* 0.0s| 1 | 0 | 3 | - | 194k| 0 | - | 2 | 3 | 2 | 3 | 0 | 0 | 0 | 2.700000e+04 | 2.700000e+04 | 0.00%
0.0s| 1 | 0 | 3 | - | 194k| 0 | - | 2 | 3 | 2 | 3 | 0 | 0 | 0 | 2.700000e+04 | 2.700000e+04 | 0.00%
SCIP Status : problem is solved [optimal solution found]
Solving Time (sec) : 0.00
Solving Nodes : 1
Primal Bound : +2.70000000000000e+04 (2 solutions)
Dual Bound : +2.70000000000000e+04
Gap : 0.00 %
</code></pre>
<p>表示内容が豊富でちょっと面食らってしまうけど、 <code>problem is solved [optimal solution found]</code> がポイント。最適解が求まったぽい。</p>
<h3 id="display">display: 解を表示する</h3>
<p><code>optimize</code> コマンドで解が求まったら、 <code>display</code> のコマンドでその解を表示してみよう。</p>
<pre><code>SCIP> display solution
objective value: 27000
x1 30 (obj:400)
x2 50 (obj:300)
</code></pre>
<p>ちゃんと最適解が求まっているのがわかる。</p>
<h3 id="write">write: 解をファイルに書き出す</h3>
<p><code>optimize</code> コマンドで求まった解を他の用途で使いたい、ということは結構よくあるはず。ファイルに書き出すことができればスクリプト言語でパースして利用する事もできるだろう。</p>
<p>それでは <code>write</code> コマンドでファイルに書き出してみよう。</p>
<pre><code>SCIP> write solution result.sol
written solution information to file <result.sol>
</code></pre>
<p>出力された result.sol を less などで覗いてみれば、<code>display solution</code> でコンソールに表示した内容と同等のものが出力されているのがわかるはず。</p>
<h2 id="_2">問題の記述方法</h2>
<p>SCIP のひととおりの使い方がだいたい分かってきたところで、他の問題も SCIP で解けるように、問題の記述方法を勉強してみよう。</p>
<h3 id="_3">ナップサック問題</h3>
<p>まずは最適解問題で定番のナップサック問題。具体的な問題は Wikipedia のページ <a href="https://ja.wikipedia.org/wiki/%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%95%8F%E9%A1%8C">ナップサック問題</a> の図より拝借。</p>
<pre><code>maximize
4 d4w12 + 2 d2w2 + 2 d2w1 + 1 d1w1 + 10 d10w4
subject to
weight: 12 d4w12 + 2 d2w2 + 1 d2w1 + 1 d1w1 + 4 d10w4 <= 15
binary
d4w12 d2w2 d2w1 d1w1 d10w4
</code></pre>
<p>ナップサック問題に入れる・入れないをフラグ的に binary で表現し、目的関数に価値の合計を、制約条件に重さの合計に対する上限値を設定すれば OK だろう。</p>
<h3 id="n">N クイーン問題</h3>
<p>ソルバーで解いて嬉しいかどうか別として、 <a href="https://ja.wikipedia.org/wiki/%E3%82%A8%E3%82%A4%E3%83%88%E3%83%BB%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3">N クイーン問題</a> をソルバーで解かせてみよう。</p>
<p>問題の記述が大変だったので、盤面の大きさは 4x4 にしてみる。</p>
<pre><code>maximize
a1 + a2 + a3 + a4 + b1 + b2 + b3 + b4 + c1 + c2 + c3 + c4 + d1 + d2 + d3 + d4
subject to
rowA: a1 + a2 + a3 + a4 = 1
rowB: b1 + b2 + b3 + b4 = 1
rowC: c1 + c2 + c3 + c4 = 1
rowD: d1 + d2 + d3 + d4 = 1
col1: a1 + b1 + c1 + d1 = 1
col2: a2 + b2 + c2 + d2 = 1
col3: a3 + b3 + c3 + d3 = 1
col4: a4 + b4 + c4 + d4 = 1
diagC1D2: c1 + d2 <= 1
diagB1D3: b1 + c2 + d3 <= 1
diagA1D4: a1 + b2 + c3 + d4 <= 1
diagA2C4: a2 + b3 + c4 <= 1
diagA3B4: a3 + b4 <= 1
diagC4D3: c4 + d3 <= 1
diagB4D2: b4 + c3 + d2 <= 1
diagA4D1: a4 + b3 + c2 + d1 <= 1
diagA3C1: a3 + b2 + c1 <= 1
diagA2B1: a2 + c1 <= 1
binary
a1 a2 a3 a4 b1 b2 b3 b4 c1 c2 c3 c4 d1 d2 d3 d4
</code></pre>
<p>すごく冗長な表現になってしまっているように思えるが、ちゃんと解くことができる。いいね!</p>
<h2 id="_4">参考文献</h2>
<p><a href="http://www.tuat.ac.jp/~miya/ipmemo.html">宮代 隆平 の web ページ(整数計画法メモ)</a></p>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-79691524428676567472015-07-25T16:22:00.000+09:002015-07-25T16:22:45.874+09:00クリック率やコンバージョン率の信頼区間を求めたい! (3) シミュレーション編<p>過去二回にわたって、</p>
<ul>
<li><a href="http://blog.k11i.biz/2015/01/1.html">クリック率やコンバージョン率の信頼区間を求めたい! (1)</a></li>
<li><a href="http://blog.k11i.biz/2015/01/2.html">クリック率やコンバージョン率の信頼区間を求めたい! (2) 実装編</a></li>
</ul>
<p>と綴ってきた、CTR, CVR の区間推定をするお話の総集編的なエントリです。</p>
<p>今回は <a href="http://commons.apache.org/proper/commons-math/">commmons-math3</a> を使って、各区間推定方法における実際のカバレッジを測定するシミュレータを作ってみました。あわせて測定結果より、それぞれの方法の特性を確認していきます。</p>
<h2>まずは復習から</h2>
<p>「二項比率の区間推定 <a href="http://en.wikipedia.org/wiki/Binomial_proportion_confidence_interval">(英語 Wikipedia)</a>」は、統計的に独立・有限回で、各々の試行において「成功」か「失敗」のどちらかの結果が得られる問題の、「成功が発生する確率 $p$ (二項比率)」の信頼区間を求めることに相当します。</p>
<p>これをクリック率 (CTR) の区間推定に置き換えると、「成功」はすなわちクリックされたこと、「失敗」はクリックされなかったことに相当します。そして「成功が発生する確率」というのは、クリック回数 / インプレッション回数、つまりは CTR となります。</p>
<p>この「二項比率の区間推定」をする方法はいくつかあって、先の英語 Wikipedia にも記載されている方法として</p>
<ul>
<li>Wald confidence interval</li>
<li>Clopper-Pearson (or 'Exact') confidence interval</li>
<li>Wilson (or 'Score') confidence interval</li>
<li>Adjusted Wald confidence interval / Agresti-Coull confidence interval</li>
</ul>
<p>などがあります。ただそれぞれ、論文で指摘されているとおりの特徴(というよりも欠点)があって、サンプルサイズの大きさや $p$ の値次第で実際のカバレッジが想定外の値になってしまう、という状況が起こりえます。</p>
<p>そのため、自身がとりあつかっている CTR や CVR のインプレッション数、クリック数、コンバージョン数に応じて、これらのいずれかをうまく使い分ける必要がある… と考えたのが、今回の一連のエントリを書き始めたきっかけでした。</p>
<h2>シミュレーションしてみる</h2>
<p>それではそろそろシミュレーションをしてみて、各区間推定方法の特性を実際に確認してみましょう。</p>
<h3>シミュレーション内容</h3>
<p>シミュレーションの内容は次のとおりです。</p>
<ul>
<li>次のサンプルサイズおよび真の二項比率 $p$ のすべての組み合わせごとに、1,000,000 回 の試行をします<ul>
<li><strong>p</strong> : 10% から 1% までの 1 ポイント刻みの値、および 1% から 0.1% までの 0.1 ポイント刻みの値</li>
<li><strong>サンプルサイズ</strong> : 100 から 1,000 までの 100 刻みの値、および 1,000 から 10,000 までの 1,000 刻みの値</li>
</ul>
</li>
<li>信頼度を 95% としたときのカバレッジを測定します<ul>
<li>このカバレッジが大きすぎず小さすぎず、 95% の値により近いことが望ましい結果となります</li>
</ul>
</li>
<li>1,000,000 回のサンプリングのうち、求められた信頼区間に $p$ の値が含まれている割合がカバレッジとなります</li>
<li>精度面の検証以外にも、処理時間の測定をして評価をします</li>
</ul>
<h3>プログラム</h3>
<p>シミュレーションのプログラムは次のリンク先になります。</p>
<p><a href="https://github.com/komiya-atsushi/binomial-proportion-confidence-interval">komiya-atsushi/binomial-proportion-confidence-interval</a></p>
<h2>結果と評価</h2>
<p>測定結果は Google スプレッドシート <a href="https://docs.google.com/spreadsheets/d/1woNN-7vm3_Qys_mZYHEQgKiF7PX3CD5GDss8rbBpmmg/edit?usp=sharing">Comparison of Binomial proportion confidence interval</a> にまとめました。</p>
<p>なお、以下の精度面の評価では Wald confidence interval の結果を省いています (Wald は評価するまでもなく突出して精度が悪く、グラフに含めると見辛くなってしまうため)。</p>
<h3>サンプルサイズを変化させたとき</h3>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJP_B4ivLx_sp30ztdZttnQ7RVSpk0VuHxfIcVUwDe41NiF54YKT0pB_Cv90Gpa7iwjl5qbkBDyEh6Wv7ft8uXO1fqtIJS3LsQyDgkrrGRPZ36gyZzKL_VtcBZXROQnf5kSeuh6mH-mvgv/s1600/p001.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJP_B4ivLx_sp30ztdZttnQ7RVSpk0VuHxfIcVUwDe41NiF54YKT0pB_Cv90Gpa7iwjl5qbkBDyEh6Wv7ft8uXO1fqtIJS3LsQyDgkrrGRPZ36gyZzKL_VtcBZXROQnf5kSeuh6mH-mvgv/s400/p001.png" /></a></div>
<p>まずはサンプルサイズの大きさを変化させたときの結果に着目してみます。</p>
<ul>
<li>サンプルサイズを大きくすれば、いずれも 95% の信頼度に近いカバレッジが得られる<ul>
<li>カバレッジのぶれもサンプルサイズが増えるごとに落ち着く</li>
</ul>
</li>
<li>全体的なカバレッジの傾向は、Clopper-Pearson > Agresti-Coull > Wilson となる<ul>
<li>Clopper-Pearson のカバレッジが一番広く、95% を下回ることはまれ</li>
<li>Wilson は常に一番狭いカバレッジとなる</li>
<li>Agresti-Coull は、サンプルサイズが小さいときは Clopper-Pearson のように広いカバレッジをとり、サンプルサイズが増えるに従って Wilson のカバレッジに近づく</li>
</ul>
</li>
</ul>
<h3>p を変化させたとき</h3>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhD49czxWEdNzHbCPMmRKxtkrsycoIvpYu1wrfIoE1e4MmjH5nRBy-3pHhNsort5T0n4RSE6I__fqAWSXeSvfWL2ddR6R1JDYqKuUS9X-tW8DOnpnmwSy7_Wg4PIT3j7btXtXHpbn3P43YF/s1600/N1000.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhD49czxWEdNzHbCPMmRKxtkrsycoIvpYu1wrfIoE1e4MmjH5nRBy-3pHhNsort5T0n4RSE6I__fqAWSXeSvfWL2ddR6R1JDYqKuUS9X-tW8DOnpnmwSy7_Wg4PIT3j7btXtXHpbn3P43YF/s400/N1000.png" /></a></div>
<p>次に、二項比率 $p$ を変化させたときの結果を見てみます。</p>
<ul>
<li>サンプルサイズがそこそこある状態であれば、 $p$ が大きくなるにつれていずれも 95% の信頼度に近づいていく<ul>
<li>こちらも、カバレッジのぶれは $p$ が大きくなることで落ち着く傾向となる</li>
</ul>
</li>
<li>全体的なカバレッジの傾向は、Clopper-Pearson > Agresti-Coull > Wilson となる<ul>
<li>これはサンプルサイズを変化させたときと同じ傾向である</li>
</ul>
</li>
<li>サンプルサイズあまりない状態で $p$ が小さい場合、Wilson は極端に狭いカバレッジ (90% 前後) となることがある<ul>
<li><a href="https://docs.google.com/spreadsheets/d/1woNN-7vm3_Qys_mZYHEQgKiF7PX3CD5GDss8rbBpmmg/edit#gid=1644893567">wilson score</a> のシートを参照</li>
</ul>
</li>
</ul>
<h3>計算時間</h3>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQiufaeq5-HkG9EShNUoBS4J3I1_osIqkipV-e4j8G5344Etm6mZkADOAnwNJc9JhJPNKPT4eh0bZznQ5OUz0RPfOa9zlYe22MfQOIPI11yTbb3dKM52eclpvnB6BTR-HUT4FR7oBaODYK/s1600/ComputationTime.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQiufaeq5-HkG9EShNUoBS4J3I1_osIqkipV-e4j8G5344Etm6mZkADOAnwNJc9JhJPNKPT4eh0bZznQ5OUz0RPfOa9zlYe22MfQOIPI11yTbb3dKM52eclpvnB6BTR-HUT4FR7oBaODYK/s400/ComputationTime.png" /></a></div>
<p>最後に、今回のシミュレーションをするのに要した時間を、計算方法ごとにグラフにしてみます。</p>
<ul>
<li>Wilson と Agresti-Coull はどちらも大差なし</li>
<li>Clopper-Pearson は他に比べて遅くなりがち<ul>
<li>他より複雑な計算が必要なため</li>
<li>サンプルサイズに比例して実行時間がかかってしまうのは、利用したライブラリ (commons-math3) の実装に起因している?</li>
</ul>
</li>
<li>Normal Approximation (Wald) は、区間の幅が 0 になってしまうようなケースの計算時間が含まれていないため、Wilson, Agresti-Coull よりも計算時間が不当に短くなっている</li>
</ul>
<h2>まとめ</h2>
<h3>計算方法それぞれの特徴</h3>
<p>論文を読んだり実際にシミュレーションをしてみて、それぞれの計算方法の特性が明らかになったので表にまとめてみます。</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>実装が容易</th>
<th>区間の幅</th>
<th>$p$ の偏り</th>
<th>区間の上限/下限</th>
</tr>
</thead>
<tbody>
<tr>
<td>Wald</td>
<td>◎</td>
<td>× (*1)</td>
<td>× (*3)</td>
<td>× (*4)</td>
</tr>
<tr>
<td>Clopper-Pearson / exact</td>
<td>×</td>
<td>△ (*2)</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<td>Winson / score</td>
<td>×</td>
<td>-</td>
<td>× (*3)</td>
<td>-</td>
</tr>
<tr>
<td>Agresti-Coull / Adjusted Wald</td>
<td>◯</td>
<td>-</td>
<td>-</td>
<td>× (*4)</td>
</tr>
</tbody>
</table>
<ul>
<li>*1 : 狭くなりがち</li>
<li>*2 : 広くなりがち</li>
<li>*3 : 狭くなる</li>
<li>*4 : 下限が 0 を下回る / 上限が 1 を超える</li>
</ul>
<h3>結論</h3>
<p>元々の目的であるクリック率やコンバージョン率の区間推定に立ち返って、今回の調査・シミュレーション結果を見てみると、</p>
<ul>
<li>Wald は欠点が多すぎてクリック率などの区間推定には適していない</li>
<li>クリック率のように、$p$ が極端に小さい値になりうることを考えると、Winson を利用するのは注意が必要<ul>
<li>サンプルサイズが十分でない場合は使わない方がいい</li>
</ul>
</li>
<li>適切な幅の区間推定をする上では、Clopper-Pearson もしくは Agresti-Coull がよさそう<ul>
<li>Clopper-Pearson は、意図して信頼区間を保守的に (慎重に) 広くとりたい場合に向いている</li>
<li>Agresti-Coull は下限が 0 より小さくなったり上限が 1 より大きくなったりする点に注意すれば (計算は楽だし) 使い勝手がいい</li>
</ul>
</li>
</ul>
<p>と言えることでしょう。</p>
Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-70004814287223428082015-01-24T18:45:00.001+09:002015-01-24T23:55:32.471+09:00第 42 回 #TokyoWebmining 深層学習・表現学習 徹底活用 祭りに行ってきたよ<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmJCP_eTpxiRfgnwawtZmx3SD0tci7mQyNqHm6yhw3Qg-CC0nnbCvipmdDp59gyRjkqkByR1fl3IzaInAEdVLVLOmFRX9sX4t5x8SeoggHWZVSUVNCvLD830ZJLmaMCHxf35WLV03ggCr1/s1600/DSC_1835.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmJCP_eTpxiRfgnwawtZmx3SD0tci7mQyNqHm6yhw3Qg-CC0nnbCvipmdDp59gyRjkqkByR1fl3IzaInAEdVLVLOmFRX9sX4t5x8SeoggHWZVSUVNCvLD830ZJLmaMCHxf35WLV03ggCr1/s400/DSC_1835.jpg" /></a></div>
<p><a href="http://www.eventbrite.com/e/42-web-tokyowebmining-42nd--tickets-15325824955">今回の TokyoWebmining</a> はここ最近、特に注目を集めている Deep Learning と word2vec がトピックということで、参加者募集も数分で枠が埋まってしまうほどの大人気っぷりでした。</p>
<p>せっかくなので、(参加したくても参加できなかった方々も多いことかと思いますし)たまにはまとめエントリを、会場内での質問やディスカッションを中心に書いてみようかと思います。</p>
<p>(聞き間違い・勘違いなどがあるかと思いますので、気づかれたかたはツッコミ願います)</p>
<h2 id="-by-unnonouno-">深層学習時代の自然言語処理 by @unnonouno さん</h2>
<iframe src="//www.slideshare.net/slideshow/embed_code/43844132" width="510" height="420" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/unnonouno/ss-43844132" title="深層学習時代の自然言語処理" target="_blank">深層学習時代の自然言語処理</a> </strong> from <strong><a href="//www.slideshare.net/unnonouno" target="_blank">Yuya Unno</a></strong> </div>
<h3 id="recurrent-neural-network">Recurrent Neural Network</h3>
<ul>
<li><a href="http://www.slideshare.net/unnonouno/ss-43844132/11">p.11 Recurrent Neural Network</a><ul>
<li>1 個の単語に対して、1 個の dense ベクトルがある<ul>
<li>次元数は 100〜1,000 ぐらい</li>
<li>RNN への入力ベクトルはこれになる</li>
<li>この単語ベクトルは各層で共有される</li>
<li>正則化して sparse にしてみたけど、別によくはならなかった</li>
</ul>
</li>
</ul>
</li>
<li><a href="http://www.slideshare.net/unnonouno/ss-43844132/14">p.14</a><ul>
<li>時間方向に層を重ねることに相当する<ul>
<li>層が文長に相当する、ここが他の NN と異なる</li>
</ul>
</li>
</ul>
</li>
<li><a href="http://www.slideshare.net/unnonouno/ss-43844132/16">p.16</a><ul>
<li>RNN の学習は、Back Propagation (Through Time) で学習する<ul>
<li>時間をさかのぼって学習しているように見える</li>
<li>図的には、赤が Back propagation になる</li>
</ul>
</li>
</ul>
</li>
<li><a href="http://www.slideshare.net/unnonouno/ss-43844132/17">p.17</a><ul>
<li>誤差が最初の方に伝搬しないという問題がある</li>
<li>これを解決したのが Long Short-Term Memory という技術</li>
</ul>
</li>
<li><a href="http://www.slideshare.net/unnonouno/ss-43844132/18">p.18 Long Short-Term Memory</a><ul>
<li>隠れ層のベクトル間でされる演算</li>
<li>影響の与えるタイミングと与えないタイミングがあるはず、という考え</li>
<li>これによりパラメータが増えることになるが、これは学習対象となっている</li>
<li>昨年後半からこれが流行ってる</li>
<li>機械翻訳や Wikipedia 文章ぽいものの再生成、構文解析などに適用されてる by Google</li>
<li>1 個の文がベクトルになって、そこから文が湧き出てくる</li>
</ul>
</li>
</ul>
<h3 id="recursive-neural-network">Recursive Neural Network</h3>
<p><em>「両方とも RNN って略すのやめろ」</em></p>
<ul>
<li><a href="http://www.slideshare.net/unnonouno/ss-43844132/22">p.22</a><ul>
<li>こちらは木構造を学習してつくる</li>
<li>文章の構文解析だけでなく、画像の構造推定に使える<ul>
<li>木構造を作る</li>
<li>二つの要素をくっつける順番を学習する</li>
</ul>
</li>
</ul>
</li>
<li><a href="http://www.slideshare.net/unnonouno/ss-43844132/23">p.23 評判分析にも使われてる</a><ul>
<li>こちらは木構造が事前に与えらて、ポジネガを判定している</li>
<li>前は feature engineering で頑張って精度を高めていたけど、この RNN を使ったら良くなった</li>
<li>文章全体ではなく、一つの文に対して適用される</li>
</ul>
</li>
</ul>
<h3 id="-">本題:構文解析</h3>
<ul>
<li><a href="http://www.slideshare.net/unnonouno/ss-43844132/32">p.32 Shift-Reduce 法</a><ul>
<li>ガーデンパス文に弱い</li>
<li>これが Recurrent Neural Network に近いんじゃないか?</li>
</ul>
</li>
<li><a href="http://www.slideshare.net/unnonouno/ss-43844132/44">p.41</a><ul>
<li>品詞情報だけだと、構文解析は全然できない</li>
</ul>
</li>
<li><a href="http://www.slideshare.net/unnonouno/ss-43844132/46">p.46</a><ul>
<li>構文解析はまだルール作りはなんとかなるが、意味解析は膨大過ぎてルール作りは辛い</li>
</ul>
</li>
</ul>
<h3 id="-">まとめ</h3>
<ul>
<li><a href="http://www.slideshare.net/unnonouno/ss-43844132/48">p.48</a>
<ul>
<li>Recurrent が流行っている</li>
<li>音声認識、特に G とか MS とかの大手では DNN が使われているんじゃなかろうか?
</li>
</ul>
</li>
</ul>
<h3 id="-">ディスカッション</h3>
<ul>
<li>単語分割、構文解析は精度が出ているが、意味解析とか<a href="http://ja.wikipedia.org/wiki/%E8%AB%87%E8%A9%B1%E5%88%86%E6%9E%90">談話解析</a>はまだまだなので、そのあたりで DNN 使って精度出せるといいね
<ul>
<li>そもそもの問題設定があいまいだったりするけど…</li>
</ul>
</li>
<li>テトリスブロックを回転させたもの同士が同じかどうかを判定するタスクで、DNN はうまくいかないというツッコミを入れた論文があった</li>
<li>「言語学者をクビにすればするほど精度が上がる」</li>
</ul>
<h2 id="-by-atelierhide-">ディープラーニング徹底活用 画像認識編 by @atelierhide さん</h2>
<iframe src="//www.slideshare.net/slideshow/embed_code/43845711" width="510" height="420" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/atelierhide/tokyo-webmining42-slideshare" title="ディープラーニング徹底活用 -画像認識編-" target="_blank">ディープラーニング徹底活用 -画像認識編-</a> </strong> from <strong><a href="//www.slideshare.net/atelierhide" target="_blank">Hideki Tanaka</a></strong> </div>
<h3 id="-">この発表で一番言いたいこと</h3>
<ul>
<li>「<strong>学習済みモデルを徹底活用しよう!</strong>」<ul>
<li>Convolutional Neural Networks (CNNs) のモデル</li>
</ul>
</li>
<li>世界一のモデルを使うことができる</li>
<li>1000 次元のベクトルが出力として得られる</li>
</ul>
<h3 id="deep-learning-frameworks">Deep learning frameworks</h3>
<ul>
<li>選択観点
<ul>
<li>学習済みモデルが提供されているフレームワークを選ぶのがいい</li>
<li>Caffe よさそう</li>
<li>Caffe と DeCAF はほとんど違いはない</li>
<li>OverFeat は使い勝手がよくない</li>
</ul>
</li>
<li>Caffe
<ul>
<li>画像のリサイズなどは、まあまあフレームワークがよろしくやってくれる<ul>
<li>横長画像は正方形に変換されてしまうので、その点は注意しないといけない</li>
</ul>
</li>
<li>Detection と Recognition は別<ul>
<li>DNN が効くのは Recognition のほう</li>
</ul>
</li>
<li>モデルの学習をする場合は、背景などが写り込んでいないものを選ぶべき<ul>
<li>分類はその限りではない</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="-">学習済みモデルの活用のアイデア</h3>
<ol>
<li>特徴抽出器として使う<ul>
<li>CNNs の最後から 2 番目に得られる部分のベクトルを使う<ul>
<li>pre-training 相当になっている</li>
</ul>
</li>
<li>これを特徴量として、SVM などで分類する</li>
</ul>
</li>
<li>ファインチューニングをする<ul>
<li>出力層・分類数を入力画像にあわせて変更し、学習済みモデルのパラメータを最適化する</li>
</ul>
</li>
<li>物体検出に使う<ul>
<li><a href="http://www.slideshare.net/hijiki_s/pydata-nyc-by-akira-shibata">PyData 2014 NYC での発表資料</a></li>
<li>Selective Search によって領域を検出する<ul>
<li>Detection 用に研究された 200 分類のモデルを利用している</li>
</ul>
</li>
</ul>
</li>
</ol>
<h3 id="-">ディスカッション</h3>
<ul>
<li>みんなが Caffe を使い出していて、いろんな適用例が発表されはじめている</li>
<li>Caffe に Recurrent / LSTM が入るらしいということで、その手の界隈がざわついている</li>
</ul>
<h2 id="word2vec-by-piroyoung-">word2vec のご紹介 by @piroyoung さん</h2>
<iframe src="//www.slideshare.net/slideshow/embed_code/43848203" width="510" height="420" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/piroyoung/word2vec2" title="Word2vec2" target="_blank">Word2vec2</a> </strong> from <strong><a href="//www.slideshare.net/piroyoung" target="_blank">Hiroki Mizukami</a></strong> </div>
<h3 id="word2vec">word2vec</h3>
<ul>
<li><a href="http://www.slideshare.net/piroyoung/word2vec2/31">p.31 単語の低次元ベクトル表現</a><ul>
<li>ウィンドウの大きさを変化させるとどうなるのか?<ul>
<li>広くすると、経験則的に共起語ばかりになる</li>
</ul>
</li>
<li>海野さん<ul>
<li>短いと、構文的に似てるのが出てくる</li>
<li>長いと、意味的に似ているものが出てくる</li>
<li>ウィンドウの大きさ、5 単語ぐらい</li>
<li><a href="https://twitter.com/unnonouno/status/558911378891624448">実は、近い単語の方が重点的にサンプリングされる実装になっている</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="python-word2vec-">Python で word2vec を使う</h3>
<ul>
<li><a href="http://www.slideshare.net/piroyoung/word2vec2/31">p.36</a><ul>
<li>gensim を利用する<ul>
<li>Paragraph vector も実装されている</li>
</ul>
</li>
<li>コーパスをライブラリに喰わせるときに工夫が必要になる<ul>
<li>ナイーブにやるとメモリが足りなくなる</li>
<li>1 行読んでスペース区切り文を分割する… の処理をイテレーションさせる</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="-">素性のクラスタリング</h3>
<ul>
<li>word2vec で得られた単語のベクトルをクラスタリング<ul>
<li>わりとよくクラスタリングできてる</li>
</ul>
</li>
</ul>
<h3 id="qpr-">QPR の学習</h3>
<ul>
<li>QPR = Quick purchase report, 消費者購買動向データ</li>
<li><a href="http://www.slideshare.net/piroyoung/word2vec2/56">p.56</a><ul>
<li>ウィンドウサイズはものすごく大きなサイズにした<ul>
<li>バスケット内の商品は、順番には意味がない</li>
<li>ただし先ほどの海野さんのツッコミにあるとおり、順番が考慮された結果となってしまった</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="-">ディスカッション</h3>
<ul>
<li>文章中の助詞などを省いてみたら結果はどうなるの?<ul>
<li>単語同士の関係性を構成する要素になるので、動詞を入れても動詞が出てこなくなる</li>
<li>ものにもよるが、助詞を入れた方がいいであろう</li>
</ul>
</li>
<li>次元数 200 以外でやってみた?<ul>
<li>次元を上げて、悪くなることはなかった</li>
<li>計算時間はその分かかる</li>
</ul>
</li>
</ul>
<h2 id="-">今回の TokyoWebmining の所感</h2>
<ul>
<li>Deep learning、いまいちちゃんと理解できてなかったけど、雰囲気はだいぶつかめてきた</li>
<li>画像の取り扱いにおいては Deep learning を利用するのがもはや当たり前っぽい<ul>
<li>ImageNet の学習済みモデル、応用の幅が広いね!</li>
</ul>
</li>
<li>自然言語処理での Deep learning 活用、研究の進展が速いので、常にキャッチアップしていかないと置いて行かれそう…</li>
<li>とにかく Deep learning 熱の高まりっぷりがはんぱない!</li>
</ul>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-44741671996362614192015-01-19T01:03:00.000+09:002015-01-19T01:07:28.760+09:00クリック率やコンバージョン率の信頼区間を求めたい! (2) 実装編<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2tQCeHDNvXAm1pG3vtCfAOeyMdGSHS2ZeJIDrXrd7LDYwBaKBJaTepXHMHpIU_CU3hK_2zRYPYnY0q2jb_-Lz3Yq9VaDLTy6ygwk5kd-VbK320T2DuTRYF9f4y3NH8tIJ5JLMBXHQWCC0/s1600/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88+2015-01-19+1.04.32.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2tQCeHDNvXAm1pG3vtCfAOeyMdGSHS2ZeJIDrXrd7LDYwBaKBJaTepXHMHpIU_CU3hK_2zRYPYnY0q2jb_-Lz3Yq9VaDLTy6ygwk5kd-VbK320T2DuTRYF9f4y3NH8tIJ5JLMBXHQWCC0/s320/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88+2015-01-19+1.04.32.png" /></a></div>
<p><a href="http://blog.k11i.biz/2015/01/1.html">前回</a> は CTR (クリック率)、CVR (コンバージョン率) に対するいくつかの区間推定方法を、それぞれの特徴とともに列挙してみました。今回はそれらの区間推定方法による実際の信頼区間を、Java や Python, R を用いて求める方法をまとめてみます。</p>
<h2 id="java-">Java による区間推定</h2>
<p>Java で二項比率の区間推定をするには、<a href="http://commons.apache.org/proper/commons-math/">commons-math3</a> の <code>org.apache.commons.math3.stat.interval</code> パッケージ以下のクラスを使うのが手っ取り早いでしょう。</p>
<p>それぞれの区間推定方法に対応するクラスは以下のとおりです。</p>
<ul>
<li>Wald confidence interval<ul>
<li><code>NormalApproximationInterval</code> クラス</li>
</ul>
</li>
<li>Clopper-Pearson (or 'Exact') confidence interval<ul>
<li><code>ClopperPearsonInterval</code> クラス</li>
</ul>
</li>
<li>Wilson (or 'Score') confidence interval<ul>
<li><code>WilsonScoreInterval</code> クラス</li>
</ul>
</li>
<li>Adjusted Wald confidence interval / Agresti-Coull confidence interval<ul>
<li><code>AgrestiCoullInterval</code> クラス</li>
</ul>
</li>
</ul>
<p>これらのクラスに定義されている <code>#createInterval(int numberOfTrials, int numberOfSuccesses, double confidenceLevel)</code> を呼び出すことで信頼区間を求めることができます。たとえば <code>numberOfTrials</code> にインプレッション数を、 <code>numberOfSuccesses</code> にクリック数を、 <code>confidenceLevel</code> に 0.95 を設定して呼び出せば、95% 信頼水準での CTR の信頼区間が得られます。</p>
<p>サンプルコードは以下のとおり。</p>
<script src="https://gist.github.com/komiya-atsushi/133085ef955c24303eed.js"></script>
</p>
<p>注意点として、 <em>CTR や CVR の割合が 0% or 100% になるケース</em> (つまりは、クリックやコンバージョンがまったく発生していない or 毎回発生している状態) において <code>NormalApproximationInterval</code> クラス、もしくは <code>ClopperPearsonInterval</code> クラスの <code>#createInterval(int, int, double)</code> メソッドで信頼区間を求めようとすると、 <code>MathIllegalArgumentException</code> や <code>NotStrictlyPositiveException</code> などの例外が発生してしまいます。</p>
<p>Wald confidence interval ではそもそも区間の幅が 0 になるケースに相当するのでどうしようもないのですが、Clopper-Pearson confidence interval では区間の片側だけでも算出することはできるはずです。</p>
<p>なので、このようなケースでも無理矢理に算出することはできるわけで、例えば <code>ClopperPearsonInterval</code> クラスの実装を以下のように修正すれば例外を生じることなく信頼区間を求めることができます。</p>
<script src="https://gist.github.com/komiya-atsushi/141eeb2272367a5c72d0.js"></script>
</p>
<h2 id="python-">Python による区間推定</h2>
<p>Python の場合は、<a href="http://statsmodels.sourceforge.net/">statsmodels</a> を使います。</p>
<p>使い方は <a href="http://statsmodels.sourceforge.net/devel/generated/statsmodels.stats.proportion.proportion_confint.html">こちらのドキュメント</a> を参考に、<code>statsmodels.stats.proportion.proportion_confint(count, nobs, alpha, method)</code> を呼び出します。CTR を算出するのであれば <code>count</code> にクリック数を、<code>nobs</code> にインプレッション数を指定し、加えて信頼水準 $100(1-\alpha)\%$ の $\alpha$ を alpha に指定します。</p>
<p><code>method</code> には、区間推定方法を文字列で指定します。</p>
<ul>
<li>Wald confidence interval<ul>
<li><code>normal</code></li>
</ul>
</li>
<li>Clopper-Pearson (or 'Exact') confidence interval<ul>
<li><code>beta</code></li>
</ul>
</li>
<li>Wilson (or 'Score') confidence interval<ul>
<li><code>wilson</code></li>
</ul>
</li>
<li>Adjusted Wald confidence interval / Agresti-Coull confidence interval<ul>
<li><code>agresti_coull</code></li>
</ul>
</li>
</ul>
<p>サンプルコードは以下のとおり。</p>
<script src="https://gist.github.com/komiya-atsushi/1e362e00a4e6792a9611.js"></script>
</p>
<p>Java 同様に注意すべきこととして、CTR や CVR の割合が 0% or 100% の場合に、Clopper-Pearson confidence interval による区間推定の結果のうち、一方の片側が NaN になってしまうことが挙げられます。この場合、下側のエンドポイントが NaN であれば 0% と、上側のエンドポイントが NaN であれば 100% と読み替えればよいかと思います。</p>
<h2 id="r-">R による区間推定</h2>
<p>R では、<a href="http://cran.r-project.org/web/packages/binom/index.html">binom パッケージ</a> の <code>binom.confintt(x, n, conf.level, methods, ...)</code> を使って二項比率の区間推定をします。</p>
<p><code>methods</code> に <code>"all"</code> を指定すると、すべての区間推定方法の結果を一覧で出力してくれます。もしくは以下の文字列を指定することで、対応する区間推定方法での結果を出力してくれます。</p>
<ul>
<li>Wald confidence interval<ul>
<li><code>prop.test</code></li>
</ul>
</li>
<li>Clopper-Pearson (or 'Exact') confidence interval<ul>
<li><code>exact</code></li>
</ul>
</li>
<li>Wilson (or 'Score') confidence interval<ul>
<li><code>wilson</code></li>
</ul>
</li>
<li>Adjusted Wald confidence interval / Agresti-Coull confidence interval<ul>
<li><code>agresti-coull</code></li>
</ul>
</li>
</ul>
<h2 id="-">まとめ</h2>
<p>今回挙げた言語の各ライブラリでは、いずれもメソッド・関数を呼び出す程度の簡単なコードで二項比率の区間推定をすることができました。</p>
<p>ただ Java と Python については、CTR / CVR が 0% or 100% といったコーナーケースにおいてあまり好ましくない振る舞いをするため、多少の注意が必要となります。</p>
<p>また、各ライブラリで区間推定方法の呼称が異なることがあるため (Python / statsmodels の <code>beta</code> (Clopper-Pearson) や、R / binom の <code>prop.test</code> (Wald) など)、この点にも注意すべきかと思われます。</p>
<p>(次回こそはシミュレーション結果を…)</p>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-54463474868447940412015-01-07T01:08:00.000+09:002015-01-07T01:08:27.370+09:00クリック率やコンバージョン率の信頼区間を求めたい! (1)<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEht9OtDcpFn32cX-6C44XvmmiNrDozvP4juRfV-wEkDavq6tX0GRarM9JNTWjbIUJ0N-jY2OLUZUr9h3P9s-WBKWTyQXzFapI_n8a_fNiWs4-LBrQcw_jtojf50P1sejhET1yhFLrKp5hZh/s1600/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88+2015-01-07+1.03.45.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEht9OtDcpFn32cX-6C44XvmmiNrDozvP4juRfV-wEkDavq6tX0GRarM9JNTWjbIUJ0N-jY2OLUZUr9h3P9s-WBKWTyQXzFapI_n8a_fNiWs4-LBrQcw_jtojf50P1sejhET1yhFLrKp5hZh/s400/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88+2015-01-07+1.03.45.png" /></a></div>
<p>わけあってクリック率・コンバージョン率の信頼区間を算出したくなったのだけど、そのやり方を調べてみたら結構ややこしかったので、調べた結果をメモに残しておきます。</p>
<h2 id=".306f.3058.3081.306b">はじめに</h2>
<p>クリック率 (Click-through rate, CTR) やらコンバージョン率 (Conversion rate, CVR) を扱う仕事をしていると、少なくとも一度ぐらいはそれらの信頼区間を求めて (区間推定して) みたくなるものかと思います。</p>
<p>それというのも、例えば「100 回のインプレッションのうち、1 回のクリックが得られた」という標本 (サンプル) があったとして、これから CTR を点推定すると 1% になるものの、これは「サンプルサイズを増やしたときにも同様に 1% になるのか?」と言ったらそんなことは言えないわけで、ならば「どれくらいの信頼水準のときにどれくらいの範囲に真の CTR が存在しうるのか?」ということを知りたくなるわけです。この範囲を求めることがすなわち信頼区間を求める・区間推定をすることに相当します。</p>
<p>さて以上のようにクリック率・コンバージョン率の区間推定をしてみたいのですが、具体的にはどのようにすればいいのか? これは二項比率 (binomial proportion, この日本語訳で適切なのか、わからない…) の区間推定をすることに等しくなります。</p>
<p>二項比率の区間推定をする方法について、あいにく日本語で網羅的にまとまった解説が Web 上には存在しないのですが (だからこのブログエントリを書いているわけでして…) <a href="http://en.wikipedia.org/wiki/Binomial_proportion_confidence_interval">英語 Wikipedia のページ</a> がそこそこ充実しているので、わかる人はこちらのページを合わせて参照することをおすすめします。以降はこの Wikipedia ページと、同ページでリファレンスされているいくつかの論文 (後述) をもとに話を進めます。</p>
<h2 id=".4e8c.9805.6bd4.7387.306e.533a.9593.63a8.5b9a.3092.3059.308b.3044.304f.3064.304b.306e.65b9.6cd5">二項比率の区間推定をするいくつかの方法</h2>
<p>さて二項比率の区間推定をする方法として、今回は以下の 4 つを取り上げてみます (他にもベイズ的な確信区間などがあるわけですが、こちらは僕自身まだちゃんと理解しきれていないので割愛します)。</p>
<ul>
<li>Wald confidence interval</li>
<li>Clopper-Pearson (or 'Exact') confidence interval</li>
<li>Wilson (or 'Score') confidence interval</li>
<li>Adjusted Wald confidence interval / Agresti-Coull confidence interval</li>
</ul>
<p>以下、それぞれの区間推定方法について、数式とともにその特徴などを列挙していきます。</p>
<h3 id="Wald_confidence_interval">Wald confidence interval</h3>
<p>$$\hat{p} \pm z_{\alpha/2} \sqrt{ \hat{p} (1 - \hat{p}) / n}$$</p>
<p>($\alpha$ は信頼係数、$z_{\alpha/2}$ は標準正規分布の上側 $100(\alpha/2)$ % 点、$n$ はサンプルサイズ or 試行回数、$\hat{p}$ は二項比率の推定値)</p>
<p>二項分布 $B(n,p)$ は正規分布 $N(np, np(1-p))$ で近似できることから、二項比率の信頼区間も正規分布 $N(p,p(1-p)/n)$ で近似することができるため、上記の式で信頼区間を求めることができます。</p>
<ul>
<li>数式がわりと容易である
<ul><li>つまりは実装するのも比較的楽、ということ</li></ul></li>
<li>この手法により求まる信頼区間は、信頼水準から得られるそれよりも狭くなる (= 実際のカバレッジが低くなる) 傾向にある
<ul><li>サンプルサイズが小さい ($n < 100$ ぐらいの) 場合に、特にその傾向が表れる</li>
<li>また、 $p$ が 0.5 から 0 もしくは 1 に偏っているほどに顕著になる</li></ul></li>
<li>下側信頼限界が負数に、もしくは上側信頼限界が 1 を超える場合がある
<ul><li>それぞれ、 $p$ が 0 に近い場合、1 に近い場合にそのような状況になる</li></ul></li>
<li>成功回数 $x$ が、$x=0$ や $x=n$ の場合は、信頼区間を求めることができない (幅が 0 の区間になる)
<ul><li>クリック数が 0、もしくはインプレッション数に等しい場合が該当する</li></ul></li>
</ul>
<h3 id="Clopper.2dPearson_.28or_.27Exact.27.29_confidence_interval">Clopper-Pearson (or 'Exact') confidence interval</h3>
<p>
$$\left[1 + \frac{n-x+1}{x F_{2x,2(n-x+1),1-\alpha/2}} \right]^{-1} < p < \left[1 + \frac{n-x}{(x+1)F_{2(x+1),2(n-x),\alpha/2}} \right]^{-1}$$
</p>
<p>
($F_{n,m,z_{\alpha/2}}$ は、自由度 $n,m$ の F 分布における右側 $100\alpha$ 点)
</p>
<p>Wald confidence interval は正規分布で近似することで信頼区間を求めていましたが、サンプルサイズが小さい場合や $p$ が 0 もしくは 1 に偏っている場合は正規分布での近似が難しくなります。その代わりに、F 分布を用いることで正確な (?) 信頼区間を求めることができるそうです。</p>
<ul>
<li>サンプルサイズが小さくても、求まる信頼区間は Wald confidence interval のように狭くはなく、比較してカバレッジがよい
<ul><li>むしろ逆に、ちょっと広すぎる…</li></ul></li>
</ul>
<h3 id="Wilson_.28or_.27Score.27.29_confidence_interval">Wilson (or 'Score') confidence interval</h3>
<p>
$$\left( \hat{p} + \frac{z_{\alpha/2}^{2}}{2n} \pm z_{\alpha/2} \sqrt{[\hat{p}(1 - \hat{p}) + z_{\alpha/2}^{2} / 4n] / n} \right) / (1+z_{\alpha/2}^{2}/n)$$
</p>
<p>Wald confidence interval も Clopper-Pearson confidence interval も、それぞれ信頼区間の幅については狭かったり広かったりしてちょっと扱いづらいわけですが、Wilson confidence interval ではその点においてバランスがとれた幅の信頼区間が求まるようです。</p>
<ul>
<li>数式が複雑である
<ul><li>実装する際にエンバグしやすい <a href="http://kenpg.seesaa.net/article/377958867.html">※参考</a></li></ul></li>
<li>得られる信頼区間は狭すぎず、広すぎず</li>
<li>サンプルサイズによらず、$p$ が 0 もしくは 1 に偏っている場合に信頼区間が狭くなる傾向がある</li>
</ul>
<h3 id="Adjusted_Wald_confidence_interval_.2f_Agresti.2dCoull_confidence_interval">Adjusted Wald confidence interval / Agresti-Coull confidence interval</h3>
<p>$$\tilde{p} \pm z_{a/2} \sqrt{ \tilde{p} (1 - \tilde{p}) / \tilde{n}}$$</p>
<p>
$$(\tilde{n} = n + z_{\alpha/2}^{2},\ \tilde{p} = \frac{1}{\tilde{n}} \left(x + \frac{z_{\alpha/2}^{p2}}{2} \right) )$$
</p>
<p>Wald confidence interval はサンプルサイズが小さい場合に信頼区間の幅が狭く、結果としてカバレッジが低下する問題がありました。一方でこの Adjusted Wald confidence interval では、信頼係数 $\alpha$ から定まる $z_{\alpha/2}$ を用いて $n,x$ を調整し、 $\tilde{n}, \tilde{p}$ を算出しています。そして、この $\tilde{n}, \tilde{p}$ を用いて、Wald confidence interval の式を使い、信頼区間の近似値を算出しています。</p>
<p>特に $\alpha$ が 0.05 の場合は <em>adding two "successes" and two "failures"</em> と言っているとおり、$n$ に $2 + 2 = 4$ を加え、$x$ に $2$ を加える操作をすればだいたいいい感じになってくれます。</p>
<ul>
<li>数式はまだ容易な方ではある</li>
<li>サンプルサイズが小さい場合であっても、信頼区間が狭くなるようなことはない
<ul><li>Wilson confidence interval 同様にバランスのとれた幅の信頼区間が求まる</li></ul></li>
<li>下側信頼限界が負数に、もしくは上側信頼限界が 1 を超えうる問題は健在している</li>
</ul>
<h2 id=".30af.30ea.30c3.30af.7387.30fb.30b3.30f3.30d0.30fc.30b8.30e7.30f3.7387.306e.7279.6027">クリック率・コンバージョン率の特性</h2>
<p>ここまで区間推定方法について見てきましたが、これらを適用する先のクリック率やコンバージョン率の特性についても見ておきましょう。</p>
<ul>
<li>クリック率
<ul><li>サンプルサイズ (インプレッション数) は十分な大きさとなる
<ul><li>コンテキストを考慮した CTR を算出する場合はその限りではない</li></ul></li>
<li>値は常に小さな値になりがちで、0 に近くなる
<ul><li>1% に満たないことも十分にあり得る</li></ul></li></ul></li>
<li>コンバージョン率
<ul><li>サンプルサイズ (クリック数) が小さいことがある</li>
<li>値はまちまちで、一桁 % のときもあれば二桁 % になることもある</li></ul></li>
<li>共通して言えること
<ul><li>0% となるケースを考慮するべき</li></ul></li>
</ul>
<h2 id=".73fe.6642.70b9.3067.306e.63a8.6e2c">現時点での推測</h2>
<p>長々と書いてきましたが、上記をふまえると、クリック率やコンバージョン率の区間推定には Agresti & Coull の Adjusted Wald confidence interval を利用するのがよいのではないか、と考えられます。</p>
<p>ただ厳密には、クリック率・コンバージョン率の特性を想定したテストケースをいくつか用意して、実際のカバレッジを測定するシミュレーションをしてみないことには胸を張って「○○ がいい!」とは言えないかな… と思います (シミュレーションは次回のブログエントリに書く予定)。</p>
<h2 id=".53c2.8003.6587.732e">参考文献</h2>
<p>本ブログエントリは、主に以下 2 つの論文で述べられている内容をまとめたものとなっています。より詳しく知りたい方はこれらの論文を読まれることをおすすめします。</p>
<ul>
<li>Agresti, Alan; Coull, Brent A. (1998). "Approximate is better than 'exact' for interval estimation of binomial proportions".</li>
<li>Sauro J., Lewis J.R. (2005) "<a href="http://www.measuringu.com/papers/sauro-lewisHFES.pdf">Estimating completion rates from small samples using binomial confidence intervals: comparisons and recommendations</a>".</li>
</ul>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-28870761676613201952014-12-18T02:13:00.000+09:002014-12-18T11:32:42.204+09:00#JJUG ナイトセミナー「機械学習・自然言語処理特集!」で Java でカジュアルに機械学習する話をしてきました<h1 id=".306f.3058.3081.306b">はじめに</h1>
<p><a href="https://twitter.com/making">@making</a> さんからオファーをいただいて、12/17 (水) の JJUG ナイトセミナーで Java でカジュアルに機械学習するお話をしてきました。</p>
<script async class="speakerdeck-embed" data-id="840aed806807013207736654e16c42af" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script>
<p>Java というコミュニティ的に機械学習ガチ勢の方が圧倒的に少ないことが予想されたので、あんまり小難しい技術の話は含めず初学者向けの内容構成とし、機械学習をシステムに組み込んでいく上でこれは大事だよね… と個人的に思っているポイントを整理してスライドにしていったら、文字が多くなってしまった上に若干エモくて Java 的な話がほんのり程度になってしまったのが今回の反省点です。</p>
<p>なお講演時の動画が <a href="https://www.youtube.com/watch?v=B4PhhPfPTq0">YouTube にアップロードされています</a> ので、より詳しい話を知りたい場合はこちらをご覧ください。</p>
<h1 id="Java_.3068.6a5f.68b0.5b66.7fd2">Java と機械学習</h1>
<p>Java で動く機械学習ライブラリ・フレームワークはわりと数多あって、でも Java で機械学習を利用する際のワークフローをすべてカバーするのがいいかというとそんなことはない、と私は考えています。</p>
<p>特に、モデルを作る際の feature enginnering やそのモデルの評価など、試行錯誤的に・繰り返し手早く実行したい操作については、Java のソースコードをコンパイルして一連の処理を最初から実行する… みたいなことをするよりも、R や IPython (Notebook) などを使ってインタラクティブ・アドホックな操作ができたほうが断然効率がいいのではないでしょうか (僕は R も IPython もほとんど使ったことないので、この辺りは僕の主観が色濃く出ています…)。</p>
<p>じゃあ Java で機械学習する価値がないか、というとそんなことはなくて、何だかんだで Java のコードはそこそこ速く動いてくれるので、サービス的に速度・レイテンシ的な要求がある場合や、機械学習を組み込もうとしているシステムが Java で作られているならば機械学習の部分も Java で統一したい… など主にシステム化以降のところで Java の機械学習を活用するのがいいんじゃないかと思っています。</p>
<h1 id=".6307.6a19.5024.30fb.30e1.30c8.30ea.30af.30b9.3092.8a2d.5b9a.3057.3066.6a5f.68b0.5b66.7fd2.3092.6d3b.7528.3059.308b">指標値・メトリクスを設定して機械学習を活用する</h1>
<p>これは懇親会の席でとある方から伺ったお話にもあったのですが、ビジネス的 or 精度的なメトリクスを設定せず、ただ何となく流行っているから的な理由で機械学習を導入する… という話をちらほらと耳にします。</p>
<p>わりと身近なレコメンデーション一つをとっても、そのレコメンデーションによって全体の売上が何 % 向上したのか、みたいなビジネス上の指標値を設定することは可能だと思います。そのような指標値をせずに機械学習を導入してしまうと、それはチューニングはできない・機械学習アルゴリズムをおいそれと変更することもできない、ただただ辛みのつまったパンドラの箱に成り下がってしまうので、僕の身の回りでこういうことにならないように、気をつけないといけないよなー、と思った次第でした。</p>
<h1 id=".307e.3068.3081.30fb.611f.60f3">まとめ・感想</h1>
<p>JJUG 主催のセミナーにはいままで聴講者としてたまに顔を出していましたが、まさか機械学習のネタで登壇する日が来るとは思ってもみませんでした (以前の納涼 LT 大会にスピーカーとしてエントリしたものの、会社イベントを優先する必要があって止む無く断念したこともありましたが…)。</p>
<p>JJUG は渋谷java ほど <em>カジュアル (= 自分の好き勝手・気ままに話したいことを話す)</em> なコミュニティではないので、発表する内容は理解を優先した構成にしてみました。その分、「この内容は果たして聴講者に伝わるんであろうか」とヤキモキしたりすることもあって、久々に資料作りで消耗しました。でも楽しかったですね!</p>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-70743373027447819472014-12-13T19:44:00.000+09:002014-12-13T20:07:33.374+09:00第九回 #渋谷java で飛び入り LT してきました (Slack 用 Logback Appender を実装する話)<h2 id=".306f.3058.3081.306b">はじめに</h2>
<p>会社の合宿予定が入っていて参加できそうになかったので、やむなく参加を見送っていた 12/13 (土) の <a href="http://shibuya-java.connpass.com/event/9996/">第九回 渋谷java</a> でしたが、思ったより早く東京に戻ってくることができたので、下記のように</p>
<blockquote class="twitter-tweet" lang="ja"><p><a href="https://twitter.com/komiya_atsushi">@komiya_atsushi</a> <a href="https://twitter.com/jflute">@jflute</a> できますよー。LT枠空いているので是非お願いしますw</p>— Naoki Takezoe (@takezoen) <a href="https://twitter.com/takezoen/status/543637368293449728">2014, 12月 13</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>と参加できそうなのかつぶやいてみたところ、カジュアル無茶ぶりコメントをたけぞー先生よりいただいたので適当にネタをでっちあげて LT 発表してきたのでした。</p>
<h2 id="SmartNews_.2665_Slack">SmartNews ♥ Slack</h2>
<p><a href="https://twitter.com/amachino">@amachino</a> さんが先日 Slack の Advent calendar に投稿したとおり、スマートニュースでは <a href="http://qiita.com/mach/items/a1477ff0c66aa65c6ac4">社内のコミュニケーションに Slack を活用しています</a>。
通常の人同士の会話だけでなく Jenkins からの通知や Datadog からのアラートなども Slack に集約しており、普段扱っているコミュニケーションツールの中でも特段利用時間が長い状況になっています。</p>
<p>そのため、「プロダクション環境で動いている Java アプリケーションの実行状況・進捗や、例外が発生したときの詳細を Slack 経由で見たい・知りたい」という要望が Java エンジニア的には自然と沸き起こってくるわけです。</p>
<h2 id="Logback_.306e_Appender_.3092.5b9f.88c5.3059.308b">Logback の Appender を実装する</h2>
<p>そういうわけで、Java アプリケーションからお手軽に Slack にメッセージをポストする方法として、Logback の Appender 実装を用意する方法を紹介しました。</p>
<script async class="speakerdeck-embed" data-id="ee1bd80064d201323f2d3a0c8878bc5a" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script>
<p>プロダクション環境で利用するにあたって、HTTP(S) 経由で Slack API を呼び出す際に</p>
<ul>
<li>ロガーメソッドを呼び出す元の実行をブロックしないように (すぐに制御が戻るように) 非同期処理する</li>
<li>非同期処理で Slack API を叩くにしてもログのイベントが前後するのは嫌なので (Array)BlockingQueue を使ってログイベントを直列化する</li>
<li>HTTP 通信で失敗したときのためにリトライ処理を入れる</li>
</ul>
<p>などの仕組みを入れ込んだ実装としています (発表中にお見せしたコードはまだ整備しきれていないので現在は非公開としていますが、いずれ公開する予定です)。</p>
<h2 id=".4f1a.5834.53c2.52a0.8005.304b.3089.306e.30c4.30c3.30b3.30df">会場参加者からのツッコミ</h2>
<p>これは発表の際に <a href="https://twitter.com/ryushi">java-ja から来られた方</a> からいただいたツッコミなのですが、Appender 内部で非同期処理をする場合は、 <code>ContextAwareBase</code> クラス (<code>AppenderBase</code> クラスの親クラス) が <code>context</code> フィールドで保持しているオブジェクトの <code>Context#getExecutorService()</code> メソッドの戻り値を使って、その <code>ExecutorService</code> オブジェクト経由でスレッドを立ち上げるといいそうです。</p>
<h2 id=".307e.3068.3081.30fb.611f.60f3">まとめ・感想</h2>
<ul>
<li>Logback の Appender 実装はツボさえ押さえれば、あんまり難しくないよ</li>
<li>Logback のインタフェースで Slack API を叩けるようになれば、Logback 使っている既存の Java アプリケーションなら容易に Slack に通知を出せるようになるね!</li>
<li>java-ja から来た人、ちょっとコワイけど、丁寧な説明だったりアドバイスをいただけたりと、とっても親切だね!</li>
</ul>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com1tag:blogger.com,1999:blog-2947217167725456676.post-83721317949759947972014-10-22T09:30:00.000+09:002014-10-22T09:30:42.128+09:00僕の Redshift の圧縮エンコード使い分けメモ<p>最近 Redshift を触っていて、圧縮エンコードについて調べることがあったのでメモメモしておきます。なお、2014 年 10 月時点での情報であることと、わりとざっくりとした確認だったので不正確な情報が混じっているかもしれないのでご承知おきください。</p>
<h2>文字列データ (VARCHAR など)</h2>
<ul>
<li>選択肢としては、 <code>text255</code>, <code>text32k</code>, <code>bytedict</code>, <code>lzo</code> あたり
<ul><li>空間効率的には <code>text255</code> <code>text32k</code> はあんまりよろしくなさげ</li>
<li>また、<code>text255</code> はカラムサイズが 255 を超えるカラムに適用することができない (厳密には、255 バイトを超える文字列が入っている場合に適用できない、となる)</li></ul></li>
<li>値の種類数が少なく (目安として、256 個以下ぐらい)、かつ種類が増える可能性が低い場合
<ul><li><code>bytedict</code> もしくは <code>lzo</code> を選ぶのがよい</li>
<li>種類数が 256 を超える場合であっても、出現頻度に偏りがある場合は <code>bytedict</code> を選択するのもありっぽい</li>
<li>ただし、文字列の平均長が長い場合は <code>bytedict</code> はあんまり性能よろしくない?</li></ul></li>
<li>最初は値の種類数が少ないが、時間経過とともに使われる値の種類が徐々に増える場合
<ul><li><code>lzo</code> を選ぶのがよい</li></ul></li>
<li>時間経過とともに使われる値の種類が増えるが、ソートキーを考慮すると使われる値の種類が少数に限定されると想定できる場合
<ul><li><code>lzo</code> を選ぶのがよい</li></ul></li>
<li>値の種類数が多い場合
<ul><li><code>lzo</code> を選ぶのがよい</li></ul></li>
</ul>
<p>というわけで、迷ったら <code>lzo</code> を選べばだいたいいい感じだと思う。</p>
<h2>数値データ</h2>
<ul>
<li>選択肢としては、 <code>bytedict</code>, <code>delta/delta32k</code>, <code>mostly8/16/32</code> あたり
<ul><li><code>lzo</code> はあんまり向いてなさげ</li></ul></li>
<li>値の種類数が少なく、かつ種類が増える可能性が低い場合
<ul><li>0 付近の値が頻出する場合は <code>mostly8</code> を選ぶのがよい</li>
<li>それ以外では <code>bytedict</code> を選ぶのがよい</li></ul></li>
<li>時間経過とともに使われる値の種類が増えるが、ソートキーを考慮すると使われる値の種類が少数に限定されると想定できる場合
<ul><li><code>bytedict</code> でよさそう</li></ul></li>
<li>値の種類数は多いが、出現する値に偏りがある場合
<ul><li>0 近辺に偏っているなら、 <code>mostly8/16/32</code> などを選ぶのがよい</li>
<li>それ以外なら <code>bytedict</code> がよさそう</li></ul></li>
<li>ソートキーを考慮したときに値が昇順に並ぶ場合
<ul><li><code>delta/delta32k</code> を選ぶのがよい</li></ul></li>
<li>それ以外の場合
<ul><li>諦めて、圧縮エンコードは設定しない (<code>raw</code> にする)</li></ul></li>
</ul>
<p>正直言って、数値データは実際のデータで性能を確認してみないとわからないと思う…</p>
<h2>その他</h2>
<ul>
<li><code>runlength</code> の使いどころがよくわからない…</li>
<li>時間計算量
<ul><li><code>bytedict</code> は時間計算量ちょっと高めな傾向がみられる</li>
<li><code>lzo</code> はバランスがとれている感じ</li></ul></li>
</ul>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-12883422362117408772014-09-21T02:52:00.000+09:002014-09-21T12:58:28.745+09:00第八回 #渋谷java にて、認証系を Java 8 で自作する話をしてきました<h2 id=".306f.3058.3081.306b">はじめに</h2>
<p>毎回、他の発表者の方々が有益情報を発表してくれる中で僕一人が誰得情報をひたすら発信しているわけですが、今回もご多分に漏れず Java 8 で認証系を自作する、というニッチな話をしてきました。</p>
<script async class="speakerdeck-embed" data-id="780bb9a022ce013253c562b11b8dfdf5" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script>
<p>昨今のパスワード流出系のセキュリティインシデントが業界内で話題になるたびに「認証系なんてものは自作するようなもんじゃない」という認識が醸成されつつあると思います。しかし、マイナー or オレオレ Web アプリケーションフレームワークなどを利用しているとそうもいってはおられず、認証系が用意されていないときはやむなく認証系の自前実装が要求されることもあるでしょう。自分自身も周りを見渡していても、過去何度かそういうことがありました。</p>
<p>ただ、実装者の認証セキュリティに対する認識や知識によって脆弱な認証系を作り込むことも少なくなく、そういうのをなるべく減らしたいなー、という思いを込めて今回の発表に至りました。</p>
<h2 id=".3069.3046.3057.3066.3082.8a8d.8a3c.7cfb.3092.81ea.524d.5b9f.88c5.3057.306a.3051.308c.3070.306a.3089.306a.3044.3068.304d.306b.6c17.3092.3064.3051.305f.3044.3053.3068">どうしても認証系を自前実装しなければならないときに気をつけたいこと</h2>
<p>前述した発表資料に書いてあることにはなりますが、今一度文章に起こしておきます。</p>
<h3 id=".30a2.30ab.30a6.30f3.30c8.5225_salt_.306e.751f.6210.3068.6697.53f7.8ad6.7684.64ec.4f3c.4e71.6570.751f.6210.5668.306e.5229.7528">アカウント別 salt の生成と暗号論的擬似乱数生成器の利用</h3>
<p>セキュリティを少しかじったことがある人であれば「salt ってやつとパスワードを組み合わせたものをハッシュする」ということぐらいは知っているものと思います。ただ、どうも salt だけがひとり歩きしていることがあったりして、アプリケーションで共通の事前に用意された salt を使いまわす、みたいなアレな実装を見たことがある人はそこそこいるんじゃないでしょうか?</p>
<p>本来は、認証単位であるアカウント別に salt を生成すべきであり、かつ salt の生成には暗号論的擬似乱数生成器を用いるべきです。この salt の生成を Java で実現するならば、</p>
<pre><code> static byte[] newSalt(int length) {
try {
byte[] result = new byte[length];
SecureRandom.getInstance(
// "NativePRNGNonBlocking"
// "NativePRNGBlocking"
"SHA1PRNG"
).nextBytes(result);
return result;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
</code></pre>
<p>のような実装になることでしょう。 <code>SecureRandom.getInstance()</code> の呼び出しで指定しているのは擬似乱数生成アルゴリズムで、Java 7 以前は <code>SHA1PRNG</code> だけだったのが、Java 8 では新たに</p>
<ul>
<li><code>NativePRNG</code></li>
<li><code>NativePRNGBlocking</code></li>
<li><code>NativePRNGNonBlocking</code></li>
</ul>
<p>が (Windows を除く) *nix-like なプラットフォーム向け JRE にて導入されたようです。</p>
<h3 id=".6697.53f7.5b66.7684.30cf.30c3.30b7.30e5.95a2.6570.306e.5229.7528.3068.30b9.30c8.30ec.30c3.30c1.30f3.30b0">暗号学的ハッシュ関数の利用とストレッチング</h3>
<p>salt を生成したら、あとはパスワードと組み合わせてハッシュ化、なのですが、これも単に SHA-* を使えばいい、というほど簡単ではありません。</p>
<p>結論から言ってしまえば、PBKDF2 などのキー派生 (導出?) 関数を使ってストレッチングすべき、となります。</p>
<p>Java 7 では PBKDF2 の実装は <code>PBKDF2WithHmacSHA1</code> しか用意されていませんでしたが、Java 8 にて</p>
<ul>
<li><code>PBKDF2WithHmacSHA224</code></li>
<li><code>PBKDF2WithHmacSHA256</code></li>
<li><code>PBKDF2WithHmacSHA384</code></li>
<li><code>PBKDF2WithHmacSHA512</code></li>
</ul>
<p>の 4 つが導入されました。この PBKDF2 を用いたパスワードのハッシュ化コードは以下になります。</p>
<pre><code> static byte[] hash(String password, byte[] salt, int numIterations, int numHashLength) {
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, numIterations, numHashLength);
SecretKeyFactory factory;
try {
factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
try {
return factory.generateSecret(keySpec)
.getEncoded();
} catch (InvalidKeySpecException e) {
throw new RuntimeException(e);
}
}
</code></pre>
<h2 id=".307e.3068.3081">まとめ</h2>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBx8NoDG9ImzKEpfciFN-TwGHRYVmW8Ab9BZ8omBhJkCjN051CqzoXcJKfGG5fS4V_uqmaJPedyYruB198sWyf8xMwxYmRoPMsSW8a3EzNgXbfXdGZrSYajwePcFDPcnMuFu7x3HDxIXK0/s1600/DSC_1333.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBx8NoDG9ImzKEpfciFN-TwGHRYVmW8Ab9BZ8omBhJkCjN051CqzoXcJKfGG5fS4V_uqmaJPedyYruB198sWyf8xMwxYmRoPMsSW8a3EzNgXbfXdGZrSYajwePcFDPcnMuFu7x3HDxIXK0/s320/DSC_1333.jpg" /></a></div>
<p>なんだかんだ書いてはいますが、やっぱり僕含めて素人は認証系の実装をするのはやめたほうがいいですね (過去何度もダメな認証系を作ってしまったし…)。</p>
<p>既存ライブラリの <a href="http://shiro.apache.org/">Apache Shiro</a> とか <a href="http://projects.spring.io/spring-security/">Spring Security</a> とか、僕は使ったことないですが、多分このあたりの面倒なお仕事をこなしえくれるのではないでしょうか。</p>
<p>なお、</p>
<blockquote class="twitter-tweet" data-cards="hidden" lang="ja"><p>Javaで認証系だとこういったのもありますね <a href="https://twitter.com/hashtag/%E6%B8%8B%E8%B0%B7Java?src=hash">#渋谷Java</a> / leleuj/pac4j <a href="https://t.co/9faG21iXoq">https://t.co/9faG21iXoq</a></p>— とーます (@grimrose) <a href="https://twitter.com/grimrose/status/513243460346720256">2014, 9月 20</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>こういうライブラリもあるようですよ!</p>
<h2 id=".53c2.8003.6587.732e">参考文献</h2>
<ul>
<li><a href="http://www.atmarkit.co.jp/fsecurity/special/165pswd/01.html">ハッシュとソルト、ストレッチングを正しく理解する 本当は怖いパスワードの話</a></li>
</ul>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-68565563053510041682014-09-17T23:59:00.001+09:002014-09-17T23:59:43.066+09:00"Can't connect to MySQL server on 'HOST_NAME' (111)" のエラーが出たときの原因の一つと対処法<p>
VM 上の Ubuntu に apt-get で mysql-server-5.6 をインストールし、VM の外から VM 内部の mysqld に接続しようとしたときにこのエラーが発生した。
</p>
<p>
原因は my.cnf に
<pre>
bind-address = 127.0.0.1
</pre>
が設定されていたためであった。
</p>
<p>
この行を my.cnf から削りとって、ようやくVM 外部から mysqld に接続できるようになったけど、毎回こんな感じのトラブルで時間を喰われてしまっているわけで、MySQL 力が低いと何かと生きるのが辛い…
</p>
Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-88688551978477507002014-09-15T23:17:00.000+09:002014-09-16T01:08:54.323+09:00Java のプロパティファイルは UTF-8 エンコーディングで記述したい<blockquote>
<p>「えーマジ native2ascii!?」「プロパティエディタプラグインが許されるのは J2SE 5.0 までだよねー」</p>
</blockquote>
<p>ジャバエンジニアはそろそろ、プロパティファイルを扱う場合に <code>native2ascii</code> やら各種プロパティエディタプラグインやらの呪縛から解放されてもいいと思うのです…</p>
<h1 id=".6982.8981">概要</h1>
<p>Java でアプリケーションの各種設定を記述したプロパティファイル (.properties) を取り扱う場合、 <code>Properties</code> クラスもしくは <code>ResourceBundle</code> クラスのお世話になるかと思います。</p>
<p>一昔前までは、プロパティファイル内で日本語などいわゆるマルチバイト文字を含む場合に、 <code>native2ascii</code> コマンドを利用して ASCII コードの文字のみで表現できる <strong>ユニコードエスケープ</strong> (!= UTF-xx エンコーディング) 表現に変換することが必要とされていました。</p>
<p>しかし、Java は 7 or 8 がメインストリームになり、また UTF-8 エンコーディングされたテキストを取り扱うことがわりと当たり前になりつつある昨今、いまだに Eclispe にわざわざプロパティエディタプラグインを導入してプロパティファイルをしこしこ編集したり、プロダクション環境でユニコードエスケープされたプロパティファイルを四苦八苦しながらパラメータ調整したりする現場があったりなかったりするようなので、ここで <code>native2ascii</code> とかプロパティエディタプラグインを必要と せずに UTF-8 エンコーディングされたプロパティファイルを扱う方法についてメモしておきます。</p>
<h1 id="UTF.2d8_.30a8.30f3.30b3.30fc.30c7.30a3.30f3.30b0.3055.308c.305f.30d7.30ed.30d1.30c6.30a3.30d5.30a1.30a4.30eb.3092.53d6.308a.6271.3046.65b9.6cd5">UTF-8 エンコーディングされたプロパティファイルを取り扱う方法</h1>
<p><code>Properties</code> クラスと <code>ResourceBundle</code> クラスそれぞれについて説明します。</p>
<h2 id=".305d.306e_1_.3a_Properties_.30af.30e9.30b9.3092.4f7f.3046.5834.5408">その 1 : Properties クラスを使う場合</h2>
<p><code>Properties#load(Reader)</code> メソッドを呼び出す際の <code>Reader</code> オブジェクトを、UTF-8 エンコーディング指定した <code>InputStreamReader</code> オブジェクトにすれば OK です。</p>
<p>すなわち、以下のような実装になるでしょう。</p>
<script src="https://gist.github.com/komiya-atsushi/0294e4a2fcffabe1b3e2.js"></script>
<h2 id=".305d.306e_2_.3a_ResourceBundle_.30af.30e9.30b9.3092.4f7f.3046.5834.5408">その 2 : ResourceBundle クラスを使う場合</h2>
<p>こちらは若干複雑になりますが、 <code>ResourceBundle.Control</code> クラスのサブクラスを用意して対処する方法をとります。</p>
<p>同クラスの <code>newBundle()</code> メソッドのオーバーライド実装にて、 <code>Properties</code> のときと同様に UTF-8 エンコーディング指定した <code>InputStreamReader</code> オブジェクトを用意し、 <code>PropertyResourceBundle</code> クラスのコンストラクタ引数にそのオブジェクトを指定します。</p>
<p>そして実際に <code>ResourceBundle</code> クラスのオブジェクトを取得する際に、その <code>ResourceBundle.Control</code> サブクラスのオブジェクトを <code>ResourceBundle.getBundle(String, ResourceBundle.Control)</code> メソッドの二つ目の引数に指定してやることで、UTF-8 エンコーディングなプロパティファイルを取り扱うことができるようになります。</p>
<p>実装は以下のとおり。</p>
<script src="https://gist.github.com/komiya-atsushi/2d9d8b2000358d4d004d.js"></script>
<h1 id=".307e.3068.3081">まとめ</h1>
<ul>
<li><code>Properties</code> も <code>ResourceBundle</code> もどちらも、文字エンコーディング指定した <code>InputStreamReader</code> オブジェクトを扱うようにすれば、 <code>native2ascii</code> 的な呪縛から逃れることができるよ</li>
<li>UTF-8 エンコーディングなどにしておけば、プロダクション環境上でプロパティファイルをどうしても確認しなきゃいけなくなった場合でも、プロパティファイルに記述した日本語コメントを頼りにスムーズな確認ができるようになるよね</li>
<li>プロパティエディタプラグインはもうオワコン扱いでいいよね</li>
</ul>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com2tag:blogger.com,1999:blog-2947217167725456676.post-76320717966574623832014-09-11T01:38:00.000+09:002014-09-11T02:13:32.785+09:00Java 8 で Base64 エンコーディング機能が導入されたらしいので使ってみた<p>「何をいまさら」な感じの機能追加だけど、Java 8 から <a href="http://docs.oracle.com/javase/8/docs/api/java/util/Base64.html">標準のクラスライブラリで Base64 エンコーディング</a> できるようになった。これはこれで嬉しいことなので、使い方とそのパフォーマンスをメモっておく。</p>
<h2 id=".4f7f.3044.65b9">使い方</h2>
<p>まずはデモコードから。</p>
<script src="https://gist.github.com/komiya-atsushi/d878e6e4bf9ba6dae8fa.js"></script>
<p>エンコーダは以下のメソッド呼び出しで得られる 3 つの種類がある。</p>
<ul>
<li><code>Base64.getEncoder()</code></li>
<li><code>Base64.getUrlEncoder()</code></li>
<li><code>Base64.getMimeEncoder()</code></li>
</ul>
<p>対応するデコーダがそれぞれ用意されている。</p>
<ul>
<li><code>Base64.getDecoder()</code></li>
<li><code>Base64.getUrlDecoder()</code></li>
<li><code>Base64.getMimeDecoder()</code></li>
</ul>
<p><code>Base64.getUrlEncoder()</code> で得られるエンコード文字列は、普通の Base64 エンコーディングではファイルパスや URI での利用時に問題となりうる <code>+/</code> の文字の代わりに <code>-_</code> を使ってエンコードしてくれる。「Base64 エンコーディングした文字列をファイル名に利用したい!」みたいなケースだととっても有用だと思う。</p>
<h2 id=".30d1.30d5.30a9.30fc.30de.30f3.30b9">パフォーマンス</h2>
<p>Java 7 以前は <a href="http://commons.apache.org/proper/commons-codec/">Apache Commons Codec</a> の <a href="http://commons.apache.org/proper/commons-codec/archives/1.9/apidocs/org/apache/commons/codec/binary/Base64.html">Base64 クラス</a> を使うことが一般的だったぽいので、それとの性能比較をしてみた。</p>
<p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguvJuXvj88e1HZBgAWaGmFCA2sssRsE6xtjEKN57U-AKHLVKJpmYP10PnVhT3fR7hxwB00onFBW6eZGeShEBPjwWF8VrpXK13aeBnleNWa9FRiZDxblIwmmFK3ouysCE0n7aDeQAv_V89h/s1600/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88+2014-09-11+1.02.54.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguvJuXvj88e1HZBgAWaGmFCA2sssRsE6xtjEKN57U-AKHLVKJpmYP10PnVhT3fR7hxwB00onFBW6eZGeShEBPjwWF8VrpXK13aeBnleNWa9FRiZDxblIwmmFK3ouysCE0n7aDeQAv_V89h/s400/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88+2014-09-11+1.02.54.png" /></a></div>
</p>
<p>今回は、メソッド呼び出しにおけるオーバーヘッドを見るスイート (上段) と、Base64 の変換処理の性能を見るスイート (下段) の二種類を用意した。</p>
<p>この結果から、</p>
<ul>
<li>全般的に、Java 8 で導入された Base64 クラスの方が処理性能的に優れている</li>
<li>特に、Java 8 側の変換メソッドを呼び出す際のオーバーヘッドが Commons Codec のそれより明らかに小さいことがわかる</li>
<li>変換処理の性能は、エンコーディングが 6 倍程度、デコーディングが 2 倍ちょっと、Java 8 の Base64 クラスの方が速い</li>
</ul>
<p>ということがわかるかと思う。</p>
<p>なお、性能測定に用いたプログラムは以下のとおり。</p>
<script src="https://gist.github.com/komiya-atsushi/301ae973f7117f856b2f.js"></script>
<h2 id=".307e.3068.3081">まとめ</h2>
<ul>
<li>Base64 だけについて言えば、Commons Codec はその役目を終えた感がある</li>
<li>これからは Java 8 の Base64 を積極的に使うのがよさそうだね!</li>
</ul>
Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com1tag:blogger.com,1999:blog-2947217167725456676.post-43482661066722952102014-08-21T02:21:00.001+09:002014-08-21T02:52:49.107+09:00Docker の Official らしい MySQL のイメージを利用してみる<p>気づいたらいつの間にか <a href="https://registry.hub.docker.com/_/mysql/">Docker Official な MySQL イメージ</a> が公開されていたので、ちょうどとある製品の検証目的で使い捨てられる MySQL の環境が欲しかったついでに試してみたところ、ちょっとハマって数時間を無駄にしてしまったことにカッとして書き殴ったメモ。</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3xXSdiM-nyUatn5QPDwlFKPiJr52nuk7ni__tGQNA4rVVnea8azn1J5Jfv11VM1hs5xv1OLcg2OAqLbZML2NBzOQGNo9ikWDlAQifaONHt2MSmddhelXflln5oMO8xR__fVWqcQB9VR0K/s1600/44480268_dd052de6ca_m.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3xXSdiM-nyUatn5QPDwlFKPiJr52nuk7ni__tGQNA4rVVnea8azn1J5Jfv11VM1hs5xv1OLcg2OAqLbZML2NBzOQGNo9ikWDlAQifaONHt2MSmddhelXflln5oMO8xR__fVWqcQB9VR0K/s1600/44480268_dd052de6ca_m.jpg" /></a>
<p>(photo by <a href="https://www.flickr.com/photos/pinhole/">Mark Interrante</a>)</p>
</div>
<h2 id=".9054.6210.3057.305f.3044.3053.3068">達成したいこと</h2>
<p>達成したかったことは以下のとおり。</p>
<ul>
<li>お手軽にポイ捨てできる MySQL 環境を構築・用意したい</li>
<li>Dockerfile をシコシコつくるのは面倒だったので、既存の Docker イメージを利用したい</li>
<li>boot2docker はあんまりいい思い出がなかったので、Vagrant で構築した VM 上に Docker 環境を構築したい</li>
</ul>
<h2 id=".3084.308d.3046.3068.3057.305f.3053.3068">やろうとしたこと</h2>
<p>やろうとしたことの具体的な手順は以下のとおり。</p>
<ol>
<li>Ubuntu 14.04 の VM 環境を Vagrant で用意する</li>
<li>上記の VM 環境上に Docker をインストールする</li>
<li>MySQL な Docker イメージを pull する</li>
<li>pull した Docker イメージを run する</li>
</ol>
<h2 id=".5b9f.969b.306f.3069.3046.3060.3063.305f.306e.304b.ff1f">実際はどうだったのか?</h2>
<h3 id="1.2e_Ubuntu_14.2e04_.306a_VM_.74b0.5883.3092_Vagrant_.3067.7528.610f.3059.308b">1. Ubuntu 14.04 な VM 環境を Vagrant で用意する</h3>
<p>Ubuntu 14.04 の daily Cloud Image を利用して <code>vagrant init && vagrant up</code> してみた。</p>
<p>Docker をインストール & <code>docker pull</code> するあたりまではうまくいったものの、MySQL イメージを <code>docker run</code> するところで、mysqld が起動しないという問題に遭遇してしまった。</p>
<p>以前、別件で <a href="https://registry.hub.docker.com/u/orchardup/mysql/">orchardup/mysql</a> の Docker イメージを使ったときはこんな問題は起こらなかったのになあ、と思いつつ <code>docker logs container-id</code> としてコンテナのログを確認してみると、</p>
<pre><code>2014-08-20 16:31:09 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2014-08-20 16:31:10 1 [Warning] Buffered warning: Performance schema disabled (reason: init failed).
2014-08-20 16:31:10 1 [Note] Plugin 'FEDERATED' is disabled.
2014-08-20 16:31:11 1 [Note] InnoDB: Using atomics to ref count buffer pool pages
2014-08-20 16:31:11 1 [Note] InnoDB: The InnoDB memory heap is disabled
2014-08-20 16:31:11 1 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
2014-08-20 16:31:11 1 [Note] InnoDB: Memory barrier is not used
2014-08-20 16:31:11 1 [Note] InnoDB: Compressed tables use zlib 1.2.3
2014-08-20 16:31:11 1 [Note] InnoDB: Using Linux native AIO
2014-08-20 16:31:11 1 [Note] InnoDB: Not using CPU crc32 instructions
</code></pre>
<p>…ログはここで途切れている。</p>
<blockquote>
<p>2014-08-20 16:31:10 1 [Warning] Buffered warning: Performance schema disabled (reason: init failed).</p>
</blockquote>
<p>の行が怪しいなあ、ということでこのエラーメッセージでぐぐってみると、<a href="http://docs.oracle.com/cd/E19957-01/mysql-refman-5.5/performance-schema.html#performance-schema-runtime-configuration">Oracle のページ</a> が引っかかった。</p>
<p>当該ページにある</p>
<blockquote>
<p>you may have specified other Performance Schema variables with values too large for memory allocation to succeed.</p>
</blockquote>
<p>を読む限り、「これメモリが足りないんじゃね?」疑惑が湧いてきたので、Vagrantfile を以下のようにいじいじして、メモリサイズを 1GB にしてみたら、ちゃんと起動するようになった。めでたしめでたし。</p>
<pre><code>Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# (省略)
config.vm.provider "virtualbox" do |vb|
vb.customize [ "modifyvm", :id, "--memory", 1024 ]
end
# (省略)
end
</code></pre>
<h3 id="2.2e_.4e0a.8a18.306e_VM_.74b0.5883.4e0a.306b_Docker_.3092.30a4.30f3.30b9.30c8.30fc.30eb.3059.308b">2. 上記の VM 環境上に Docker をインストールする</h3>
<p><code>apt-get install docker.io</code> でインストールできる Docker は 0.9 だった。</p>
<p>せっかくなので新しいバージョンを使ってみたいので、</p>
<pre><code>curl -s https://get.docker.io/ubuntu/ | sh
</code></pre>
<p>として Ubuntu 向け最新のバージョンをインストールするのであった。</p>
<h3 id="3.2e_MySQL_.306a_Docker_.30a4.30e1.30fc.30b8.3092_pull_.3059.308b">3. MySQL な Docker イメージを pull する</h3>
<p>以前使っていた orchardup/mysql は <a href="https://github.com/orchardup/docker-mysql">GitHub</a> の README を見るとオワコン宣言されていたので、Docker official らしい Docker イメージに乗り換えるのであった。</p>
<h3 id="4.2e_pull_.3057.305f_Docker_.30a4.30e1.30fc.30b8.3092_run_.3059.308b">4. pull した Docker イメージを run する</h3>
<p>とりあえず</p>
<pre><code>docker run \
--name hogehoge \
-e MYSQL_ROOT_PASSWORD=hogehoge_password \
-d \
mysql
</code></pre>
<p>で mysql イメージのコンテナを立ち上げて、Docker コンテナをホストしている Ubuntu 上の MySQL CLI で</p>
<pre><code>mysql -u root -phogehoge_password -h 127.0.0.1
</code></pre>
<p>としてみたんだけど、</p>
<pre><code>Can't connect to MySQL server on '127.0.0.1' (111)
</code></pre>
<p>などと悲しいことを仰る MySQL CLI さんに、僕は涙を浮かべずにはいられなかった。</p>
<p><code>ps</code> コマンドでコンテナ上の mysqld が稼動していることは確認できたものの、それ以上のことはわからず試行錯誤したりいろいろぐぐったりしているうちに、「これコンテナのポートが開いてないんじゃね?」疑惑が湧いてきて <a href="http://stackoverflow.com/questions/22111060/difference-between-expose-and-publish-in-docker">Difference between “expose” and “publish” in docker</a> のページにたどり着いた。</p>
<p>当該 Stackoverflow のページの回答をかいつまんで説明すると、</p>
<ul>
<li>Dockerfile にて <code>EXPOSE</code> でポート番号を設定すると、コンテナ間でポートを通じた通信ができるようになる
<ul><li>コンテナ間の通信をしたい場合は、これを設定すべき</li></ul></li>
<li>Dockerfile での <code>EXPOSE</code> のポート番号指定に加えて、 <code>docker run</code> する際の <code>-p hostPort:containerPort</code> を指定すると、 コンテナ側のポート <code>containerPort</code> をホストのポート <code>hostPort</code> でパブリッシュする
<ul><li>コンテナ間だけでなく、Docker の外の世界と通信したい場合は、 <code>-p</code> も設定すべき</li></ul></li>
</ul>
<p>ということになる。そんなわけで、</p>
<pre><code>docker run \
-p 3306:3306 \
--name hogehoge \
-e MYSQL_ROOT_PASSWORD=hogehoge_password \
-d \
mysql
</code></pre>
<p>としてコンテナを立ち上げてみたところ、ようやく MySQL CLI からコンテナ上の mysqld にご挨拶をするハッピーエンディングを迎えることができたのであった。</p>
<h2>まとめ</h2>
<p>Docker ネタのブログエントリって、たいてい Dockerfile の手組みから始まる系のやつが多い印象なんだけど、既存の Docker イメージを活用するカジュアル利用的なブログエントリももうちょっと増えてもいいと思う。</p>
<h2>おまけ</h2>
<p>できあがった Vagrantfile はこちら。</p>
<script src="https://gist.github.com/komiya-atsushi/49414ea19917414a4e48.js"></script>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-20795082970101709192014-06-10T09:56:00.000+09:002014-06-10T10:08:10.803+09:00#MLCT 「機械学習のテスト自動化コトハジメ」のタイトルで Machine Learning Casual Talks #1 で発表してきました。<h2 id=".306f.3058.3081.306b">はじめに</h2>
<p>ちょこっとご報告が遅れてしまった気もしますが、タイトルにあるとおり、 <a href="https://twitter.com/chezou">@chezou</a> さん主催の <a href="http://mlct.connpass.com/event/6275/">Machine Learning Casual Talks #1</a> @クックパッド社にて発表をしてきました。</p>
<p>当 Casual Talks 開催に至った背景は以下のとおり。</p>
<blockquote class="twitter-tweet" lang="ja"><p><a href="https://twitter.com/unnonouno">@unnonouno</a> <a href="https://twitter.com/komiya_atsushi">@komiya_atsushi</a> <a href="https://twitter.com/yamakatu">@yamakatu</a> Machine Learning Testing Casual talkの機運ですね!(白目)</p>— chezou (@chezou) <a href="https://twitter.com/chezou/statuses/458883980205387776">2014, 4月 23</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>4/22(火)に開催された、QA エンジニア向けの勉強会、 <a href="http://atnd.org/events/48666">第 4 回 Ques</a> で登壇・発表したのをきっかけに、機械学習に関してカジュアル(≠初心者的)に話せる勉強会があるといいよね、という流れができ、その後の @chezou さんのご尽力もあってめでたく開催、となりました。主催の @chezou さんおよび会場提供のクックパッド社には感謝です!</p>
<h2 id=".767a.8868.5185.5bb9.306b.3064.3044.3066">発表内容について</h2>
<p>今回の Casual Talks では、その Ques で QA エンジニアの方々向けに発表した内容を機械学習寄りのエンジニア向けに再構成・焼き直しして、機械学習なアプリケーションへのテスト自動化の適用について、基礎的なお話をさせていただきました。</p>
<script async class="speakerdeck-embed" data-id="ce31fb10cf970131ae261e02cdc90b71" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script>
<p>僕自身、機械学習を用いたアプリケーションへのテスト自動化の取り組みは暗中模索な意味合いが強かったのですが、他の発表者の資料を拝見するに、思いのほか以下のモデルを参考にしていただいている方々が多いようで、ちょっと嬉しかったですね!</p>
<p><img src="https://speakerd.s3.amazonaws.com/presentations/ce31fb10cf970131ae261e02cdc90b71/slide_47.jpg" width="100%"/></p>
<p>機械学習の分野で「テスト自動化」とか「品質」というと、肌感覚的に後回しにされがちな傾向があるように思うものの、僕個人の思いとしては他の機能と同様に、ちゃんとテスタビリティを高めたり再現性を確保したりと、品質維持のための努力をきちんとしていきたいなあ、と思うばかりであります。</p>
<p>もちろん、「テスト自動化」自体が直接的な利益を生み出すわけではないので、過剰に注力するのも考えものなんですけどね…</p>
<h2 id=".4ed6.306e.767a.8868.306b.3064.3044.3066">他の発表について</h2>
<p>今回のトークの目玉はなんといっても <a href="https://twitter.com/unnonouno">@unnonouno</a> さんの <a href="http://www.slideshare.net/unnonouno/20140606-mlct">Jubatus における機械学習のテスト</a> でした。「あーそうそうあるあるあるよねーそれ(白目」と、自分の古傷をえぐられてる感じがしたのはきっと気のせいでして、パラメータ一つの設定方法にしても、論文を是とするのではなく利用者の観点に立って考えた時に整合性のあるインタフェースを提供することが大事という考えにとても共感できました。</p>
<p>その他の登壇者の発表内容は各ブログに詳しく掲載されていますので、そちらをご参照ください。</p>
<ul>
<li><a href="http://chezou.wordpress.com/2014/06/07/machine-learning-casual-talks/">Machine Learning Casual Talks を開催しました #MLCT</a></li>
<li><a href="http://blog.unnono.net/2014/06/mlct1.html">Machine Learning Casual Talks #1で話しました</a></li>
<li><a href="http://yamakatu.github.io/blog/2014/06/07/mlct01/">Machine Learning Casual Talks #1 でLTしてきました</a></li>
<li><a href="http://showyou.hatenablog.com/entry/2014/06/07/065433">#MLCT Machine Learning Casual Talks でLTしました</a></li>
</ul>
<h2 id=".96d1.611f">雑感</h2>
<p>"Casual Talks" の名にふさわしい、機械学習に関する自由な発表ができる場として、この Machine Learning Casual Talks はとても良い場所だと思います。「テスト自動化」という機械学習ならぬ発表のわりに connpass 上で登録されていた方々の人数も相当でしたし、第2回の登壇者もちょっとずつ決まって来つつある雰囲気があるので、次回開催も恐らく時間の問題だと思いますね!</p>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-2102473406465593282014-04-07T09:02:00.001+09:002014-04-07T09:02:45.038+09:00Ansible にて、ssh の接続情報を記述する方法<p>ようやく Ansible 始めたけど右も左も分からない初心者なので、忘れないようにメモっておきます。</p>
<h2 id="ssh_.63a5.7d9a.306b.95a2.3059.308b.60c5.5831.3092.3069.3053.306b.8a18.8ff0.3059.308c.3070.3044.3044.306e.304b.ff1f">ssh 接続に関する情報をどこに記述すればいいのか?</h2>
<h3 id=".65b9.6cd5_1.3a_.2essh.2fconfig_.306b.8a18.8ff0.3059.308b">方法 1: .ssh/config に記述する</h3>
<p><code>ssh</code> コマンドが参照する <code>.ssh/config</code> ファイルに、ssh 接続に必要な情報を記述する方法です。</p>
<pre><code>Host hoge.example.com
HostName hoge.example.com
User deployguy
IdentityFile ~/.ssh/id_rsa.hoge.example.com
</code></pre>
<p>普段お使いの <code>.ssh/config</code> を Ansible にそのまま流用・活用することができるため、
開発者ごとにサーバへのログインアカウントが異なる場合に適している方法と言えるでしょう。</p>
<p>一方で、Ansible 自体のバージョン (1.2 以前) や OS にインストールされている OpenSSH のバージョン
(具体的には、 ControlPersist をサポートしていないちょっと古いバージョン) によっては、
<code>ssh</code> コマンドではなく Paramiko という Python 製の SSH クライアント (?) が使われるようで、
その場合には <code>.ssh/config</code> が参照されませんので、注意が必要です。</p>
<p>上記の条件に当てはまる場合で、Paramiko ではなく <code>ssh</code> コマンドを使いたいときは、
以下のように Inventory ファイルで <code>ansible_connection</code> パラメータに <code>ssh</code> を指定すれば
いいようです。</p>
<pre><code>[server-hoge]
hoge.example.com ansible_connection=ssh
</code></pre>
<h3 id=".65b9.6cd5_2.3a_Ansible_.306e_Inventory_.30d5.30a1.30a4.30eb.306b.8a18.8ff0.3059.308b">方法 2: Ansible の Inventory ファイルに記述する</h3>
<p><code>ansible-playbook</code> コマンドのオプション <code>-i</code> で指定する Inventory ファイルに、
接続設定を記述する方法です。</p>
<pre><code>[server-hoge]
hoge.example.com ansible_ssh_user=deployguy ansible_ssh_private_key_file=~/.ssh/id_rsa.hoge.example.com
</code></pre>
<p>各開発者の <code>.ssh/config</code> に依存しないことと、方法 1 にあったような Ansible / OpenSSH のバージョンによる ssh 接続手段の違いを意識する必要がないため、この Inventory ファイルをリポジトリで共有することで環境依存・属人的な状態を小さく保つことが出来るでしょう。</p>
<p>一方で、ログインアカウントの情報を Inventory ファイルに記述する必要があるため、開発者ごとにサーバへのログインアカウントが異なる場合にはこの方法はあまり向きません。</p>
<h2 id=".53c2.8003.6587.732e">参考文献</h2>
<ul>
<li><a href="http://k1low.hatenablog.com/entry/2013/10/15/230229">CentOS6をホストとしていて、かつ.ssh/configに頼ったAnsibleは動かない</a></li>
<li><a href="http://docs.ansible.com/intro_inventory.html#list-of-behavioral-inventory-parameters">Inventory - Ansible Documentation</a></li>
</ul>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-2494909492760391382014-03-31T12:37:00.001+09:002014-03-31T12:42:45.329+09:00バンディットアルゴリズムのシミュレータを作ってみました<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglRkfIvnrsmsp8MN5AVYreP2DtPL_M2MZZQXNuoz6XXZw_TVvDzjm9_fVCL8bwZsn1Xk8eRhtyu6HVqqD7mOTZWuUJA9K3QTM5kwRhb9HkteB8HQk6GBz3p_tRbDuDhoOsU9a6G2VQ1b2M/s1600/bandit-simulator.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglRkfIvnrsmsp8MN5AVYreP2DtPL_M2MZZQXNuoz6XXZw_TVvDzjm9_fVCL8bwZsn1Xk8eRhtyu6HVqqD7mOTZWuUJA9K3QTM5kwRhb9HkteB8HQk6GBz3p_tRbDuDhoOsU9a6G2VQ1b2M/s400/bandit-simulator.png" /></a>
<p>お手軽に各種バンディットアルゴリズムの特性・性能を比較することができる Web ベースのバンディットアルゴリズムシミュレータを、Yeoman, Bower, Grunt, D3.js, NVD3.js, AngularJS, Bootstrap なんかを使って作ってみましたよ、というお話です。</p>
<h2 id=".30c7.30e2.30b5.30a4.30c8.ff06.30bd.30fc.30b9.30b3.30fc.30c9">デモサイト&ソースコード</h2>
<p>シミュレータのデモサイトとソースコードはそれぞれ以下になります。</p>
<ul>
<li>デモサイト : <a href="http://playground.k11i.biz/bandit-simulator/">http://playground.k11i.biz/bandit-simulator/</a></li>
<li>ソースコード : <a href="https://github.com/komiya-atsushi/bandit-simulator">https://github.com/komiya-atsushi/bandit-simulator</a></li>
</ul>
<h2 id=".52d5.6a5f">動機</h2>
<p>とあるお仕事で各種バンディットアルゴリズムの特性を調査・検証したことがあって、そのときは Java で各種アルゴリズム&シミュレータを実装 → TSV ファイルにシミュレーション結果を出力して Excel でグラフ化、なんてことをやっていました。けど、これが結構な手間でして、どうにかならないかなーと悩んでいたところで、「あれ、これって JS でバンディットアルゴリズムを実装しちゃえば、d3.js とか使って Web ブラウザでお手軽にシミュレーション&可視化できるんじゃね?」と思い立ったので作ってみた次第です。</p>
<p>あと最近、仕事・プライベート問わず JS に触れる機会がめっきり減ってしまったことで、フロントエンドの開発事情にめっきり疎くなてしまったこともあり、そんな状況に危機感を抱いていて作ってみた、という副次的な動機もあったりします。</p>
<h2 id=".6240.611f">所感</h2>
<p>作ってみた所感など。</p>
<ul>
<li>この程度の規模の Web アプリケーションでも AngularJS を使って開発をしておくと、モジュール構成を疎結合にできてよい感じです。</li>
<li>Bower の依存モジュールの管理・解決の仕組み、フロントエンド開発でもこういうことが実現できるのは素晴らしいですね!</li>
<li>Grunt は詳細機能を使いこなす程度に慣れるまでに、ちょっと学習コストが掛かりそう。JSON でもりもりと設定を書かなきゃいけないのはやっぱり辛い…</li>
<li>D3.js を生で取り扱うとなると、結構辛いですね… 特に AngularJS と統合して使うのはかなり苦労するかも。</li>
<li>でも、出来合いのチャート表示をしたいだけなら NVD3.js を組み合わせて使うのがおすすめ! これを使うとすごく楽ちんです!</li>
</ul>
<h2 id="ToDo">ToDo</h2>
<p>もうちょっと機能を追加したり改善したいと思っています。</p>
<ul>
<li>1,000 回のイテレーションでも結構重いので、進捗を表示したい</li>
<li>2 腕バンディット問題のシミュレーションしかできていないけど、n 腕対応したい</li>
<li>何回かシミュレーションした結果を箱ひげ図表示したい</li>
</ul>Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0tag:blogger.com,1999:blog-2947217167725456676.post-2301767426336351942014-02-27T23:11:00.001+09:002014-02-27T23:11:19.041+09:00LZ4 の近況を確認してみる<p><a href="https://rubygems.org/gems/lz4-ruby">lz4-ruby</a> の開発を進めるために、LZ4 の近況を確認してみたところ、
それなりに活発に開発されているようで変更点が多かったため、メモを兼ねてエントリにまとめてみました。</p>
<p><a href="https://code.google.com/p/lz4/source/detail?r=76">r76</a> から <a href="https://code.google.com/p/lz4/source/detail?r=113">r113</a>
までの変更履歴を追う形で、主だった変更を列挙していきます。</p>
<h2 id="API_.304c.5897.3048.305f">API が増えた</h2>
<p>r76 の時点ではマクロを含めて 6 個だった API が、r113 では obsolete を除いても 36 個と大幅に増えました。</p>
<p>LZ4 の基本機能は以前とはそう変わらないものの、後述するストリーム処理用 API など、
利用シーンごとに適した API を拡充しているようです。</p>
<h2 id="liblz4_.304c.4f5c.6210.3055.308c.308b.3088.3046.306b.306a.3063.305f">liblz4 が作成されるようになった</h2>
<p><a href="https://code.google.com/p/lz4/source/detail?r=111">r111</a> より。</p>
<p>以前の LZ4 は Makefile はあれど <code>make</code> してもライブラリは生成されず、
そのためアプリケーションから LZ4 の圧縮・伸長機能を利用しようとすると、
アプリケーションのビルド時に <code>lz4.c</code> などをあわせてコンパイルし、
同ソースコードのオブジェクトファイルをリンクする必要がありました。</p>
<p>この方法では LZ4 のリビジョンをアップデートしてアプリケーションを
再ビルドする手順がちょっと複雑になるデメリットがありましたが、
r111 で更新された Makefile によって、ライブラリ <code>liblz4.a / liblz4.so</code>
が生成されるようになり、この問題は多少緩和されたのではないかと思います。</p>
<p>ただ、<code>make install</code> でのライブラリ / ヘッダファイルのインストールには
対応しているものの、 <code>yum</code> やら <code>apt-get</code> でインストールできるわけではないので、
依存パッケージの自動的な解決などはまだ期待できません。</p>
<h2 id=".30b9.30c8.30ea.30fc.30df.30f3.30b0.51e6.7406.306b.5bfe.5fdc.3057.305f">ストリーミング処理に対応した</h2>
<p><a href="https://code.google.com/p/lz4/source/detail?r=102">r102</a> より。</p>
<p>以前の LZ4 では、圧縮したい単位で圧縮対象のデータを API に渡し、また圧縮後のデータを記録する
ヒープを十分に割り当てした上でAPI を呼び出す必要がありました。
この API 構成は zlib などの API とは大きく異なり、利用ケースによっては使い辛いこともあったようです。
(圧縮・伸長の時間性能を稼ぐためには仕方のない API 設計ではあったのですが…)</p>
<p>r102 で導入されたストリーム処理の API によって、ストリーミング的な圧縮処理を実現することができるようになりました。
(詳しい利用方法などは確認中です…)</p>
<h2 id="LZ4_HC_.306e.5727.7e2e.30ec.30d9.30eb.3092.6307.5b9a.3067.304d.308b.3088.3046.306b.306a.3063.305f">LZ4 HC の圧縮レベルを指定できるようになった</h2>
<p><a href="https://code.google.com/p/lz4/source/detail?r=113">r113</a> より。</p>
<p>LZ4 には、時間的な圧縮処理性能を犠牲にしつつ、空間効率的によりよい (= 圧縮率を重視した) 結果を得るためのモード、
LZ4 HC が存在します。</p>
<p>直近のリビジョンである r113 にて、この LZ4 HC に「圧縮レベル」パラメータが追加され、
圧縮率と処理時間のトレードオフのバランスを開発者がチューニングできるようになりました。</p>
<h2 id=".5727.7e2e.30fb.4f38.9577.306e.6642.9593.52b9.7387.304c.3055.3089.306b.5411.4e0a.3057.305f">圧縮・伸長の時間効率がさらに向上した</h2>
<p>LZ4 の一番の特徴である高速な圧縮・伸長処理は継続的に改善されているようです。
特にプラットフォームやコンパイラごとの細かな最適化がなされている印象です。</p>
<h2>まとめ</h2>
<a href="https://code.google.com/p/lz4/source/list">更新履歴</a> を見るとそれなりに開発が継続されているようですし、 <a href="https://code.google.com/p/lz4/issues/list">イシュー</a> を見てもまだやるべきことは残されているようなので、今後も開発は継続されていくことでしょう。まだまだ要注目ですね!Anonymoushttp://www.blogger.com/profile/08926099351651341198noreply@blogger.com0