天色グラフィティ

技術ちっくなことを書きます

ICNR: Sub-Pixel Conv使用時のcheckerboard artifactを防ぐ初期化

f:id:ejinote:20190729202002p:plain

ニューラルネットワークで画像を拡大(アップサンプリング)する際、Transposed ConvolutionやSub-Pixel Convolutionという手法を使います。

しかし、これらの手法を用いた場合、拡大した画像に格子状の模様(checkerboard artifact)が発生することが知られています。

以前のLTのスライドも併せてご覧いただけると良いかと思います。

checkerboard artifactの主要な原因として挙げられているのは2つです。

1つ目はfilter overlapです。filter overlapとは、kernel_sizeやstrideの設定によっては出力に寄与する画素数が異なってしまう(フィルタが重なってしまう)現象のことです。 特にTransposed Convを利用した場合に発生します。

Sub-Pixel Convolutionの場合、原理上出力に寄与する画素数が異なることはありませんが、kernelの初期化によってcheckerboard artifactが発生することが指摘されています。これが2つ目の原因です。

Sub-Pixel Convolution使用時、初期化によるcheckerboard artifactを防ぐ方法として、ICNRという初期化方法が提案されています *1。 ICNRを利用することで超解像タスクにおいて(向上幅はわずかですが)綺麗な画像が生成されることが報告されています。

今回はPyTorchでICNRを実装し、ICNRの動きについて簡単な可視化を行いました。

ICNRの挙動

ICNRの基本的な発想は「Sub-Pixel ConvolutionでNearest Neighborを再現する」です。

Nearest Neighborで拡大した画像にはcheckerboard artifactは出ないので、それを初期値として学習を始めることでcheckerboard artifactを抑えて学習をすすめることができると期待されます。

Sub-Pixel ConvolutionはConv2dPixelShuffleからなります。Conv2dの初期化を下図のように行うことで、PixelShuffleした後の画像がNearest Neighborと同様になります。

f:id:ejinote:20190728165735p:plain

直感的ではないと思いますので、これを実験によって確かめてみます。

実験

設定

32x32のRGB(3チャネル)の画像を nn.Conv2d で畳み込み、12チャネルに増やした後 nn.PixelShuffle で並べ替えて64x64のRGB画像を作るという問題設定にします。

f:id:ejinote:20190728154213p:plain
元画像

元画像は以下のようなコードでPyTorchで読み込み可能な形式に変換します。

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

import torch
import torch.nn.functional as F
from torch import nn

image = Image.open('dog.jpg')
image = np.asarray(image, np.float32) / 255

x = image[np.newaxis, :, :, :].transpose(0, 3, 1, 2)
x = torch.from_numpy(x)

通常の初期化を行った場合

out = nn.Conv2d(in_channels=3, out_channels=12, kernel_size=3, stride=1, padding=1)(x)
out = nn.PixelShuffle(2)(out)

f:id:ejinote:20190728155037p:plain
通常のConv2d→PixelShuffle

ご覧のとおり、それはそれはキレイなcheckerboard artifactが出ていることが分かるかと思います。もちろんこれは全く学習を行っていない状態なので、学習を進めていけば徐々に消えてはいきます。

ICNRで初期化した場合

ICNRの実装例は以下のとおりです。2倍に拡大する場合は出力チャネル数を1/4で初期化したあと、チャネル方向に4倍に引き伸ばしたものをConv2dの初期値として使います。

通常であればreshapepermuteを組み合わせて行列演算だけで書くのですが、初期化処理は何度も呼ばれるものではないので可読性重視でfor文を使っています。

def ICNR(tensor, scale_factor=2, initializer=nn.init.kaiming_normal_):
    OUT, IN, H, W = tensor.shape
    sub = torch.zeros(OUT//scale_factor**2, IN, H, W)
    sub = initializer(sub)
    
    kernel = torch.zeros_like(tensor)
    for i in range(OUT):
        kernel[i] = sub[i//scale_factor**2]
        
    return kernel

使用例です。conv.weight.data.copy_を使用してICNRで生成した初期値を与えています。

conv = nn.Conv2d(in_channels=3, out_channels=12, kernel_size=3, stride=1, padding=1)
kernel = ICNR(conv.weight)
conv.weight.data.copy_(kernel)

out = conv(x)
out = nn.PixelShuffle(2)(out)

f:id:ejinote:20190728162641p:plain
Conv2d(ICNR)→PixelShuffle

checkerboard artifactは出ていないことがわかります。

ICNRで初期化したConv2dを適用した後にPixelShuffleで拡大を行った場合、畳み込んだものをNearest Neighborで拡大したのと同様の処理が実現できることが確認できました。

まとめ

ICNRを利用することで、学習の初期からcheckerboard artifactを抑えて画像の拡大を行えることを確認しました。

この記事は技術アウトプットもくもく会の成果物です。ご参加いただいた方々、ありがとうございました! 次回もたくさんの方に参加いただけると幸いです。

実験に使用したnotebookはGistにアップロードしてあります。

Sub-Pixel Conv with ICNR · GitHub

Sub-Pixel Convolutionについて#5【画像処理&機械学習】論文LT会!で発表しました

エルピクセル株式会社で開催された #5【画像処理&機械学習】論文LT会! で発表しました。 題材に選んだのはSub-Pixel Convolutionで、関連する論文をいくつか紹介したという感じです。

ちょっと前だけど定番な論文から最新の論文まで、幅広い論文が紹介される良い会でした。運営のfam_taroさん、okamotoさん、ありがとうございました。 次回は残念ながらすでに締切が過ぎているようですが、次次回以降でタイミングが合えばまた参加させてください!

資料はSpeaker Deckにアップロードしています。7分の発表枠だったのですが、文量の調節をミスってだいぶオーバーしてしまったので反省です。

他の方の発表メモ (資料は随時追加します)

When Does Label Smoothing Help? (Appianさん)

  • よく使われる割にはあまり理解されていないよね
  • penultimate layer(dense layerの1つ前)の出力を可視化して確認
  • hard labelを使った場合logitが極端な値を取るし、間違ったラベル同士もかけ離れてしまう
  • knowledge distillationとの組み合わせはよくない
  • データの種類に関する言及はあったか?
    • ラベルノイズがある場合、学習に寄与すると考えられる
  • 情報量が失われるというのは、2次元のmappingを見てのことか?
  • label smoothingは他のラベルの情報も持たせているのだから、分布は広がるのでは?
    • lossが極端な値を取らないので、penultimate layerも広がりが小さくなる

Unreproducible Research is Reproducible (紺さん)

  • 再現性を細かく定義した
  • シード、データセット、ハイパーパラメータ、順番などを変えると結果は大きく変わってしまった
  • 1つのシードで比較しただけだと結論は出せない
  • exploratory researchが多いが、empirical researchが増えるべき
  • この論文にネガティブに引用されている論文はあるか?
    • この論文中にはないが、そういう言及をしている論文もある
  • ばらつきを考慮できる評価指標があるといいですよね
    • random seed averageはよくやる

Move Evaluation in Go Using Deep Convolutional Neural Networks (msnrさん)

  • Alpha Goの前身となる論文
  • CNNで盤面状態を評価する
  • 現在の状態の評価値と、次に取るべき行動を出力する
  • 参加者の段位を持つchennelが存在するところが面白い
  • 段位をchannelで表現するメリットはあるのか?
    • アーキテクチャをいじるアプローチではなく、汎用的に使えるアプローチを好んでいるのではないか

Gait Recognition via Disentangled Representation Learning (twtwrさん)

  • 歩き方は人に固有
    • ユーザーの協力が不要で、遠くから判定できるが、服装や手荷物に大きく左右される
  • 外観と歩様を分離するアプローチ
  • 以下の3つの部分からなる
    • 歩様特徴から画像を復元
    • 歩様特徴に外観特徴が流れ込むのを抑制する部分
    • 別の人物を識別できるようにする部分
  • 人間的にはもつれていても、モデル的にはもつれていないことがあるのでは?
    • 最初に「これが異なっていても同じに分類されてほしい」というような願望がある。それにあわせていくためには情報を分離する必要がある

Interpretation of Neural Networks is Fragile (klnWさん)

  • NNの予測に対する解釈性へのAdversarial Attack
  • 予測結果を保ちつつ、解釈だけを変更することができる
  • 法律・医療など、意思決定を重視する領域では重要
  • DNNの決定境界は区分的に線形なので、ロスに対する勾配の向きを変えることが容易
  • どの次元が寄与したかだけではなく、どの学習データが予測に寄与したかという解釈もハックできる
  • オリジナルとの非類似度が大きくなるように更新し、距離が大きくかつラベルが一緒になるものを採用
  • じゃあどうすればいいのかも付録に書いてある
  • 自然に乗るノイズでも判断根拠がブレることが起こりうるか?
    • あり得る。今出ている特徴マップがたまたま出ている可能性があることを考慮しなければいけない

Mask Scoring R-CNN (fam_taroさん)

  • bounding boxが綺麗についていて、予測も正しいのに、セグメンテーションがうまくいかないケースがある
  • 分類の質とマスクの質は相関がなかった
  • Mask R-CNNにマスクのIoUを予測するサブネットワークを追加して精度向上
  • セグメンテーション一般で評価指標を予測するサブネットワークを追加するアプローチは有効かも
  • dice lossを追加するのとは何が違うか分からない

Learning to Generate Synthetic Data via Compositing (phalanxさん)

  • 自然な合成画像を作る手法の提案
  • 画像を合成するネットワークと、合成された場所を見破るネットワークをE2Eで学習
  • 本物の画像と合成画像を見分けるdiscriminator
  • synthesizer networkは前景をどう変換して重ねるかを出力

Distilling the Knowledge in Neural Network (kaerururuさん)

  • アンサンブルモデルの出力を蒸留したら軽量モデルで表現可能
  • 教師生徒の両モデルについて、温度付きsoftmaxのKL divergenceが小さくなるように学習を進める
  • 温度付きを使うのは、どのクラスとどのクラスが間違いやすいかも学習したいので、温度パラメータをつけることで出力をマイルドにする
  • 温度はどう決める?
    • 論文中ではいくつか試して選んでいた

【質疑応答付き】Kaggle Tokyo Meetup #6 に参加しました

f:id:ejinote:20190713175727p:plain

DeNAで開催された、Kaggle Tokyo Meetup #6の参加記です。YouTube配信の視聴を含めるとMeetup参加は3回目ですが、回を増すごとに情報量も発表内容の多様性も増しているように思います。

本当にすばらしい発表を皆様ありがとうございました。僕も発表やLTでコミュニティに貢献していきたいと思います。

この記事では、各発表について僕自身が面白い・知らなかったと思ったポイントを中心にまとめ、可能な限り出典などのリンクをつけています。 内容を網羅しているわけでは必ずしもありませんので、もとの資料を併せてご覧になることを強くおすすめします。素晴らしい資料なので。

それでは、15000文字を超える長い記事ですが、最後までお読みくださると幸いです。

Opening Talk (threecourseさん)

  • イキっている人もちゃんとバリデーションを切っている
  • Kaggle Masterもまぁ間違える。カバーしている知識も違う
  • いまはソリューションの発表が多いが、それはそちらのほうが準備が楽だから。Tipsなども歓迎。アウトプットしていきましょう

Petfinder 2nd Place Solution (Wodoriチーム)

  • 特徴量作成から学習、予測まで2hに収めるkernel onlyコンペ
  • 3種類の特徴量を作成し、4モデル(NN/LGBM×2/XGBoost)のridge stacking
    • LGBMしか使っていない人が多かった。モデルの多様性が差別化ポイント

takuoko part

  • テキストの処理
    • 前処理を施したあと、BOW/tf-idfをして、それを行列分解にかける
    • できるだけembeddingにおさめて、embeddingの平均を特徴量にした
  • 画像の処理
    • Kerasのdensenet121とInceptionResNetV2を採用
    • KerasとPyTorchで精度が全然違う
  • テーブルの処理
    • 基本的なアグリゲーション
    • 平均との比、平均との差などの特徴を作成
    • カテゴリの共起を取り、行列分解
    • 交差項の作成
    • 絵文字の情報やマレーシアの州の情報などをexternal dataとして利用
  • Kernelは間違っていることもあるので、自分で考えよう
    • (これはほんとそう!)
  • 特徴量は合計4000-5000ほど作成。importanceのTOP1000を利用
  • NNはAdam/CLRを利用

kaerururu part

  • CNNの出力、doc2vec、tfidfを利用した
    • これらはすべて高次元。低次元にいろいろ潰してみて、スコアが伸びたものだけを利用
  • 画像のサイズ、幅、高さを特徴量にする
  • 「cute」で検索して出てきた犬猫画像データセットで学習したモデルで予測したcute特徴を入れたが、効かなかった
    • クレンジングが足りなかったからでは?
    • (アイディア自体は面白いので、外部データを利用できるコンペではやってみるといいかも?)
    • (そこそこめんどくさそう)

gege part

  • はじめてのコンペだった(!?)
  • Kernelをベースに粛々と進めた
  • testっぽくないtrainデータを10%程度削ったが、精度向上はしなかった
  • 基本なにしてもダメだった

ynktk part

  • 4モデルをstackingした
    • LGBM < Average < Ridge だったのでRidgeを採用
  • Ridgeに入れる前の前処理でランク変換を行った
    • foldごとに予測値の分布が異なりがあったのでは?
    • ランク変換によって予測値分布の差を吸収
    • QWKは閾値に敏感。予測分布の差があると悪影響がある
  • 後処理
    • ImageHashを使って重複画像を探索→train/testで重複している画像はtargetで置き換える

u++ part

  • 泥臭いこと担当
  • クレンジング
    • 綴りの間違いを人力で修正

質問

  • 1位との大きな差はなに?(smlyさん)
    • まじでわからん
    • 外部データが効いたらしいが、再現してみたら全然効かなかった
  • ultimate model作ろうとしたらいまのtrainにoverfitするんじゃ?(smlyさん)
    • 今はロバスト/lightweightなモデルを作ろうとするムーブはあんまりない
    • あくまでボランティアとしてやっているので、他の参加者もそこまでモチベーション高くはない
  • interaction featureは何を意識して作ったの? 普通はビジネスセンスが必要(smlyさん)
    • 今回は総当たりで効きそうなのを試した。列が少ないからいける
    • 全然効いていない特徴量は総当たりの対象から外した
  • ods.aiに有用な情報はあった?(koukyoさん)
    • petfinderのときには、ods.aiにしかない情報はなかった
    • これが話題だから見よう、みたいな情報は取れた。取れてしまった
  • テキストの情報をクラスタリングしたら効く、みたいな話があったが、やった? (pocketさん)
    • やってないです
  • 閾値が大事という話だが、どう決めた? (pocketさん)
  • 実際閾値はprivateでも最適だったの?(onoderaさん)
    • 検証はできていない
    • QWKが0.4くらいになるので、それって全然あたってないよね。タスクとして難しかった
  • 各FoldでQWKの閾値はどれくらい変わるのか? データの分布が違うと閾値はかなり敏感にスコアを変えるのでは? (maxwellさん)
    • ログとしては取っているが、詳しくは調べていない
    • RescuerIDを利用したGroupKFoldを利用した
    • 最終サブミットはFoldの切り方を変えた2つを提出した

iMet 7th Place Solution & 画像コンペのアプローチ (phalanxさん)

壺コンペソリューション

  • 推論だけKernelで回すタイプのKernel Onlyコンペ
  • 2nd stageでテストデータが5倍になるので、それを考慮して提出しなければいけない
  • アノテーションがまぁまぁ雑。ラベルが欠けている画像が多くある
  • class imbalanceがある
  • モデルをひたすら積み続けた。ResNet34も最後まで生き残った
  • ラベルごとに最適なモデルが違ったので、アンサンブルが効くと思った
  • cultureとtagで根本から別々のモデルにした
    • Grad-CAMを見ても見ている画像の部分が違う
    • 全結合層だけ分けるのが普通だが、それだとあまり上がらなかった
    • すべてのモデルにこれをやると時間が足りないので、強いモデルだけやった
  • 蒸留を頑張っていたけど、効かなかった
    • 蒸留をがんばればモデルが小さくなるので推論時間を稼げるのでは?
    • attention transfer (activation-based method)を使った
    • studentのattention mapをteacherのattention mapに近づける手法
  • focal lossとlovasz lossを採用したが、ほんの少し良くなっただけ
  • 頻度が少ないクラスはdropしたが、意味がなかった
    • 過去にGibaがやっていた
  • 長い画像には特に何もせず、resizeして突っ込んだ
    • 上位の人を見ても対処している人はいなかった
  • CNNでstackingした
    • 過去コンペでKeepLearrningがやっていた
    • 1000クラスあるので、全部ridgeはやってられない
    • CNNでモデル間の相関を学習し、denseで特徴間の相関を学習する
  • チームメイトの予測をスタッキングに載せた
  • 1st place solutionの紹介
    • batchsizeを1000-1500と大きい値を設定(ノイズの軽減?)
    • 誤差が大きい画像を弾く
    • ImageNetのpredictionや画像の長辺の長さなどの特徴をLightGBMにかける
  • psuedo labelingとhard example miningをちゃんとやれば精度が上がった

画像コンペのアプローチ

  • yamlを書いたら全部走るpipelineがある
    • 壺コンペはyamlを書き換えつづけるだけ
  • 初日
    • ルールとかOverviewとかをちゃんと読む
    • mean, std, min, maxをRGB, HSVのチャンネルごとに確認する
      • めちゃくちゃ明るい/暗い画像のチェック
    • 画像サイズのmean, std, min, maxなどを確認
    • targetの分布を確認
    • 画像を目で見る
    • resnet18, 34などの小さいモデルを作った後、resnet101, 152に進む
    • optimizerはAdamを使う。 3e-3 〜 1e-4 の範囲をコンペによって変える
    • image_sizeは (mean/2, mean/2) , (mean, mean), (mean*2, mean*2)を試す
  • ベースラインの予測を作ったら、予測を確認する
    • CVとLBの違いや、attentionを可視化
  • サーベイ
    • ドメインの論文が効くことがある
    • 読むだけじゃなくて実装もする
  • パイプラインは作ろう
  • 時間を効率的に使う。学習回している間に論文を読んだりコーディングをしよう
  • 終盤
    • ドメイン特化の論文を読む(10%)
    • アンサンブルに備えていく

質問

  • ラベルが信用出来ないとき、ルールで許されていたらハンドラベリングしたりするか?(kaerururuさん)
    • 1103クラスに対してはハンドラベリングはだるすぎるのでやってない
    • 今回はpseudo-labelingをやれば十分だった
  • optimierをAdam固定にはどんな意図があるか?(koukyoさん)
    • そこは本質的な価値じゃないので、Kagglerとしては本質的なところで戦うべき
  • 蒸留がうまくいかなかったのはなぜ?
    • 予測に対してL2ノルムで最適化した。しかし、出力が小さいところまで合わせる必要はなかった
    • 今回はpseudo-labelingで十分
  • 早い段階からたくさんモデルを作るという戦略か?
    • 最近のコンペはだいたい、多くのモデルを混ぜればうまくいく
    • 今回は特にラベルごとに最適なモデルが違った。ちゃんとそれを確認している
  • CNNでアンサンブルするとき、モデルの並べ順によって差が出るのでは?(Jackさん)
    • 学習時に順番をぐちゃぐちゃにしても学習可能なのでよくわかりません
  • パイプラインについて。1080TiとKaggle Kernelで両方実行可能にするのはどうする?(flowlightさん)
    • Kernelで実行する時は、モジュールをべた張りしている
  • pseudo-labelingについて工夫を教えてほしい(u++さん)
    • LBが最も高くなるような閾値で切ってpseudo-labelとして使う
    • もともとのラベルをhard-label、pseudo-labelをsoft-labelとする。soft-labelの方はlossの寄与を小さくする
  • phalanx-pipelineはどうやって完成した?(koukyoさん)
    • segmentation/detection/recognitionでそれぞれパイプラインがある
    • detectionはmmdetectionというライブラリがあるので、それに似た形にしている
    • コンペごとに進化していっている
    • 作り始めたのはタンパク質コンペのとき。新しいタスクに挑戦する時は、最初はパイプラインが崩壊することもあるけど、そうしたら組み直す

Quora Insincere Questions 10th Place Solution & 昔話 (tksさん)

Quoraコンペの解法

  • 外部データ利用不可のKernel-Only
  • Embeddingが4種類与えられている
    • これをどう使うかがひとつのポイント
  • BERT発表後初めてのNLPコンペ
  • モデル構造はかなりシンプル
    • 層を複雑なモデルを作ったことはない
    • 小さいモデルをアンサンブルさせてスコアを取っている
    • Embeddingの組み合わせで4C2=6個のモデルをアンサンブルしている
  • CVをきちんとすることが勝利の秘訣だった
  • 最初からaveragingすることは決めていたので、averageでのスコアで評価
  • モデル構成が定まるまではtrain/dev/valの3分割を5-foldで行う
    • trainで学習、devで閾値選択、valで評価
    • ここで閾値を何種類かに絞っておく
  • スペル修正はしなかった(面倒だったので)
  • ラベルノイズも多かった
  • モデルの安定化のため、Exponential Moving Averageを利用する
  • Embeddingの扱い
    • concatすると次元が大きくなってしまうので、重み付き平均を使う
    • Projection Meta Embedding
      • concat後低次元に射影して、ReLUする
  • 実行時間制限が大切
    • EMAの更新回数を減らした
    • 長さが近いものを同じバッチに入れると早くなるが、トライしなかった
    • そんなに気分が乗らなかったからだと思う
  • 反省点
    • 長さが近いものをバッチに入れる、は最初に実装すべき
    • statistical feature (質問の長さ、大文字だけの単語数、など)を入れておけばよかった
    • 早期に選択肢を狭めている
  • Local CVを信じれば、たまに良い順位に入れる

昔話

  • Kaggle歴5年以上の人どれくらいいる?→ほんの少し
  • Submission Limitも変わっている。個人的な意見としてはFinal Submissionは1個にしてほしい
  • なにか問題があったら、オープンなフォーラムで話し合う文化は昔からあった
  • 要望・提案があればどんどん出していきましょう

質問

  • QuoraのEMAについてもう一度説明してほしい
  • EMAは学習率を単純に下げるのとは違いがあるのか?(upuraさん)
    • 自分はoptimizerは据え置きでやるようにしている
    • BERTではEMAは全然効かなかったので、チューニングは必要
  • 同じ長さの文を同じバッチに入れるとなぜ早くなるのか?
    • 長さをまとめなかったら最大長でpaddingする必要がある
    • 同じ長さでまとめたら、バッチ単位でpaddingすることができるので早くなる
    • 精度はほとんど変わらないはず
  • Freesoundでやったとき、paddingが長すぎると精度が下がりました(osciiartさん補足)
  • 出るコンペはどういう基準で選んでいる?(koukyoさん)
    • 基本、簡単そうなやつ
  • 今と昔だと上位に行く難易度に違いはあるのか?(pocketさん)
    • 昔の方が断然簡単だった
    • 昔はいけたけど、今は悩んでいる人はたくさんいると思う
    • 昔はツールを作ってるリサーチャーが多かったからそれに勝つにはツールを作るしかなかった(smlyさん補足)

(おまけ)僕の参加記

amalog.hateblo.jp

PLAsTiCC 3rd Place Solution (nyanpさん)

公開してくださっているGitHub

解法

  • 特徴量エンジニアリングが好き
  • 突発天体・変動天体のように、明るさが変わるような天体を見つけたい
  • いままでは漏らしていたけど、LSSTの運用で発見できるようになるはず
  • これまで人類が発見した天体は1万くらいしかないのに、LSSTは10年間で1000万程度発見してしまう
  • 突発天体を早期検出して、後続の観測機器で精度良く観測する
  • LSST自身でも自動分類したい
  • Light Curveから天体を特定する多クラス分類
  • かなりimbalanceなデータセットで、少数クラスは30件程度
  • minority classほど1データの重みが大きいので、sample_weightなどで補正しないと良いスコアが出ない
  • 超新星の爆発のときには観測ができていなくて、残り滓しか見えないようなケースもあるので難しい
  • trainは既存の観測データ、testはLSSTが観測するもの、という問題設定だった
  • ノイズの大きい観測データをどうするかが争点
    • Gaussian Process
    • NN
    • Template Fit
  • Class 99をどうするかもスコアを大きく左右したが、Kernelに準じても金メダルは取れた
  • LSST Science Bookという文献を読むことで、ドメインのエキスパートがどこに注目して分類しているかがわかった
  • マージした時点でnyanpさんは200特徴量だったが、mamasくんは80000個作っていた(!?)。yuvalは1個も作っていなかった(!?!?!?)
  • CNN、LightGBM、CatBoostのアンサンブル
  • CNN
    • 欠損を線形補間/detected=1だけ抜き出して線形補間/最近傍の有効データとの時間差 をCNNに突っ込む
    • 1DConvを数回行い、GlobalMaxPoolingにした後、メタデータの特徴量とくっつけてDenseに通す
    • 時間方向のshiftについてクラスは変わらないはずなので、CNNが効きそうだし、augmentationとしても使える
    • 特徴量なしでも金が取れた(!?)
  • Template Fitting
    • 遅い。テストデータに対しての計算は30日くらいかかった
    • 並列化が効かなかったので、インスタンスを30個立てて30倍速にした
    • コマンドは心をこめて手打ちした
    • sncosmoというライブラリで試せるものだけで数十個ある
    • 全部やった。CVであたりをつけてから、よいものを試した
  • preemptible instanceの牧場管理をがんばった。最終的には60個まで増えた
  • Gaussian Processも試した。時間がかかるのでやっぱり30インスタンス立てた
  • tsfreshやfeetsといった時系列の特徴抽出ができるライブラリを使った
    • ベースラインとしては使える
  • pseudo-labeling
    • class 90, class 42に絞ってラベルを付けた
    • class 99はtestにしかなく、class 99に間違ったpseudo-labelをつけると大きくスコアを落としてしまう。class 99と遠いクラスのみラベルを付けた
  • Adversarial Pseudo Labeling
    • training dataに似ているサンプルを使ってtraining
  • クラスごとに異なる重みでアンサンブルした
    • OOFのpredictionの精度で決めた。サブミット数が残り少なかったため
  • LB Probingでclass 99を決めた
    • one-class SVMなどを利用した通常の異常検知はうまく行かない
    • class 99はどんな天体なのか考えた
      • class 99はすべてのクラスから均等に遠いことはないはず
      • クラスごとに異なる重みを付けてみた
  • モデルの方向性がみんな全然違ったのが良かった

質問

  • Template Fittingのハイパーパラメータはどう決めた?(akiyamaさん)
    • コードが見たい人はopenにしているkernelを見てほしい
    • 時間がなかったので、あまり調整はしていないが、一部のパラメータはちゃんとlsstと設定しないといけない
    • Fittingによって出てくるパラメータをそのまま特徴量として使う
  • 1位との違いは何ですか?(u++さん)
    • 1位はdata augmentationをやっていた。これが一番の差分
    • train dataをtest dataの分布に合わせるため、遠方にシフトさせるaugmentation
    • これをやっていれば1位いけたかも
    • 上位解法のばらつきが大きく、上位の答えをアンサンブルをするだけでスコアが上がる
  • サーバー代はいくらですか?
    • 8コアくらいのcheapなインスタンスをたくさん立てた。トータル5万くらい
    • Seed Averageのために立てたインスタンスを止め忘れ、7万くらい請求された。悲しい
  • CatBoostはなぜ強かった?
    • データにカテゴリ変数はぜんぜんなかった
    • かなりoverfitしやすいデータだった。CatBoostに含まれているsymmetric treeとordered boostingという機構がコンペにマッチしていた
    • ordered boosting
      • t番目のデータに対する残差を計算するとき、t-1番目までのデータで学習したモデルを使う
      • サンプルが少ないときに特に有効
      • 比較した結果としても、ordered boostingが良かった
    • 使う特徴量によってLightGBMとCatBoostでどちらが良いかは変わった
    • 最近はCatBoostも使いやすくなっているので、スモールデータコンペだったら試す価値がありそう
  • データ数が少ないとき、NNはoverfitしやすい。augmentationはどう選んでいる?
    • そのクラスは何に対して不変なのかを考えるべき。cyclic shiftは自然な発想
    • 観測ノイズが載っているので、ノイズを乗せても良さそう
    • そんなにアクロバティックじゃないとは思う
  • psuedo-labelingについて。コードは公開している? OOFでやるなど実装方法もいろいろあるが、どれを使った?(pocketさん)
    • GitHubを公開しているので、どこかに埋まっているはず
    • ラベルを付けた数がtrainの10倍になるくらいにした。基準は実験的に決めた
  • Gaussian Processはどうした?(onoderaさん)
    • fittingして、そのまま特徴量として突っ込んだ。そんなに寄与は大きくなかった
    • 1位はGaussian Processでデータを補完してその波形上で集約して特徴量を作っていた

スポンサーセッション (hoxoshさん)

  • DeNAの事業は多岐に渡っていて、Kagglerが各地で活躍している
  • 合宿(magic camp)に行きました。今度も行きます
  • @DeNAxAI_NEWSをフォローしてください

Neural Network のご機嫌取りがしたい(tawatawaraさん)

  • テーブルより画像のほうがメダル取りやすいのでは?
  • batchsizeが小さいと一部のサンプルに引っ張られがち。batchsizeを大きくしたらlrも大きくする
  • 基本的にbatchsizeは大きく取りましょう
  • lrはLR-RangeTestで決めよう
    • fastaiのライブラリでlr_findとして実装されている
  • 学習率のスケジューリングは正直好みでは? warmupは有効だとは思う
  • 学習率が不変 or AdamならEarlyStopping
  • initializerはscaleを小さめに
  • TuningのためのCourseraもある

質問・コメント

  • fastaiのfind_lrはモデルやデータで良いlrは変わる?(osciiartさん)
    • chainerで自分で実装しているからfastaiのは実はわからない
    • 実際モデルやデータで変わりそうではある
  • scaleを小さくすると学習は安定するが、結果はscaleが大きい方が結果は良くなりそう。回数を打てるならscale大きいほうがよさそう(owrubyさん)
  • batchsizeが大きすぎると汎化性能が下がるのでは? BERTだとそのためのoptimizerがある

kagglerのためのAllenNLPチュートリアル (tamakiさん)

資料

内容

  • 最近はテキストが有害かどうかのコンペが多い
  • かなり分割がうまくいっていて、書いていて気持ちいい
  • DatasetReaderがテキストファイルからInstanceのリストを返してくれる
  • Modelがtorch.nn.Moduleのサブクラスを返す
  • AllenNLPはjsonから実験ができる

質問・コメント

  • NLPコンペで初心者が詰まりがちなところを教えてほしい(u++さん)
    • NNと同様で、学習率どうする?みたいなポイントはある
    • ベースラインを作るまでにはハマりポイントはあんまりない。それ以降何をするかが大事

Freesound Audio Tagging 2019 4th Place Solution (oumedチーム)

  • 医学部6年なので、実はKaggleしてる場合ではない
  • domain adaptationも必要
  • 人間の聴覚はlog-scaleなので、それを反映したlog-melspectrogramが主力
  • スペクトル画像に変換したらほぼ画像分類として扱える
  • 時間方向に圧縮すると意味が変わってしまう
  • 波形とlogmelの両方使った
  • 波形についてはEnvNet-v2を使った
  • MixUp/BC learning
    • 画像と違い、音声は2つの音声が混ざるのはかなり自然
  • cropするより、全長を使ったほうが良かった
    • 最初の方にクラスを決める要素が多かった
  • noisyの使い方がポイントだった
    • 多くの参加者はpretrainとして使ったが、OUMedではマルチタスク学習として使った
  • soft pseudo-labeling
    • マルチラベルに対応できないし、分布の差によって信頼性が高いラベルが得られない
    • 疑似ラベルを0, 1にしない
  • 長さの異なるモデルを複数用意してaveragingするのが有効だった
  • 外部ラベルデータダメなのにハンドラベリングOKだった→1位はそれ
  • 2位はlogmelの変換もlayerとして入れて、パラメータ探索した
  • 2位は時間軸方向はGlobalMaxPooling、周波数方向はGlobalAveragePooling
    • 意味合い的にも妥当
  • Kaggleだと半教師付き学習はpseudo-labelingが最強だよね
    • 論文で言ってるpseudo-labelingはKaggleのpseudo-labelingは全然違う
    • biasがかかっていた瞬間に論文のpseudo-labelingは死ぬ
    • Kaggleのpseudo-labelingは蒸留に近い

質問・コメント

  • BC learningについて。もとはマルチラベル対応ではなかったのでは?(koukyoさん)
    • このコンペはほぼシングルラベルみたいなものなので、えいやでやってしまう
    • powerだとそのままmixupしていいけど、dbでmixupするとおかしくなる
  • マルチタスク学習について。どういう学習方法を使っている?(koukyoさん)
    • noisy/cleanはそれぞれに対応したheadを使っている
    • 推定は別々でやって、backpropは同時にやっている
    • lossの足し合わせは1:1で行っている
  • 1次元側の工夫はあるか?
    • 基本は論文の実装をそのまま使った
    • 単体ではあまり精度は高くなかったので、あくまでアンサンブルの材料
    • 得意なクラスが違ったかも
  • 半教師付き学習について。本来は十分教師がない状況に使うためのものなのでは? 今年のlandmarkコンペでは半教師付き学習が使われている(smlyさん)
    • 適切な目的のところでは半教師付き学習は使える

Large-scale Landmark Retrieval / Recognition under a Noisy and Diverse Dataset (smlyさん)

  • 巨大なデータセットに対して学習
  • 半分以上のクラスが10枚以下というimbalanceなデータセットで、しかもノイズが多い
  • single modelでもbestfitting以上が出せるので、アンサンブルしないと勝てないのは甘え
  • 画像検索で大事なのは2つしかない
    • ArcFaceなどのcosine based softmax lossを使え
    • データセットをキレイにしろ
    • 識別モデルを検索のre-rankingに使え。決定境界から遠いものから順にrankingする
  • データセットをキレイにする
    • 去年のデータセットはキレイだったので、それをベースにクレンジング
      • (そもそも去年のコンペに参加していないと難しい)
    • 近傍を取ってきた後、spatial verificationでキーポイントが保存されていることを確認する
  • 1回recognitionのタスクを解き、ラベルが一致するものを上位に置く

質問・コメント

  • 計算リソースはどれくらいですか?(osciiartさん)
    • pairwiseの学習だとリソースがたくさん必要だが、ArcFaceなどならV100×1×1日くらいで済む

Santander Customer Transaction Prediction 2nd place solution (onoderaさん)

  • すべての特徴量が連続値で、正規分布していて、positiveとnegativeで分布が違う
  • fake rowsを抜いてcount encodingするだけで銀圏に行った
  • roundしてcount encodingしたらめっちゃ上がった
  • ゼルダの続編が開発されている

「結局、Kagglerは何を必死にやっているのか?」というLTをしました

弊社では毎週、新卒LT会が開催されています。 エンジニアがメインですが、同期が職種を問わず広く集まる場になっています。 僕もなにか話したいと思い、7/5(金)に発表しました。

タイトルは「結局、Kagglerは何を必死にやっているのか?」です。

スライドはSpeakerDeckにアップしていますので、何かに使いたい方がいらっしゃいましたらぜひどうぞ。「使ったよー」って言ってもらえるとめちゃめちゃ喜びます。

LTをしようと思ったきっかけ

「Kaggle」や「Kaggler」という単語はデータサイエンス界隈では通りが良くなってきており、Kaggleについて詳しく知っているという人も多いでしょう。

しかし、ビジネス職の方はKaggleについて知らないという方も多いですし、「Kaggle」という言葉を聞いたことがあっても、何が行われているのかきちんと理解している人は少ないのではないでしょうか。

Kagglerが適切に評価され、活躍していくためには「なんか内輪でワイワイやってる連中でしょ」という立ち位置から抜けていくことが大切だと考えています。 そのためには、Kagglerの得意なことや、どのような形で事業に貢献できるのか伝えていくことが重要なのではないでしょうか。

これがマジメな理由です。

マジメじゃない理由としては、「Kaggleってなんなの?」って聞かれたときに「ほらこれ見て」って言える資料を作っておきたかったという感じです。 Kagglerのみなさんはn回この質問をされているでしょうから、この資料が何かの助けになれば嬉しいです。

(おまけ)スライドを作るときに気をつけたこと

  • 聴衆が誰かを意識する
  • 話す目的が何かを意識する
  • 太くて大きい文字を使う
  • 真っ黒い文字は圧が強すぎるのであまり使わない。#333333くらいが個人的には好き
  • 線や矢印など、情報が少ないものは薄く表示する
  • Unsplashでキレイな画像を取る
    • 「laptop」「business」「mountain」とかはかなりそれっぽい
  • icooon-monoのアイコンを使う
    • アイコンの色は文字色に合わせる

なぜn_estimatorsやepochsをパラメータサーチしてはいけないのか

f:id:ejinote:20190630174727p:plain

ハイパーパラメータを探索するため、グリッドサーチやOptunaなどを利用することがあると思います。

しかし、「ハイパーパラメータ探索してみた」のようなQiita記事などでは間違って書かれていることも多いのですが、XGBoostやLightGBMの n_estimators ( num_boosting_rounds )やKerasの epochs をパラメータサーチの対象にしてはいけません。

いけません、というか、すごく無駄なことをしています

なぜ、n_estimatorsやepochsを探索すると無駄なのか

理由はシンプルで、これらのパラメータは「大きい値で精度確認する過程で小さい値の結果も分かる」からです。

LightGBMのn_estimatorsは構築する決定木の数を表しています。

f:id:ejinote:20190630173645p:plain

例として、n_estimators=5 (こんな小さい値で学習することはないですが、簡単のため)で学習を行ったとします。学習の過程で、n_estimators=1のスコアも、n_estimators=2のスコアも確認することができます。

f:id:ejinote:20190630173702p:plain

1, 2, ..., 5とn_estimatorsを振って確認した場合、合計15個の木を構築する必要がありますが、正しくやれば5個の木で十分です。単純計算で3倍、探索を高速化することができるでしょう。

n_estimatorsは学習率によっては5000程度になることもざらにあります。500, 1000, 1500, ... , 5000と500刻みに探索した場合、合計で27500個の木を構築することになります。本当なら5000個で済むのに。しかも、500刻みで探索していた場合、最適な点を見逃す可能性もあります。

Kerasのepochsに代表される、ニューラルネットワークのepoch数も同様です。

epochs=100で学習した場合、その過程で1epochから100epochまでのすべての学習状態を取得することができます。

では、どうすればいいのか?

一般的なのはEarlyStoppingを使用することでしょう。

テストデータとは別にバリデーションデータを用意し、バリデーションで対しての精度がサチったら(一定epochのあいだ向上が見られなかったら)終わりにするという方法です。

LightGBMのscikit-learn interfaceを使っているなら、eval_setearly_stopping_roundsを指定すれば動きます。n_estimatorsは大きめに取っておくとよいでしょう。

import lightgbm as lgb

params = {
    'n_estimators': 10000  # 大きめにとっておく
    # 他のパラメータは省略
}

model = lgb.LGBMClassifier(**params)
model.fit(X_train, y_train, 
          eval_set=[(X_valid, y_valid)], early_stopping_rounds=100)

scikit-learn interfaceを使っていないなら、lgb.train関数にvalid_setsearly_stopping_roundsを設定すれば動きます。num_boost_roundn_estimatorsと同様、大きめに取っておきましょう。

import lightgbm as lgb

train_set = lgb.Dataset(X_train, y_train)
valid_set = lgb.Dataset(X_valid, y_valid)
model = lgb.train(params, train_set, num_boost_round=10000, 
                  valid_sets=[valid_set], early_stopping_rounds=100)

KerasでEarlyStoppingを行うならkeras.callbacks.EarlyStoppingを使います。使う場合はkeras.callbacks.ModelCheckpointと組み合わせ、最も良いモデルを保存するようにしておくと良いでしょう。

from keras import callbacks

# モデルの定義とcompileは予めしておく

callbacks = [
    callbacks.ModelCheckpoint('best_model.h5', save_best_only=True)
    callbacks.EarlyStopping(patience=5)  # 5epoch改善が無ければ止める
]
model.fit(X_train, y_train, epochs=1000, callbacks=callbacks,
          validation_data=[(X_valid, y_valid)]

PyTorchなど、他のフレームワークの場合もEarlyStoppingの仕組みは実装されています。

まとめ

学習の途中経過が全て確認可能な手法を使うとき、n_estimatorsやepochsのような「学習回数」のパラメータを調整するのは時間がもったいないです。

他にもやりがちな例で各種ライブラリのverboseをチューニングしてしまう、というものがあります。verboseは学習中にどれくらいメッセージを吐き出すかというパラメータで、モデルの精度には一切影響を与えません。精度が変わらないので、もちろんチューニングする必要はありません。

機械学習モデルをチューニングする時はそれぞれのパラメータの意味を理解した上で行うようにしましょう。使っているアルゴリズムに対しての理解を深めることも助けになるでしょう。

Dockerでデータ分析環境を手軽に作る方法

f:id:ejinote:20190512163833p:plain

何かデータ分析を行わなければいけないとき、手軽に分析環境を用意したいというニーズがあります。

Jupyter Notebook上でnumpy、pandas、matplotlib、scikit-learnあたりが使えれば十分でしょうか。XGBoostやLightGBMといったライブラリも使えるようにしておきたいという人もいるかと思います。

一方、ローカルにいろいろなライブラリをインストールしていくと、次第に環境が汚れていってライブラリの衝突などが起こりやすくなってしまいます。

KaggleにはKernelという計算環境があり、そこには主要な機械学習ライブラリが予めインストールされています。データ分析をやっていく上で不自由はありません。今回はDockerとdocker-composeを使ってKaggle Kernelを手元に再現し、ポータブルな分析環境として使う方法を紹介します。

データ分析界隈には、なんとなくDockerを敬遠しているような人もいるかと思いますので、この機会に入門してしまいましょう。

解説はMacOSで行いますが、Dockerとdocker-composeがインストールできれば同じ方法が使えるかと思います。

登場する用語の説明

Dockerは、まっさらな環境を簡単に作るツールです。

Dockerfileというファイルに環境の設定を書けば、そのとおりの環境を作ることができます。他人が作ったDockerfileに自分なりのカスタマイズを加えることも可能です。

今回は、Kaggle公式が公開しているpython環境をもとにカスタマイズを行っていきます。

加えてコンテナ(container)イメージ(image)という用語も覚えましょう。

f:id:ejinote:20190512163300p:plain

イメージはDockerfileをビルドして作ります。イメージはDockerfileという設計図を元に作られた「型」だと考えて良いと思います。

イメージを元にコンテナを起動し、そのコンテナ上でJupyterを立ち上げます。利用する際はコンテナにアクセスします。イメージができていればコンテナは数秒で起動できますし、どれだけ環境を汚してもイメージから起動しなおせばまた使うことができます。同じイメージから何個もコンテナを起動することも可能です。

Google Container Registryは便利なイメージが多く登録されているサイトです。今回はKaggleが提供しているPythonイメージを利用します。

docker-composeはDockerfileのビルドと起動を管理するツールです。

f:id:ejinote:20190512163312p:plain

Dockerコンテナを起動する際、いろいろなオプションをつけることができます。しかし、それをいちいちコマンドラインで打つのは煩雑です。docker-composeを使えば、様々なオプションをdocker-compose.ymlというYAMLファイルで設定することができます。

docker-composeは本来は複数のコンテナを連携して使うために作られたツールですが、今回はコンテナを簡単に立ち上げるためだけに使いたいと思います。

Dockerとdocker-composeのインストール

それでは、Dockerとdocker-composeをインストールしていきましょう。

既にインストール済みの方はこの節は読み飛ばしてください。

https://docs.docker.com/docker-for-mac/install/ に従ってDocker Desktop for Macをインストールします。

インストールが終わったら、アプリケーションからDocker.appを起動します。(起動にはしばらく時間がかかるかもしれません)

Dockerが起動されたら以下のコマンドを打ち、dockerとdocker-composeのバージョンが表示されるか確認してください。

$ docker --version
$ docker-compose --version

Kaggle Kernelを元に分析環境を作る

それでは、Kaggleが提供しているDockerfileを元に、データ分析の環境を作っていきます。

今回は以下のようなフォルダ構成で解析を進めていくとします。

.
├── .dockerignore
├── Dockerfile
├── docker-compose.yml
├── input/     # データ
├── notebook/  # Jupyter Notebook
└── script/    # スクリプト

このうち、以下の3つのファイルは新しく作成します。

  • Dockerfile
  • docker-compose.yml
  • .dockerignore

Dockerfile

Dockerfileは、イメージの定義です。どういうOSを使って、どういうライブラリをインストールするのか、という内容を書きます。

# kaggleのpython環境をベースにする
FROM gcr.io/kaggle-images/python:v56

# ライブラリの追加インストール
RUN pip install -U pip && \
    pip install fastprogress japanize-matplotlib

内容はこれだけです。

FROM gcr.io/kaggle-images/python:v56は、Google Container Registry(gcr.io)上にあるKaggle公式Dockerイメージを出発点にしてイメージを定義する、という意味です。 gcr.io/kaggle-images/python には、既にnumpyやpandasを始めとして、データ分析に必要な多くのライブラリが含まれています。

:v56はタグの指定です。KaggleのDockerイメージは日々改善されているので、今の時点での最新版を書いておくと良いでしょう。タグの一覧はgcr.io/kaggle-images/pythonにアクセスすると見ることができます。

:latestと指定して最新版を入れることもできますが、イメージが更新されるたびにダウンロードが走ってしまいますし、環境がころころ変わるのは望ましいことではないので、バージョンを特定しておくことをおすすめします。

もし足りないライブラリがあるならば、 RUN コマンドを使うことで pip install をすることができます。

docker-compose.yml

docker-compose.ymlにはコンテナを起動する際の設定を書きます。

version: "3"
services:
  jupyter:
    build: .
    volumes:
      - $PWD:/tmp/working
    working_dir: /tmp/working
    ports:
      - 8888:8888
    command: jupyter notebook --ip=0.0.0.0 --allow-root --no-browser

versionはdocker-compose.ymlの書き方のバージョンです。3を指定しておけばよいかと思います。

services以下に起動するコンテナの設定を書いていきます。jupyterはコンテナを管理するための名前です。

build: .は同じフォルダにあるDockerfileをビルドする、という意味です。先程作成したDockerfileがビルドされます。

volumesはマウントするフォルダの設定です。$PWD:/tmp/workingとすることにより、現在のディレクトリを、Dockerコンテナ上の/tmp/workingに紐付けることができます。これにより、Dockerコンテナの中からでも現在のディレクトリ(とその中のデータとか)にアクセスすることができます。

working_dirはコンテナ内の初期ディレクトリの設定です。今回は/tmp/workingに設定しています。

portsはポートフォワードの設定です。手元のポート:コンテナのポートの形式で書きます。

ふだんJupyter Notebookを起動するとき、localhost:8888からアクセスすることになるかと思います。今回はDockerコンテナ上でJupyterを起動するため、Dockerコンテナ内のlocalhost:8888にアクセスしないとJupyterを見ることができません。しかし、portsの設定をしておくことで、Dockerコンテナ内の localhost:8888を手元のlocalhost:8888につなぐことができます。

commandはDockerコンテナを起動したときに走るコマンドの内容です。今回はJupyter Notebookを起動しています。

いくつか見慣れないオプションがついているかと思います。

--ip=0.0.0.0は起動したJupyter Notebookにコンテナ外からアクセスできるようにするオプションです。

--allow-rootはルートでの実行を許可するオプションです。Dockerコンテナはデフォルトでルート権限で起動するので、このオプションが必要です。

--no-browserはJupyter Notebook起動時にブラウザを立ち上げないオプションです。

.dockerignore

.dockerignoreは、Dockerfileをビルドする際に無視するファイルを列挙するものです。

今回の場合、データやノートブックはDockerfileのビルドの瞬間は必要ありませんから、.dockerignoreに書いておきましょう。(コンテナとのデータの共有は、ビルドを行った後にマウントで対応します)

input
notebook
script

input/などに大容量のデータが入っていて、かつ.dockerignoreに記述もしなかった場合、Dockerのビルドの際に時間がかかるようになってしまいます。ビルドに必要の無いファイルやフォルダは、.dockerignoreに書くように心がけましょう。

起動してみる

それでは、実際に分析環境を起動してみましょう。

ここで注意ですが、この操作は初回時に限りめちゃめちゃ重いデータをダウンロードする必要があります。実は、Kaggleの公式イメージは便利なライブラリがたくさん入っている反面、とても重いDockerイメージになっています。その容量、なんと18GB!

学校や職場など、WiFi環境が整っている場所で行ってください。間違ってもテザリング中なんかにやらないようにしてくださいね。

$ docker-compose up --build

まず、最初にDockerfileのビルドが走り、その後Dockerコンテナの中でJupyter Notebookが起動されます。最後のJupyter Notebookが起動するところはだいたいこんな感じのログになるかと思います。

jupyter_1  | [I 07:11:32.796 NotebookApp] Writing notebook server cookie secret to /root/.local/share/jupyter/runtime/notebook_cookie_secret
jupyter_1  | [I 07:11:33.065 NotebookApp] JupyterLab extension loaded from /opt/conda/lib/python3.6/site-packages/jupyterlab
jupyter_1  | [I 07:11:33.065 NotebookApp] JupyterLab application directory is /opt/conda/share/jupyter/lab
jupyter_1  | [I 07:11:33.068 NotebookApp] Serving notebooks from local directory: /tmp/working
jupyter_1  | [I 07:11:33.069 NotebookApp] 0 active kernels
jupyter_1  | [I 07:11:33.069 NotebookApp] The Jupyter Notebook is running at:
jupyter_1  | [I 07:11:33.069 NotebookApp] http://33c518cf1679:8888/?token=hogefugatoken
jupyter_1  | [I 07:11:33.069 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
jupyter_1  | [C 07:11:33.069 NotebookApp]
jupyter_1  |
jupyter_1  |     Copy/paste this URL into your browser when you connect for the first time,
jupyter_1  |     to login with a token:
jupyter_1  |         http://33c518cf1679:8888/?token=hogefugatoken

最後のlogin with a tokenの下のURLをコピーし、33c518cf1679の部分をlocalhostに変えてブラウザのURLバーに入れればJupyter Notebookにアクセスできます。

ローカルにあるファイルにもアクセスできることを確認してください。

まとめ

今回はDockerとdocker-composeを使い、Kaggleの環境をベースにした分析環境の立ち上げを行いました。

自分なりにカスタマイズしたDockerfileを持っておけば、新しいデータが来たときも迅速に解析に取り掛かることができます。

みなさんもぜひ試してみてください。

Docker/Kubernetes 実践コンテナ開発入門

Docker/Kubernetes 実践コンテナ開発入門

追記 (2019/05/13)

Twitterでmhiro2さんにいただいた指摘を元に記事を修正しました。ありがとうございました!

追記2 (2019/07/12)

Dockerのメモリ上限を大きくする方法についてu++さんが書いてくださいました。メニューバーのDockerマークから設定に飛び、メモリ上限を拡張してください。

upura.hatenablog.com

Kaggle Eloコンペの振り返り・上位解法まとめ

f:id:ejinote:20190302203900p:plain

KaggleのElo Merchant Category Recommendationコンペに参加しました。

僕は@kasuminkoさん、@hirokasさんとチームを組んで、ラスト2週間だけ参加しました。結果から書くと、Public 221位からのPrivate 2220位という乱高下で儚く散りました。

手元に銀メダル相当のスコアを持っていたにもかかわらず、間違ったサブミットを選んでしまっており、とても悔しいです。

  • コンペの概要
  • 上位解法
    • 1st place solution (30CrMnSiA)
      • 特徴量
      • モデル
    • 5th place solution (Evgeny Patekha)
      • 特徴量
      • モデル
    • 7th place solution (senkin)
      • 特徴量
      • モデル
      • その他
    • 11th place solution (Zakaria EL Mesaoudi)
      • 特徴量
      • モデル
      • その他
    • 16th place solution (nlgn)
      • 特徴量
      • モデル
    • 18th place solution (pocket)
      • 特徴量
      • モデル
    • 上位解法のうち、今後も使えそうなアイディアのメモ
  • 僕たちの解法

コンペの概要

Eloというブラジルのカード会社が主催となり、各ユーザーの購買行動に対応したRoyalty Scoreという値を予測するコンペです。

データとしては各カードの属性を書いたtrain.csv/test.csvと、それぞれのカードに紐付いた購買履歴(transaction)を表すhistorical_transactions.csv/new_merchant_transactions.csvの4ファイルが与えられていました。

タスクの種類は値を当てる回帰で、targetの分布は0を中心とした分布に加え、-33付近に外れ値が存在するというものでした。

f:id:ejinote:20190302203644p:plain

評価指標はRMSEで、外れ値の影響を受けやすい指標です。特に今回は-33.22付近とかなり外れた位置にサンプルが存在するため、外れ値をどう捌くかが大きな論点のひとつでした。

続きを読む