プロクラシスト

今日の寄り道 明日の近道

【Loctek】オシャレで快適なデュアルディスプレイ!モニターアーム「D8D」レビュー

こんにちは!ほけきよです。

ブロガーやプログラマの皆さんは、自分のデスクにこだわりを持っている人も多いかと思います。

かくいう私も作業効率をUPさせるためデュアルディスプレイ*1なわけですが、やっぱり自分のデスク、スタイリッシュで効率的に行いたいですよね。

デスクを快適に使うことが出来るモニターアームを入手したので、レビューしていきます!

Loctek D8D

今回紹介するのはコチラ

ロックテックLoctek ガス圧式デュアルモニターアーム D8D

概要とポイント

  • デュアルディスプレイモニターアーム
  • 30インチまで対応
  • USBポート付き
  • 価格は14000円程度
  • 私は27インチディスプレイ*2を二枚使っているので、2枚とも取り付けられるこのタイプを選びました。

    開封の儀

    届いたので、開封してみます。

    中身を空けるとこんな感じ。一つ一つビニールで丁寧に梱包されています。

    梱包を取り外すと、こんな感じ。他の記事ではキズや汚れありと書かれているものもありましたので、少し心配でしたが、私のはキズなどはありませんでした。

    こうしてみると結構重厚感がありますね!

    組み立て・取り付け

    組み立て・取り付けですが、二人で行うほうが良いと思います。モニターアームが重いので、一人でも出来なくはないですが、そこそこ苦労しました。

    デスクへの取り付けはクランプタイプグロメットタイプの二種類あります

    クランプ グロメット
    方法 机の端で挟み込む 机に穴を空けて挿す
    特徴 簡単に取り付けられる しっかりと固定される
    クランプのほうが簡単に取り付けられるので、位置がはっきり決まっていないうちはクランプで固定でいいと思います。

    机に固定が終わると、モニターの装着です。モニターに付いているネジを一旦外して固定しましょう。

    モニター背部の幅が装着可能な幅かどうかは、予めチェックしておきましょう。

    装着すると、こんな感じ!とてもスッキリ!!

    D8Dモニターアームのいいところ

  • 省スペース
  • 自在に動く
  • 便利なUSBポート
  • 利用前と比べて、ディスプレイの土台がない分、かなりデスクの上がスッキリとしました。

    また、自在にディスプレイを動かせることで、いろんな使い方が出来ます。例えば、画面を90°回転も簡単に出来るので、コードを書くとき、文書を読むときなど、縦長のほうが良いときなどは重宝します!*3

    このアームの真ん中にUSBポートがあるのもうれしいですね。USBメモリを装着したり、充電をする時など、いちいちデスクトップ側のポートを使わなくても良くなりました。

    モニターアームのイマイチなトコロ

    一つだけ、イマイチな点は

    • 左右のディスプレイをくっつけるには奥行きが必要

    なところ。


    (上から見た図)

    こんな感じで、くっつけるためには結構な場所をとるので、奥行きが必要になります。 構造上仕方ないのですけどね。どうしてもディスプレイをくっつけたい人は、机の間を空けるか、奥行きの大きな机で利用しましょう。

    まとめ

    モニターアーム、組み立てがめんどそうだなと思って、入手してからしばらく放置していたのですが、意外と簡単に取り付けられました。 前からほしいと思っていたので個人的に、とても満足です。

    • ディスプレイを快適に動かしたい方
    • 机をスッキリさせたい方
    • 机の上をオシャレに見せたい方

    などは一度検討してみてはいかがでしょうか?

    無くても生きてはいけるけど、あったらデスク作業がますますはかどります!是非検討してみては!ではではっ

    ロックテックLoctek ガス圧式デュアルモニターアーム D8D

    *1:片方がだいたいYouTubeな事は内緒。

    *2:Dell ディスプレイ モニター P2717H/27 インチ/IPS/6ms/VGA,DP,HDMI/USBハブ/3年間保証

    *3:ちなみにWindows10では画面回転のショートカットがあって、Alt+Ctrl+方向キーで簡単に回転ができます。

    頑張れ受験生!受験直前にするべき7つのコト

    こんにちは、ほけきよです。

    そろそろ大学受験シーズンですね。 これまで一年間、成績に伸び悩んだ人、成績が急上昇した人。それぞれでしょう。

    それでも、明日1年間受ける人のほとんどが自分の意思でその道を選び、努力してきたと思います。 遊びたい気持ちを抑え、頑張ったと思います。目標に向かって努力する人はかっこいいですよね!

    そこで今日は、本番まであと少し、そういう時に何をすればいいかを自分の経験を踏まえ書いてみます。 受験直前期に大事なのは問題をときまくるよりもメンタルコントロールと、凡ミス撲滅です。

    どうすれば気持ちを整えられるか、自身を持って臨めるかをまとめました。

    多くの人が、自分の実力を出し切れることを祈っています!

    1. 忘れ物チェック

    • 受験票
    • 鉛筆、シャーペンと芯、消しゴム
    • 時計

    など、絶対に忘れられないものだけは、試験当日にバタつかないように、必要な物はきちんと前日までに用意しておきましょう。

    2. 親や友達など信頼できる味方に弱音をはいておく

    本当に最後の最後、どうしても心落ち着かないときは、信頼出来る人に弱音をそっと吐きましょう。 その人はあなたの一年間をちゃんと見ています。そういう人の言う「大丈夫」に、根拠もないのに案外救われたりします

    また、自分を少しでも下に見ている人・嫌いな人とは話さないでおきましょうね。「嫌いな人とも付き合う」のは社会に出てからでいい。大一番の前に心がざわつくことになります。臆病な自尊心で上等!プライドを傷つけられないようなるべく近寄らないようにしておきましょう。

    3. 絶対解ける問題を解く

    本当の直前の問題演習は、解ける問題の復習に当てましょう。

    この段階で問題を解くのは弱点を克服するためではありません、安心するためです。今までに習ったことを反芻しながら、解けるという自信をつけてから試験に臨みましょう。英単語などもおすすめです。

    4. 腹痛と風邪に注意、体調管理

    体調は集中力に影響するので、なるべく万全な体制で臨みたいですね。

    • いつも通りの睡眠時間
    • 加湿やマスクを忘れずに
    • 試験の3時間前には起床
    • 油物はあんまり食べない

    などなど。わたしは緊張でお腹を壊しやすかったので、直前期は梅干しのおにぎりをずっと食べてました。胃腸に良いらしいと聞いたので!笑

    5. ゲンを担ぐ

    自分が試験前に行うと上手くいくというジンクスなどがある人はそれをしましょう。わたしの場合、試験前にエナジードリンクを飲むです。今でも大一番の前には続けています。

    お守りも効果的です。神様のご利益もありますが、例えば人からもらったものなら、「あの人が応援してくれている」という安心した気持ちにつながると思います。

    6. 今までの参考書とノートを積み上げてみる

    「かなり/まあまあ頑張った」とかだと、イメージしづらいので、努力を定量してみてください。 勉強記録をつけている人なら、1年で何時間勉強したか、とか。

    私のオススメはこの参考書とノートを積み上げることです。一年間って、かなりの勉強と演習を積んでるんだ。となると思います。

    写真を撮ってトップ画にしておくと、お守り代わりになるかもしれません。

    7. 4月に大学生の自分をイメージ

    センター試験に不安で悩むぐらいなら、4月以降の受かった自分を想像しておきましょう。 進む大学、入るサークル、出会う運命の人、挫折を味わう日々、挫折を乗り越えた研究成果など。 イメージの力は強大です。強い想いが、必ず良い方向に導いてくれるでしょう。

    頑張れ受験生!

    受験で実力以上のものが出ることはまずないです。 本番に強い人というのは、実力通りの力を出せる人です。

    実力は1年間の努力分。あとは集中力や緊張、体調などの要素次第です。 今まで通りの力を出し切れるよう、頑張ってください!応援しています。

    2017年の振り返りと2018年のテーマ

    こんにちは、ほけきよです。

    ちょっとアドベントカレンダーで燃え尽きていた&プライベートでバタバタしていたもので、更新が滞っていました。 新年一発目ということで、去年の振り返りと今年の目標的なものを。

    2017年の振り返り

    年が明けました。皆様今年もよろしくお願いします。 昨年は「放」をテーマにしていました。 自分自身を変え、新たな挑戦をどんどんして行くという目標は、ある程度達成できたと思っています。

    ブログでいえば、『技術×情報発信』ということで、プラグイン作ったり、自動記事作ったり、アドベントカレンダーしたり、色々しました。 この辺ふりかえって見ると、なんか楽しそうだな自分、、、という気になります。笑

    どれも楽しそうなので、覗いてみてください!

    また、オフ会に結構参加しました。こうやってブログを通じてたくさんの人と価値観に触れられたのは、自分の今後を考えるいい機会となりました。

    去年1年の教訓は

    • 特に必死で頑張っているときに出来た繋がりは、良縁なことが多い
    • 運がいいというのは、行き当たりばったりではなく、チャンスを掴める準備をすること
    • 自分の過去の意思決定を振り返ると、結構自分の価値基準や行動理念が見えてくる

    特に最後。結構やりたいことなんか無くて、適当に生きてると思ってたんですけど、案外一貫した基準があるんですよねー。私の価値基準は2つ

    • その選択が、振り返ったときに失敗しても「面白い」と思えるか
    • 自分が取りうる最大の難易度の場所か

    はっきりとした目標がない人、結構いると思いますが、振り返って見ると案外知らない自分がわかるかもですよ。

    2018年のテーマ:『届』

    今年は去年とまた環境がガラリと変わりました。

    今年のテーマはです。

    • 言葉を届ける : 英会話・マネジメント・プレゼン
    • 文章を届ける : 記事、執筆
    • サービスを届ける : webアプリケーション

    とかかな。ウェブアプリとか作って一発当てたい気もする。。。笑 *1

    人に言葉、文章、サービスを「届ける」ことを意識して仕事も趣味もブログも頑張ります。

    皆さんに面白いと思ってもらえるコンテンツを届けられるよう、またいろいろとネタを仕込んでいきますので、本年もプロクラシストをよろしくお願いします!

    *1:もちろん、技術メモについても引き続き書いていく予定です!

    知識0だった僕がデータ分析をこれまでどう学び、これからどう使うのか

    f:id:imslotter:20171225203840p:plain

    長かったデータ分析ガチ勉強カレンダーも最終日*1

    自分のこれまで歩いてきた道を軽く振り返ったあと、自分が思う機械学習/データ分析のあり方について書き連ねたいと思う。あくまで一つの価値観として楽しんでもらえればと思います。

    データ分析って何?状態から

    データ分析業務を行うにあたって、まずはじめの難関は、言葉の壁だった。ほぼコンピュータと無縁の世界で生きてきた私は、「Linuxって何?Vimって何?」っていうのを毎日繰り返していた。

    データ分析を実務で扱うには、アルゴリズムを知っているだけじゃどうしようもない。 列挙すると下記のようなものが必要になってくる*2

    • アルゴリズムを動かすプログラム、用意する環境(Linux, VM, サーバーなど)
    • サーバーでコードを動かすための知識、ネットワークの知識
    • 計算量の見積もり、高速に動かすための並列化技術
    • データのin/outを扱うDBやqueueのシステム
    • プログラムの死活を監視するシステム
    • 分析アルゴリズムの理解
    • 複数の処理に対応するトランザクションの知識
    • サービスとして提供するアプリケーションの知識
    • 複数人で開発を進めていくプロジェクト管理技術

    などなど。。。今だからこそ、そこそこ俯瞰的に見られるようになってきたが、はじめはまるで言葉が分からなかった。

    じゃあ、どうやって知識を獲得していったのか。 自分が意識的にやってたことを振り返ってみる。

    やったこと

    わからないところを聞くレベルに達するまで

    はじめは、どこが分からないかすら分からない状態。質問しろといわれても質問できない。だから、下記のことを行っていた。

    • ひたすら単語をメモ帳にメモしまくって、ググる。飲み会の間も分からない単語はメモしてた。調べるたびに分からない単語が増えるけど、耐えるしかない。辛抱強くメモ
    • その道のもっとも簡単な本を専門家に聞くサルでもわかるようなやつ。
    • 染み付くまで訓練を重ねる。一朝一夕でコマンドは打てるようにならない。Linuxコマンドなどは、lsさえ知らなかったので、無意識に基本コマンドが打てるようになるまで体に叩き込んだ。

    そうすれば、ぼやっと聞きたいことくらいはわかるようになってきた。

    わからないところが分かるようになると

    ある程度のことが分かるようになると、このあたりから少しずつ楽しくなってくる。こういうときには、以下のことを意識していた。

    • 人に聞きまくる。わからないことだけじゃなくて、わかったことが正しいかの確認も込めて聞く。
    • 詳しい人が実際にコードを書いたり、デバッグしている過程をよく観察する。結果としての物よりも、過程に知見が詰まっていることが多い。ショートカットの使い方だとか、バグ取りにつかっているコマンドとか。とにかく、観察して、盗む
    • 知っている範囲内の言葉で説明ができないか試みる。「これはつまり~~ってことだな。」と、自分の言葉で納得するまで考える。
    • 複雑な要素は根気強くほどく。世の中の大半が実は難しくなくて、簡単な要素がたくさん組み合わさっていて難しく見えているだけ。
    • 訓練を重ねる。自分がやっていることは大したことではないと思えるレベルまで、理解と実装を重ねる。

    とにかく、自分の言葉で説明できるっていうのに重きを置いていたように思う。あとはやっぱり、ひたすら手と頭を動かした。

    アルゴリズムをどう理解したか。

    物理出身ということもあって、数式の理解には少し自信があった。なのでアルゴリズムの理解はいろいろな技術領域の中でも自分の強みとしたかった。

    • 大事な理論は数式レベルで理解する。基礎的な理解は低レイヤーでの思わぬつながりを産み、未知の状況に対する応用のロバスト性**が高いように感じる。ここの式をこういじれば...みたいなイメージができるようになると強い。
    • 実装はデータのinput/outputを重要視する。特にディープラーニングにおいては、ここはベクトルで入っているのか?それともスカラーなのか?はたまたテンソルかもしれない...それをうやむやにすると魔法の箱化してしまう。あくまで演算にすぎないという意識を持つ。
    • アルゴリズム既存のものとの差分を意識する。何が変わったのか(精度向上、次元拡張、スピードアップ、対象拡大)、どうやって変えたのか(システムレベル、アルゴリズムレベル)などを意識して読む。

    この中でも一番意識したいのは、魔法の箱じゃなくて、計算を行っているに過ぎないということ。だから、どういう計算過程なのかを強く意識した。そうすることで、何が出来て何が出来ないかがぼんやりと分かる。

    自分が思う、これからのデータ分析

    今まで分析業務に従事したり、一ヶ月間ガチで勉強してきたデータ分析を実務で使うものとしての視点で書く。

    良いデータが集まるところに価値が生まれる

    データ分析は料理みたいなものだと思う

    • データは食材、前処理は調味料、アルゴリズムは調理器具。
    • アルゴリズムはすぐに汎用化される。arXivにあげられた論文が1週間後にはgithub上で誰かが上げられている状況。
    • 調理器具の使い方をいち早く理解すること、元となるおいしい食材を集めるところが最重要課題。

    つまり、データが集まるプラットフォームを作れるかどうかが今後のデータビジネスのカギとなってくると思う。メルカリとかお見合いアプリとか理想的だと思っている。人の心理をデータによって数値化できる基盤が整っている。特にスタートアップなどは、真似できないようなデータ収集プラットフォームをどうつくるか、ここに大きな労力を割くべきではないのかと思っている。

    実務のデータ分析は高い精度よりも低コストと高い説明能力

    現場において、ディープラーニングを果たして使うのか?というと、難しいのではと想像する。

    • 失敗原因がわからない怖さ
    • コストと納期の関係

    が原因。実際データサイエンティストの泥臭いフィーチャーエンジニアリングの過程は、それ自体に価値があったりする。だからこそ現場の最前線でロジスティック回帰*3が用いられる。一方で分からないけどいい結果というのは、なによりもクライアントの不安を増長する恐れもある。

    でも、だからといって、ディープラーニングが使われないのは、あまりにもったいなさ過ぎる。 あれだけの精度をわけも分からなく産めるものを、今後実務で使うためには、結果を説明出来る技術が必要だと思う。 機械学習の意味付けの研究はこれから実務的にも重要で、発展していくのではないかと思う。*4

    データ分析はトップダウン

    物理をやっていたものからすると、ボトムアップ的アプローチも利用していきたいものである。

    • データから推論できること、出来ないことをはっきりさせる
    • システムの隠れた状態などをうまくモデリング出来たら、強い
    • トップダウン的に分析し、ボトムアップ的に仮説を立てて実験をすることで、より本質的な理解となる

    と思っている。 大量のデータがあって、それを魔法の箱に突っ込めがなんかしらの良い結果が出る時代にはなってきている。 しかし、データに頼りすぎず、どこが本質的に重要かをミクロな観点から見極めながら、分析できる能力は身につけておきたい。

    あくまで人間の補助、人間とのシナジーを考える

    最後に、私はあまり人間が得意なことを機械でやらせようとは思わない。 そういうことに労力を割くよりは、機械が得意な領域を磨いていくほうが、生産性が高いと思っている。

    意思決定、連想、ばかみたいな発想、人との関わり。こういうのは人間が得意とするところだろう。 データ分析はこれを最大化する方向に利用したい。

    • 自動化できるところ、自動化出来ないトコロを明確に
    • 事務作業は自動化で良い。サービス的な要素は消えない。
    • 職人が自発的にひねり出したアイディアは、独創的で面白い

    まとめ

    とりとめもなく終わりますが、これが数年間データ分析技術を学んで、また現場で実践して考えているところです。 自分が数年後道を見失ったときに読み返せるようにと、書いてみました。

    技術の進歩は著しく、データ分析の技術はこれからますます楽しみになっていきます。 それについていけるようこれからも精進していきたいと思っています。

    これまでのアドベントカレンダーをマージして、ゼロからデータ分析を学べるようなサイトマップを作りました。

    データ分析に興味を持った方は、コチラで勉強してみてはいかがでしょうか。ではでは。

    *1:ながかった、、、ガチだった。。。

    *2:レベル感のばらつきはお許し下さい

    *3:回帰の最も簡単な手法

    *4:発展していって欲しい。

    Pythonでゼロから機械学習/データ分析を学ぶためのサイトマップ

    f:id:imslotter:20171224195620p:plain

    データ分析ガチ勉強アドベントカレンダー 24日目。

    当サイトでも、Pythonを使ったデータ分析や機械学習について、勉強しながらそれをアウトプットとして出すと言うかたちで、何個も記事を書いてきました。 記事数で言えば50とかそのくらいあるような気がします。

    カレンダーも完成しつつあるので、個々では当サイトの総まとめとして、機械学習やデータ分析に触れたいという人がゼロから始めて触れられるように、記事をまとめていきたいと思います。 何か面白いことを勉強したい学生、就職までの勉強に、急に機械学習を使わなければならない社会人方々は、読んで見てください。

    0. 環境構築

    まずは何と言っても環境構築。Pythonは他の言語に比べて構築が簡単な方だとは思いますが、ここでかなり苦戦する人が多いです。

    0.1. Pythonの導入 (Anaconda)

    当サイトではWindowsでも環境構築が簡単に出来るように記事を書いています *1*2。全くゼロから始める方はコチラをどうぞ。

    0.2. エディタ (Pycharm/VSCode)

    いわゆる高機能メモ帳。実際にコードを書き始めると、自分好みのエディタが欲しくなるものです。当サイトでは、PythonならPycharmを、またオールラウンドに使えるエディタとしてVSCodeを紹介しています。

    0.3. バージョン管理 (Git)

    (※あれば便利ですが無くてもコードは書けるので、面倒な方は飛ばしてもらってOKです。)

    賢くコードを管理する仕組みです。ちょっと試したいことがあるだけなのに、コードを一部変更して、そのご間違って保存したりすると悲しいですよね。 そんなことがないように、しっかりと自分の作ったコードのバージョン管理しましょう。Gitの基本的な使い方はこちら

    また、当サイトのGithubアカウントはコチラです。

    github.com

    作ったおもちゃや勉強の様子を保管しているので、よろしければぜひ。

    1. Pythonの使い方(基本ライブラリ)

    環境が作れたら、いよいよコードを書いていきます。 Pythonライブラリが充実しているので、それらを使いながらコードを書いていきます。 機械学習専用のライブラリもあるのですが、まず必ず入れておくべきライブラリであるnumpy, matplotlib, pandas, jupyterの使い方を紹介しています。

    1.1. 数値計算 : numpy

    これを用いることで面倒な基本計算(平均計算、行列計算、etc...)を一行で書けるようになります。スゴい!

    1.2. 表計算/統計処理 : pandas

    Pythonで表を読み込んだり、計算したり、また表として書き出したりするにはpandasがとても便利。 少し使い方にクセがありますが、かなり強力なので、是非身につけておきたいものです。

    1.3. グラフ描画 : matplotlib

    データ分析をしていると、結果をグラフで可視化したいということが多くあります。 そういうときにはmatplotlib. これ一つで色々なグラフを書くことが出来ます。

    また、よりオシャレなグラフを作りたい方向けに、KibanaとElasticsearchで可視化する方法も書いています。この場合は、Python以外の知識も必要です。

    1.4. インタラクティブなコード実行 jupyter

    jupyterの良い点はちょっとずつコードを書きながら試すことが出来るというところです。 コード書いて、コンパイルして、実行...を短いサイクルで回すイメージ。 同時にメモも残せるので、研究や実験に最適です。

    2. データ分析事始め

    Pythonがある程度使えるようになったら、データ分析/機械学習のお勉強です。

    その際に参考になる本やサイト、ライブラリなどをざっと洗い出した記事がありますので、リファレンス代わりにしていただければなと思います。

    3. データ分析の流れ

    ここから、実際に機械学習を交えながら、データ分析を進めます。

    実務では、下図のようにデータ分析を進めていくのですが、その流れを、sklearnを使いながら説明していきます。

    3.1 データを集める

    まず、データを集めないといけません。 モデル/アルゴリズムの性能を調べたいときに、sklearnはいろいろなデータを予め用意してくれています。

    また、情報を集めたいときはスクレイピング/クローリングなどの技術が必要です。 beautifulsoupを使ったり、公開APIを使うなどして、データを集めましょう。

    3.2 データ分析の流れ

    4. 時系列データ

    時間依存のあるデータはそうでないデータに対して、少し扱いが面倒だったりします。 けれど、扱うことも多いので、まとめています。時系列に関する基礎的なまとめから、ディープラーニングに至るまで、まとまってますので、読んでみてください。

    6. 深層学習

    最近界隈を賑わせているディープラーニングに触れない訳にはいかないでしょう。 当サイトでは、KerasとPyTorchの2つに絞って、その使い方について説明しています。

    6.1 自作

    ライブラリを使う前に、ディープラーニングのココロを知るため、まずはPythonで自作しました。

    1から書くと、どういう思想でネットワークが組まれているのかとか、学習の仕組みなどが分かるようになります。

    6.2. Keras

    とっつきやすさでは随一のKeras。簡単なデータ分析に使うにはこれで十分だと思います。ディープラーニングなんて知らなくても使えるそのお手軽さはスゴい。

    6.3 PyTorch

    研究者界隈で盛り上がりを見せているPyTorch。すこしコード記述量は増えますが、Define by Runの設計しそうなので、かなり柔軟な設計が可能。 更に、Sklearnとの連携で、より使いやすくなります。各ライブラリとの比較も書いていますので、是非ご一読を。

    7. 教師なし学習(異常検知/次元削減など)

    上記までが、正解データのラベルに従って学習を進めていく教師あり学習です。 実際の現場では正解データを使わないタスクも多くあります。

    異常検知*3や、座標を変換する空間変換など、正解データという概念が無いようなものに対してもまとめましたので、必要な方はどうぞ。

    8. 強化学習

    強化学習は、教師あり学習とも教師なし学習とも違います。

    実験して、その結果が帰ってきて、学習してまた実験する。

    そのようなまるで人間のような学習の方法です。定式化が出来ない複雑な状況などに応用が期待されており、 実際にマーケティングの広告の配置などに使われたりしています。

    9. 実際にデータ分析をしている記事

    当サイトでは、実際に分析を行った記事をいくつか載せています。

    そこまで高度なことはしていませんが、記事からデータ分析から分かること、データ分析のちからを感じてもらえればと思います。

    まとめ

    いかがでしたか。かなりいろいろなことをやっていたので、一つにまとめました

    今回のアドベントカレンダーは、この記事の順番を意識して進めてきました。その流れで勉強していくと、割とスムーズに進められるのではないでしょうか。

    データ分析業界が盛り上がっているので、これを機に一念発起して勉強したい方なども、ぜひご参考ください。ではでは!

    *1:MacLinuxは環境構築方法をWebで漁れば簡単に出て来るし、またハマりどころもそんなに多くないので、ぐぐってみてください。

    *2:機械学習ライブラリによっては、どうしてもwindowsで出来ないものもあります。

    *3:厳密に言えば教師のある異常検知もあります。

    【Day-23】機械学習で使う"距離"や"空間"をまとめてみた

    f:id:imslotter:20171223191319p:plain

    データ分析ガチ勉強アドベントカレンダー 23日目。

    ここまでデータをどういう風に処理したり、どういうタスクをこなしていくかについて勉強してきたが、 一度基礎的な事項に戻ってみたいと思う。基礎だから簡単というわけではない。基礎だからこそ難しく、また本質的な内容

    データ分析で使われている手法などをまとめて集約して、簡単な説明を付け加えていく。 しかし、このあたりの数学*1は苦手なので、なるべく直感的に自分のイメージを書いていく。

    われわれが生きている空間や、距離は"正しい"のか

    "正しい"というのは、データ分析に使うのに適切なのか。という意味で書いている。 たとえば、新宿まで1.2km"というような表示を見る。地球という座標空間の中で、新宿までの距離が1.2kmというわけだ。われわれは日常生活の中で、それに対して何の疑問も抱かない。それは、日常の距離はユークリッド空間が 大前提にあるからである。

    ユークリッド空間/ユークリッド距離

    簡単に言うと、高校まで*2われわれが生きてきた空間である。たとえば、(0,0)から(3,4)までの距離は?ときかれると、大体の人は三平方の定理だ!となって、5という数字が思い浮かぶ。

    けれど、下図を見てほしい。空間が必ずしもx,yの直交座標であらわされるわけではない。厳密に言うと、地球は丸いので、曲がった空間での距離を求めるべきなのである。また、距離の測り方だってバリエーションがあっていいはずだ。 ユークリッド距離といえば、斜辺の距離と思いがちだが、たとえば街などは、斜めに横切れないことだってあるので、かくかくと進んでいくことを前提に距離を測ったりする*3。このように状況によって空間や測りかたは変わるべきなのである。

    データ分析とは、いろいろなジャンル/いろいろなタスクがあるわけで、それが本当にユークリッド空間/ユークリッド距離で考えるべき話題なのかどうかというのは、考えておくべき問題なのである。 非常に根本的な話であるだけに、きれいな空間や距離で解けたものは美しく、汎用性がある。

    点の距離

    Name 名前 備考(あれば)
    Euclid ユークリッド \sqrt{ \sum_{i}^{n} {\left(x_{1i}-x_{2i}\right)^{2}} } 一般的な距離
    Manhattan マンハッタン \sum_{i}^{n} |x_{1i}-x_{2i}| 外れ値の影響を受けにくい
    Minkowski ミンコフスキー \left(\sum_{i}^{n}{|x_{1i}-x_{2i}|^{p}}\right)^{1/p} Euclid, Manhattan, Chebyshevを一般化したもの
    Chebyshev チェビシフ \max_{i}|x_{1i}-x_{2i}| 成分の差がもっとも大きい次元だけを抽出している
    Mahalanobis マハラノビス \sqrt{\mathbf{ \left( x_{1}-\bar{x} \right)^{T} S^{-1}  \left(x_{2}-\bar{x}\right)}} 正規分布の共分散の形にあわせて算出する距離。よく使う
    Hellinger ヘリンジャー \sqrt{ \sum_{i}^{n} {\left(\sqrt{x_{1i}}-\sqrt{x_{2i}}\right)^{2}} } 外れ地の影響を受けにくいの
    Hamming ハミング dim(\mathbf{x})-\sum_{i}^{n}\delta\left( x_{1i},x_{2i} \right) ベクトルの要素中で一致していない素数。カテゴリ変数に利用

    分布の距離

    分布の距離というときにもいろいろな距離/距離尺度がある。厳密には距離の公理(非負性・同じ点なら0・対称性・三角不等式が成り立つ)*4を満たしていないものもあり、それらは距離とはいえないが、差をあらわすものとしてよく使われるものなので、距離尺度として用いられる。

    名前 備考(あれば)
    Histogram Intersection D_{HI}(p,q) = \sum_i \mathrm{min}(p,q) (距離じゃなくて類似度)ヒストグラムのような離散値に使う。2つの分布の共通領域。
    KL divergence D_{KL}(p||q) = \int_{-\infty}^{\infty}p(x)\log{\frac{p(x)}{q(x)}}dx 相対エントロピーの概念に基づいて、2分布間の距離を算出(非対称)
    JS divergence m(x) = \frac{p(x)+q(x)}{2}
     D_{JS}(p,q) = \frac{D_{KL}(p||m)+D_{KL}(p||m)}{2}
    KLを改良して**p,qに対称性をもたせたもの
    L1 norm D_{L1}(p,q) = \int_{\infty}^{\infty}|p-q|dx 連続的な分布における誤差の絶対値の和
    L2 norm D_{L1}(p,q) = \int_{\infty}^{\infty}(p-q)^2dx 連続的な分布における二乗誤差の和
    Wasserstein distance W_p(\mu, \nu)=\left( \inf_{\gamma\in \Gamma \left(\mu,\nu\right)} \int_{M\times M} d(x,y)^{p}d\gamma(x,y) \right)^{1/p} 分布を荷物量とみなし、荷物を他の分布に移しかえるときにかかるコスト

    それぞれの違いの実装をgithubにあげておく(day23)

    github.com

    wasserstein計量

    物理では昔からある輸送距離だが、WGANの登場により、分布の距離表現として注目される様になってきた。

    • 輸送コスト最小化問題を解いた場合の最小の輸送コスト
    • 最小コストをいちいち計算するため、計算時間はめちゃくちゃかかるが、その分物理的にも本質的な距離になっている。
    • 実装にはPOTというライブラリを使う(Optimal Transportation)github
    pip install Cython
    pip install POT

    カーネル(再生核ヒルベルト空間)

    非線形の問題を扱うものとしては、かなり伝統的な手法。数式を抜いて文字だけで説明するとこんな感じ

    • 線形の特徴量x_1,x_2を組み合わせて、非線形な特徴量を作りたい。
    • こんな特徴量の組み合わせは無数にある(例:x_{1}^2, x_1x_2,...,x_{1}^{4}x_{2}^{3},...)
      • 多いほど非線形性は高まるが、組み合わせが膨大
    • カーネル関数を使うと、無限次元の特徴ベクトルを用いているのと等価*6
    • でも、計算量は無限じゃなくて、データ数に依存する*7
    • 一般的化線形モデルは、カーネル関数によって書き換えることが出来るので、データ数に依存する形で非線形を学習できる

    というわけで、データ数分の計算量で、無限次元空間の学習が出来るって感じ。 注意としては、入力するデータ数が多くなると、計算が厳しくなる(データ数×データ数の逆行列を解く)

    以下、わかりやすい&数式もきちんと載っている説明。

    Topological Data Analysis(TDA)

    • データを点群として扱うのでなく、データの持つ幾何学的な情報に基づいて識別や分類を行う
    • Persistent Homologyという分野
    • 点群の幾何学的な情報を抽出した二次元座標上の点集合(Persistence diagram)を得る
    f:id:imslotter:20171223123208p:plain
    persistent homologyの生成元の発生と消滅のイメージ
    f:id:imslotter:20171223123233p:plain
    上図のように円を広げていき、発生の時刻と消滅の時刻を2次元プロットにしたのがpersistent diagram

    以下、わかりやすい説明と論文

    次元削減/Embedding

    特徴量が非常に多い場合、その特徴量全てがデータとして重要かどうかは微妙。 特徴量を重要な部分だけ抽出したり(Dimension Reduction) 相性の良い空間へ今ある雑多なデータを埋め込んだり(Embedding)することが多い。以下は主要/有望な手法と簡単な説明、文献を列挙する(随時更新)

    PCA(principal component analysis)

    典型的な次元削減の方法。次元を落としても情報をなるべく落とさないような軸を計算で求める。

    ちなみに、AutoEncoderはPCAの純粋な拡張になりうることが数学的に証明できる *8

    t-SNE(t-Distributed Stochastic Neighbor Embedding)

    PCAが点だけを見るのに対し、t-SNEは分布単位で見る。圧縮前と圧縮後の確率分布のKLダイバージェンスを最小化することにより求める。

    f:id:imslotter:20171223125426p:plain
    [t-SNEの仕組み(ALBERT)](https://blog.albert2005.co.jp/2015/12/02/tsne/)より引用

    Word2Vec

    CBoW(Continuous Bag-of-Words)を用いて、文脈中の単語から対象単語が現れる条件付き確率を最大化するように学習を進めていく。

    そうすることで、単語を座標空間上に埋め込むことができる。 これによって、言葉の足し算引き算ができる可能性が拓けた。

    f:id:imslotter:20171223191909p:plain
    男女間の関係が近い値のベクトルで表現される(参考記事より画像を引用)

    最近では、word2vecだけではなくdoc2vecなどもあり、ますます応用可能性が増している。

    Poincare Embeddings

    Word2Vecの空間改良版といったところ。双曲空間にデータを埋め込むことで、

    • 階層構造/木構造を自然に空間の中に埋め込める。そういう構造のデータに良い。
    • リッチな空間表現のため、元の次元を減らすことも出来る
    • 空間に少しの補正を加えるだけで使えるので、拡張が容易

    な点などから、注目されている。双曲空間というのは、下図真中のような、曲がった空間。外に行くほど密になっている(=空間が広い)

    f:id:imslotter:20171223192945p:plain
    [Fig]双曲空間。場所によって距離尺度が変わる

    実際、単語は階層構造をなすことが多く、下図の結果のように、空間上に効率よく単語を配置することができる。

    f:id:imslotter:20171223193551p:plain
    [Fig] 論文の実験結果、ハブと周辺語の階層関係が表せている

    Wasserstein Embeddings

    この前読んだ論文が、Wasserstein空間が作る距離上の空間に埋め込むというものだった。

    LEARNING WASSERSTEIN EMBEDDINGS

    まとめると

    • wassersteinは計量として優秀。分布の差をうまく表す。
    • でも計算重い。だいたい次元の3乗の計算量
    • うまく近似する関数をディープラーニングで作ろう
    • 近似にはSiamese networkが有効そうだから学習して関数を作る
    • うまく近似できた。理論的裏づけが課題。

    使ったのはSiamese network。距離学習によく使われる。

    f:id:imslotter:20171223194521p:plain

    2つのネットワーク\phi,\psiを用意して、パラメータの更新は

    • \phiで変換されたベクトル同士のの二乗誤差と、Wasserstein距離の差を近づけるように
    • \psi\phi(x)xの誤差(再構成誤差)を小さくするように

    行う。今後、リッチな空間で、計算量がネックになる場合は、このようにニューラルネット空間の計量を近似するような手法が主流になるかもしれない*9

    まとめ

    今日は、かなり基礎的な内容になった。 個人的には、このレベルでの新しいアルゴリズムが今後出てくるのではないのかなと思っている。基礎的なところからの変更は、ドラスティックな変革を引き起こすことが多いので。今後も随時追っていきたいと思う。

    いよいよあと2日。明日は、これで本サイトで書いてきたデータ分析/機械学習に関する内容を総まとめしたいと思う。必見です!ではでは。

    *1:空間、計量、測度論...ムリ...

    *2:極座標を除く

    *3:マンハッタン距離

    *4:長くなるので割愛。詳しくはこちら

    *5:物理用語ではこういう。

    *6:証明

    *7:リプリゼンタ定理という

    *8:深層学習 (機械学習プロフェッショナルシリーズ)などを参照

    *9:と、個人的に注目している

    【Day-22】データ分析技術で仮想通貨の暴騰・暴落を捉えられるか

    f:id:imslotter:20171222012923p:plain

    データ分析ガチ勉強アドベントカレンダー 22日目。

    今日は、データ分析の練習も兼ねて、ちょっとした実験!! 対象は最近話題の仮想通貨。 乱高下の激しい通貨に対して、データ分析技術がどこまで通用するかと言うのを検証してみる。

    使う技術 : Change Finder

    change finder とは、データマイニングによる異常検知に出てくる、変化検知の技術。

    ざっくりいうと、データをある時系列モデルで予測し、そこからの変化具合を評価する手法

    全体の流れ

    1. 窓幅kで時系列モデル(ARモデル)を用意してSDARアルゴリズム(忘却型学習アルゴリズム)で学習する
    2. 上記の時系列モデルp_{t-1}に対して、時刻tでの異常値スコアを次のように算出
      • Score(x_{t})=-\ln{p_{t-1}(x_{t}})
      • もしくはヘリンジャースコア(参考)
    3. 幅Tのウィンドウを設けて、スコアの平均を計算する(smoothing)
    4. 平滑化された時系列データy_{t}に対して、再度ARモデルを用意してSDARアルゴリズムで学習する
      • 時刻t-kからt-1までの値で、それ以降の時系列を予測するモデルq_{t}が完成する
      • T'のウィンドウを設けて、スコアの平均を計算する(下式)
      • Score(x_{t})= \frac{1}{T'}\sum_{i=t-T'+1}^{t}\left(-\ln{q_{t-1}(y_{t}})\right)

    ポイントは、2回学習しているところ。一回目のsmoothingで、ノイズに反応した外れ値の除去を行っている。 そのため、本質的な変動を捉えられるようになっている。

    SDARで設定する忘却パラメータはかなり大事で、どのくらい過去の影響を重視するかに関わってくる。これについては後で見てみる。

    ライブラリ

    何気なく「changefinder python」で調べると、作っている素晴らしい人がいた。

    changefinder - Argmax.jp

    なので拝借。上記ページにも書かれているように、numpy, scipy, nose, statsmodelsは必要

    pip install changefinder

    で入る。二種類のアルゴリズムが用意されていて、通常のChangeFinderと、ARモデルをARIMAモデルに変更したChangeFinderARIMA *1

    ChangeFinder

    changefinder.ChangeFinder(r=0.5,order=1, smooth=7)

    主要パラメータは下記の通り

    • r : 忘却パラメータ
    • smooth : 外れ値スコアをsmoothingするための区間
    • order : 時系列モデルの次数

    実験に使うデータ

    • 12/13-12/21の仮想通貨の価格データ ((githubcoindata.csvに保管している))
    • 草コインも含めて868銘柄のデータを10分おきに保管している

    データの集め方については以前記事にしたAPIを使っている。

    コード

    詳しくは、githubに上げている。 github.com

    銘柄を指定し、changefinderにかけてグラフ表示するまで

    コードをみる
    %matplotlib inline
    import changefinder
    import pandas as pd 
    from datetime import datetime as dt
    import matplotlib.pyplot as plt
    import numpy as np
    import os
    
    
    def str2datetime(tstr):
        if tstr.__class__.__name__ == "datetime":
            return tstr
        ts = tstr.split(".")[0]
        return dt.strptime(ts, "%Y-%m-%d %H:%M:%S")
    
    def calc_cf(name, df, cf, threshold=30):
        values = df[name].values
        scores = np.array([cf.update(value) for value in values])
        print(scores)
        # 描画
        fig, ax1 = plt.subplots(figsize=(15,5))
        ax1.set_title(name)
        ax1.plot(df.index, scores,color="red")
        ax1.set_ylabel("anom_score")
        ax2 = ax1.twinx()  # 2つのプロットを関連付ける
        ax2.plot(df.index, df[name].values)
        ax2.set_ylabel("value")
        # しきい値越えリスト
        df["score"] = scores - threshold
        for i in range(1,len(df)):
            if df.iloc[i-1]["score"] < 0 and df.iloc[i]["score"] >= 0:
                print("time:{}".format(df.iloc[i]["timestamp"]))
                ax2.plot(df.index[i],df.iloc[i][name],"o")
        plt.show()
        return df
    
    cf = changefinder.ChangeFinder(r=0.01, order=1, smooth=3)
    df = pd.read_csv("coindata.csv").dropna()
    df.index = df.timestamp.apply(str2datetime)
    calc_cf(name="btc",df=df, cf=cf, threshold=15)
    

    実行結果

    r=0.01, order=1, smooth=3 で実行してみた。結果がコチラ

    ふむ、一見よく捉えられているようにも見える。 でも、実際はそんなに簡単じゃない

    パラメータによる違い。

    r=0.01, 0.02, r=0.05で試してみる。結果は↓

    r グラフ
    0.01
    0.02
    0.05

    忘却パラメータに関しては、与えるパラメータによってかなり変わってくる。 センシティブなので、ナゾの場所で変化検知する場合もあり、シビアな調整が必要そうだ。

    また、r=0.01, order=1は固定で、smoothを3と18で比べてみた。

    smoothing グラフ
    3
    18

    やはり平滑化をしすぎると、反応は遅れるのだなという感じ。しかし、結構変化に敏感に反応はできているという印象を受けた。

    注意したいのが、グラフの縦軸は全然値が変わっているところ。この辺のしきい値の調整もシビアそう。

    結論

    暴騰暴落を捉えられたか?

    • 正直微妙
    • ピークが捉えられたとして、少し反応が遅れると暴落に飲み込まれる
    • 後述するパラメータ調整がシビアすぎる印象

    って感じ。正直、強いトレンドを見るならボリンジャーバンドでいいのでは?って思った。 そう思って、ボリンジャーバンドでもトレンド検知をしてみた。結果がこれ(赤が買いトレンド、青が売りトレンド)

    若干ミスってはいるものの、トレンドを割と追従できてる気がする。真ん中の2点は要らないけど、超安定してたから仕方ない気もする。sigmaの絶対値でしきい値設ければ弾けそう。 これもパラメータ調整が難儀ではあるが、changefinderよりも直感的になので、やりやすそう。

    モデルに関して

    • 特に忘却係数の調整がシビア
    • 基本的に反応は早めだが、smoothing次第で遅れる。ノイズとの兼ね合い
    • スコアもパラメータによって変わるので、相対的な判断が強いられる

    あたりが難しそうだなと思ったところ。探索的に調べたが、なかなか直感にバシッと合うようなものは見つけられなかった。 パラメータの調整方法としては、Day15で書いたベイズ的最適化を使ってやってみるのも面白いと思うので、もうちょっと良いパラメータを見つけたいトコロ。

    *1:ARIMAは計算が重い&非定常な時系列に対して時間窓を区切ってARIMAモデルを独立に作成しているので、モデルの妥当性は不明とのこと。

    【Day-21】統計的異常検知/変化検知の基本をまとめる

    f:id:imslotter:20171221005033p:plain

    データ分析ガチ勉強アドベントカレンダー 21日目。

    世の中のデータ分析のニーズは、何らかの異常を発見したいというところに多くある。 機械で言えば故障を検知する、マーケティングで言えば流行を発見する、株価で言えば相場変動を見つける...

    普通と違うことを発見する技術、それが「異常検知/変化点検知」 今回は下記二点の本を参考にしながら、異常検知とは何か?変化点検知とは何か?をぎゅっとまとめる

    データマイニングによる異常検知

    データマイニングによる異常検知

    異常検知と変化検知 (機械学習プロフェッショナルシリーズ)

    異常検知と変化検知 (機械学習プロフェッショナルシリーズ)

    異常検知と変化検知

    データマイニングによる異常検知では、確率モデルの違いに重きをおいて異常検知を分類している。

    機能 入力対象 確率モデル 検出対象 応用
    外れ値検知 多次元ベクトル 独立モデル
    (ガウス混合分布、ヒストグラム)
    外れ値 不正検出
    故障検知
    変化点検出 多次元時系列 時系列モデル
    ARモデル等
    時系列の急激変化 攻撃検出
    障害予兆検出
    異常行動検出 セッション時系列 行動モデル
    隠れマルコフモデル
    異常行動パタン なりすまし検出
    不審行動検出

    異常検知と変化検知では、データの性質から異常検知を分類している。下図のように

    • (左上)ほかと比べて値が異なる(外れ値)
    • (右上)前後の時系列と比べて値が異なる(時系列的外れ値)
    • (左下)振る舞いが変化している(変化点)
    • (右下)外れ値と変化点が同時に起きている(異常部位検出)

    f:id:imslotter:20171221040958p:plain

    タスクによって、使うアルゴリズムも変わってくる。

    『統計的』異常検知とは

    統計的 = データが裏で、ある確率分布で動いていることを仮定

    もうすこし噛み砕いて言うと、

    1. 自分が観測した情報から、"このシステムはこういう動き方をする"というのを統計的に推測する
    2. 統計的な推測から、どのくらいずれているかを統計的に算出する。

    学生時代を思い出してみる。みんなの平均点が30点なのに、一人だけ100点だったらヤバい。なぜヤバいのか。それを論理的に説明するために、 平均点周りで点数がイイ感じに散らばっているという仮定を置く。イイ感じの分布の一つが正規分布で、ソレを元に、定量的にどのくらいヤバいのかを計算していく。

    異常度の算出

    さっきの例のヤバい定量的に表すことができれば、どの程度異常なのかがはっきりと分かる。 方法は、ラベル付きデータと、ラベルなしデータで違う。

    ラベル付きデータ

    ラベル付きデータの場合は、下図の様に正常・異常共に分布を描くことが出来るので、正常の確率分布と異常の確率分布の値の比から、新しく入力したデータを正常/異常を判定することが出来る。

    これをネイマン・ピアソン決定則といい、次式で表す。

    {\ln{\frac{p\left(x' | y=1,D\right)}{p\left(x' | y=0,D\right)}}}が所定のしきい値{\tau}を超えたら異常

    この決定則は、正常な標本の精度を保ったまま、異常標本の精度を最大化するという条件付き最大化により数式で計算できる。 計算方法に関してはコチラの記事が詳しい。

    ひとことで言うと、ラベルデータの異常判定は正常/異常の対数尤度比から判定できるということ

    ラベルなしデータ

    多くのデータは正常が圧倒的に多くて、異常が少ない/無い。この場合、異常の分布が出せないので、全体のデータから判定する。 ありふれた観測値より「珍しい」観測値を得たほうが得られる情報量が大きいので、それを数式で表すと、対数尤度の負の対数になる。

    \mathbf{x'}に対する異常度a(\mathbf{x'})
    a(\mathbf{x'}) = -\ln{p\left(\mathbf{x'}|D\right)} で表される。

    統計分布で分ける異常検知

    基本的な異常の計算は上記のように、確率分布を仮定し、対数尤度を求めて計算する。

    問題は確率分布pをどうするか。いつもデータがきれいな正規分布とは限らない。 下記に、主要な分布と性質、計算方法をまとめる

    分布 性質 計算方法
    正規分布 単純な分布、大数の法則に従うようなデータには基本使えるので汎用性が高い ホテリングのT2(参考)
    混合分布モデル 分布の山が2つ以上あるようなデータに適用できる。厳密計算が出来ない EM法による近似計算(参考)
    経験分布 分布を仮定せず、データから分布を作る。複雑な形を作れる一方で、データに左右されすぎて非直感的な結果になることも。 k近傍法/LoF (参考)
    ガウス過程 入力と出力が同時に観測できる場合ガウス過程により、関数を確率モデルで近似して異常検知に用いることが出来る ガウス過程回帰(参考)
    ミーゼス・フィッシャー分布 方向データ(長さ1で方向にだけ情報がある)に対する分布、自然言語などに対して用いられる 積率法(参考)

    時系列データの異常

    時々刻々と変わるものに対しては、概ね下記のような手法で変化検知を行っていく

    • 一定の窓幅をとって、誤差を出す
    • それをスライドさせながら、誤差を足していく
    • ある閾値を累積の誤差が超えたところで異常

    誤差に関して

    • 時系列モデルを作って予測してからの誤差 (参考)
    • 少し前の分布との誤差 (参考)

    の二種類がある。

    まとめ

    他にも、密度比推定や、AutoEncoderを用いた異常検知など、まだ色々と異常検知手法はある。 今日のまとめとしては、基本的に

    • 分布をつくり
    • 分布の誤差を計算して
    • しきい値を超えたら異常

    の流れ。分布の作り方、誤差の計算の仕方にバリエーションがあるというイメージ。 異常検知は何かとすることが多いタスクなので、どういうときに何を使うかまで、把握したいところ。

    明日は、変化点検知を実際のデータでやってみたいなと思う。ではでは!

    【Day-20】PyTorchを超絶使いやすくするsklearnラッパー『skorch』で快適ディープラーニング

    f:id:imslotter:20171220124248p:plain

    データ分析ガチ勉強アドベントカレンダー 20日目。

    Skorchとは

    f:id:imslotter:20171220123959p:plain
    • PyTorchのsklearnラッパー
    • sklearnのインターフェースでPyTorchを使える

    自分が感じたメリット

  • sklearnが行うところとPyTorchが作るところがはっきりしていて、コードがすっきりまとまる
  • sklearnの関数(fit, predictなど)がそのまま使える
  • numpy配列をそのまま学習器に投げられるので、イメージしやすい
  • 前処理、GridSearch, 評価もsklearnのものを使えて、便利
  • インストール

    git clone https://github.com/dnouri/skorch.git
    cd skorch
    # create and activate a virtual environment
    pip install -r requirements.txt
    # install pytorch version for your system (see below)
    python setup.py install
    

    ※私の環境(ubuntu14.04, python3.6.1)では、sklearn0.18.1では実行時エラーが出たので、sklearn0.19.1にアップグレードしました。

    pip install -U sklearn

    使い方

    データ読み込みはsklearn

    データの作り方などはday-7の記事を参照

    コードをみる
    %matplotlib inline
    import matplotlib.pyplot as plt
    
    import torch
    from torch import nn
    import torch.nn.functional as F
    torch.manual_seed(0);
    
    import numpy as np
    from sklearn.datasets import make_classification
    import sklearn
    X, y = make_classification(1000, 20, n_informative=10, random_state=0)
    X = X.astype(np.float32)
    X.shape, y.shape,y.mean()
    

    学習ネットワークの構築はPyTorch

    day19の記事のように、ネットワークの設計をdefine by runでしていきましょう。

    コードをみる
    class ClassifierModule(nn.Module):
        def __init__(
                self,
                num_units=10,
                nonlin=F.relu,
                dropout=0.5,
        ):
            super(ClassifierModule, self).__init__()
            self.num_units = num_units
            self.nonlin = nonlin
            self.dropout = dropout
    
            self.dense0 = nn.Linear(20, num_units)
            self.nonlin = nonlin
            self.dropout = nn.Dropout(dropout)
            self.dense1 = nn.Linear(num_units, 10)
            self.output = nn.Linear(10, 2)
    
        def forward(self, X, **kwargs):
            X = self.nonlin(self.dense0(X))
            X = self.dropout(X)
            X = F.relu(self.dense1(X))
            X = F.softmax(self.output(X), dim=-1)
            return X
    

    skorchでwrap

    skorch.net 用意されているのは2種類

    関数 用途
    NeuralNetClassifier 分類器をsklearn風に
    NeuralNetRegressor 回帰をsklearn風に

    初期化の際に、学習の仕方を決める。パラメータは、PyTorchの関数を使用できる。

    • criterion : 損失関数の設定
    • optimizer : 最適化関数の設定
    • lr : 学習率の決定

    その他色々とパラメータはあるので、skorch.netを参照。

    PyTorchのパラメータに関しては『PyTorch入門』 使い方&Tensorflow, Keras等との違いとは?を参照

    • .fitで、自動的にtorch.tensorに変換される
    • validationまでやってくれて嬉しい
    コードをみる
    from skorch.net import NeuralNetClassifier
    net = NeuralNetClassifier(
        module=ClassifierModule,
        max_epochs=20,
        lr=0.1,
        # use_cuda=True,  # uncomment this to train with CUDA
    )
    net.fit(X,y)
    y_pred = net.predict(X[:5])
    y_proba = net.predict_proba(X[:5])
    for pred, proba in zip(y_pred,y_proba):
        print("score {}: class {}".format(proba, pred))
    

    sklearnとのその他連携

    pipeline

    • スケーリングなどsklearnの処理をデータの流れに組み込める
    • 前処理の話は day-8
    コードをみる
    from sklearn.pipeline import Pipeline
    from sklearn.preprocessing import StandardScaler
    
    # データの流れるPipelineを設計
    pipe = Pipeline([
        ("scale",StandardScaler()),
        ("neuralnet", net)
    ])
    print(pipe.named_steps)
    
    pipe.fit(X,y)
    
    y_pred = pipe.predict(X[:5])
    y_proba = pipe.predict_proba(X[:5])
    for pred, proba in zip(y_pred,y_proba):
        print("score {}: class {}".format(proba, pred))
    
    • NeuralNetClassifier/NeuralNetRegressorで設定できるパラメータを調べることができる(GridSearchCV or RandomSearchCV)
    • optimizerなどもtorch.optimのリストを使って網羅的に調べられる
    • クラス内変数も module__hoge(hogeはメンバ変数)と入力することで置き換えられる
    コードをみる
    from sklearn.model_selection import GridSearchCV
    params = {
        "lr":[i*0.01 for i in range(1,5)],
        "optimizer":[torch.optim.Adam, torch.optim.Adagrad, torch.optim.SGD],
        "module__num_units":[10,20],
    }
    gs = GridSearchCV(net, params, refit=False, cv=3, scoring="accuracy")
    gs.fit(X,y)
    import pandas as pd
    df = pd.DataFrame(gs.cv_results_)
    df_scored = df.sort_values(by=["rank_test_score"])[["params","mean_test_score","std_test_score","mean_fit_time"]]
    df_scored
    

    MNIST

    MNISTを実装してみる。sklearnで書けるところはsklearnで書いて、PyTorchで書くべきところはそちらで書く。使い分けがはっきりしていてかなりいい感じ。

    # データの読み込み(sklearn)
    from skorch import NeuralNetClassifier
    from torch import nn
    from sklearn.datasets import fetch_mldata
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import classification_report
    mnist = fetch_mldata('MNIST original')
    X = mnist.data.astype('float32')
    y = mnist.target.astype('int64')
    X /= 255
    XCnn = X.reshape(-1, 1, 28, 28)
    XCnn_train, XCnn_test, y_train, y_test = train_test_split(XCnn, y, test_size=0.25, random_state=42)
    # Networkの設計(PyTorch)
    class Net(nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            self.conv1 = nn.Conv2d(1, 32, kernel_size=3)
            self.conv2 = nn.Conv2d(32, 64, kernel_size=3)
            self.conv2_drop = nn.Dropout2d()
            self.fc1 = nn.Linear(1600, 128) # 1600 = number channels * width * height
            self.fc2 = nn.Linear(128, 10)
    
        def forward(self, x):
            x = F.relu(F.max_pool2d(self.conv1(x), 2))
            x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
            x = x.view(-1, x.size(1) * x.size(2) * x.size(3)) # flatten over channel, height and width = 1600
            x = F.relu(self.fc1(x))
            x = F.dropout(x, training=self.training)
            x = self.fc2(x)
            x = F.softmax(x, dim=-1)
            return x
    # ラッパーを使う(skorch)
    net = NeuralNetClassifier(
        Net,
        max_epochs=10,
        lr=1,
        optimizer=torch.optim.Adadelta,
        # use_cuda=True,  # uncomment this to train with CUDA
    )
    # training
    net.fit(XCnn_train, y_train)
    
    # test
    y_pred = net.predict(XCnn_test)
    print(classification_report(y_test, y_pred))
    

    結果

    学習の様子

    結果の表示

                 precision    recall  f1-score   support
    
              0       1.00      0.99      0.99      1677
              1       0.99      0.99      0.99      1935
              2       0.99      0.99      0.99      1767
              3       0.99      0.99      0.99      1766
              4       0.99      0.99      0.99      1691
              5       0.99      0.99      0.99      1653
              6       0.99      0.99      0.99      1754
              7       0.99      0.99      0.99      1846
              8       0.98      0.99      0.99      1702
              9       0.99      0.98      0.99      1709
    
    avg / total       0.99      0.99      0.99     17500
    
    

    まとめ

    sklearnとPyTorchをつなげられる便利なライブラリを紹介しました。 PyTorchの持つ柔軟性と、sklearnの利用しやすさが相まって最高ですね。

    かなり使いやすいので、sklearnに慣れている人は、一回使ってみることをおすすめします!

    明日はどうするかな、ベイズ的な変化点検知をする予定だが、果たして、、、ではでは!

    【Day-19】『PyTorch入門』 使い方&Tensorflow, Keras等との違いとは?

    f:id:imslotter:20171219000627p:plain

    データ分析ガチ勉強アドベントカレンダー 19日目。

    2日間、Kerasに触れてみましたが、最近はPyTorchがディープラーニング系ライブラリでは良いという話も聞きます。

    とりあえずTutorialを触りながら使ってみて、自分が疑問に思ったことをまとめていくスタイルにします。

    また、同じく有名ライブラリであるKerasやTensorFlowについての比較もしたいと思っています(Define and RunかDefine by Runか)

    PyTorchとは

    f:id:imslotter:20171219043523p:plain

    ざっくりまとめると

    • 深層学習用ライブラリ
    • chainerからフォークされて作られている。思想はChainerを引き継いでいる。
    • GPUでの計算も楽に行える
    • Define by Run
    • コミュニティが活発で、後発にもかかわらず急速に発達

    特にDefine by RunはTensorflowやKerasと大きく異なる特徴です(後述)

    PyTorch入門

    変数の扱い方

    PyTorchでは、変数や関数をPyTorchオリジナルの型として扱う。大体はnumpyライクに扱えるので、ストレスは少ない

    x = torch.Tensor(5,3) #ゼロ行列
    y = torch.rand(5,3) # ランダム行列
    # 演算
    print(x.add_(y)) #アンダースコアをつけると破壊的変化
    print(torch.add(x,y)) #torchの関数から
    print(x+y) #通常の演算もいける
    # numpy likeに扱える
    print(y[:,1],y.mean(), y.std())  #ある程度の関数はそろっている
    print(torch.ones(10))
    print(torch.ones(10)+1)
    # numpyからの変換も可能
    import numpy as np
    a = np.arange(4).reshape(2,2)
    x = torch.from_numpy(a)
    

    Autograd

    • torch.autograd FunctionVariablesで定義すると、演算結果が保存されるので、 そのままさかのぼった微分が可能。

    下記の式は、

    • {x=} [[1,2],[3,4]]
    • {y = x^{2} +2}
    • {z = y^{2} = (x^{2}+2)^{2}}

    {out = \frac{1}{4} \sum_{i} z_{i} z_{i}  (x^{2}+2)^{2}} より、 {\frac{\partial out}{\partial x_{i}}=x_{i}(x_{i}^{2}+2)}

    その結果を返す より詳しい内容は公式

    from torch.autograd import Variable
    import numpy as np
    x = Variable(torch.FloatTensor([1,2,3,4]), requires_grad=True)
    y = x.float()**2 + 2
    z = y**2
    out = z.mean()
    out.backward() # 
    print(x.grad)
    

    出力

    <AddBackward0 object at 0x7f88d576ea90>
    Variable containing:
      3  12
     33  72
    [torch.FloatTensor of size 2x2]
    

    チュートリアル:NeuralNetの構築

    学習の手順

    • 学習ができるニューラルネットを定義する。
    • データセットを繰り返し投げられるようにする。
    • インプットに応じて、処理(計算)が走るようにする
    • 誤差(損失)を計算する
    • back propagationを実施する
    • optimizerによってパラメータを更新する

    この中でデータセットを繰り返し投げる以外の要素を説明していく。

    ライブラリ構成

    PyTorchのよく使うパッケージ

    パッケージ 説明
    torch NumPyのような配列(テンソル)ライブラリ。GPUも簡単に使える
    torch.autograd 自動微分ライブラリ。Torchで定義されたすべての関数に対して微分を可能にしている
    torch.nn ネットワークを構成する要素
    torch.optim パラメータ更新時に使う最適化パッケージ
    torch.utils DataLoaderなど、その他のユーティリティ関数

    torch.nn

    ネットワークを構成する要素関連はここに入っている

    • Conv1d,Conv2d,MaxPool1d, AvePool1d, AdaptiveAvgPool1d... : CNN向け
    • RNN, LSTM, GRU.... : RNN向け
    • BatchNorm1d,BachNorm2d, InstanceNorm1d,... : バッチ正規化
    • functional.hoge : 活性化関数(SoftMax, ReLUなど)
    • その他、dropout, sparse_embeddings,...

    詳しくはpytorch:nn

    すべてPyTorch内の関数で渡してやることができれば、autogradにより、back propagation時の微分演算などがスムーズ

    import torch
    from torch.autograd import Variable
    import torch.nn as nn
    import torch.nn.functional as F
    
    class Net(nn.Module):
    
        def __init__(self):
            super(Net, self).__init__()
            # 1 input image channel, 6 output channels, 5x5 square convolution
            # kernel
            self.conv1 = nn.Conv2d(1, 6, 5)
            self.conv2 = nn.Conv2d(6, 16, 5)
            # an affine operation: y = Wx + b
            self.fc1 = nn.Linear(16 * 5 * 5, 120)
            self.fc2 = nn.Linear(120, 84)
            self.fc3 = nn.Linear(84, 10)
    
        def forward(self, x):
            # Max pooling over a (2, 2) window
            x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
            # If the size is a square you can only specify a single number
            x = F.max_pool2d(F.relu(self.conv2(x)), 2)
            x = x.view(-1, self.num_flat_features(x))
            x = F.relu(self.fc1(x))
            x = F.relu(self.fc2(x))
            x = self.fc3(x)
            return x
    
        def num_flat_features(self, x):
            size = x.size()[1:]  # all dimensions except the batch dimension
            num_features = 1
            for s in size:
                num_features *= s
            return num_features
    
    net = Net()
    print(net)
    

    出力 : ネットワーク構成が分かる

    Net(
      (conv1): Conv2d (1, 6, kernel_size=(5, 5), stride=(1, 1))
      (conv2): Conv2d (6, 16, kernel_size=(5, 5), stride=(1, 1))
      (fc1): Linear(in_features=400, out_features=120)
      (fc2): Linear(in_features=120, out_features=84)
      (fc3): Linear(in_features=84, out_features=10)
    )

    値を投げる

    torchの型にしたがってデータを構成し、投げる。

    params = list(net.parameters())
    input = Variable(torch.randn(1, 1, 32, 32))
    out = net(input)
    

    損失関数

    誤差の算出のために、いろいろな関数が用意されている。シンプルなのはMean Squared Error。いろんな誤差を知りたい人は、機械学習で使う指標総まとめ(教師あり学習編)へ。

    • MSELoss
    • CrossEntropyLoss
    • NLLLoss(negative log likelihood loss) (1d, 2d)
    • Poisson NLL Loss
    • KLDivLoss (Kullback-Leibler divergence)
    • BCELoss (Binary Cross Entropy)
    • ...

    より詳しくは公式

    output = net(input)
    target = Variable(torch.arange(1, 11))  # a dummy target, for example
    criterion = nn.MSELoss()
    loss = criterion(output, target)
    

    back propagation

    損失が算出できたので。この損失からさかのぼっていく。PyTorchだと、backwardとだけ実行すれば、簡単にパラメータの微分値を算出できるようになっている。

    net.zero_grad() #とりあえず0で初期化
    loss.backward()
    

    重みのアップデート

    学習には、torch.optimを使う。下記のようなアルゴリズムがある。

    • SGD, ASGD, Nesterov-SGD
    • Adadelta, Adagrad, Adam, SparseAdam, Adamax
    • LBFGS
    • RMSProp, Rprop

    また、torch.optim.lr_scheduler学習率の調整もできる。

    import torch.optim as optim
    
    # create your optimizer
    optimizer = optim.SGD(net.parameters(), lr=0.01)
    
    # in your training loop:
    optimizer.zero_grad()   # zero the gradient buffers
    output = net(input)
    loss = criterion(output, target)
    loss.backward()
    optimizer.step()    # Does the update
    

    これで一通り終了。最終的にはデータを繰り返し投げて、学習を進めていく。 Githubのday19では、最後にMNISTの分類をPyTorchでやっている。そちらも是非どうぞ。

    主要フレームワークとの比較とDefine by Run

    Define and RunとDefine by Run

    ディープラーニングライブラリは上記の二種類の設計思想に大きく分かれる。 Chainerの血を受け継ぐPyTorchは、Define by Run。TensorflowやKerasとの最も大きな違い。

    どのように違うのか。下図は、PyTorchとKerasで定義した、Mnistに投げるCNN。 PyTorchがデータを投げて実行しながらネットワークを定義するのに対して、Kerasはネットワーク構成をかっちりと決めてからデータを投げる。定義の時点でデータは考えない。

    Define by Runのメリットとしては、

    • ネットワークを動的に変更できる。

    ということで、研究者界隈では、Define by Runが主流。

    使いやすさのKeras, 柔軟性のPyTorch

    とはいえ、Kerasはやはり圧倒的に使いやすい。 ネットワークを積み上げるだけで、簡単にディープラーニングができてしまう。

    その一方で、ネットワークの詳細設計はしにくい。

    通常のデータ分析業務ならば、Kerasの簡潔さが輝くだろうし、研究や難しいタスクならばPyTorchが優位なのかなという印象。

    コミュニティの強いPyTorch

    PyTorchの優位性は、コミュニティの強さにもある。 同じくdefine by runのChainerは、やはり日本が主流であって、海外での利用は少ない。

    一方でPyTorchは、研究者が続々と採用していて、主要な論文が出るとすごいスピードで実装されるので、最新論文のアルゴリズムをすぐに試すことができる。the incredible pytorchなどが好例。

    github.com

    まとめ

    PyTorchについて勉強してみた。 設計思想の違いなんかにも触れられたと思う。一長一短なので、両方とも使えるようになっていたら便利そうだなと思った。

    明日もPyTorch系の話題。どうやらsklearnラッパーがあるようなので、試してみたいと思う。ではでは!

    詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~

    詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~

    Natural Language Processing With Pytorch: Build Intelligent Language Applications Using Deep Learning

    Natural Language Processing With Pytorch: Build Intelligent Language Applications Using Deep Learning

    【Day-18】時系列のディープラーニング、RNNのまとめとKeras実装

    f:id:imslotter:20171218194346p:plain

    データ分析ガチ勉強アドベントカレンダー 18日目。

    Kerasの使い方を復習したところで、今回は時系列データを取り扱ってみようと思います。 時系列を取り扱うのにもディープラーニングは用いられていて、RNN(Recurrent Neural Net)が主流。

    今回は、RNNについて書いた後、Kerasで実際にRNNを実装してみます。

    今日の参考書はこの本!

    詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~

    詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~

    • 作者:巣籠 悠輔
    • 発売日: 2017/05/30
    • メディア: 単行本(ソフトカバー)

    RNNとは

    通常のNeural Networkとの違い

    Recurrent Neural Netの略。再帰ニューラルネット。何が再帰かは下図

    入力層、隠れ層、出力層の構造はDay-15で説明したNeural Netとほとんど同じだが、最も大きな違いは隠れ層同士がつながっているところ。これによって時系列に対応できるようにしている。順伝播の計算も、再帰性の要素が入ってくる。(添え字等はDay15参照)

    誤差逆伝播法のアルゴリズム

    基本的にニューラルネットと同じだが、隠れ層の時間方向に微分がつながっていくので、時間を遡りながら誤差の影響を伝えていく、しかし、本来は一番初めの時刻まで遡るものだが、遡りすぎると時間方向の微分がかけ粟さて勾配消失/爆発を引き起こし、うまく学習されないことも多くある。シンプルなRNNではBPTTを途中で打ち切る場合も多い。

    下記にアルゴリズムを記す

    1. 順伝播計算により{z}の更新式、出力{y}を求める

    2 ラベル{d_{nk}^{t}}との誤差を計算

    3. 重みを最小化する


    4. デルタはBPTTを行うことで再帰的に求められる

    5. 何らかのオプティマイザにより重みを更新

    勾配消失の工夫 : LSTMやGRU

    時間を遡ってBackpropagationを行うため、勾配消失が起こる。それを解消する工夫として、LSTM(Long-Short Term Memory)とGRU(Gated Recurrent Unit)がある。上の図の隠れ層に置ける、○の中身を工夫しながら、何を忘れて何を覚えておくか**まで賢く学習する。

    LSTM

    正直、本の図はちょっと分かりにくい、ウェブをあさってて一番厳密かつ分かりやすかったのは A Beginner’s Guide to Recurrent Networks and LSTMsというサイトの図

    複雑...一番のポイントは

  • 中心のcellと書かれている箇所(CECという)+forget gateで、過去情報をどのくらい記憶するかを調整する
  • これにより、BTPP中の勾配消失を数式的にも抑えることができた*1

    GRU

    LSTMの難点は複雑でパラメータが多いところ。上図で言えばinput/forget/blockと、それぞれのGateに入れるときの重みを最適化しないといけない。一方でGRUはLSTMベースだが、入力ゲートがLSTMよりも断然少ない。

    ゆえに計算量も少ない。さらに、タスクによってはLSTMより良い性能を発揮するということで、注目されている

    見た目の違いが論文に載っている。(Empirical Evaluation of Gated Recurrent Neural Networks on Sequence Modeling)

    だいぶシンプル。計算も軽いわけだから、とりあえずGRUから試してみるのがいいのかもしれない。

    自然言語をにぎわすAttention Model

    NLP(Natural Language Process)のRNN界隈では、Attention Modelというのがにぎわっているように見受けられる。

    勉強不足でまだまだ全然分かっていないので、勉強用のソースだけ張っておく。勉強。

    Keras実装

    練習がてら、KerasでRNNを実装してみる。 githubにもあげているのでそちらも参考に。

    github.com

    データの入力の仕方がちょっと難しかったので、そこだけ重点的に。

    データの変形、入力

    BPTTの都合もあり、投げるデータの配列をすこしいじってやらないといけない。いじり方について図でまとめてみた。このような3次のテンソル的な配列になる。

    コードをみる
    %matplotlib inline
    import matplotlib.pyplot as plt
    import pandas as pd
    import numpy as np
    import keras
    df = pd.read_csv("AirportPassengers.csv",delimiter=";").dropna()
    data = []
    target = []
    max_len = 24
    dim = 1
    # 正規化
    maximum = df.Passengers.max()
    minimum = df.Passengers.min()
    df["Passengers"] = (df.Passengers-minimum)/(maximum-minimum)
    # データを箱に入れる
    for i in range(len(df)-max_len-1):
        data.append(df.Passengers.values[i:i+max_len])
        target.append(df.Passengers.values[i+max_len+1])
    # データの整形
    data = np.array(data).reshape(len(data),max_len,dim)
    target = np.array(target).reshape(-1,1)
    # データの分割
    from sklearn.model_selection import train_test_split
    N_train = int(len(data)*0.7)
    N_test = len(data) - N_train
    X_train, X_validation, Y_train, Y_validation = train_test_split(data, target, test_size=N_test)
    

    学習モデル構築

    keras.layers.recurrentの中に、学習モデルが入っている。 LSTM, GRUも実装されていて、model.addするだけで使えるようになる。Optimizerの設定は普通のニューラルネットと同じ。Day-17にOptimizerについて書かれている

    コードをみる
    from keras.models import Sequential
    from keras.layers import  Dense
    #一番シンプルなやつ
    from keras.layers.recurrent import SimpleRNN
    from keras.layers.recurrent import LSTM, GRU #改良版
    model = Sequential()
    # ネットワーク構成
    input_shape=(max_len, dim)
    # model.add(SimpleRNN(units=64, kernel_initializer="random_uniform",input_shape=input_shape))
    #model.add(LSTM(units=64, input_shape=input_shape))
    model.add(GRU(units=64, input_shape=input_shape))
    
    model.add(Dense(input_shape[1],activation="linear"))
    # optimizerの設定
    from keras.optimizers import Adam
    model.compile(loss="mse", optimizer=Adam())
    

    学習と予測

    7割を学習用データにして、残りの3割を予測することにした。

    コードをみる
    from keras.callbacks import EarlyStopping
    early_stopping = EarlyStopping(monitor='val_loss', patience=10, verbose=1)
    epochs = 500
    batch_size = 10
    model.fit(X_train, Y_train,
              batch_size=batch_size, epochs=epochs,
              validation_data=(X_validation, Y_validation))
    prediction = []
    data_in = data.reshape(data.shape[0],data.shape[1])[N_train]
    
    iteration = len(data) - N_train
    for _ in range(iteration):
    #     print(data_in)
        pred = model.predict(data_in.reshape(1,-1,1))
        data_in = np.delete(data_in, 0)
        data_in = np.hstack((data_in, pred[0]))
        prediction.append(pred[0,0])
    passenger = list(df.Passengers)
    data_num = len(passenger)
    plt.plot(passenger)
    plt.plot(range(N_train+max_len, N_train+max_len+iteration), prediction)
    

    結果

    上記の学習を3回行ってみて、LSTMと普通のRNNとGRUを比べた。

    今回の結果は、LSTMが良かった。

    きちんとトレンド/周期共に捕らえられているようだった。ただ、時間を追うごとに値がずれていっている。もう少し精度を上げたいなら、前処理をしっかりしたほうがいいのかもしれない。前処理については以前時系列まとめで書いた(【Day-12】時系列分析の良リソースまとめ&基礎チュートリアル)

    まとめ

    せっかくKerasを学んだので、時系列もディープでしておこうと思い、まとめた。 ちょっと苦労したけど、これで学習器に入れられるようになった。予測がちゃんとできれば楽しい。

    明日はPyTorchやりたいなぁ。ではでは。

    *1:数式載せようかと思ったけど、異常にめんどくさいからやめますごめんなさい。

    【Day-17】DeepLearning系ライブラリ、『Keras』の使い方まとめ(2.x対応版)

    【最終更新 : 2017.12.17】
    ※以前書いた記事がObsoleteになったため、2.xできちんと動くように書き直しました。

    f:id:imslotter:20171217160749p:plain

    データ分析ガチ勉強アドベントカレンダー 17日目。

    16日目に、1からニューラルネットを書きました。 それはそれでデータの流れだとか、活性化関数の働きだとか得るものは多かったのですが、Kerasと言うものを使ってみて、何て素晴らしいんだと感動してしまいました

    今まで苦労して数十行書いていたものが、わずか3行で書ける! 正直、スクラッチで書く意味って、理解にはいいけど研究や分析には必要あんまないんですよね。車輪の再発明になるし。 と言うわけで、使えるものはどんどん使っていこうスタンスで、今日はKerasの紹介です!

    Tutorial+気になった引数を掘り下げて補足のような感じで書いています。 ちなみに、各部のコード以下をつなぎ合わせるとmnistの分類器が動くようになっています。 *1 *2

    Kerasとは?

    Keras is a high-level neural networks library, written in Python and capable of running on top of either TensorFlow or Theano. It was developed with a focus on enabling fast experimentation. Being able to go from idea to result with the least possible delay is key to doing good research. (Documentationより)

    TensorFlowやTheanoのラッパーで、簡単にディープ系の実験環境を整えられるようになっている。 実際に使ってみましたが、かなり直感的にネットワークを構成することが出来る

    使ってみる

    インストール

    前に記事でも少し書いた。

    www.procrasist.com

    pip install tensorflow
    pip install keras

    で入ると思います。その他のライブラリ(opencvとか)は必要に応じて入れてください。

    データを用意

    とりあえずMNIST(デフォルトでmnistデータセットは利用可能) from keras.datasets import hogehogeでhogehogeのデータセットを読み込める。以下は読み込めるデータセット一覧

    データセット 内容 trainデータ数 testデータ数
    mnist 28×28の手書き数字(白黒)10個に分類 60000 10000
    cifar10 32×32のカラー画像10に分類 50000 10000
    cifar100 32×32のカラー画像100に分類 50000 10000
    imdb 25000の映画のレビューのデータセット、ラベルは肯定否定の2種 25000 25000
    reuters 11228個のニュースデータセット46トピックに分類 8972 2246
    fashion_mnist 28×28の白黒画像を10種類のカテゴリに分類 60000 10000

    求めたいものがあれば各々で利用すれば良い。データの渡し方の参考にこれらのデータセットの型を知っておくのがいいかも。

    コード

    from keras.datasets import mnist
    from keras.utils import np_utils
    (X_train, y_train),(X_test,y_test) = mnist.load_data()
    X_train = X_train.reshape(60000,784).astype('float32')
    X_test = X_test.reshape(10000,784).astype('float32')
    #[0,255]の値を[0,1]に正規化
    X_train /= 255.0
    X_test /= 255.0
    # 1 of Kのベクトルに変換
    y_train = np_utils.to_categorical(y_train, 10)
    y_test = np_utils.to_categorical(y_test, 10)
    

    modelを作る

    model = Sequential()で初期化
    model.add()で層を積んでいく

    • 一層目:IN-784次元, OUT-64次元, 活性化関数-Selu
    • 二層目:IN-default(多分64次元) OUT-10次元 活性化関数-SoftMax関数

    入力のイメージは下図。MNISTは28×28の図だが、784次元の1次元ベクトルに変換してから入力している

    • デフォである活性化関数
    • より高度な活性化関数 : keras.layers.advanced_activations モジュール内

    関数の違いは下図 f:id:imslotter:20170107153956p:plain

    コード

    from keras.models import Sequential
    from keras.layers import Dense
    model = Sequential()
    model.add(Dense( activation="selu", units=64,input_dim=784))
    model.add(Dense(activation="softmax", units=10))
    

    学習プロセス

    model.compile

    • 損失関数 : どのくらいの誤差があるかを定量
    • 最適化関数 : 誤差からのパラメータ更新の仕方

    loss : 損失関数

    デフォで用意されている関数

    関数名 意味
    mean_squared_error, mse 二乗誤差
    mean_absolute_error, mae 絶対誤差
    mean_absolute_percentage_error, make 正解とのズレ(絶対値)の割合
    mean_squared_logarithmic_error, msle 正解とのズレ(二乗誤差)の割合
    squared_hinge マイナスのところは0, プラスは二乗誤差
    hinge マイナスのところは0, プラスは絶対値
    binary_crossentropy loglossとしても知られている
    categorical_crossentropy マルチクラスloglossとして知られている(ラベルがバイナリ配列であることが必要)
    sparse_categorical_crossentropy スパースラベルを取る
    kullback_leibler_divergence, kld 確率を分布とみなした時の差
    poisson 予測-正解*log(予測)の平均
    cosine_proximity 予測と正解間のコサイン近似の負の平均

    詳しい実装例はこちら GitHub

    optimizer : 最適化

    デフォで用意されている関数

    • SGD
    • RMSprop(デフォルトパラメータ推奨)
    • Adagrad(デフォルトパラメータ推奨)
    • Adadelta(デフォルトパラメータ推奨)
    • Adam(デフォルトは提案論文通り)
    • Adamax Adamの拡張(無限ノルム)
    • Nadam Adam+RMSprop with momentumらしい
    • TFOptimizer よくわかんない
    • 引数の詳細な設計も可能(こちらを参考 web)
    • 新しい最適化関数を作りたいなら GitHubを参考に

    指標の参考には以前書いたこちらの記事もどうぞ

    コード

    from keras.optimizers import SGD
    # optimizer = "sgd"でも、簡単に最適化関数の設定ができる
    #(その場合パラメータはデフォルト値)
    model.compile(loss="categorical_crossentropy", 
                  optimizer=SGD(lr=0.01, momentum=0.9, nesterov=True),
                  metrics=["accuracy"])
    

    モデルの学習

    学習

    model.fit()でモデルを学習。引数は以下

    • X_train : データ(MNISTだと、どこに何個データが入っているか)
    • y_train : ラベル(1-10)
    • batch_size : ミニバッチにデータを分けるこの場合60000個ある学習データを、32個ずつに分けて、重みを更新する
    • epochs : 学習の繰り返し。60000個を何回学習するか
    • validation_split : 学習データの何パーセントをvalidation用データにするか(各エポックのテスト。validationの説明はこの記事を参考にどうぞ : 【Day-10】Cross Validationとパラメータサーチでモデルの調整 )

    また、学習の様子も保存されている model.fit内の変数を見てみるとこんな感じ

    print(history.__dict__)
    >>> {'model': <keras.models.Sequential object at 0x110c78510>, 'params': {'verbose': 1, 'nb_epoch': 3, 'batch_size': 32, 'metrics': ['loss', 'acc', 'val_loss', 'val_acc'], 'nb_sample': 48000, 'do_validation': True}, 'epoch': [0, 1, 2], 'history': {'acc': [0.89862500000000001, 0.94735416666666672, 0.96150000000000002], 'loss': [0.35020409799863894, 0.18034435256198048, 0.132605804043822], 'val_acc': [0.94125000000000003, 0.95816666666666672, 0.96499999999999997], 'val_loss': [0.20651897403846184, 0.14732480475058157, 0.1263637450747192]}}
    

    コールバック関数

    keras.callbacks内の関数を使ってモデルの保存ができる。

    • check = ModelCheckpoint("modelname.hdf5")で、学習済みモデルの重みを保存する
      • その場合、model.fit(hogehoge,callbacks=[check])としてやる
    • tensorboardなどとも連携可能
    • 自分でcallbackしたい関数を作ることも可能
    • 詳しくはドキュメント参照

    コード

    from keras.callbacks import ModelCheckpoint
    check = ModelCheckpoint("model.hdf5")
    history = model.fit(X_train, y_train, epochs=20, 
                        validation_split=0.2, batch_size=32,
                        callbacks=[check])
    

    モデルの評価

    model.evaluate()という関数で、テストデータを用いたモデルの評価が可能。lossとaccuracyを見ている

    コード

    loss, accuracy = model.evaluate(X_test, y_test)
    print("\nloss:{} accuracy:{}".format(loss, accuracy))
    

    モデルの可視化

    可視化(tensorflow)

    モデルの可視化

    ニューラルネットのネットワークを可視化するとき
    keras.utils.visualize_util
    手順(Mac, Homebrew有り)

    • $brew install graphviz
    • $pip install pydot

    とすれば使える

    • to_file : 出力の画像ファイルの名前
    • show_shapes : グラフ中に出力形状を書くか(デフォはFalse)
    • show_layer_names : レイヤー名を書くか(デフォはTrue)

    コード

    from keras.utils.visualize_util import plot
    plot(model, to_file="model.png", show_shapes=True, show_layer_names=True)
    

    こんなのが出てくる
    f:id:imslotter:20170107113053p:plain

    学習の様子をplot

    matplotlibで可視化

    コード

    import matplotlib.pyplot as plt
    
    def plot_history(history):
        # 精度の履歴をプロット
        plt.plot(history.history['acc'],"o-",label="accuracy")
        plt.plot(history.history['val_acc'],"o-",label="val_acc")
        plt.title('model accuracy')
        plt.xlabel('epoch')
        plt.ylabel('accuracy')
        plt.legend(loc="lower right")
        plt.show()
    
        # 損失の履歴をプロット
        plt.plot(history.history['loss'],"o-",label="loss",)
        plt.plot(history.history['val_loss'],"o-",label="val_loss")
        plt.title('model loss')
        plt.xlabel('epoch')
        plt.ylabel('loss')
        plt.legend(loc='lower right')
        plt.show()
    # modelに学習させた時の変化の様子をplot
    plot_history(history)
    

    こんな感じに

    f:id:imslotter:20170107151009p:plain

    正解率98%とかって半端ないですね。人間と同じかそれ以上の識別性能かも!

    Keras 1.xからKeras 2.xの変更点

    詳しくはこちらの公式記事を参考

    上記チュートリアルで変更した点をメモとして記しておく。

    Layerを作る際に、活性化関数も一緒に入れるようになった

    from keras.layers import Dense, Activation
    model = Sequential()
    model.add(Dense(output_dim=64, input_dim=784))
    model.add(Activation("relu"))
    

    出力

    UserWarning: Update your `Dense` call to the Keras 2 API: `Dense(input_dim=784, units=64)

    変更後

    model = Sequential()
    model.add(Dense( activation="relu", units=64,input_dim=784))

    nb_epoch -> epochs

    from keras.callbacks import ModelCheckpoint
    check = ModelCheckpoint("model.hdf5")
    history = model.fit(X_train, y_train, nb_epoch=20, 
                        validation_split=0.2, batch_size=32,
                        callbacks=[check])
    

    出力

    UserWarning: The `nb_epoch` argument in `fit` has been renamed `epochs`.
      warnings.warn('The `nb_epoch` argument in `fit` '

    変更後

    from keras.callbacks import ModelCheckpoint
    check = ModelCheckpoint("model.hdf5")
    history = model.fit(X_train, y_train, epochs=20, 
                        validation_split=0.2, batch_size=32,
                        callbacks=[check])
    

    show_accuracyの廃止 : defalutでaccuracyが出力されるようになった。

    model.evaluate(X_test, y_test, show_accuracy=True)
    

    出力

    TypeError: evaluate() got an unexpected keyword argument 'show_accuracy'

    変更後

    model.evaluate(X_test, y_test)
    

    まとめ

    今日のポイントは
    ・Kerasを使うと、簡単にディープラーニングができる
    ・可視化も簡単にできるので、実験にはもってこい
    ・ただ、便利・簡単すぎるので、中身の仕組み知りたい人は一から書いてみるのもいいかも!

    実際にモデルを動かしてる部分って、たかだか十数行とかですものね。すごい。 いろいろな実験がしやすそうだし、これからどんどん使っていきたい。

    なお、Kerasを書籍で勉強したい方はこちらがオススメです。特にRNNに関しては丁寧に書かれているので!

    詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~

    詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~

    明日はKerasを用いたRNN実装にチャレンジしてみる(予定)です!お楽しみに!

    *1:日本語があると怒られる方は、ファイル先頭に#coding:utf-8をつけておきましょう。

    *2:順を追ってimportしているので、そのまま使うとものすごく見にくいかもです。コピペした後は適当に体裁を整えてください

    PROCRASIST