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

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

エルピクセルさんの論文読み会で初LTをした感想。

こんばんは、kaerururu (@kaeru_nantoka) です。

今回は、エルピクセルさんにてありました、[画像処理&機械学習] 論文LT会 #5 https://lpixel.connpass.com/event/138687/ に LT発表者として参加し、2019年の目標であった 「初LT をやる」という目標を達成できたので、その取り組み、感想・反省などを書いていきます。LT やってみたいけどなんか怖くてできないや・・っていう方や、LT といってもネタとかないなぁ といったかつての私のような方の参考になると嬉しいです。


目次

  1. 私とLT

  2. 準備

  3. 反省点

  4. 良かった点

  5. 今回の資料等

  6. 感想


私とLT

私は LT やってみたいなあと上京した去年の 10月くらいから思っていました。

というのもエンジニアの文化として、アウトプットをすることが重要であるということとエンジニアのイベントに多く参加する中で、自分の業務内容・興味関心を短い時間で収められるようにまとめて人前で堂々と発表する姿をかっこいいと思ったからです。

ひょんなことから kaggle の meetup イベントで世界2位のチームの一員として発表することはあったのですが、質問応答やスライドの作成 (チームメイトが作ってくれたフォーマットの中に自分のパートが用意されていて自分のやったことを埋め込む形でよかった。感謝・・!) など自分で色々準備して臨んだ訳ではなく、 他の勉強会で LT 枠で参加しようにもネタがないしなあという日々を悶々と過ごしていました。

そのような折、twitter の kaggler の知人が参加しており楽しそうだったのと、運営の方が絶妙な具合に発表のハードルを下げてくださっていたということもあったので、人に説明できるほど論文を正しく読めるのだろうかという不安も当然ありましたが、えいやっと参加することにしました。


準備

初の LT ということで自分の中では結構準備しました。

・ 取り組み

当日の 2週間前から論文を読み始めました。同時にスライドの表紙も作りました。(<- ここ重要) スライド 7枚程度で良いとのことだったので 1/7 できたと思うと気が楽でした。

また、論文の読み進めかたで自分に合っていた方法として、スライド作成を意識して iPad Pro の GoodNote に絵付きのメモを取りながら読み進めました。このおかげで、スライドの大枠は、ノートを書き写すだけで完了したので随分気が楽でした。(2回目)

さらに5日前くらいに実装込みでブログ記事をアップしました。 たまたま実装もうまくいき、概ね論文の主張通りに行ったのもあり、後述しますが役に立ったので良かったです。

・ 論文選んだ基準

3つあります。

  1. 業務で活かせそう

  2. 解説記事が充実している (<- 重要)

  3. GitHub に実装が落ちている (<- 超重要)

今回選んだテーマはモデルの蒸留ということで、業務で BERT を扱っているのですが、良い精度が得られる一方でモデルサイズ 500MB と重く実運用上少し不便だったりします。BERT の精度をある程度保ったまま軽いモデルにできればという気持ちでその道で割と古いものを選んだ次第です。

LT 初めてということなので、ある程度理解してから発表したいと思い、もとの論文を読んでつまづいた時のために解説記事が充実しているものを選びました。

せっかく論文発表するからにはと思って実装にチャレンジしました。いち kaggler として kaggle のデータを使って実証実験することにしました。とはいうものの、文章を元に正しく実装できるかわからなかったので GitHub の実装の有無を確認しました。


反省点

実際に発表してみて色々反省点がありました。

・ スライドに書くべき内容が書ききれていないように感じた

他の発表者さんのスライドに書かれているような内容で自分のスライドに書かれていないなあと思う内容 (論文で使ったデータセットの説明など) が間々あり、自分の経験不足が知れて良かったです。

・ 旧式の MacBookAir (2013) を使用していた

プロジェクターの接続機器が TypeC なのが一般的なこともあり、接続確認と進行に少しごたつきがあったので、MBP 買わないとなあと思いました。

タイムマネジメントが微妙だった

発表用資料の用意や簡単な練習はしていたもののやはり人前で話す緊張からしどろもどろになってしまいました。

・ 他発表者の予習ができず、せっかくの他の方の発表の内容を十分に理解および質問ができなかった。

abstract と conclusion くらいは読んで質問内容くらいはあらかじめ考えておいたほうが自分の身になるのかなーと思いました。

良かった点

・ あらかじめ実装を公開していた

質問で回答に詰まった時に実装を見ていただくことで「あ〜」と納得していただけたので良かったです。

・ あらかじめブログを書いて公開していた

スライド作成は不慣れな一方でブログは歴1年くらいになるので慣れていました。自分の伝えたい内容、構成の整理に役に立ちました。

・質問をしていただけた

質問をしていただく中で新しい発見がありました。LT の中で温度付き softmax という「普通の」softmax 関数に渡す x を重みパラメータ temperature で割った値 x/temperature を渡す verision の softmax 関数 ( temperature = 1 の時に「普通の」softmax 関数と同じになる) をご紹介したのですが、この式は ボルツマン分布 [

http://www.mech.kagoshima-u.ac.jp/~nakamura/bussei/thermo-statistics.pdf

] といい物理の世界では、温度付きのものが一般的で温度パラメータ temperature = 1 の特殊ケースの方を機械学習では採用しているらしいといった議論も (私はポカーンでしたが) 行われ、とても勉強になりました。


今回の資料等

・ スライド

https://www.slideshare.net/yuyaosujo/lpicel-paper-lt5

・ ブログ

https://kaeru-nantoka.hatenablog.com/entry/2019/07/20/020920


感想

・ 今回は初 LT をすることができた。

・ 論文を一本完読し、実装・ブログにまとめる・LT発表まですることで自信がついた。

・ 何より論文を読むことが楽しいと思えるようになった。

このような素晴らしい機会があるので、(人気が高まってきてはいますが) またうまいこと滑り込めたらこちらの読み会に参加したいです。

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

モデルの蒸留を実装し freesound2019 コンペで検証してみた。

こんばんは、kaerururu (@kaeru_nantoka)です。

今回は、Distillation the Knowledge in a Neural Network (2015) [ https://arxiv.org/pdf/1503.02531.pdf ] を読みました。

そして、kaggle freesound2019 コンペで実際に使ったデータとモデルを用いて蒸留の検証をしたので、これについて書いていこうと思います。

通しの実装は、kaggle 上に公開カーネルとして載せていますので合わせてご覧ください。

Distillation : [ https://www.kaggle.com/kaerunantoka/distillation-implementation-with-freesound2 ]

Simple (比較用) : [ https://www.kaggle.com/kaerunantoka/simple-cnn-image-size-299 ]


目次

  1. 参考

  2. 概要

  3. 本記事の目標

  4. 結果

  5. 実装の説明

  6. 結論

  7. 考察

  8. まとめ


参考

実装の参考

https://github.com/moskomule/distillation.pytorch/blob/master/hinton/utils.py

温度付き softmax 関数の理解する際に参考

https://qiita.com/nkriskeeic/items/db3b4b5e835e63a7f243

KL divergence を理解する際に参考

https://qiita.com/ceptree/items/9a473b5163d5655420e8


概要

まず、蒸留の基本的なお気持ちについてご紹介します。

一般的に、教師データをこれ以上増やせないという制約の元でより良い精度を実現するためにはモデルのアンサンブルという手法が取られます。 この手法はより良い予測を得られる一方、合計のモデルの容量がとても大きくなり、しばしばデプロイ環境 (モバイルデバイスなど) で利用するのに不便が生じます。

そこで、より良い予測を得られるアンサンブルモデルの出力を別な軽量なモデルの学習にうまいこと利用しようという発想です。

以下、

・教師モデル (アンサンブルモデルなど容量が重いがより良い予測が得られる。)

・生徒モデル (より軽量なモデル。教師モデルの出力も学習に使う。)

とします。


本記事の目標

これまでの説明を聞いて、「より良い予測が得られるが、モデルが重い... 」

スーパーアンサンブルモデルを送りつけられる kaggle の host を想起する読み手のかたも多くいらっしゃると思います。

そこで本記事では、モデルの蒸留を実際に筆者が取り組んだ kaggle freesound2019 コンペで使用し、金メダルをとったスーパーアンサンブルモデルから、本コンペでベースラインとなったシンプルな CNN モデルへと知識を継承させる実験をしました。


結果

実験の結果以下のようになりました。

CV Private LB 順位 合計容量
A 0.74435 10位 (金) 188MB (94 * 2)
B 0.75014 0.59023 190位 18MB
C 0.74545 0.60895 185位 18MB

model A : 教師モデル, InceptionV3 * 2 のアンサンブル

model B : 生徒モデル1 (素)

model C : 生徒モデル2 (教師モデルの出力使う)

LB スコア… 私の実験ではおよそ 0.018 の上昇で、順位だと5位アップ相当でした。教師モデルのスコアが 0.744 なことを考慮すると、イマイチパッとしないように見えますが後ほどこれに対する私見を述べます。

CV スコア … 少し下がっています。実はこれもまた蒸留の1つの特徴で、overfit に抑制がかかるとされています。言い換えると、蒸留によってある種の正則化の効果が得られます。これは当論文の第6章に書かれておりますのでご覧ください。

ファイルサイズ … 教師モデル Inception V3 はそれぞれ 94MB で合計 188MB でした、一方で生徒モデルの CNN は 18MB でした。

より強力なモデルの力を借りることで、軽量なモデルの予測が少し良くなっているのがみて取れます。


実装の説明

ポイントは In[23] の以下の2箇所です。

for x_batch, y_batch in progress_bar(train_loader, parent=mb):
            
    teacher1 = model1(x_batch[:, 0, :, :].view(-1, 1, 299, 299).cuda())
    teacher3 = model3(x_batch.cuda())
    lesson = ((teacher1 + teacher3) / 2)
    preds = model(x_batch.cuda())
            
    kl_loss = F.kl_div(F.log_softmax((preds / temperature)), F.softmax((lesson / temperature)),
                               reduction="batchmean")
    loss = criterion(preds, y_batch.cuda()) + lambda_factor * (temperature ** 2) * kl_loss
    model = Classifier(num_classes=num_classes).cuda()
    
    model1 = model_1ch_incep
    model1.load_state_dict(torch.load(f"../input/inception-1ch-dameoshi-aug/weight_best{binary_number}.pt"))
    model1.cuda()
    model1.eval()    
    
    model3 = model_3ch_incep
    model3.load_state_dict(torch.load(f"../input/inception-3ch-dameoshi-aug/weight_best{binary_number}.pt"))
    model3.cuda()
    model3.eval()

蒸留では、教師モデルと生徒モデルの出力の分布を似せるように学習させます。そのため、同じ iter の中で prediction をするために上のように一気に model と重みを load します。

そして得られた両方の出力は通常の softmax 関数ではなく温度付き softmax 関数 (softmax_with_temperature) に通します。

というのも蒸留で利用したい教師モデルが学習した情報というのは、出力値の分布 (何々と何々は間違えやすいといったもの)であるからです。通常の softmax 値だと正解ラベル以外の確率が限りなく0に近い値が割り振られてしまうため、正解ラベルを利用するのとさして変わらず不適当なので、温度 (=重み) をつけてあげて低い確率を重視しようぜというお気持ちなのです。

それらの'ならされた'出力たちを KL divergence Loss 関数に渡して、これを加味した CrosEntropyLoss を最小にしようという流れです。

KL divergence は2つの確率分布の類似具合を測る指標で、2つの確率分布が完全に一致したら (=lossがなくなったら) 0 になる特徴があります。

これを最小化しようというのはなるほど納得という感じです。


結論

教師モデルが学習した知見をモデルサイズのより小さい生徒モデルに受け継がせることで何もしない生徒モデルに比してより良いスコアを得る、という蒸留の望む効果を kaggle の過去コンペで実際に使用したアンサンブルモデルに対して適用しても一応の結果が得られました。


考察

教師モデルのスコア 0.74435 に対して、生徒モデルのスコアは 0.60895 と効果は限定的なのではないかと感じます。このことについて私は、教師モデルの精度に近づくように生徒モデルが学習しているというより、生徒モデル本来の伸び代の限界までしか精度が伸びないといった側面があるのではないかと考えました。例えば、教師モデル SE-ResNeXt で生徒モデル 3層のMLP で学習させたケースにおいて、生徒モデルのMLPが SE-ResNeXt に匹敵する表現力を得られる、というのは考えにくそうであるなという所感です。

実際当論文では、入力のパラメータを変えた同じモデル 10 個のアンサンブルを教師モデル、同じモデルのシングルモデルを生徒モデルとし、そのままのシングルモデルよりよい精度が得られたといった文脈で書かれていました。


まとめ

・ CV は下がる (ある種の正則化効果) が、LB は微増 (汎化性能の向上) した。

・ 軽量なモデルの予測精度向上への寄与に成功した。

・ 一方で、教師モデルに近い表現力を持った生徒モデルを利用しないケースでは精度は向上するものの効果は限定的であるという示唆が得られた。

以上3点、今回私が実験した限りではわかりました。

特に 「CV が下がる (が成功している)」という点が 'Trust CV' を信条とする多くの kaggler にとって実際のコンペで利用するのに心理的な壁になりそうだと思いました。一方で、昨今の kaggle では限られた推論時間にスーパーアンサンブルモデルをいかに詰め込むかといったことに注力するシーンが散見されます。本実験では扱いませんでしたが、同じモデルの複数アンサンブルの予測に近いものを同一モデルのシングルモデルに出力させるような当論文の手法は、限られた時間を有効に活用しなければならない現代 kaggle においての1つの解足りうるのではないかと思います。

以上誤り等に気づかれましたら、優しくご指摘くださいますようよろしくお願いいたします。 ありがとうございました。


追記

2019/07/24 「実装の KL divergence loss の計算をしているところで、なぜ softmax ではなく log_softmax を使用しているのか?」 という質問をいただきました。 結局質問者の方が、F.kl_div(input, target) 関数に渡す input は log 形式である必要がある旨を docs を調べて教えてくださいました。 https://pytorch.org/docs/stable/_modules/torch/nn/modules/loss.html ありがとうございました🙇‍♂️

単語 ID 列を長さでソートしてミニバッチ内で padding する。

こんばんは、kaerururu (@kaeru_nantoka) です。

今回は、kaggle meetup #6 での tks さんの発表にもありました、「 (batch 内で) batch 毎に padding する」の実装にプラスして ID列を長さでソートしたものを batch 内で padding できるようにした実装を公開しようと思います。

誤り、もっと良い実装等ございましたらご指摘いただけると幸いです。m( )m

何が嬉しいの?

ID 列の長さでソートしたものを dataloader に渡し、batch 内で padding すると 初めの方は、系列長 0 や 1, 2 などが渡ってくるので padding した後の長さが 1 や 2 になり無駄がなくなるので処理速度が爆速になります。

昨今の kaggle の NLP コンペ (NLPに限った話ではないですが..) では、学習は local でもやっても良いが推論は kaggle kernel 内で済ませる必要があるタイプが多く、いかに個別の model にかかる時間を節約し、規定の推論時間内に model を詰め込みアンサンブルするかが勝負の分かれ目になります。

デメリット

model の training 時には学習にかかる時間を大きく減らす効果が期待できます。一方で、以下の論文  

https://www.anlp.jp/proceedings/annual_meeting/2017/pdf_dir/A7-1.pdf

でも指摘されているように、長さの似た文章は似た情報を持っていることも考えられるため同じミニバッチに詰め込んで学習させることで model が偏った知識を学習してしまうことで精度が少し落ちてしまう恐れもあります。

実装

「 batch 毎に 0 padding して系列長を揃える 」までは、以下の kernel の実装を参考にしました。

https://www.kaggle.com/kunwar31/pytorch-pad-sequences-per-batch/notebook

あとは系列の長さで sort した x_train (sorted_x_train) とそれに対応する順番に並べ替えた y_train (sorted_y_train) を dataset に渡すだけで OK です。

sort した x_train と y_train を入手する関数を以下のように用意しました。

[[長さ], [x_train], [y_train]] のように配列を作り、1番目の配列(長さ)でソートしたのち、単体の配列に詰め直して返してます。

from operator import itemgetter

def get_sorted_list(lengths, x_train, y_train=None):
    tmp_list = []
    if y_train is not None:
        for l, m, n in zip(lengths, x_train, y_train):
            tmp_list.append([l, m, n])  
        tmp_list.sort(key=itemgetter(0))
        sorted_x_train = []
        sorted_y_train = []
        for i in tmp_list:
            sorted_x_train.append(i[1]) 
            sorted_y_train.append(i[2]) 
        return sorted_x_train, sorted_y_train
    else:
        for l, m in zip(lengths, x_train):
            tmp_list.append([l, m])  
        tmp_list.sort(key=itemgetter(0))
        sorted_x_train = []
        for i in tmp_list:
            sorted_x_train.append(i[1]) 
        return sorted_x_train

class TextDataset(data.Dataset):
    '''
    Simple Dataset
    '''
    def __init__(self,X,y=None):
        self.X = X
        self.y = y

    def __len__(self):
        return len(self.X)

    def __getitem__(self, idx):
        if self.y is not None:
            return [self.X[idx],self.y[idx]]
        return self.X[idx]


class MyCollator(object):
    '''
    Yields a batch from a list of Items
    Args:
    test : Set True when using with test data loader. Defaults to False
    percentile : Trim sequences by this percentile
    '''
    def __init__(self,test=False,percentile=100):
        self.test = test
        self.percentile = percentile
    def __call__(self, batch):
        if not self.test:
            data = [item[0] for item in batch]
            target = [item[1] for item in batch]
        else:
            data = batch
        lens = [len(x) for x in data]
        max_len = np.percentile(lens,self.percentile)
        data = sequence.pad_sequences(data,maxlen=int(max_len))
        data = torch.tensor(data,dtype=torch.long).cuda()
        if not self.test:
            target = torch.tensor(target,dtype=torch.float32).cuda()
            return [data,target]
        return [data]
collate = MyCollator(percentile=100)

lengths = torch.from_numpy(np.array([len(x) for x in x_train]))

sorted_x_train, sorted_y_train = get_sorted_list(lengths, x_train, y_train_final)

train_dataset = TextDataset(sorted_x_train, sorted_y_train)

train_loader  = torch.utils.data.DataLoader(train_dataset, batch_size=512, shuffle=False, collate_fn=collate)

まとめ

Quora や jigsaw の solution を見ていて実装したいと思っていたのですが、日本語での解説記事など探しても見当たらなかったので公開しようと思った次第です。

(batch padding sort kaggle でググって公開カーネルにたどり着いた)

余力があれば、

1 ) 精度面でどれだけ悪化するのか

2 ) どれだけ早くなるのか

を比較実験した記事も書きたいなと思います。

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

Kaggle Master になりました!

こんばんは、kaerururu (@kaeru_nantoka) です。

今回は、3人チームで参加した先日 Freesound Audio Tagging 2019 にて2枚目の金メダルを獲得し、Kaggle Master になることができたので私が kaggle (というか機械学習) を始めてから今までの 10ヵ月を振り返ってみようと思います。

最近 Kaggle 始めたけど titanic の次何すればええの? っていう質問を受けることも多くなったので、私の取り組みが少しでも参考になれば嬉しいです。


目次

・ Titanic, HomeCredit

・ 塩, Two Sigma

・ Quora

・ Petfinder

・ Freesound

・これから


2018年 8~9月 -- Kaggle に出会う, Titanic, HomeCredit --

  • できるようになったこと :
    1. kernel を folk して submission.csv を出力する,
    2. カラム同士をコネコネして新しい特徴を生み出して score の変化を楽しむ
    3. RandomForest
  • できなかったこと : テーブルの結合、Groupby

当時プログラミングをはじめて半年やそこらで周りにプログラミング友達が2, 3人しかいなかった私は Twitter をはじめました。 #プログラミング初心者さんと繋がりたい, や #100DaysOfCode といったハッシュタグもあり所謂プログラミングアカウントみたいなものがどっと増え始めた頃でした。

当時プログラミングアカウント界隈では、バズらせるのを目的に rubyonrails や Django のようなフレームワークで Webアプリを作り、Heroku に公開するのが流行っていました。私も例に漏れず、バズるアプリを作って一発当てようとネタを探している中で、Qiita で見つけた「AI(keras) で画像認識をする Webアプリ」(アイドルの画像分類機の作成) 記事を読み、これ面白いんじゃね?と見よう見まねで実装し、web にあげるのではオリジナリティがないので LINE BOT に仕立てて公開したところそこそこ反響がありました。

4値分類問題を設定し、Google の画像収集API でそれぞれのラベル 100ずつくらい集めました。この時、ディープラーニングで云々することの楽しさとデータを手動で集め、整形することの大変さの両方を知ることができました。 ディープラーニングにせっかく興味が湧いたものの、素人が予測モデルを作るのに必要なデータを自力で集めるのも面倒大変なところがあったので無料で大量のデータを扱えるサイトを探していたところ kaggle に出会いました。

そこでは 公開Kernal や Discussion というやその道の先人たちが知見を惜しまず公開しており、近くにディープラーニングを教えてくれる人などいない私が、独学するのに適した環境でした。

Titanic 問題を使って Kaggle の取り組み方を説明したサイト(日本語)などを参考に見よう見まねで取り組んでいきました。 また、当時アクティブだった HomeCredit コンペにも参戦してみました。 これは、金融機関の顧客データ(複数テーブル)を使い、借り入れ顧客がきちんと借金返してくれるか予測する問題でした。SQL なども使ったことがなかったので 複数テーブルにまたがった情報の取り扱いや、同じID の人が複数の情報を持っていたりと何が何だかわけがわからないまま終わりました。

Kaggle はわけがわかりませんでしたが #100DaysOfCode のタグをつけてその日の取り組みを呟くと優しい人がいいねくれたのでちょっとしたモチベーションになり続けることができました。


2018年 ~10月 -- 塩, Two Sigma --

  • できるようになったこと :

    1. ハイパーパラメータをいじって score の変化を楽しむ
    2. Keras の層を (わけもわからないまま) 追加する
    3. GCP をはじめて使う
    4. LightGBM を使う
    5. 複数テーブルの groupby --> concat
    6. 都度都度更新されるハイスコア Kernel と手元の folk してきた kernel との差分について考える
  • できなかったこと :

    1. Pretrained とか Finetune とか
    2. Predefined モデルの利用

取っ掛かりが Karas を用いた画像判別アプリの作成だったこともあり、 画像コンペに参加しようと引き続き塩コンペに参加しました。

適当な Kernel を folk (U-Net + Residual module)してきて最初は seed とか epoch数, train_test_split の比率などをいじったり最新のハイスコアカーネルとの差分についたり考えてはスコアの変化を楽しんでいました。 この頃には discussion も読むようになり、みんながやっている計算重くね? Kernal でできないぞ・・と思い立ち GCPで初のGPUインスタンスを立ててみたりしました。結局どんなインスタンス立てればいいかわからず、CPU 2core + NVIDIA TESLA P100 * 2 とかいうアホなインスタンスを立て、計算を回すも一向に計算が終わらず、無料$300クーポンを溶かすなどしてました。 discussion に出てくる ResNet34 がどうとか理解できないまま、これ以上は計算機が足らん・・となり撤退。

次は、元証券勤務ということで同じ期間に始まっていた Two Sigma コンペ(株価予測コンペ)に参加しました。 新聞記事のテキスト情報と直近10年分の株価情報という2つのテーブルが与えられていました。この時の公開カーネルをみて groupby や concat を扱えるようになりました。金融のドメインが多少あったので移動平均線ゴールデンラインといったドメイン由来の特徴量を作成し実装して LGBM に投げるなどして初のPublic銀圏に到達するなど(*1month to go) Twitter に呟いてはいいねがもらえることが楽しくてやって行きました。 リークやげきつよカーネルの登場で 2度LBが崩壊し、モチベーションが保てなくなり撤退。ただ基本的なことは結構身についた気がします。(気がする)


2018年 ~12月 -- PLAsTiCC コンペ --

  • できるようになったこと :

    1. ソロ銅メダルを入手!
    2. 巨大データを扱う (20GB)
    3. wikipedia で得た知識を特徴量にする
    4. ライブラリの実装を見に行って手元でそれっぽく再現実装する
    5. discussion の「情報」をコードにする
  • できなかったこと : GCP で適切なインスタンスを立てる

Twitter で色々な kaggler をフォローするようになった頃、TL の強強な方々が参加されるという PLAsTicc コンペに私も参加してみることにしました。この頃の私は 「LightGBM に何かしらの特徴量を渡して出てきた予測値を to_csv して submit する」ことには慣れていたのでひたすら特徴量のアイデアをひねり出すことに執心しました。

そのため discussion で皆が使っているらしいライブラリ (tsfresh) を Kernel で利用しようとして落ちて使えなかった時はドキュメントを見に行って使えそうな関数を手元で再現してみたり、wikipedia やよくわかる天体観測みたいな web ページみては特徴を作っていました。

これがなかなか面白く、特徴量を思いつくたびに LB を更新し、一時は銀圏まで行きました。 結局は public で80位くらいで Finish し、shake down の洗礼を受け Private 103位のなんとか銅メダル獲得で終えました。


2019年 ~2月 -- Quora コンペ --

  • できるようになったこと :

    1. ソロ銀メダルを入手!
    2. 初の NLP
    3. 初の PyTorch
    4. Kaggle Expert になった
    5. 過去類似コンペを参考に特徴量を生成
  • できなかったこと :

    1. 高速化等の solution にある工夫
    2. NN レベルでの工夫

やったことのない領域にチャレンジしてみようということで自然言語処理に挑戦する目的で Quora コンペに参加しました。

最終的にはソロ銀メダルを獲得することができましたが、今思うとげきつよカーネルに過去類似コンペでやっていた text特徴の追加と NG辞書の拡充といったくらいの変更しかできなかったこと、評価指標が f1 score というちょっとした閾値の違いで差が出るものであったことこともあり運の要素が強かったなという所感ですが、何より自力で Expert にまで慣れたのは嬉しかったです。


2019年 ~3月 -- Pet コンペ --

  • できるようになったこと :

    1. 初チーム参加、初入賞
    2. 初の Multi-modal コンペ
    3. PyTorch に慣れた
    4. Predefined model の利用

またまたやったことのないことにチャレンジしてみようということで、複数データソース(teble, text, image) かつ外部データありの Pet コンペに当初はソロで参加しました。

このことについては別のエントリでも書きましたが、ひとりで銅メダルけん上位くらいまで行ったタイミングでつよつよな kaggler のみなさまとチームを組ませていただくことになりチームとしてガンガンスコアを伸ばして行くことができました。

一方で個人の取り組みでいうと、自分が最初に伸ばしていた model を強化することと、チームメイトの一人が discussion でこんな情報出たと共有してくれたもののうち、優先順位の低いものを1つ1つ潰していくことの両輪でした。最終的な weight は 0ではないくらい (シングルスコアはかなり悪かったが、抜いたら抜いたでスコアが落ちる)ということでチーム準優勝という輝かしい実績に反して、個人の力の及ばなさを強く実感する出来事でした。

とはいうもののこの pet コンペを通して、つよつよ kaggler の取り組みや思考、コンペを進める上でのスケジュール感、そして何より、自分の取り組みに対してフィードバックがもらえたことが自分の成長を加速させました。Wodori (その時のチーム名)のみなさまには感謝しかないです。

この Pet コンペでの取り組みを通して PyTorch でいい感じにできるようになったことが今の仕事や、後述の音声コンペにとても活きました。


2019年 4~6月 -- 音声コンペ --

  • できるようになったこと :

    1. 金メダルを入手!
    2. Kaggle Master になった
    3. PyTorch かなり慣れた (個人比)
    4. 論文を元に augmentation を実装
    5. Predefined の model のソースをいじって実装

理論を強化しようと参加したとある勉強会でツイッターのアカウント名と顔が一致した某氏と意気投合し、一緒にコンペに参加することになりました。.wav のデータを扱うの初めてだし面白そうという理由で音声コンペを選びました。その実態は画像コンペで個人的には塩コンペのリベンジかつPyTorch で色々やれてよかったです。Shirogane (当時のチーム名) のみなさまありがとうございました。

画像コンペということもあり、よく耳にする 〇〇 Net を片っ端から実装してみたり、同時期にやっていて先に終わった壺コンペの solution をみながら試していない Network や augmentation, Layer を実装してみたりするなど自分の中にかなりの知見が貯まりました。一方でチームでの weight はというとパッとせず、総合 7位金メダルという素晴らしい結果とは裏腹に、正直なところ自分の中で少なからず悔しい想いも残りました。この気持ちとチームで得られた知見を糧に精進していくつもりです。


これから何するの

tier 的には Kaggle Master になることができました。しかし、その瞬間瞬間で Kaggle Master たる働き・貢献ができていたのか? と自問自答するとうーんというのが正直なところです。(Weight は少なかったかもですが、投入時間は負けず劣らずだったはずです・・) 従って、まずは真の Kaggle Master を目指して以下の内容に取り組んでいこうかなーと思っています。

  • コード資産の拡充、画像、NLP コンペで使うベースライン notebook の作成

  • NLP コンペの solution であった network を再現実装して GitHub に草を生やす

  • NLP コンペの solution の手法リストを作成する

  • NLP コンペは(できるだけ)ソロ参加する

  • discussion 投稿、BaseLine Kernel 投稿

今までかなり場当たり的にやっていたのですが、そろそろ自分のやり方のようなものを確立したいなと思っています。特に NLP のコンペではどのコンペでもやっているような共通の処理があったり, 画像コンペでは predefined model の使用して色々な augmentation を試して~ などやることの大筋が変わらないなど一度きれいにまとめておくと、あのコンペの何位の手法と試すぞ!と行った実験を高速に回せるようになったり、どのコンペに出ようかなと思った時のとりあえずの 1st sub がすぐに実装できるのは判断の上で重要だと思います。

またせっかく業務で自然言語処理に取り組んでいるので、NLP系のコンペはしばらくソロで参加して力をつけたいと思っています。

最後に tier 的には Master になったのでできる範囲でコミュニティへの貢献できるように努めていこうと思っています。kaggle コミュニティだけでなく kaggler-ja での発言も増やしていきたいなあ。


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

Xonsh はじめました。

こんばんは、かえるるる(@kaeru_nantoka)です。今回は、興が乗ったのでみんな大好き某くし氏激推しの shell 'xonsh' のセットアップを行いました。控えめにいってサイコーです。

xonshrc は基本的に某ブログのコピペで問題ないと思いますが、私の環境では丸々コピペで ls 系統のコマンドが全部利用できなくなるという事故を経験したので ls の alias 部分をこう書き換えたらうまくいったよということを残しておきます。

ほぼコピペですが、私の xonshrc と zshrc は以下のリポジトリにおいています。

https://github.com/osuossu8/dotfiles


参考

https://vaaaaaanquish.hatenablog.com/entry/2018/06/22/194227


つまづいたところ

ls 関連の alias 部分です。 以下の設定のまま source ~/.xonshrc すると・・・

aliases['ls'] = "ls --color=auto"
aliases["l"] = "ls -l"
aliases["lf"] = "ls -f"
aliases["ld"] = "ls -d"
aliases["la"] = "ls -la"
aliases["ll"] = "ls -l"

このようなエラーが出て、無事 ls が利用できなくなりました。

ls: illegal option -- -
usage: ls [-ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1] [file ...]

上の部分を以下のように書き換えて source ~/.xonshrc したら復活しました。やったぜ。

aliases["lt"] = "ls -ltr -G"
aliases["l"] = "ls -ltr -G"
aliases["la"] = "ls -la -G"
aliases["ll"] = "ls -l -G"
aliases["ls"] = "ls -G"

まとめ

・ 某くしさんのチュートリアル記事で xonsh のセットアップができた。

・ 色とか補完がいい感じでサイコーだった。

・ xonshrc だと環境によっては ls が使えなくなるのでソースを少しいじった。

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

「 Sports Analyst Meetup #2 (#spoana)」に参加してきました。~ 安西先生 LTがしたいです。 ~

こんばんは、かえるるる(@kaeru_nantoka)です。 今日は、「 Sports Analyst Meetup #2 (#spoana)」に参加してきました。 こちらのイベントに参加(聴講)するにあたって、目標を1つ自分に課しました。その観点に沿って聞いてメモしたものの中から抜粋して、そのまとめを綴っていこうと思います。


目次

・どんなイベントなの?

・どんな課題感で望んだの?

・各発表について

・まとめ


1 どんなイベント?

スポーツデータを題材に 実務 / 研究 / 趣味 で分析をしている方々による発表 ・ LT を聞ける会。 #2 では、実務(プロチームの戦略立案に役立てるための分析)でスポーツデータにを分析している方 2名のロングトークとLT 10本という大満足の内容だった。

https://spoana.connpass.com/event/126625/


2 どんな課題感で望んだの?

「自分が LT をすることを想定して、どのようにデータを用意し、どのような流れでまとめているかを生の LT を聞くことで知る」

ことを目標に、相棒の iPad Pro 9.7 インチにメモを書きなぐりました。

このような課題を自分に課した経緯としては次の通りです。

自分のアウトプットの機会の1つとして、せっかく(機械学習)エンジニアをやっているわけなので、LT をやってみたいという兼ねてからの願望があった。

-> やってみよう。・・・そもそもデータがない。

-> データを集めよう。・・・そもそもデータってどうやって(方法・観点・サンプル数)集めるんだっけ???

-> \(o^)/

ということで他の方の生の発表を聞いてみたいと思いました。

以上の目標を達成するために、観点を、

( i ) 概要・手法

( i i ) データ取得方法

( i i i ) データ数

( i v ) 期間

( v ) 感想

に分けて、メモしていきました。。メモが追いつかなかったものなどは - (ハイフン)にしています。

その中から一部抜粋して、ご紹介します。


3 各発表について

LT #1 戦略シミュレーション分析 (バドミントン)

( i ) ショットをハイリスク・ローリスクに分け、各ショットから得られる得点の期待値を数式として、またそのショットの組み合わせを戦略として定義し、その条件下でシミュレーション。その結果からどの戦略が優位であるかを示した。

( i i ) なし

( i i i ) なし

( i v ) なし

( v ) データがなくてもここまでの発表ができるのか。と自分の視野の狭さを痛感。 問題設定とアプローチは、学部自体にやったゲーム理論や効用最大化問題に近いと感じた。 競技の特性、プラスの効用とマイナスの効用をどう定義するかなど難しさはあるがぜひ挑戦してみたいと思った。


LT #2 大相撲優勝決定巴戦に見る不合理な分布 (相撲)

( i ) 相撲の優勝決定戦という、実力が拮抗 (両者の勝率が 0.5 と仮定)している時の理論値と標本値の比較、適合度の検定(カイ自乗検定)を行い、実力・・拮抗してるんじゃなかったっけ...? (=八○長の存在)を数的根拠を以って示唆した。

( i i ) -

( i i i ) 142

( i v ) 1958年 (今の巴戦のルールが確立した年) ~ 2014年

( v ) 理系の出身の方なら当たり前の手法なのかもしれないが、個人的に理論分布と標本分布の差異を数的に示す手法は私の目標の観点から、とても参考になった。サンプル数も142と自力でアノテーションできる数だなと思った。


LT #3 高校セーリング部のための「データ活用ツール」制作秘話 (セーリング)

( i ) 高校ヨット部をデータ分析の力で強くしよう。しかし、航路、船の傾きなど気象条件やルール上の制約からデータ集めるのが大変 -> どうするか という内容。

( i i ) スマホで集める。

競技の特性上、センサーやコンパス、防水性など多機能かつ高性能な分析デバイスが必要 -> スマホでよくね?

( i i i ) 大変

( i v ) 大変

( v ) やりたい分析対象はあるのに、変動パラメータが多すぎてデータを集めるのに苦戦していた発表者の方。自分の欲しいデータを効率的に集めるためのスマホアプリの紹介もされててすごかったです。一方スマホをデータ収集ツールとして使えばいいじゃないという観点にはハッとさせられた。以前 u++ さんが、iPhone のヘルスケアツールから歩行データなどを xml で取り出せるみたいな記事を書かれていたが、気づいていないだけでそういった魅力的な生データはその辺りに落ちているのかもしれない。


LT #5 富士山登山競争を定量的に評価する (登山)

( i ) 富士山登山競争という競技のつらさを構成する要素を数式で定義。そして、安静時やフルマラソン完走時、高尾山登山時のつらさも同じ式で表して定量的に評価した。

( i i ) 富士山登山競争の過去競争タイムデータから、区間ごとの距離・高低差・平均タイム を運動の消費カロリー(METS)に換算して使用

( i i i ) 1レース分?

( i v ) 1レース分?

( v ) フェルミ推定を彷彿とさせる手法だった。オチも用意されておりプレゼンって感じだった。


LT #7 ボール保持力・奪取力マップから見るロシアW杯2018 (サッカー)

( i ) ボール保持力・奪取力を可視化、国や選手の特性をうまくプロットしていた。

( i i ) Statsbomb 社がオープン化しているデータセット (.json)

Competition : FIFA World Cup 2018

Event : "Pass", "Dribble", "Miscontroll", "Duel"

Location : PosX, PosY

Output : Success, Failure

( i i i ) -

( i v ) FIFA World Cup 2018

( v ) ゲームの視聴者として経験的に把握していた、国や選手の特性を実際の試合データをプロットすることで可視化できており凄かった。(語彙)


4 まとめ

本日 spoana に参加してきた。

「LTをやってみたい。だが何をどんな観点で発表すればいいのか、そもそもデータってどうやって収集するのかわからない」という自分の中にある課題に対し、「その手がかりになる情報を生の発表の中から持ち帰る」という目標を課した。

結果、ぼんやりと聞くより多くの情報をインプットできた(気がする。)し、 自分が LT をするまでに何をすべきか道すじがクリアになった(気がする。)

ぜひ、自分も LT をして良質なアウトプットをする習慣をつけたい。

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

PetFinder.my Adoption Prediction で準優勝しました!

こんばんは、kaerururu (@kaeru_nantoka) です。

今回は、5人チームで参加した Kaggle の通称ペットコンペで準優勝し、金メダルを無事獲得できたのでそのポエム簡単な経緯と役割分担のような話を綴っていきます:)

技術的な話(解法など)は、kaggle の discussion に

Summary by upura

kaeru part description

などなど追記されていくと思いますので、そちらをご参照ください。


経緯

きっかけは「かえるさんの転職活動成功のお祝いをしよう」と u++ さんがお声かけしてくださったことでした。

他に誰か誘おうとなったときに kaggle の meet up で ynktk さんと3人でお話ししたことを思い出し、お声かけしたところ OK. すぐに日程調整し、u++ さんが予約してくださった焼き鳥居酒屋「をどり」で会食。

Kaggle のイベントでお会いしたのがきっかけなのでもちろん話題は kaggle .

その時私はソロで参加しており、銅メダル上位くらいの順位でした。

「かえるさんは今何のコンペに参加しているのですか?」

この質問に対し、ペットコンペの簡単な概要(table, image, text を用いたマルチモーダルなコンペであること)、チームで参加してみたいのでぜひやりましょう!という旨をお伝えしました。

「え〜 0 sub だけどいいんですか?」と言っていたが、彼らとチームを組んだら絶対に楽しいと思ったのでそのまま鋭意勧誘、その場でスマホから invite してそのまま accept してもらいました笑

チーム名は、飲み会の会場の名前からとって「Wodori」。簡単にはわからないだろうし、なんか響きと綴りが気に入りました。のちに綴りが Wodori ではなく Odori であることに気づく・・笑

二人の加入で、銀圏まで上昇。当時はお二方とも何やかんや忙しい&キャッチアップの時間が欲しいということで、パッと思いつくアドバイスをいただきながら kaeru が実装するというようなスタイルだった。これで銀と銅を行ったり来たりするくらいで落ち着いた。ちょうど銀圏にいる時、東京大学の入学式に関するツイートを発見し、入学式...新歓!! ということでツイッターでふざけて Wodori チームメンバー募集の旨を呟いた。

何と反応があった。初期に参加していたが 1ヶ月ほどペットコンペの戦線から離れていた takuoko さんだった。

「takuoko さん・・・?!」顔パスだった。 4名になった Wodori は takuoko さんにチーム名の由来を伝えることなく邁進。忙しかったお二方も徐々に(というか急激に)コミット量が増えた。

結果4人でアンサンブル ( kaeru + ynktk takuoko u++) を駆使し金圏手前までいった。

もうひと伸び・・!と思っていたところに開始1週間ほどで金圏手前まで駆け上ってきたペンギンアカウントの gege さんが現れた。u++ さんにより、gege さんのチームマージに成功。

何と彼はシングルで金圏手前まで来ていた。

gege さんのソースをマージし、試行錯誤する中で金圏に到達。

そのまま、金圏で finish.

コンペ期間中は、夜中まで slack が動いているなどそれはそれは楽しい時間だった。

わかったこと

  • 当初 0 sub であってもチームマージしてデータを見るとがっつりやっちゃうのが kaggler だった。

  • チーム戦はめちゃくちゃ勉強になるし、楽しい。

  • チームメイトに迷惑をかけられないといういい緊張感がある。


役割分担

  • kaerururu リーダー、自分のパートをひたすら改善, 手が回らないところを拾う
  • u++ 司令塔, discussion追う, 類似過去コンペの検証、external特徴作成, データクレンジング, u++特徴量作成, catboost検証, 猫カフェ
  • ynktk 提出コードの大枠作成, NN 検証 postprocess、高速化、Stacking
  • takuoko ソースコードマージ、NN実装、LGBM
  • gege gege part の改善, 実務でのデータ分析経験を活かしたinsight で作成した特徴作成

上で書いたのはほんの一例ですが、いい具合に得意分野や使える時間のバランスが取れていたと思います。


ソースコードの管理など

ペットコンペは、kernel 限定コンペという kaggle 上で提供されている実行環境 ( = Kernel ) で書かれたコードにより出力された提出ファイルしか提出できないコンペでした。

従来のコンペでは、 各々がローカル環境やクラウド環境など各々環境を構築し、それぞれが計算し、 npy, feather... などの形式で保存した特徴量ファイルを融通し合い、誰か一人がそれらの特徴を load して model の計算を行うなどしてチーム運営がなされていたと聞きます。(私自身チーム戦が初めてだったので伝聞口調です。)

一方、カーネルコンペでは、特徴量の生成〜モデリング(アンサンブル)〜 postprocess までを一気通貫で行う(しかもGPUカーネルの実行時間制限の2h に収めないといけない)必要があり従来のチーム戦に慣れていたチームメイトは勝手が違うために戸惑っていたようです。

また notebook 形式で書かれた kernel は実行単位でセルが分かれていることもあり、まとまりがない書き方をしても気にならないためソースコードマージが大変だったとチームメイトの takuoko さんは言っていました。

結果的に、kaeru (notebook), gegeさん(noteboook), ynktk & takuoko & u++ 諸氏 (script) で途中まで各々進め、マージするタイミングでとてもとても見やすい ynktk さんの script ( with 文で実行単位ごとに区切るような形で記述 )をベースに takuoko さんが鋭意マージしてくださり、3000~4000行の大作になりました。

それ以降は、with 文で区切られた自分のパートの中を書き換え --> 自分のモデルのスコアを確認 --> 良さげだったら、全体で回してサブミット する流れでやっていきました。

今回のコンペを通じて、script 記法という慣れない記法に慣れることができ(むしろ終盤は script 万歳状態だった)こう言った形での成長もあるんだなーといった感じです。


感想

私は初めてのチーム戦だったのですが、最高の仲間と競技で世界2位になるという最高の結果を得られたのでとても最高な2ヶ月ほどでした。

もっともっと勉強して、また Wodori でコンペに出よう!となったらいいなあと思う深夜3時でした。

以上ポエムでした。