2017年9月21日木曜日

RNN(Recurrent Neural Network)による時系列データ予測の分かりやすい例

RNN(Recurrent Neural Network)を使った時系列データの予測(推定)を理解するための良い例題(アプリ)がGoogleから提供されています。とても参考になるように思います。

https://magenta.tensorflow.org/sketch-rnn-demo

We taught this neural net to draw by training it on millions of doodles collected from the Quick, Draw! game. と書かれています。


以下の例は、「人の手」の簡単なイラストです。これを無数に用意して、RNNに学習させているはずです。RNNの学習とは、「P1, P2, P3, ... , Pn-1」まで描いた次はPnへ行きます、という時系列データセットP = {P1, P2, P3, ... , Pn-1, Pn }を十分多く用意します。そして、このようなデータセット群の全てについて、以下を満たすような一つの近似関数Fを求めることです。
 Pn = F(P1, P2, P3, ... , Pn-1)

十分満足できるようなFに到達するには、多くの学習回数が必要となるでしょう。以下は、そのような学習が済んだRNNを使っているはずです。

[Case1] マウスで、親指から人差し指の途中まで描くと、RNNはうまく、残りの部分を描いてくれました。



[Case2] 今度は、小指から薬指の途中まで描くと、これについてもRNNはうまく、残りの部分を描いてくれました。

[Case3 今度はうまく描けません!親指と人差し指あたりを強調するため、何度も行ったり来たりしたためです。そのような点列のデータは、このRNNは学習していなかった!


2017年9月16日土曜日

チンパンジーと人工知能(Deep Learning)による「じゃんけん」の理解

[追記:2017-9-17]チンパージと人間(または人工知能)とのじゃんけんについて追加しました。
 
 チンパンジーに「じゃんけん」のルールを理解させることに成功した(京都大学にて)とのニュースがありました。

http://www.kyoto-u.ac.jp/ja/research/research_results/2017/documents/170810_1/01.pdf
http://www.kyoto-u.ac.jp/ja/research/research_results/2017/170810_1.html
https://www.youtube.com/watch?v=5qqLKADacOE

 それならば、現在の人工知能Deep Learnig、特にCNN(畳み込みニューラルネットワーク))にも同じことをやらせてみよう、というのが本稿の趣旨です。以下では、私の理解した京都大学での実験をもとにしました。(私の理解に誤りがあるかも知れません。その節はご指摘いただければ幸いです。)



チンパンジーは何を学んだのか
 下図に、チンパンジーの手による「グー」「チョキ」「パー」があります。それぞれ1種類のみです。このうちの異なる2つを並べた画面をみて、どちらが勝ちかをチンパンジーに学ばせます。勝ちの方を正しく答えた(指を指した)場合に、餌をもらえます。


 そのような画面(左右入れ替えも含めて6種類の画面)を、1日に144回(3パタン×48回)学ぶ。それを約100日続けた結果、6種類のどの画面が出ても、正しく答える(指さす)ようになった。
 なお、この1セットの画像以外に、「手の甲とひらを変えた画像のセット」や「人間の手による画像のセット」でも、同様に学習できることが判明したとのこと。

人工知能 CNN君による学習
 結論から言いましょう。CNN(畳み込み層3層+α)では、チンパンジーが学習した6種類の画面に加えて、さらに12種類の画面(合計18種類の画面)を学習しました。これに60エポックを要しました。その学習結果を使って、本来の6種の画面をテストした結果、すべてに対して正解を得ました。(十分に学習が済んでいれば当然そうなります。)下図が、その出力結果図です。ここでのCNNは、Keras on Tensorflowを使って構成しました。


(注)このCNNでは、18画面を学習用データとしました。そのうちの6画面をテスト用にしました。通常の場合は、学習用データをテスト用データは別々に用意しますが、チンパンジーの学習の仕方に合わせるため、このようにしました。

簡単な考察

  • チンパンジーの学習では、学習完了までに、6種のうちのいずれかの1画面×140回×100日 = 14,000回画面を見た。
  • 人工知能CNNでは、学習完了までに、18種類の画面×60回 = 1,080回画面を見た。
  • 単純計算では、(かなり乱暴だが)CNNはチンパンジーよりも、14,000/1,080 = 13倍の効率で学習できたとも言える。
  • チンパンジーは、6種類の画面だけをひたすら学習した。
  • 一方、CNNではこの6種類の画面だけでは、十分に学習することができなかった。以下のようにさらに12種の(元の画像を左右に回転させるなどして得られた画像を編集した)画面を追加して学習することで上記の結果を得た。
  • すなわち、チンパンジーは少ない種類の画面を多くの反復回数をかけて学習した。一方のCNNは、(いくつかの変形を含む)多くの種類の画面を少ない反復回数で学習した。これは、CNNの重要な特性であろう。






チンパンジーと人間の間のじゃんけん

 この京大の研究結果に基づいて、将来的には、チンパンジーと人間(または人工知能CNN君)がじゃんけんすることもありそうです。そこまでは検証できませんので、ここでは、CNN君が、下図のような、チンパンジーと人の手の組み合わせでも難無く学習できることを示しておきます。

 実際に学習した成果(CNN君による判定結果)を示します。チンパンジーの手だけの場合と比べて、特に難しいことではありませんでした。CNN君にとっては。


2017年9月10日日曜日

LSTMによる学内消費電力の予測

 Deep Learningにおいて、CNN(畳み込みニューラルネットワーク)とRNN(再帰型ニューラルネットワーク)はその双璧とも言えよう。ここでは、RNNのうちのLSTM(Long short-term memory)の応用について検討する。

 LSTMと言えば、時系列のデータ。株価、為替、乗客数、売り上げ等々、予測したいものはいくらでもある。ここでは、大学らしいデータでやってみたい。公開されている「KAIT学内電力使用状況」のデータを対象として検討した。Keras(on TensorFlow)を使用した。




簡単な考察
  1. 約1日半の実測データのうちの6割を使って学習。(夏期休業中の金曜と土曜のため、電力消費は少ない。)
  2. ここでの学習とは、時点tでの実測値とそれ以前の連続nステップ(ここではn=2)前のデータから成る順序付きセットを、(t+1)での実測値に結び付けることである。それらの結び付けを全部(可能な限り正確に)反映するマシンLSTM(ニューラルネットワーク)を作成することである。
  3. その学習結果にしたがって予測を行う。上図のとおり、学習が進む(epochが増える)にしたがって、良い予測結果が得られている。
  4. ただし、誤解がありそうである。評価領域での予測は、何もデータを与えずに予測するのではない。あくまで、学習済みLSTMを使って、②で示した時刻tまでの実測値のセットから次のステップ(t+1)での値を予測する。
  5. 今回の時間刻みは30分毎にしてある。したがって、基本的には30分後を予測する。しかし、その予測がかなり妥当であれば、それを元にさらにその先を自動的に予測することも可能かもしれない。
  6. 学習用領域における、学習済みのLSTMを用いた予測結果は、当然、評価領域での予測よりも良好になるはず。

2017年7月26日水曜日

グラフィカルな人工知能(ニューラルネットワーク)作成ツール

 すでに試された方もいるかも知れませんが、私が「日経ソフトウェア 2017年9月号」の記事で、これは!と目にとまったものがあります。Simbrainというソフト、グラフィカルに、通常のコーディング無しに、ニューラルネットワークを構成するもののようです。

 誤差逆伝播(バックプロパゲーション)もできるようです。興味深いです。早速、記事の内容をトレースしてみました。引き続き、記事には載っていないが、非線形分離問題としてポピュラーなXORを構成し、学習させてみました。まだ、全然深く調べていないので、一見うまくいっているようですが、これが正しいネットワークであり、結果も妥当なのがまだ確信は持てません。


グラフィカルに作成したニューラルネットワークで、XORを学習させる

 しかし、人工知能となる(ディープな)ニューラルネットワークをこんなに簡単に構成できて、学習させることができるならば、そのインパクトは大きいのではないでしょうか。今後、さらに調査し、応用を深めたくなります!

2017年7月17日月曜日

マルチコア並列の性能を見る

 学生の皆さんが持っているノートPCですが、マルチコアになっています。それを意識している学生諸君はほとんどいないように思われます。実質4台のCPU(正確には、多くの場合、2コア×2ハイパースレッディング)が載っているのに!

 情報工学応用ユニット1のある実験のある課題では、ここに焦点を当てました。通常のプログラミング言語で、この4台のCPUを使った並列プログラムを書いて動かすことはとても困難です。しかし、Java SE8の並列ストリームとラムダ式を使うと、非常に簡単にそのような並列プログラムを作成し、動かすことができます。

 この実験での課題は、「見出し語が約12,000語の英語辞書」を使って、「約1,000語のミススペル語を正しいスペルに直せ!」という問題です。Windowsの標準機能である「リソースモニタ」を使うと、以下のような綺麗なCPU稼働状況が分かります。解答した学生諸君の中には、もっときれいな(逐次と並列の対比がより明確な)図を提出した人もいます。

[図が小さいので、拡大してご覧下さい]

2017年7月16日日曜日

IT夢コン2017のピア賞 投票快速集計アプリ

 今年も、本学で開催の「IT夢コン2017」の最終選考会が迫ってきました。生徒同士が、互いに発表ポスタを評価して決める「ピア賞」もあります。その投票の集計ですが、当日、スケジュールがタイトであるため、すばやく、確実に行う必要があります。そこで、作成したのが、下図のAndroid用「快速集計アプリ」です。

 以下の画面のデータは、テスト用の架空のデータです。模擬投票の結果は、投票者数=52名、投票総数=133票、第一位は35番の作品、第二位は31番の作品となりました。



 さて、このAndroidアプリ、大した機能はなく、トリビアルな処理に見えます。確かにそうですが、そうでもないところも少しあります。このアプリ設計での留意点を列挙します。


  • このようなユーザインタフェースを持つAndroidアプリの作成は、MIT App Inventorの得意とするところであります。特に、画面タッチ。その効率的開発の恩恵を受けます。
  • 多数のボタンがあります。それを効率良く配置し、ボタンに対する反応(アクション)も効率良く書きたい。
  • 集計中に、不意に中断せざるを得ないかも知れない。中断と再開内部データベースを使って実現する。
  • 集計中に、画面を不意に触れてしまい、カウントがダメになることを防ぎたい。そのために、ボタンの「クリック」ではなく「ロングクリック」による反応を用いる。
  • 来年度も使いたい。また、今年度も直前に何かデータの修正があるかも知れない。したがって、ポスター作品データは、プログラムに組み込むのではなく、テキストファイル(スマホのSDカードに保存)に記載する。
  • 想定投票者50名、投票総数150票で、結果をえるまでに5分と見積もる。上記の「ロングクリック」で6割ほど時間が増すが、確実性を重視します。


2017年7月15日土曜日

スマホでマルチエージェントモデリング!

 社会現象、物理化学現象、生物/生命現象、コンピュータアルゴリズム等をモデル化し、シミュレーションによってその現象を解析したり、予測を行うための手法として、「マルチエージェントモデリング」があります。そのためのソフトウェアはいくつかあるのですが、NetLogo(無償)が非常に有力なものの一つです。NetLogoは昨年から、メニューやテキストに日本語が使えるようになり、いっそう身近なものになりました。

 さらに、すばらしい機能があります。これまでのマルチエージェントモデルはPCの上で動く重たい処理が付きものでした。しかし、ここに来て、スマホでも事実上実行できるようになりました!(正確に言えば)Web版が公開されています。PCには、何も専用ソフトは要らず、ブラウザからNetLogoのソースファイルを指定すれば、スマートフォンの画面でも実行できるのです。もちろん、(画面が小さくちょっとやりにくいが)その場で、NetLogoソースコードも編集できます。

 これで何か新しい方向が生まれそうです。詳しくは言えませんが、例えば、
→「スマホのカメラで現場を撮影する」
→「人工知能による画像解析で被写体の特徴をテキストで得る」
→「マルチエージェントモデルのパラメータにそれ反映させる」
→「その場で、スマホの画面で実行させる」

というような使い方も起こるだろう。

有名な「羊」と「オオカミ」の生存のダイナミクス:Androidスマホでの実行

「環境にどのように影響されるか」の私のモデリング:Androidスマホでの実行

2017年6月30日金曜日

人工知能アプリの開発体験講座

オープンキャンパスや、受験生向けの講座では、「人工知能」を利用したアプリ開発が多分注目されるものの一つでしょう。単に、人工知能関係アプリをダウンロードして使うだけではありません。自分で自分なりにアプリケーションを組み立てるのです。(人工知能サービス、人工知能のためのAPIは使いますが。)

ここでは、MicrosoftImage Recognizerという人工知能サービスと、Androidのアプリケーション開発環境であるThunkableを使ってアプリを作成します。単に作成するだけではなく、フィールドワークとディスカッションもセットにします。

step1: 1時間くらいで、下図のようなアプリを作ります!できます!
step2: この「人工知能アプリ」を持って、学内を撮影してもらいます。
step3: 人工知能の認識結果に対して、生徒の皆さんに評点を付けてもらいます。
step4: それを画像とともに、Dropboxへ格納して皆で共有できるようにします。。
step5: 研究室へ戻って、ディスカッションしましょう。どんな認識が得意なのか。

以下に、プロトタイプをテストした際の、学内の風景などの認識の具合を示します。例えば、「野球場のクローズアップ:a closeup of a bseball field」という認識結果には、私は満点の100点を与えました!













2017年5月14日日曜日

Java 8 ラムダ式の初歩(続き2)

 Java8のラムダ式と「Javaオブジェクトの集合(Collections)とそのソート」には、重要な関係があります。非常に簡単な例は下記のものです。 
 
=====================================
// 学部名のリストを作り、その文字数で昇順に並べる。 
import java.util.*;public class ListSort_Lambda{
  public static void main(String... args){

List<String> list = Arrays.asList("E:工学部", "C:創造工学部",
"I:情報学部","A:応用バイオ科学部","N:看護学部" );

// sortの第⒉引数に(Lambda Expressions)を与える
Collections.sort(list, (s1, s2)-> s1.length() - s2.length());

System.out.println("学部名を文字数の昇順に列挙します:");
 list.forEach(s -> System.out.println(s)); //内部反復にラムダ式
  }
}
=====================================

 上記のリストについての、詳細な説明は以下にありますので、ご覧いただければ幸いです。
http://kait-kbook.sakura.ne.jp/it/+6360-4/^06-Sort-of-List-Map(A)@(2016.5.23%2013.00-).pdf

2017年5月13日土曜日

Java 8 ラムダ式の初歩(続き1)

 前回の続編として、ラムダ式(Lambda Expressions)の続きを検討してみます。
 下図は、自分が最も関心のあるキーワード(一つだけ)を含むタイトルの書籍を何冊持っているかを示しています。そのキーワード毎に、学生が持っている書籍数を合計するカウントプログラムを考えます。

最も関心の高いキーワードを含む書籍を何冊持っているか?

 やりたいことは自明であり、とにかくプログラムを作ることはできます。しかし、ここでは、書籍のカウントの仕方を問題にします。よくあるプログラムでは、カウントするためのメソッド(関数)の内容は、「指定されたものをカウント(合計)する」のと「カウントすべきものは何か、それをどのような手順で決めるか」が混っていることがあります。

 ここでは、後者の「カウントされるものが何か(どの本か)」を、前者の「カウントすること」から分離させることを考えます。それによって、書籍の種類を追加したり、合計したい本に何らかの条件を付けたりしても、前者の「「指定されたものをカウント(合計)する」関数は変更を受けないはずです。これは古くからあるデザインパタンの一つ(関心の分離:seperation of concernsですが、ラムダ式を用いることによって、いっそう柔軟な実装ができます。

 以下のプログラムは、Venkat Subramaniam氏の書籍[1]を参考に作りました。このなかで、【方式1】は、氏の方式に沿ったものです。一方、【方式2】は、当方で独自に修正してみたものです。【方式1】では、カウント関数 countAを呼び出す際に、「何をカウントすべきか」を決める手続きをラムダ式で(t -> t.type == Type.Keras のように)渡している所に特徴があります。

 一方、【方式2】は、関数呼び出しの度に同じような形のラムダ式を与えたくないので、ラムダ式自体を分離してみました。しかし、それは、カウントする関数 countBの中に含まれているので、「関心の分離」からは好ましくないようです。結論として、【方式1】に従うのがよさそうです。ただし、【方式2】もラムダ式の活用練習にはなるでしょう。

========================================
package designing.fpij;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import designing.fpij.Student.Type;
public class StudentManager2 {
  
  // 【方式1】Venkat Subramaniamの書籍の方式(但し、以下のコードは山本自作)
  public static int countA(List<Student> sts, Predicate<Student> selector){
  return sts.stream().filter(selector).mapToInt(s -> s.number).sum();
  }
  // 【方式2】Venkat Subramaniamの方式の変更版(以下のコードは山本自作)
  public static int countB(List<Student> sts, Type type){
    Predicate<Student> selector = s -> type == null ? true: s.type == type;
    return sts.stream().filter(selector).mapToInt(s -> s.number).sum();
  }

  public static void main(final String[] args) {
    List<Student> students = Arrays.asList(
    new Student(Type.Java8, 3), new Student(Type.Python, 1),
    new Student(Type.NetLogo, 1), new Student(Type.Python, 2)
    );
    
    // 【方式1】を使った実行
    System.out.println("total:" + countA(students, t->true));
    System.out.println("Keras:" + countA(students, t->t.type==Type.Keras));
    System.out.println("Python:" + countA(students, t->t.type==Type.Python));    

    // 【方式2】を使った実行
    System.out.println("total:" + countB(students, null));
    System.out.println("Keras:" + countB(students, Type.Keras));
    System.out.println("Python:" + countB(students, Type.Python));
  }
}

class Student {
    public enum Type {Java8, Python, NetLogo, Keras }; 
    protected Type type;
    protected int number;
    public Student(Type type, int number) {
        this.type = type;
        this.number = number;
    }
}
========================================
実行結果:【方式1】,【方式2】とも同一
total:7
Keras:0
Python:3
========================================

[参考文献]
[1] Venkat Subramaniam : Functional Programming in Java, O'Reilly, 2014.
(O'Reilly Japanから、和訳本も出版されている)