レトリバインターン参加報告

経緯

サマーインターンで2ヶ月間,株式会社レトリバ様(以下敬称を略させていただきます)にお邪魔し,製品開発の職業体験をさせていただいたのでその記録です.

retrieva.jp

 

想定する読者

  • 来年以降インターン時期になるNLPer
  • レトリバに興味がある人
  • レトリバの人

 

 

選考

インターンに参加しようと思ったきっかけ

弊学ではインターン参加が修士の単位として認められています.毎年多くの M1 が夏休みに 2週間~2ヶ月間 のインターンに参加します.私も夏休みにどこかのインターンに参加することにしておりました.

インターンに参加するには(基本的に)受け入れ機関の審査に合格する必要があります.選考方法は受け入れ機関によって様々ですが,私が受けたところは大体 書類選考→ プログラミング課題 → 面接 の流れだったように思います.プログラミング課題はそれこそ機関によって様々で,時間内に解くものもあれば時間は自由でしっかり作り込むようなものもありました.ただし時間制限がないと言っても学業に差し支えるといけないので,そこは課題を出す側も解く側も気をつけます.

レトリバにしたきっかけ

どうせ行くならしっかりと得られるもののあるインターンに参加したいと思い,1ヶ月以上の長期のインターンを中心に選びました.また,苦学生なのでちゃんとお給料がでるところっていうのも大事です.インターン参加によって普段のバイトをお休みするので,最低でもその分は稼げるところじゃないと生活できません.

このような基準でいくつかのインターンを選び,応募しました.その中でも自然言語処理を前面に推しているレトリバインターンはトップクラスで行きたいものでした.人気が予想され,また枠も少ないので落ちる覚悟でした.なので他のインターン選考も結構ちゃんと進めていました.

結果,一度は落ちたもののご縁あって開発のインターンに参加させていただけることになりました. 

レトリバインターンについて少し詳しく

レトリバは例年,研究のインターンを1名程度受け入れています.今年からはインターン枠を少し増やして,研究2名,開発1名という枠でした.狭き門...

レトリバのインターン選考は プログラミング課題→面接 だったかと思います.プログラミング課題は研究も開発も共通です.時間制限がないタイプの課題だったので私なりに結構しっかり作りました.プログラミング技能そのもので私が他の人(特に競プロer)に勝てる気は全くしなかったので,テストや README をちゃんと書くことで差別化を図りました.ちょうどその時期テストにハマっていたんですよ〜.テスト楽しい.テスト通ると嬉しい.

プログラミング課題で通ると面接に進みます.面接は研究開発別々で,どちらも応募している場合はそれぞれ1回ずつあります.遠方にお住いの際はリモート面接OKでした.私はリモートでさせていただきました.大阪-東京 の往復で丸一日潰れてしまうので,リモートOKは助かりました.

面接が終わるとしばらくしてから,具体的には他の候補者の面接が全て終了してから,合否が返ってきます.実は私は一度落ちています.3枠が埋まり,4番手だったらしいです.だったのですが,面接をしていただいた社員さん(インターン期間中のメンターさん)が私のコードの雰囲気を気に入ってくださったようで,私をとりたいと思ってくれていたらしいです.そしてその思いが社長に届いたようで,開発の枠を一つ増やすという取り計らいをしてくださったらしいです.嬉しい.

 

インターンでやったこと

Answer Finder (レトリバが提供する FAQ 検索システム)の改善

Answer Finder ユーザからいくつかの改善してほしい事項が上がっており,これの原因究明および対応をさせていただきました.以下ざっくりと時系列でやったことをまとめます.

1~2 週目

Answer Finder やその周辺のコンポーネントの開発環境構築や修正の反映方法の確立をしました.コンパイル言語がまず初めてだったので,ビルドでこけた時にめっちゃ詰まりました.メンターさんにビルドとはなんぞやを教わりました.院試勉強で知識としては知っていたけれど,実際のコマンドとリンクしていなかった...

3~4週目

課題の原因究明と対応を2, 3件ぶん行いました.めっちゃC++読んだ.いじるコード量はそんなに多くなかったので,使い慣れている PyCharm で作業していました.それをみた CRO が不思議な顔をしていたのが印象に残っています.わかる.

5週目

中間報告資料作成とか発表練習とか発表本番とかをしました.

Answer Fidner の裏で回っているシステムのリファクタリング

中間報告までで最初に用意されていた課題を全て解決してしまいました.残りの期間は自由にしていいということだったので,Answer Finder の裏で回っているシステムのリファクタリングを強く希望しました.コードをみていてちょくちょく気になったところがあったんですよ.

リファクタリングは『レガシーコード改善ガイド』という本にしたがって進めました.大まかにはまずテストを作って,その上でコードの編集を行うという手順です.また,コードを読みやすく編集する上では『リーダブルコード』を参考にしました.どちらも良本です.

6週目

リファクタリングをする上での目標を定めました.現在は使われていない機能の切り離しを目標とすることにしました.

7週目

テスト作成をしました.テストが圧倒的に足りていなかったので,足りていないところの整備です.ただ時間がなかったのでひとまず外から見たときの挙動がざっと変わらないようにメソッドを絞って単体テストすることにしました.

8週目

リファクタリングをしました.インデントやタブのスタイルの統一という軽いところから初めて,リーダブルなコードになるようにこまごまと編集しました.機能の切り離しまで到達できました.実は機能の切り離しはすでになされていたなんて言えない

並行して最終報告資料作成なども行いました.最終報告は社外に公開されるので緊張しました.発表中に放送が落ちてしまうというハプニングがありつつもなんとか耐えました.

最終報告資料はこちらになります.

speakerdeck.com

 

業務以外の色々

歓迎会

インターン生および同時期に入社した方の歓迎会がありました.歓迎される側の人は自己紹介の一環として一発芸を披露することが慣例となっているそうです.私は腕を一回転させるっていう関節やわらかい自慢をしました. 

昼食

オフィス街に位置しているのでお昼ご飯を食べるところがたくさんあって,毎日「さて今日はどこに行きましょう...」という問答が生じていました.サクラテラス3Fの炭火の焼き魚やさんが好き.

ボドゲ

ボドゲ好きな社員さんたちが持ち寄ったボードゲームがオフィスにたくさんありました.レトリバでは歓迎会やカジュアルパーティーなどでしばしばボードゲームが行われているそうです.インターン期間中に3回ほどボードゲームに興じました.『私の世界の見方』はゲームに勝手も負けても楽しく,盛り上がるカードゲームでした.『ダイスフォージ』というボードゲームはダイスを強くしていくダイスゲームです.絵柄が綺麗で好き.

社風

レトリバは,その理念の3つ目に人材への投資を掲げるほどに社員を大切にする企業です.リモートワークや半休を気軽に取得できたり,完全週休2日だったり,休憩スペースの備品が充実していたりと働きやすい環境づくりがしっかりとなされていました.あと椅子が最高です.弊研究室の椅子も結構いいやつなのですが,それが霞んで見えるくらいにめっちゃいい椅子でした.

下の要望を上が全力で通そうとしてくれる,というのも感じました.例えば,私の「お客様が実際に製品を使っているところを見たい」という願いを受けて,インターン生の連携企業見学が実際に計画されていました.残念ながら震災の影響で中止になってしまいましたが,それがなければ実際に見学に行けていました.行きたかった...

このように風通しの良い社風で,アットホームな職場です(ホワイト)って感じでした.おかげでのびのびとインターンを楽しめました.

学び

今回のインターンを通じて,製品の保守や,保守しやすいコードとは何かを学ぶことができました.また,2ヶ月間がっつりと職業体験ができて,就職した後の生活を垣間見ることができました.

 

インターン仲間の参加記たち

www.creativ.xyz

 

専門用語抽出手法の研究と 抽出アプリケーションの開発 - Speaker Deck

feature_importances_ について調べてみた

経緯

授業でランダムフォレストを使ってみる課題が出たが,いまいち feature_importances_ の算出方法がわからずモニョったので調べてみた.

 

想定する読者

  • sklearn を使う人
  • 決定木がなんとなくわかる人
  • ランダムフォレストが主に分類に用いられるアルゴリズムであると知っている人

 

 

sklearn.ensemble.RandomForestClassifierのfeature_importances_ について

概要

from sklearn.ensemble import RandomForestClassifier
model
= RandomForestClassifier()
model.fit(train_data, train_label)

importances = model.feature_importances_

すっごく色々はしょるが,こうすると特徴量ごとの重要度が出てくる.

詳しくはこの辺のサイトを参考にしてください.

mayokoex.hatenablog.com

 

feature_importances_ の算出方法

では,この feature_importances_ はどのようにして算出されているのだろうか?

これを知るにはまずランダムフォレストのアルゴリズムをおさらいする必要がある.

決定木のアルゴリズム

ランダムフォレストは決定木の集まりでできている.決定木とは以下のようなもののことである.

f:id:ensyu3-141592653589793238:20180605233109p:plain

決定木そのものは訓練データを用いて構築される.

あるノードにおいて分類にもっとも効果的な特徴量を選択し,データ集合の乱雑さが0になるまで,つまりそのノードにおける全てのデータが同じラベルを持つまで,順次ノードを作っていく.ここで言う効果的な特徴量とは,その特徴量によってデータ集合を分割した際にクラスラベルの乱雑さがもっとも減少するものを差す.乱雑さは gini係数やエントロピーなど様々な式で定義でき,sklearn ではデフォルトで gini係数を用いている.

sklearn.tree.DecisionTreeClassifier — scikit-learn 0.19.1 documentation

ランダムフォレストのアルゴリズム

決定木は過学習を起こしやすいとされ,これを避けるのがランダムフォレストである.

ランダムフォレストではまず,訓練データからいくつかの部分データ集合をランダムサンプリングによって生成する.この部分データ集合ごとに決定木を構築することを考える.ただしあるノードにおいて特徴量は,全ての特徴量のうちランダムにサンプリングされたものの中から選択される.こうすることによって全ての決定木が同じような挙動をすることを避ける.

こうして得られた決定木それぞれが分類を行い,その投票によって分類結果が決定される. 

feature_importances_ の算出方法

決定木ではある特徴量による分類の前後で乱雑さがどれほど減少するかで特徴量の選定を行っていた.この減少幅を利得と言うことにする.利得は木の構築時に計算されていることになる.

ざっくり言えば,feature_importances_ はこの利得の特徴量ごとの平均である.ただし,決定木の構築に使われたデータのうちいくつのデータがそのノードへ到達したかで重み付けがなされている.たくさんのデータをさばくノードは重要度が高くなると考えれば,この定義は直感的に納得がいく.

詳しい説明はこのサイトを参考にしてください.ベストアンサーの Gilles Louppe 氏は sklearn の開発メンバーの1人です.

stackoverflow.com

 

あとがき

今回は sklearn.ensemble.RandomForestClassifier の feature_importances_ の算出方法を調べた.ランダムフォレストをちゃんと理解したら自明っちゃ自明な算出だった.今までランダムフォレストをなんとなくのイメージでしか認識していなかったことが浮き彫りなった.この執筆を通してランダムフォレストを分かった気になれたのでスッキリですわ.

ところで開発者本人から回答が来るって羨ましすぎるよ...

ここまで読んでいただきありがとうございました.私の理解が足りていないところなどがあれば,なにとぞ優しくまさかりを投げてください.ちょっとした質問などもいただけると嬉しいです.

今回の執筆にあたって,一緒に調べたり考えたりしてくれた同研究室のT氏にはお世話になりました.

 

参考にさせていただいたサイト

scikit learn - How are feature_importances in RandomForestClassifier determined? - Stack Overflow

Random Forestで計算できる特徴量の重要度 - なにメモ

http://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html

http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html

HMMとCRFとの違いについて調べてみた

経緯

系列ラベリングの代表的な手法として HMM と CRF はそれぞれ聞いたことあるし概要は本を読んでわかったつもりになっているけど,どうもそれらの違いがわからないなぁ...と思ってちょっと調べてみた.意外と日本語の記事が見つからず,英語の記事でいいものがあったのでそれの翻訳兼要約としてまとめる.英語に抵抗感がない人は元記事へ.

 

想定する読者

以下の用語を聞いたことがあるかた

ちなみにこの辺りのことは自然言語処理概論サポートベクトルマシンを参考にしてください.

 

 

HMM と CRF との違いは何か

ざっくり言えば

HMMはナイーブベイズを,CRFはロジスティック回帰を用いる.

 

以下詳細

以下では入力系列をX=(x1, x2, ..., xi, ..., xn),ラベル列をY=(y1, y2, ..., yi, ..., yn)とする.

 モデリング対象としている確率分布

HMM: XとYとの共起確率 P(X, Y)

CRF: Xが与えられた時のYの条件付き確率 P(Y|X)

 学習の仕方

HMM: 学習データ中の出現頻度をカウント.またはEMアルゴリズムなどを用いて出現確率や遷移確率を推定.

CRF: 勾配効果法 (SGD) などの最適化アルゴリズム

 HMMの方がCRFよりも早く学習されるが,CRFの方が推定精度や偏りのある学習データへの頑健性などの面で強い.

 系列全体の依存関係への挙動

(単純な)HMM: Xとyiとの依存関係を直接モデル化できない.

(単純な)CRF: Xとyiとの依存関係を直接モデル化できる.

CRFはラベル全体の分布Yをモデル化するだけであり,入力系列全体の分布Xを考慮しない.これに対しHMMは共起確率をモデル化する際にXとYの両方を考慮する必要がある.したがって,CRFはXのyiへの影響を直接モデル化することができる. 

ほかの記事では

HMMはP(X, Y)をモデル化しているのに対してCRFはP(Y|X)をモデル化している.このためHMMでは P(X) = ΣP(X, Y) を行うことで,P(X)を求めることができる.P(X)は入力系列Xの確からしさを表しており,つまりはXに対する全てのYのスコアを足し合わせることで言語モデルとして使うこともできる.

 

あとがき

今回HMMとCRFとの違いという観点から両手法への理解を深めた.HMMは共起確率を,CRFは条件付き確率をそれぞれモデリングの対象としていることが全ての違いの中心にあると感じた.

余談であるがこのブログが私の初めてのブログである.間違ったことはいえねぇと,色々な書籍を引っ張り出して復習した.ブログむずい....

ここまで読んでいただきありがとうございました.私の理解が足りていないところなどがあれば,なにとぞ優しくまさかりを投げてください.

今回の執筆にあたって,一緒にCRFのことを調べたり考えたりしてくれた同研究室のT氏とT氏には大変にお世話になりました.

参考にさせていただいたサイト

What is the difference between HMM and conditional random field? - Quora

きまぐれ日記: CRF と HMM

https://www.cs.cmu.edu/~epxing/Class/10701-08s/recitation/em-hmm.pdf