かえるのプログラミングブログ

プログラミングでつまずいたところとその解決策などを書いていきます。

営業マンが1年でSEになって機械学習エンジニアに転職する話

こんばんは、かえるるる(@kaeru_nantoka)です。

先日、10ヶ月勤めたSES企業に辞意を伝えました。 そして4月からは、ストックマーク株式会社(https://stockmark.ai/ )にて、NLPを応用した機械学習エンジンを開発する機械学習エンジニアとして参画することになりました。

ちょうどいい人生の節目なので、流行っている転(退)職エントリを描いてみようと思います。


概要

・営業職だけど趣味で始めたプログラミングにハマったよ

・未経験だけど第二新卒的なアレでプログラマーになるぞ

・ひょんなことから kaggle にハマったぞ

・なんか上京することになったよ

・なんで私がエクセル職人に!?

・なんとかソロ銅メダル取れたぞ

・kaggle 強くなりたいからもう一度転職するぞ!


筆者のスペック

・経済学部卒

・プログラミング歴1年ちょい(2017年12月~)

・kaggle(機械学習)歴半年ちょい (2018年8月~)


目次

I ) 証券時代(職種: 営業)

I I ) 転職活動(1)

I I I ) SES企業時代(職種: C#プログラマー)

I V ) 金融系SIer時代(職種: エクセル職人)

V ) 転職活動(2)

V I ) おまけ


I )

新卒では大手証券会社に入社し、営業職をしておりました。

金融商品の営業は難しい仕事であるという認識はあったものの、色々あって(この内容でもう一本書けそう)私の社会人経験はこの仕事でスタートしました。日経新聞を毎日読み、風が吹けば桶屋が儲かると言わんばかりに記事の一つ一つを無理やり取り扱い金融商品の値動きで締めくくるような営業トークを朝練習して、金融商品のパンフレットを持って個人宅や各種法人に突撃する日々を過ごしていました。

金融の勉強は面白かったし、この商品はイイぞと思える商品もあったのですが、突然来た若造が売りに来た値下がりするかもしれない金融商品を買うでしょうか?それ以前に、「金融商品買ってください」で締めくくられる話を聞く気になるでしょうか?

そもそも、金融商品の良さを知ってる人は自分でやってます。

結局、練りに練った営業トークは聞き入れられることもなく数字は上がりませんでした。

中々数字が上がらないので上司に相談したりしました。「運もあるからね。仕方ないよ。これだけ頑張ってたらどこかで報われるよ。」と励ましてくれましたが、「結局最後は運なのか」と思いました。

別部署へ異動したいという考えもありましたが、資格が必要で、その資格の要件に「実務経験3年以上」というものがあり、この環境を出るためにこの環境に3年も居続けなければならず、さらに資格を取っても配属面談やら人事考課やら、大企業ならではのプロセスがあり不確実です。そして、自分の人生なのに自分の職種を会社が決め、さらに数年経ったらローテーションで職種も変わり、転勤で住む場所も変わりうるという所謂一般的な大企業の人事制度が自分に合わないなと思うようになりました。

そこで、「自分の努力がダイレクトに返ってくる。自分の人生を自分である程度はハンドリングできる実力をつけられる。そんな環境で勝負したい。」と思い、当時流行り始めていたプログラミングを始めることにしました。もともと「ブラッディマンデイ」や「王様達のヴァイキング」といった漫画が好きで、プログラミングできたらカッコイイし、やってみたいけどやり方分からんの状態だったので 「PythonGUIRPGゲームを作ろう」みたいな本からはじめました。


I I )

見る見るプログラミングにハマりました。 自分の書いたコードがそれなりの形になって画面上に表示されることの喜び、理解には時間がかかるものの時間をかけたら何とか動かせたことに「自分の努力がダイレクトに返ってくる体験」を覚えました。もともと営業仕事を終え自宅に帰ってからの時間でやっていて楽しく感じていたので、「これだけコードを書くのが楽しければ、仕事でつまづいても業後の時間を全て割いてでもキャッチアップしたい」「社会人1年目で第2新卒枠として年収を下げてでもチャレンジする最後のチャンス」だと思い、マイナビ転職、リクナビネクスト、greenなどに登録し、未経験OKかつコードを書かせてくれそうなところに片っ端からエントリーしては面接しました。営業職からの異業種転職ということで面接では結構苦労しましたが、最終的に地元のSES企業5社から内定をもらい、金融関係にシステムの受託開発をしているという現職の内定をお受けすることにしました。

ここでの決め手は、金銭面と業務面です。金銭面では、プログラミング未経験でありながら金融機関での経験を買ってもらい当時の給与を少し下がるくらいの水準で給与提示してくれました。(他の4社は実務未経験なので額面月17万からスタートみたいなのが多くコレは生活できんぞ…と思ってました。)業務面では金融関係のドメインを使えるということで「1年でやめてしまうはずの金融の知識を引き続き使えるならちょっとお得だな」と思ったのとコードかけるよと言ってもらったからです。他の数社では、コードを書けるのは案件次第だったり、案件のない隙間の期間で別の非コーディングの案件に入ってもらうという話でした。

利用言語はJava ということでしたが、自分のスキルとして残り、それで勝負できるという働き方ができるならそれでもいいかと納得して4月からその会社に勤めることとなりました。


I I I )

入社してから2ヶ月間は、研修と称し、Java + HTML + CSS + 生JS + MySQL で顧客管理システムを作ったり、使わなくなったPCに ubuntu を入れて自作サーバーを作るなどしてLinux の扱いなどを学ぶ傍ら、金融系の受託案件のコーディングを手伝うなどさせてもらってました。それから9月まで、別な金融機関向けのスマホアプリの案件ということで C# を用いた開発のコーディングを手伝わせてもらってました。残業で次の日の朝に帰るようなこともあり受託開発の厳しさを知るもののコーディングしている満足感から辞めたいとまでは感じませんでした。どちらかというとデスマーチさえも楽しめていたと思います。

一方プライベートでは、このころ Twitter アカウント(かえるるる)が誕生しました。 ツイッターの世界では、自作のWEBアプリを公開し、たくさんのいいねやRTをもらっている先人たちがおり、すごいなと思って見てました。

「わいもバズるアプリ作ってアルファアカウントになるんや!!」と意気込み、Django でその場で聴ける簡単な楽曲投稿サービスを半月ほどで作成しリリースしました。6月くらいだったと思います。これがめちゃくちゃバズ...らず、ユーザー志向のサービスを作るのは難しいなあなどと考えていました。

そんな中、Qiita で顔判別AI を作ろうみたいな記事を見つけ、この技術は面白い、これを応用したらすごいアプリが作れそうだと思いました。 使われていたのは keras でした。

画像は自分で用意しましたが、実装の部分は写経して何とか動くものを作りました。これだとオリジナリティがないので、元ネタはWebアプリとしてリリースしていたものを、LINE-BOT API + Heroku + flask に書き換え、顔判別LINE-BOT 「塩顔しょうゆ顔ソース顔判別ちゃん」通称もこみちLINE-BOTを無事リリースしました。これはなかなかバズって友達登録数39人、200いいね近くいきました。

( https://twitter.com/kaeru_nantoka/status/1041705619705610240 )

ちなみに画像は Google Custom Search API なるものを使って全部で 400枚ほど集めましたが、被りが多く素材集めに大変苦労しました。

実は、この「AI使ったアプリ作り楽しいけど画像集め大変やん...」がきっかけで、無料でビッグデータを使用して機械学習に取り組めるサービスを探し、Kaggle にたどり着いたのです。

Kaggle は titanic, homecredit, サンタンデール、Two sigma, 塩コンペなどのカーネルを見てやり方に慣れていきました。

ド初心者の私でも(今でも駆け出しですが)、XGB というものに入れられるように データを云々して、出てきたデータをさらに云々して、 to_csv すればええんやくらいの理解で写経を中心に取り組んでいたのですが、それでもめちゃくちゃ楽しかったです。よって、業務ではC#をかいて、帰ったらkaggle をやるという今のスタイルに近い形が8-9月で出来上がりました。


I V )

そんなある日社長から言い渡されます。「SEとして東京に行くんやで」 正直えっと思いましたが、今度は Java ということではあるが引き続きコードを書けるということだったし、このころには何人かの kaggler の方をフォローしており東京に行くのも悪くないなと快諾しました。

10月に東京に来てからの業務は、9割方 Excel を使用したものでした。 プロジェクトは引き続き、金融機関向けのアプリの作成業務で、オフショアのコーディングをしてくださる方のために、仕様書を起こしたり、画面のイメージやレイアウトをお伝えするために画面キャプチャをエクセル上で切った貼ったするものばかりでした。 正直騙されたわ。。。と思ったもののこの頃はまだ定時で帰ることができていたので、「とにかく定時で帰れるように頑張って仕事を調整して、一秒でも長く kaggle する時間を確保できるようにしよう」の思いで日々過ごしていました。

一方プライベートでは、 Twitterで繋がった kaggler の方とお話しする機会を設けてもらったり、 PLAsTiCCコンペに夜な夜な取り組んだり、kaggle meetup tokyo に一回でも submit したことのある枠で参加させていただいたり東京に住んでいるメリットをフルパワーで享受していました。

仕事の話に戻ると、12月頃から残業が多くなって来ました。 というのもアプリの画面開発に際して、(自称)アジャイルな開発体制をとっていたのですが、作ってはここを変えてくれ、作ってはここを変えてくれの繰り返しで一向に進展しませんでした。そのように手戻りは多いものの、「営業で使うから」や「役員にプレゼンするから」今日中に仕上げてくれみたいな支持を受けることがままあり、「そういったことがあるなら事前に教えておいてほしいな」などと思いながら残業に甘んじていました。

個別の仕事自体はそれほどしんどくないし、何なら kaggle やっている方が頭をめちゃくちゃ使うくらいの認識だったので残業そのものは何ともありませんでしたが、エクセル仕事、特に VBAマクロのようなコードを書く仕事ではなく何も身に付かない仕事で残業を強いられるのが辛くて堪りませんでした。 また、kaggle をする時間が圧迫されるのも我慢なりませんでした。

このプロジェクトにコーディングをする仕事がないかというとそうでもないですが、新卒社員を中心にコーディングの仕事が割り振られていたようでした。SES社員には特別なスキルのいらない仕事を振っておいて、自社の社員にはきちんとコーディングを教えるというのはとても理にかなっていることだと思います。

こういった事情から、この会社にいてもずっとテイよく一労働力として搾取され続けるんだろうなと思うようになり、転職したいなと思うようになりました。 しかし、社会人二年目にして早くも二社も退職してしまうのは少し気が引けたのと、「どうせ転職するなら kaggler のいるような職場がいいなあ。でもこれといった実績もないなあ。どうしようかなあ。」というような気持ちでした。

この辺りから、kaggle でソロメダルを獲得してそれを実績として捉えてくれるところに転職しようという目標ができました。


V )

転職の動機

上記のような不満も多少なりともありましたが、直接的な動機は kaggle で強くなりたい。という気持ちでした。

わたしの知る範囲内の先輩 kaggler は理系で大学院を出た方、或いは大学に在学中で余暇は関連の技術論文を読み漁っては実装しているなどの数理的な背景、技術のために惜しみなく時間を使っている(時間を使える環境にある)といった印象を受けました。

私も「時間がない」という理由は甘えでしかないと考えており、18:30定時に会社を出られた日は20時から、残業で20時くらいに会社を出ることになったらタクシーを利用するなどして時間と体力を温存しつつ、22時くらいから26~27時くらいまで kaggle に取り組んでいました。

上京してそうした暮らしを2ヶ月ほど続けて、やっとの想いで PLAsTiCCコンペにてソロ銅メダルを獲得(ボーダーから数えて3番目くらい)しました。

銀メダル圏も見えていましたが、最後の最後まで Public LB では届きませんでした。その上 Private LB でのシェイクダウンによりこの成績です。

「ソロメダルを獲得する」という当初の目標は達成できましたが、同時に「こんなに時間を投入してもギリギリ銅メダルなのか」と厳しさを実感しました。

経済学部卒で在学中はプログラミングもまともに勉強したことがなく、論文といえば日本語の歴史系のものを卒業のために何本か読んだことのあるくらいでした。

そんな普通の文系卒の私が、「日中エクセルに画面キャプチャを何時間も貼って過ごして平日業後と土日にちょちょいとキャッチアップする生活を続けて kaggle で勝てるのか?」と考え、日中の時間も機械学習モデリングEDAができる環境に飛び込みたいと考えるようになりました。

転職活動

今回は以下のツールを使用しました。

Twitter

Wantedly

企業フォームからの直接の応募

ヒヨコの方のように、Twitter 転職でかっこよく決めたかったのですが、今回は Wantedly で転職予定の会社と出会いました。

有名どころのWeb企業の機械学習エンジニア職には直接企業の応募フォームからエントリーしましたが、こちらで応募した会社はことごとく書類落ちしました。

両ツールを通してたくさんの方と面談させていたくことができたのでとても勉強になりました。

転職活動の軸

kaggler と働きたいな~職場の人とチーム組んでコンペに参加したいな~などと思ってましたが、最終的には

「業務で得た知見を kaggle で活かす、kaggle で得た知見を業務で活かす」

のサイクルを確立した働き方がしたい

という想いに賛同頂ける会社

の一本に落ち着きました。

現場社員の方との面談や技術面談、CTOの方との面談で上記の話は必ずしました。

この話をして「うちならできるよ」や「うちでやってる人いるよ」などの返答が返ってくる場合は、既に kaggler が活躍されているなどで kaggler に対する理解があるかつ kaggler が満足して働ける環境がある会社ということなので、「ぜひ今すぐに私も混ぜてください~」という気持ちになってました。

持論ですが、kaggler が満足して働けている会社はいい会社です。

職務経歴書

職務経歴書を書き始めました。

そこには、

1年で新卒で入った証券営業職を辞め、転職先のSES企業でコーディング半年(しかもC#)、最後の数ヶ月に至ってはエクセル職人(それっぽく書くと、オフショアのプログラマの方々への作業依頼書の作成含むのディレクション業務 になりました。)

の悲惨な業務経験の2年目社会人がいました。

「こんなんで機械学習エンジニアになりたいとかどうかしてるぞ…?てか社会人2年目で2社目を辞めようとしてるのか私は…?これサラリーマン向いてないんじゃ…」 ととても悩みました。

kaggleソロ銅メダル、これを評価してくれる会社があればいいなとダメ元で進むことにしました。

最終的には、独学短期間でkaggleソロ銅メダルを評価していただいたことが内定獲得に大いに貢献してくれました。

内定を受諾した決め手

内定は今回お世話になる1社のみですが、数社選考の途中で辞退させていただきました。いずれの会社も面接で私がやりたいことに対してとても関心を示してくださり、魅力的で自分が三人くらいに分身できたら全部の会社の選考を最後まで受けたかったです。

決め手は、自社サービスを運営している点とNLP技術に特化している点でした。 先にも述べた通り、私はこの世界で生きていくことを考えたときにあまりにも背景が弱いです。よってこれからこの分野は自信を持って得意と言えるぞ、というものが欲しかったのです。NLP は前処理も多岐にわたり学習済みのモデルも日進月歩で進歩しています。また、使用技術がNNなのも魅力的でした。昨今の kaggle ではテーブルデータについてもNNを使用してモデルを作り、アンサンブルすることで上位に食い込んでいるチームが多いです。よって、業務でNNに取り組める環境は私の kaggle で強くなりたいという目標の実現を加速させるものだと思いました。 自社サービスである点については、単純に前職が、受託開発とSESだったので、一回自分の会社のプロダクトを成長させるために注力してみたい気持ちがあったからです。

転職活動を終えて思うこと

今回の転職活動において、kaggle ソロ銅メダルはとても大きな仕事をしてくれました。

コンペ途中に、最終的に銀メダルを獲得するチームとチームマージさせていただけるかもしれない機運があったのですが、「ソロ」の実績が欲しかったこともあり、お断りしてしまいました。kaggle master になるには、金一枚と銀二枚以上のメダルが必要ということもあり、勿体無いことしたなあと思ったこともありますが、今ではあの決断は間違ってなかったなあとも思います。

なにはともあれ、4月から昼も夜も機械学習に塗れた生活を送れるということで楽しみで仕方ありません。

これからげきつよkaggler になれるよう精進していく所存ですので、どうぞよろしくお願いします。


V I )

SIer勤務kaggler として辛かったこと

日中kaggleに全く関係のないことで時間が削れていくつらみもありましたが、最もつらかったのは「話題がない」ことでした。

上京し kaggle meetup や コンペの反省会を通じて知り合った方々との勉強会に参加させていただく機会がチラホラ増えてきたのですが、その勉強会後の飲み会での話題にとても困りました。

勉強会に参加されてる方同士の会話では「(さまざまな業界で分析業務に従事されてる方々が)実務においてどのように技術を活用しているか」や「コンペで使われてたあの手法について」などが主で、私を含めてそう言った会話をしに(聞きに)来ているという認識でした。

したがって私の「エクセルに画面キャプチャを貼っている愚痴」のような話題でみなさんの貴重な時間を奪うのは誰も幸せにならないと思い、聴講マシーンになってました。

実はここで見聞きしたことは、面接や面談で大いに活きました。というのも「実際に分析業務に携わっている方の関心」「kaggle と実務でのデータやモデルの扱いの違い」について業務未経験ながら背景知識やその業務に従事することのイメージを持つことができ、質問したい内容が自然出てきたり、自分がその御社で働くことになったとしたらどういうような働き方をしそうかのようなところのすり合わせがスムーズにできたように実感しています。


以上です、ありがとうございました。

【追記】 一部日本語の使い方に誤りがある点をご指摘いただきましたので訂正致しました。 ご指摘くださった皆様、どうもありがとうございました。

VOC2007 dataset で遊ぶ① (2019/01/26)

かえるるる(@kaeru_nantoka)です。

今回はかねてより segmentation task に取り組みたいなあ と思っていた私が、手頃なデータ落ちてないかな〜とネットサーフィンをしていたところ tarファイルで 480MB という頑張ったらローカルで云々できそうなデータセットを見つけたので、云々した物語の第一弾です。

それでは、VOC2007データセットで遊ぶ① と称して

VOC2007データセットのダウンロード ~ train_dfの作成 ~ リサイズ ~ img画像と mask画像の可視化

までを残していこうと思います。

ソースコードは ↓ です。

https://github.com/osuossu8/Play_With_VOC2007/blob/master/get_idx_name_and_mk_train_df.ipynb

ちなみに環境は、Google Colab です。

(...いいぱそこんほしい。。。)


参考 URLs

data の準備 :

https://qiita.com/tktktks10/items/0f551aea27d2f62ef708

train_dfの作成:

https://www.kaggle.com/shaojiaxin/u-net-with-simple-resnet-blocks-v2-new-loss



まず、データをここ(http://host.robots.ox.ac.uk/pascal/VOC/voc2012/#devkit)から落としてきます。

次に、tar ファイルを解凍します。

!tar -xvf "/content/drive/My Drive/VOCtrainval_06-Nov-2007.tar"

/content/ 配下に解凍されました。

[in]
import os
os.listdir("/content/VOCdevkit/VOC2007/")

[out]
['SegmentationObject',
 'Annotations',
 'JPEGImages',
 'ImageSets',
 'SegmentationClass']

中身は ↑ のようになっています。 今回使うのは、JPEGImages(元画像), SegmentationObject(マスク画像) の二つです。

これらの配下に、 'hogehoge.jpg' や 'piyopiyo.png' といった形で画像が入っています。

最終的には、画像を pixel の numpy.array に変換して保持します。

Kaggle の塩コンペの kernel を参考に実装していきました。

img_path = "/content/VOCdevkit/VOC2007/JPEGImages"
mask_path = "/content/VOCdevkit/VOC2007/SegmentationObject"
import os

def get_idx_name(path):
  idx = os.listdir(path)
  idx_name = []
  for i in range(len(idx)):
    idx_name.append(os.path.splitext(idx[i])[0])
  return idx_name

まず、画像ファイル名の拡張子以外の部分を抜き出します。↑

[in]
img_idx = get_idx_name("/content/VOCdevkit/VOC2007/JPEGImages")
mask_idx = get_idx_name("/content/VOCdevkit/VOC2007/SegmentationObject")
print(len(img_idx), img_idx[:3])
print(len(mask_idx), mask_idx[:3])

[out]
5011 ['006473', '008023', '009659']
422 ['000661', '005859', '009950']

↑ を見ると、segmentation と対になっている元画像が422枚しかないようです。 segmentation 画像のある元画像を抜き出してみます。

[in]
img_has_mask_idx = set(img_idx) & set(mask_idx)
img_has_mask_idx = list(img_has_mask_idx)

print(len(img_has_mask_idx), sorted(img_has_mask_idx)[:3])
print(len(mask_idx), sorted(mask_idx)[:3])

[out]
422 ['000032', '000033', '000039']
422 ['000032', '000033', '000039']

これで使いたい画像のインデックスを集めることができました。 次にこれをもとに画像を取得して pixelの numpy.arrayにしたものを df[img], df[mask] というカラムに格納します。

まず使うライブラリを宣言して

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
import seaborn as sns
sns.set_style("white")

%matplotlib inline

from keras.preprocessing.image import array_to_img, img_to_array, load_img
train_df = pd.DataFrame()
train_df["images"] = [np.array(lod_img(img_path + "/{}.jpg".format(idx))) / 255 for idx in sorted(img_has_mask_idx)[:100]]
train_df["masks"] = [np.array(load_img(mask_path + "/{}.png".format(idx), color_mode="grayscale")) / 255 for idx in sorted(mask_idx)[:100]]

こんな感じになります。

[in]
train_df.images[0].shape, train_df.masks[0].shape

[out]
((281, 500, 3), (281, 500))

このままだと、縦横の長さが異なるので一旦縦に合わせてリサイズします。 コードは、塩コンペのカーネルにあったものを流用しています。

from skimage.transform import resize

img_size_ori = train_df.images[0].shape[0]
img_size_target = 101

def upsample(img):# not used
    if img_size_ori == img_size_target:
        return img
    return resize(img, (img_size_target, img_size_target), mode='constant', preserve_range=True)
    
def downsample(img):# not used
    if img_size_ori == img_size_target:
        return img
    return resize(img, (img_size_ori, img_size_ori), mode='constant', preserve_range=True)
[in]
img_resize = downsample(train_df.images[0])
msk_resize = downsample(train_df.masks[0])

img_resize.shape, msk_resize.shape

[out]
((281, 281, 3), (281, 281))

揃いました。

あとは、plt.imshow()したら終わりです。お疲れ様でした。

plt.subplot(1, 2, 1)
plt.imshow(img_resize)

plt.subplot(1, 2, 2)
plt.imshow(msk_resize)

f:id:kaeru_nantoka_py:20190125032916p:plain


結び

野生のデータを取得して、過去コンペのソースを頼りに欲しい形にデータを整形し、データセットを作ることができました。 train, mask 420枚づつと少々物足りないですが、augmentation などで水増しすることなどを含めて遊んでいこうと思います。

ありがとうございました。

[おまけ] 筆者が、 plt.imshow()と間違えて、plt.plot() してしまった時の写真。

f:id:kaeru_nantoka_py:20190125032815p:plain

おぞましすぎる。。

julia 言語に入門してみた。 (2019/1/11)

かえるるる(@kaeru_nantoka)です。

今回は julia 言語を Jupyter notebook 上で扱えるよう環境構築をしたので備忘として残しておきます。

環境 **

PC : MacBook Air
OS : macOS High Sierra ver 10.13.6

how to **

$ brew cask install julia
$ julia

bash 上で上記コマンドを叩きます。
私の場合は、install した時点で環境変数に登録されていましたので、
すぐに $ Julia でインタラクティブ・セッションに入れました。

julia > ]
(v1.0) pkg > add Conda#master
(v1.0) pkg > add IJulia

julia > のモードに入ったら、] を叩きます。
するとさらにモードが変わるので、残りのコマンドを叩いて完了です。

$ jupyter notebook


f:id:kaeru_nantoka_py:20190111014522p:plain

比べてみる **

julia の特徴はとにかく計算が高速らしいです。

中学校で習うレベルの簡単な計算問題を for 文で回してみました。
まずは、 python

import time
from tqdm import tqdm

start = time.time()

def f(x):
    y = 2 * x + 1
    return 3 * y

for i in tqdm(range(50001)):
    print (f(i))

end = time.time()

print("{} sec".format(end - start))

f:id:kaeru_nantoka_py:20190111023436p:plain

約6.5 sec ... 微妙...100万ループとか気合いの入ったコード書けばよかったですね笑(チキってしまいました。)

それでは、次に julia

@time for i in 1:50000;f(x) = 3(2x+1);println(f(i)); end

f:id:kaeru_nantoka_py:20190111022303p:plain

約1.4 sec 4~5倍も差がついてますね。早いです。

そしてちゃっかり、julia の別な特徴である
「数式をそのままかける(ものもある)」

を盛り込みました。

f:id:kaeru_nantoka_py:20190111024159p:plain

数式チックにかけると言っても、数字がカッコの後ろに来てはいけないなどの簡単なルールがあります。

感想 **

環境構築が簡単 & kaggler だと馴染みの深い人も多かろう Jupyter notebook で実験できるのはとっつきやすいなーという印象でした。

計算の速さを活かして kaggle の前処理なんかに使えていけたらなと思っております。

ちなみに、Jupyter notebook の ju は julia の頭文字らしいです。
https://en.wikipedia.org/wiki/Project_Jupyter

それでは、ありがとうございました。

Confusion Matrix の復習をしてみた。 2018/12/18

かえるるる(@kaeru_nantoka)です。

今回は、私が今朝まで参加していた通称 PLAsTiccコンペ
PLAsTiCC Astronomical Classification | Kaggle)で大変お世話になった、
Confusion Matrix (sklearn.metrics.confusion_matrix — scikit-learn 0.20.1 documentation)

について復習したのでその備忘として書いていこうと思っております。

ソースコードは、私の github に残しているのでよろしければご覧になってください。

https://github.com/osuossu8/myEDAs/blob/master/plasticc/confusion_matrix.ipynb

*****

( i ) Confusion Matrix とはなんぞや

このような図を描画してくれる便利メソッドです。

f:id:kaeru_nantoka_py:20181218225533p:plain
PLAsTiCC コンペでの私の best model の Confusion Matrix

簡単に言うと分類問題で、test label と prediction label とで、何を何に分類しているのかが格子状になっていてひと目でわかる描画メソッドです。

PLAsTiCC コンペは たくさんある星のデータを15種類に分類するのが課題でした。

コンペ中は、
New Confusion matrix | Kaggle

というような discussion スレッドが立ち、上位陣のモデルでは何を正しく分類できており、何を正しく分類するのが難しいのかを知ることができ、大変参考になりました。

( ii ) 動機

今回の執筆の動機は、シンプルに言うとまた使えるように整理しておきたかったからです。
実はこの PLAsTiCC コンペで散々お世話になったこのメソッド、 コンペ期間中はコピペで、中身を理解せずに使用しておりました。
コピペのままじゃあ次につながらぬ。と言うことでおさらいがてらまとめてみようと思った次第です。

( iii ) 本題

はい、今回は定番中の定番、アヤメのデータセットを使って復習してみました。(一度やってみたかった)

アヤメのデータセットは、花弁や茎などの長さといった特徴から 3種類に分類する基本的なデータです。
分類に使用したモデルは XGBoost です。

import numpy as np
import pandas as pd
import warnings
warnings.filterwarnings('ignore')

import matplotlib.pyplot as plt
import seaborn as sns 

import xgboost as xgb

from sklearn import datasets
from sklearn.model_selection import train_test_split

使用するライブラリを import して

# Iris データセットを読み込む
iris = datasets.load_iris()
X, y = iris.data, iris.target

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1111)

params = {
        # 多値分類問題
        'objective': 'multiclass',
        # クラス数は 3
        'num_class': 3,
}

# 上記のパラメータでモデルを学習する
clf = xgb.XGBClassifier(**params)
    
clf.fit(X_train, y_train)
    
# テストデータを予測する
y_pred = clf.predict(X_test)

# 精度 (Accuracy) を計算する
from sklearn.metrics import accuracy_score
print(accuracy_score(y_pred,y_test))

accuracy は 0.97 とかでした。

アヤメのデータセットは ndarray の形で与えられているので、DataFrame に変換しておきます。

y_test_df = pd.DataFrame(y_test)
print(y_test_df[0].unique())

y_pred_df = pd.DataFrame(y_pred)
print(y_pred_df[0].unique())


で主役の Confusion Matrix です。

def plot_confusion_matrix(cm, classes,
                          normalize=False,
                          title='Confusion matrix',
                          cmap=plt.cm.Blues):
    if normalize:
        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
        print("Normalized confusion matrix")
    else:
        print('Confusion matrix, without normalization')

    print(cm)

    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=45)
    plt.yticks(tick_marks, classes)

    fmt = '.2f' if normalize else 'd'
    thresh = cm.max() / 2.
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        plt.text(j, i, format(cm[i, j], fmt),
                 horizontalalignment="center",
                 color="white" if cm[i, j] > thresh else "black")

    plt.ylabel('True label')
    plt.xlabel('Predicted label')
    plt.tight_layout()


# http://scikit-learn.org/stable/modules/generated/sklearn.metrics.confusion_matrix.html

from sklearn.metrics import confusion_matrix

# Compute confusion matrix
cnf_matrix = confusion_matrix(y_test_df, y_pred_df) # 引数に先ほどの df を渡す...(a)
np.set_printoptions(precision=2)

class_names = list(y_pred_df[0].unique()) # 正解ラベルを定義 ...(b)

# Plot non-normalized confusion matrix
plt.figure(figsize=(5,5))
foo = plot_confusion_matrix(cnf_matrix, classes=class_names,normalize=True,
                      title='Confusion matrix') ...(a) (b) を渡す

これで以下のような画像が得られます。

f:id:kaeru_nantoka_py:20181218231632p:plain


1.00 となっている label 0 と label 1 は 100% 正しく分類できており、0.94 となっているところは、label 2
を正しく分類できた確率が 94% , 残りの 0.06 は、正解ラベル 2 のものを間違えて ラベル 1 と予測しちゃったのが 6% あるよ。という見方をします。


( iv ) まとめ

結局ソースコード自体は kernels のものを丸々 パクった 参考にした形になりましたが、
うまく基本データセットで応用できたのできちんと身についたかなと思います。

ありがとうございました。

$gcloud コマンドがどうしても効かない時の tips. 2018/12/18

お久しぶりです。かえるるる(@kaeru_nantoka) です。

今回は、私が2ヶ月ぶりに GCPGPU インスタンスを立てようとした時につまづいたことと、それを脱することができた解決法を記していきます。

根本的な解決法ではないのですが、藁にもすがりたい. そんな時にお役に立てれば幸いです :)

〜今回のケース〜

OS:macOS High Sierra 10.13.6
SDK : google-cloud-sdk-196.0.0-darwin-x86_64.tar
shell : bash

GPU で計算回したいな〜」
「いまはやりのくらうどなるものをいちどさわつてみむ」

はい、このように考えて、

macOS 用のクイックスタート  |  Cloud SDK のドキュメント  |  Google Cloud

ここにたどり着いた方はたくさんいらっしゃると思います。
私もその一人でした。

ここを覗くとありますね、問題の一文が。そう。

f:id:kaeru_nantoka_py:20181218005832p:plain

そして、こう。

f:id:kaeru_nantoka_py:20181218005927p:plain
ローカルの bash で gcloud コマンドが効かなかった図

💢💢ローカルで $gcloud コマンドが効かないんだけど💢💢


path が通っていないんだろうな〜と思い、環境変数を云々してみたものの応答なし。。

環境変数むつかしい・・・

〜〜今回の解決法〜〜

shell までのフルパスでコマンドが叩けます。

f:id:kaeru_nantoka_py:20181218010328p:plain
指定zone の利用可能な設備を確認できるコマンドを叩いた図

よくよく考えたら当たり前なのですが、ちょっと感動しました。

〜おまけ〜

cloud shell というGCP のプラットフォーム上で専用の shell を起動できます。 gcloud, datalab(GCD), gsutil(GCS) などGCPの各サービスで使えるコマンドのパスがデフォルトで通っている shell です。幸せになれます。

以上、ありがとうございました。

「深層学習を用いた株価予測の分析」宮崎・松尾(2017)を読了して

かえるるる(@kaeru_nantoka) です。

 

最近AI関連の技術論文を読むのにハマっておりまして、発見や思ったことを文字として残しておこうかなと思ったので書いていきます。

 

第1弾はこちらです。

https://www.ai-gakkai.or.jp/jsai2017/webprogram/2017/pdf/1112.pdf

以下、当論文 と表記します。

 

概要

画像認識で頻繁に使われる技術を CNN を株価予測に応用してみた。

 

といった内容で考察されてます。

 

発見

1. CNN を画像データ以外に対しても適用できるということ。

 

CNN自体は以前から知っておりました。

この技術を使って 顔認識AI内蔵のLINE BOT を作成し、30人ほどの方に使って頂いたこともあります。

 

一般的に CNN について説明がなされる場合、

当論文の 図1 で示されるような概念図を用いて説明されます。

 

「人間の網膜の仕組みを機械的に再現し、コンピュータに処理させる」という理系的背景がなくても直感的に理解できるもので、私も漏れなくそのように認識しておりました。

 

従って「CNNで株価予測」とはじめて聞いたときは ??? だったのですが、当論文でも言及があるように

i ) 株価の値動き自体を画像データに落とし込む

i i ) 入力データをそのまま画像データと同様に扱いインプットとする

 

というように考えられることを知りました。

 

2. 当論文では、9:00のデータをブレが大きいアウトライナーとして処理しておりました。

 

以前証券会社に勤めていた私はこの点にささやかながら疑問を感じました。

 

株価予測の過去データの有用性は、当論文でも言及があるように市場関係者がテクニカル分析(過去の値動きを参考に経験則で導き出された予測手法)を使用していることから一定の価値があるとされます。

 

午前9時は、寄り付きといい株式の売買が開始される時間です。

 

よって「寄り付きの時間の値動きにブレがある」という事実もまた将来の株価予測を導き出すための1パラメータになり得るのではないか

と考えていたからです。

 

データ分析のプロの知見とかつて市場関係者として勤めていた者の細やかな経験則とで1つの事象に対する考え方の相違がとても新鮮でした。

 

まとめ

技術論文を読むと学びが多いです。

特に、最初に関連研究や研究史に触れた上でその論文のトピックがどうその流れを変化させうるのかが簡略に述べてあります。

また、当該技術の簡単な実装法、比較対象としてどの技術が有用かなどその分野のバックボーンがない私にとっては宝の山のような情報源でした。

 

これを機会にこういった論文を読んでみようと思った方が増えると嬉しいです。

ありがとうございました。

 

Google Cloud Datalb で kaggle の画像コンペ用の画像データを扱えるようにする。 2018/09/28

かえるるる(@kaeru_nantoka)です。

 

今回は、有料のGPUインスタンスが立てられる、 Google Cloud Datalab 環境で

kaggle の画像コンペ用の大容量の画像ファイルを扱えるようにするプロセスについて書いていきます。
以前、無料でGPU を扱える Google Colab で似たようなエントリを書いたのですが、Datalab の GPUインスタンスでは幾分勝手が違いました。ということで備忘として残していきます。

 

今回のゴール **

(写真A)
 f:id:kaeru_nantoka_py:20180928232720p:plain

からの

img = load_img("TGSsalt/train/hoge/fugafuga12345.png")

train_df = pd.read_csv("TGSsalt/train.csv")

で、エラーにならず読み込めるようになることです。

手順 **

1. zip ファイルをドラッグ&ドロップで持ってくる。

2. zip ファイルと同ディレクトリに notebook を立ち上げる。

3. !unzip コマンドでファイルを展開する。

********


1 )
写真A の上部真ん中あたりに、 upload と書かれたところがあります。
ここを押すと ファイルをアップロードできます。

kaggle の画像ファイルは大容量なので、「容量が大きいですよ!」という旨のポップアップが出ますが、それほど時間もかからずアップロードできます。

2 )
今回のポイントです。

最初私は、デフォルトで存在するディレクトリの datalab/notebook/ というところに 新規notebook を立ち上げ、意気揚々と以下のコマンドを叩きました。

../datalab/TGSsalt.zip #画像がたくさん入っているディレクトリを固めた zipファイル

すると「そのようなファイル、ディレクトリはないですよ〜」と言われました。
はい、 パスが通っていないのです。


Google Colab では、drive/My \ Drive というところにマウントされるので、
drive/My \ Drive/hoge/fuga でパスを通すことができました。

ということで根本的な解決策ではないですが、同一ディレクトリ上に notebook を立ち上げて、ことなきを得ました。

3 )

(写真B)
f:id:kaeru_nantoka_py:20180928235548p:plain


写真の通りです。
こちらは Colab に比べると光の速さで(気持ちの問題です笑)展開されました。

まとめ **

実際に画像がうまく読み出せている画面キャプチャはあるのですが、コンペ期間中なので控えておきます。
私と同じ事象ではまったどなたかの一助になれば幸いです。
以上、ありがとうございました。

Happy Kaggling !