俺人〜OREGIN〜俺、バカだから人工知能に代わりに頑張ってもらうまでのお話

俺って、おバカさんなので、とっても優秀な人工知能を作って代わりに頑張ってもらうことにしました。世界の端っこでおバカな俺が夢の達成に向けてチマチマ頑張る、そんな小さなお話です。現在はG検定、E資格に合格し、KaggleやProbSpaceのコンペに参画しながら、Pythonや機械学習、統計学、Dockerなどの勉強中です。学習したことをブログにアウトプットすることで、自分の身に着けていきたいと思います。まだまだ道半ばですが、お時間がありましたら見て行ってください。

Solafune x Microsoft 市街地画像の超解像化コンペに向けて超解像化について学ぶ。#MScup

今回は、衛星データ分析サイトのSolafuneで現在開催されている「市街地画像の超解像化」コンペ(MScup)に向けて参考にしている情報をまとめてみました。

現在参加中の皆様や、これから参加予定の皆様のご参考になれれば幸いです。

【目次】

1.【宙畑】超解像×衛星画像でできること。関連論文の紹介とTellusでやるには

sorabatake.jp

今回のコンペを開始するのにピッタリのサイトだったので、最初に参考にさせていただきました。

このサイトのおかげで、初手で躓かずに提出までこぎつけました。

衛星画像分野で、機械学習が必要になっている背景から始まっているので、Solafuneの今回のコンペの主旨にある、社会実装の加速に貢献するという意味でも、非常に有用なコンテンツです。

また、超解像の理論的な説明から、論文やサンプルコードへのリンクが貼ってあり充実した内容になっています。

著者は、以下の記事の事前準備として、勉強されたとのことです。

sorabatake.jp勉強された内容についても、以下の資料にまとめて公開してくださっています。

docs.google.com

2.【Sansan Builders Blog】超解像の歴史探訪 -SRGAN編

buildersbox.corp-sansan.com

1つ目のサイトで出てきたキーワード「SRGAN」で検索してたどり着いたサイトになります。

GANの説明から始まり、SRGANについて、生成器、識別器、損失関数、学習の部品に分けて実装例つきで説明してくださっています。

また、GitHubにコードも公開してくださっていて、とても参考になりました。

3.【Quiita】トップ学会採択論文にみる、超解像ディープラーニング技術のまとめ

qiita.com2014年〜2018年までのCVPR, ECCV, ICCV などのコンピュータビジョンのトップ画像処理学会に採択された、ディープラーニング(DL)を用いた超解像モデルをまとめてくださっています。

どのモデルが、どのような系統のモデルなのかという樹形図もあるので、各モデルの特徴を把握する目安になります。

主要論文リストや、トレーニング用データセットなども紹介されているので、お役立ち度が高いです。

4.【ULCAMTCVSMPS】超解像ネットワークを微分の差の絶対値で学習してみました。

crater.blog.ss-blog.jpこちらのサイトは、GANを使わない、Super-Resolution Neural Netowrk について、説明してくださっています。

残念ながら学習済みモデルの公開は終わっているようなのですが、モデルのコードはGitHubに公開してくださっています。

6.おわりに

とても興味深いテーマで、様々な分野で応用されている技術なので、まだまだ、始まったばかりのコンペですが、すでに学びが盛りだくさんです。

引き続き、コンペで取り組む中で得た情報を発信していきたいと思います。

 

f:id:kanriyou_h004:20210917182331p:plain

 

 

【3位解法】ProbSpace開催「宗教画テーマの分類」の振り返り。

データ分析好きが集まる交流プラットフォーム「ProbSpace」で開催された「宗教画テーマの分類」に参加し、3位の成績を残せました!

今回のコンペは、私の好きな画像分類のタスクだったので、結果も残せてよかったです。

また、画像分類のタスクでも、プロ野球データ分析チャレンジで使った、多値分類に2値分類を応用する戦法が活用できたのもよい経験でした。

Image

では、振り返って参りたいと思います。

1.全体構成

今回のコンペは、米・メトロポリタン美術館が公開している、キリスト教の宗教画画像を、「受胎告知」、「最後の晩餐」など、13種類のテーマに分類するという画像分類コンペでした。

データの特徴として、訓練データが654枚、テストデータが497枚と、比較的データ量が少ないデータだったので、今回のコンペで許容された学習済みモデルをいかに活用できるかがポイントになりました。

また、今回も前回のプロ野球データ分析チャレンジと同様、分類するクラスごとの数に偏りがあったため、画像分類の処理を行った後、2値分類で精度を上げて上書きする処理を実施しました。

<データの分布>

f:id:kanriyou_h004:20210913203104p:plain

 

f:id:kanriyou_h004:20210913212909p:plain

少ないデータ量を補うために、以下の対策を実施いたしました。

  • 前処理:垂直・水平に反転した画像、回転した画像、セピア色に変換した画像を水増しした訓練データを作成。それぞれの画像の水増し割合を16パターンで学習を実施。
  • モデル1段目:学習済みのEfficientNetを活用してファインチューニングを実施。
  • モデル2段目:全クラスを予測する多値分類のモデルと、クラスごとの2値分類を実施するモデルを作成して、最後に上書きを実施。

また、ProbSpaceのトピックで公開させていただいたデータ内の画像の重複について(簡易自動化バージョン)を使って、重複・類似した画像を調べました。

2.前処理

前処理については、以下の2通りで実施いたしました。

データの前処理については、albumentationsというライブラリを利用しました。

【前処理 共通】

こちらは、訓練データ、テストデータの両方に適用する共通の処理です。

前処理

処理内容

サイズ変更

albumentationsのResize()を使って、画像サイズの変更を実施。後続の学習済みモデルに合わせたサイズに変更。

標準化

albumentationsのNormalize()を使って、画素値の標準化を実施。

【前処理 水増し】

こちらは、訓練データを水増しするために実施する前処理です。テストデータには実施しません。

前処理

処理内容
水平反転

albumentationsのHorizontalFlipを使って、指定した割合の画像を水平反転。

垂直反転

albumentationsのVerticalFlipを使って、指定した割合の画像を垂直反転。

回転 albumentationsのRotateを使って、指定した割合の画像を回転。
セピア変換 albumentationsのToSepiaを使って、指定した割合の画像をセピア色に変換。今回のデータでは、古い絵画もあったので、採用してみました。

 

3.モデル構築

 今回は、大きく分けて、「学習済みのEfficientNetを活用してファインチューニングを実施」する1段目と、プロ野球データ分析チャレンジで使った、「全クラスを予測する多値分類のモデル」の出力に、「クラスごとの2値分類を実施するモデル」の出力を上書きをする2段目を組み合わせた、スタッキングモデルを構築しました。

f:id:kanriyou_h004:20210913212909p:plain

 

【1段目:EfficientNet】

1段目は、EfficientNetの学習済みモデルをファインチューニングして、2段目に渡す訓練データの予測値と、テストデータの予測値を出力するモデルを16個作成しました。

それぞれのモデルで、訓練データの水増しの割合を変更することで、パターン分けしました。

このモデルは、skywalkerさんがトピックに投稿してくださっている、EfficientNetB0使ったベースラインも参考にさせていただきました。

このモデルの学習には、GPUが必要となるので、Google Colabで実行するには、実行時間に制約があるので、とても骨が折れました。

 

【2段目:LighetGBM】

2段目は、16種類の予測値を訓練データとして、「多値分類するモデルの予測値」に、「各分類ごとの2値分類をするモデルの予測値」を上書きすることで、精度を上げる方法を実施しました。

この方法は、プロ野球データ分析チャレンジで採用した方法を応用しました。

今回も、通算500個以上のモデルを作って、いろいろな組み合わせを試し、そのうち200回以上の提出を実施しました。後半はほぼ毎日提出しました。


4.感想

今回のコンペは、宗教画の意味するテーマを分類するコンペでした。

これまで、宗教画をじっくり眺めて、テーマを考えることがなかったので、「あ、この絵のこの部分はこういうことを表しているんだ。」と、モデル以上に自分自身も学習することができました。(笑)

途中、自分が分類する場合に、「十字架があるな」、「人が多いな」などを基準にしたりするので、物体検出が応用できないかと、Yoloにも挑戦してみましたが、なかなか精度は上がりませんでした。

参考:学習済みのYOLOv5による物体検出結果の特徴量への追加

新しい技術にも触れられて、とても有意義なコンペとなりました。

また、今回からProbSpaceでも、最終提出ファイル選択方式となったので、最後の最後まで、ファイル選びに悩みました。

Public:Privateが13%:87%と、Publicスコアがあまり重視できない割合だったこともあって、ShakeDownしてしまいましたが、何とか3位になることができました。

5.謝辞

最後となってしまいましたが、本コンペを運営してくださいました、ProbSpace の運営の皆様、一緒にコンペに取り組んでいらっしゃった皆様、Twitter上でやりとりを実施させていただいた皆様に心より感謝申し上げます。

今回学ばせていただいた事項を糧に、社会貢献できるよう引き続き精進してまいりたいと思います。

 

【過去記事】

G検定、E資格の取得から、これまでに取り組んできた道のりは以下にまとめております。何かのご参考にしていただければ幸いです。

oregin-ai.hatenablog.com

oregin-ai.hatenablog.com

【第2弾】 rinna社が公開した、日本語に特化した「GPT-2」「BERT」事前学習モデルをつかって昔話創作モデルを実装してみた!

今回も、rinna株式会社が8月25日に公開してくださった、日本語に特化した「GPT-2」と「BERT」の事前学習モデルを使ってモデルを実装してみました。

今回は、昔話の冒頭の文章を与えると、話の続きを創作してくれるモデルです。

corp.rinna.co.jp

 では、振り返っていきたいと思います。

日本語に特化した「GPT-2」「BERT」事前学習モデルをつかって昔話創作モデルを実装してみた!

1.今回実装した昔話創作モデル

今回実装した昔話創作モデルは、冒頭の文章を与えると、続きの文章を複数生成し、提案してくれるというモデルです。

本来であれば、膨大な量の文章を集めて、長時間学習させないと行けないところ、公開された事前学習モデルを使うことで、GPUも使うことなく簡単に実装することができました。

昔話創作モデルの仕様

  1. 昔話の冒頭の文章として「昔々あるところに、」という文章を入力する。
  2. 入力された文章をもとに、続きの物語を複数生成する。
  3. おもしろ文章を見つけて、日々の生活に役立てる。

2.全体像

コード全体は以下の通りで、Google colaboratory上で実行しました。

GitHubにも公開しています。

https://github.com/Oregin-ML/Fairy-tale-creation-model

!git clone https://github.com/rinnakk/japanese-pretrained-models

%cd /content/japanese-pretrained-models

!pip install -r requirements.txt

# ライブラリをインポートします。
from transformers import T5Tokenizer, AutoModelForCausalLM
# 学習済みモデルをダウンロードします。
tokenizer = T5Tokenizer.from_pretrained("rinna/japanese-gpt2-medium")
tokenizer.do_lower_case = True
model = AutoModelForCausalLM.from_pretrained("rinna/japanese-gpt2-medium")

# 生成する文章の冒頭部分を設定します。
beginning = '昔々あるところに、'
# 文章を機械学習の入力とできるようコード化します。
input = tokenizer.encode(beginning, return_tensors="pt")

# 文章の生成処理を実施します。(出力はコードで出力されます。)
output = model.generate(input,do_sample=True, max_length=100, num_return_sequences=5)
# 出力されたコードを文章に戻します。
DecodedOutput = tokenizer.batch_decode(output)

# 生成された文章を表示します。
print('#'*40)
print(f'冒頭が「{beginning}」となる文章を出力します。')
print('#'*40)
for j in range(5):
 
print('#'*40)
 
print(f'### 文章案{j} ####')
 
print('#'*40)
 
i = 0
 
while i < len(DecodedOutput[j]):
  
print(DecodedOutput[j].replace('</s>','')[i:i+30])
  
i = i+30

では、コードを順番に見ていきます。

3.学習済みモデルをインストールする

GitHubより、学習済みモデルをダウンロードして、ダウンロードされたフォルダ内にある、「requirements.txt」を使えば、必要なライブラリが一発でインストールできます。 

!git clone https://github.com/rinnakk/japanese-pretrained-models 

%cd /content/japanese-pretrained-models

!pip install -r requirements.txt

4.学習済みモデルを定義する

学習済みモデル("rinna/japanese-gpt2-medium")を、読み込みます。

この数行を記載するだけで、莫大なデータやリソース、時間を必要とする学習を省略することができます。

# ライブラリをインポートします。
from transformers import T5Tokenizer, AutoModelForCausalLM
# 学習済みモデルをダウンロードします。
tokenizer = T5Tokenizer.from_pretrained("rinna/japanese-gpt2-medium")
tokenizer.do_lower_case = True
model = AutoModelForCausalLM.from_pretrained("rinna/japanese-gpt2-medium")

5.生成の基となる昔話の冒頭部分を設定する。

昔話の冒頭部分として、'昔々あるところに、'を設定します。この部分を変更すれば、昔話に限らず、いろいろな文章が作れます。

なお、文章を機械学習の入力として使えるようにコード化する必要があります。

# 生成する文章の冒頭部分を設定します。
beginning = '昔々あるところに、'
# 文章を機械学習の入力とできるようコード化します。
input = tokenizer.encode(beginning, return_tensors="pt")

6.続きの物語を生成して出力する。

モデルのgenerate()を使って、続きの物語を生成します。

入力にはコードに変換済みの冒頭の文章(input)を指定します。

各オプションは以下のとおりです。

do_sampleをTrueとすることで、実行毎に出力を変化させることができます。

max_lengthは、生成する文章の最大の長さになります。

num_return_sequencesは、生成する文章の数になります。

出力は、コードで出力されるため、.batch_decode()を使って、文章にもどします。

表示にあたっては、改行をいれて出力させています。

# 文章の生成処理を実施します。(出力はコードで出力されます。)
output = model.generate(input,do_sample=True, max_length=100, num_return_sequences=5)
# 出力されたコードを文章に戻します。
DecodedOutput = tokenizer.batch_decode(output)

# 生成された文章を表示します。
print('#'*40)
print(f'冒頭が「{beginning}」となる文章を出力します。')
print('#'*40)
for j in range(5):
 
print('#'*40)
 
print(f'### 文章案{j} ####')
 
print('#'*40)
 
i = 0
 
while i < len(DecodedOutput[j]):
  
print(DecodedOutput[j].replace('</s>','')[i:i+30])
  
i = i+30

7.実行結果

このコードを実行した出力の例は以下のとおりです。

少し違和感のある文章もありますが、なかなか良い文章もできています。

中には、続きが気になってしまう文章案もあります。

手直しすれば、オリジナルの昔話も作れそうですね。

f:id:kanriyou_h004:20210827172901p:plain

8.感想

今回は、日本語に特化した事前学習モデルを使って、昔話創作モデルを作ってみました。

大したものは作れないと思っていたのですが、なかなか良い文章が出てくるので、創作文章を作るときの最初のアイデア出しに使えそうな気がしました。

もっと色々使ってみて、活用方法を考えていきたいと思います。

 

【第1弾】簡易大喜利モデル

oregin-ai.hatenablog.com

【これまでの道のり】

oregin-ai.hatenablog.com

oregin-ai.hatenablog.com

oregin-ai.hatenablog.com

oregin-ai.hatenablog.com

oregin-ai.hatenablog.com

f:id:kanriyou_h004:20210826185619p:plain



 

rinna社が公開した、日本語に特化した「GPT-2」「BERT」事前学習モデルをつかって簡易大喜利を実装してみた!

元女子高生AI「りんな」などで知られるrinna株式会社が8月25日に公開してくださった、日本語に特化した「GPT-2」と「BERT」の事前学習モデルを使って、簡易大喜利(?)モデルを実装してみました。

日本語CC-100と日本語Wikipediaの計75ギガバイトのデータを、8つのNVIDIA Tesla V100 GPUで、45日間も掛けて学習しないと行けない事前学習モデルが、無料で簡単に使えるのは感動でした!

corp.rinna.co.jp

 では、振り返っていきたいと思います。

日本語に特化した「GPT-2」「BERT」事前学習モデルをつかって簡易大喜利を実装してみた!

1.今回実装した簡易大喜利モデル

今回実装した簡易大喜利モデルは、指定した文字列のうち、隠した部分の文字列を予測する機能を使って、面白い回答を期待するというモデルです。

本来であれば、いろいろと実装して、データを集めて、長時間学習させないと行けないところ、公開された事前学習モデルを使うことで、あっという間に実装することができました。

簡易大喜利モデルの仕様

  1. 穴埋めさせたい文章を入力する。
    例:「世界一うるさい人と言ったら、。」
  2. 簡易大喜利モデルが「」の部分を予測して、確率が高い順に出力する。
    例:「あなた
  3. おもしろ回答を見つけて、こっそり楽しむ。

2.全体像

コード全体は以下の通りで、Google colaboratory上で実行しました。

GitHubにも公開しています。

https://github.com/Oregin-ML/Simple_Ogiri_model

 

!git clone https://github.com/rinnakk/japanese-pretrained-models

%cd /content/japanese-pretrained-models

!pip install -r requirements.txt
import torch from transformers import T5Tokenizer, RobertaForMaskedLM # load tokenizer tokenizer = T5Tokenizer.from_pretrained("rinna/japanese-roberta-base") tokenizer.do_lower_case = True # due to some bug of tokenizer config loading # load model model = RobertaForMaskedLM.from_pretrained("rinna/japanese-roberta-base") model = model.eval() print('#'*40) print('答えさせたい内容を「〜、何。」と聞いてみてください。') print('例;世界一うるさい人と言ったら、何。') print('※最後の「。」を忘れずに。') print('#'*40) # original text text = input() # prepend [CLS] text = "[CLS]" + text if '何' in text: # tokenize tokens = tokenizer.tokenize(text) # mask a token masked_idx = -2 tokens[masked_idx] = tokenizer.mask_token print('#'*40) print('#以下の[MASK]の部分を考えます。') print(tokens) print('#'*40) # convert to ids token_ids = tokenizer.convert_tokens_to_ids(tokens) # convert to tensor token_tensor = torch.tensor([token_ids]) # get the top 10 predictions of the masked token with torch.no_grad(): outputs = model(token_tensor) predictions = outputs[0][0, masked_idx].topk(10) print('#'*40) print('#思いついた答えは・・・') for i, index_t in enumerate(predictions.indices): index = index_t.item() token = tokenizer.convert_ids_to_tokens([index])[0] print(i, token) print('#以上です。') print('#'*40) else: print('何か聞いてくれないとわからないです。')

では、コードを順番に見ていきます。

3.学習済みモデルをインストールする

GitHubより、学習済みモデルをダウンロードして、ダウンロードされたフォルダ内にある、「requirements.txt」を使えば、必要なライブラリが一発でインストールできます。

 

!git clone https://github.com/rinnakk/japanese-pretrained-models 

%cd /content/japanese-pretrained-models

!pip install -r requirements.txt

4.学習済みモデルを定義する

学習済みモデル("rinna/japanese-roberta-base")を、読み込みます。

この数行を記載するだけで、莫大なデータやリソース、時間を必要とする学習を省略することができます。

import torch
from transformers import T5Tokenizer, RobertaForMaskedLM

# load tokenizer
tokenizer = T5Tokenizer.from_pretrained("rinna/japanese-roberta-base")
tokenizer.do_lower_case = True  # due to some bug of tokenizer config loading

# load model
model = RobertaForMaskedLM.from_pretrained("rinna/japanese-roberta-base")
model = model.eval()

5.大喜利させたい文章を入力する

大喜利させたい文章を標準入力で受け付けます。

ポイントは、文章の頭に[CLS]を追加するところです。

print('#'*40)
print('答えさせたい内容を「〜、何。」と聞いてみてください。')
print('例;世界一うるさい人と言ったら、何。')
print('※最後の「。」を忘れずに。')
print('#'*40)

# original text
text = input()

# prepend [CLS]
text = "[CLS]" + text

6.「何」の部分を予測して、出力する。

「何」の文字列が含まれていれば、「masked_idx」で指定した箇所の単語を予測して、確率が高い単語を10個出力します。今回は、文末が「何。」となっていることを前提に、後ろから2つ目の単語を予測することにしています。

赤字下線の部分で、穴埋めの予測処理を実施しています。

if '何' in text:
  # tokenize
  tokens = tokenizer.tokenize(text)
  # mask a token
  masked_idx = -2
  tokens[masked_idx] = tokenizer.mask_token
  print('#'*40)
  print('#以下の[MASK]の部分を考えます。')
  print(tokens)  
  print('#'*40)
  # convert to ids
  token_ids = tokenizer.convert_tokens_to_ids(tokens)

  # convert to tensor
  token_tensor = torch.tensor([token_ids])

  # get the top 10 predictions of the masked token
  with torch.no_grad():
      outputs = model(token_tensor)
      predictions = outputs[0][0, masked_idx].topk(10)

  print('#'*40)
  print('#思いついた答えは・・・')
  for i, index_t in enumerate(predictions.indices):
      index = index_t.item()
      token = tokenizer.convert_ids_to_tokens([index])[0]
      print(i, token)
  print('#以上です。')
  print('#'*40)

else:
  print('何か聞いてくれないとわからないです。')  

7.実行結果

このコードを実行して、「世界一の天才といったら、何。」と入力した場合の実行結果は以下の通りです。

なかなかいい味を出している回答を返してくれています。

f:id:kanriyou_h004:20210826203630p:plain

 

8.感想

今回は、日本語に特化した事前学習モデルを使って、簡易大喜利モデルを作ってみました。このモデル自体が何かの役に立つかというと、そうでもないのですが、こんなに簡単に穴埋め予測モデルが作れてしまうので、この事前学習モデルの有用性を身を持って知ることができました。

今後は、このモデルをどの様に活用できるかの視点でも考えていきたいと思います。

 

 

【これまでの道のり】

oregin-ai.hatenablog.com

oregin-ai.hatenablog.com

oregin-ai.hatenablog.com

oregin-ai.hatenablog.com

oregin-ai.hatenablog.com

f:id:kanriyou_h004:20210826185619p:plain



 

2021年上半期+αの振り返り(機械学習の積み上げ~さらなる高みを目指して~)

2021年上半期は、昨年に引き続き、機械学習の積み上げの成果を試すため、いろいろなデータ分析サイトのコンペティションに挑戦しました。

中でも、念願のKaggleでの初メダル獲得や、ProbSpaceでの初優勝など、自分内「初」の記録を残せた半期でした。

いろいろな制約があり、なかなか思うようにならないことが多いご時世ですが、自身のできることを、できる範囲でコツコツと進めてきた成果だと思っています。

引き続き、「ゆっくりでも止まらなければ結構進む」の精神で頑張って行きたいと思います。

 

【目次】

【コンペ関連】

 1.Kaggleで初メダル獲得!(Cassava Leaf Disease Classification)

2021年上半期で印象に残った出来事の1つ目は、念願のKaggleにて初メダルを獲得できたことになります。

2月に終了した鳥蛙コンペ(Rainforest Connection Species Audio Detection)では、善戦したものの、Top16%でメダル獲得ならずだったのですが、直後に結果がでたタロイモコンペ(Cassava Leaf Disease Classification)にて、Top6%に入ることができ、初の銅メダル獲得となりました!

残念だったのは、強化学習に本格的に取り組んだじゃんけんコンペ(Rock, Paper, Scissors)では、Top11%と、あと7つ上位に届かず、メダル&Expert昇格を逃してしまったことでした。

とはいえ、メダル獲得が夢ではなく手に届くところまできたのは、大きな進歩でした。

なんとか今年中に、もう一つメダルを獲得して、Expertを目指します!

f:id:kanriyou_h004:20210812142757p:plain

2.ProbSpaceで初優勝!総合ランキング1位をキープ

2021年上半期で印象に残ったもう一つの出来事は、データ分析プラットフォームProbspaceで開催された、プロ野球データ分析チャレンジで、初優勝できたことでした。これまで、コンペで2位や3位になったことはあったのですが、優勝は初めてだったので、感無量でした。

また、3月に終了した、論文の被引用数予測コンペでは、41位と散々な成績だっただけに、喜びもひとしおでした。

この優勝で、ProbSpace内ランキングにおいて、トピック、コンペティション、総合の3部門全部で1位を達成することができました。(総合ランキング

各コンペでの記録は以下の通りです。

f:id:kanriyou_h004:20210812143337p:plain

f:id:kanriyou_h004:20210812145252p:plain

3.Solafune、Nishikaで宇宙・航空系コンペに挑戦

宇宙・航空系に興味をもっている私は、宇宙・航空系のコンペにも参加しました。

具体的には、衛星データ分析サイトのSolafuneで開催された「夜間光データから土地価格を予測」、データサイエンスコンペティションサイトのNishikaで開催された「航空機ターボエンジンの残存耐用時間予測」の2つに挑戦し、以下の結果を残すことができました。

また、昨年から宇宙関連のコンペに参加していたこともあり、宇宙関連の情報サイト宙畑さんの取材を受け、以下の記事にしていただけました。

Kaggle では、まだまだヒヨッコなので、ランカーというのはお恥ずかしい限りなのですが、良い経験をさせていただきました。

sorabatake.jp 

 【積み上げ関連】

1.AIQuest2020受講(〜2021年2月)

経済産業省が実施しているAI Quest 2020|SIGNATEに昨年から参加し、無事終了することができました。

f:id:kanriyou_h004:20210812154756p:plain

守秘義務があり、詳細は記載できませんが、要件定義あり、コンペ形式でのAI開発あり、経営層向けのプレゼンありで、実業務に即した、かなり濃厚な講座でした。

結果としては、以下の通り、第1タームAI課題優秀賞&総合賞、第2タームプレゼン課題優秀賞&総合賞の表彰を受けることができました。

f:id:kanriyou_h004:20210812162853p:plain


signate.jp

2.実践データサイエンスシリーズ(講談社サイエンティフィク)当選!

講談社サイエンティフィク (@kspub_kodansha) さんのキャンペーンに応募して、以下の3冊をちょうだいいたしました。

Kaggleでの戦い方から、ベイズ統計モデル、データの可視化まで、実践を交えながら一通り学習できて、とても有意義な時間を過ごすことができました。

講談社サイエンティフィクの皆様ありがとうございました!

f:id:kanriyou_h004:20210812171823p:plain

おわりに

2021年に入ってからも、引き続き、なかなか思うように活動できない日々が続いていますが、できる範囲の中で、チャレンジ精神を忘れずに、活発に行動していきたいと思います。

また、コンペに限らず、実社会でも貢献できるように引き続き精進してまいります。

さまざまなチャネルで、交流させていただいたり、繋がらせていただいたりしている皆様、本当にお世話になっております。

ささやかながら、皆様の活動の一助 となれるよう頑張ってまいりますので、今後ともよろしくお願いいたします。

 

【これまでの道のり】

oregin-ai.hatenablog.com

oregin-ai.hatenablog.com

oregin-ai.hatenablog.com

oregin-ai.hatenablog.com

f:id:kanriyou_h004:20201209122737p:plain 

 

 

【1位解法】ProbSpace開催「プロ野球データ分析チャレンジ 」の振り返り。

データ分析好きが集まる交流プラットフォーム「ProbSpace」で開催された「次の一投の行方を予測! プロ野球データ分析チャレンジ」に参加し、1位の成績を残せました!

現在、オープンレビュー中のため、賞金獲得は未確定ですが、解法について公開させていただきます。確定できれば、昨年のNishika開催の「Jリーグプレイヤーの出場予測」(参考;【2位解法】Nishika開催「Jリーグプレイヤーの出場時間予測」の振り返り)に続き、スポーツ関連で2個目の賞金獲得になります。

また、今回1位が確定できれば、ProbSpace内で、トピック、コンペティション、総合の3分野で1位になることができます!

【後日談】無事オープンプレビューが完了し、優勝が確定しました!

2021年上半期+αの振り返り(機械学習の積み上げ~さらなる高みを目指して~)

 

今回のコンペは、様々な手法の前処理を適用するとともに、回帰、2値分類、多値分類の複数の種類のモデルを駆使し、持てる力を十二分に発揮することができました。

f:id:kanriyou_h004:20210623222431p:plain

では、振り返って参りたいと思います。

1.全体構成

今回のコンペは、日本のプロ野球で、投げられた1球が、ストライクになったか、ヒットになったかなどの投球結果を予測するテーブルコンペでした。

データの特徴として、球速や、投げられたコースなどは、trainデータにしかなく、testデータから予測する際には、一度、testデータに不足している特徴量を予測するモデルで予測してからひと工夫が必要でした。

【trainデータにしかない特徴量】

f:id:kanriyou_h004:20210608172353p:plain

また、当然といえば当然なのですが、ストライクやボールに比べ、ヒット、2塁打、3塁打、ホームランの数が非常に少なく、分類されるデータ量が偏ったデータとなっていました。testデータも同様の分布になると過程し、数が少ない分類については、個別に予測モデルを作成することにしました。

【trainデータの「投球結果」の度数分布】

f:id:kanriyou_h004:20210608172132p:plain

上記のような状況を踏まえ、最終的には以下のような構成のモデルを作成しました。

f:id:kanriyou_h004:20210608164651p:plain

前処理済みのデータは2種類用意して、以下の2種類のモデルで予測し、多値分類を行った予測値に、頻度が少ない値を2値分類として予測し予測値を上書きすることで、最終的に提出する予測値を作成しました。

  • trainにしかないSpeedの予測値をtestデータの特徴量に追加して多値分類を行うモデル
  • その1球が「ヒットになるかならないか」、「2塁打になるかならないか」、「3塁打になるかならないか」、「本塁打になるかならないか」の2値分類を行うモデル

2.前処理

前処理については、以下の2通りで実施いたしました。

【前処理A】

こちらは、ProbSpaceのトピックで公開させていただいたベースラインの前処理となります。[トピックはこちら→改良版-LightGBM Base line−コメント付き (CV= 0.14834 / LB= 0.13733)]

前処理

処理内容
年月日、曜日、時分秒を追加

'startDayTime'から、試合の開始年月日、曜日、時分秒を作成してそれぞれを特徴量として追加。

回数と裏表を追加

'inning'から、回数と裏表を作成して、それぞれを特徴量として追加。

ボール、ストライク、アウトの合計値を追加

ボール、ストライク、アウトのカウントの合計値、およびボール、ストライクの合計値を特徴量として追加

ベース上のランナーの数を追加

1塁、2塁、3塁のベース上のランナー数の合計値を特徴量として追加

バッターのチームを追加

表の場合は'topTeam'を、裏の場合は'bottomTeam'を、バッターのチームとして追加

ピッチャーのチームを追加

表の場合は'bottomTeam'を、裏の場合は'topTeam'を、ピッチャーのチームとして追加

 【カテゴリカル変数の処理】

前処理

処理内容

カテゴリカル変数をカウントエンコード

 xfeat の CountEncoder を使用して、各カテゴリ変数をカウントエンコードした特徴量を追加

カテゴリカル変数をターゲットエンコード xfeat の TargetEncoder を使用して、各カテゴリ変数をターゲットエンコードした特徴量を追加

 【その他】

前処理

処理内容

pivot tabel を用いた特徴量を追加

Pandas の pivot_table を使用して、"gameID"をインデックスとした各種ピボットデータを特徴量として追加

【前処理B】

こちらは、ProbSpaceのトピックでDT-SNさんが公開してくださいましたベースラインの前処理となります。

詳細は、DT-SNさんが公開してくださったトピックをご参照ください。

[トピックはこちら→LightGBM Base line(CV=0.2228,LB=0.16746)]

3.モデル構築

 今回は、大きく分けて、目的となる分類の全クラスを分類するモデルと、頻度の少ないヒット、2塁打、3塁打、ホームランのそれぞれを予測するモデルを作成いたしました。

f:id:kanriyou_h004:20210608164651p:plain

【全体の多値分類】

前者は、2段階のモデルを組み合わせています。

1段階目は、前処理Aのデータを用いて、訓練データのみにあるspeedの特徴量をMLPRegressor(回帰)で予測するモデルを作成し、TestデータにもSpeedの特徴量を追加しました。

2段階目は、前処理AのデータにSpeedの特徴量を追加した特徴量からLightGBMで多値分類を行うモデルを作成しました。 

【頻度の少ないクラスの2値分類】

後者は、ヒットになるかならないかの2値分類を行うモデル、2塁打になるかならないかの2値分類を行うモデル、3塁打になるかならないかの2値分類を行うモデル、ホームランになるかならないかの2値分類を行うモデルを、それぞれ作成しました。

2値分類については、過去にProbSpace実施された、「スパムメール判別コンペ」の1位解法で利用されていた「ダウンサンプリング」や「MultinomialNB」などを採用させていただいたり、「対戦ゲームデータ分析甲子園」で武器ごとの予測を試したことを応用して、チームごとの予測を採用したりしました。

最終的には、後者のそれぞれのモデルで「なる」に分類されたデータを前者のモデルでの予測値に上書きすることで、最終的な予測値としました。

(通算500個以上のモデルを作って、いろいろな組み合わせを試し、そのうち約170回の提出を実施しました。後半はほぼ毎日提出しました。)


4.感想

今回のコンペは、プロ野球選手の実名のデータが登場するコンペだったので、実際の状況を想像しながら楽しんで取り組むことができました。

野球は、スポーツの中でも戦略やゲーム性が高いスポーツなので、こういった分析が実際の試合でも使われていると考えると、これからますます機械学習が応用されるのではないかと感じました。

今回も、とにかくいろんなモデルを作成しては、出力を提出して、LBスコアを確認しながら、とりくみました。

コンペの前半で、多値分類のモデルだけでなく、出現頻度の低いクラスについては、2値分類のモデルを採用することを思いついたことが、スコアの向上に大きく貢献しました。

2値分類については、過去いろいろなのコンペで取り組んでいたので、これまでの資産が十分に効果を発揮しました。改めて、コンペ毎に完結するのではなく、コンペで培った資産は、次に活かしていくことも大切と感じました。

また、今回は、Open Review Competitionということで、公開することも考慮しながらコードを作成いたしました。途中で、トピックにベースラインを公開して、皆さんのご指摘もいただきながら修正して、なんとか提出ができました。

あとは、レビュー結果が楽しみです。

5.謝辞

最後となってしまいましたが、本コンペを運営してくださいました、ProbSpace の運営の皆様、一緒にコンペに取り組んでいらっしゃった皆様、Twitter上でやりとりを実施させていただいた皆様に心より感謝申し上げます。

今回学ばせていただいた事項を糧に、社会貢献できるよう引き続き精進してまいりたいと思います。

 

【過去記事】

G検定、E資格の取得から、これまでに取り組んできた道のりは以下にまとめております。何かのご参考にしていただければ幸いです。

oregin-ai.hatenablog.com

oregin-ai.hatenablog.com

【9位解法】Solafune開催「夜間光データから土地価格を予測」の振り返り。

アジア初の衛星データ解析コンテストプラットフォーム「Solafune 」で開催された「夜間光データから土地価格を予測」に参加し、9位の成績を残せました!

賞金獲得はなりませんでしたが、前回開催の「衛星画像から空港利用者数を予測」の2位受賞に続き、連続でのToP10入でした。

今回のコンペは、使えるデータが実質2カラム分しかなく、特徴量の活用が非常に難しいコンペでした。全体的にShakeが発生していたのもこのあたりが影響しているのかなぁと思いました。

f:id:kanriyou_h004:20210408192910p:plain

f:id:kanriyou_h004:20210408192833p:plain


 

では、振り返って参りたいと思います。

1.全体構成

今回のコンペは、テーブルコンペなのですが、与えられた生の特徴量が少ないため、特徴量をいかに増やすかが考えどころでした。

あとは、CVの工夫と、2段のStacking、加重平均で構築していきました。

f:id:kanriyou_h004:20210408193239p:plain

2.前処理

前処理については、以下の通りで実施いたしました。
(この処理は、cha_kabuさんのベースモデルを参考にしました。)

【四則演算等】         

前処理

処理内容
Area

その地域の合計の光量が「SumLight」で、平均の光量が「MeanLight」であることから、「SumLight ÷ MeanLight」が、その地域の面積であるとみなし、特徴量としました。

MeanLightが63となった回数

MeanLightは「63」が上限値となっていて頭打ちとなっていたので、上限値の「63」を超えた回数を特徴量としました。

 【統計情報】

前処理

処理内容

PlaceIDをキーとした統計情報

PlaceIDをキーとして、min,max,median,mean,std,max-min,q75-q25を特徴量として追加しました。

Yearをキーとした統計情報 Yearをキーとして、min,max,median,mean,std,max-min,q75-q25を特徴量として追加しました。

 【その他】

前処理

処理内容

同一PlaceID内の年ごとの差分

同一のPlaceID内で、年毎のMeanLighetの差分,年毎のSumLighetの差分を特徴量として追加しました。

同一PlaceID内の年ごとの差分

同一のPlaceID内で、年毎のMeanLighetをShiftした値,年毎のSumLighetをSiftした値を特徴量として追加しました。

同一PlaceID内の相関係数

同一のPlaceID内で、MeanLighet,SumLighet,Areaと年の相関係数を特徴量として追加しました。

ピボットテーブルを用いた特徴量

pandasのpivot_tableを使って、特徴量を水増ししたうえで、sklearn.decompositionのPCAを利用して、特徴量の選択を実施しました。

3.モデル構築

 今回は、モデル構築には、2階層のStackingでモデル構築をしました。

1層目は、LighetGBMで構築し、検証はGroupKfoldを用いました。

2層目は、MLPRegressorで構築し、検証はホールドアウト法を用いました。

1層目、2層目ともに、いろいろなモデルを試してみたのですが、あまり精度のよいモデルを構築できなかったのが残念でした。もっと多様なモデルで精度が出すことができていれば、もう少し上位を狙えたかもしれません。

(通算300個以上のモデルを作って、そのうち130個以上の提出を実施しました。後半はほぼ毎日提出しました。)

最終的には、以下の4つの組み合わせを採用しました。

1層目

  • LGBM GroupKfold Fold数5 × 6モデル
  • LGBM GroupKfold Fold数11 × 1モデル
  • エッジ抽出画像→ResNet-34 モデル3
  • 多重化画像→efficientnet-b7 モデル4

2層目

  • MLPRegressor ホールドアウト × 2モデル

その後、この2つの組み合わせで加重平均をとりました。

f:id:kanriyou_h004:20210408193239p:plain

4.感想

今回のコンペは、カラム数が非常に少ないデータから特徴量を作り出すというアプローチの勉強になりました。

画像データの様にデータ量が多くないので、学習に時間がかからないという利点があるのですが、精度を出すための特徴量づくり、特徴量選択が非常に難しかったです。

いろいろなみなさんのベースラインを拝見しながら、よいモデルを作成することができました。

他の皆さんのベースライン等は以下にまとめました。とても勉強になったベースラインばかりでした。

oregin-ai.hatenablog.com

5.謝辞

最後となってしまいましたが、本コンペを運営してくださいました、Solafune の運営の皆様、一緒にコンペに取り組んでいらっしゃった皆様、Twitter上でやりとりを実施させていただいた皆様に心より感謝申し上げます。

いつもながら、宇宙からのデータについて分析できるというのは、とてもワクワクします。今回学ばせていただいた事項を、社会貢献に活用できるよう引き続き精進してまいりたいと思います。

 

【過去記事】

G検定、E資格の取得から、これまでに取り組んできた道のりは以下にまとめております。何かのご参考にしていただければ幸いです。

oregin-ai.hatenablog.com

oregin-ai.hatenablog.com