u++の備忘録

Kaggle の Code Competitions で処理済ファイルやライブラリを使う

近年の Kaggle では、参加者が Kaggle の Code 環境上でソースコードを実行する「code competitions」形式でのコンペ開催が増えています。実行時間や処理内容など諸条件はコンペごとに異なります*1が、モデルの学習を事前に実施し、評価用データセットに対する推論コードのみを提出する形式が一般的です。不正対策などの要因で、インターネットの利用は禁じられている場合が多いです。本記事では、この形式のコンペで、処理済ファイルを使ったり、ライブラリをインストールしたりする方法を紹介します。

処理済ファイルの利用

推論部分のみのコードを提出する形式の場合、学習済モデルや前処理済ファイルなどは、Kaggle の datasets 機能を用いて notebook の input に追加できます。過去のコンペで公開されている notebook が参考になります。datasets には公開設定があるので、コンペ開催中は private に設定しておくと良いでしょう。

www.kaggle.com

ライブラリのインストール

Kaggle の Code 環境上 にはあらかじめ機械学習の処理で頻繁に使われるライブラリがインストールされています*2。コンペによってはインストールされていない特別なライブラリを使いたい場合がありますが、インターネットが使えない状況では notebook 上で pip install することができません。画像やテキストを題材にしたコンペでは、ニューラルネットワークのための事前学習済の重みを読み込みたい場合もあります。

このような時は、以下の投稿を参考にインストールに必要なファイルを含む datasets を input に追加し、notebook から直接実行します。有名なライブラリの場合は既に他の参加者が datasets として保存・公開している場合もあります。参加しているコンペや類似コンペの公開 notebook を確認すると良いでしょう。

www.kaggle.com

おわりに

本記事では、code competitions での datasets の利用方法を紹介しました。

*1:Overview の Code Requirements のページを確認しましょう

*2:github.com

Solafune「夜間光データから土地価格を予測」コンペ 6 位解法

衛星データに関するコンペティションプラットフォーム「Solafune」で開催されていた「夜間光データから土地価格を予測」コンペ*1で、 6 位になりました。終了直前の参加だったので、優勝した方が公開していた特徴量に少し足して、pseudo labeling で水増しした程度の解法です。後述しますが、ある程度の順位変動が予想できたので、あまり突き詰めることはなく放置してお祈りしていました。

コンペ概要

夜間光データを元に土地価格を予測するコンペでした。データセットで与えられている列は目的変数を含めて 5 つのみでした。土地価格を推定する回帰問題です。その他の詳細は、他の参加者の方が公開しているブログ記事*2を参照してください。

解法概要

コンペ用の GitHub リポジトリを公開したので、Commit ログを辿ると具体的な雰囲気が分かるかもしれません。

github.com

私がコンペに参戦したのが 3 月 30 日で、終了まで残り 1 週間足らずでした。その時点でも上位に相当するスコアが出るベースラインの記事*3が公開されていたので、こちらを軸に進めることに決めました。

具体的には、当該記事で紹介されていた特徴量を丸々流用しつつ、最終的に以下の 377 個の特徴量を生成しました。

  • 当該記事の特徴量
  • 元々の特徴量
  • カテゴリ変数をラベルに置換
  • カテゴリ変数を登場回数に置換
  • カテゴリ変数を軸にした集計

この特徴量を用いて、LightGBM および CatBoost のモデルを作成しました。2 つの出力を、検証用データセットに対する性能が最大化するように重み付き平均することで、最終的な予測値としています。

コンペでは、しばしば全ての予測値を定数倍することで順位表のスコアが良くなる場合があります。今回、予測値をそれぞれ 0.9、0.8 倍したところ、以下のような結果が得られました。0.9 倍の予測値を提出した時点で public の順位表で 10 位に入りました。データセットがそれほど大きくないコンペだったこともあり、今回は以下のような意思決定をしました。

  • 定数倍で順位を上げても private には反映されなさそう
  • public の順位表の上位がどれほど後処理を頑張っているのか読めないので、ある程度頑張ったらコンペを終了してお祈りすれば良さそう
public private
original 0.490048 0.494568
original * 0.9 0.483107 0.497904
original * 0.8 0.501885 0.526949

最終的には、少しでも private で使われているデータセットに強いモデルにしようと思い、評価用データセットに対して疑似ラベルを付与する「pseudo labeling」を実施したところでコンペを終了しました。最終提出は 2 つ選ぶことができたので、定数倍の有無で 2 種類を用意しました。

順位はある程度の想像通り定数倍をしていない提出が最良のスコアを取り、public の 14 位から private の 6 位になりました。5 位までが入賞圏内で少々残念ですが、自分のデータセットに対する勘所を確認できた点で有意義なコンペだったなと感じます。

運営・参加者の皆さまにお礼申し上げます。

f:id:upura:20210430234327p:plain

Kaggle Notebooks Master になった

2018 年の GW に Kaggle を本格的に始めて丸 3 年、Notebooks カテゴリで Master の称号を獲得しました。

f:id:upura:20210427121955p:plain

2019 年 4 月に終了したコンペでチームメイトにも恵まれ金メダルを獲得できた後、入門記事入門書など、主に日本人参加者の Kaggle に対する障壁を下げて裾野を広げたいと考えていました。副次的な報酬として、Kaggle 上で一つの節目となる称号が得られたのは非常に嬉しいです。

Competitions 部門で Master になった際、以下のような投稿をしていました。齢を重ねつつある中、3 年以上も打ち込める趣味に出合えて良かったなと改めて感じています。

次なる Master の目標は Discussions 部門になりますが、狙いに行くものというより、コンペに真面目に参戦する中で自然と積み上がっていくものだと捉えています。なかなか Kaggle コンペで金メダルを取れていませんが、機を見て挑戦していきたいところです。

f:id:upura:20210427121834p:plain https://www.kaggle.com/sishihara

中国語繁体字版『PythonではじめるKaggleスタートブック』

昨年4月に出版した書籍『PythonではじめるKaggleスタートブック』(講談社*1の中国語繁体字版が、今月出版されました。原著も第3刷&電子版好調らしく、時間をかけた執筆作業が報われている気分です。

books.gotop.com.tw

他言語版ということで、サポートページに英語の説明文も追加しました。

github.com

Google Code Jam 2021 Qualification Round 参加録

Google Code Jam 2021」の Qualification Round に参加しました。「Code Jam」は、Googleが主催する世界的なコーディングコンテストで、Qualification Round は最初の予選です。今年は日本時間の3月26日22時〜28日午前4時にわたり開催され、出題5問から合計30点以上を獲得することで次のラウンドに進出できます。

競プロに挑戦するのは久々でしたが、今回無事に31点を獲得できました。本記事では、解法をまとめます。

f:id:upura:20210328023425j:plain Code Jam - Google’s Coding Competitions

Reversort (7点)

1問目は、データ構造とアルゴリズムで頻出の「ソート」が題材でした。制約の数字も大きくないので、問題文の指示に従って愚直に実装すれば通ります。

T = int(input())
case_id = 0
for test_case in range(T):
    cost = 0
    case_id += 1
    N = int(input())
    L = list(map(int, input().split()))
    for i in range(N - 1):
        min_j = L[i]
        min_j_idx = i
        for j in range(i + 1, N):
            if min_j > L[j]:
                min_j = min(min_j, L[j])
                min_j_idx = j
        cost += (min_j_idx - i + 1)
        L[i: min_j_idx + 1] = L[i: min_j_idx + 1][::-1]
    print(f'Case #{case_id}:', cost)

Moons and Umbrellas (5 + 11 + 1点)

2問目は、文字列に関する話題でした。問題文を読んで、?をどう処理するかを考えるのが肝になります。?が何個連続するのか、?が両端にあるのかなどのパターンを挙げていきながら考えていきました。コストX, Yが0以上の場合には、?が何個連続しようがCもしくはJを連続させることで、部分文字列のコストがXかYに帰着します。

Pythonの場合は文字列の正規表現を用いて次のように実装できます。

import re


T = int(input())
S = [list(input().split()) for i in range(T)]

case_id = 0
for test_case in range(T):
    x, y, s = S[case_id]
    x = int(x)
    y = int(y)
    cost = 0
    cost += (len(re.findall(r'C\?*J', s)) * x)
    cost += (len(re.findall(r'J\?*C', s)) * y)
    case_id += 1
    print(f'Case #{case_id}:', cost)

Reversort Engineering (7 + 11点)

第1問の応用問題です。問題文の制約を見ると、7点のテストケースは総当たりで通せそうです。この時点で24点を積み上げていたため、まずは確実に7点を取りに行きました。

import itertools


def calc_cost(L):
    cost = 0
    for i in range(N - 1):
        min_j = L[i]
        min_j_idx = i
        for j in range(i + 1, N):
            if min_j > L[j]:
                min_j = min(min_j, L[j])
                min_j_idx = j
        cost += (min_j_idx - i + 1)
        L[i: min_j_idx + 1] = L[i: min_j_idx + 1][::-1]
    return cost


def check_list(N, C):
    for candidate in list(itertools.permutations([i + 1 for i in range(N)])):
        candidate_list = list(candidate)
        cost = calc_cost(candidate_list)
        if cost == C:
            ans = [str(c) for c in list(candidate)]
            return ' '.join(ans)
    return 'IMPOSSIBLE'


T = int(input())
case_id = 0
for test_case in range(T):
    case_id += 1
    N, C = list(map(int, input().split()))
    ans = check_list(N, C)
    print(f'Case #{case_id}:', ans)

おわりに

本記事では「Google Code Jam 2021」の Qualification Round の解法をまとめました。

【YouTube更新】大学入学共通テスト「情報」(プログラミング)のサンプル問題を解いてみた

大学入試センターは24日、2025年1月に実施する大学入学共通テストの教科・科目の再編案を公表しました。プログラミング関連の知識を試す「情報」が導入されるそうです*1

今回は、公開されたサンプル問題*2をすべて解いてみました。サラッと流し見で問題の雰囲気が分かるかと思います。

言語処理学会第27回年次大会ワークショップ「AI王 〜クイズAI日本一決定戦〜」参加録

言語処理学会第 27 回年次大会のワークショップとして開催されていた「AI王 〜クイズAI日本一決定戦〜」*1に参加しました。Kaggle などで親交のある atfujita さんとのチームで、最終結果は 5 位でした。

コンペ概要

日本語の 20 択のクイズ問題に回答する課題でした。データセットとして質問文・選択肢・回答のための Wikipedia データが与えられました。

暫定の評価用データセットを用いた順位表は、2020年4月から公開されていました*2。その順位表を通じて各自がモデルを改善しつつ、2021年3月19日に実施されたイベント内で新しい評価用データセットに対する性能を競うという形式でした。

チームとしての取り組み

チームとしての取り組みは、ワークショップ内でシステム報告として口頭発表しました。資料は下記の通り公開しています。基本的には運営が公開しているベンチマークコード*3を軸にしつつ、BERT の事前学習済モデルを含めた細かな拡張を重ねながら多様性を生み、最後にアンサンブルで性能を高めました。

他チームの取り組み

暫定の順位表で 1 位を獲得した方をはじめ、データの前処理に注力していたチームが多かった印象でした。事前学習済モデルによる取り組みが一般的な時代において、前処理の重要性を改めて実感する良い機会となりました。

私が知る限りの公開されている資料は、記事末尾にまとめました。

おわりに

日本語の質問応答という、題材としては馴染みがありつつも、モデル構築という観点では初めての領域に挑戦できました。コロナ禍の影響で当初の計画通りに行かない部分も多かったのではないかと推察しますが、データセットを公開しコンペを運営してくださった皆さんに感謝いたします。またチームを組んだ atfujita さんや、ワークショップ内で知見を共有してくださった参加者の皆さまにも、改めてお礼申し上げます。ベンチマークコードを読み解いたり(時に修正の PR を送ったり)、古典的な手法を再考したり、関連の論文を調査したりで、学びの深いコンペでした。

公開資料

公開されている資料をまとめました。

招待講演

コンペ解法

qiita.com

www.ai-shift.co.jp