とある京大生の作業ログと日々の雑記

コンピュータサイエンスについて学んだことを可視化したり日々の雑記をまとめてます。

Deep Learningを使って株価の予測してみた話(後編)

こんばんは!コミさん(@komi3__ )です!


前々回に「Deep Learningを使って株価の予測してみた(前編)」と題して、Quandlでのデータの引き出しの方法を解説して放ったらかしてましたね....


そして課題に追われ続けてHaskellの話を間に挟んで、ようやくって感じです。


今週は大変だった...(レポート何個か間に合ってないんですけど)


まあとりあえず実装の方をパパッと解説していきましょう。



実装解説


とりあえず実装の方はGithubに上げておきましたので、実装解説とか見なくてとりあえずコード見てみたい人はこちらを参照してください。


今回の実装の基本アーキテクチャとしてはLSTMを使って、って感じでとても簡単なんですけど、PyTorchに慣れてない人からすれば多少実装で困ったりつまずくポイントがあると思うので(ぼくもいくらかつまずいたので)、そこらへんをTipsとしてまとめつつ解説していこうと思います。

データ取得クラス

まずはデータ取得クラスのget_data.pyを見ていきましょう。

import quandl
import numpy as np 
import torch
from torch.autograd import Variable 


class Get_data:
    def __init__(self, n_prev, data_code):
        self.n_prev = n_prev
        self.data = quandl.get(data_code, returns="numpy")
        self.X = []
        self.Y = []

    def get_data(self, today):
        for k in range(self.n_prev):
            self.X.append(self.data[today-self.n_prev+k][1])
        self.Y.append(self.data[today][1])
        self.X = Variable(torch.from_numpy(np.array(self.X))).float().view(1,1,self.n_prev)
        self.Y = Variable(torch.from_numpy(np.array(self.Y))).float().view(1,1,1)
        return self.X, self.Y

    def get_raw_data(self):
        return self.data


データの取り方はどうしようかなって悩んだんですけど、簡単にNumpyからのデータ取得でスライスでリストにぶち込んでくスタイルが簡単にわかりやすいかなぁってことで、データの取得形式にはNumpyにしました。

引数には日にちをとって、その直前の日数(n_prev)を出力します。(for文でリストにappendしていきます)

そんな感じで、データの取得は学習材料となる直前n_prev日分のデータと教師データとしてのその日のデータの2つを返すようにしました。


そのあとの作業としてPyTorchでの実装に沿うようにデータをfloatTensor形式にして、ってのがそのあとに書いてる作業です。

「Numpyで要素取り出し→リスト→Numpyリストに変換→TorchのTensor形式に変換」っていうなんかめんどくさい手法とってるけどもっとうまい方法あるはずなんだよなぁ...

とりあえずこんな感じでデータの取得が完了します。


まあこれで簡単に済むんですけど、実装の際にはデータの形式に少し戸惑いまして...

そこをTipsとしてまとめときます。


Tips1. PyTorchでのTensor形式について

最初、ネットワーク部分に突っ込むときにリストをただぶち込んでたんですけどエラーめっちゃ吐きまくってたんですよ。

んで、色々ググってたんですけど、どうやらまずはtorch.autograd.Variable(~~~)で変数形式にしないといけないらしいんですよね。

で、変数以外にもIntTensorとか色々形式があって、そこも一致させなければいけないんですよ。

Tensor形式は以下の通りです。

Data typeCPU TensorGPU Tensor
32-bit floating pointtorch.FloatTensortorch.cuda.FloatTensor
64-bit floating pointtorch.DoubleTensortorch.cuda.DoubleTensor
16-bit floating pointtorch.HalfTensortorch.cuda.HalfTensor
8-bit integer (unsigned)torch.ByteTensortorch.cuda.ByteTensor
8-bit integer (signed)torch.CharTensortorch.cuda.CharTensor
16-bit integer (signed)torch.ShortTensortorch.cuda.ShortTensor
32-bit integer (signed)torch.IntTensortorch.cuda.IntTensor
64-bit integer (signed)torch.LongTensortorch.cuda.LongTensor

これに基づいて、データ形式の一致をさせなければいけないんです。

ネットワーククラス

次にネットワーククラスのnetwork.pyです。

import torch.nn as nn 
from torch.autograd import Variable


class Network(nn.Module):
    def __init__(self, n_prev, h0, c0):
        super(Network, self).__init__()
        self.n_prev = n_prev
        self.h0 = h0
        self.c0 = c0

        self.LSTM_layer = nn.LSTM(self.n_prev, self.h0, self.c0)
        self.fc1 = nn.Linear(self.h0, 300)
        self.fc2 = nn.Linear(300, 250)
        self.fc3 = nn.Linear(250, 150)
        self.fc4 = nn.Linear(150, 100)
        self.fc5 = nn.Linear(100, 50)
        self.fc6 = nn.Linear(50, 20)
        self.fc7 = nn.Linear(20, 1)

    def forward(self, x):
        output, hn = self.LSTM_layer(x)
        out = self.fc1(output)
        out = self.fc2(out)
        out = self.fc3(out)
        out = self.fc4(out)
        out = self.fc5(out)
        out = self.fc6(out)
        predict = self.fc7(out)
        return predict

Linearを7層にしたのは友達に「好きな数字言って」って聞いたら「7」って答えたので7層にしました(笑)

ここら辺は、まあLSTM使ってるんだなぁって感じで見てくれたらだいたいやろうとしてることはわかると思います。

LSTMについては以下のQiitaの記事がわかりやすいので参照お願いします。

qiita.com

Tips 2. Define by run を意識した組み方を

ぼくもともとTensorflowをメインに使ってたんですけど、Tensorflowって静的グラフ構築を特徴としてて、Define and runって表現されるじゃないですか。

それに対してPyTorchは動的グラフ構築というアーキテクチャを使っててDefine by runって表現されます。

そこの基本部分の差にちょっとつまづいて、ネットワーククラスの構築は少し手間取りました。


具体的に、__init__関数ではまず雛形を作って、その後のforward関数で流れを記述する感じです。

まあデータ形式さえ間違えなければ、基本はPyTorchのチュートリアルとかを参考にしてLSTMのネットワークは組めると思います。

エージェント部分

これをもとに組めばいけると思います。


予測結果は以下のような感じでした。

f:id:komi1230:20171119180636p:plain

なんかそれっぽいですよね(笑)

平均誤差は以下の通りでした。

Average loss : 10.2456


果たしてこれが当たってると見るかどうかは人次第ですね....


まあ多少はそれっぽいものが組めたんかなぁ...


まとめ

今回はPyTorchを使っての株価分析モデルの実装を紹介しました。

Tensorflowと比べてだいぶ実装しやすかったような気がします。


多少データ処理とか色々修正箇所があると思いますが、とにかくひとまずはこんなところで完成とします。

今後目立つ修正部分があったりしたらコメント等お願いします。


雑記

ところでなんでこんなPyTorchでの実装の記事書くかっていうと、身の回りで機械学習系の実装してる人、みんなTensorflowかChainerなんですよね。

PyTorchってChainerのフォークしてできたDefine by runのモジュールで〜って話はいつかにしましたよね(してないかも)


Chainerって日本じゃかなり人気ですけど、PyTorchってFacebookがバックについてるから世界規模で見たら圧倒的にPyTorchの方が多いんですよね〜

まあそれで、将来的にシリコンバレーとかで働いてみたいな〜なんて願望を持ってて、ChainerよりPyTorchの方がいいかなってことで最近はPyTorchでの実装をしてます。


(まああとぼくがマークザッカーバーグに憧れを抱いてるってのもあるんですけど)


PyTorchでのメリットって、CUDA使うかどうかの入れ替えが簡単だったり、割と速かったり、コーディングがかなり直感的で理解しやすくパイソニックに書けるって感じで、実はTensorflowに比べてコーディング面なり利用面で優秀なポイントが多いと思うんですよ。


とりあえず、そんなこんなで近々ぼくがTensorflowからPyTorchに乗り換えた理由とかPyTorchの利用方法、実装面で少し詰まったポイントを簡単にまとめようと思ってます。



お疲れ様でした!