09 Jun 2017, 07:18

OpenAI Gym の CartPole-v0 を試したメモ

OpenAI Gym を試してみたメモです。

CartPole-v0 というゲームを動かしてみました。

OpenAI Gym

OpenAI Gym とは

OpenAI Gym is a toolkit for developing and comparing reinforcement learning algorithms.

OpenAI Gym は、強化学習アルゴリズムを開発し評価するためのツールキット。

  • gym … python テスト環境ライブラリ.
  • OpenAI Gym service … エージェントのパフォーマンスを評価するサービス。

ちょっとわかりにくいが、自分の解釈では、 いろんなゲームをプレイする環境が提供されていて、 自分の AI エージェントをつくってゲームをプレイして遊べるツール。

どんなゲーム(環境)があるの?

三目並べからシューティングゲーム、囲碁まである。詳しくは、以下。

Open AI Gym ライブラリのインストール

OpenAI Gym を pip でいれる。

pip install gym

以下のジャンルのゲームができるようになる。

  • algorithmic
  • toy_text
  • classic_control

CartPole で遊ぼう

公式のチュートリアルで紹介されている CartPole というゲームを触ってみる。

CartPole 問題

CartPole 問題は、強化学習の古典的問題らしい。

棒(pole)が動く台車(cart)の上に立っている。 棒は倒れるので、台車を右か左に動かして倒れないようにする。 より長く棒を直立させることが目的。

以下は、ルールの Google 日本語翻訳。

ポールは、作動していないジョイントによって、摩擦のないトラックに沿って動くカートに取り付けられる。システムは、カートに+1 または-1 の力を加えることによって制御される。振り子が起立して、それが転倒するのを防ぐことが目標です。ポールが直立したままのタイムステップごとに+1 の報酬が与えられます。エピソードは、ポールが垂直から 15 度を超えると終了するか、またはカートが中心から 2.4 ユニット以上移動すると終了します。
  • 1step の間に直立 h していれ報酬を 1 もらえる
  • 右(+1) or 左(-1)の行動を選択できる
  • 棒が 15 度傾くとゲームオーバー
  • 台車が中心から一定距離(2.4unit???) とゲームオーバー

コードを調べる

公式ドキュメントに乗っているコードを見ていく。

import gym
env = gym.make('CartPole-v0')
for i_episode in range(20):
    observation = env.reset()
    for t in range(100):
        env.render()
        print(observation)
        action = env.action_space.sample()
        observation, reward, done, info = env.step(action)
        if done:
            print("Episode finished after {} timesteps".format(t+1))
            break

まずは、gym というライブラリをインポートする。

gym.make(“環境名”) で動かす環境(env)を生成する。ここでは、CartPole-v0 を指定。

import gym
env = gym.make('CartPole-v0')

env の 3 つの主なメソッドは、

  • reset() - 環境(environment)をリセットする。最初の 観測(observation) を返す。
  • render() - 現在の環境の状態をレンダリングする。
  • step(a) - 行動(action)を実行し、以下を返す(new observation, reward, is done, info)
    • new observation - 行動を実行したあとの観測
    • reward - 報酬
    • is done - ゲームが終了したら True, 続いているなら False
    • info - 詳細情報

for 文で 20 エピソード分を実行する。

env.render()で以下のような図を表示する。

env.reset()を実行すると、以下の numpy 配列が帰ってくる。

# [position of cart, velocity of cart, angle of pole, rotation rate of pole]
array([-0.01717682,  0.00789496,  0.03295495, -0.0202679 ])

env.observation_space で、観測状態、env.action_space で、行動がそれぞれ帰ってくる。

Box は、n-次元の Box を、Discrete は固定された範囲の非負の数をそれぞれ表す。

print("observations:", env.observation_space)
print("actions:", env.action_space)
observations: Box(4,)
actions: Discrete(2)

CartPole-v0 では、observation は 4 次元の配列, action は 0 or 1 の数。

以下で、observation_space の上限、下限が分かる。

print(env.observation_space.high)
#> array([ 2.4       ,         inf,  0.20943951,         inf])
print(env.observation_space.low)
#> array([-2.4       ,        -inf, -0.20943951,        -inf])

以下で、action_space の数が分かる。

print(env.action_space.n)
#> 2

env.action_space.sample()で、action をランダムに選択できる。

env.action_space.sample()
#> 0
env.action_space.sample()
#> 1
env.action_space.sample()
#> 1

step()関数に action を渡すことで、action を実行できる。

done が True になるまで繰り返す。reward には、1.0 が入る。

結果を記録、アップロード

以下のように、wrappers.Monitor(env, ‘/tmp/cartpole-experiment-1’)を使うと、 実行結果を記録することができる。

import gym
from gym import wrappers
env = gym.make('CartPole-v0')
env = wrappers.Monitor(env, '/tmp/cartpole-experiment-1')
for i_episode in range(20):
    observation = env.reset()
    for t in range(100):
        env.render()
        print(observation)
        action = env.action_space.sample()
        observation, reward, done, info = env.step(action)
        if done:
            print("Episode finished after {} timesteps".format(t+1))
            break

以下のような mp4 の動画と meta 情報の json がディレクトリに作成される。

$ ll /tmp/cartpole-experiment-1
合計 32K
-rw-rw-r-- 1 tsu-nera tsu-nera  817  6 月  9 15:59 openaigym.episode_batch.0.13181.stats.json
-rw-rw-r-- 1 tsu-nera tsu-nera  412  6 月  9 15:59 openaigym.manifest.0.13181.manifest.json
-rw-rw-r-- 1 tsu-nera tsu-nera 2.0K  6 月  9 15:58 openaigym.video.0.13181.video000000.meta.json
-rw-rw-r-- 1 tsu-nera tsu-nera 4.0K  6 月  9 15:58 openaigym.video.0.13181.video000000.mp4
-rw-rw-r-- 1 tsu-nera tsu-nera 2.0K  6 月  9 15:58 openaigym.video.0.13181.video000001.meta.json
-rw-rw-r-- 1 tsu-nera tsu-nera 3.9K  6 月  9 15:58 openaigym.video.0.13181.video000001.mp4
-rw-rw-r-- 1 tsu-nera tsu-nera 2.0K  6 月  9 15:58 openaigym.video.0.13181.video000008.meta.json
-rw-rw-r-- 1 tsu-nera tsu-nera 3.8K  6 月  9 15:58 openaigym.video.0.13181.video000008.mp4

以下のようなスクリプトを実行すると、OpenAI Gym に結果をアップロードできる。

import gym
gym.upload('/tmp/cartpole-experiment-1',api_key='<api key>')

api_key は、OpenAI Gym にログインすると得られる。

$ python carpole_upload.py
[2017-06-09 16:09:39,697] [CartPole-v0] Uploading 20 episodes of training data
[2017-06-09 16:09:48,712] [CartPole-v0] Uploading videos of 3 training episodes (9058 bytes)
[2017-06-09 16:09:49,232] [CartPole-v0] Creating evaluation object from /tmp/cartpole-experiment-1 with learning curve and training video
[2017-06-09 16:09:49,618] 
****************************************************
You successfully uploaded your evaluation on CartPole-v0 to
OpenAI Gym! You can find it at:

    https://gym.openai.com/evaluations/eval_7fz1aflRO6alkzRRfWhQ

****************************************************

gist にコードをあげて、URL を取得する。

評価ページにいき、gist を貼り付ける。以下のリンクが今回の評価ページ。

追記

長い間プログラムを動作させると、manifest.json ファイルが生成されなかった。 そういう場合は、念のため env.close()を終了時に呼び出すことで、manifest.jssn が生成されるようだ。 参考にしたコードはここ.

01 Jun 2017, 04:41

Oracle Certified Java Programmer, Silver SE 8 認定資格に合格

Java SE8 Silver(Java SE 8 Programmer I 試験[1Z0-808]]) に 3 日間 で合格しました。

受験するまで

最近はディープラーニングの勉強をしているのだけれども、会社から脅された。

  • ディープラーニングが業務ににどう役に立つか説明してください。
  • ディープラーニングでどうやって会社に貢献するんですか?
  • Java の資格をさっさととらないとクビにするよ?

(´・ω・`)

ということで、Java SE8 Silver[1Z0-808]を勉強をはじめた。

Oracle はキャンペーンをやっていて、2017/5/31 までに受験すると、 一度落ちても再受験が無料のキャンペーンを実施中であることに、 528 の夕方に気づいた。

受験料がバカに高い(28728 円!)ので、落ちたらお金がもったいないし、 こっちは人生かかっているので、3 日間で死ぬ気で勉強することになった。

結果

82%の正解率で合格。(合格ライン 65%)

勉強内容

前提

Java の業務経験は、3 年前に 1 年程度。それから 2 年のブランク期間あり。

オラクル社主催の試験のランクは、ブロンズ、シルバー、ゴールドとあるけれども、 ブロンズは受けていない。

元々 Java の知識はあったので、問題をひたすら解くという対策方法をとった。

学習時間

528 の夕方 から 531 の夕方までなので、4 日間にわたるのだけれども、実質 72 時間。 そのうち、37 時間を Java に費やした。

  • (0 日目:528: 6 時間)
  • 1 日目 529: 13 時間 (黒本模試 66%, 68%)
  • 2 日目 530: 8 時間 (白本模試 75%)
  • 3 日目 531: 10 時間 (本番 82%)

参考書

売り出されている参考書は、黒本と白本と紫本の3つがある。

まず、一番評判がいい黒本を 2 周した。(1 日目)

まだ時間の余裕と心の不安があったので、白本を購入して一週した(2 日目)

最後の 3 日目は、黒本と白本の間違えたところを復習。

黒本

  • 解説が文章でかかれていて丁寧。
  • 問題の解説の前に概念の説明があるので、問題演習の延長で基礎の復習もできる。
  • 紙質が白本に比べていい。

白本

  • 解説に図を多様している。図解で直感的理解ができる。
  • 問題のすぐ下に解説があるので、解いてすぐに答えを確認できるようにつくられている。
  • 黒本よりもやさしい。
  • 出なさそうな問題もたまにある気がする。
  • アプリ版があるので、スマートフォンで満員電車のなかでも勉強できる!

紫本

  • 問題の前に、説明にベージが多く割かれている。
  • 体系的にまとまっているので基礎から学びたい人におすすめ。

受験する人へのアドバイス

どういう問題が出たかは、問題の情報漏洩になるのでいえないのだが、

黒本をやれ!!(。・ω・)ノ

そう、ひたすら黒本をやれば受かる。

自分のように白本に手を出す時間があるならば、黒本の問題を繰り返し解こう。

なぜなら・・・おっとこれは書けない。

26 May 2017, 16:28

Emacs で conda.el をつかって環境が切り替えられない時の対処方法

Emacs で、anaconda 環境を切り替える便利な eLisp に conda.el というものがある。

しかし、これがどうもうまく動かなかったので調査してみた。

環境

  • fish shell 2.5.0
  • Emacs 25.1.2

事象

conda-env-activate を使うと、切り替わったよというメッセージはでるが、 実際は Anaconda の root を使っている。指定した環境を使ってくれない。

原因

PATH に何が設定されてるか調べてみると。 (getenv "PATH")

"/home/tsu-nera/anaconda3/envs/kaggles/bin:/home/tsu-nera/.rbenv/shims:/home/tsu-nera/anaconda3/bin:/home/tsu-nera/.cask/bin:/home/tsu-nera/bin:/home/tsu-nera/go/bin:/home/tsu-nera/.rbenv/bin:/home/tsu-nera/script/scala:/home/tsu-nera/script/ruby:/home/tsu-nera/script/sh:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8-oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin"

つまり、二つのパスが登録されている。

  1. /home/tsu-nera/anaconda3/envs/kaggle/bin
  2. /home/tsu-nera/anaconda3/bin

使いたいのは、1 のほうで2はいらない。

なぜかわからないが、Emacs を起動すると、PATH を自動で読み込んでくれるようなのだ。

こんな機能しらないぞ!exec-path-from-shell をつかって実現する機能ではなかったか? デフォルトで PATH を引き継ぐように仕様変更されたのか??

解決方法

fish shell の環境設定ファイル(自分の場合は env.fish に分けている)、 から、anaconda のパスを削除すると、Emacs で conda-activate をつかった切り替えができる。

しかし、これでは、ふだん conda コマンドが使えない。

そこで、fish shell にこんな関数を定義した。まず Emacs を立ち上げた上で、conda を有効にする。

# anaconda
function conda-activate
    set fish_user_paths $HOME/anaconda3/bin $fish_user_paths
end

一時しのぎだけれども、これで Emacs から conda で環境を切り替えることができるようになった。

21 May 2017, 03:01

ディープラーニング(char-rnn)でバッハの音楽を生成してみた

前回、テキストで音楽を表現する方法 を調べた。今回は実際に char-rnn を利用して音楽を生成してみた。

まずは結果から

バッハのインベンションの No.1 - No.15 の全 15 曲を学習データにして、 char-rnn を利用して学習させた。結果がこちら。

無調音楽に近いような感じ。

実装

以下のサイトの記事を真似しました。

参考にした記事では、karpathy さんの char-rnn をそのままつかっていたけれども、 理解を深めるために Tensorflow で char-rnn を実装した。 といっても、Udacity で学んだことを応用しただけ。

その他、

  • テキスト形式としては、**kern 記譜法を採用。
  • 音楽を扱うライブラリは music21 を利用。

今回の Jupyter Notebook はコチラ。いつものようにコードを抜粋しながら説明。

KernScore からデータ取得

KernScores には、大量のクラシック音楽の **kern 記譜法でかかれた楽譜が置いてある。 まずは、バッハのインベンションの楽譜を取得した。

from urllib.request import urlopen
for i in range(1,15+1):
    filename = "inven{0:02d}.krn".format(i)
    file = urlopen("http://kern.humdrum.org/cgi-bin/ksdata?l=osu/classical/bach/inventions&file=%s&f=kern"%filename)
    with open("kernscore/bach/"+filename,'wb') as output:
        output.write(file.read())

データを char-rnn に食わせるために整形

データを見てみると余分なものがあることに気づく。これはいらない。

  • metadata
  • コメント
  • 小節記号
!!!COM: Bach, Johann Sebastian
!!!OPR: Inventio
!!!OTL: Inventio 1
!!!XEN: Two-part Inventions [for keyboard]
!!!ONM: No. 1
!!!ONB: In C major.
!!!SCT: BWV 772
!!!YEC: Copyright 1994, David Huron
!!!YEM: Rights to all derivative electronic formats reserved.
!! Performance duration: 1:29; performance tempo: 59.3 quarter-notes per minute.
!! (Andras Schiff, piano, "Two-Part Inventions BWV 772a-786; Three-part
!! Inventions BWV 787-801" Decca 411 974-2)
**kern  **kern
*staff2 *staff1
*clefF4 *clefG2
*k[]    *k[]
*C: *C:
*M4/4   *M4/4
*MM59.3 *MM59.3
=1- =1-
2r  16r
.   16c
.   16d
.   16e
.   16f
.   16d
.   16e
.   16c
16r 8g
16C .
16D 8cc
16E .
16F 8bM
16D .
16E 8cc
16C .

...

.   16b
=22 =22
1CC; 1C;    1e; 1g; 1cc;
==|!    ==|!
*-  *-
!!!CDT: 1685/3//-1750/7/28
!!!OCY: Deutschland
!!!AGN: polyphony
!!!AST: baroque
!!!AMT: simple quadruple
!!!SCA: Bach-Werke-Verzeichnis
!!!YOR: Bach Gesellschaft
!!!AIN: cemb; clavi
!!!EEV: 1.0
!!!RDT: 1986 November
!!!YER: 1995 May 22
!!!YEN: Canada
!!!EFL: 1/15
!!!EED: David Huron

これらを除去して、インベンション 15 曲を一つのファイルに出力する。

import glob
REP="@\n"
def trim_metadata(output_path, glob_path):
    comp_txt = open(output_path,"w")
    ll = glob.glob(glob_path)
    for song in ll:
        lines = open(song,"r").readlines()
        out = []
        found_first = False
        for l in lines:
            if l.startswith("="):
                ## new measure, replace the measure with the @ sign, not part of humdrum
                out.append(REP)
                found_first = True
                continue
            if not found_first:
                ## keep going until we find the end of the header and metadata
                continue
            if l.startswith("!"):
                ## ignore comments
                continue
            out.append(l)
        comp_txt.writelines(out)
    comp_txt.close()



output_path = "composer/bach.txt"
glob_path = "kernscore/bach/*.krn"
trim_metadata(output_path, glob_path)

char-rnn で音楽生成

ここからのコードは、Udacity で与えられたコードをほぼそのまま使った。 ハイパーパラメータは、以下のとおりに設定した。これで、学習時間が 30 分くらい。 曲の完成度からみると、これではすくないような気もする。

batch_size = 10
num_steps = 10 
lstm_size = 512
num_layers = 2
learning_rate = 0.001
keep_prob = 0.5

出力データのフォーマットを整える

出力データが 結構ぐちゃぐちゃに吐き出される。

  • 右手左手の 2 行だけでよいのに、3 行目がある。
  • 右手パートしかない
  • 左手パートしかない
  • 終端マークが途中で現れる。

これらを解消するために、**kern 記法に沿ったフォーマットで吐き出されるようにした。

ついでに、メタデータと小節番号の bar も追加。

r = []

r.append("**kern\t**kern\n")
r.append("*staff2\t*staff1\n")
r.append("*clefF4\t*clefG2\n")
r.append("*k[]\t*k[]\n")
r.append("*C:\t*C:\n")
r.append("*M4/4\t*M4/4\n")
r.append("*MM80\t*MM80\n")

bar = 1
for line in samp.splitlines():
    sp = line.split('\t')
    if sp[0] == '@':
        r.append("={bar}\t={bar}\n".format(bar=bar))
        bar += 1
    else:
        ln = len(sp)
        if ln == 1 and sp[0] != "":
            r.append(sp[0])
            r.append('\t')
            r.append('.')
            r.append('\n')
        elif ln == 1 and sp[0] == "":
            r.append(".")
            r.append('\t')
            r.append('.')
            r.append('\n')
        elif sp[0] == "*-" or sp[1] == "*-":
            continue
        else:
            r.append(sp[0])
            r.append('\t')
            r.append(sp[1])
            r.append('\n')

r.append("==|!\t==|!\n")
r.append("*-\t*-\n")

open("results/bach2ai.krn","w").writelines(r)

これで、楽譜が完成!

midi 吐き出し

あとは、これを midi に吐き出して再生するだけだ。

from music21 import *
m1 = converter.parse("results/bach2ai.krn")
m1.write('midi', fp='midi/bach2ai.mid')

Jupyter Notebook 上でも再生できる。

m1.show("midi")

おわりに

今回は、あまり満足のいく作品ができなかった。改善点としては、

  • char ベース見ていくのではなくて、音符単位(8a, 7b など)で音を見る
  • 左手、右手を分けて音を見ていく
  • 学習をもっと実施する、ハイパーパラメータの調整

などが考えられる。とはいえ、音楽をディープラーニングで生成できた。 ディープラーニングを学ぶ動機のひとつが音楽生成だったので、達成できて嬉しい。

音楽に関係する取り組みは、char-rnn ベース以外にもあるみたいだ。 今後は、これらを理解していくことにしよう。

19 May 2017, 07:49

テキストで音楽を表現する方法を調べた

テキストで音楽を表現する方法を調べた。

char-rnn で音楽生成したい

以前の記事で、char-rnn というものを試して、 坊ちゃんのテキストからテキスト生成をすることを試した。

これを音楽に応用してみたい。今回の記事はその準備として情報収集をした。

こういうテキストから LSTM を使って音楽を生成する試みは、いろんな人がやっている。 発端となっているのは、Andrej Karpathy 氏のブログ記事。

Andrej Karpathy さんは、Touch で char-rnn を実装している。

私は最近、TensorFlow や Keras による、char-rnn の実装を勉強した。

Keras が好きなので、勉強のために Keras で実装したいと考えている。

記譜法を調べた

ABC 記譜法

ABC 記法はわりと有名な記法。WikiPedia にも情報がある。

以下の特徴がある。

  • アスキー文字で音楽を表現
  • 関連ソフトウェアが豊富
  • 民族音楽に強い

ABC 記法から、五線譜に変換して再生する OSS.abcjs. これは凄い。

データベース・音源集

LSTM に応用した事例

**kern notation

マイナーな記法。

データベースにクラシック音楽の曲がたくさんあるのが魅力。

ツールとしては、music21 をつかう。これは、DeepJazz でも使われている。

music21 はデータベースが充実しているけれども、データ形式が XML 形式だから char-rnn には使えないかな。

LSTM に応用した事例

自力で midi から text 変換

そういう手法もある。欲しいデータがみつからなかったら、この手も使う。

18 May 2017, 23:06

ハイパーパラメータは可視化して決めよう!Keras で TensorBorad を使う

はじめに

とあるコンペに Keras で参加しているのだけれども、 ハイパーパラメータ、たとえば以下のようなパラメータ

  • 隠れ層のニューロンの数
  • ネットワークを何層にするか
  • 学習率

をどう決めていたかというと、直感である。

これでは、いけないなと最近気づく。もっと早く気付けよ。

モデルに最適なハイパーパラメータの決め方を調べてみた。

“ディープラーニング ハイパーパラメータ”を検索

みんな困っているようで、事例はすぐにみつかった。 たとえば、この記事なんて、まさに自分のこと!!

これはテストデータの精度に対して、試行錯誤を繰り返しながら決めていくしかありません。

StackOverFlow でも、

asically it is just trial and error. Those are called hyperparameters and should be tuned on a validation set (split from your original data into train/validation/test).

Tuning just means trying different combinations of parameters and keep the one with the lowest loss value or better accuracy on the validation set, depending on the problem.

ようは、総当たりしろ!!!ということか??

3 つの手法:

また、別のページでは、もっと効率のよい方法が紹介されている。大きく分けて、3 つあるようだ。

  • グリッドサーチ:

昔からある手法で、格子状の空間で最適なパラメータを探索する方法です。 格子の範囲を総当りするため、膨大な計算時間がかかるという課題があります。

  • ランダムサーチ :

無作為にパラメータを抽出して探索します。 グリッドサーチよりも計算時間が短くて済むというメリットがあります。

  • ベイズ最適化 (Bayesian Optimization) :

無作為にパラメータを抽出して探索します。 グリッドサーチよりも計算時間が短くて済むというメリットがあります。 ディープラーニングを含む機械学習の手法で、比較的良いハイパーパラメータを探索できることが知られています。

また、bengio 先生のおすすめレシピというのがある。

ハイパーパラメータはグリッドサーチするのではなく,ランダムサンプリングしたほうが性能が出る場合が多いよ

ベイズ最適化

ちょっとこのページは難しいが読み解くと、なにか得られそう。

ツール

scikit-learn には、GridSearchCV というものがあるらしい。いつか試そう。

hyperopt というツールもある。いつか試そう。

hyperopt の keras ラッパーもみつけた。いつか試そう。

調査結果

とりあえず、バカでも出来る全探索(グリッドサーチ)をする

目的

ここからが本題。

ニューラルネットワークのハイパーパラメータを調節したい。今回は簡単に以下の2つを調整。

  • 隠れ層の数
  • ニューロンの数

TensorBoard を Keras で使う

TensorBoard は、TensorFlow のログビューア。いい感じに可視化してくれる。

Keras で TensorBoard を使うには、Keras のコールバック機能を使う。 以下のように keras.collbacks.TensorBoard を利用する。

import keras
tbcb = keras.callbacks.TensorBoard(log_dir=log_filepath)

定義した変数を fit に渡す。

model.fit(trainX, trainY, epochs=30, batch_size=batch_size, validation_data=(validX, validY), callbacks=[tbcb])

これだけだ。簡単簡単。あとは log_filepath を指定して、tensorboard をコマンドラインから起動。port 6006 でアクセスできる。

$ tensorboard --logdir=[log_filepath]

参考: Keras から Tensorboard を使用する方法 - Qiita

複数のパラメータを追う

複数のパラメータをログするには、以下のように、log_dir に渡す文字列に変数を組み込む。

実例で示す。

import keras
from keras.models import Sequential
from keras.layers import Flatten, Dense, Dropout, BatchNormalization
from keras.optimizers import Nadam

batch_size=64

def get_model(num_layers, layer_size):
    model = Sequential()
    model.add(BatchNormalization(axis=1, input_shape=(256,3)))
    model.add(Flatten())
    for _ in range(num_layers):
        model.add(Dense(layer_size, activation='relu'))
        model.add(BatchNormalization(axis=1))
        model.add(Dropout(0.2))
    model.add(Dense(24, activation='softmax'))
    model.compile(Nadam(), loss='categorical_crossentropy', metrics=['accuracy'])
    return model

for num_layers in [2,3,4,5]:
    for layer_size in [64,128,265,512,1024]:
        log_string = 'logs/1/nl={},ls={}'.format(num_layers, layer_size)
        tbcb = keras.callbacks.TensorBoard(log_dir=log_string)
        model = get_model(num_layers, layer_size)
        model.fit(trainX, trainY, epochs=30, batch_size=batch_size, validation_data=(validX, validY), callbacks=[tbcb])

こうすると、logs/1/配下に nl=?,ls=? というディレクトリがそれぞれできて、そのなかにログがたまる。

$ tree 1
1
├── nl=2,ls=1024
│   └── events.out.tfevents.1495116649.letsnote-ubuntu
├── nl=2,ls=128
│   └── events.out.tfevents.1495115992.letsnote-ubuntu
├── nl=2,ls=256
│   └── events.out.tfevents.1495116161.letsnote-ubuntu
├── nl=2,ls=512
│   └── events.out.tfevents.1495116351.letsnote-ubuntu
├── nl=2,ls=64
│   └── events.out.tfevents.1495115856.letsnote-ubuntu
├── nl=3,ls=1024
│   └── events.out.tfevents.1495118093.letsnote-ubuntu
├── nl=3,ls=128
│   └── events.out.tfevents.1495117340.letsnote-ubuntu
├── nl=3,ls=256
│   └── events.out.tfevents.1495117513.letsnote-ubuntu
├── nl=3,ls=512
│   └── events.out.tfevents.1495117727.letsnote-ubuntu
├── nl=3,ls=64
│   └── events.out.tfevents.1495117193.letsnote-ubuntu
├── nl=4,ls=1024
│   └── events.out.tfevents.1495119950.letsnote-ubuntu
├── nl=4,ls=128
│   └── events.out.tfevents.1495119010.letsnote-ubuntu
├── nl=4,ls=256
│   └── events.out.tfevents.1495119233.letsnote-ubuntu
├── nl=4,ls=512
│   └── events.out.tfevents.1495119509.letsnote-ubuntu
├── nl=4,ls=64
│   └── events.out.tfevents.1495118840.letsnote-ubuntu
├── nl=5,ls=1024
│   └── events.out.tfevents.1495122077.letsnote-ubuntu
├── nl=5,ls=128
│   └── events.out.tfevents.1495121077.letsnote-ubuntu
├── nl=5,ls=256
│   └── events.out.tfevents.1495121291.letsnote-ubuntu
├── nl=5,ls=512
│   └── events.out.tfevents.1495121586.letsnote-ubuntu
└── nl=5,ls=64
    └── events.out.tfevents.1495120894.letsnote-ubuntu

これを tensorboard から見ると、accuracy, loss, valid loss, valid accuracy が見える。 以下の図は、valid accuracy.

闇雲にパラメータを調べるよりもよっぽど効率がよい。

17 May 2017, 11:00

fast.ai の Practical Deep Learning for Coders, Part1 を受けた

fast.ai が提供する MOOC, “Practical Deep Learning for Coders Part1” を受けた。

特徴

プログラマのための実践ディープラーニング入門

この講座は、プログラマのためにある。素晴らしい理念の序文を引用したい。

The purpose of this course is to make deep learning accessible to those individuals who may or may not possess a strong background in machine learning or mathematics.

We strongly believe that deep learning will be transformative in any application; as such, this course is designed for individuals who possess a background in computer programming and would like to apply these techniques to their domain of expertise.

Deep Learning は、機械学習や数学に深い造詣がないといけないというまやかしを、 吹き飛ばそうという野心を感じる。

そして、機械学習も数学もできない自分にはピッタリの講座だ!

Practical~実践の意味、Kaggler になれ!

講師を努めるのは、Kaggle のかつての President、Jeremy Howard.

TED の動画もある。

そして毎週の課題は、Kaggle に挑戦すること。 そのうち、トップ 50% に入ることが基準として課される。

トップ 50% に入るのは、正直とてもたいへんだ。 しかし、この手法を使えば入れるという種明かしを授業のなかでしてくれる。

ここでタイトルの実践の意味がわかる。つまり、kaggle のデータを使って、 実際にデータ解析をすることで、実力をつけようという意図があるのだ。

実際、以下のコンペに挑戦する。

全て無料!ただし GPU つかうから AWS でインスタンス を借りてね

この講座は無料である。state-of-the-art の内容が無料で受けられる。

しかし、GPU をつかうから AWS を借りてねと言われる。1 時間 90 セントだから安いよと言われる。

p2 タイプというのが GPU 対応らしいのでそのインスタンスを借りる。

AWS の EC2 の自動セットアップスクリプトが提供されるのだけれども、 このスクリプトがアメリカとヨーロッパしか対応してなくて、アジアがない。

しかたがないので、アメリカの EC2 のインスタンスを使う。 操作すると、距離のせいか、レスポンスが遅いが、なんとか頑張る。

floydhub が使えるという情報を見つけた。

2 時間の動画と丁寧なレクチャーノート

毎週 2 時間の動画がある。他の MOOC は動画が短く区切られているけれども、 この MOOC は 2 時間ぶっ通しである。

なので、疲れる。毎回 TimeLine の wiki ページがあるので、 自分は途中休憩をはさみながら細切れに見た。

英語(ただし英語の字幕はある)なので、聞いていてもよくわからない。

しかし、ありがたいことに、すごく丁寧なレクチャーノートの wiki と Jupyter Notebook が提供されている。

疑問点があるときは、Forum で同じことに困っている人がいるので、Forum を検索する。

なので、英語のリスニングに不安がある人でも大丈夫。

Keras 大活躍

この講座では、Python2 と keras 1.x(Backend は Theano)を使う。なぜなら、簡単にかけるからだ。

(一応、Python3, Keras2 に対応した非公式リポジトリもある roebius/deeplearning1_keras2)

今まで TensorFlow しか知らなかったけれども、 Keras をつかうと、Deep Learning のコードがすごく簡単にかける。

Keras がこの講座で好きになった。

全 7 週間で最低 8 時間は自習しましょう

講義は全 7 回ある。2時間の講義ビデオに加えて 8 時間の自習が必要。

勉強時間は平均的に 8-15 時間が一般的らしい。 なかには、15-30 時間勉強する人もいるとか。

ハードだ。でも、他の MOOC と違い、自分のペースで進めることが出来るので、 時間に追い詰められることはなく、自分が納得できるまで努力することができる。

この MOOC は自習が重んじられているように感じた。

自分はこんな感じで、各回を進めた。

  • 動画みる(2h)
  • レクチャーノートを読む(2-3h)
  • Jupyter Notebook を読む(2h)
  • Assignment をやる(???)

講義メモ

以下、各回が終わるたびにメモを書いていきました。

lesson1: Image Recognition

lesson1 の動画はうれしいことに日本語字幕がついている。

前半で、AWS の環境構築をする。全てセットアップスクリプトが面倒見てくれるので、 問題なくセットアップできた。

それから、VGG16 という imagenet のモデルを ファインチューニングして、 Dogs vs. Cats Redux| Kaggle 用にモデルをつくる。

fine-tuning については、この記事が詳しい。

課題は、上記 kaggle のコンペティション(競技会)に参加してみること。 自分が参加したときは、もう既にこのコンペが終了していた。 提出はできたので、スコアを眺めてみたけれども、どうもあまり成績はよくなかった。

lesson1 では、理論的な話はでてこないので、説明された通りに進めていけば OK.

lesson2: CNNs

前半は、lesson1 の課題の説明。Dogs or Cats コンペで 上位に入るための種明かしがされる。

後半は、CNN について。CNN の説明はガイダンスでしたよね?といわれ、 CNN の理論は飛ばされて線形問題を SGD で解くことをやる。 そのあと、Keras をつかって、線形問題を解く。

その後、Keras をつかって、スクラッチから Dogs vs Cats をかいて どうやれば精度が向上するかを実験する。

課題は、コンペで 50%以内に入る種明かしを元に、再度 kaggle に挑戦してみること。 また、vgg16 の fine-tuning による方法はいろんな kaggle のコンペに適用可能なので、犬猫以外のコンペに参加してみること。

また、課題図書で 以下を読むこと。こんなに読めないよ!!と思ったので、読まなかったけど。

てか、普通にこれだけ勉強するなんて、アメリカの学生勉強しすぎでしょ、偉いよ。

lesson3: Overfitting

前半は、CNN の復習。サブ講師のレイチェルさんがちょくちょく質問をして、講義を遮る。

後半は、Overfitting と Underfitting について。以下の手法が紹介される。

  • Data Augmentation
  • Dropout
  • Bach Normalization

そして、これらのテクニックをつかって MMIST の認識を試み、 精度 97%まで達することを示す。自分も Kaggle の Digit Recognizer で好成績を出すことが出来た。

課題は、今までの復習(CNN はここまで)を各自でやるようにとのこと。 それから、State Farm のコンペで上位 50% に入ることが課せられるのだが、 これができなかった。。

lesson4: Embedding

前半は、CNN を Excel で表現していろいろ動かしてみるデモ。

それから、いくつかの最適化手法が紹介される。

  • Momentam
  • Adagrad
  • RMSProp
  • Adam
  • Eve

これを Excel で実装したものが与えられるのだが、Excel もっていない。 LibreOffice では、VBA マクロを動作させることができない。 しかたがないので、Lecture Note と Video で雰囲気だけ感じた。

それから、State Farm のコンペの攻略法について 30 分ほど話がある。 Psuedo-labeling という手法。今週も頑張ってねとのこと。

Psuedo-labeling で検索かけたら面白いスライド見つけた。10 位だって、すごい。

State Farm の課題はサーバーのメモリエラーが発生したので Pesude-labeling の手法ができない! 上位 50%は諦めた。

State Farm が終わったら、Fisheries Monitoring のコンペが紹介される。 Vgg16 の転移学習を試したら、すぐにいい成績が出た。転移学習最強説がでできた。

最後に協調フィルタリングの紹介。Excel のソルバーを使ってデモをしていたけれども、 自分は Excel を持っていないので、試すことができない。 講義資料の ipynb で keras による、協調フィルタリングの説明もある。 ここで、embedding という概念を説明して、次の lesson の word embedding につながる。

lesson4 は Excel 大活躍だな。

lesson5: NLP

まずは、Vgg16 に BatchNormalization を適用したモデルの紹介。

次に、協調フィルタリングについて先週のノートを元に復習したあと 今回のテーマである NLP に。

センチメント分析を Embeddings をつかって実施する。 データは、IMDB という映画のレビューのデータセットを利用する。

単純なモデルから、複雑なモデルへと説明していき、精度が向上することを確かめる。

面白いと思ったのは、NLP の世界でも画像のような訓練済みのモデルを使った 転移学習ができるということだ。Glove という訓練済みのモデルを利用したりした。 日本語の訓練済みモデルが欲しいところだ。

最後に、次のレッスンの導入として RNN の簡単な説明があって終了。

lesson6: RNNs

RNN のモデルが説明される。簡単なモデルから、だんだん複雑になっていく。

文章の文字を読み込んで次の文字を推測するということをやる。

  • 3 層のモデル
  • 8 層のモデル
  • N 層のモデル
  • Sequential RNN
  • Stateful RNN

そして一通り説明が終わったところで、なんと、Theano がでてくる。

今までは実践的なことばかり教えてきて、Keras で簡単に DL を実装してきたけど、 Keras がどう動いているのかとか、低レイヤとかのことも知っておいたほうがいいよね、 というわけで、Theano による RNN の実装の説明がはじまる。

そして、次回予告として、次回は numpy で RNN を実装するよ!とのこと。感動の最終回??

lesson7: CNN Architectures

ResNet という新たなモデルが出てくる。 これは 2015 年に 現れた手法のようで、VGG モデルよりも複雑。 Input を 層を重ねたあとに Merge するというよくわからないことをやっていた。 ソースコードも提供されている。(courses/resnet50.py)

そのあとに、kaggle Fisheries Monitoring コンペの攻略法の解説。 lesson7 は、3/4 の時間を Fisheries Monitoring の解説に費やすというサービス。 Kaggle 必勝法が凝縮している講義だ。 自分は、一回動画を見ただけでは理解できなかった。

この講座はこれで最後でこれが終わったら、暇になるだろうから、 この Jupyter Notebook を何度も読んで、Kaggle で遊んでねとのこと。

そして、残りの 30 分で、numpy を使った RNN の実装と GRU の紹介。 LSTM よりも、GRU のほうが便利なので、GRU を紹介するとのこと。

難しいのが最後にきた。。keras は一行でかけるが本質を理解することが大事とのことで、 ここでも Theano による実装が紹介された。BackPropagation、復習しよう。

おわりに

この講座でおしいところは、紹介されている kaggle のコンペがすでに終わっているところだ。

今 Active な Kaggle コンペに参加して腕試ししようかと思って、入門の Titanic や Digit Recognizer にも挑んだりした。

DeepAnalytics という日本のデータ解析のコンテストサイト(Kaggle の日本版)を知った。 私は、この MOOC で学んだ技で腕試しをしようと思ってコンテストに挑戦した。そういう実力もつくのがこの MOOC だ。 自分がそういう力を数週間のうちに獲得できるとは思わなかった、順位は低いけど。

coursera で、Octave 使って Machine Learning 学んで結局何にも応用できずに終わるのならば、 この MOOC で実践的なことを学んで、Kaggle なり DeepAnalytics に挑戦したほうがいい。

Machine Learning よりも時代は Deep Learning だ。 DeepAnalytics では、参加者がどの手法や言語をつかったかが分かるのだが、 圧倒的に Python と DeepLearning が使われている。

この MOOC は実践的でかつわかりやすいところが素晴らしい。もっと知られるべきだ。 Udacity で Deep Learning Nanodegree Foundation を受講してるが、この MOOC ほうがいい。

この MOOC は Part2 もある。Part2 はもうすぐ公開予定。楽しみ!

13 May 2017, 09:11

gensim で謎かけしたら微妙な結果になった

はじめに

word2vec を知ったので、これを利用して謎かけできないかと考えました。

結論からいうと、面白いものはできませんでした m(._.)m

今回の Jupyter Notebook は以下です。

謎かけとは

謎かけとは、

「x とかけまして、y と解く。その心は・・・ z でございます。」

というもので、x と y の共通点を z という言葉遊び。

落語家が大喜利でお客さんから お題 x をもらって、それに対して洒落た答えを返す。

例えば、「眼鏡とかけまして、椅子と解く、その心はどちらもかけるものでございます」など。 あまり面白くないね。

自分は学生のとき落語研究会に入っていたので、学園祭のときに謎かけをよくやって恥をかいていた。

gensim を使う

gensim という python で NLP をするときによく使われるライブラリがあるが、 そこに word2vec が実装されてライブラリとして提供されている。

word2vec を使うと、ある単語に関係する単語を導くことができる。(most_similar)

これをつかって、謎かけめいたことができないか考えたのだった。

gemsin のインストール

Anaconda 環境で以下のコマンドで。cython をインストールすると計算が早くなるらしい。

conda install gensim
conda install cython

model の作成

text8 という 英語の Wikipedia のデータセットを使う。なぜかというと、用意が簡単だから。

$ wget http://mattmahoney.net/dc/text8.zip -P /tmp
$ unzip text8.zip

解凍した text8 ファイルには英単語が羅列されている。これを学習のインプットにする。

from gensim.models import word2vec
data = word2vec.Text8Corpus('/tmp/text8')
model = word2vec.Word2Vec(data, size=200)
model.save("sample.model")

これで sample.model というモデルができる。size=200 というのは 単語を表現するベクトルの長さ。

embeddings の 加算

単語を表すベクトル同士の足し算をしてみる。

model.most_similar(positive=['dog','cat'])

[('goat', 0.7966023683547974),
 ('bee', 0.7859479784965515),
 ('pig', 0.7830795645713806),
 ('bird', 0.7660524845123291),
 ('hound', 0.7580216526985168),
 ('panda', 0.7541525363922119),
 ('hamster', 0.7503507137298584),
 ('ass', 0.7488968372344971),
 ('haired', 0.7469390630722046),
 ('rat', 0.7466884851455688)]

加算した結果に類似する単語が帰ってくる。動物が特徴なことが分かる。

謎かけをしてみる

加算だとあまりよい結果がでなかったので、ある単語に近い単語を求めて、二つの単語に共通する単語を求めてみる。

wx = 'japanese'
x = model.wv[wx]
wy = 'smart'
y = model.wv[wy]

sx = set()
for word, emb in model.most_similar([x], [], 500):
    sx.add(word)
sy = set()
for word, emb in model.most_similar([y], [], 500):
    sy.add(word)

sz = (sx & sy)

sz で集合 x と 集合 y の両方に含まれる単語 z が求められる。これを表示してみる。

for wz in sz:
    print(wx + "とかけまして" + wy + "と解く。その心は・・・" + wz + "でございます")
japanese とかけまして smart と解く。その心は・・・ capcom でございます
japanese とかけまして smart と解く。その心は・・・ starcraft でございます
japanese とかけまして smart と解く。その心は・・・ doraemon でございます

日本人とかけて秀才と解く、そのこころは、ドラえもんです。。。微妙だ。

いろいろ試してみたけれども、うまくいかなかった。z が名詞だとつまらないな、動詞が来てほしいが方法がわからない。

時間があれば、日本語版 Wikipedia を情報源に使ってみたいけれども、作成に時間がかかりそう。

13 May 2017, 04:42

Word2Vec(skip-gram)で自分の twitter アカウントのツィート分析した

はじめに

Udacity DLND、今週は week8。word2vec がテーマ。

週をおうごとによくわからなくなっていくのは、自分だけだろうか。 だんだん、コピペと写経の講座になってしまっている。

リンクが張られてこれ読んでおいてねという感じ。自学自習が重視される。

というわけで、理解を深めるために、試行錯誤してみた。

week8 は、word2vec(skip-gram model) を tensorflow で実装するという内容。 word2vec は、2 層のニューラルネットワークに過ぎないので理解はたやすいのだけれども、 その前処理(SubSumpling)や 高速化のテクニック(Negative Sampling)が意味わからなかった。

この絵で説明する word2vec の解説ページがとてもわかりやすかった。感謝!

演習では、text8 という Wikipedia のデータセットを用いるのだけれども、相変わらず英語で、 日本人の自分にはピンとこない。というわけで、日本語のデータセットを自分で用意して試すことにした。

今回試したフル実装の Jupyter Notebook は以下です。

ツィートをデータセットに用いる

自分の twitter アカウントのツィートをデータセットにもちいることにした。

といっても、元ネタがあって、元ネタはこの記事。

この記事に 自分のツイートを取得する方法が詳しく書いてある。 twitter が csv データを提供してくれるのだ。 ダウンロードすると、tweets.csv というファイルが手に入る。

pandas で読み込んで前処理を加える。 studyplus とか fitbit のログを垂れ流していたので、それらは削除。

raw_data = pd.read_csv('tweets.csv')
text = raw_data['text']

# studyplus の垂れ流しツイートは削除
text = text[text.str.contains("#studyplus") == False]
# fitbit のライフログは削除
text = text[text.str.contains("おはようございます。今日は") == False]

オープンソースの形態素解析エンジンである MeCab をインストールして、 ツイートを単語ごとに分解して保存する。

ここでもさらに文章からゴミを落としていく。以下を参考にした。re.sub を使う。

import Mecab
import re
f_out = open("tweets_wakati.txt", "w" )
for line in text.iteritems():
    line = re.sub('https?://[\w/:%#\$&\?\(\)~\.=\+\-…]+','', line[1])
    line = re.sub('RT', "", line)
    line = re.sub(r'[!-~]', "", line)#半角記号,数字,英字
    line = re.sub(r'[︰-@]', "", line)#全角記号
    line = re.sub('\n', " ", line)#改行文字
    f_out.write(m.parse(line))
f_out.close()

これで tweet データセットがてにはいった。

Word2Vec を Tensorflow で実装

Word2Vec を tensorflow で実装!といっても課題をコピペしただけなので、省略!!

元の課題のコードを見てください。

可視化

こうなりました。自分を構成している概念が可視化されて面白い。

たとえば、落語という言葉に注目してみると、 周辺には寄席、談志、独演会など、落語関係の言葉がちゃんとあつまっている。

09 May 2017, 15:53

pybitflyer をつかって Python で ビットコインレートを取得してみた

以前、FX システムトレードをしていたので、その経験を生かし(5 万損したけどね)、 Bitcoin でシステムトレードが出来ないか調べてみた。

Bitcoin API 調査

“bitcoin api” で検索をかけた。また、言語は Python で書きたいので、 Python で使えるかも注目して調べた。

ざっと調べた限りだと、 日本では以下の会社が API を提供しているようだ。

なお、調査には、以下のサイトの情報が役立った。 システムトレードできる会社の名前が列挙されて、比較されている。

python library 調査

BitFlyer に決めた

BitFlyer の API を利用することにした。

理由は、検索で上位に引っかかったから。とりあえずお試しなので、これでいいだろう。

そんな決定で大丈夫か?大丈夫だ、問題ない(ぬわー)

インストール

Anaconda 環境を構築して、そこにインストールした。

conda create -n bitcoin
source activate bitcoin
pip install pybitflyer

BitCoin レートを取得

使い方は簡単。4 行だ。

import pybitflyer

api = pybitflyer.API()
while True:
    print(api.ticker(product_code = "BTC_JPY"))
{'product_code': 'BTC_JPY', 'timestamp': '2017-05-09T14:55:00.413', 'tick_id': 388314, 'best_bid': 208700.0, 'best_ask': 208820.0, 'best_bid_size': 6.95343174, 'best_ask_size': 0.001, 'total_bid_depth': 5013.20612844, 'total_ask_depth': 1350.24206904, 'ltp': 208700.0, 'volume': 135481.11248751, 'volume_by_product': 18380.43374774}
{'product_code': 'BTC_JPY', 'timestamp': '2017-05-09T14:55:01.023', 'tick_id': 388315, 'best_bid': 208700.0, 'best_ask': 208820.0, 'best_bid_size': 6.95343174, 'best_ask_size': 0.001, 'total_bid_depth': 5011.09612844, 'total_ask_depth': 1350.24206904, 'ltp': 208700.0, 'volume': 135481.11348751, 'volume_by_product': 18380.43374774}
{'product_code': 'BTC_JPY', 'timestamp': '2017-05-09T14:55:01.477', 'tick_id': 388318, 'best_bid': 208700.0, 'best_ask': 208820.0, 'best_bid_size': 6.95343174, 'best_ask_size': 0.001, 'total_bid_depth': 5011.21504903, 'total_ask_depth': 1350.24206904, 'ltp': 208700.0, 'volume': 135481.11348751, 'volume_by_product': 18380.43374774}

ドキュメントは以下。

API は、

  • API キーによる認証が不要な HTTP Public API
  • 認証が必要な HTTP Private API

に分けられる。なのでほんとうは、pybitflyer.API()のインスタンス引数に、

  • api_key
  • api_secret

を取得して、設定する必要があるのだが、口座開設してすぐには発行されないので、今はこれで。 API Key, API Secret は、ビットコイン取引所【 bitFlyer Lightning 】 にログインして、 左バーのところにある API を選択して、取得する。

どんな情報が取得できたのか

json ライブラリで見やすくする。

import pybitflyer
import json

api = pybitflyer.API()
while True:
    print(json.dumps(api.ticker(product_code = "BTC_JPY"), 
                     sort_keys=True, indent=4))

取得結果。

{
    "best_ask": 209190.0,
    "best_ask_size": 0.0075,
    "best_bid": 209147.0,
    "best_bid_size": 0.02277838,
    "ltp": 209557.0,
    "product_code": "BTC_JPY",
    "tick_id": 392364,
    "timestamp": "2017-05-09T15:08:51.51",
    "total_ask_depth": 1312.51807976,
    "total_bid_depth": 4998.61968155,
    "volume": 134942.30375862,
    "volume_by_product": 18338.51424803
}

トレード用にデータを間引く

ここでトレードに必要な情報は、FX の経験からいうと、

  • best_bid
  • best_ask

(- product_code)

  • timestamp

データを修正する。

import pybitflyer
import json

api = pybitflyer.API()

class Event(object):
    pass

class TickEvent(Event):
    def __init__(self, instrument, time, bid, ask):
        self.type = 'TICK'
        self.instrument = instrument
        self.time = time
        self.bid = bid
        self.ask = ask

    def show(self):
        print("instrument:" + self.instrument +
              ", time:" + self.time +
              ", bid:" + str(self.bid) +
              ", ask:" + str(self.ask))

while True:
    data = json.dumps(api.ticker(product_code = "BTC_JPY"))
    data_dict = json.loads(data)
    event = TickEvent(data_dict['product_code'], 
                      data_dict['timestamp'],
                      data_dict['best_bid'],
                      data_dict['best_ask'])
    event.show()
instrument:BTC_JPY, time:2017-05-09T15:52:25.537, bid:209164.0, ask:209165.0
instrument:BTC_JPY, time:2017-05-09T15:52:26.413, bid:209164.0, ask:209165.0
instrument:BTC_JPY, time:2017-05-09T15:52:26.853, bid:209164.0, ask:209165.0
instrument:BTC_JPY, time:2017-05-09T15:52:26.697, bid:209164.0, ask:209165.0
instrument:BTC_JPY, time:2017-05-09T15:52:27.257, bid:209164.0, ask:209165.0
instrument:BTC_JPY, time:2017-05-09T15:52:27.977, bid:209164.0, ask:209165.0
instrument:BTC_JPY, time:2017-05-09T15:52:27.977, bid:209164.0, ask:209165.0
instrument:BTC_JPY, time:2017-05-09T15:52:27.977, bid:209164.0, ask:209165.0
instrument:BTC_JPY, time:2017-05-09T15:52:27.977, bid:209164.0, ask:209165.0
instrument:BTC_JPY, time:2017-05-09T15:52:30.457, bid:209164.0, ask:209165.0

これで、FX とおなじデータ形式になったので、FX のコードが再利用できるぞ。

追記 ヒストリカルデータが欲しいな

シストレするためには、バックテストをしたい。そのために、ヒストリカルデータが必要だ。

さがしてみると、coincheck のデータが Bitcoincharts というサイトで Markets API として公開されているようだ。

以下の日本語の記事が詳しい。

なので、Bitflyer は止めて、Coincheck(コインチェック) に変更することにした。

coincheck も python の API がある。ありがたい。

これをつかって、Producer-Consumer Pattern をつかって、値を取得する処理を途中まで書いた。

開発中のリポジトリは以下です。