とある京大生の作業ログと日々の雑記

コンピュータサイエンスについて学んだことを可視化したり日々の雑記をまとめてます。

Kaggle、始めてみないかい?

こんにちは!コミさん(@komi3__ )です!




この土日でトビタテ留学Japan!という、文部科学省が留学のための奨学金をくれるプログラムの面接に行ってました!





スイスは物価が高くて奨学金がないとしんどいんですよね.....(とりあえず今回は手応え的に良さそうだから期待)





トビタテについては以下のリンクへ↓



www.tobitate.mext.go.jp




まあそんなこんなで先週はずっと準備とかでバタバタしてて、それで今もほとんど進捗がないという状況で....w




しばらくブログ更新してなかったのでとりあえず何かブログを更新しようということで、今回は掲題の通り、



「Kaggleの始め方・楽しみ方」



について書いていこうと思います!



Kaggleって何?

そもそもKaggleってなに?ということからまず始めましょう。




......まあそもそもこの記事にたどり着いたという人は「もうKaggleは知ってるし始めたいんだよ!」って人がほとんどだと思うんですけどね.......w




まあくどいかもしれませんが、一応説明しておこうと思います!





Kaggleとは....

Kaggleは企業や研究者がデータを投稿し、世界中の統計家やデータ分析家がその最適モデルを競い合う、予測モデリング及び分析手法関連プラットフォーム及びその運営会社である。 モデル作成にクラウドソーシング手法が採用される理由としては、いかなる予測モデリング課題には無数の戦略が適用可能であり、どの分析手法が最も効果的であるか事前に把握することは不可能であることに拠る。

出典:Wikipedia


という感じですね。



まあつまり、

  • 企業がデータを提供
  • Kaggleの参加者がそれらのデータに対して最適モデルを構築して競い合う
  • 優秀者には賞金が与えられる


というような流れです。



言ってしまえば競技プログラミングのデータサイエンス版です。



簡単に言えばそういう感じですが、しかし個人的には


データサイエンスの祭典


だと捉えています!




なぜKaggleをやると良いかというと、「データサイエンティストとして箔が付き、企業にヘッドハンティングをしてもらえる」という点が比較的大きいと考えています。




技術者は腕で雇われる生き物ですからね。





まあそんなこんなで、Kaggleについて簡単な解説をしていこうと思います。



Kaggleの始め方

Kaggleは色々なタスクが転がっているんですけど、Kaggleの始め方のサイトではよくTitanicというタスクについて解説がされています。




別にTitanicでもいいんですけど、一応差別化を測るためにDigit-Recognitionというタスクで行こうと思います!



まずはアカウントの準備

Kaggleを始めるにあたって、まずはKaggleアカウントを用意しましょう。




GoogleのアカウントやFacebookのアカウントで登録できると思うので、各自お願いします。



課題について

アカウントが準備できたら早速ログインしましょう。



f:id:komi1230:20180516110215p:plain




そしたら、このCompetitionsというところをクリックし、今やっているコンペを見てみます。




f:id:komi1230:20180516110345p:plain




色んなコンペがありますね!




この画面の右側に書いてある2,500ドルとかあるのが、みなさんが大好きな賞金です!




今回はDigit-Recognizerをやるべく、この中からAll CategoriesをクリックしてGetting Startedを選びます。




そこからDigit-Recognizerを選びます。




f:id:komi1230:20180516105948p:plain




課題のサイトではこんな感じがトップページですよね。




この課題は手書き数字の認識というタスクです。





OverviewのページのDescriptionでは課題の説明が、その横のEvaluationでは課題の提出フォーマットが示されています。




ちなみにこの課題では


ImageId,Label
1,0
2,0
3,0
4,2


というようなcsvファイルで提出しろと書いてありますね。



次にDataページを見てみましょう。




f:id:komi1230:20180516111733p:plain




ここではモデル構築において必要なtrainデータや提出用のtestデータが用意してあります。




これらをダウンロードすれば、もうKaggleを始められます...!!




その次のKernelのページでは色んな人のモデルが置いてあります。




f:id:komi1230:20180516112136p:plain




その次のDiscussionでは質問や疑問点などの掲示板が用意してあります。




そしてその次がLeaderboardで、ここにランクが載っています!




まあざっとこんな感じでしょうか?




ということで、早速モデル構築を始めてみましょう!


データ分析をしてみよう。

trainデータやtestデータはダウンロードしましたか?




早速データを取り出して中身をざっと見てみましょう。



import pandas as pd


train = pd.read_csv("train.csv")
train.info()


こうして見ると、出力は以下の通りとなります。

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 42000 entries, 0 to 41999
Columns: 785 entries, label to pixel783
dtypes: int64(785)
memory usage: 251.5 MB


ここでは、28x28ピクセル+ラベルの785行のデータが42000パターン用意してあることがわかります。




一つ取り出して中身を見てみましょう。



import pandas as pd
import matplotlib.pyplot as plt


train = pd.read_csv("train.csv")

# set label and image
def label_and_pixel(num):
      label = train.iat[num, 0]
      pixels = train.iloc[num, 1:].as_matrix()
      pixels = pixels.astype("float").reshape(28,-1)

      return label, pixels


number = 3
label, image = label_and_pixel(number)

plt.imshow(image)
plt.show()


コードを見れば画像情報の取り出しなどはわかると思います。



ちなみに画像はこのようになります。



f:id:komi1230:20180516113509p:plain




一応、4の形してるんかな....?




labelも確認してみましょう。



number = 3
label, image = label_and_pixel(number)

print(label)


とすると、ちゃんと4と出力されます。



ちゃんとぼくらの目は正しかったわけですねw




ということで、こんな感じでちゃんとデータを取り出すことができました。




もうあとはSVMニューラルネット等、好きな道具を振り回して識別器を用意するだけです!!!




PyTorchを使って識別器を作るよ!


今回はよく慣れたやり方で攻めましょう。




つまりCNNを使った方法です。




ネットワークの構成は以下の通りです。



import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim


# make network
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()

        # set layers
        self.conv1 = nn.Conv2d(1, 6, 3)
        self.pool = nn.MaxPool2d(2)
        self.conv2 = nn.Conv2d(6, 16, 3)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        if not torch.is_tensor(x):
            x = torch.FloatTensor(x).view(1,1,28,28)

        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5))
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)

        return x

まあよく知ってるネットワーク構成ですよね....w



PyTorchのネットワークに流し込むにあたってテンソル化が必要なので、それの関数もこのクラスに組み込みます。

def to_tensor(self, x):
        if torch.is_tensor(x):
            x = torch.FloatTensor(x)

        return x
def get_image(self, num, test=False):
        # get data
        self.train = pd.read_csv("train.csv")

        # set label and image
        label = self.train.iat[num, 0]
        pixels = self.train.iloc[num, 1:].as_matrix()
        pixels = pixels.astype("float").reshape(28,-1)

        # set answer data
        labels = torch.zeros(10)
        labels[label] = torch.FloatTensor([1])

        return labels, pixels


あとでLoss関数にCrossEntropyを使うため、出力ラベルにちょっと細工してますがまあそこはちょっとした操作なので問題ないです。




これでほぼ準備は完了ですかね?




では、あとはtrainする部分を作っていきましょう。


if __name__ == "__main__":
    USE_CUDA = torch.cuda.is_available()
    model = Net()

    if USE_CUDA:
        model = model.cuda()

    criterion = nn.CrossEntropyLoss()
    optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)

    train_num = 42000

    for eps in range(2):
        for i in range(train_num):
            # get the inputs
            label, image = model.get_image(i)
            label = model.to_tensor(label)
            label = label.type(torch.LongTensor)

            # CUDA Tensor
            if USE_CUDA:
                label = label.cuda()
                image.cuda()

            # zero gradient
            optimizer.zero_grad()

            # forward + backward + optimize
            output = model.forward(image)
            outputs = output.repeat(10,1)
            #print("output : ", output.data.numpy().argmax())
            loss = criterion(outputs, label)

            loss_show = loss.data.numpy()
            loss.backward()
            optimizer.step()
            torch.save(model.state_dict(), "./save_model/model.pth")

            # print statistics
            if i % 10 == 0:
                print("Eps : ",eps," Number : ",i," loss : ",loss_show)

完成です!



簡単にbackwardを用意しただけですけどねw




特に細やかなテクニックはないですが、ちゃんとモデルを保存しておくのを忘れずに。




submissionをしよう


さて、trainはできたということで今度は提出ファイルを用意しましょう。



ファイルの作成部分はこんな感じになります。


if __name__ == "__main__":
    USE_CUDA = torch.cuda.is_available()
    model = Net()
    
    # Load Model
    param = torch.load("./save_model/model.pth")
    model.load_state_dict(param)

    if USE_CUDA:
        model = model.cuda()

    test_num = 28000

    # save submission file
    text = "ImageId,Label\n"

    for play in range(test_num):
        data = model.get_test_data(play)
        if USE_CUDA:
            data = data.cuda()
        output = model.forward(data)

        # save file
        answer = output.data.numpy().argmax()
        id = play+1

        text += str(id)+","+str(answer)+"\n"

    with open("./submission.csv", "w") as f:
        f.write(text)


with構文で提出ファイルsubmission.csvを作成します。



ちょっとしたコツとして、型を全てstrとして、それを足し上げていくことで出力する文字列を用意します。


提出しよう


これでできたファイルをKaggleの提出フォームに投げます。



f:id:komi1230:20180516115201p:plain



これで提出してしまえば終わりです!



お疲れ様でした。



終わりに


今回は簡単に初めから課題提出までを解説しました。



今回のモデルはデータが完璧だったので問題ないのですが、タスクによってはデータが一部欠損していてそれらを埋める作業が必要だったりします。



そうしたデータへの取り扱いは、また各自で勉強してください(色んな手法があります)



PRMLやGoodfellowのDeep Learningで勉強したことがこうして試せるKaggleは非常に面白いと思います。



みなさんもやってみましょう!



ではお疲れ様でした!