27 Jul 2017, 15:30

Deep Learning に挑んだ半年間、そして今後の勉強計画について

はじめに

半年くらい前、まだ機械学習についてなにも知らなかったときに、書いた記事が炎上してとても恥ずかしい思いをした(記事は非公開にしました)。

この記事はただの日記です。

この半年で取り組んだこと

この半年で、機械学習の勉強はせずに、ディープラーニングと強化学習の勉強をした。

3月〜7月

上記記事を書いてモチベーションを高め、さあ機械学習のための数学をやろうと意気込んでいたのだけれども、すぐに気が変わって、機械学習の王道を進まずにディープラーニングに突っ込んでいった。なぜなら、Udacity で Deep Learning Nanodegree Foundationという4ヶ月の講座を受講し始めたからだ。

この講座に 3月から7月までの4ヶ月間取り組むことによって、

  • Deep Learningという学問分野の概要を学んだ(NN, CNN, RNN, GAN)
  • TensorFlowで実装できるようになった。

このDLND、超初心者向けな講座で、手取り足取り Deep Learningを教えてくれた。なので、数学が必要なかった(笑) あれ、おかしいな、ディープラーニングって、もしかして数学あんまり必要ない??統計とかほとんど出てこないよ。

4月〜5月

また、同時進行で Fast.aiのPractical Deep Learning for Coderという講座も受講したのだが、これがまたすごくいい講座。

この講座の理念は、Deep Learningの敷居を下げて、誰もがDeep Learningを簡単に使えるようにすること。もちろん、ここでも難しい数学は抜き!そして、ここで Keras という Deep Learningをおそろしく簡単にするライブラリを知ってしまう。これをしったら、numpyの実装はおろか、tensorflowですら面倒に感じてしまう。この講座によって、

  • Kerasでバリバリコーディングできるようになった。
  • Kaggler としてデビューし、画像系コンペなら、いい結果を出せるようになった。

というわけで、この2つの講座によって、この半年でバリバリのディープラーニングコーダーになったのだった。

6月〜7月

しかし転機はまたやってきた(コロコロ変わる…)。会社にAIの勉強をしてます!といったら、「うちにはAIの仕事はまったくないよ!」といわれ、さらには「そんな役に立たない勉強よりも、Javaの資格とらないとクビにするよ」という脅しまでされたのだった。

というわけで、AIとの付き合い方について、考えを見直さざるを得なくなってしまった。今の会社は、組込みソフトの受託開発がメインだ。組込みソフトと AIがどう関係するのだ???うーん、と悩んだところ、2つの答えにたどりついだ。

  • 強化学習
  • ロボティクス

というわけで、強化学習の勉強とLEGO Mindstormsを使ったロボット制御の勉強をはじめた。

これにより、

  • OpenAI Gymデビューし、強化学習問題が解けるようになった。
  • 強化学習やロボット制御の理論を LEGO Mindstormsで試すことができた。

これから取り組むこと

数学の苦手意識を克服

この半年間で、理論よりは実践重視でバリバリコーディングしてきたのだけれども、ディープラーニングが趣味レベルで中途半端にできるだけでは、仕事には生かせないし、なにもできない!!

そもそも、である。機械学習に興味を持った理由は、数学を使って現実問題を解決するところがかっこいいと思った憧れからである。そのために、大学では数学を専攻したはずだった。

大学を卒業して10年くらい経った。大学は情報系の専攻で、卒業研究は、情報理論 を学んだのだが(学部卒)、10年も経って数学から離れていたらすっかり忘れてしまった。なので、大学の数学を一から学び直したい。

また、やっぱり数学が壁で挫折したことが、この半年間でたくさんあった。

数学で撃沈した思いでをつらつらと並べたい。

  • 誤差逆伝播法が理解できず挫折。(これはデーィプラーニングがわかる数学という本によってようやく理解できた)
  • Udacity: Artificial Intelligence for Roboticsや確率ロボティクスでベイズ統計や確率が理解できず挫折。
  • Deep Learning Nanodegreeで学んだことの先にいこうとすると、論文を読んでいかないといけない。しかし、論文を開くと数式の羅列に意味が分からずフリーズ。
  • 深層学習(イルカ本)挫折。
  • Deep Learning Javaプログラミング 深層学習の理論と実装、挫折。生成モデル??
  • Siraj Ravalの The Math of Intelligence 挫折。

というわけで、数学、やります!

プログラミングのための30代からのやり直し数学である。

勉強の方針

大学生のころは、理学系だったので、数学の勉強は定理と証明の繰り返しだった。ソフトウェア開発者になると、数学に対する姿勢は工学系よりになる。

  • 理論よりも応用を考える
  • この定理がどう役に立つかを考える
  • 抽象性よりも、具体的イメージを
  • 証明の厳密性はほどほどに(理解できることに越したことはないが)

大学1,2年生の数学の復習

機械学習で必要な数学とはなにか、それは情報系の大学生が1,2年生で習う数学で十分という意見が多い。私は、情報系の専攻だったのだけれども、そこで習った数学は以下の4つ。

  • 線形代数
  • 解析学
  • 統計学
  • 離散数学

離散数学は、TopCoderなどのアルゴリズムコンテストにとても役に立ちそうな分野だ。機械学習との関係は、よくわからなかった。集合や代数的な知識は、線形代数を勉強することで、身につけられそう。離散数学の勉強は保留で。

基礎固めのための参考書はマセマで

やり直し数学ということで、最近大学生の間で評判の高いマセマシリーズで基礎固めをすることにした。高校数学から大学数学への考え方の移行がスムーズにいける、定理の証明に手を抜いていないのでガチ、コメントが多くページを遡って読みなおす必要がなく読みやすい、などの印象を受けた。

基礎ということで、以下の3つをすすめることにした。これで、まずは、大学の初等数学を復習する。

  • 線形代数
  • 微分積分
  • 統計学

基礎の補強と応用へ

マセマは数学をとても簡単に(でも手を抜かずに)書かれているけれども、知識を厚くし、また別の角度から知識を補強したい。そこで選んだのが「プログラミングのための〜」のシリーズ。

解析系がこのシリーズにないので、代わりに最適化数学をメニューに組み込む。また、機械学習ではベイズ統計が使われるので、メニューに組み込む。

  • プログラミングのための線形代数
  • プログラミングのための確率統計
  • これなら分かる最適化数学
  • Pythonで体験するベイズ推論 PyMCによるMCMC入門

数学を復習したら機械学習へ

数学力を強化したら、もともとの目標である機械学習の勉強に着手したい。まずは、はじパタから。

理論よりも実践を重視したいので、なるべくPythonとJupyter Notebookでプログラミングできる教材を使って勉強していきたい。

ココらへんまで来たら、Kaggleにもガンガン挑戦していきたい。Deep Learningの手法のみに頼らずに、いろんな手法から最適な方法を取捨選択できるようになりたい。

その他、情報理論を勉強したい。この本は、情報理論的な立場から機械学習を捉えているらしいので、気になっている。

読みたい本

目指すは、機械学習の登竜門、パターン認識と機械学習(PRML)

また、確率ロボティクスも挫折したので、数学力をつけて再挑戦したい。

その他の勉強

Deep Learning

今後はDeep Learningの勉強は抑えて他の勉強にリソースを割り当てる。

ただし、fast.aiの Deep Learning のオンライン講座 Cutting Edge Deep Learning for Coders は進める。この講座はほんとうによい講座なので、引き続き受講する。

Deep Learning Book の 本が翻訳されたら、勉強を再開しよう。

ロボティクスと強化学習

仕事で AI を活用するためには、この2つの分野の学習が必要なので、ここに力点をいれていく。

具体的には、Udacity Robotics Nanodegreeを半年間に渡って受講します。おそらく、これはかなりの負荷になるので、他のことをやる時間がとれなくなるかもしれない。

また、強化学習は 次期 MLPシリーズで発売が予定されているので、その本が発売されたら勉強を再開したい。

まとめ: 今年やること

まとめると、今年の残りの予定は以下の3つだ。

  • 機械学習のための数学力強化
  • Udacity Robotics Nanodegree
  • fast.ai Cutting Edge Deep Learning for Coders

26 Jul 2017, 03:34

UdacityでArtificial Intelligence for Roboticsを受けた

UdacityでArtificial Intelligence for Robotics(CS373)を受けた。

[https://www.youtube.com/embed/g-fk3RQiw5Q]

しかしながら、この講座はとても難しく、挫折した。

なので、簡単に内容の紹介と感想を書く。

動機

Udacityの Deep Learning Nanodegree を受講し終わったので、

次の講座として Robotics Nanodegreeの受講を考えている。

その間のつなぎの講座として、タイトル惹かれてこの講座を受けてみることにした。

また、最近 LEGO mindstormsを購入したので、学んだことを応用できればいいなと思っている。

内容

Googleの自動運転車の要素技術について学ぶ講座。この要素技術は、自動運転車に限らずあらゆるロボティクスについて応用できるとのこと。講座のタイトルが昔は Self Driving Car だったが今の AI for Roboticsに変わったようだ。

講師は、Udacityの創立者にしてGoogleカーのエンジニア、セバスチャン・スラン氏。すごい。

シラバスは以下のとおり。

Lesson1-3は自己位置推定(Localization)について、4,5は探索と制御について、6は地図生成だ。

  • Lesson 1: The Problem of Localization ・・・ヒストグラムフィルタについて学ぶ
  • Lesson 2: Kalman Filters ・・・ カルマンフィルタについて学ぶ
  • Lesson 3: Particle Filters ・・・粒子フィルタについて学ぶ
  • Lesson 4: Motion Planning ・・・経路探索について、幅優先探索、A*, 動的計画法について。
  • Lesson 5: PID Control ・・・経路の平滑化、PID制御について学ぶ。
  • Lesson 6: GraphSLAM ・・・ Lesson1-5まで学んだまとめ、おまけとしてGraphSLAMについて。

途中、よくわからなくなったので、参考書を買った。確率ロボティクス。スラン先生の本だ。

講座の進め方は、ミニクイズとPythonによるプログラミング課題が、説明のあとに出される。少しずつ難易度が上がっていくので、理解しやすい。そして、週の終わりにミニテストとプログラミング課題が出される。一応リポジトリを起こして、コードを書いた。

この講座、一番うれしいところは、すべての動画に日本語字幕がついているところだ。

その他、Forumが充実しているところもうれしい。が、講座が開講された2012年のころの投稿が多い。

感想

難しく、挫折した。一応、動画は最後まで目を通した。これが完全に理解できれば、君はスタンフォードの優等生だと講義でいっていた。むりだー。

少し飛ばしぎみで講義を進めていったので、深くは理解を深めようとしていないからかもしれない。

大体ひとLesson 5時間くらいかければ終わる。

無料の講座だとついつい気が緩んで真剣にとりくまないのかもしれない。

この講座は、今の Self-Driving Car NanoDegreeに内容が引き継がれているようだ。

DeepLearning Nanodegreeのあとの進路は、Self-Driving Car, Artificial Intelligence, Roboticsの3つに分かれるのだが、自分は 組込み屋なので、Roboticsに決めている。ただ、自動運転車の講座もおもしろそうだと思った、と同時に難しそうだと思った。自分には、Roboticsを挫折しないでやり遂げる能力があるのだろうか・・・。

挫折したことが悔しいし、確率ロボティクスの本も買ったことなので、いつかこの講座をやり直そう。ロボティクスでも、自己位置推定が扱われるようなので、そのときに振り返ることにする。

Path Planningや PID制御は LEGO Mindstormsで実際に試せそうだ。時間があればやってみよう。

25 Jul 2017, 21:55

(失敗) Leap Motionで Mindstorms EV3をリモートコントロールしてみた

(失敗) Leap Motionで Mindstorms EV3をリモートコントロールしてみた

うまくいかなかった。

前進、後退はうまくいくのだが、左右への旋回が失敗する。

動画

[https://www.youtube.com/embed/a_fWdyaC93A?ecver=1]

Code

25 Jul 2017, 13:23

MQTTでMindstorms EV3のロボットカーを パソコンのキーボードからリモコン操作

LEGO Mindstorms EV3 を パソコンのキーボードから操作してみます。

私は、LEGO Mindstorms EV3の教育版を買ったので、家庭版と違いリモコンがありません。でも、ラジコンのようにロボットカーを操作したい!そこで、MQTTというプロトコルを利用して、ノートPCのキーボードを使ってロボットカーを制御する方法を思いつきました。

まずは、結果をどうぞ!

[https://www.youtube.com/embed/kl_07BWGNWo?ecver=1]

環境

  • Publisher(PC) Ubuntu 16.04
  • Subscriber(ev3) ev3dev
  • Python 3.6
  • ev3dev-lang-python

ロボットの組み立て

この本に載っているtribotを作成しました。

Setup

MQTTという軽量な通信プロトコルを使った方法がev3devのサイトに紹介されていたので、それを参考にする。

MQTTではpublisher(出版者)が発するメッセージをbroker(仲介者)がsubscriber(購読者)へ配信する。今回は、publisherが ノートPC, brokerとsubscriberが ev3になる。

ev3に brokerサーバソフトをインストールする。mosquittoというソフトをインストール

sudo apt-get install mosquitto

インストールが完了すると、サービスが立ち上がる。

続いて、mqttをPythonで使うための pahoというソフトをノートPCと ev3の両方にインストール。

sudo apt-get install python3-pip
sudo pip3 install paho-mqtt

PC 側

pip3 install paho-mqtt

これで、MQTT で通信する準備は整った。

punput

Pythonで押されたキーボードのキーの取得をするために、punputというライブラリを利用する。

ラズパイカーで同じようなことを考えている人のブログ記事を発見した。これはありがたい。

コード

最後に、書いたコードが以下。これで、キーボードの十字キーを使ってロボットカーをリモコン代わりに操作することができた。

25 Jul 2017, 06:51

Leap Motion を Pythonから使う方法を調べた

Leap Motion を Pythonから使う方法を調べた。

環境

  • Ubuntu 16.04, 64bit
  • Leap Motion SDK 2.3.1
  • Python 2.7.13

Pythonは 2系でしか動かないようだ。私はAnacondaを利用して、2系の環境を構築した。

必要なファイルを揃える

まずは、前回の記事に従って、Leap Motion SDKをインストールする。

Linux用のtarファイルを解凍すると、LeapSDKというフォルダがあるので、そこに移動。

Leap Motionを Pythonから操作するためには、以下の3ファイルが必要。

  • lib/Leap.py
  • lib/x64/libLeap.so
  • lib/x64/LeapPython.so

(64bitはx64/32bitはx86フォルダ)

作業用ディレクトリを作成して、そこに3ファイルをコピーする。

mkdir -p ~/repo/leap
cp lib/Leap.py ~/repo/leap
cp lib/x64/libLeap.so ~/repo/leap
cp lib/x64/LeapPython.so ~/repo/leap

LeapSDKの中にSample/Sample.pyがあるので、まずはそれを作業用ディレクトリにコピーして動かしてみる。数値がたくさん現れれば成功。

cp samples/Sample.py ~/repo/leap/
cd ~/repo/leap/
python Sample.py

基本スニペット

Leap Motionのプログラムの書き方は、Listener型とPoling型がある。

Listener型は、Leap Motionのフレームワークで Loopがある場合、

Polingは Leap Motion以外のフレームワークで Loopがある場合に使う。

サンプルコードに従って、Listener型の基本スニペットを書く。

import Leap, sys

class SampleListener(Leap.Listener):
    def on_frame(self, controller):
        # Get the most recent frame and report some basic information
        frame = controller.frame()
        print "Frame id: %d, timestamp: %d" % (frame.id, frame.timestamp)

def main():
    # Create a sample listener and controller
    listener = SampleListener()
    controller = Leap.Controller()

    # Have the sample listener receive events from the controller
    controller.add_listener(listener)

    # Keep this process running until Enter is pressed
    print "Press Enter to quit..."
    try:
        sys.stdin.readline()
    except KeyboardInterrupt:
        pass
    finally:
        # Remove the sample listener when done
        controller.remove_listener(listener)


if __name__ == "__main__":
    main()

main関数は変更せずに、on_frame()メソッドの中身だけ修正すれば良さそう。

frameに現在の情報がすべて含まれているので、そこからいろいろ取り出す。

手の座標を取得

まずは、手の座標を取得してみる。

on_frameの中に以下を書き込む。

    hands = frame.hands
    hand = hands[0] # first hand
    print(hand.palm_position)

palm_positionで手のひらの中心の座標が手に入る。実験してみた結果、手の座標が、(x, y, z)のタプルで取得できた。

(41.2968, 119.34, -71.5027)
(40.8835, 122.556, -71.095)
(38.7474, 126.202, -69.3811)
(36.5977, 130.135, -66.6525)
(34.1101, 134.531, -63.37)
(31.7521, 137.867, -59.3138)
(28.9372, 141.859, -54.9556)
(27.5701, 145.658, -50.0342)
(25.3786, 149.093, -45.6736)
(23.8103, 152.436, -40.7532)
(21.8484, 156.879, -36.0352)

ジェスチャーを検出する

ジェスチャーは4種類ある。今回は、Key Tapというジェスチャを試す。

ジェスチャーの検出には、事前の登録が必要。on_connect() でジェスチャーを登録する。

def on_connect(self, controller):
    controller.enable_gesture(Leap.Gesture.TYPE_KEY_TAP);

on_frameに以下を追加。

for gesture in frame.gestures():
   if gesture.type == Leap.Gesture.TYPE_KEY_TAP:
        print "  Key Tap id:", gesture.id

ジェスチャーを以下のようにすると、反応する。

Key Tap id: 1
Key Tap id: 2
Key Tap id: 3
Key Tap id: 4

とりあえず、今日はここまで。

25 Jul 2017, 02:11

Ubuntuに Leap Motion SDKをインストールした作業メモ

机の中に眠っていたLeap Motionを数年ぶりに使ってみようと思う。

Ubuntuに Leap Motion SDKをインストールした作業メモです。

環境

  • Ubuntu 16.04
  • Leap Motion SDK 2.3.1

SetUp

公式サイトからLinux用のSDKをダウンロード

cd Downloads
tar xvzf Leap_Motion_SDK_Linux_2.3.1.tgz
cd LeapDeveloperKit_2.3.1+31549_linux
sudo dpkg -i Leap-2.3.1+31549-x64.deb

エラーが発生した。leap deamonがない。

Failed to start leapd.service: Unit leapd.service not found.
dpkg: パッケージ leap の処理中にエラーが発生しました (--install):
 サブプロセス インストール済みの post-installation スクリプト はエラー終了ステータス 5 を返しました
ureadahead (0.100.0-19) のトリガを処理しています ...
ureadahead will be reprofiled on next reboot
処理中にエラーが発生しました:
 leap

解決策がForumにあった。パッチを当てればいいらしい。(パッチは結局失敗する、後述)

  • Leap Motion SDK fails to install properly on Ubuntu 15.04 – Customer Support – Leap Motion Community

    Download the .tgz file from https://www.leapmotion.com/setup120, extract, and download the patch file to /tmp/patch:
    tar xzf Leap_Motion_Setup_Linux_2.3.1.tgz
    cd Leap_Motion_Installer_Packages_release_public_linux
    wget -O /tmp/patch https://gist.githubusercontent.com/jmwilson/8e6c579eac5fa7fa9f0d/raw/0b597ceb1f8184952bf067267ac4171691949068/patch
    
    Extract the .deb file into a new leap directory and enter it:
    dpkg-deb --raw-extract Leap-2.3.1+31549-x64.deb leap
    cd leap
    
    Patch the contents of the current directory:
    patch -p2 </tmp/patch
    
    Go back to the parent directory and build a new .deb file:
    cd ..
    fakeroot dpkg-deb --build leap (this can take a while...)
    
    Install the patched .deb:
    sudo dpkg --install leap.deb
    

patchを当てても動かなかった。他の人も同様の症状がでているみたい。

解決策がforumにあった。

  • Linux install of SDK fails – Development – Leap Motion Community

    1 - After the install failure, I simply uninstalled with:

    sudo dpkg -r leap

    2 - Now, with no leap installed yet, I followed the post above and just created the file as mentioned there (I used the terminal to write the following command, to use the nano text editor as root user):

    sudo nano /lib/systemd/system/leapd.service

    3 - I pasted that content (reproduced here for easiness): (also please note that on Ubuntu terminal, you paste with CTRL+SHIFT+V instead of just CTRL+V)

    Found by Kevin Cole 2014.11.22 at

    https://github.com/atejeda/leap-fedora-rpm

    #

    Remember to:

    #

    ln -s /lib/systemd/system/leapd.service /etc/systemd/system/leapd.service

    systemctl daemon-reload

    # [Unit] Description=LeapMotion Daemon After=syslog.target [Service] Type=simple ExecStart=/usr/sbin/leapd [Install] WantedBy=multi-user.target

    4 - Saved (CTRL+O then ENTER), and exited (CTRL+X)

    5 - Still using the terminal, executed the two commands from that same post, BUT I included the sudo prefix to run them as root user:

    sudo ln -s /lib/systemd/system/leapd.service /etc/systemd/system/leapd.service sudo systemctl daemon-reload

    6 - All is right now and we can properly install. So, I just installed the original package:as in the official Leap guide:

    sudo dpkg –install Leap-2.3.1+31549-x64.deb

    (please just note that I'm using a x64 Ubuntu, so I installed the 64 bits package)

    7 - Done!!!

これでうまくいった!

確認

LeapControlPanelを起動する。ツールバーにLeap Motionのアイコンがでて、緑色になった。

試しに、Diagnostic Visualizerを起動してみる。手が正しくトラッキングされていることが分かる。

23 Jul 2017, 13:55

Twiddle(いじりまわし)でPID制御のパラメータ(ゲイン値)を求める

はじめに

前回の続き。

PID制御での、疑問点は、どうやってP,I,Dのゲイン値を求めるかということだ。

これについて、twiddle(いじり回し)アルゴリズムというのがあり、PIDのゲイン値の最適解が簡単に求まるらしい。

日本語の情報はおろか、英語の情報もなく、あるのは、AI for Roboticsの Forumの投稿記事くらいなので、どっからでてきたアルゴリズムなのかわからないけれども、スラン先生曰く、これは簡単に実装できて、とても強力、だそうだ。

アルゴリズム

  • 講義動画

[https://www.youtube.com/embed/2uQ2BSzDvXs]

  • スラン先生の板書。

ちょっと板書が汚いので、清書。

  • p = [0, 0, 0], dp = [1, 1, 1] で初期化する。
  • シミュレーションを実行して、best_error を求める。
  • while: sum(dp) > (しきい値)
    • for i in (パラメータ数)
      • p[i] += dp[i]
      • シミュレーションを実行して、error を求める。
      • if error が best_error よりも小さい
        • best_error = error
        • dp[i] = dp[i] * 1.1
      • else
        • p[i] = p[i] – 2*dp[i]
        • シミュレーションを実行して error を求める。
        • if error が best_errorよりも小さい
          • best_error = error
          • dp[i] = dp[i] * 1.0
        • else
          • p[i] = p[i] + dp[i]
          • d[i] = d[i] * 0.9

実装

前回と同じ、Afrel 楕円コースでのPID制御を用いた軌道走行を考える。

23 Jul 2017, 09:30

Afrel楕円コースの軌道をロボットカーでPID制御を使ってシミュレートしてみた

[mathjax]

はじめに

Udacityで Artificial Intelligence for Roboticsを受けている。

[blogcard url=”https://www.udacity.com/course/artificial-intelligence-for-robotics&#8211;cs373&#8243;]

この講座は、Googleカーの要素技術について学ぶ講座。 講師は、Udacityの創立者にしてGoogleカーの開発者、セバスチャン・スラン氏だ。

lesson5のテーマはPID制御。

この記事では、PID制御の概要を自分なりに整理し、目標とする軌道上をロボットが動くシミュレーション(Homework5.4)問題を書く。

PID制御とは

講義資料

講義動画

[https://www.youtube.com/embed/-8w0prceask]

PID制御とは、制御に使われる古典的な手法。P, I, D はそれぞれ、

  • P ・・・Propotional(比例)
  • I ・・・Integral(積分)
  • D ・・・Differential(微分)

を意味している。

今、自動車の制御を考える。目的とする基準軌道(横座標)と、車との距離をCross Track Error(CTE) という。

このときの望ましい制御は、CTEに比例して車のハンドルを切ること。そうすることで、スムーズに基準軌道へと車を近づけることができる。

今回、実験に使ったコードは以下。講義のなかのコードから抜粋した。

P 制御

Pは Propotional(比例)を表す。CTEに比例してハンドルを切る。式で表すと、

$$

steering = – \tau_p ・CTE

$$

厳密には、0 – \tau_p ・CTE としている。この問題設定では、xy座標で考えると、y=0を基準軌道としている。なので、(目標値) – (出力値) において、(目標値)が0となり、マイナス項だけが残る。

これをP制御という。P制御は、CTEが小さくなる、基準軌道に近づくに従って、修正量も比例して小さくなるようになっている。

しかし、P制御には、問題がある。以下の図のように、P制御しようとすると、基準軌道を通り越す(オーバーシュートという)してしまう。基準軌道に近づいては離れを繰り返して、安定しない。

PD制御

そこで、時間tで微分したCTEを式に加える。CTE_DIFFは時刻t-1におけるCTEから時刻tのCTEを引いた値。

$$

steering = – \tau_p ・CTE – \tau_d ・CTE_DIFF

$$

これによって、基準軌道にそった結果が得られた。

これを、PD制御という。

微分項を加えることで、制御の 反応性 が増す。この基準軌道の例では、仮に急激なCTEの減少が起こった場合、下の方にsteerを切りすぎないようにCTE_DIFFの値が大きくなって、オーバーシュートすることを防ぐ。

PID制御

I制御は、理解が曖昧で自分の言葉で説明できるかわからないので、参考にしたサイトの言葉を引用します。

偏差が小さいときに操作量が小さくなり過ぎてしまい、制御量が目標値とずれたところで安定してしまうということです。P制御の制御量は目標値より下側で安定してしまいます。この制御量と目的地の差を「定常偏差」あるいは「オフセット」と呼びます。

これは、例えば、タイヤが少し傾いていて、ハンドルを一定に切っても基準軌道に近づいてくれないようなシチュエーションで発生する。講義では、以下のようなメソッドで10度タイヤをずらすようなことをやっていた。

  robot.set_steering_drift(10.0/180.0*pi)

以下は、タイヤがずれた状態でのPD制御。

また引用。

ライントレーサの場合、P制御のパラメータ(Kp)が適正であれば、直線を走っているとき制御量は目標値付近で安定します。しかし、カーブがはじまるとオフセットが発生します。

カーブがはじまったとき、P制御によってその時点ごとの制御量に応じた操作量を決定し、カーブを曲がろうとします。目標値から離れれば離れるほど操作量が上がるP制御ですが、それは長所であると同時に短所にもなります。なぜなら、偏差が小さいと操作量も小さくなり、カーブの最中に偏差0の位置まで戻れず、カーブの外側に寄ってしまうからです。この状態が、目標値と違う場所で安定してしまう“オフセットが発生している状態”です。

オフセットが発生していてもカーブを抜けられればよいのですが、場合によってはコースアウトしてしまうことがあります。では、Kpを大きくし偏差が小さいときの操作量も大きくなるようにしてはどうでしょうか?

こうすることで、オフセットの発生は防げます。しかし、P制御では現在の値しか見ないため、いま直線にいるのか、カーブにいるのかが分かりません。そのため、P制御でせっかく力の抜き方を決めているのにもかかわらず、P制御のパラメータを大きくすると、カーブの間はいいのですが直線に戻っても操作量が大きくなってしまいます。その結果、せっかくオンオフ制御から改善したハンチングが再発する可能性があります。

そこで、「I制御」を用いてカーブにいる間だけ、操作量を上げるようにしましょう。

というわけで(笑)、I制御が必要となってきます。PD制御にIを加えた、最終的なPID制御式は、以下。

$$

steering = – \tau_p ・CTE – \tau_d ・CTE_DIFF – \tau_i ・* int_CTE

$$

$int_CTE$ は、時刻tまでのCTEの総和。これがハンチングに効いてくる。実験結果は以下。

Homework5.4

AI for Roboticsの Homework5.4は、レーストラックの軌道上をPID制御を使ってロボットカーを走らせるシミュレーションをすること。

自分は、課題のレーストラックを少し修正して、Afrelから売り出されている楕円コースの軌道をロボットが描くように修正してみた。

寸法は実物と同じなので、mindstorms ev3で実際にロボットカーをつくって走らせれば、軌道上をロボットが走行するはず!!実物を走らせるのは、次回!!

参考

12 Jul 2017, 13:57

USDJPYのヒストリカルデータをダウンロードしてDQN Agentを動かしてみた

前回の続き。

USDJPYでバックテスト

今回は、DukascopyからUSDJPYのヒストリカルデータをダウンロードして、DQN Agentを動かしてみました。

すごく苦労して、なんとかDQN Agentに学習させることに成功した。

ロジックは、前回とほぼ同じです。今回の Jupyter Notebookは以下。

苦労した点

  • はじめ、keras-rlで testメソッドを走らせたあとに、rewardが0になってしまった。いくら論理を見直しても、0になってしまう。
  • 波の形で学習できるときとできないときがあることが分かった。たとえば、サイン波は学習できるがコサイン波は学習できない。
  • 標準化を適用して、なるべくサイン波に近い形にヒストリカルデータを編集した。

11 Jul 2017, 22:55

Dukascopyのヒストリカルデータの日付をpandasでパースする方法

FXのヒストリカルデータを取得するために、私はいつもDukascopyを利用している。

おかしな日付

ダウンロードしたデータをプロットしてみたら、おかしなことになった。

self.csv_data = pd.read_csv(self.csv_path, index_col=0, parse_dates=True, header=0)

dukascopyの日時のフォーマットは、03.07.2017 00:00:00.000 のようになっている。

なので、2017年7月3日をpandasは間違えて 2017年3月7日としてパースしてしまったようだ。

正しい日付にパース

こういう場合は、自前のパーサを作成して、_pandas.readcsv に date_parser optionの引数としてパーサを渡すことで解決する。

f = '%d.%m.%Y %H:%M:%S.%f'
my_parser = lambda date: pd.datetime.strptime(date, f)
self.csv_data = pd.read_csv(self.csv_path, index_col=0, parse_dates=True, header=0,
                           date_parser=my_parser)