きっと3日坊主

Every day is day 3.

LSTMで日経平均株価を予測する

時系列データを処理できるRNNを使ったなにがしかの実験をしてみたかったので、試しに日経平均株価をLSTMで予測するということをしてみた。

LSTMとは

LSTMとは、1995年に登場したRNNを拡張したモデル。RNNに比べ、時系列データの非常に長い依存関係(長い文章など)も学習することが出来る。通常のRNNでは数十ステップほどだが、LSTMは100ステップを超える依存関係も処理することができる。

実験概要

日経平均株価の2007年から2017のデータを使い、LSTMを使って学習します。10日分のデータを入力とし、その次の日のデータを教師ラベルとすることで、予測を学習します。

結果

(MAPEバージョンとMAEバージョンの結果について書く) LSTMセル数: 50 バッチサイズ: 50 エポック数: 100 損失関数: MAPE(Mean Absolute Percentage Error, 平均絶対パーセント誤差)

f:id:thunders1028:20171112013102p:plain

f:id:thunders1028:20171112013154p:plain

青: 予測 オレンジ: テストデータ

大きく上昇したときに予測が全然追いつかず。その後セル数やエポック数を変えてみても特に変わりなし。

しかし、損失関数をMAPEからMAE (Mean Absolute Error, 平均絶対誤差)に変更したところ、予測が改善。

f:id:thunders1028:20171112013546p:plain

f:id:thunders1028:20171112013604p:plain

損失関数の違いをわかってないので、勉強していきたい。

考察

MAEからMAPEにしたら予測がかなりテストデータに近くなったがあまりに近いので、前日の値をそのまま出力してるのでは疑惑がある。どうしたら確かめられるだろうか…?

参考文献

TensorFlow(LSTM)で株価予想 〜 株予想その1 〜 - Qiita

Deep Learningによる株価変動の予想

RNN(LSTM)で株価予測をやってみた(失敗): EeePCの軌跡

代表的なCNNのアーキテクチャについて

CNNについて調べているとLeNetやVGGなど名前のついた構成のネットワークがでてくるのでまとめてみました。各項目の最後に原著論文を載せています。

LeNet

1998年に提案された、現Facebook AI ResearchのYann LeCun先生によるCNNの元祖となるネットワーク。畳込み層とプーリング層を交互に重ねたネットワークで、この時点ですでに現在使われているアーキテクチャとほぼ同じ形になっている。活性化関数がシグモイド関数な点、プーリング層がMaxプーリングではなくサブサンプリングで縮小している点などが特徴。

Gradient-Based Learning Applied to Document Recognition

AlexNet

LeNetが登場してから14年ほど経った2012年に発表された、トロント大のHinton教授を含むチームによるネットワーク。ImageNetを使った画像認識コンペILSVRCで圧倒的な成績を残し、ディープラーニングの火付け役となった。

畳み込み層とプーリング層、そして正規化層と呼ばれる局所的正規化(LRN ― Local Response Normalization)を行う層を重ねた14層のネットワーク。活性化関数はReLUで、Dropoutを用いているのが特徴。他にもData Augmentationなども行っていて、現在使われているCNNでの主要な手法がこの時点ですでに活用されている。

当時はGPU一台にネットワークのすべてのパラメータ(重みなど)を乗せることができなかったので、パラメータを半分にした同一構造のネットワークを2つのGPUに乗せて学習させ、最後に結合していたとか。

ImageNet Classification with Deep Convolutional Neural Networks

VGG

2014年のILSVRCで2位になった、オックスフォード大学のVGGチームのネットワーク。AlexNetをより深くした、畳み込み層とプーリング層から成るどノーマルなCNNで、重みがある層(畳み込み層や全結合層)を16層、もしくは19層重ねたもの。それぞれVGG16やVGG19と呼ばれる。

小さいフィルターを持つ畳み込み層を2〜4つ連続して重ね、それをプーリング層でサイズを半分にするというのを繰り返し行う構造が特徴。大きいフィルターで画像を一気に畳み込むよりも小さいフィルターを何個も畳み込む(=層を深くする)方が特徴をより良く抽出できるらしい。(理由はよくわかってないが、活性化関数を通る回数が増えるため、表現力が増す?)

コンペでは2位に終わったが(1位は後述のGoogLeNet)、とてもシンプルなアーキテクチャなのでよく使われるらしい。

VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE-SCALE IMAGE RECOGNITION

GoogLeNet

前述したとおり、2014年のコンペで1位になったアーキテクチャ。このアーキテクチャは通常の入力層から出力層まで縦一直線な構造ではなく、インセプション構造と呼ばれる横にも層が広がる構造をしている。このため、Inceptionモデルとも呼ばれる。

横への層の広がりは、異なるサイズのフィルターの畳み込み層を複数横に並べて、それを結合するという形になっている。

Going deeper with convolutions

構造にいくつかのバージョンが存在するらしく、現在の最新はInception-v3らしい。

Rethinking the Inception Architecture for Computer Vision

ResNet

Microsoft(当時)のKaiming He氏による、2015年のILSVRCで優勝したネットワーク。それまでのネットワークでは層を深くしすぎると性能が落ちるという問題があったが、それを「スキップ構造」によって解決し、152層もの深さ(前年優勝のGoogLeNetでも22層)を実現した。

スキップ構造は、ある層への入力をバイパスし層をまたいで奥の層へ入力してしまうというもので、これにより勾配の消失や発散を防止し、超多層のネットワークを実現している。

Deep Residual Learning for Image Recognition


もちろんこれらのモデルの派生系になるアーキテクチャも多数存在していますが、基本形として語られる構造はこのくらいわかっていれば話についていけなくなることはないと思います。多分。

参考文献

ゼロから作るディープラーニング

AlexNet

[ディープラーニング] AlexNet – Tech Memo

AlexNet論文 | 有意に無意味な話

VGG

機械学習論文読み:VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE-SCALE IMAGE RECOGNITION - Qiita

ResNet

[Survey]Deep Residual Learning for Image Recognition - Qiita

7月第3週

あるブログでその週に知ったこと / 学んだことをブログに書くということをしていていいなぁと思ったので、自分もやってみる。(いつまでつづくかわからんけど…)

IaaS と PaaS と SaaS

IaaSはOS、ハードウェア、ネットワークといった ”インフラ” の部分が用意されていて、そこに仮想サーバーを立て、ミドルウェアを自前でインストールし、アプリケーションをデプロイする。なので、Linux上での設定やセキュリティ対策もすべて自前でしなければならないが、その分自分ですべて管理し設定できるというメリットもある。

PaaSはIaaSの提供するものに加えて、データベースや言語の実行環境などのミドルウェアの範囲まで提供する。そのため、アプリケーションさえ用意すれば簡単にデプロイすることができ、OSの更新や脆弱性対策までサービスの管理下にあるので手間いらずではあるが、そのPaaSが提供するミドルウェアしか選択することができないというデメリットもある。

SaaSはアプリケーションまで用意されているので、そのサービスを使って目標を達成すればいい。GmailやこのはてなブログSaaSに該当する。

IaaS と VPS

IaaSとVPSは基本的には同じであるが、IaaSは従量課金制で柔軟にリソース(CPUやストレージなど)を変更できるが、VPSはリソースの変更のためには契約を更新しなければならないなどの違いがある

VPSレンタルサーバー(共有サーバー)

VPSレンタルサーバーって同じでしょ?って思ってたら、そういうわけではないらしい。VPSは一つの物理サーバーを複数人が使うが、ユーザーごとにゲストOSが作られゲストOSごとにリソースが確保される。そのため、他のユーザーが負荷の高い処理を行ったとしても、基本的に自分には影響しない。これがVirtual Private Server(仮想専用サーバー)という名前の由来だろう。

それに対し、共有サーバー型のレンタルサーバーは同じOS、同じリソースを複数人で使うため、他のユーザーの負荷の影響が自分にも現れる。

静的リンクライブラリと動的リンクライブラリ(.soファイル)

ライブラリには、

  • コンパイル時に結合する静的ライブラリ
  • 実行時に結合する動的リンクライブラリ

の2種類がある。

動的リンクライブラリは共有ライブラリとも呼ばれる。

実行時に結合されるので、ライブラリの改造、交換などがしやすい。

動的リンクライブラリの拡張子は、ウインドウズでは.dll、Unixでは.so(Shared Object: 共有オブジェクトの略)であることが多い。

システムコールとは

C言語の関数のことではなく、OSに処理を依頼するもので、CPU割り込みなど通常のプログラムとは違う動作をする。

そう遠くない昔の私がそうでしたが、素直なプログラマならシステムコールをCライブラリで提供されている関数のことだと定義するかもしれません。しかしこれは全く正しくありません。確かにCライブラリに含まれる関数群はシステムコールときれいに対応するものが多い一方(例:chdir)、オペレーティング>システム(OS)に対して特定の動作を要求する以上に色々な処理が行われるものもあります(例:forkや fprintf)。またこれらの他に、qsortやstrtokに代表されるような、OSの機能は特に使わずにプログラミングのための機能を提供するような関数もあります。

実は、システムコールには非常に明確な定義があります。それは、「ユーザーが実行したい操作をユーザーの代わりに実行するように、OSのカーネルに対して要求する手段」です。

チュートリアル – システムコールの書き方

intel Coreシリーズの型番の読み方

f:id:thunders1028:20170715174925p:plain

f:id:thunders1028:20170715174917p:plain

f:id:thunders1028:20170715174912p:plain

【CPU】Intel Core i7, Core i5, Core i3の世代の一覧・見分け方のまとめ

IntelのCPUの末尾についているK, S, Tなどのアルファベットについて

デカルト座標系とユークリッド空間

みんなが普通に使っている直交座標系のことを「デカルト座標系」、そして2点間の距離をピタゴラスの定理で定義したものを「ユークリッド空間」と呼ぶ。

つまり「デカルト座標系」や「ユークリッド空間」は「普通の空間」のこと。

ベクトルの基礎

構文と式と文

まず「構文(Syntax)」は、そのプログラミング言語内でプログラムが構造を持つためのルールです。多くの場合、プログラミング言語内で特別扱いされるキーワード、たとえばclassやval、ifなどが含まれ、そして正しいプログラムを構成するためのルールがあります。 classの場合であれば、classの後にはクラス名が続き、クラスの中身は{と}で括られる、などです。この節はScalaの制御構文を説明するので、処理の流れを制御するようなプログラムを作るためのルールが説明されるわけです。

次に「式(Expression)」は、プログラムを構成する部分のうち、評価することで値になるものです。たとえば1や1 + 2、"hoge"などです。これらは評価することにより、数値や文字列の値になります。

最後に「文(Statement)」ですが、式とは対照的にプログラムを構成する部分のうち、評価しても値にならないものです。たとえば変数の定義であるval i = 1は評価しても変数iが定義され、iの値が1になりますが、この定義全体としては値を持ちません。よって、これは文です。

制御構文

ペンライトとサイリウムUO

ペンライトは電池式の光る棒。電池を交換すれば再利用可能。

サイリウムは液体薬品の混合により発光する棒。使い捨て。5〜6時間光り続ける。200円くらい。

UOサイリウムの一種で同じように使い捨て。サイリウムよりも強烈に発光する。5〜6分くらいで暗くなる。つまりは短時間だけ強烈に発光するサイリウム。160円くらい。

百万畳ラビリンス

百万畳ラビリンス(上)

百万畳ラビリンス(下)

友人に勧められて読んだマンガ。SFファンタジーみたいな感じ。ゲーム会社のデバッガーとして働く主人公(ふたりいる)が異世界に迷い込んでしまうが、デバッガー業で培ったバグ探し技能や発想の機転を駆使し、異世界を攻略していく。異世界の仕様を把握し、それを逆手に取って武器にしていく様がカッコイイ。

主人公のふたりのうち一人は平凡な人間で一般的な常識人という立ち位置。もう一人は人と違う価値観や能力を持っているために人の間に入れなかった人間。この二人の対比から「人と違う人」の幸せ・価値観・向かう先みたいなものを描いていたりもする。

C言語の規格、方言の種類をざっくりまとめる

なんとなく気になったので調べてみた。主にWikipediaの情報を自分なりにまとめたもので、難しくてよくわからないのでとりあえずざっくり学ぶことが目標なので、細かい部分とかはばっさりカットしてます。

規格の種類

  • K&R
  • C89/C90
  • C99
  • C11

K&R

C言語の作者デニス・リッチーベル研究所に在籍していたカナダ出身の計算機科学者ブライアン・カーニハンの共著である「The C Programming Language」が1978年を出版され、その後標準ができるまで実質的なC言語の標準として扱われる。発展可能性のある部分は曖昧に書かれていたため、C言語の普及とともに互換性のない処理系がいくつも作られた。(これはプログラミング言語でしばしば起こる現象であり、C言語固有の現象ではない。)

C89/C90

上記のような状況から、C言語の標準規格がつくられた。まずはじめに89年にANSI(American National Standards Institute - 米国国家規格協会)で標準化され、その後90年にISOでも標準規格がつくられた。それぞれ、C89(ANSI C89)、及びISO/IEC C90という通称がある。C90の方が章立てが追加されており、その後C89もそれにならって章立てが追加された。

最大の特徴は、C++ と同様の関数プロトタイプを導入して引数の型チェックを強化したことと、void や enum などの新しい型を導入したことである。

C99

1999年に策定された、規格改定で機能拡張されたC。C++の機能をいくつか取り込んでいる。この版のCの規格を通称としてC99と呼ぶ。gccはC99にほとんど対応しているが、一部実装の部分も残っている。

主な追加機能は

  • 変数宣言がブロックの先頭でなくても良くなった。
  • ブール代数を扱うための標準ライブラリー stdbool.h が追加された。
  • 複素数を扱うための標準ライブラリーとして complex.h が追加された。
  • 64 ビット整数値を保持できる long long int 型の追加。
  • // による1行コメント。

など

C11

2011年に改定されたC言語の規格、通称C11が現在の最新のCの規格である。gccやClangが一部対応している。Unicode文字列に標準対応するなどの変更がなされた。

参考

C言語 - Wikipedia

ブライアン・カーニハン - Wikipedia

Pythonで他のディレクトリの.pyをインクルード

他のディレクトリにあるPythonスクリプトをインクルードする場合、ファイル参照パスにそのディレクトリを追加したのち、importを行う。

実行ファイルの同階層のとなりにある../mail-projectディレクトリのsend_email.pysend_mail()をインクルードする場合、次のように書く。

from sys.path import append
from os.path import dirname, abspath
append(dirname(abspath(__file__)) + '/../mail-project')

from send_email import send_mail

fromには.pyを抜いたファイル名を書くことに注意。

Python2.7からGmailを送信する

研究室で毎週特定の曜日(水曜日)の特定の時間にお知らせメールを送信する仕事を任されていて、いままでは前日の毎週火曜日にRight Inboxを使って送信設定していたが面倒になった + Right Inboxの無料枠を使い潰したくないので、Gmailを送信するPythonスクリプトを作ってそれをcronから叩くようにした。備忘録として手順を残しておきます。

Google API Client Libraryを使って、PythonからGmailを送信

今回は、Google API Client Libraryという各言語から各種APIにアクセスする用のライブラリを使った方法を書いていきます。

Gmailを送信するまでの手順

GmailPythonから送信するまでには、OAuthの認証周りを含む以下のような手順が必要です。

  1. Google Developer Consoleから新しいプロジェクトを作成し、OAuthクライアントIDを取得する
  2. authorization codeを取得する
  3. authorization codeをアクセストークンとリフレッシュトークンと交換する
  4. メールを送信する

新しいプロジェクトを作成し、OAuthクライアントIDを取得する

Google Developer Consoleから新しいプロジェクトを作ったら、API Managerの認証情報 -> 認証情報を作成 -> OAuthクライアントID を選択し、クライアントIDとクライアントシークレットを作成します。

f:id:thunders1028:20170605195438p:plain

次に出てくる「アプリケーションの種類」の部分では、今回はPythonスクリプトからAPIを叩くので「その他」を選択してください。

これで、クライアントIDとクライアントシークレットを取得することができました。

次に、Pythonからプロジェクトの情報を利用するための設定ファイル client_secrets.json を作成します。

{
  "web": {
    "client_id": "クライアントID",
    "client_secret": "クライアントシークレット",
    "redirect_uris": [],
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://accounts.google.com/o/oauth2/token"
  }
}

使い捨てみたいなスクリプトをつくるんならわざわざファイルを分けずにハードコードしてもいいんじゃない?って思うかもしれないけれど、OAuth認証をするライブラリ oauth2client がファイルから情報を読むようになっているので、ファイルに書いておいたほうが無難です。(あとでコードを公開することになったときにヘタをこくのも防止できる)

authorization codeを取得する

ここからは、Python上の作業になります(すこしブラウザ操作も入りますが…)。

authorization codeとは、アクセストークンとリフレッシュトークン(後述)を取得するために一度だけ使うトークンのようなものです。一度アクセストークンを取得するために使い終わると、そのauthorization codeはもう使うことができません。

def retrieve_authorize_code(flow):
    auth_url = flow.step1_get_authorize_url()
    webbrowser.open(auth_url) # ブラウザで認証画面を表示
    exit(0)

~~~

"""Main"""
flow = client.flow_from_clientsecrets(
    "client_secrets.json",
    scope = "https://www.googleapis.com/auth/gmail.send", # メール送信の権限を取得する
    redirect_uri = "urn:ietf:wg:oauth:2.0:oob") # authorization codeをブラウザ上に表示

retrieve_authorize_code(flow)

flowとは、OAuthの処理の流れを制御するオブジェクト…のようなものです。OAuthとflowについては、Google Client LibraryのOAuthのガイドページにあるスライドがとても簡潔にまとめられていてわかりやすいです。

さて、retrieve_authorize_code(flow) を実行すると、ブラウザが立ち上がり認証画面が表示されます。

f:id:thunders1028:20170605201537p:plain

ここで「許可」をクリックすると、画面上にauthorization codeが表示されます。

f:id:thunders1028:20170605201738p:plain

このcodeをコピーしてとっておきましょう。

実行したコードは、webbrowser.open(auth_url) のところで止まっています。Ctrl-cで一度中断してください。codeを取得してコード上に埋め込んだら(次のステップでやります)、retrieve_authorize_code(flow) はもう不要です。コメントアウトするなりしましょう。

authorization codeをアクセストークンとリフレッシュトークンと交換する

取得したauthorization codeを使って、アクセストークンとリフレッシュトークンを交換します。リフレッシュトークンとは、アクセストークンの期限が切れた際に、新しいアクセストークンを取得するのに使われるトークンです。

def retrieve_credential(flow):
    auth_code = "auth_code" 
    credential = flow.step2_exchange(auth_code)

    #with open("credential.pickle", "w") as fpickle:
    #    pickle.dump(credential, fpickle)

    #with open("credential.pickle", "r") as fpickle:
    #   credential = pickle.load(fpickle)

    return credential

auth_code のところにauthorization codeを書いてください。

flow.step2_exchange(auth_code) にauthorization codeを渡すだけでアクセストークンとリフレッシュトークンが入ったcredentialが取得できます。このcredentialはメール送信をする際に使いまわすので、DBなどに保存してください。今回は簡単にpickleで保存しました。(oauth2clientのStorage.locked_put() というのを使うのがスジらしいけどなぜか自分の環境ではうまく動かなかったのでこの方法になりました。)

メールを送信する

やっとメール送信です。

def create_service(credential):
    http_auth = credential.authorize(httplib2.Http())
    return build("gmail", "v1", http=http_auth)

def create_mail(message_text, subject, to, from_):
    message = MIMEText(message_text)
    message["subject"] = subject
    message["to"] = to
    message["from"] = from_

    return {"raw": base64.urlsafe_b64encode(message.as_string())}

def send_mail(service, raw):
    try:
        message = service.users().messages().send(userId="me", body=raw).execute()
        print "A message sent. Id: {}".format(message["id"])

    except errors.HttpError, error:
        print "An error occurred: {}".format(error)

~~~

flow = client.flow_from_clientsecrets(
    "client_secrets.json",
    scope = "https://www.googleapis.com/auth/gmail.send",
    redirect_uri = "urn:ietf:wg:oauth:2.0:oob")

credential = retrieve_credential(flow)

service = create_service(credential)

message_text = "hello, world!"
subject = "test subject"
to = "example@gmail.com"
from_ = "example@gmail.com"

mail = create_mail(message_text, subject, to, from_)

send_mail(service, mail)

疲れたので続きはあとで追記します…

Coursera MLコースを修了した

研究で機械学習を使っていることもあり、一度ちゃんと勉強したいという想いから定評のあるAndrew Ng先生のCourseraの機械学習コースを4月終わりに受講し始め、本日修了しました。

f:id:thunders1028:20170529011015p:plain

線形回帰から始まり、ロジスティック回帰、ニューラルネットワーク、応用編にはOCRアプリケーションの構築の仕方など幅広くとてもわかりやすい講義で、機械学習分野を広く一望することができたように思う。まさに自分の学びたかったことなので楽しく受講することができた。

これからは、ゼロからつくるディープラーニングというこれまた定番の本を(研究費で)Getしたので、やっていきます。