競プロ用オレオレ環境ジェネレータを作った

はじめに

この間、競プロ始めました。

去年の10月くらいから興味が出てきていたんですが(主にKaggleの人たちが競プロをやっているのを見て)なかなか腰が重くしばらく様子見していました。

最近、ちょっと暇ができたタイミングでちょうどAtCoderでABC120をやっていたので始めてしまった、というわけなんですがしばらくやってみて忙しくて手が回らさそうならやめてしまうかもしれません(と予防線だけ張っておく)。

とまあ、一回しかまだやっていないわけですが一回やってみて思ったのはAtCoderのサイトのエディタでやるのはちょっときついと(それはそう)。

そこで、手元の環境で競プロ用のコードをかけるように環境構築していたんですが、今回はその記録になります。

コード類は、

github.com

においてあります。

環境構築の詳細

実行環境

Docker使いました。

Dockerfileはこんな感じ。

FROM ubuntu:16.04
RUN apt-get update &&\
    apt-get install -yq software-properties-common

RUN add-apt-repository universe &&\
    apt-get update &&\
    apt-get install -yq g++ libboost-all-dev cmake make gdb &&\
    apt-get clean &&\
    rm -rf /var/lib/apt/lists/*
RUN mkdir /app
WORKDIR /app

CMD ["/bin/bash"]

出来るだけ実際の実行環境と同じような環境を作りたかったのでDockerを使うことにしたわけですが、やっぱりDocker便利ですね。

docker runコマンドも手打ちするのが面倒なのでmakeを使います。

Makefile(抜粋)はこんな感じ。

IMAGE := competitive:1.0

build: Dockerfile
    docker build -t ${IMAGE} .

env:
    docker run -v `pwd`:/app -it ${IMAGE} /bin/bash

環境ジェネレータとは

コンテストごとに、プログラムを書くディレクトリ構成を複製したかったので'環境ジェネレータ'です。

treeコマンドでジェネレートしたディレクトリ構成をみてみると

ABC119/
├── Makefile
├── README.md
├── build
├── cases
│   ├── a
│   │   ├── 0
│   │   │   ├── answer.txt
│   │   │   └── input.txt
│   │   ├── 1
│   │   │   ├── answer.txt
│   │   │   └── input.txt
│   │   └── 2
│   ├── b
│   │   ├── 0
│   │   │   ├── answer.txt
│   │   │   └── input.txt
│   │   ├── 1
│   │   │   ├── answer.txt
│   │   │   └── input.txt
│   │   └── 2
│   ├── c
│   │   ├── 0
│   │   │   ├── answer.txt
│   │   │   └── input.txt
│   │   ├── 1
│   │   │   ├── answer.txt
│   │   │   └── input.txt
│   │   └── 2
│   │       ├── answer.txt
│   │       └── input.txt
│   └── d
│       ├── 0
│       │   ├── answer.txt
│       │   └── input.txt
│       ├── 1
│       │   ├── answer.txt
│       │   └── input.txt
│       └── 2
├── jobs.sh
└── src
    ├── a.cpp
    ├── b.cpp
    ├── c.cpp
    └── d.cpp

19 directories, 25 files

といった感じになります。

srcが各問題に対応したC++ソースファイル(当然ながら解法まではジェネレートしてくれません)が入り、buildはコンパイル済みオブジェクトが入ります。

casesには、それぞれの問題のテストケースが入ります(この部分はスクレピングで取ってきています)。

README.mdには問題の説明が入り、実行制御用のMakefileとjobs.shはテンプレートをコピーしてきています。

Makefileのテンプレート(抜粋)は

CXX := g++
ACPP := src/a.cpp

CFLAGS := -O2 -Wall -std=c++11 -DDEBUG
A := build/a.out

prob-a: ${A}
    ./jobs.sh ${A} a


${A}: ${ACPP}
    ${CXX} ${CFLAGS} ${ACPP} -o ${A}

みたいな感じになっています。make prob-aコンパイルから答え合わせまでやってくれます。

jobs.shの中身は

for f in 0 1 2; do \
  ./$1 < cases/$2/$f/input.txt > cases/$2/$f/output.txt; \
  diff cases/$2/$f/output.txt cases/$2/$f/answer.txt; \
done

となっています。input.txtの中身を標準入力で読んで、output.txtに標準出力で吐き、diffでanswer.txtとの差分を取って答え合わせをするという流れが書いてあります。

ジェネレート部分

ファイル生成はシェルで行います。

if [ ! -d $1 ]; then \
  mkdir $1; \
  cp Makefile.template $1/Makefile; \
  cp jobs.sh.template $1/jobs.sh; \
  mkdir $1/src $1/build $1/cases; \
  touch $1/build/.keep $1/cases/.keep; \
  for f in a.cpp b.cpp c.cpp d.cpp; do \
    touch $1/src/$f; \
  done; \
fi

あらかじめ書いておいたテンプレートをコピーして、所定の手続きでディレクトリやらファイルやらを作るだけです。

README.mdへの問題の書き出しとテストケースの取得はPythonで書いていますが、ちょっと長くなるので割愛します。

コンテストごとにそんなに問題の書き方は変わらないよね?という前提で処理しています。

まとめ

こんなことばっかりやっているので積みタスクが増えていくわけですが、競プロもできたら頑張りたいですね。

オレシカナイトデータコンペティションで優勝しました!

はじめに

サイバーエージェント主催の『オレシカナイト』データ分析コンペティションに参加し、優勝しました!

cyberagent.connpass.com

実際の分析時間はトータルで6時間程度でしたので初期の戦略で大きく結果が左右されるコンペでしたが、Kaggleエキスパートも数人参加する中で 非常にいい経験となりました。本記事では、運営の確認の上で、問題のない範囲でコンペの概要や解法を紹介します。

なお、今回のコンペで二位に輝いたupuraさんもこのコンペについて記事を書いております。

upura.hatenablog.com

コンペの概要

オレシカナイトについて

オレシカナイトとは、AbemaTVなどを運営するサイバーエージェントのアドテクノロジー開発を行う部門主催の技術者向けの勉強会だそうです。機械学習に限らずアドテクに関連する様々なテクノロジーについての講演、LTなどが過去にも開催されているようで今回のコンペはそのスピンオフとのことでした。

ちなみにこの「オレシカナイト」の由来はコンペ開催前から気になっていたのですが、ゲーム「俺の屍を越えてゆけ」が元になっているようで「自分や他の人の失敗を糧にみんなに成長してもらえるよう共有する」ということが目的となっているとのことでした。

コンペについて

今回のコンペは実は全く同じデータ・問題設定の学生向けイベントが以前に開催されていたとのことで、その時の上位3名のスコアがリーダーボードに表示されているなど若干の緊張感を煽られるコンペでした。上位3名のスコアはかなり高く正直抜くのにかなり苦労しました。運営の方も、学生のレベルが上がっていると言っており、同世代の人間がデータ分析という世界でも活躍し始めていることを実感させられました。

f:id:koukyo1213:20190128233054p:plain
最終的なリーダーボードの様子。上位3-5位が前回の1-3位でした。背景が花火なのは一位になった時に表示される特別仕様です笑

本コンペの参加者は15名で、うち自分を含めた3人が学生でした。
本コンペではAbemaTVのデータを用いて、そこに配信される広告が実際にどの程度閲覧されるかを予測しました。
学習データは2ヶ月分与えられており、それを用いて直後の1週間分のデータに対して予測を行うというもので、時系列性を考慮することが一つの鍵となっていることが特徴的でした。

個人的には時系列性を考慮するまでには至らず、一般的なテーブルデータに対して行われるようなモデル作成を最後まで行なっていましたが、後から考えると時系列性を考慮した特徴を作れていればさらにいい結果が得られていたかもしれません。

データの内容としては、

  • チャンネル内での広告の配信位置などを示す広告枠に関する情報
  • CMの開始時刻などの配信タイミングに関する情報

など、時間に関する情報とターゲットを除いてカテゴリ変数のみで構成されたもので、カテゴリ変数の扱い方が問われたコンペティションでもありました。また、ほとんどの情報は匿名化、符号化されている点も特徴的でした。

データ数はtrainが543万レコード、testが59万レコードで全体としては300MBほどでしたが、全てがカテゴリ変数なため密行列表現でone-hot化すると自分の16GBメモリPCがメモリエラーを起こすくらいの大きさに膨れ上がります。そのためか、メモリ不足との戦いで苦慮している方も散見されました。

なお、このデータは実際のデータを間引いたりして、(おそらく)各カテゴリの間の偏りをならすなどの整形がされており実際の業務で触る際はさらに様々な困難があることが伺えるデータでした。普段のデータハンドリングはSQL(BigQuery)を用いているとのことで巨大データとの格闘というアドテクらしい話も垣間みえていました。

精度評価は広告配信という分野の性質から下記のような独特なものが用いられていました。

  • ユーザをあるまとまりで分類し
  • まとまりの中での予測閲覧数と実際の閲覧数との比をとり
  • 比が0.9より大きく1.1未満であった時にそのまとまりの得点がえられるとして
  • 全てのまとまりに対する、得点が得られたまとまりの比を最終的なスコアとする

という指標でした。この指標が使われる理由として、予測値が実際の値よりも大きすぎても小さすぎてもいけないというビジネス上の制約があるというものが挙げられていました。すなわち、

  • 大きすぎた場合、本来の料金より低い料金で広告枠を提供してしまったことになり割引に当たる、またその広告枠を他の広告に提供できたはずなので機会損失と捉えることもできる。
  • 小さすぎた場合、一定の閲覧数以上を提供するという契約に違反したことになり違約金が生じる

という不都合があるとのことで、閲覧数予測はビジネス的にも大きな価値を持ったタスクであることが伺えました。

このスコアを大きくすることが今回のコンペの目的で、最終的な優勝もこのスコアを元に決められていましたが、参考値としてMSEも計算されてリーダーボードに表示されるようになっており、これを一番低くした3名にも商品があるということでした。僕は欲張りなのでスコアの最大化とMSEの最小化を同時に行なって両方で同時優勝を目指していましたが、このスコアをあげるとしばしばMSEも上がるといった逆転現象が起きることも今回のコンペの特徴で、参加者を大いに悩ませた一因でもありました。

また、リーダーボードのスコアはそのまま最終的なスコアに用いられるものでしたのでLBプロービングなどが行えるというやや不健全なものでしたが、ルールの範囲内でしたので有効活用させていただきました。

自分の取り組み

解法

自分の取り組みはかなりオーソドックスなテーブルデータに対する手順を踏んでいたかと思っています。

特徴は、

  • カテゴリカルな特徴はそのまま用い、時間に関する情報のみ曜日・時間(hour/min)のカテゴリ特徴に直したもの
  • それらカテゴリ特徴をTarget Encodingしたもの

の二種類を用意しました。upuraさんの解法にあるような時間の循環性を意識したエンコード手法には思い至らなかったため時間に関しては非常にシンプルにカテゴリ化しています。

やや特徴的な点があるとすれば、Target Encodingではmeanだけではなくmax、std、median、skewも計算していたことと、これは主に時間的な制約が厳しくて手が回らなかったためですがTarget Encoding時に弱リークが発生しないようにCVで計算するなどの工夫は行なっていないことが挙げられます。

また、この二種類の計算方法を、

  • 与えられた2ヵ月分のデータ全てに対して計算したもの
  • テストデータに近い1ヵ月分のデータのみに対して計算したもの

の二種類を用意しています。すなわち2×2の計4種類のデータセットを使っています。

これらのデータをLightGBMに5fold CVで流し、出てきた結果をブレンデッドアンサンブルしたものが最終的な提出ファイルとなりました。LightGBMのハイパラチューニングなどは手作業で少し行なったのみで概ね、Kaggleのメルカリコンペに参加した際に用いていた値を流用しました。

結果として、最終的には性質の異なるデータセットを複数用意できたことが勝因と考えています。

f:id:koukyo1213:20190129202146j:plain

戦略

upuraさんは実応用の観点も持ってシングルモデルにこだわっていらっしゃったとのことでしたが、自分はのっけからアンサンブルする気満々でしたのでいかに多種の性質の違うモデルを作れるかどうか、という一点にかけた戦略をとりました。このためには実験量がある程度ものをいうと考えていたため、自分のローカルPC(MacBook Pro) + Google Colaboratory4枚(自分の個人のアカウントと大学での個人アカウントでそれぞれCPUとGPUの2枚ずつ)の5環境での並列実験を行いました。

具体的には、ローカルでは一番勝率が高そうな取り組みを計算しつつ、ColaboratoryではMLPや線形モデル、CatBoostなどJust Ideaだけどモデルの多様性に寄与しそうなアイデアを試していくということを行いました。Colaboratoryで計算した結果で最終的なモデルに寄与したものは実はなかったのですが、時間がかかりそうなアイデアも他の環境に投げれば手元で他のことができるという安心感から試したいことを思いっきり試せたのも優勝の遠因かと思います。

なお最終的にはLightGBM一本に絞ったものの一番最初は非常に素朴にone-hot表現+Ridge回帰からはじめ、多項式ベースの手法もいくつか試していましたがどれもうまくいきませんでした。これは、ほとんどすべてがカテゴリ特徴だったからと考えられますが、単純な線形モデルでもある程度の精度を出せるだろうと考えていたので結構面食らいました。

所感

自分はこうしたオフラインコンペに参加するのは初めてでしたが、新たな楽しみを覚えてしまいました。Kaggleとはまた少し違った能力が問われるため新鮮な気分で臨むことができたのですが、ちょうど手の速さを強みにしていきたいと考えていたところでしたので自分の現状を評価する上でも非常にいい機会となりました。

個人的には、今回のように限られた時間の中で競いながら精度を高め合うというのはかなりうまく自分にハマっていると感じたので、今後もKaggleなどのコンペでも同じチームの人と1日かけて競い合いながら精度を向上させるようなハッカソン的な枠組みを取り入れていけたらと感じています。

運営の方々のサポートも素晴らしく、1日を快適に過ごすことができました。

f:id:koukyo1213:20190129220556j:plain
お昼の高級弁当

f:id:koukyo1213:20190129220637j:plain
差し入れのシュークリーム

f:id:koukyo1213:20190129220722j:plain
懇親会のお寿司

個人的にはSlackのtimesチャンネルで騒ぎながら競技に臨めたのが非常に楽しかったです。このような場を提供してくださった運営の皆様方、そして競技を盛り上げてくださった参加者の皆様、ありがとうございました。

Kaggle APIとSlack APIとGoogle Apps Scriptで新規カーネル投稿を監視する

はじめに

最近Kaggleにハマっています。今はQuoraのコンペをやっているところです。

NNなんも分からんけど楽しい!

Kaggle Advent Calendarのu++さんの記事を読んで自分も新規カーネルの投稿を監視する仕組みを作りたくなったのですが、u++さんの方法は自分のMacが通信できる状態にないといけないため、一番カーネルを読む時間が取りやすい電車内などで新規カーネルの投稿を監視できなくなってしまいます。

upura.hatenablog.com

家のデスクトップでcronで叩いてもよかったのですがそのためだけにデスクトップを立ち上げておくのも少し気がひけるので今回は、スクリプトの定期実行が無料で簡単にできるGoogle Apps Sciptを用いてシステムを構築してみました。

コードは下記のリポジトリにて公開しています。

github.com

全体像

システムの全体像は

上の図のようになっています。全体の流れは以下の通りです。

  1. まずGoogle Apps ScriptからKaggle APIのエンドポイントを叩き、現在あるカーネルのリストを入手します。
  2. 次にこのリストをGoogle Spreadsheet内に作った簡易データベースと照合し、新しいカーネルがないかを調べます。
  3. 新しいカーネルが見つかった場合は時系列昇順に並べてシートの行末に追記していきます。また、新しいカーネルについてはSlack APIと連携して自分用slackにも通知を飛ばします。

Slack通知の様子

Kaggle APIカーネルのリストを入手するとJSONの配列の形で送られてきます。1つ1つのカーネルに関してはかなり多くの情報が用意されているのですが(タイトル、作成者、GPU onかどうか、などなど)ほとんどがnullになっているので、実際に使えるのは、タイトル、作成者、オリジンからのパス、更新日時くらいかと思います。

これらを少し整形して送っている様子が上の通知の画像です。

使ってみて

やはり一覧表示されていると情報量に圧倒されてしまうので、変化があったときにだけ見るのは非常に役立っています。これからもどんどん利用していきたいと思います。

技術的な話

Kaggle APIについて

今回は公式が出しているKaggle APIクライアントを使えないので、APIクライアントのソースを読んでエンドポイントの叩き方を調べる必要がありました。

github.com

このAPIクライアントはSwaggerのコードジェネレート機能を用いて構築されているらしく読んでいてなかなか勉強にもなりました。

まず、APIのエンドポイントについてですが、KaggleSwagger.ymlの中に記述されています。

また認証に関しては、複数のファイルに分散していますが、kaggle.jsonの情報を用いてBasic認証を行なっているようです。この際のエンコーディングなどはconfiguration.pyで行なっています。

挙動を定義するために--competitionなどで与えるパラメータはURLの中にクエリパラメータとして入れることができるようになっています。

Spreadsheetによる簡易DBについて

Google Apps Scriptの強みはやはりGoogleのサービスを操作できることかと思います。

今回はKaggle APIで作成日順にソートとして得られたカーネルの情報を、初回実行時にスプレッドシートに順に入れておき、次回以降Kaggle APIを叩いて得られたときはJSON配列とスプレッドシートの中身の配列の長さを用いて新規カーネルがあるかどうかを判定しています。

また、このように順番をソートしておくことで新しいカーネルがあった場合もソートされている上位n個のカーネルが新規である、と判定することができ、過去に投稿があったものかどうかの判定が簡素になっています。

Slack連携

Slackへの通知はGASライブラリSlackAppを用いています。

このライブラリを使うことで、SlackのAPIトークンを渡すだけでSlack通知ができるようになります。

テスト

今回は小規模なのであまり必要はないのですが今後拡張することも考えてGSUnitを用いてテストを行っています。

クレデンシャルの扱いについて

Google Apps Scriptでは、クレデンシャルなどのハードコーディングを防ぐ仕組みとしてPropertiesServiceというものがあります。これを用いることでキー:バリューの形で保存したプロパティを呼び出すことができます。

今回はこれを用いてSlackのAPIトークン、Kaggle APIBasic認証トークン、そしてspreadsheetのIDを保存しています。

なお、この情報はWebUIなどでみたときには普通に見えてしまうため、共用のアカウントなどで行うことはオススメしません。

深層カルマンフィルタについて(1)

この記事は東京大学航空宇宙工学科/専攻 Advent Calendar2018の七日目の記事として書かれています。

adventar.org

昨年はカルマンフィルタについての記事を書きましたが、今年は引き続きカルマンフィルタについて書いていきます。といっても一年前と同じことを書いても芸がないので近年流行りのディープラーニングを用いた「深層カルマンフィルタ」[1] に関するお話です。猫も杓子もディープラーニングな時代ですから航空宇宙工学専攻でもきっとディープラーニングが花開いているんですよ、多分。

はじめに

去年に引き続きAdvent Calendarの記事がやって来たわけで、昨年のカルマンフィルタの記事が比較的好評だったのもあって、今年も真面目に専門的な話題を書いていこうと思ったわけですが、ふとすると専門無し弱者になりがちな弊学科にあって研究テーマに悩みに悩んで大した研究もしてこなかった僕としては専門的な話を他の優秀な学科民のようにはできないような気がしてしまったりしまわなかったりします。

仕方ないのであえて言うなら専門と言えないでもない状態推定のお話をしようと思ったわけですが、せっかくなので流行りに乗ってディープラーニングでもしてみむとするかと思い、深層カルマンフィルタの記事を書くことにしました。そこで早速深層カルマンフィルタについて調べ始めたのが、この記事が公開される一週間前とかになります。

なにが言いたいかと言うと、ドシロートが雰囲気で書いている記事なので大目にみてくださいよろしくお願いします。

事前知識

カルマンフィルタの復習

カルマンフィルタは、「モデルがわかっている線形システムに関して、観測誤差による影響と状態遷移誤差による影響を上手に扱うことにより精度よく状態推定を行う関数」でした。去年と微妙に文言が変わっていますがお気になさらず。

ここでキモになってくるのが、「線形モデルが分かっている」ことと「誤差に関する情報は事前に分かっている」ことが前提にある点です。現実的には線形モデルではうまくいかない場合は数多くありますし、そもそも数理モデルが存在しなようなシステムというのも一般には存在します。また、観測誤差、状態遷移誤差も実際のところ事前に確率分布が分かっているということは多くはないかと思います。

実際に式を書いてみると、時刻tの状態変数を\mathbf{x}_t、観測変数\mathbf{y}_t、制御入力を\mathbf{u}_tとして

$$ \begin{align} \mathbf{x}_{t+1} &= \mathbf{A}\mathbf{x}_t + \mathbf{B}\mathbf{u}_t + \mathbf{w}_t \\ \mathbf{y}_{t} &= \mathbf{C}\mathbf{x}_t + \mathbf{v}_t \\ \mathbf{w}_t &\sim \mathcal{N}(\mathbf{0},\mathbf{Q}) \\ \mathbf{v}_t &\sim \mathcal{N}(\mathbf{0}, \mathbf{R}) \end{align} $$

と表されるような系が対象となるわけですがこの\mathbf{A}\mathbf{B}\mathbf{C}がわからないような系というのも一般には数多く存在すると考えられます。例をあげるとすれば、

  1. ある講義を受けている受講者の学力の推移
  2. 治療を受ける患者の体調の推移

などが挙げられます1。2.は[1]で論文著者たちが利用法として挙げている例ですね。1.の例を状態推定という枠組みで見るとすれば、学力が状態変数\mathbf{x}_tに対応し観測変数\mathbf{y}_tとしてはテストのスコアが対応するでしょう。制御入力\mathbf{u}_tは講義になります。同様に、2.の例では状態変数が体調、観測変数が検査スコア、制御入力が治療になるのでしょうか?

いずれにせよ数理モデルとしての表現は容易では無いように思える例ですがこのような例に関して推定を行いたいという状況もありうるでしょう。

データからの学習

話は変わって、機械学習にうつります。機械学習、近年大流行りですよね。

先に挙げた数理モデルを論理的に構築する2のが困難な状況においても、データが豊富であればそのデータを使ってなんらかのモデルを構築することはできます。これを可能にしているのが機械学習の技術です。ここで「数理モデル」ではなく「モデル」というぼやかした表現にしているのは必ずしも数式的な表現ができる形になるとは限らないということを表現する3意味合いを持たせています。

最も単純な例として線形重回帰モデルを考えてみます。線形重回帰モデルは、説明変数と目的変数の間に線形な関係が存在するという仮定を置いたモデルになります。つまり、目的変数は説明変数の線形結合(アフィン結合)

$$ \begin{equation} y=\sum_{i=0}^N w_i x_i +b \end{equation} $$

と表されるという仮定を置いています。このとき各説明変数にかけられた係数w_iをデータを最もよく説明するように調節します。この場合であれば、ある説明変数\mathbf{x}_jに対応した目的変数y_jがあるとしてこの説明変数に対してモデルが出力する値を\hat{y}_{j}とするとモデルの予測値と目的変数の値から計算される二乗誤差\sum_{j=1}^M (y_j - \hat{y}_j)^2を最小化するように係数を調節する、などが妥当です。

この例は教師あり学習の例ですが、基本的に教師あり学習はどの手法であっても根っこの部分では同じ思想に基づいていると言えます。すなわち、

  • データには説明変数と目的変数のセットがあります。
  • モデルは説明変数と目的変数の関係を表現するようにフィッティングさせます。
  • フィッティングの作業はモデルの予測値と目的変数の値を近づける4ようにします。

だいぶざっくりした話ですが、この考え方を使えば適切なモデルとデータを用いることで先に挙げた状態方程式・観測方程式が数理モデルとして与えられない場合にも対応できそうな気がします。

とまあ、ここまで話してきたわけですが実のところデータが豊富にあってただ単に説明変数と目的変数の関係が抽出したいのならばカルマンフィルタの良さというのは使うことなく終わるので機械学習のモデルを組めば良いわけです。もう一度カルマンフィルタとは何だったのかを振り返ってみると

「モデルがわかっている線形システムに関して、観測誤差による影響と状態遷移誤差による影響を上手に扱うことにより精度よく状態推定を行う関数」

でした。ポイントとなるのは後半の「観測誤差による影響と状態遷移誤差による影響を上手に扱うことにより精度よく状態推定を行う」の部分です。精度よく状態推定を行うと言っていますが、これは誤差の伝播を評価して事後確率分布の誤差分散が小さくなるようにしていくと言い換えることもできます。

ニューラルネットワークについて

話はニューラルネットワークに飛びます。

ニューラルネットワーク機械学習のモデルの1つになります。さまざまなアーキテクチャやバリエーションがあるためその全てを紹介することは出来ませんが、基本となる部分は同じですのでその部分についてまず紹介します。

ニューラルネットワークを構成するのは人工ニューロンと呼ばれる素子です。ニューロンは複数の入力を受け取り1つの出力を吐き出す関数と見ることが出来ます。人工ニューロン内部では次のような演算を行っています。

  1. 入力の重み付き線形和をとる。
  2. 重み付き線形和の値を非線形な活性化関数に通す。
  3. 活性化関数の出力値を人工ニューロンの出力値とする。

f:id:koukyo1213:20181206131954p:plain
人工ニューロン

ポイントとなるのは重み付き線形和と、活性化関数です。

まず重み付き線形和ですがニューラルネットワークをデータに対してフィットさせるときに調節するのはこの重み付き線形和の各入力に対する重みの値です。この値を適切に調節することで説明変数と目的変数を結ぶ関数を表現できるようにします。活性化関数はの役割は、ネットワークの出力に非線形性を加えることです。ここが線形関数だったり重み付き線形和をそのまま出力していたりするとネットワークは全体として線形になってしまいます。

非線形関数としてよく使われるのはシグモイド関数5

$$ \begin{equation} f(x) = \frac{1}{1 + \exp(-x)} \end{equation} $$

ReLU関数

$$ f(x) = \max (0, x) $$

tanh関数

$$ f(x) = \frac{e^{x} - e^{-x}}{e^{x} + e^{-x}} $$

などがありますがいずれも微分値が存在し6、容易に計算できるものです。これらを使って1つの人工ニューロンを関数として表現すると

$$ \begin{equation} f(x) = h\left(\sum_{i=0}^{N} w_i x_i + b\right) \end{equation} $$

となります。h(\cdot)が活性化関数です。

ニューラルネットワークはこの人工ニューロンを多数まとめた層をいくつも積み重ねるようにして構成し、層から層へ値を伝播して変換を施していくようなモデルです。

f:id:koukyo1213:20181206162355g:plain
人工ニューラルネットワーク

このとき、一番最初の層は説明変数の入力を受け取るため入力層と呼ばれ、最後の層は目的変数の予測値を出力するため出力層と呼ばれます。間の層は中間層、隠れ層などと呼ばれますがこの中間層の存在がニューラルネットワークが複雑な関数に対しても高い近似性能を誇る理由となっています。

深層ニューラルネットワークまたの名をディープラーニングはこの隠れ層が一般に2~3以上になった深いネットワーク構造に対する呼称ですが実際のところ明確な定義はありません。

ニューラルネットワークの学習

ニューラルネットワーク教師あり学習アルゴリズムの1つ7なので、学習データに対するフィッティングの作業があり、その作業が学習と呼ばれるという点は機械学習一般の話と変わりません。この場合もやはり、予測値と目的変数値から計算される損失関数を最小化することでフィッティングを行います。この際には微分が重要となってきます。

人工ニューロンを1つとってみたとき、出力値に対する重みによる微分というものを計算することを考えます。いま、人工ニューロンの入力と出力の計算において

$$ \begin{align} y &= \sum_{i=0}^{N} w_i x_i + b \\ f(\mathbf{x}) &= h(y) \end{align} $$

のように書くことにすると、その出力に対する重み \mathbf{w}による微分とは

$$ \begin{align} \frac{\partial f}{\partial \mathbf{w}} = \frac{\partial h}{\partial y} \cdot \frac{\partial y}{\partial \mathbf{w}} \end{align} $$

となります。この右辺第一項は活性化関数に依存しますが、入力から出力へと値を伝播するとき(forwardといいます)に計算した値を保存しておくことで効率的に計算することができます。

また右辺第二項は入力されたベクトル\mathbf{x}そのものになります。

さて、このように人工ニューロンは出力に対する重みの微分が簡単に求められるのですが、これは多層に重なっていても同じです。同様にして各演算についての偏微分の積になりますので、出力層での出力値に対する第一層の重みによる微分みたいなものも簡単に求められます。

ニューラルネットワークの学習においては、損失関数に対する各重みによる微分というものを計算します。この重みによる微分の意味を考えるとその重みを少しずらした時にどれくらい損失関数の値が変わるかを表現していると言えますので、損失関数の値が小さくなるように微分値を用いて各重みを更新してやれば損失関数を最小化することができます。

もちろん、損失関数は山あり谷ありなことがほとんどですので、単純に損失関数値が下がる方向にだけ調節しても大域的な最適解というものに辿り着かないこともあります。そこのあたりの最適化に関しては今回は割愛させていただきます。

潜在変数モデル

またまた、話は飛びます。カルマンフィルタのような、観測変数の背後に非観測の状態変数の存在を仮定するモデルを潜在変数モデルと言います。潜在変数モデルの考え方は機械学習の世界では非常によくみられます。これは、潜在変数モデルにおける潜在変数の考え方が機械学習の適用先となる現実世界の問題設定によくある階層構造やデータの分布構造をよく表現できているからだと考えられます。

カルマンフィルタは潜在変数が時系列性を持つ隠れマルコフモデルですが、それ以外にも単語群の出現の背後にトピックと呼ばれる潜在変数の存在を仮定するトピックモデルや、変分オートエンコーダも潜在変数モデルの1つと考えることができます。

今回、深層カルマンフィルタを理解する上でこの変分オートエンコーダを潜在変数モデルの1つと考えることがキモとなります。

潜在変数モデルにおいてよく現れる考え方として、潜在変数の分布が観測変数の分布の事前分布となる、すなわち潜在変数の取る値が観測変数を生成する分布のパラメータとなる、というものがあります。実際トピックモデルなどにおいてはトピックと呼ばれる潜在変数の分布をディリクレ分布として仮定し、その値に応じて各単語の出現確率を決定する多項分布のパラメータが変化する、というLDAというモデルが一般的に用いられます。

変分オートエンコーダ

変分オートエンコーダの説明をする前に、オートエンコーダについて簡単に触れておこうと思います。

オートエンコーダは、ニューラルネットワークによる次元削減の教師なし学習アルゴリズムの1つです。オートエンコーダは入力に対応した出力として入力と同じデータを用います。

f:id:koukyo1213:20181207113355p:plain
オートエンコーダの構造

上の図のような構造のニューラルネットワークの入力と出力に同じデータを与えた場合このネットワークが学習するのはなんでしょうか?

左半分のネットワーク、すなわち入力から中間層へと流れていく部分に関しては、層を挟むごとにどんどん層のサイズが小さくなるようにします。これにより、入力データをより圧縮したような中間的な表現が中間層には現れることになります。そして右半分の中間層から出力層へと流れていく部分では、この圧縮された中間的な表現を再度拡張して元の入力と同じようなデータを出力するようにしています。結果としてこの構造をもったニューラルネットワークの入力と出力に全く同じデータを与えた場合には、そのデータの本質的な部分のみを抜き出したような表現が得られると考えられます。この中間表現を得ることは画像や自然言語など情報が疎な構造に分散している場合には有効であると考えられています。

このオートエンコーダを先のニューラルネットワークの学習という観点で見直すと、説明変数と目的変数が同じものになっていると考えれば教師あり学習の枠組みで捉えることが出来ます。したがって出力の予測値と出力(入力)が近づくと小さくなるような損失関数を与えてやりそれを最小化するように学習すればネットワークはそのデータに対してフィットしたということが出来ます。

さて、変分オートエンコーダでは、オートエンコーダでは特に制限を加えなかったこの中間層に関して、多次元標準正規分布に従うような制限をかけることを考えます。これにより、例えば画像群に関してフィットさせると各画像は中間層においては標準正規分布を構成する一点として配置されるようになります。そして、学習データが射影されていない点というのをその正規分布からサンプリングすることで学習データには含まれないデータを得ることが出来ます。このように、学習によって分布を得るような機械学習のモデルを生成モデルと言いますが、これが生成モデルと言われるのは学習データにはないデータも生成できるから、という背景があります。

変分オートエンコーダは、オートエンコーダの中間表現を標準正規分布を構成するような制限をかけたもの、ということはわかりましたがこれをどのように実現するのでしょうか?

世の中には変分オートエンコーダに関する説明がいろいろと溢れていますのでそれらとの差異を出すためにも、ここではお気持ちについて詳しく述べていこうと思います。

まず、標準正規分布を構成するように制限をかける、という点に関してですが、これは「エンコーダでの行き先の分布を標準正規分布にできるだけ近づける」ということを行って実現します。ここで分布同士の近さを表現する指標としてKullback-Leiblerダイバージェンスと呼ばれる指標

$$ \begin{equation} D_{KL}[p(x)||q(x)] = \int p(x) \log\frac{p(x)}{q(x)}dx \end{equation} $$

と呼ばれるものが導入されます。この指標は、分布が完全に一致する場合には0となり、それ以外の場合は正の値をとります。また、一般には非可換です。したがってこの値を0に近づける(=最小化する)ようにすれば、2つの分布は近づいていくことになります。

エンコーダでの行き先の分布を標準正規分布に近づけるためにはエンコーダの出力が分布(のパラメータ)になっている必要があります。したがって、エンコーダ部分に関して言えば、さきにニューラルネットの学習で述べた損失関数としてこのKullback-Leiblerダイバージェンスを設定し、エンコーダの出力としては多次元正規分布のパラメータ\mu\Gammaを設定します。これらの値がKLダイバージェンスを最小化するように学習をすすめればいいのです。

一方で、エンコーダで標準正規分布を近似するように構成された潜在変数をデコーダでは入力データを再構成するように復元してやる必要があります。これを実現するために潜在変数からデコードされたデータと入力データの再構成誤差

$$ \begin{equation} \sum_{i=1}^{D} \left( x_i \log y_i + (1 - x_i) \log (1-y_i) \right) \end{equation} $$

を最小化するようにしてやります。この2つの和を最小化するように学習をすすめることで、エンコーダの行き先の分布を標準正規分布に近づけるようにしながら入力と出力ができるだけ同じようになるニューラルネットワークというものを得ることが出来ます。

f:id:koukyo1213:20181207175757p:plain
変分オートエンコーダの構造

深層カルマンフィルタとは

ここまでくるともうお気づきの方も多いかもしれませんが、深層カルマンフィルタとは状態方程式\mathbf{x}_{t+1} = \mathbf{A}\mathbf{x}_{t} + \mathbf{B}\mathbf{u}_t + \mathbf{w}_tや観測方程式\mathbf{y}_t = \mathbf{C}\mathbf{x}_t + \mathbf{v}_tを深層ニューラルネットワーク(DNN)に置き換えたものになります。

数学的な表現をすると、記号の定義は同じとして

$$ \begin{align} \mathbf{x}_{0} &\sim \mathcal{N} \left(\mu_{0} , \Gamma_{0}\right) \\ \mathbf{x}_{t} &\sim \mathcal{N} \left( G_{\alpha}(\mathbf{x}_{t-1}, \mathbf{u}_{t-1}, \Delta t), S_{\beta}(\mathbf{x}_{t-1},\mathbf{u}_{t-1}, \Delta t) \right) \\ \mathbf{y}_{t} &\sim \Pi (F_{\gamma}(\mathbf{x}_{t})) \end{align} $$

となります。このうちG_{\alpha}(\cdot)S_{\beta}(\cdot)F_{\gamma}(\cdot)の部分がDNNで表現されているというのが深層カルマンフィルタです。この、G_{\alpha}(\cdot)S_{\beta}(\cdot)の部分をエンコーダ、F_{\gamma}(\cdot)の部分をデコーダと考えると、これは変分オートエンコーダに非常によく似たモデルであることがわかります。変分オートエンコーダとの違いがどこにあるかというと、制御入力\mathbf{u}があることと状態変数\mathbf{z}_tが時系列性をもつ、すなわち

$$ \begin{equation} q_{\phi}(\mathbf{z} | \mathbf{x}, \mathbf{u}) = \Pi_{t=1}^{T}q(z_t | z_{t-1}, x_1, x_2, \cdots, x_T, \mathbf{u}) \end{equation} $$

となっている点です。また、用途としても変分オートエンコーダが主にデコーダを用いて未知画像を生成する、といった用途を考えている8のに対し、深層カルマンフィルタではエンコーダ、すなわち観測データと制御入力の系列から状態を推定する方がメインになっている点が異なります。

このq(z_t | z_{t-1}, x_1, x_2, \cdots, x_T, \mathbf{u})はエンコーダ部分に対応しています。デコーダ部分に関して言えばやっていることは変分オートエンコーダと変わりません。

このネットワークの学習においてはどのような損失関数を最小化すれば良いのでしょうか?ここでも、詳細な証明は元の論文[1]が詳しいため割愛させていただくとして、お気持ちだけ書いておこうと思います。

まず、デコーダ部分は潜在変数を入力としてエンコーダに入ったデータと全く同じデータが出力されるようにしたいため再構成誤差を最小化するようにします。この部分は変分オートエンコーダと変わりません。

変分オートエンコーダと大きく異なるのが、状態遷移が存在する点です。結論から言えば変分オートエンコーダがエンコーダとデコーダの2つのネットワークを用いていたのに対し、深層カルマンフィルタではエンコーダとデコーダと状態遷移の3つのニューラルネットワークを使います。ではどのようにしてこれを学習するか、というと初期状態については初期の潜在変数分布とエンコーダの出力の分布を近づけるようにKullback-Leiblerダイバージェンスを最小化するのですが、それ以降の時間ステップに置いては、状態遷移のニューラルネットワークの出力と、1ステップずれた観測変数+制御入力の入力があったエンコーダの出力の分布を近づけるように学習していく、という点が変分オートエンコーダとの大きな違いです。

f:id:koukyo1213:20181207224131p:plain
Deep Kalman Filterのアーキテクチャ

まとめ

今回は深層カルマンフィルタの説明を行いました。変分オートエンコーダの理論的な詳細や深層カルマンフィルタの理論的な説明は僕の理解力不足もあっておざなりになってしまったので今後余裕があったら追加していこうと思います。また、実装に関してもできたらいいなと思っています。かなり中途半端ですが、アドベントカレンダーに間に合わせるために今回は一旦ここで終わりにしたいと思います。

参考文献

[1] Krishnan, Rahul G., Uri Shalit, and David Sontag. "Deep kalman filters." arXiv preprint arXiv:1511.05121 (2015).

[2] Kingma, Diederik P., and Max Welling. "Auto-encoding variational bayes." stat 1050 (2014): 10.

[3] Variational Autoencoder徹底解説
https://qiita.com/kenmatsu4/items/b029d697e9995d93aa24

[4] 猫でも分かるVariational AutoEncoder
https://www.slideshare.net/ssusere55c63/variational-autoencoder-64515581

[5] DL_hacks_20151225
https://deeplearning.jp/wp-content/uploads/2017/07/DL_hacks_20151225.pdf

[6] 深層カルマンフィルタ
http://ubnt-intrepid.hatenablog.com/entry/2016/10/10/205229

[7] 著者GitHub
https://github.com/clinicalml/structuredinference


  1. 正確にはこの二例はおそらく非線形になるので、\mathbf{A}\mathbf{B}\mathbf{C}が分かっていない場合の例としては不適切だが説明の手間を考えてごまかしています。

  2. 論理的に構築する、というのがなんともぼやかした言い方ですが、自然科学の伝統的方法を鑑みるに「データからの法則性の抽出」と「法則性の適用と組み合わせ」によって数理モデルは成り立っているというのが個人的な見解です。この「法則性の適用と組み合わせ」を「論理的に構築する」と表現したつもりです。

  3. 数理モデルの定義としてこれが妥当なのかはよくわからない。

  4. 近づけるという表現が結構曖昧ですがまあここはごまかしています。

  5. \expの中身に実数倍かけたものであることもあります。

  6. 正確にはReLUはx=0微分不可能であるが劣微分により、x > 0で1、x \le 0で0とする。

  7. それ以外の使い方もありますが

  8. 違うかもしれない

GCI優秀者研修旅行【パリ編】

はじめに

この記事はGCI優秀者研修旅行のパリ編です。

GCI優秀者研修旅行とはなんぞや?という方はこちらをご覧ください。

パリ到着 - 夜まで

前の記事ではユーロスターでパリに向かうところで終わったのでその続きから始めます。

パリについたのはお昼すぎだったのですが、なかなかタクシーが捕まらず徒歩でホテルまで行きました。パリはひったくりが多いと聞いていたので内心結構警戒心強めでした。

f:id:koukyo1213:20181025112928j:plain
道すがら見かけた教会

ついてからしばらくホテルにチェックインできなかったのですが、荷物を置いたらすぐに次の訪問先のEcole42に向かいました。

f:id:koukyo1213:20181025114005j:plain
パリのホテルの中庭

Ecole42

Ecole42はパリにある私設のプログラミングスクールです。学校、と言っても卒業することで特別な資格がもらえるわけではないとのことでしたが、それでも毎年1万人以上の応募があるのだとか。その秘密はいくつかあるのですが、いくつか紹介しようと思います。

f:id:koukyo1213:20181025114732j:plain
Ecole42

この学校の面白いところは先生がいないことです。いるのは生徒とスタッフだけで基本的に生徒たちは用意された課題(プロジェクト)を解いて行くという形で学習をして行きます。

f:id:koukyo1213:20181025144927j:plain
Ecole42のシステム

生徒たちは上の写真のようなシステムを用いてプロジェクトを進めます。この水色になっているところがすでに完了済みのプロジェクトで、やや明るい灰色の部分がこれから始められるプロジェクト、暗い灰色の部分はまだ手をつけることができないプロジェクトです。このプロジェクトは、スタッフが用意したものもあれば、生徒が作ったものもあるとのことでした。

扱う内容は多岐に渡り、シェルの作成やWebプログラミングからOSやセキュリティ、アルゴリズム、果ては機械学習まで様々なものが用意されているとのことでした。

卒業の要件というものは明確に定められていないとのことでしたが、学生たちは入学するとまずピシーヌと呼ばれる一連のプロジェクトに携わることになります。この期間は、他の学生から助けを受けることができず自分一人でやり方を発見していかなければいけない期間ということですが、これを修了するとその後は、すぐにやめてもいいしそのまま続けても良いとのことでした。

さらにこのEcole42がすごいのはこの環境が無料で提供されていることです。この学校はフランスの大富豪による寄付で成り立っており、生徒たちは一銭も払うことなく居続けることができるとのことでした。

f:id:koukyo1213:20181025152738j:plain

OECD

f:id:koukyo1213:20181025151854j:plain
OECD

Ecole42での見学を終えた後、僕たちはOECDで松尾先生が講演をするのについて行きました。

ここでは、OECDに日本の様々な官庁から出向している官僚が集まっておりそこで松尾先生が人工知能の導入とその影響や各国の反応などを講演しました。僕たちはそれを傍で聞いているという形でした。

この内容に関しては、松尾先生がよく講演しているもの(年間200回以上同じ内容の講演をしているとのことでした)でしたが、それを聴く人たちの反応を見ているのはなかなか面白かったです。松尾先生も話し方を僕たち学生にするときとは少し変えていて、あとでそのことについてお聞きしたら話の掴みで何人かよくうなずく人を見つけておき、その人たちの反応を見ながら聴衆に合わせた難易度の話し方をするようにしているとのことでした。

食事

この日の夜はフランス料理を食べましたが、お肉とレモンキャビア?みたいなのが美味しかったです。

f:id:koukyo1213:20181025152945j:plain
お肉

2日目-パリ観光とベルリンへの移動-

2日目はある程度の暇をいただいていたので、パリ観光をしました。朝早く起きた組はルーブルに行っていたようなのですが、僕の部屋は二人とも疲れが溜まっていたのかかなり遅くまでダラダラしていたので10時過ぎにホテルをチェックアウトして近場を回りました。

f:id:koukyo1213:20181025153546j:plain
運河

僕は部屋が一緒だったM2の人とその日は行動していました。その人はKaggleエキスパートだったので一緒にKaggleなどについて話しながらあちこちを回りました。最初に行ったのは近くにある運河です。上の写真だとなかなか綺麗に見えますが実は結構緑がかっていてややパリの印象から外れていました。

f:id:koukyo1213:20181025154008j:plain

その後、ピカソ美術館に向かって歩きました。ピカソ美術館はそこそこ広く全部は見切れなかったです。

f:id:koukyo1213:20181025154126j:plain

f:id:koukyo1213:20181025154136j:plainf:id:koukyo1213:20181025154146j:plainf:id:koukyo1213:20181025154152j:plain
ピカソ美術館

その後、空港に向かい、ドイツのテーゲル空港まで行きました。この日は基本的に移動が多い日でそのくらいしかしませんでした。

f:id:koukyo1213:20181025154334j:plain
空港にて遊ぶ人たち

続きはベルリン編で・・・

GCI優秀者研修旅行【ロンドン編】

はじめに

この記事はGCI優秀者研修旅行のロンドン編です。

GCI優秀者研修旅行とはなんぞや?という方はこちらをご覧ください。

出発 - ロンドン到着

成田

今回の旅行は2018年9月24日から10月1日のスケジュールでした。初日はほぼ飛行機で移動だけだったのですが、朝成田空港に集まるところから始まりました。 飛行機の搭乗の時間が11時だったので全体の集合は9時だったのですが、僕はクレカがお亡くなりになっていたので現金を換金したり、保険に入ったりとやることが多かったので 朝8時過ぎには空港についていました。

f:id:koukyo1213:20181003134828j:plain
成田出発

ヘルシンキ

今回はフィンランド経由でイギリスに行ったので途中のヘルシンキで乗り継ぎがありました。ヘルシンキは森の中に転々と街があるといった感じの自然豊かな都市でした。

f:id:koukyo1213:20181003135112j:plain
ヘルシンキの街並み

ヘルシンキ空港の中では待ち時間が少しあったのでみんなで近くのお店でビールを飲みました。

f:id:koukyo1213:20181003135556j:plain
みんなでビール

その後、乗り継いだ飛行機でヒースロー空港に向かいました。ヒースロー空港まではあまりかかりませんでした。ロンドン着が大体現地時間の18:00ごろだったと思います。

ホテル到着

その後、空港でタクシーを捕まえ、ロンドン市内のホテルに向かいました。

f:id:koukyo1213:20181003140012j:plainf:id:koukyo1213:20181003140125j:plain
ホテルの様子

川上さんとディナー

その後、St.Pancras駅構内にあるブリティッシュパブで、現在博士課程に在籍しながらDeepMindインターンをしていらっしゃる松尾研修士卒の川上さんと会食に行きました。

f:id:koukyo1213:20181003140426j:plainf:id:koukyo1213:20181003140437j:plain
ブリティッシュパブの料理

僕はフィッシュ&チップスを頼みましたが、なかなか量があって食べ応えがありました。イギリスの料理はマズイことに定評がありますが、意外なことに美味しかったです。松尾先生いわく最近料理のレベルが上がってきているんだとか。ただし、グリーンピース山盛り(ミント味)、お前だけは許さない・・・

川上さんとの会食ではDeepMind社について色々と聞くことができました。

DeepMind社は会社としては、研究開発組織の色合いがかなり強いらしく、川上さんも会社の利益に繋がるかどうかなどを一切考えることなく研究に専念できているとのことでした。話を聞いただけの印象ですが、大学にも雰囲気は近いのだろうかと感じました。

今回の旅行にはPreferred Networks(PFN)のサマーインターンに参加していた方も二人いたのですが、その人たちの話も聞いたところPFNも雰囲気としてはかなり近いとのことでした。

個人的には、DeepMindは巨大組織のため社員は数千人いるという話は意外でした。その中でも様々なチームがあり活発に動いているそうです。また、論文になるかどうかということを考えながら研究しているわけではないので、論文にはならなさそうな研究も沢山あり、カンファレンスなどでDeepMindとして現れる研究はその中のごく一部なのだそうです。

会社の利益になるかどうかを考えずに研究に専念できる、という環境を維持し続けられることについても質問が上がっていましたが、どうしてそんなことが可能なのかという明確な回答は川上さんにもわからないとのことでした。

その後、近くのKings Cross駅を見に行きました。かの有名な9と3/4番線も見てきました。

f:id:koukyo1213:20181003142003j:plainf:id:koukyo1213:20181003142126j:plainf:id:koukyo1213:20181003142144j:plain
夜のKings Cross

2日目 ATI - RCA - Babylon

朝食と朝の散歩

f:id:koukyo1213:20181003143543j:plain
朝食
朝食がビュッフェ形式だったので欲張って取り過ぎたら食べ切るのが大変でした。向こうの食事は全体的に塩味が強い印象を受けました。

f:id:koukyo1213:20181003143825j:plain
ロンドンの静閑な住宅街
その後、朝のロンドンを散歩しました。ロンドンはこの時期はもう朝は寒いようで、みんな冬服になっていました。

ロンドンは観光地などでは全然ないような場所も全てレンガづくりの街並みが広がっていて街全体としての統一感が非常に美しい都市でした。大通りを歩いていても楽しいですが、一本隣の道に入って地元の雰囲気を味わうのもなかなかよかったです。

f:id:koukyo1213:20181003144012j:plain
浅草 in London
f:id:koukyo1213:20181003143923j:plain
ホテルからの景色

Alan Turing Institute訪問

その後、研修旅行最初の訪問活動としてAlan Turing Institute(ATI)に行きました。ATIは、イギリスの大学が共同で立ち上げたAIの研究機関で発足は2015年とのことでした。

ATIBritish Libraryの一室にオフィスがあり、その前には名前にもあるAlan Turingにちなんで第二次世界大戦の時に使われたエニグマ暗号機が飾られていました。

f:id:koukyo1213:20181003151532j:plain
エニグマ

ATIでは、組織の沿革についての話と、Ph.Dの方が現在研究している内容についての話を伺うことができました。

ATIはAI研究の中でも基礎研究や共同研究に注力する組織で、事業としての展開やユースケースケーススタディなどは行わないそうです。その意味でイギリスのAI研究を下支えする研究機関という立ち位置を担っているという印象を受けました。

その上でATIが初期の目標として掲げているのは、

  • Safe and Ethical A.I.
  • Robotics

とのことでした。Safe and Ethical A.I.というのは研究室でもよく話題に上がる倫理的なAI、説明可能なAIといったAIの課題として話題になっている事柄とかなり近いと感じました。また、Roboticsは松尾先生の講演の中でもあった、機会が目を持つようになったことで今までできなかった領域における自動化が促進される、といった話と近いのかなと思いました。

ATIがSafe and Ethical A.I.を実現するにあたって重要としている事柄は

  • Fairness
  • Transparency
  • Privacy
  • Security
  • Robustness
  • Control

など多岐に渡っていたのですが、その中でもこの時はFairnessに関する取り組みを少しお話していただけました。

ATIが取り組んでいる研究の一つ、Counterfactual Fairness[1]という話をざっくりと聞かせていただきました。非常に大雑把な説明をすると、人間の意思決定を任せるようなシステムにおいて、公平性が担保されているかどうかを確認する手法で、反実仮想的な問いかけをシステムに対して繰り返し結果の出力の変化を観測する方法です。例をあげると、ローンの貸付の審査を行う自動化システムにおいて、ある男性が貸付をするという結果を得たとして、もし仮にその男性のapplicationのうち性別に関する部分だけを女性に変化させたとして結果が貸付をしない、というものになったとしたらそのシステムは何らかの差別的な学習をしてしまっている、と判断する、というようなことだそうです。

この説明は誤りがあるかもしれないので、詳しくは論文を参照していただければ、と思います。

その後、ATIPh.Dとして研究を行なっているAlvaroさんから、交通流の最適化に関する研究についてお話していただきました。 Alvaroさんは航空宇宙の出身で数学の博士を取った後、現在はATIPh.Dとして研究活動を行なっている、という方でした。

Alvaroさんは、ATIで都市交通に関してデータ探索やシミュレーションのテストシナリオを作成するツールの開発や、交通システムに対する変更の影響をシミュレーションなどを駆使して評価するような研究を行なっているとのことでした。交通システムなどの巨大で複雑なシステムにおいてはエージェントの行動がシステムの挙動を変更してしまうような現象が起こる(Knock on Effectと表現していました)ため、適切に影響を評価することは現在になっても難しいとのことでした。

今回はそのAlvaroさんの研究活動の中でも、交通信号の表示の仕組みを強化学習を使って最適化し、信号待ちで止められる車の台数を低減する、という研究に関して発表を聞きました。交通信号のアルゴリズムは、最適化が難しく全体として待ち時間を最小化するような解を得るためには個々の信号の最適化ではうまくいかない、という研究がこれまでになされてきたようです。Alvaroさんはこれに対し、強化学習のアプローチを用いてシミュレータにおいては改善することを確かめたとのことでした。今後は実データでの検証なども視野に入れながら研究を進めるとのことです。

Royal College of Art訪問

その後、Royal College of Art(RCA)を訪問しました。RCAはデザインシンキングなどで有名な大学でした。今回は、たまたまRCAに9月から短期の留学をしている僕の高校同期の磯部くんがRCAツアーのアレンジをしてくれました。

RCAは三つキャンパスがあるそうなのですが、今回はその中でもWhite City Campusを案内していただきました。RCAは、異なる分野、異なるバックグラウンドをもつもの同士が協調することによる可能性を強く信じている大学とのことで、ワーキングスペースの配置なども異なる分野に強みをもつもの同士が隣り合うようにするなどしているとのことでした。

また、学生が発表や自己の作品などを発信する機会を非常に多く取っているとのことでした。

f:id:koukyo1213:20181011175326j:plainf:id:koukyo1213:20181011175312j:plain
RCAで行われた展示会の様子

このような展示会のためのスペースや学生同士が話し合うためのスペースなどがあちこちにあり、空間設計に非常に気を使っている印象を受けました。東大の近辺にもコワーキングスペースのようなものは近年増えていますが、それよりもはるかに多くのワーキングスペースを設けてありました。また、White City Campus自体もそうですし、その隣にある建物もBBCが以前は所有していたとのことでそこにあったスタジオのような設備も使えたりと制作活動に専念できそうな環境が揃っていました。キャンパス内の広場のようなところには、テーブルゲーム台やチェスなどがおいてあり、学生同士が遊んでいました。また、たまに屋外の広場に巨大なディスプレイが出されていることがあるそうで、みんなでサッカーを見たりするそうです。

近くにはEU内最大のショッピングモールがあったり、一室を買うとしたら100万ポンドは下らないだろうというマンション?などがあり賑やかな地区という印象を受けました。

f:id:koukyo1213:20181011180148j:plainf:id:koukyo1213:20181011180154j:plain その後20分ほど歩いて、2日前までやっていたというLondon Design Festivalの会場の一つを見学しました。 f:id:koukyo1213:20181011180646j:plainf:id:koukyo1213:20181011180702j:plain

この場所は、バイオデザインの展覧会場だったのことで、プレハブの一つ一つがバイオデザインの研究室なのだそうです。アイデアはあってもお金や研究環境へのアクセスがない人がかなりの低額でプレハブの研究スペースを借りて独自の研究をすることができるようにしているとのことで研究を支援する環境が整っている街なんだ、という印象を受けました。

その後、案内などもしてくれた磯部くんと個人的に留学についてや今後の身の振り方などについて濃い話をした後、ロンドンでの最後の訪問先のBabylon Healthに向かいました。

Babylon Health

Babylon Healthは医療系AIのスタートアップで創業から数年しか経っていないにも関わらず、海外展開をしていたり400人以上のスタッフを抱えていたりと非常に勢いを感じるスタートアップでした。

Babylonの掲げる医療におけるAIの導入は、病院における医師のサポートや日々の生活における病気予防など多岐にわたるそうで医療という分野で様々に手を広げているようでした。

この時の訪問では、自閉症の早期発見や患者の感じる痛みの検知などに使われる顔画像からの感情分析の話をしてもらいました。 顔画像からの感情分析のタスクは昔からあるタスクで、僕も研究室の大先輩の博士論文などで見かけたことがありますが、CNNによる画像処理タスクの大幅性能改善により新たなブレイクスルーを迎えたそうです。このタスクは顔画像の抽出と画像内の顔の感情分析の二つに大きく分けられます。

顔画像の抽出も現在の最新の成果では、98%以上の精度で抽出できるようになっており、100人以上の顔が写っているような写真からほぼ誤りなく顔を抽出できている様子などは非常に衝撃的でした。 また、感情分析のタスクでは、各感情の間に位置するような微妙な表情の分析が難しいとのことだったのですが、これをAction Unitという人間の顔で変化しやすい点を事前知識として定義するという比較的古典的な手法と各Action Unitがどのような値を取っているかという関係をグラフとして扱ったMarcov Random Fieldの学習として解くことで大幅な性能改善を行なったとのことでした。

仔細は論文を確認した方がいいのですが、残念ながら論文のタイトルを忘れてしまったのでまた後ほど・・・

食事

その後、RCAの紹介のアレンジメントをしてくれた磯部くんと会食をしました。 f:id:koukyo1213:20181011183012j:plainf:id:koukyo1213:20181011183018j:plain

肉料理にはハズレはなく、食事を楽しむことができました。その後、近くのラーメン屋さんに松尾先生といきましたが、驚いたことに日本のラーメン屋と比べてもまったく遜色ないくらい美味しかったです。松尾先生はどうやら食事に関しては一家言あるようで、旅行中の他の機会にもラーメン屋さんにご一緒させていただきました。

3日目 パリへ移動

3日目は朝早くに起きてパリへユーロスターで移動しました。

f:id:koukyo1213:20181011183652j:plain
St.Pancras
f:id:koukyo1213:20181011183645j:plain
Platform
f:id:koukyo1213:20181011183657j:plain
Eurostar
f:id:koukyo1213:20181011183701j:plain
フランスの田舎

基本的にユーロスターから見られる眺めはずっと広大な平原とところどころある林と、ポツポツと見える町でした。牧歌的な雰囲気がとても気に入りました。

続きはパリ編で・・・

参考文献

[1] Kusner, M. J., Loftus, J., Russell, C., & Silva, R. (2017). Counterfactual fairness. In Advances in Neural Information Processing Systems (pp. 4066-4076).

GCI優秀者研修旅行に行ってきました

はじめに

今日は、9/24-10/1の日程でGCIの優秀修了者が招待される欧州研修旅行に行ってきた記録を残しておきたいと思います。今回のGCIは第5回ですがこの研修旅行は第1回の頃から行っているものとのことでした。年によって行く場所が違うらしいですが、今年は欧州研修旅行として、ロンドン・パリ・ベルリンに行ってきました。

 

非常に内容が濃かったので、ロンドン編、パリ編、ベルリン編の三つに分けてこれから書いていこうと思います。

GCIとは

本編を書くまえにGCIの説明をしておこうと思います。

GCIとは、東京大学 松尾研究室が主催している寄附講座で正式名称は「東京大学グローバル消費インテリジェンス寄付講座」と言うそうです。内容としては、PythonSQLなどからScipyやPandasなどの科学技術計算には欠かせないツールの使い方、そしてマーケティング的思考や分析の手法など幅広い内容を取り扱う、データサイエンスの入り口のような授業です。

 

学部1年生から博士課程の学生、また社会人に向けても門戸を開いており、単位は出ないにも関わらず例年定員を大きく上回る受講希望が届けられているとのことです。

 

今年は、授業内にKaggleのようなデータ分析コンペが取り入れられたこともあり、楽しんで参加することができました。

優秀修了者の条件

GCIの修了条件は、毎回の授業で出される課題を全て提出していること、授業を4回以上欠席していないこと、でした。その上で、今回の優秀修了者として選ばれたのは、1回でも授業内のデータ分析コンペで3位以内に入賞しているか、最終課題で優秀な成績を納めたと認定されたか、と言うことで選ばれていて全部で10人程度だったかと思います。

ロンドン編

koukyo1213.hatenablog.com

パリ編

koukyo1213.hatenablog.com

ベルリン編

近日公開予定です。