小学生向けディープラーニング体験教室でロボットカーの授業をしました。

maruyama
リサーチャー

2019-06-11 13:05:34

こんにちは。丸山史郎です。

Preferred Networksでは2019年の6/8(土)に小学校高学年向けのディープラーニング体験教室を行いました。
体験教室の内容は大きく3つに分かれており、その中の30分くらいの時間でレゴ® マインドストーム®を使ったロボットカーの体験教室を行いました。この直前に「ものまね」算という形で小学生向けのディープラーニング(機械学習)の解説があり、ここではディープラーニングをロボットに使うとどのようなことができるのかということを実際に体験してもらうことを目的としました。

また、弊社としては小学生向けの体験教室は初めてのことでしたので、ロボットの準備やロボット体験の内容へのアドバイス、当日の運営などを株式会社アフレル様にご協力いただきました。

続きを読む »

ローカル環境のコード差分をリモートで実行する際に再現性を担保できるコマンドラインツール「Git Ghost」公開

Daisuke Taniwaki

2019-05-13 08:00:37

概要

大村谷脇で開発したローカル環境のコード差分をリモートで実行する際に再現性を担保できるコマンドラインツールGit Ghostをオープンソースとして公開しました。このツールを使うことで、試行錯誤しながら実験をするフェーズにおいても、以前修正して実行したローカル環境のコードに簡単に戻ることができます。

開発の動機

機械学習のジョブを実行中に試行錯誤でさらに他のジョブを実行することはよくあります。Git Ghostを作る前では、そのための一番単純な方法として、例えば、ソースコードをgitで管理し、rsyncコマンドでローカル環境での差分をKubernetesクラスターに同期して機械学習ジョブを実行していました。その際、実行したプログラムが良い結果を出した場合に、以前に修正したコードに戻りたいことがよくありましたが、この方法では、gitでソースコードをバージョン管理していても、rsyncで同期したローカル環境での差分についてはバージョン管理がされていないため、以前のコードに戻ることは困難でした。

これに対処するための1つのアイデアとして、ローカル環境での修正を全てコミットしてリモートにプッシュすることがまず考えられます。しかし、たった数文字の変更のためにコミットしてプッシュするのは非常に面倒であり、リモートのレポジトリーがこの細かい修正で汚れてしまうのを好む人はいないでしょう。そこで我々はこのツールを開発することにしました。

使用方法

ローカル環境で行ったfooというファイルの中身をaからbに変更する修正をリモート環境にあるディレクトリーに送りたい場合を考えます。

まず、ローカル環境の差分パッチをGit Ghostで作成します。

$ git ghost push
xxxxxxx yyyyyyy
$ git ghost show yyyyyyy
diff --git a/foo b/foo
index 7898192..6178079 100644
--- a/foo
+++ b/foo
@@ -1 +1 @@
-a
+b

そして、リモート環境に移動し、以下のコマンドを実行しローカル環境の修正を同期します。

$ git ghost diff HEAD
$ git ghost pull yyyyyyy
$ git ghost diff HEAD
diff --git a/foo b/foo
index 7898192..6178079 100644
--- a/foo
+++ b/foo
@@ -1 +1 @@
-a
+b

ローカル環境の修正を簡単にリモート環境に同期することができました。

このようにGit Ghostはすごくシンプルなツールですが、他のツールと連携させることで最大の効果を発揮します。例えば、Kanikoを使ってDocker imageを作成する際にローカル環境の差分を含めることもできます。ローカル環境の差分を含めたDockerイメージを作り、そのイメージを使って再現性のあるジョブを動かすArgo利用例も公開しています。

アーキテクチャ

アイデアは非常にシンプルです。このツールはリモートのレポジトリーに対してローカル環境でのコミットの差分およびコミットされていない差分のパッチを別のリポジトリで管理します。そして、リモート環境でそのパッチを適用することで、ローカル環境を再現します。細かい点ですが、ローカルコミットの差分とコミットしていない差分を別々のパッチで管理することで、ローカルコミットをリモートのレポジトリーにプッシュした際にコミットしていない差分をそのまま使うことができるようになっています。

他のツールや認証情報を不要とするため、Gitレポジトリーをパッチのストレージとして使っています。

我々はこのツールをKubernetesクラスターで使っていますが、その他の環境でも同じように使えるはずです。オンプレミスのサーバーにラップトップでの変更をトラッキングしつつ送りたいという場合でも使えます。

 

是非試しに使っていただいて、GitHubにてフィードバックをよろしくお願いします!

KubernetesのSchedulerを評価するためのシミュレーター「k8s-cluster-simulator」公開

Daisuke Taniwaki

2019-04-11 08:00:27

概要

2018年夏のインターンおよびPEとして勤務した薮内さんとそのメンターである谷脇大村で開発したKubernetesクラスターのシミュレーターであるk8s-cluster-simulatorのアルファ版をオープンソースとして公開しました。このシミュレーターはKubernetesクラスタに投入されるPodのワークロードを時間とともにシミュレートできるため、Kubernetesのスケジューラーを本番環境に投入する前に評価することができます。

開発の動機

PFNでは巨大なオンプレのGPUクラスタを持っており、その上でKubernetesを使って様々な実行時間の機械学習ジョブを研究者が実行しています。我々クラスターサービスチームのミッションの一つとして、GPUの利用率を向上させ費用対効果をあげることが挙げられます。一方で、研究者間で使えるリソースの平等さも考慮しなければなりません。これを実現させるために、我々はKubernetesのスケジューラーを独自で開発したり、Extender (例 kube-throttler)を拡張したりしています。しかし、新しく開発したロジックを本番環境で走っている機械学習ジョブに影響させずに評価するのは難しく、また頻繁に試行錯誤を本番環境上で行うのは好ましくありません。バグのあるスケジューラーをデプロイしてしまった場合には研究者の仕事を止めてしまうことになるので、絶対に避けなければなりません。またスケジューラーのアルゴリズムを試すためだけに、大規模なクラスタを用意し、多くのワークロードを実際に可動させることも現実的ではありません。これらの理由からKubernetesのスケジューラーを評価するためのクラスタのシミュレーターの開発を開始しました。

デザイン

シミュレーターを開発するにあたって以下のことを考慮しました。

  • シミュレーター用のスケジューラーの実装を最小限の変更で本番環境で動かせるようにする。
  • 時間をシミュレートすることで評価を高速化するとともに、通信や内部処理のレイテンシーがスケジューリングのロジックの評価に影響しないようにする。
  • シミュレートするワークロードを自由に設計できる。
  • 後段の分析のために様々なメトリックスを出力できる。

 

アーキテクチャ

以下は簡単なフロー図になります。

 

アイデアはすごく簡単です。シミュレーターはループのステップ毎にクロックを1つ進めます。各ステップでサブミッターにそのクロックで投入するPodがあるかどうかを聞いて、サブミッターは投入または削除するPodがあればPodのリストを返します。シミュレーターはPodのリストをスケジューラーに渡し、スケジューラーはBindするものと削除するPodを選んでイベントとして返し、シミュレーターがリソース管理を行います。そして、この時に処理されたPodのメトリックスをMetrics Loggerに出力する流れになります。

 

以下はハイレベルなクラス図になります。

 

本シミュレーターでは拡張できる点は以下の2つになります。

 

Submitters

シミュレーターの定義するインターフェースに沿っていれば任意の数、組み合わせのサブミッターを使用することができます。複数のサブミッターをシミュレーターにプラグインできるので、例えばAさんは朝たくさんのPodをサブミットする傾向があるが、Bさんは夕方たくさんのPodをサブミットする傾向があるといったシミュレーションをする場合、それぞれのユーザの振る舞いモデルを独立に開発してシミュレーターにプラグインできます。

また、サブミッターはクロック毎のメトリックスを受け取ることができるため、クラスターの利用状況に応じて挙動を変えることも可能です。

Scheduler

スケジューラーの拡張方法は2種類あります。
Kubernetesのスケジューラー(kube-scheduler)をそのままもしくは拡張したアルゴリズムを利用したい場合、kube-schedulerが用意しているのと同様, Prioritizer, Extender, Predicateをセットできるミミックスケジューラーが用意されています。kube-schedulerはキューベースのスケジューラーですが、複数のPodを条件に応じてまとめてスケジュールするような、例えばより複雑なスケジューラーをシミュレーションしたい場合には、シミュレーターが定義するインターフェースを実装するように少しラッパーメソッドを書くと、それも評価できるようになっています。

*kube-schedulerの挙動については大村によるQiita投稿をご覧ください。

ロードマップ

現在、シミュレーターの使いやすさを向上させ、またより現実的な環境をシミュレーションできるように、ベータバージョンに向けて以下の機能を開発しています。

  • より疎結合なコンポーネント(例:スケジューラーとサブミッターにRPCインターフェースをサポート)
  • よく使われるサブミッターの提供(例: 典型的な確率分布に従うサブミッター(一様分布、二項分布、ポアソン分布等)
  • より多くのクラスターイベントへの対応(ノード故障、突発的なPod故障、ノード追加、削除)
  • デファクトなプロッターツール(matplotlib, gnuplot等)で直接読み込める出力フォーマットのサポート

興味のある方は是非試していただいて、フィードバックをいただけると幸いです。

 

Rust向け字句解析器生成器「rflex」を公開しました

kashihara
エンジニア

2019-04-09 08:00:14

Rust向け字句解析器生成器である「rflex」をOSSで公開しました。ここでは簡単に、「rflex」や開発に至った経緯について紹介します。

PFNエンジニアの柏原です。あまりリサーチブログには出てきませんが、前回は「[BoF] How to choose programming language for product/in-house software development」というブログを書きました。

「rflex」はプログラミング言語処理系のフロントエンドにおける文字列解析を行うコンポーネントである字句解析器(Lexical analyzer)と構文解析器のうち、前者の字句解析器のコードを生成するツールです。字句解析器生成器の「flex」とよく似たツールとなっています。構文解析器の生成では 「GNU Bison」が有名です。

開発のモチベーション

個人的には「rflex」開発においては社内外での言語処理系開発の盛り上がりについて期待を込めて作っている部分もあります。実務に役立つのはもちろんありがたいことですが、コンパイラ・言語処理系の開発といったプログラミングを楽しむことにも役立ててもらえると開発者として嬉しいと思っています。

PFNでは、業務中の活動として20%に相当する時間を個人の研究テーマや、新規アイディアのプロトタイプ実装などに当てることが認められています(20%ルール)。

今回、私は字句解析器生成器がRust に存在しないことを確認した、2018年7月頃から「rflex」の開発を開始しました。正確には、2018年1月頃から個人的に字句解析器生成器の開発のための学習をしていましたが、せっかくなので制度を活用することにしました。
「rflex」の開発においては既存ライブラリの再実装・移植、つまり車輪の再発明という側面が強いですが、以下の点でメリットがあると考え実装に至りました。

  • Rust向けのツールとして、字句解析器生成器を提供することができる
    • プログラミング言語処理系のフロントエンド開発(Rust)において、字句解析器の作成が楽になる
    • GitHubに公開することでユーザを増やし、バグレポート等の対応により品質の向上が期待できる
    • ブログ執筆時点で社内ユーザは確認できていないが、将来的に社内で必要なテキスト処理・言語処理系フロントエンド開発を手伝える可能性がある
  • Rustを業務時間内に学習できる
  • 字句解析器生成器の仕組みを再実装を通して学習できる
    • 正規表現パーサの実装
    • 非決定性オートマトン(NFA)及び決定性オートマトン(DFA)を構築するコードの実装
    • 決定性オートマトンの最小化アルゴリズムの実装

終わりに

PFNではこのような個人の活動を支援する制度(20%ルール)があり、何かに挑戦したい人にとって嬉しい仕組みだと思います。私自身も「rflex」のユーザとして応用的(言語処理系フロントエンド開発といった)な活動を新たに挑戦していく予定です。これからも「rflex」は継続的に開発を続けていく予定ですので、GitHubでのPull Request/Issueを通してフィードバックをお待ちしています。

最後に宣伝となりますが、今年もPFNはインターンを募集しています。

深層強化学習エージェント可視化ライブラリChainerRL Visualizer公開

ofk
エンジニア

2019-03-19 12:40:11

本記事は、2018年インターンシップを経て、PEとして勤務した石川さんによる寄稿です。

ChainerRLで学習したエージェントの挙動などを, ブラウザ上に可視化するライブラリ「ChainerRL Visualizer」を公開しました.

PFN2018年夏季インターンシップに引き続き, 現在アルバイトをしている東京大学の石川貴大です.

このライブラリは「強化学習のデバッグを容易にする」「強化学習のエージェントの仕組みの理解に貢献する」という思想の元で作られ,
学習済み, 及び学習途中の強化学習のエージェントの挙動をインタラクティブにブラウザ上から観察できるような機能が実装されています.

使い方は非常に簡単で, このライブラリで提供されている launch_visualizer という関数に,
ChainerRLで実装した agent オブジェクトと, 特定のインターフェースを満たした env オブジェクトを, オプションと共に渡すだけです.

from chainerrl_visualizer import launch_visualizer

# Prepare agent and env object here
#

# Prepare dictionary which explains meanings of each action
ACTION_MEANINGS = {
  0: 'hoge',
  1: 'fuga',
  ...
}

launch_visualizer(
    agent,                           # required
    env,                             # required
    ACTION_MEANINGS,                 # required
    port=5002,                       # optional (default: 5002)
    log_dir='log_space',             # optional (default: 'log_space')
    raw_image_input=False,           # optional (default: False)
    contains_rnn=False,              # optional (default: False)
)

実行するとローカルにサーバーが立ち上がり, ブラウザ上から以下のような操作ができます.

1. 指定したステップ分, エージェントをサーバー上で動作させる
サーバー上でエージェントが指定されたステップ分の動作をし, エージェントのモデルの出力が時系列で可視化されます.
以下の動画では, A3Cで学習されたエージェントの Probability of next action と State Value が時系列で出力されています.

2. エージェントを1ステップずつ動作させ, その時の挙動をモデルの出力と共に可視化する
以下の動画では, A3Cで学習されたエージェントを1ステップずつ(前後に)動作させ, その出力をenvの様子と共に観察しています.
右下の円グラフは, 各ステップにおける Probability of next action を表しています.

3. Saliency mapの可視化 (モデルの入力が画像のピクセルデータの場合のみ)
エージェントが画像のどの部分に特に注目して特徴量を抽出しているのかを可視化する機能を, モデルの入力が画像のピクセルデータの場合に特化して実装しました.
この機能は, Visualizing and Understanding Atari Agents を参考にして実装しました.
以下の動画では, CategoricalDQNで学習されたエージェントのSaliency mapを可視化しています.
現時点でSaliency mapを可視化する計算コストがかなり大きいため, Saliency mapを可視化するステップの範囲を指定できるようにしています.

4. その他様々な可視化
エージェントの種類に応じて様々な可視化をサポートしています.
例えば以下の動画では, CategoricalDQNで学習したエージェントの, ステップごとの価値の分布を可視化しています.

とりあえず動かしてみるためのクイックスタートガイドを用意しています.

これまでの多くの可視化ツールは, 「学習の進行に合わせたスコアの表示, およびその他指標の遷移」を可視化することに主眼が置かれていましたが,
ChainerRL Visualizerは, 学習済み, 及び学習途中のエージェントの挙動を動的かつインタラクティブに可視化したという点に, これまでにない可視化ツールとしての特徴があります.

似た思想の元作られたライブラリとしては, Uber Researchによる Atari Zoo が挙げられます.
このライブラリは, 強化学習エージェントを理解するための研究を加速することを設計理念として掲げ, 学習済みモデルと, その学習済みモデルを分析するツールを提供することによって, 計算リソースを十分に持たない研究者に対して, 強化学習エージェントを理解するための研究を促進することを狙っています.
Atari Zooでは, 特定のアーキテクチャ(RawImagePIxel => Conv => Conv .. => FC => FC..)とALEという環境に限定した学習済みモデルと分析ツールを提供しているのに対し, ChainerRL Visualizerでは, ChainerRLで学習したエージェントならばユーザーが学習したどんなエージェントも動的に可視化できるという点で差別化ができています.

また, DQNViz のようにDQNに特化して各種メトリクスを可視化し, DQNのエージェントがどのようなStrategyを学習過程で獲得しているのかを研究しやすいようにサポートするツールの提案も出てきています.

これまで数多くの強化学習の性能向上に関する研究がなされてきましたが, 強化学習のエージェントがどのように環境を解釈し, 何を学習したのかについての研究は比較的少ないものでした.
しかし今後, 以上に見た各種ツールの提案に見られるような強化学習エージェントを理解するための研究が徐々に増えていくことが予想されます.

現在ChainerRL Visuailzerはベータ版であり, エージェントを分析するための機能もまだまだ少ない状態です.
今後発展していくであろう強化学習エージェントを理解するための研究開発に少しでも貢献できるようなライブラリとして進化していけるように, さらなる継続的な開発が必要です.

機能の追加やUX向上に関する調整に関して, OSSなどを通したChainerRL Visualizerへの貢献を歓迎しています.

プログラミング教育推進月間の教材について

Hiroshi Maruyama

2019-02-18 18:00:37

PFNフェローの丸山です。2月18日に、PFNは文部科学省、総務省及び経済産業省の「未来の学び プログラミング教育推進月間」に協力して、小学校向けのプログラミング教材を作成することを発表しました。この教材は、今年の9月に一部の小学校で、総合学習の一環として利用されることを目指しています(指導案のページはこちらです)。この記事では、私達PFNがなぜこのような活動をしているかをお話ししたいと思います。

PFNは若い会社です。多くの若い社員が次々に家庭を持ち、子どもを育て始めています。社長の西川をはじめ皆、次の世代が活躍し、よりよい社会を作っていくことを強く願っています。これからの社会を考えたとき、マーク・アンドリーセンが「ソフトウェアが世界を侵食する」(Software is eating the world) と言ったことに象徴されるように、社会の価値の多くが情報技術、特にソフトウェアから得られることは明らかです。ですから、私達の次の世代の誰もが、小さい頃から情報技術に親しみ、プログラミングの楽しさを知る機会を持てることは、私達にとっても大変喜ばしいことです。そんな若い人たちが、ソフトウェアに興味を持ち、将来社会のあらゆる場で活躍している、そんな社会の実現をPFNは願っています。

新しいスタイルのプログラミング

同時に私達は、技術の進歩によって、今までとは違う新しいスタイルのプログラミングが現れつつあることも強く認識しています。簡単にするため、プログラムとはある入力Xに対して出力Yを計算する箱であると考えます。

このようなプログラムを作る1つの方法は、計算のルールを書き下すことです。たとえば、商品の価格を入力としてその消費税を出力するプログラムを考えましょう。このようなプログラムは、入力Xに対して「X の0.08倍を計算してYとせよ」 というルールで表現することができます。これが普通のプログラムの作り方で、ここではルールによるプログラミングと呼ぶことにしましょう。

しかし、深層学習という新しい技術によって、別の形のプログラミングが現れてきました。こんな例を考えてみましょう。人とじゃんけんをする機械を作るために、カメラで撮った手の画像を入力として、それがグー・チョキ・パーのいずれであるかを判定して出力するプログラムを作りたいとします。

このようなプログラムを、ルールによるプログラミングで作るのは容易ではありません。カメラで撮影した画像は画素が格子状に並んだものですが、ある画素が肌色だからこれはチョキだ、と判断するわけにはいきません。同じチョキでも位置や角度や光源が違ったりして毎回異なる画像になるからです。

そこで、深層学習では、様々に異なるチョキの画像をプログラムに見せて「これはチョキだよ」と教えていくことによってプログラミングを行います。これを例示によるプログラミングと呼ぶことにします。例示によるプログラミングでは、ルールを書くのが難しいようなプログラムも作ることができます。

一方で、例示によるプログラミングでは、例示に使うデータによっては、必ずしも毎回正解が出ないかもしれません。あるいは例示に偏りがあった場合には、偏りのある結果が出るかもしれません。これは、ルールによるプログラミングが(プログラムに誤りが無い限り)常に正しい答えを出すこととは対照的です。

将来のソフトウェア

例示によるプログラミングは、ここ10年ほどの、深層学習の急速な発展によって可能になってきていて、今までのルールによるプログラミングでは難しかった画像認識、音声認識、機械翻訳などに応用されつつあります。これは、1950年代にデジタル計算機が発明されて以来の最大のパラダイムシフトかもしれません。おそらく、将来のソフトウェアの多くは、ルールによるプログラミングと例示によるプログラミングを組み合わせたハイブリッドなものになるでしょう。

私達が今回の「未来の学び プログラミング教育推進月間」にご協力している真の理由はここにあります。今の子供達が大人になって、社会におけるソフトウェア開発の一翼を担うころには、例示によるプログラミングが広く使われていることは間違いありません。ルールによるプログラミングが苦手でも、例示によるプログラミングは得意だ、という子どももいるでしょう。

「プログラミング」を狭く捉えないで、いろいろな考え方があるのだ、ということを知ってほしい、それが私達の願いです。

 

Chainerモデルのさらなる高速化、デプロイの簡便化、可搬性の向上に向けた実験的な取り組みについて

Shinichiro Hamaji

2019-01-25 16:06:16

PFN のエンジニアの浜地です。入社以来取り組んできた実験的なプロジェクト Chainer-compiler を github で公開しました。まだ実運用に投入していける段階では無いですが、面白いものになってきているのではないかと思うので、紹介させてもらいたいと思います。

https://github.com/pfnet-research/chainer-compiler

昨年末、 PFN は ChainerX をベータリリースしました。 ChainerX は Chainer の使いやすさを維持しつつ、 Python で実装されていた部分を C++ 実装で置き換え、以下の3つを実現するものでした。

  • モデルの実行を高速化する
  • Python の無い環境でもデプロイ可能にする
  • CPU/GPU以外への移植を容易にする

Chainer-compiler プロジェクトは ChainerX を利用して、上記の ChainerX の目標をさらに押し進めるツールチェインを開発しています。現状、以下のようなコンポーネントからなります。

  1. Python 構文木を解釈して、計算グラフを、拡張された ONNX フォーマットとして取り出す
  2. 拡張 ONNX で表現された計算グラフを変換して、高速化や自動微分をし、コード生成をする
  3. ChainerX の C++ 部分を用いて、生成されたコードを実行する

想定している使い方の例をいくつか紹介すると

  • オペレーションが逐次実行される Chainer/CuPy/ChainerX の計算モデルと違って、いったん複数のオペレーションからなる計算グラフが作られるので、オペレーションをまたいだ命令融合や、データフォーマットの事前変換などの最適化ができる
  • 上記の1,2を事前に実行して、3の部分だけをデプロイ環境で実行することによって Python の無い環境でのデプロイが手軽にできる
  • 2のコード生成部のターゲットを追加することによって、特に静的グラフを前提としたモデル実行系や用途特化チップ(例えば MN-Core)での実行をサポートしていける
  • 2,3の部分のみを使うことによって、 ONNX-chainer や他の ONNX 生成系で作られた ONNX モデルを実行する。また、これに限らず、他のツールとの連携は、色々な組み合わせが考えられると考えています

などがあります。上記以外にも、色々と実験的なことをやっていきたいと考えています。

深層学習用コンパイラは、他の深層学習の領域同様、競争が激化していて、とても面白い領域だと思います。深層学習用コンパイラとひとことで言っても、用途や目標によって色々なものがあるのですが、 chainer-compiler プロジェクトでは Chainer のフレキシビリティをなるべく損なわない形でモデルをコンパイルすることを、重要な目標の一つとして考えています。そのため、次元が固定されていない tensor や Python の条件分岐・ループ、 Python のリストなども表現できるようにしています。多くの深層学習コンパイラは最適化に集中していて次元が静的であることを前提にしているものが多いので、この点は少しユニークな点になりえるのではないかと思っています。

この投稿では、 Chainer モデルをコンパイル・実行する実験的なプロジェクトについて紹介しました。結構広い領域について、色々とやりたいことがあって、楽しく作業しています。こういう作業に興味がある方は、ぜひ PFN への応募をご検討ください。この投稿では説明しきれなかった点も多くあります。技術的な話でも採用の話でも、なんでも疑問点がある方はご連絡いただければ、と思います。

最後に、 chainer-compiler プロジェクトに協力して下さっている全ての方々に感謝します。特に、「Chainer を使った Python コードを ONNX に変換する」というテーマに取り組んでもらった、インターンの佐藤さんの多大な貢献に感謝します。

インターン参加報告:Concolic Testing による SystemVerilog 向けテストパターン生成

Masahiro Sakai

2018-12-25 12:00:56

本記事は、2018年インターンシップに参加された押川さんによる寄稿です。


こんにちは。2018年夏季インターンシップに参加していた東京大学の押川広樹です。大学では定理証明支援系やモデル検査を用いたソフトウェアの検証について研究しています。

インターンでは、PFN で開発中のハードウェアに対して「良い」テストを実行することが目標でした。「良い」テストの基準は色々ありますが、今回は効率的で効果的なテストケースを生成することを目指しました。ここで言う効率的なテストとは、短い時間で実行できるように出来るだけサイズの小さいテストセットのことです。また、効果的なテストとはプログラムのより多くの部分を検査できるカバレッジの高いもののことです。

今回はそのようなテストケースを Concolic Testing と呼ばれる手法に基づいて生成することを試みました。

Concolic Testing

まず、テストというとランダムテストが考えられます。ランダムテストは手軽ですが効果的だとは言えません。例えば以下のようなコードを考えてみます。

int x, y;
if (x == y)
  if (x == 10)
    fail;
  else
    ...
else
  ...

上の例は xy が共に 10 の時だけバグがあるプログラムを表します。ランダムテストによってバグを見つけられる確率は単純計算で (int が 32 ビットの時) 232 × 232 回に一回です。

このためランダムテストはコーナーケースになるような微妙な部分のテストには向いておらず、高いカバレッジをとるためにはもう少し賢くテストケースを作る必要があります。その一つの例が Concolic Testing と呼ばれる手法です。Concolic は Concrete と Symbolic を組み合わせた言葉で、Concolic Testing とはプログラムの実際の実行とシンボリックな実行を交互に行うテスト手法です。

Concolic Testing では次の手順でテストを進めて行きます。

  1. ランダムな入力を生成する
  2. 入力に対して プログラム を実行する
  3. 実行時にプログラムのどの部分が実行されたかを記録しておく
  4. 3. の情報を元にその部分が使われるための条件を計算する
  5. 4. の条件の一部を変更し、プログラムの別の部分が実行されるための制約を得る
  6. 5. の制約を論理ソルバーで解くことで、実際にその部分を使うような入力を得る
  7. 2.-6. を繰り返す

各イテレーションごとにプログラムの新しい部分を実行するような入力が得られるので、理想的にはラインカバレッジ100%のテストケースを生成することが出来ます。

ランダムテストと同じ例でどのように動作するかをみてみます。
プログラムは if 文などで分岐する木だと思えるので、上の例は次のように表せます。

まず、xy の値をランダムに生成します。例えば x = 1163551168y = 1363922006 だとします。この下でプログラムを実行すると以下のようなパスを通ります。

このパスを通ったのは、x == y が成り立たなかったからです。したがって制約としてこの条件の否定、つまり x != y を考えます。これを満たすような xy をソルバーを使って求めます。
例えば x = 0y = 0 はこの制約を満たします。次はこれを入力としてプログラムを実行します。次のようになります。

確かに1度目の実行とは異なる部分が実行されています。先ほどと同様、このパスを通ったことから、「x == y かつ x != 10」が成り立つとわかります。x != 10 を否定した制約、「x == y かつ x == 10」をソルバーを用いて解くことで次の入力 x = 10y = 10 を得ます。そして、x = 10y = 10で実行することでちゃんと fail を見つけることができます。

Concolic Testing は Godefroid らによる DART (Directed Automated Random Testing) [1] によって導入されました。[1] では Concolic Testing の手続きの導入と、Cで書かれたプログラムに対しての実装の実験がなされています。

上で説明した Concolilc Testing の手続きを素朴に行うと、対象のプログラムが大きくなるにつれてたどる必要のあるパスの数が爆発するためスケールしません。また、生成される制約が大きくなりすぎてソルバーで制約が解消できなくなる可能性もあります。

そのため実用上は、できるだけ早くカバレッジを増やすようにパスをたどったり、生成される制約を小さくする最適化を加えることで、実際のアプリケーションにも適応できるように改良されています。実際、DART にこのような最適化を加えたものに SAGE [2] があります。SAGE は X86 アセンブリを対象にしており、Microsoft で Office のバグを見つけるのに使われたようです。

また、対象をハードウェア設計言語にしたものに HYBRO [3] があります。HYBRO は Verilog を対象とします。

やったこと

今回は SystemVerilog で記述されたプログラムに対して Concolic Testing を行うフレームワークを作成しました。実装時間の都合で、受け入れられるプログラムの種類は限られていています。具体的には、ある程度制限された SystemVerilog の機能を用いて書かれた組み合わせ回路になります。例えば、interface が使われていないことなどを仮定しています。

テストケース生成の手続きの全体像は以下の図のようになります。

大まかには上で説明した手順と同じです。

  1. まず、SystemVerilog のソースコードをパース・解析して always 文ごとに Control Flow Graph (CFG) を作ります。この際にプログラムが期待する入力の情報(名前や型)を得ます。
  2. 次に、得た情報を使って最初の入力をランダムに生成し、シミュレータを用いて実行します。シミュレータは実行時の各変数の値の情報を Value Change Dump (VCD) というフォーマットで出力します。
  3. VCD には各タイミングでの変数の値の情報が入っているのでこれを元に CFG のどのパスが実行されたかを計算します。
  4. そこからその実行が行われるための条件を求めて、まだ実行されていない部分を次に実行するような入力を生成するのための制約を求めます。
  5. この制約をSMT ソルバーで解くことで次の入力を得ます。
  6. このプロセスをラインカバレッジが100%になるまで繰り返します。

SMTソルバーは Z3 [4] を用い、その他は OCaml によって実装しました。Z3 の API は OCaml から利用することができ便利です。

実装は https://github.com/pfnet-research/ATPG4SV で公開しています。

結果

300行程度の比較的小さめの回路に対して実行したところ10イテレーションほどで100%のカバレッジになるテストケースが得られました。

まだ実装が不完全なので対象に制限がありますが、実際の回路に対して動作させることができました。

まとめ

効率的で効果的なテストケースを生成する手法として Concolic Testing を紹介しました。また、インターンで取り組んだ、SystemVerilog で記述されたハードウェアへの適用例を紹介しました。まだ実用的に役に立つレベルのものではないですが、プロトタイプとして面白いことができたと思います。

最後になりましたが、メンターの酒井さんと Kühn さんには、テーマ決め、自分の知識が少なかったハードウェアに関する質問、発表練習、そして休憩中の雑談、とインターン期間を通して大変お世話になりました。ありがとうございました。

参考文献

  • [1] P. Godefroid, N. Klarlund, and K. Sen. DART: Directed Automated Random Testing
  • [2] P. Godefroid, M. Levin, and D. Molnar. Automated Whitebox Fuzz Testing
  • [3] L. Liu and S. Vasudevan. Efficient validation input generation in RTL using hybridized source code analysis
  • [4] The Z3 Theorem Prover https://github.com/Z3Prover/z3

おまけ:メンターより

押川さんのメンターを担当した、PFNの酒井とKühnです。

PFN ではディープラーニングを高速化する専用プロセッサー MN-Core™(エムエヌ・コア)の開発も行っていますが、チップ設計の検証は大きな課題の一つでした。 今回の取り組みは、この課題への取り組みとして始まった実験的なプロジェクトであり、押川さんには短い期間で、Coqによる部分的な証明などのアプローチも含めた複数のアプローチを検討のうえ、Concolic Testing に基づいたアプローチを選択し、プロトタイプを実装して実際の回路を対象にテストパターン生成のループを回せるところまで開発していただきました。(注: 既存の回路を対象に実験したものであり、現時点でのMN-Coreの実際の開発に適用しているわけではありません。)

PFNは上から下まで様々なことに取り組んでいていますが、まだまだ手が回っていないことも沢山あり、そこに興味のあるインターンの学生さんが来てくれたことをきっかけに新たな取組みが始まることがしばしばあります。今回のプロジェクトはそのような取り組みの一例でもあります。我こそはという学生の皆さんは、ぜひ来年のPFNインターンシップへの応募をご検討ください。 また、もちろん中途・新卒の人材募集も通年で行っていますので、こちらも興味のある方はぜひご検討ください!PFNの人材募集のページはこちら https://www.preferred-networks.jp/ja/jobs です。(FPGA/ASIC開発の人材も募集しています)

分散深層学習とモデル並列性

Kota Uenishi

2018-12-21 15:29:18

(本記事は、2016年インターンシップを経て現在はアルバイトとして勤務されている包さんによる寄稿です)

はじめまして。Preferred Networksの分散深層学習チームでアルバイトをしている包です。私は分散深層学習の中でも主にモデル並列に関する機能実装を行っています。今回はモデル並列性の概要と、ChainerMNにおいてどのようにモデル並列性を実現しているのかについて紹介します。

分散深層学習: データ並列性とモデル並列性

深層学習における各種フレームワークは目覚ましい発展を遂げ続けており、最近では一般ユーザーでも簡単に複数GPUを用いたニューラルネットの訓練ができるようになってきました。たとえば、ChainerMNではoptimizerの定義にほんの数行加えるだけでニューラルネットを複数GPUで訓練できます[1]。これにより1024GPU上でImageNetによるResNet-50の学習を15分で行うなどの実績を上げています[2]。このような複数プロセス、複数ノードを用いた分散深層学習によってニューラルネットの訓練は高速に行えるようになっており、分散深層学習は現在の深層学習の基盤を支えているといえます。

ところで、「分散深層学習」にはデータ並列とモデル並列という2通りのアプローチがあることが知られています[3]。データ並列では、全プロセスに同じモデルのコピーして訓練することでバッチサイズをプロセス数倍し、学習を高速化させる手法です。先程お話したImageNetの並列訓練もデータ並列による高速化の一例です。一方でモデル並列とは、1つのモデルを分割して複数のプロセスに配置し、全プロセスで協調して1つのモデルを訓練する手法です。主なユースケースとしては超解像度を入力とするCNNやMixture of Experts[4]など、1プロセス上に載りきらないサイズのモデルを訓練したい場合に用いられます。最近ではMesh-Tensorflow[5]というTensorflow用のモデル並列ライブラリが公開されましたが、現状ではモデル並列をサポートしているフレームワークは非常に少ないです。

この記事では、ChainerMNに実装されているモデル並列APIを、実例を交えて紹介します。特に、Define-by-Runとともにモデル並列を実現する際に発生する問題と、その解決方法について重点的にお話をします。

ChainerMNにおけるモデル並列性の実現

ChainerMNでは、通信をChainerの関数呼び出しによって定義 します。これにより非常に柔軟な通信パターンを実現することができます。

図1: 関数呼び出しによる通信の定義の例

ChainerMNにおける通信はMPIを用いて実現されており、モデル並列でも基本的にMPIの通信スタイルを踏襲しています。MPIでは大きく分けて MPI_Send を始めとした1対1通信と、 MPI_Bcast のような集団通信向けのAPIが提供されています。ChainerMNでは、これらの通信APIと対応するように chainermn.functions.sendchainermn.functions.bcast のように、Chainerの関数を提供しています。通信用の関数は、それぞれbackwardにおいて「勾配を逆向きに通信」するように設計されています。例えば bcast の場合、forward計算ではmasterからslaveに対して入力変数がbroadcast通信されます。一方で、backward計算ではslaveからmasterに対して勾配をallreduceします。

ChainerMNに実装されているforward通信に対応するbackwardの通信パターンは以下のようになります。

表: forward と backward における通信パターンの対応

forward backward
allgather allgather
alltoall alltoall
bcast allgather
gather scatter
scatter gather
send recv
recv send

 

次に、モデル並列APIの具体的な使い方について見ていきます。まず、データ並列の際と同様に、通信を行うためのコミュニケータを作成します。

comm = chainermn.create_communicator()

例えば、図1のようなモデルの実装イメージは次のようになります(図1のモデルに特に意味はありません)。

class ExampleModel(chainer.Chain):
    def __init__(self):
        self.comm = chainermn.create_communicator()
        self.conv = L.Convolution2D(...)

    def forward(self, x):
        x = chainermn.functions.bcast(self.comm, x)
        h = self.conv(x)
        y = F.relu(h)
        ys = chainermn.functions.gather(self.comm, y)
        ...

この例では、masterからブロードキャストされた変数が Convolution2D の入力になります。一方で、backward計算の際には、 Convolution2D の勾配が自動的に Bcast のbackwardによってmasterへ集約されます。

ChainerMNに用意されているAPIの詳細については、ドキュメントを参照してください[6]。なお、モデル並列関連のAPIに関しては現状では実験段階なので、将来的に後方互換でないAPIの変更が起こる可能性があります。

Define-by-Runにおける注意点(その1)

ChainerをはじめとしたDefine-by-Runによる計算グラフの定義はモデルを直感的に記述することができる点で優れているといえます。backward計算時には、出力変数からグラフのバックトラックを行うことによってパラメータの更新を行うことができます。しかし、モデル並列を実現するために上述のように通信を関数として定義すると、計算グラフが正しくバックトラックできない状況が発生します。

例えば、下記のような2つのプロセス間におけるシンプルな1対1通信の例を考えます。

図2: 1対1通信の例

「Process #0」に注目してみると、出力変数 y からバックトラックを行ったときに、 recv から send へ戻ることができません。その結果、「Process #1」は recv のbackward(すなわち勾配のsend)を呼んでいるにもかかわらず、「Process #0」は send のbackward(すなわち勾配のrecv)を呼ぶことができず、デッドロックが発生します。このような状況は、1つのプロセス上における計算グラフが非連結になっているときに生じます。そのため、 send 関数が戻り値として返す特別な変数を recv に渡すことによって、 計算グラフが連結になるようにモデルの定義を行います

図3: delegate variableによる計算グラフの連結化

このような sendrecv を繋ぐような send 関数の戻り値を、便宜的に「delegate variable」と呼ぶことにします。Delegate variableは「Process #0」においてグラフを連結にする役割を果たす他に、「Process #1」でもバックトラックの起点となるダミーの出力変数として振る舞います。図3をコードで記述すると以下のようになります。

class ExampleModel_0(chainer.Chain):
    def forward(self, x):
        # first component
        z = f(x)
        phi = chainermn.functions.send(z, comm, rank=1)

        # second component
        z = chainermn.functions.recv(comm, rank=1, delegate_variable=phi)
        y = h(z)

        return y

class ExampleModel_1(chainer.Chain):
    def forward(self, _):
        z = chainermn.functions.recv(comm, rank=0)
        z = g(z)
        phi = chainermn.functions.send(z, comm, rank=0)
        return phi

Define-by-Runにおける注意点 (その2)

先程の節ではグラフが非連結になると計算グラフのバックトラックができない例を1つ挙げました。このような例は他にも存在します。

 

図4: 1対1通信を2回呼ぶ例

 

図4では、1対1通信が2回発生しています。この場合、「Process #0」における send が返す2つのdelegate variableを適切に処理する必要があります。そこで、以下のように2つの変数を1つにまとめる処理を行います。

 

図5: pseudo_connectを用いた例

 

chainermn.functions.pseudo_connect という関数は、「delegate variableがあたかも別の変数であるかのように振る舞うような変数」を返す関数です。図5の例では、 \( \phi_1 \) というdelegate variableが実際には \( \phi_2 \) という別の変数として振る舞うような変数 \( \psi \) を返します。 \( \psi \) をバックトラックする際には、まず \( \phi_1 \) のバックトラックを行い、次に \( \phi_2 \) のバックトラックを行います。このようにして、backward計算の際に2つのdelegate variableを正しくトラックバックすることができます。図5をコードで記述すると次のようになります。

class ExampleModel_0(chainer.Chain):
    def forward(self, x):
        z1, z2 = f(x)
        phi1 = chainermn.functions.send(z1, comm, rank=1)
        phi2 = chainermn.functions.send(z2, comm, rank=1)
        psi = chainermn.functions.pseudo_connect(phi1, phi2)
        return psi

class ExampleModel_1(chainer.Chain):
    def forward(self, _):
        z1 = chainermn.functions.recv(comm, rank=0)
        z2 = chainermn.functions.recv(comm, rank=0)
        y = g(z1, z2)
        return y

図5では pseudo_connect で2つのdelegate variableをまとめましたが、次の図6のように通常の変数にdelegate variableを結合することも可能です。

図6: delegate variableと通常の変数を結合する例

 

y_ = chainermn.functions.pseudo_connect(phi, y)

以上がChainerMNにおけるモデル並列の概要になります。次に、実際のモデルの例を見てみます。

1対1通信を用いた例: encoder-decoderモデル

Encoder-decoderモデル[7]は可変長の入力を可変長の出力に変換することを目的としたモデルで、自然言語処理をはじめとした応用分野で広く用いられています。
Chainerのexampleにも機械翻訳の例があります[8]。Encoder-decoderモデルの入力や出力に画像を用いるようなモデルの場合、CNNをencoderやdecoderに用いることになりますが、層数やパラメータ数が膨大なencoderやdecoderになると、全体のモデルが1GPUに載らないケースが発生します。その場合、モデルをいくつかに分割して複数プロセスでモデル並列学習を行うことによって学習できます。例えば、下図のようにencoderとdecoderにそれぞれ1プロセスずつ割り当てるような分割が考えられます。

図7: encoder-decoderのモデル並列化

 

ここでは、はじめのプロセスでencodeしたcontext vectorをdecoderへ送信して、decoder側のプロセスでdecodeするように分割を行っています。例えばLSTMの場合はcontext vectorが2つあるので、2回の1対1通信を行うことで実現できます。ただし、図5の例と同様に、encoder側では pseudo_connect を用いてdelegate variableを1つにまとめる必要があることに注意してください。基本的には sendrecvpseudo_connect を用いれば実装することができますが、encoder-decoderモデルの分割は実装が煩雑になるので、専用のLinkを用意しています。

rnn = chainermn.links.create_multi_node_n_step_rnn(
        L.NStepLSTM(n_layers, n_units, n_units, 0.1),
        comm, rank_in=None, rank_out=1)

create_multi_node_n_step_rnn は、Chainerで提供されている NStepRNN [9](可変長系列をまとめて入出力するAPI)をラップして、内部で別のプロセスと自動的にcontext vectorを送受信します。rank_in に指定したプロセスからcontext vectorを受信し、 rank_out に指定したプロセスに対してcontext vectorを送信します。これを用いると、次のようにモデル並列なencoder-decoderモデルを簡単に実装することができます。

class Encoder(chainer.Chain):
    def __init__(self, comm, n_layers, n_units):
        super(Encoder, self).__init__(
            # Corresponding decoder LSTM will be invoked on process 1.
            mn_encoder=chainermn.links.create_multi_node_n_step_rnn(
                L.NStepLSTM(n_layers, n_units, n_units, 0.1),
            comm, rank_in=None, rank_out=1
            ),
        )
        self.comm = comm
        self.n_layers = n_layers
        self.n_units = n_units

    def forward(self, *xs):
        exs = f(xs)
        c, h, _, phi = self.mn_encoder(exs)
        return phi

class Decoder(chainer.Chain):
    def __init__(self, comm, n_layers, n_units):
        super(Decoder, self).__init__(
            # Corresponding encoder LSTM will be invoked on process 0.
            mn_decoder=chainermn.links.create_multi_node_n_step_rnn(
                L.NStepLSTM(n_layers, n_units, n_units, 0.1),
            comm, rank_in=0, rank_out=None),
        )
        self.comm = comm
        self.n_layers = n_layers
        self.n_units = n_units

    def forward(self, *ys):
        c, h, os, _ = self.mn_decoder(ys)
        ...

この例はChainerMNのexampleに公開されています[10]。

集団通信を用いた例: チャネル方向の並列化

集団通信を用いると、下図のようにCNNのチャネル方向の並列化が実現できます。この並列化は高解像度画像を扱う際や、バッチサイズを大きくする際に有用です。

図8: チャネル方向の並列化

 

各プロセスはCNNのチャネルのうち一部だけを入力としてとって畳み込みを行うので、各々のプロセス上のCNNのパラメータ数を減らすことができます。CNNの出力に対して “allgather“ を用いることで、全チャネルを集約することができます。実装のイメージは以下のようになります。

class ParallelConvolution(chainer.Chain):
    def __init__(self, comm, in_channels, out_channels):
        self.comm = comm
        self.in_channels = in_channels
        self.out_channels = out_channels
        self.conv = L.Convolution2D(...)

    @property
    def _indices(self):
        # index % comm.size == comm.rankとなるインデックスのチャネルを担当
        # 例 (size=4, rank=1の場合): _indices = [1, 5, 9, ...]
        idx = numpy.arange(self.in_channels)
        return idx[idx % self.comm.size == self.comm.rank]

    def forward(self, x):
        # 当該プロセスの担当チャネルをスライス
        x = x[:, self._indices, :, :]

        y = self.conv(x)

        # 全チャネルを集約
        ys = chainermn.functions.allgather(self.comm, y)
        return F.concat(ys, axis=1)

この例はchainerMNのexampleに公開されています[11]。

まとめ

本記事では、ChainerMNにおけるモデル並列の実現と、実際の例をいくつか紹介しました。特に、Defined-by-Runの下では計算グラフが連結でなければならないため、delegate variableやpseudo_connectなどのテクニックが必要になります。今回はスペースの都合で紹介がかないませんでしたが、特定のタイプのモデル向けによりシンプルにモデルを定義できるようなAPI( MultiNodeChainList, MultiNodeNStepRNN)も用意されているので、お手軽に試してみたい方はぜひドキュメント[6]をご覧ください。

参考文献

Google Colaboratoryを用いた機械学習・深層学習の入門教材を無料公開(健康・医療向けデータを用いた実践編も含む)

Shunta Saito
リサーチャー

2018-12-20 13:13:56

PFNのリサーチャの齋藤です。今年は色々な仕事に取り組みました。本記事では、日本メディカルAI学会が新しく始める公認資格へ向けたオンライン講義資料について書きます。

昨今、機械学習や深層学習といった技術はIT企業のみならず様々な分野で活用されるようになってきました。その一つに医療分野があります。しかし、忙しい臨床医・研究医・その他医療従事者の方々の中には機械学習や深層学習の可能性を知りつつも、なかなか自ら手を動かして学び、それを医学の研究や医療の現場へ生かしていく時間がとれない方もいらっしゃいます。その大きな理由の一部には、特に深層学習を実践的に用いる方法を学ぶ場合に必要となる計算機環境の用意および環境構築が難しいといった点があります。

そこで、PFNは、Google Colaboratory(以下、colab)を用いた学習教材を作成しました(なお、資料の一部は株式会社キカガクの協力を得て執筆されています)。本資料は、日本メディカルAI学会公認資格:メディカルAI専門コースのオンライン講義資料として作られたものですが、メディカルAI学会所属でない方にも自由にご覧いただけるよう、全ての資料をウェブで無料公開しています。colabを用いると、Googleアカウントさえあれば誰でも無料でGPUが有効な環境の上でPythonコードを実行することができます。従来は、GPUを搭載したコンピュータを自前で用意したり、また用意できたとしても様々な深層学習フレームワークを動作させられるように環境構築を行う部分などでつまづいてしまうケースも多くありましたが、colabを用いればこれらの行程をスキップして本質的に重要なコーディングの部分から学び始めることができます。

今回の学習資料は、全てcolab上で執筆を行い、colabから直接GitHubへ.ipynb形式のファイルをpushし、Pythonパッケージのnbsphinxを用いてそれをHTMLへ変換してドキュメントサイトを構築するというワークフローで作成されました。また、colabで書いたプログラムが実行時に生成したファイルは、簡単にGoogle Driveへコピーすることができるため、学習の結果得られた成果物を再利用するといったことも行いました。具体的には、本資料は1章が2〜3時間で終えられるように作られていますが、中には深いニューラルネットワークの学習に必要な時間だけで数時間かかってしまうものもあります。そういった場合には、あらかじめ筆者らで途中までcolab上で学習を行って学習途中のスナップショット(ある時点のネットワークの重みなどをファイルに保存したもの)を作成しておき、記事中ではそれをダウンロードしてきて途中から学習を再開するという形にすることで、資料中のコードを実行したあと待機する時間を減らしつつ、実際に学習が行われる様子を体験することができるよう工夫しています。

本資料は全8章からなり、機械学習に必要な数学の基礎から深層学習を用いたMRI画像のセグメンテーション、血液の顕微鏡画像からの物体検出、DNA配列解析、心電図の信号波形データの時系列解析といった具体的な応用まで、その背景にある理論の概説から実行可能なコードを用いた実践的な解説まで広く扱っています。目次は次の通りです。

1章:機械学習に必要な数学の基礎

1章では、深層学習に限らず、機械学習の様々な手法を学んでいく際に必須となる微分の知識、線形代数の基礎、そして確率・統計の基礎について、最低限の知識をおさえるために簡潔にまとめています。

2章:機械学習ライブラリの基礎

2章では、機械学習や深層学習の領域では広く用いられているPythonと、その代表的な数値計算ライブラリであるNumPyに慣れるために、重回帰分析をNumPyのみを使って実装する方法をコードを実行しながら学んでいけるようになっています。また、様々な機械学習アルゴリズムを実装しているScikit-learnというライブラリの使い方も紹介しています。

3章:ニューラルネットワークの基礎

3章では、ニューラルネットワークの基礎について、図や動画を用いてできるだけ分かりやすく說明しました。NumPyを用いて誤差逆伝播法(バックプロパゲーション)を実装し、colab上で実行してみることで、具体的な数値を見ながらニューラルネットワークの学習の仕組みを理解することができます。

4章:Deep Learningフレームワークの基礎

4章では、より複雑なニューラルネットワークを扱いやすくするために深層学習フレームワークの一つであるChainerを用いた画像分類の問題に取り組みます。ここからは、colab上でGPUを使ったより実践に近いプログラムを実行することで深層学習を活用していく際のエッセンスを効率よく学びます。

5章:実践編: MRI画像のセグメンテーション

5章では、心臓MRI画像の中から左心室の領域を抽出するセマンティックセグメンテーションのタスクに取り組みます。Chainerを用いて色々なニューラルネットワークを実装し、そのパフォーマンスの違いを見てみます。ChainerCVという画像を取り扱う場合に便利なChainerの追加パッケージの使い方も簡単に說明しています。

6章:実践編: 血液の顕微鏡画像からの細胞検出

6章では、血液の顕微鏡画像の中から赤血球、白血球、血小板の3種類の物体を検出する物体検出タスクに取り組みます。物体検出のためにデザインされたニューラルネットワークの中から代表的なものをいくつか概説し、ここではSingle Shot Multibox Detector (SSD)という手法を使って自ら用意したデータセット(ここでは血液の顕微鏡画像)を用いるモデルの訓練方法を解説しています。本章でもニューラルネットワーク自体の実装コードの転用や評価のためにChainerCVを活用しています。

7章:実践編: ディープラーニングを使った配列解析

7章では、DNA塩基配列を入力として受け取り、配列中の長距離相互作用を考慮した上でDNA塩基配列と特定の転写調節因子の結合可能性を予測するために1次元Dilated Convolutionを使ったニューラルネットワークを訓練する方法を說明しています。

8章:実践編: ディープラーニングを使ったモニタリングデータの時系列解析

8章では、心電図の信号波形データを入力として、不整脈を検出するという時系列解析の問題に取り組んでいます。この章では1次元Convolutionと1次元Dilated Convolutionを使った教師あり学習による時系列データの分類方法について解説しています。

本資料を通じて、機械学習や深層学習の分野について学び始める方が増えることを期待しています。

また、本資料のうち1章〜3章の作成にあたっては株式会社キカガクの吉崎様にご協力をいただきました。この場を借りてお礼申し上げます。そしてGoogle Colaboratoryがなければこのような文章を中心としつつも実行可能なコードを埋め込むことで実践的な資料としても成り立たせることはできませんでした。合わせてお礼申し上げます。

【関連リンク】

日本メディカルAI学会:https://www.japan-medical-ai.org/
株式会社キカガク:https://www.kikagaku.co.jp/
深層学習フレームワークChainer https://chainer.org/