読者です 読者をやめる 読者になる 読者になる

【TensorFlow】リカレントニューラルネットワークで為替レートを予測【FX】

Deep Learning Neural Network TensorFlow

以前、ニューラルネットワークで為替レートを予測する記事を書きましたが、 今度はTensorFlowを使って予測してみました。
前回とは異なり、今回はリカレントニューラルネットワークというものを使ってみます。理論は殆ど理解できていないので、 ここにあるコードを書き換えました。

入力は、4時間足のデータ25個、出力は3パターンで、4時間後に値が上昇するなら、[1,0,0]、下がるなら[0,1,0]、同値なら[0,0,1]としています。 なお、入力値は0~1の値に正規化しています。

学習プログラム

import tensorflow as tf
from tensorflow.contrib import rnn
import numpy as np


# Parameters
learning_rate = 0.01
training_iters = 100000
batch_size = 100
display_step = 10

# Network Parameters
n_input = 1
n_steps = 25 # timesteps
n_hidden = 1024 # hidden layer num of features
n_classes = 3

#exchange rates
data=np.loadtxt("input.csv",delimiter=",")

# tf Graph input
x = tf.placeholder("float", [None, n_steps, n_input])
y = tf.placeholder("float", [None, n_classes])

# Define weights
weights = {
    # Hidden layer weights => 2*n_hidden because of foward + backward cells
    'out': tf.Variable(tf.random_normal([2*n_hidden, n_classes]))
}
biases = {
    'out': tf.Variable(tf.random_normal([n_classes]))
}

def BiRNN(x, weights, biases):

    # Prepare data shape to match `bidirectional_rnn` function requirements
    # Current data input shape: (batch_size, n_steps, n_input)
    # Required shape: 'n_steps' tensors list of shape (batch_size, n_input)
    
    # Permuting batch_size and n_steps
    x = tf.transpose(x, [1, 0, 2])
    # Reshape to (n_steps*batch_size, n_input)
    x = tf.reshape(x, [-1, n_input])
    # Split to get a list of 'n_steps' tensors of shape (batch_size, n_input)
    x = tf.split(x, n_steps, 0)

    # Define lstm cells with tensorflow
    # Forward direction cell
    lstm_fw_cell = rnn.BasicLSTMCell(n_hidden, forget_bias=1.0)
    # Backward direction cell
    lstm_bw_cell = rnn.BasicLSTMCell(n_hidden, forget_bias=1.0)

    # Get lstm cell output
    try:
        outputs, _, _ = rnn.static_bidirectional_rnn(lstm_fw_cell, lstm_bw_cell, x,
                                              dtype=tf.float32)
    except Exception: # Old TensorFlow version only returns outputs not states
        outputs = rnn.static_bidirectional_rnn(lstm_fw_cell, lstm_bw_cell, x,
                                        dtype=tf.float32)

    # Linear activation, using rnn inner loop last output
    return tf.matmul(outputs[-1], weights['out']) + biases['out']

pred = BiRNN(x, weights, biases)

# Define loss and optimizer
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred, labels=y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)

# Evaluate model
correct_pred = tf.equal(tf.argmax(pred,1), tf.argmax(y,1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

# Initializing the variables
init = tf.global_variables_initializer()

# Launch the graph
with tf.Session() as sess:
    sess.run(init)
    step = 1
    # Keep training until reach max iterations
    while step * batch_size < training_iters:
        
        np.random.shuffle(data)
        
        batch_x=data[0:batch_size,0:n_steps]
        #normalize
        batch_x=batch_x-np.min(batch_x,axis=1).reshape(batch_size,1)
        batch_x=batch_x/np.max(batch_x,axis=1).reshape(batch_size,1)

        batch_x = batch_x.reshape((batch_size, n_steps, n_input))
        batch_y=data[0:batch_size,n_steps:n_steps+n_classes]
        batch_y=batch_y.reshape((batch_size,n_classes))

        # Run optimization op (backprop)
        sess.run(optimizer, feed_dict={x: batch_x, y: batch_y})
        if step % display_step == 0:
            # Calculate batch accuracy
            acc = sess.run(accuracy, feed_dict={x: batch_x, y: batch_y})
            # Calculate batch loss
            loss = sess.run(cost, feed_dict={x: batch_x, y: batch_y})
            #print ("Iter"+str(step*batch_size)+", Training Accuracy="+str(acc))
            print ("Iter " + str(step*batch_size) + ", Minibatch Loss= " + \
                 "{:.6f}".format(loss) + ", Training Accuracy= " + \
                  "{:.5f}".format(acc))

        step += 1
    print ("Optimization Finished!")

結果

Iter 90000, Minibatch Loss= 0.746534, Training Accuracy= 0.50000
Iter 91000, Minibatch Loss= 0.750871, Training Accuracy= 0.47000
Iter 92000, Minibatch Loss= 0.738956, Training Accuracy= 0.54000
Iter 93000, Minibatch Loss= 0.803958, Training Accuracy= 0.55000
Iter 94000, Minibatch Loss= 0.784448, Training Accuracy= 0.58000
Iter 95000, Minibatch Loss= 0.764126, Training Accuracy= 0.49000
Iter 96000, Minibatch Loss= 0.750926, Training Accuracy= 0.54000
Iter 97000, Minibatch Loss= 0.836504, Training Accuracy= 0.47000
Iter 98000, Minibatch Loss= 0.828720, Training Accuracy= 0.51000
Iter 99000, Minibatch Loss= 1.095886, Training Accuracy= 0.54000
Optimization Finished!

10万回回した結果、学習データに対してすら50数%程度で、ランダムと対して変わらない結果になってしまいました。 モデルが単純すぎるのか、入力値が悪いのか、そもそも予測ができないものなのか分かりませんが、もう少し工夫してみたいです。

WindowsにTensorFlowをインストール

TensorFlow

普段、TensorFlowはUbuntuが入ったノートパソコンで動かしていますが、 画像処理を行おうとすると、流石にスペック不足の為、 Windows10のデスクトップPCにインストールすることにしました。

インストール方法

基本的に公式サイトを見れば良いですが、 案内通りにAnacondaをインストールして下記を実行すると、エラーが発生しました。

pip install --upgrade https://storage.googleapis.com/tensorflow/windows/cpu/tensorflow-0.12.1-cp35-cp35m-win_amd64.whl
tensorflow-0.12.1-cp35-cp35m-win_amd64.whl is not a supported wheel on this platform.

AnacondaでインストールされたのがPython3.6で、公式サイトでサポートしていると謳っているのが、3.5なので、 3.6をアンインストール後、3.5をインストールして、上記コマンドを実行すると、無事インストールされました。

ちゃんとインストールされているかどうかは、公式サイトにある通り、 pythonを起動して、tensorflowをインポートできるかどうかで確認できます。

TensorFlowのTutorialを改造して画像識別

TensorFlow

以前少しだけTensorFlowの記事を書きましたが、 久しぶりにTensorFlowを触ってみたので、成果物のご紹介。

やりたいこと

アイドルマスターシンデレラガールズのキャラクターを識別する。

やったこと

  • フリーソフトを使って画像を自動収集。
  • ここのプログラムの応用で、顔画像を切り出して、手動でタグ付け。(ファイル名を"タグ,(連番).jpg"に)
  • チュートリアルのプログラムを元に、学習プログラムを作成して、顔画像を学習。
  • 学習したパラーメタを使って検証。

学習プログラム

学習した顔画像は、64*64のリサイズにして保存しています。 また、ファイル名のカンマ以前の数字がキャラクターを識別するタグとなります。 今回は2500枚程度用意しました。

顔画像の例↓

f:id:oki-lab:20170205200131j:plain f:id:oki-lab:20170205200202j:plain

import cv2
import sys
import os.path
import glob
import numpy as np
import tensorflow as tf

image_w=64
image_h=64
dim_in=image_w*image_h
dim_out=18
limit=3000
batch_size=100

paths=glob.glob("images/*")
image_num=len(paths)

train_x=np.zeros((image_num,dim_in))
train_y=np.zeros((image_num,dim_out))

#loading images
cnt=0
for path in paths:
    image = cv2.imread(path,0)/255.0
    tag=int(os.path.basename(path).split(",")[0])
    train_x[cnt,:]=[flatten for inner in image for flatten in inner] #flatten matrix
    train_y[cnt,tag]=1
    print (tag)
    cnt+=1

#neural network
x = tf.placeholder(tf.float32, [None, dim_in]) #place holder
W = tf.Variable(tf.zeros([dim_in, dim_out])) #weight
b = tf.Variable(tf.zeros([dim_out])) #bias
y = tf.nn.softmax(tf.matmul(x, W) + b) #normalize
y_ = tf.placeholder(tf.float32, [None, dim_out]) #placeholder

#cross entropy
cross_entropy = -tf.reduce_sum(y_ * tf.log(y))

#minimize cross_entropy using the gradient descent algorithm
train_step = tf.train.GradientDescentOptimizer(0.0005).minimize(cross_entropy)

#initialize all variables
init = tf.initialize_all_variables()

#correct boolean list
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
#cast to float point numbers
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
saver=tf.train.Saver()

sess = tf.Session()
sess.run(init)

#training step
train_count=0
for i in range(limit):
    rnd=np.random.randint(image_num-batch_size)
    sess.run(train_step,feed_dict={x:train_x[rnd:rnd+batch_size,:],y_:train_y[rnd:rnd+batch_size,:]})
    train_count+=1
    print train_count,sess.run(accuracy,feed_dict={x:train_x[rnd:rnd+batch_size,:],y_:train_y[rnd:rnd+batch_size,:]})
    
print sess.run(accuracy,feed_dict={x:train_x,y_:train_y})

#save
saver.save(sess,"model.ckpt")

概要説明:
“images"フォルダに保存された顔画像を読み込み、画素情報を一次元化し、入力用テンソルに保存。
ウェイトやバイアス、損失関数や正答率用の関数を定義。
バッチサイズ分のデータを切り出して、学習。それを規定ステップ分繰り返し。
最後にモデルを保存。

評価用プログラム

import cv2
import os.path
import glob
import numpy as np
import tensorflow as tf

image_w=64
image_h=64
dim_in=image_w*image_h
dim_out=18

paths=glob.glob("images/*")
image_num=len(paths)

train_x=np.zeros((image_num,dim_in))
train_y=np.zeros((image_num,dim_out))

#loading images
cnt=0
for path in paths:
    image = cv2.imread(path,0)/255.0
    tag=int(os.path.basename(path).split(",")[0])
    train_x[cnt,:]=[flatten for inner in image for flatten in inner] #flatten matrix
    train_y[cnt,tag]=1
    print (tag)
    cnt+=1

#neural network
x = tf.placeholder(tf.float32, [None, dim_in]) #place holder
W = tf.Variable(tf.zeros([dim_in, dim_out])) #weight
b = tf.Variable(tf.zeros([dim_out])) #bias
y = tf.nn.softmax(tf.matmul(x, W) + b) #normalize
y_ = tf.placeholder(tf.float32, [None, dim_out]) #placeholder

#correct boolean list
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
#cast to float point numbers
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    
saver=tf.train.Saver()
sess=tf.Session()
saver.restore(sess,"model.ckpt")

print sess.run(accuracy,feed_dict={x:train_x,y_:train_y})

概要説明:
画像の読み込みや変数、関数の定義は同じ。
モデルを読み込み、これを使って識別した時の正答率を表示。

所感

今回は画像があまり集められなかったことと、振り分けが面倒だったことが理由で、
画像の量が少ないですが、学習用データに対する正答率は94%程度でした。
上記のプログラムはディープラーニングではなく、非常に単純なニューラルネットワークなので、
気が向いたらディープラーニング化してみたいと思います。

Unityの起動失敗と対策

Unity

初めてUnity Bug Reporterを使ってみた、というお話。

先日、デスクトップPCを買い替えたため、色々と開発環境を整えているところですが、
Unityをインストールしたところ、起動直後にクラッシュする現象が発生しました。

とりあえず調べてみて、下記の事を試してみました。

・再インストールする。
・セキュリティソフトを終了させる。
・起動オプションに「 -force-d3d11」を追加する。
・管理者として実行する。
・互換モードで実行する。
・起動時にAltキーを押す。

全部やっても解決せず、万策尽きた感じになったため、
Unity Bug Reporterにて、レポート送信してみました。

ログは勝手に送信可能な状態になってるので、メールアドレスとタイトルを
入れてSendボタンを押すだけです。

回答が来るまで時間がかかるかと思いましたが、約15時間で返ってきました。

回答要約すると、
Lavasoft Web Companionというソフトがインストールされてるので、
これをアップデートしなさい。
という内容でした。

Lavasoft Web Companionなどというソフトをインストールした覚えが無かったため、
アンインストールしたところ、無事Unityが起動するようになりました。

あまり期待していなかったのですが、非常に早く解決できたため、
Unityに関して何か問題があった場合は、Bug Reporterを活用すると
幸せになれるかもしれません。

ニューラルネットワークで手書き文字認識

Python Neural Network

前回の記事でニューラルネットワークを使って為替レートを予測してみましたが、 せっかくなので、それを少し改良してTensorflowのチュートリアルと同じく手書き文字認識を試してみました。

import cv2
import numpy as np
from itertools import *

digit_w=28
digit_h=28
dim_in=digit_w*digit_h
dim_out=10
hidden_count=128
learn_rate=0.005
limit=50000

#weight and bias
w1 = np.random.rand(hidden_count, dim_in)-0.5
w2 = np.random.rand(dim_out, hidden_count)-0.5
b1 = np.random.rand(hidden_count)-0.5
b2 = np.random.rand(dim_out)-0.5

# activation function
def activation(x):
    return np.maximum(0, x)
    #return 1.0/(1.0+np.exp(-x))
    
# differential
def activation_dash(x):
    return (np.sign(x) + 1) / 2
    #return (1-activation(x))@activation(x)

#forward calculation
def forward(x):
    #return w2 @ activation(w1 @ x + b1) + b2
    return np.dot(w2,activation(np.dot(w1,x)+b1))+b2
    

# backpropagation
def backward(x, diff):
    global w1, w2, b1, b2
    #v1 = (diff @ w2) * activation_dash(w1 @ x + b1)
    #v2 = activation(w1 @ x + b1)

    v1=np.dot(diff,w2)*activation_dash(np.dot(w1,x)+b1)
    v2=activation(np.dot(w1,x)+b1)

    w1 -= learn_rate * np.outer(v1, x)
    b1 -= learn_rate * v1
    w2 -= learn_rate * np.outer(diff, v2)
    b2 -= learn_rate * diff

#column and row number of mnist images
image_shape=np.zeros((10,2),dtype=int)
#number of all mnist data
data_num=np.zeros((10,1),dtype=int)

#count number of mnist data
images=[]
for idx in range(0,10):
    images.append(cv2.imread("mnist_img/mnist_train"+str(idx)+".jpg",0)) #load images
    image=images[idx]
    image_shape[idx,0]=len(image[:,1])/digit_h
    image_shape[idx,1]=len(image[1,:])/digit_w-1
    data_num[idx]=image_shape[idx,0]*image_shape[idx,1]

train_count=int(sum(data_num))
train_x=np.zeros((train_count,dim_in))
train_y=np.zeros((train_count,dim_out),dtype=int)

#load input data
cnt=0
temp_num=0
for idx in range(0,10):
    print ("load image:"+str(idx))
    train_y[temp_num:temp_num+int(data_num[idx]),idx]=1 #set output data
    temp_num+=int(data_num[idx])
    image=images[idx]
    for i in range(0,image_shape[idx,0]):
        for j in range(0,image_shape [idx,1]):
            temp=image[digit_h*i:digit_h*(i+1),digit_w*j:digit_w*(j+1)]/255.0 #cut images
            train_x[cnt]=[flatten for inner in temp for flatten in inner] #flatten matrix
            cnt+=1

#main
idxes = np.arange(train_count)
_error=limit*[0]
batch_size=100
for epoc in range(limit):
    np.random.shuffle(idxes)
    error = 0
    cnt=0
    for idx in idxes:
        y = forward(train_x[idx])
        diff = y - train_y[idx] 
        error += diff ** 2
        cnt+=1
        backward(train_x[idx], diff)
        if cnt==batch_size:
           break

    _error[epoc]=error    
    print(epoc+1,error.sum(),y)

result=train_count*[0]
for idx in range(train_count):
    result[idx]=forward(train_x[idx])

#accuracy rate
eval=np.argmax(train_y,axis=1)==np.argmax(result,axis=1)
print (float(eval.sum())/eval.size)

np.savetxt("estimated.csv",result,delimiter=",")
np.savetxt("train_y.csv",train_y,delimiter=",")
np.savetxt("error.csv",_error,delimiter=",")

np.savetxt("w1.csv",w1,delimiter=",")
np.savetxt("w2.csv",w2,delimiter=",")
np.savetxt("b1.csv",b1,delimiter=",")
np.savetxt("b2.csv",b2,delimiter=",")


文字のデータはネットを探してjpg化されたものを拾ってきました。

Index of /~roweis/data

0から9までの手書き文字がそれぞれ1枚ずつ用意されていて、 それをグレースケールで一次元のデータとして読み込んでいます。 ※値は255で正規化。

データが読み込めたら後は、学習させるだけです。

上のプログラムに記載されているノード数、学習回数、学習率で実行すると、 約94%の正答率でした。学習したデータに対する正答率なので、もう少し高くても良い気もしますが、 特に何の工夫もしていませんので、こんなものでしょうか。

やる気があれば、ディープラーニングのプログラムを組んで、もう一回試してみたいです。



Python機械学習プログラミング 達人データサイエンティストによる理論と実践 impress top gearシリーズ

機械学習ライブラリを使わずニューラルネットワークで為替レートを予測する

Neural Network Python

ニューラルネットワークといえば、pylearn2やTensrflowなどのライブラリがありますが、 使い方が独特だったりして習得に時間がかかるため、今回はこれらのようなライブラリを使わずに、 pythonの標準機能とnumpyで、為替レートの予測をやってみました。


ニューラルネットワークのプログラムは、一から作るのが面倒だったため、Wikipediaのソースを改変。

ニューラルネットワーク - Wikipedia

# -*- coding: utf-8 -*-
import numpy as np

dim_in = 10              # 入力
dim_out = 1             # 出力
hidden_count = 1024     # 隠れ層
learn_rate = 0.05      # 学習率
limit=3000             #学習回数

#学習データ読み込み
data=np.loadtxt("USDJPY_1D.csv",delimiter=",")
train_x=data[:,0:dim_in]/150.
train_y=data[:,dim_in:dim_in+dim_out]/150.
train_count=len(data)
    
# 重みパラメータ。-0.5 ? 0.5 でランダムに初期化。この行列の値を学習する。
w1 = np.random.rand(hidden_count, dim_in)-0.5
w2 = np.random.rand(dim_out, hidden_count)-0.5
b1 = np.random.rand(hidden_count)-0.5
b2 = np.random.rand(dim_out)-0.5

# 活性化関数
def activation(x):
    return np.maximum(0, x)
    #return 1.0/(1.0+np.exp(-x))
    
# 活性化関数の微分
def activation_dash(x):
    return (np.sign(x) + 1) / 2
    #return (1-activation(x))@activation(x)

# 順方向。学習結果の利用。
def forward(x):
    return w2 @ activation(w1 @ x + b1) + b2

# 逆方向。学習
def backward(x, diff):
    global w1, w2, b1, b2
    v1 = (diff @ w2) * activation_dash(w1 @ x + b1)
    v2 = activation(w1 @ x + b1)

    w1 -= learn_rate * np.outer(v1, x)  # outerは直積
    b1 -= learn_rate * v1
    w2 -= learn_rate * np.outer(diff, v2)
    b2 -= learn_rate * diff

# メイン処理
idxes = np.arange(train_count)
_error=np.zeros(limit)
for epoc in range(limit):
    np.random.shuffle(idxes)            # 確率的勾配降下法のため、エポックごとにランダムにシャッフルする
    error = 0                           # 二乗和誤差
    cnt=0
    for idx in idxes:
        y = forward(train_x[idx])       # 順方向で x から y を計算する
        diff = y - train_y[idx]         # 訓練データとの誤差
        error += diff ** 2              # 二乗和誤差に蓄積
        cnt+=1
        backward(train_x[idx], diff)    # 誤差を学習
        if cnt==np.round(train_count*0.1):
           break
    _error[epoc]=error    
    print(epoc+1,error.sum(),y)                  # エポックごとに二乗和誤差を出力。徐々に減衰して0に近づく。

#結果表示
result=np.zeros([train_count,2])
for i in range(train_count):
    result[i,0]=train_y[i]*150.
    result[i,1]=forward(train_x[i])*150.
    print(result[i,0],result[i,1])

#ファイル出力
np.savetxt("error.csv",_error,delimiter=",")
np.savetxt("result.csv",result,delimiter=",")

ニューラルネットワークの入力は過去10日分の終値、出力は翌日の終値としています。これを約6年分。 なお、どう正規化するのが良いのかわからなかったため、適当に150で割っています。 このデータ自体はMT4というFX用のソフトを使って取得しています。

3.ヒストリカル・データのCSVエクスポート - とあるMetaTraderの備忘秘録


実際に上記のプログラムで学習させた結果が以下です。上が誤差の推移、下が真値と推定値の比較です。

f:id:oki-lab:20160619003154p:plain

f:id:oki-lab:20160619003205p:plain

パッと見、良く予測できているように見えますが、実際には平均で0.5%ほど誤差があります。 流石にFXに使える程の精度ではありません。

実際にプログラムを動かす時に、学習時間の短縮のために全部のデータを学習するのではなく、 一部を使用するように以下の文を加えたのですが、何故か全データ学習した時より誤差は小さくなっていました。 時間が短縮できて、誤差も小さくなるのは素晴らしいですが、理屈が分からずじまい。

        if cnt==np.round(train_count*0.1):
           break

また、活性化関数としてシグモイド関数も試してみましたが、計算時間が長くなってしまった上に、誤差が大きくなりました。 ニューラルネットワークといえばシグモイドというイメージでしたが、今はReLUが最強?。


確かな力が身につくPython「超」入門 (確かな力が身につく「超」入門シリーズ)

Raspberry Pi3にUbuntu mateをインストール

Raspberry Pi

遅ればせながらRaspberry Pi3を入手しましたので、Ubuntu mateをインストールしてみました。 Raspberry Pi 3 Model B

Windowsを使ったセットアップ方法を簡単にまとめてみます。

まず、下記のリンク先で、OSのISOをダウンロードします。

Download Ubuntu MATE | Ubuntu MATE

Win32 Disk Imagerをダウンロードします。

sourceforge.net

Win32 Disk Imagerを起動して、ダウンロードしたISOを選択し、SDカードに書き込みます。

f:id:oki-lab:20160505081753p:plain

最後に、SDカードをRaspberry Piに差し直して起動し、普段通りに初回起動のセットアップを行います。

なお、Raspberry Pi3は標準でWifi機能を搭載しており、普通のLinuxと同じように繋ぐことができます。 ただし、その分電気を食いますので、ご注意ください。

ちなみに、インストールしてみて初めて知りましたが、Minecraftがプリインストールされていました。 普通の製品版とは違うと思いますが、少し遊ぶ分には良いと思います。

f:id:oki-lab:20160505081947p:plain

一番初めのRaspberry PiはPCとしての性能は低く、実用には堪えないものでしたが、ここまで性能が高くなってくると、ウェブブラウジング程度であれば問題ないため、子供用PCとしての使用もアリかも知れません。