修行の場

知人が言っていました。これは修行だと。

面接想定のコーディング問題は最低でも月一くらいで解いたほうがいいのでは?

コーディング問題、面接、実務の違いと関係

最近、毎日コーディング問題を解くようにしておりますが、 実務にも良い影響があると思ったため、 考えを整理しておきます。

ここでいうコーディング問題は TopCoderとかleetcodeのコーディング問題です。

コーディング問題で求められる能力には次のような能力があり、 コーディング問題をうまく解くようにすることで、 これらの能力の向上が期待できます。

  • 経験と知識を使い効率よく実装する
    • 類似の問題を探して解を再利用する能力
  • 効率の良いアルゴリズムを探す能力
  • バグのないプログラムを書く能力(コードのシミュレーション能力)
    • 凡ミスをしない、気付ける能力
    • コーナーケースへの注意力
    • 副作用があるコードを書く場合は順序に気をつけられる
    • ライブラリや言語機能の詳細への配慮
  • テスト能力(問題やコードの理解)
    • 入力パターンを分割してグループごとに検証する能力

面接では次のことが必要です。

  • 例を作ること、不明確な場合の入力・期待出力ペアを対話により作ること
  • PC無しでのコードの確認。詳細なデバッグなし。
  • うまく図示したりきれいなコードを下記、して、自分自信や他人とともにプログラムの検証をする

実務で必要とされること、訓練できることは次の能力です。

  • 問題を問題として切り出す能力
  • 制約に応じて問題を説かないという判断もする

実務では、うまくして問題を解くことを回避することもできます。 面接が最も制約が強く、あえてこの強い制約を加えて問題をとくこと、すなわち、 時間を制約を加えたり、printデバッグやプログラムの実行をしないといった制約を加えることで、 より時間を意識したり、頭の中でプログラムをシミュレートする能力があがり、 より正確なコードをより早く書けるという効果が見込めるのではないかと思っています。

また、実務で得た知識やCSの知識を結合する効果もあるように感じました。

心構え

私はleetcodeのsubmitをWebサービスのデプロイ、 testcaseをユニットテスト、 errorを障害と見立てて問題を解いています。

このように自分の実務と結びつけて問題を解くことで、 より効果的な練習となるのではないかと思います。

実務でも役立ちそうと思ったこと

使う言語の言語機能や標準ライブラリの詳細把握

コードを書く際はできる限りコーナーケースまできちんと意識して書く。 これは実際にプログラム書くときもできる限り意識したり、 ハマったものは覚えておいたほうがいいと思います。 ライブラリの同じミス、類似したミスは二度と踏まないくらいの心意気で。

アルゴリズムや理論を検証できるレベルで言語化・図示

アルゴリズムや理論をわかりやすく言語化したり、 図示したりすることで、自分自信がアルゴリズムを検証したり、 他人のレビューを受けたりしやすくなります。 

入力空間の効果的な分割

leetcodeでは、テストケースを書くことで、特殊パターンの期待結果が何かを確認できる。 実際の開発では議論によって決めることになると思います。

とにかく、これらの能力を厳しい時間制約の中でやるようにするして、 何度も繰り返すことで実務の質も上がるのではないかと思います。

面接特有の問題

図に頼らず英語で伝える練習をするべき

リモート面接で図を書けるとは限らない(要調査)ので、 言葉で数式やイメージをスラスラ共有できるようにしなければ、 コードを完璧にかけない場合の途中点を得にくくなります。 最悪、ノートツールなどで書いて共有したり、 可能ならホワイトボードツールへの誘導をお願いしたりするのもありでしょう。(要調査)

過剰な読みやすさの追求やエラー処理はしない

手で書いたり補完を使わないこと、 長くても100行程度のコードで済む場合は 変数名など、短くスッキリにしたり、 エラー処理は記号や口頭の説明で済ましたほうが、 本質的な問題に集中できる。

Webページの種類の分類

Webページの種類

Webページを文章の内容ではなく、WebページのWebサイト中の役割で分類する分類器を構築しました。

WebページをWebサイト中の役割で分類する機能があることで、 特定の種類のページを収集できるクローラを開発しやすくしたり、 RSSに依存しないフィードツールを開発できると期待できます。

約100個のWebページに商品ページ、ブログ記事、その他といったタグ付けをしました。

特徴量

HTMLのツリー構造をinorderでトラバースして、 HTMLタグの列を作成、そのHTMLタグ列から作ったuni-gramとbi-gramを結合したものを特徴量としました。

モデル

モデルは3層のソフトマックス分類器、SVM、ロジスティック回帰モデルを試しました。 交差検定を使って評価したところ、SVMで88%の正解率を達成しました。

3層のNNのソフトマックス分類器は凸関数でないこともあり学習が少しむずかしいです。 SVMやロジスティック回帰モデルは100程度のデータ数を適当に突っ込んでグリッドサーチすれば、 それなりの正解率を達成できます。

参考文献

ファッション分野のアプリ

ファッション分野のこと

消費者側としては、自分の服装、髪型、メイクの仕方を変えたりして、 自分を満足させたり、あるコミュニティでのキャラづくりをしたり、異性に気に入られたり、人によって、多様な目的があると思います。

販売者側としては、売れるデザインの商品を出したいなどといったことがあるのではないでしょうか。

ファッション分野では、組み合わせの試行錯誤が必要なコーディネート提案まで出てきている。 ユーザの能動的な検索を支援したり、チャットボットなどで相談に乗るようなサービスもできている。 また、アパレル企業などがブランド計画を立てるためか、流行予測があったり、 パルコなどの小売店が差別化のためなのか、個人に最適化したサービスを提供しているようです。

アプリ

化粧を支援するアプリ

YouCamMakeup

YouCamは使ってみると面白いです。 撮影した写真に対してメイクできます。 ほかにも、meituのmakeup plusやlooksなどがあります。 looksとYouCamMakeupは化粧品の購入もできるようです。

AIスマートファインダー

キャラチェン下地カラー診断で採用されているとのことです。ただ、このWebサービスは色診断のみで、 YouCamについているようなAR機能はついていないようです。

https://www.aiap.jp/case-study.html

服のラインアップ充実化を支援するアプリ

XZ

  • クローゼットにある服を元にコーディネートを提案してくれる。ユーザは服選びを考える時間が減る。もしくは、新しい組み合わせを発見できる。
  • 服はユーザが写真を撮影したり、アプリからの問いかけに答えることで登録できる。

Sensy Closet

  • 質問とAIとのやりとりによるユーザ理解
  • ユーザの嗜好に応じたコーディネートを数あるコーディネートから試行錯誤して提案

Pashaly

  • アップロードした画像を解析してアイテムごとに分解
  • 類似アイテムを検索

Wheretoget

  • 画像をアップロードして、他のユーザにアイテムの入手先を訊く機能がある。

髪型提案

東京大学で制作されたそうです。詳細は不明。

参考サイト

関連する技術

情報検索

見た目による検索はできているようです。Google Lensでは、写真をアップロードすると似たような商品をショッピングサイト横断的に検索してくれます。たぶん、Pashalyでも同じような機能はありそうです。ただ、手触りがどういったものかがわかるレベルなのかは不明です。ある程度は反映されていますが、完璧ではなさそうです。また、zozoでは属性による検索も検討されているようです。 画像入力による検索は結構枯れている感があります。 今後はチャットボットやSiriなどとのインタラクティブな検索が増えていきそうです。

レコメンデーション

東京大学の研究でAIによる化粧が人の化粧を上回っていたり、 meituのアプリで自動的に可愛く補正したりしてくれたりする機能はある。 現実の化粧品で可能な範囲で化粧を提案できれば完璧だと思います。

魅力工学

sijieらのチームが顔の魅力度をよりロバストに数値化するネットワークを提案した。 画像を入力として、魅力を出力できれば損失関数として利用することも可能で、おそらく自動化粧AIは評価ネットワークを使って強化学習のどれかの手法か勾配法を使ったのではないか。 詳細は不明

データセット

顔と魅力度評価がセットのデータセットがあります。

旅行を助けるアプリのまとめ

所感

ホテルやフライトの予約を支援するアプリはかなり多い印象です。 旅行に関する様々な予約をしてくれるチャットボットから、 価格予測機能付きの予約ツール。 予約サイト横断の価格比較ツールなど、 お得で自分にあったものを探すサービスが充実してきている印象です。

アプリ

Utrip

行き先の好きな属性の度合いを選択すると、 行き先の候補を出してくれる。 ただ、旅行先の全体集合が小さく、 検索インターフェースを活かしきれていない。

Deaps

  • ユーザのライブラリの写真やユーザが自ら入力した好みのカテゴリやタグを元に観光スポットをおすすめしてくれる。

Google Trips

  • 都市をインプットとして、おすすめの散策コースを何らかの基準によって2,3個提案してくれる。
  • GmailやInboxのbuy confirmationなどのメールを分析して自動的に旅行に関する情報をまとめてくれる。

Hopper

  • フライトやホテルの価格を予測して、ベストな購入タイミングを教えてくれる。

参考サイト

旅行アプリで使われているML技術

レコメンデーション

ユーザのWebサイト内の行動履歴を元に数ある選択肢の中から少数を提案 * ユーザの検索履歴や予約の履歴を利用 * ユーザにあったレンタカー、ホテル、フライトを提案 * 他の目的地、他の日付のサジェスト

予測

  • 飛行機の価格、ホテルの価格・空き状況の変化を予測して、提案してくれる。
  • 購入のタイミングを教えてくれる。

Sentiment Analysis

  • ユーザ側としては行き先の評価を収集できる
  • 客側としては自分の評価を収集できる

参考サイト

hyper sklearnについて調査した

ライブラリの機能

sklearnのモデル選択、ハイパーパラメータチューニングにhyperoptを使うためのライブラリです。 いちおうぺーぱーらしきものは出ています。

my take

このライブラリのコントリビューションは、 scikit-learn用のパラメータ探索空間を定義したことです。 パラメータ探索空間はconfiguration spaceの部分空間です。

活用方法としては、 そのまま使いつつhyperopt sklearnの探索空間を参考にして、 自前の探索空間を定義してそちらでもhyperoptで探索する。 結果的に良かったものを使う。という流れになると思います。

もしくはデータさえ増えればディープネットが使える見込みがある問題で モデル自体の解釈をしなくていい場合ならば 将来的にディープネットに置き換えられるので 性能差は少ないのでグリッドサーチとか簡単なものを使えばいい気もします。 どれ使っても変わらないでしょうね。

しかも、20 newsgroupsでも最適解にたどり着くのに、 2400evalかかっています。 ざっくりした性能のものをすぐに作りたいと行った場合は、

まとめると、

  • 問題によっては1日回す覚悟で
    • 少ないエポックで試して並列で長いエポックで試したものも作り置き換えるとか
  • SVMとか古典的なモデルで十分な性能が達成できそうで作り込んでいくのなら使ってもいいかも
  • ディープネット使うのならぶん回して、並列でグリッドサーチ。適当に良かったのを使い、最終的にDNNで置き換えるとか

使いどころが難しそうなライブラリですね。

Hyperoptを使ってみた

使い方

中身がわからない関数の最適化をするためのライブラリです。 使い方は簡単で、最適化対象の関数、探索空間、最適点の探索アルゴリズムを指定するだけで使えます。

サポートされている探索アルゴリズムは、ランダムサーチとTPEというアルゴリズムで、 beyesian optimizationは現時点では実装されていないようです。

実装

ドキュメントのサンプルコードを参考にすれば良いです。 sklearnの学習用のコードも書きました。 下記で説明しますが、パラメータの組み合わせによってはハングしたりクラッシュしたりします。 他のカーネルやパラメータの組み合わせでも正しく動く保証はなく、 何らかの対策が必要になりそうですが、ありえない範囲を指定しないといった暫定対策で対応刷ると良いと思います。

Hyperoptがハングする問題

irisデータセットsvm+poly kernelを探索範囲に入れたらhangしました。 多項式カーネルに関して似たような問題は報告されており、 おそらく、どこかで値が無限になってしまったり無効値になってしまったりしているのだと想像しています。 他にもcross_val_score関数がハング刷る問題もレポートされています。 どうも、ドキュメントによると、forkのあとにexecしない場合、生成したプロセスのスレッドプールが壊れて、 タイムアウトによりhangするようです。 この2つの問題を解決して初めて並列実行できます。

AutoSklearnを使ってみた

背景

AutoSklearnを使ってみました。 ただ、実行してみた結果、GridSearch, Hyperoptよりも得られた分類器の性能が低かったです。 autosklearnのバージョンは0.5.0です。 ちなみに、AmazonDeep learning AMIで構築したUbutu1804のEC2インスタンスではエラーが出ます。 クリーニンストールされた、Ubuntu 18.04では動きました。 どうも動かしてみた感じだと、指定したmetricが直接使われているわけではなく、 別の目的関数で探索が行われてそうな感じです。

APIドキュメントとサンプルを元に通り使っただけですが、 私の環境とデータセットではout of boxで使えませんでした。 現状はautosklearnのソースコードを読む必要がありそうです。

ライブラリが提供する機能の概要

シンプルで、

  • classifierとregressorおよびハイパーパラメータの選択
  • データ処理手法の選択
  • 特徴量処理手法の選択

です。scikit-learnベースなのと、 ディープネットモデルは学習に時間がかかることを考えると、 おそらく、データが集まっていないプロジェクト初期段階で活躍する可能性を秘めています。 ただ、今の所、GridSearchやHyperoptの方が使いやすいです。

アルゴリズムの概要

アルゴリズムは論文にさらっと書かれています。

Efficient and Robust Automated Machine Learning

この論文のポイントは次の2点です。

  • meta learningから、ベイズ最適化をwarm startさせたこと。過去にベイズ最適化で学習させたものを、活用。メタ特徴ベクトル間の距離からtopkを選び、そのconfiguration(ベイズ最適化の探索空間の変数)を選び、それらのconfigurationで学習させることからベイズ最適化がスタートされる。空間は2つあって、メタ学習記録用の空間と、configurationの探索空間の2つです。
  • bayesian optimizationとemsemble selectionを組み合わせた点。meta learningは素人でもまっさきに思いつくけど、途中のアウトプットを組み合わせるのは確かにシンプルで効果的。ディープラーニングではEnsembleがbayesian optimizationより最適になりそうとのことです。

メタ学習には140個のモデルしか使われていないようで、 メタ学習で大まかな開始点が決まるから、メタ学習をうまく活用できていないと、 時間をかけても最終的に得られる性能が低くなってしまう懸念はあります。 なので、データセットによっては性能が低くても不思議ではないです。

インストールして実装する

並列実行刷るサンプルが実用的で役立つので、このサンプルを元に拡張しました。 あとは、APIドキュメントが役立ちます。 結果的にできたプログラムはこんな感じです。 あと、この方法に関しては、日本語のドキュメントもたくさんあります。

得られた結果の詳細を見る

期待と異なる結果が得られた場合や、 どういった結果が得られたか詳細を知る方法についてまとめます。 APIドキュメントには学習以外のことが何故かまとまっておらず... 上記サンプルプログラムのIPython内で実行刷る想定です。

Ensembleされた最終的なモデルの分析

Autosklearnの出力はEnsembleされたモデルです。 Ensembleに使われたモデル一つ一つの詳細を見たりできます。 例えば、下記の例はそれぞれの構成モデルのprecisionを計算します。

refitしていない場合は構成要素からはインデックスが返ってくるので変換します。

for m in automl.get_models_with_weights(): 
   print(sklearn.metrics.precision_score(y_test, np.array(automl._automl[0]._classes).take(np.array(m[1].predict(X_test)))))
    

refitしている場合は、素直です。

for m in automl.get_models_with_weights():  
    ...:    print(sklearn.metrics.precision_score(y_test, np.array(m[1].predict(X_test))))

探索された全モデルの分析

探索空間を調べるためのpublicメソッドは提供されておらず、 プライベートメンバにアクセスしなければなりません。 下記のコードは探索された全モデルのprecisionを計算します。

これはrifitしていない場合です。

import pickle 
 
scores = [] 
model_paths = [] 
for model_path in automl._automl[0]._backend.list_all_models(-1): 
    try: 
        model = pickle.load(open(model_path, 'rb')) 
    except EOFError: 
        print(f"skip eof error {model_path}") 
        continue 
    
    scores.append(sklearn.metrics.precision_score(y_test, np.array(model.predict(X_test) + 1)))
    model_paths.append(model_path)
     
scores = np.array(scores) 
scores.max()

refitするとエラーがでますが、原因は不明。 どちらにせよコードを読まないとだめな気がします。