Private LB公開時刻変更のお知らせ(2021/9/4更新)
先日見つかりました同スコア時の順位が提出時刻順となっていない問題につきまして、対応方法を検討いたしました結果、コンペ終了後のパッチ対応により修正することとなりました。
皆さまには大変ご不便おかけいたしますが、当対応に伴い、Private LBの公開日時を
9/12(日) 24:00 → 9/13(月) 18:00
へと変更させていただきたく存じます。
なお提出締切時刻の変更はなく、予定通り9/12(日) 24:00での終了となります。
お楽しみのところ誠に申し訳ございませんが、ご理解いただけますと幸いです。
ホワイトリストルール追加のお知らせ
Imagenet等汎用的に使われる学習済みモデルが、テストデータ使用不可の制約にかかる可能性があるとのご指摘を受け、ルールを追加いたしました。下記ホワイトリストについては、たとえテストデータとの被りが含まれる場合も使用可とさせていただきます。
ホワイトリスト
なお、本コンペにおいては、当初通り外部データ・学習済みモデル使用にあたる運営確認は不要です。ホワイトリストにないモデルの使用について、ご心配な場合はトピック等でお気軽にお問い合わせください。運営にて判断させていただきます。
(※ ホワイトリストへの追加申請はコンペ終了7日前の9/5 24:00までとさせていただきます)
Open to Work リーダーボード設置 / 求人紹介サービス開始のお知らせ
本コンペティションより、 データ関連人材を対象とした求人紹介サービスを開始いたします。
Open to Work リーダーボードに参加されている方々に対し、ProbSpaceより転職求人、副業/フリーランス案件についてのメールを登録アドレスにお送りいたします。
ご希望の方は、コンペ終了までに下記参加手順よりOpen to Work リーダーボードにご参加ください。
データサイエンティスト様に限らず、データ活用に関連したエンジニア・コンサル・事業/企画部門の皆さまを対象としております。どうぞよろしくお願いいたします。
(Open to Workリーダーボードへの参加手順)
① リーダーボード右上の"LBチーム"をクリックし、LB設定ページを開く
② リーダーボードチームリストよりOpen to Workリーダーボードへの"参加申請"をクリック
※ 完了後、リーダーボードにOpen to Workが追加されます
宗教画は、特定宗教に関する逸話や伝説などを描いた作品のことであり、歴史的にも宗教を語る上では欠かせない存在の一つです。
宗教画が活況となった中世では、様々な画家が権力者の娯楽や宗教的権威を示すことを目的として、旧約聖書の1シーンが描画された宗教画が様々なところで取引されていました。
当時後進国であったヨーロッパでは読み書きができない人が多かったため、逸話のイメージを印象強く描いた数々の作品が、多くの人々にその情景を印象づけることができたと言えます。
そのような宗教画は、新古典派やロマン派など、時代にあった形式で複数の異なる潮流の中で描かれていますが、同一のテーマを扱った作品も数多く存在しています。
例えば、レオナルド・ダ・ヴィンチの「最後の晩餐」は宗教画として有名な作品です。
一方で、タッチは異なり見慣れない絵であるかもしれませんが、「最後の晩餐」を描いた宗教画は他にも多々存在しています。
(左:サンタポリナーレ・ヌオヴォ聖堂のモザイク画 / 右:サン・マルコ寺院の壁画)
そこで今回、「最後の晩餐」の様な、異なる時代や作者によって描かれた宗教画の題材を予測させる問題を設計いたしました。データセットとしては、キリスト教絵画の中でも代表的な計13テーマを用意しております。
本コンペティションでは、テストデータを用いた教師なし学習を許可しております。(詳細はルールをご確認ください)
例えば癌検診・商品の類似性分析では、データを取得してから時間をかけて画像分類することが可能であり、テストデータを教師なし学習として用いる有用性が想定されます。
過去kaggleにおいても、教師なし学習可能なコンペティションが開催されており、今回ProbSpaceでも同様の扱いができることといたしました。
ただし実際には、テストデータを教師なしデータとして使える / 使えない場合で、どれほど精度差が出るかは不明です。
運営の興味本位であり大変恐縮ではございますが、どなたかトピック化いただける方がおりましたら、大変嬉しく存じます。
1位 100,000円
2021年9月12日 24:00 JST
ビジュアル図解 聖書と名画 [世界史徹底マスター]
今すぐ試したい! 機械学習・深層学習(ディープラーニング) 画像認識プログラミングレシピ
医療AIとディープラーニングシリーズ Pythonによる医用画像処理入門
データをダウンロードするにはログインまたはユーザー登録して下さい
コンペに使用するデータは3つに分けられます。
データ数は、訓練データが654枚、テストデータが497枚です。
各画像のサイズは224×224で、すべてRGBの画像データです。
「訓練データラベル」のラベル毎のテーマは下記の通りです。
label | テーマ | 絵画の詳細(一例) |
---|---|---|
0 | 受胎告知 | 処女マリアがキリストを妊娠したことを告げられる |
1 | キリストの降誕 | イエス・キリストが誕生する |
2 | 聖家族 | 幼少年時代のイエス・キリスト、養父ヨセフ、聖母マリア |
3 | 羊飼いの礼拝 | イエス・キリストを目にするために羊飼いが訪れる |
4 | 東方三博士の礼拝 | マリアとイエス・キリストを拝み、乳香、没役、黄金を捧げる |
5 | エジプトへの逃避 | 養父ヨセフは、ヘロデ王のたくらみを避けて、マリアとともにエジプトへと逃れる |
6 | イエスの洗礼 | ヨルダン川で洗礼者ヨハネからイエスは洗礼を受ける |
7 | 最後の晩餐 | イエスが処刑される前夜、十二使徒と共に食事をしている。使徒の一人が裏切者であることが告げられる |
8 | 茨の冠 | 笞打ちの刑となったイエスが、兵士から茨でできた冠をかぶせられあざ笑われる |
9 | キリストの磔刑 | イエスは十字架に磔となって処刑される |
10 | キリストの嘆き | キリストの体が十字架から剥がされ、その体をイエスの友人たちが悼む |
11 | ラザロの復活 | ラザロの墓の前で、イエスが祈った直後、イエスの友人であるラザロが蘇生する |
12 | 最後の審判 | 再臨したイエスが死者に裁きを下し、天国と地獄へと振り分けられる |
データセットは、米・メトロポリタン美術館が公開している、宗教画画像を使用しています。
このコンペティションは、accuracy(正解数/全サンプル数)によって評価されます。
christ-test-imgs.npz
に対して、作成したモデルで予測を行い、 その結果を次のフォーマットのcsvファイルで提出してください。
また今回は、テストデータが少ないため、
同着を減らす措置として、public : private = 13% : 87%と、過去コンペと比べprivateの割合が多くなる設定としております。
以下のフォーマットで提出します
id,y
1,0
2,5
3,2
...
本コンペでは、開催期間終了後 賞金対象者のコードを公開し、ユーザーの皆様にチーティング有無をレビューしていただき順位確定させる、オープンレビュー方式のコンペティションを行います。
コード公開後1週間:
レビュアー(ユーザー)より、チーティングの疑いに関するコメントがある場合は、ご回答をお願いいたします。
※チーティングとは無関係のコメント(ノウハウに関する質疑 等)についてもご回答いただけると幸いですが、順位確定の判断材料とは致しません。
レビュアーからの質疑と、回答状況をふまえて、最終的に運営側で順位確定を判断します。
開始日 2021/6/28 0:00 JST
終了日 2021/9/12 24:00 JST
Private LB公開 2021/9/13 18:00 JST
エントリー締め切り なし
本コンペでは、テストデータ・外部データを用いた学習を許可します:
ただし下記データについて、ゴールドラベルを用いた学習は禁止します。
i. テストデータ 又は 外部データのうち、テストデータと被るサンプル
ii. テストデータと同一の原画より作成・加工されたサンプル
自己回帰学習や、疑似ラベル学習などにご使用ください。
※ ゴールドラベルとは、何らかの手段によって付与された正解ラベルのことです。例えば、人手で正解ラベルを付与する、外部データのメタデータなどからラベルを抽出する、などの手段によって付与されます。
人手により正解を絞り込むラベルの付与も、禁止行為とみなします。
※ ii.については、複製画・写真・スキャン画像を含みます。また、テストデータ自体の加工についても対象となります。
事前学習済みモデルの使用を許可します:
ただし、事前学習済みモデルの学習に関しては、上記1.と同じ基準が適用されます。
例えば、事前学習済みモデルの学習データに、テストデータとそのゴールドラベルが含まれている場合、そのモデルは使用できません。
その他、コンペティションの趣旨にそぐわない行為については、運営より禁止行為と判断させていただく場合がございます。
また、判断に迷うケースがありましたら、トピックを作成のうえ、運営にご連絡ください。運営にて判断・回答させていただきます。
以下ライブラリについては、ホワイトリストとし、たとえテストデータとの被りが含まれる場合も、使用に際して不正とはみなされないものとします。ホワイトリストにつきましては下記URLより参照ください。
・ホワイトリスト
https://docs.google.com/spreadsheets/d/1GSOeYEl0inJdrbt00ERrKpNWJf2sTMwggOG0crvP49Y/edit?usp=sharing
もちろん本コンペにおいては、ライブラリの使用にあたる運営確認は不要ですが、ホワイトリストにないツールの使用に際してご心配になられることもあるかと存じます。
その場合は運営にて、ホワイトリストへの追加を判断いたしますので、お気軽にお問い合わせいただけましたらと存じます。
(※ ホワイトリストへの追加申請はコンペ終了7日前までとさせていただきます)
※コンペ期間中であっても、不正が疑われる場合は、運営より確認のためメール連絡させていただくことがございます。一週間以内にご回答いただけない場合も、不正と判断させていただきます。
公平性の担保、チーティング等の不正防止のため、予告なくルールの追加・変更を行う場合がございます。
ご不便をおかけすることもあるかと思いますが、サービス向上のためご了承ください。
はい。
最も精度の高い学習モデルを作成した優勝者には、賞金を贈呈します。
順位確定までのプロセスについては、ルール「Open Review Competition」を参照ください。
可能です。チームページから作成いただけます。
こちらから作成いただけます。
コンペティション参加にはアカウント登録が必要となりますのでご注意ください。
Seed を固定することが推奨です。
ただし、Seed を固定しなくても提出用コードとしては認めています。
このチュートリアルでは、与えられた画像データに対して
を行います。
まずはデータの読み込みをしてみましょう。
import numpy as np
import os
class ChristDataLoader(object):
"""
Example
-------
>>> ukiyoe_dl = ChristDataLoader()
>>> datapath = "./data"
>>> train_imgs, train_lbls, validation_imgs, validation_lbls = christ_dl.load(datapath)
"""
def __init__(self, validation_size: float):
"""
validation_size : float
[0., 1.]
ratio of validation data
"""
self._basename_list = [
'christ-train-imgs.npz',\
'christ-train-labels.npz'
]
self.validation_size = validation_size
def load(self, datapath: str, random_seed: int=13) -> np.ndarray:
filenames_list = self._make_filenames(datapath)
data_list = [np.load(filename)['arr_0'] for filename in filenames_list]
all_imgs, all_lbls = data_list
# shuffle data
np.random.seed(random_seed)
perm_idx = np.random.permutation(len(all_imgs))
all_imgs = all_imgs[perm_idx]
all_lbls = all_lbls[perm_idx]
# split train and validation
validation_num = int(len(all_lbls)*self.validation_size)
validation_imgs = all_imgs[:validation_num]
validation_lbls = all_lbls[:validation_num]
train_imgs = all_imgs[validation_num:]
train_lbls = all_lbls[validation_num:]
return train_imgs, train_lbls, validation_imgs, validation_lbls
def _make_filenames(self, datapath: str) -> list:
filenames_list = [os.path.join(datapath, basename) for basename in self._basename_list]
return filenames_list
データのフォーマットが.npz
なので、numpy
のnp.load
関数を使って読み込みます。
それ以外のコードは、データを保存した場所(datapath)を渡すだけで、そこから読み込んでくれるようにするための処理です。
ここで定義したクラスを使うことで、以下のようにしてデータをロードすることができます。
datapath = "./"
validation_size = 0.2
train_imgs, train_lbls, validation_imgs, validation_lbls = ChristDataLoader(validation_size).load(datapath)
validation_size
ではテストデータの比率を指定しており、ここでは2割のデータをテストデータとして扱っています。
データを各クラスごとに、どんな画像データなのか表示してみます。
ここではプロットにmatplotlib
を用います。
import numpy as np
import matplotlib.pyplot as plt
class RandomPlotter(object):
def __init__(self):
self.label_char = ["0", "1", "2", "3",\
"4", "5", "6", "7",\
"8", "9", "10", "11", "12"]
def _get_unique_labels(self, labels: np.ndarray) -> np.ndarray:
label_unique = np.sort(np.unique(labels))
return label_unique
def _get_random_idx_list(self, labels: np.ndarray) -> list:
label_unique = self._get_unique_labels(labels)
random_idx_list = []
for label in label_unique:
label_indices = np.where(labels == label)[0]
random_idx = np.random.choice(label_indices)
random_idx_list.append(random_idx)
return random_idx_list
def plot(self, images: np.ndarray, labels: np.ndarray) -> None:
"""
Parameters
----------
images : np.ndarray
train_imgs or validation_imgs
labels : np.ndarray
train_lbls or validation_lbls
"""
random_idx_list = self._get_random_idx_list(labels)
fig = plt.figure(figsize=(15, 10))
for i, idx in enumerate(random_idx_list):
ax = fig.add_subplot(3, 5, i+1)
ax.tick_params(labelbottom=False, bottom=False)
ax.tick_params(labelleft=False, left=False)
img = images[idx]
ax.imshow(img, cmap='gray')
ax.set_title(self.label_char[i])
fig.show()
このコードでは、各クラスについて一つずつランダムにデータを取り出して、取り出したデータをプロットしています。
_get_random_idx_list()
では、各クラスごとにランダムにデータのインデックスを抜き出しています。
plot()
内が実際に画像をプロットするコードで、matplotlib
のimshow()
を用いて表示しています。
ここで定義したクラスを用いると、以下のようにしてデータをプロットすることができます。
RandomPlotter().plot(train_imgs, train_lbls)
RandomPlotter().plot(validation_imgs, validation_lbls)
/usr/local/lib/python3.7/site-packages/ipykernel_launcher.py:46: UserWarning: Matplotlib is currently using module://ipykernel.pylab.backend_inline, which is a non-GUI backend, so cannot show the figure.
以下のように出力を見ることで、誤識別をした宗教画の内容について確認できます。
データの前処理を行います。
ここでは、画像データに対しては、
[0, 255]
から[-1, 1]
に標準化を行います。ラベルデータに対しては,
import numpy as np
from tensorflow.keras.utils import to_categorical
class Preprocessor(object):
def transform(self, imgs, lbls=None):
imgs = self._convert_imgs_dtypes(imgs)
imgs = self._normalize(imgs)
if lbls is None:
return imgs
lbls = self._to_categorical_labels(lbls)
return imgs, lbls
def _convert_imgs_dtypes(self, imgs):
_imgs = imgs.astype('float32')
return _imgs
def _normalize(self, imgs):
_imgs = (imgs - 128.0) / 128.0
return _imgs
def _to_categorical_labels(self, lbls):
label_num = len(np.unique(lbls))
_lbls = to_categorical(lbls, label_num)
return _lbls
DNNのフレームワークであるkeras
を用いて簡易なCNNを作成して識別してみましょう。keras
はtensorflow
に統合されていますので、tensorflow
からインポートします。
(tensorflow.keras
が存在しないというエラーが出た場合は、古いバージョンのtensorflow
を使用している可能性があります。tensorflow
のアップデートを試みてください。)
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.models import Sequential
from tensorflow.keras import layers
from tensorflow.keras import backend as K
from sklearn.metrics import log_loss
# dataの準備
datapath = ""
train_imgs, train_lbls, validation_imgs, validation_lbls = ChristDataLoader(validation_size).load(datapath)
train_imgs, train_lbls = Preprocessor().transform(train_imgs, train_lbls)
validation_imgs, validation_lbls = Preprocessor().transform(validation_imgs, validation_lbls)
# modelの設定
batch_size = 128
label_num = 13
epochs = 10
# model作成
model = Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu'))
model.add(layers.Conv2D(32, (3, 3), activation='relu'))
model.add(layers.Conv2D(32, (3, 3), activation='relu'))
model.add(layers.Conv2D(32, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(label_num, activation='softmax'))
loss = keras.losses.categorical_crossentropy
optimizer = keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999)
model.compile(loss=loss, optimizer=optimizer, metrics=['accuracy'])
# modelを学習する
model.fit(train_imgs, train_lbls,
batch_size=batch_size,
epochs=epochs,
verbose=1, shuffle=True,
validation_data=(validation_imgs, validation_lbls))
# modelを評価する
train_score = model.evaluate(train_imgs, train_lbls, batch_size=batch_size)
y_train = model.predict(train_imgs)
validation_score = model.evaluate(validation_imgs, validation_lbls, batch_size=batch_size)
y_val = model.predict(validation_imgs)
print('Train loss :', train_score[0])
print('Train accuracy :', train_score[1])
print('validation loss :', validation_score[0])
print('validation accuracy :', validation_score[1])
Train on 524 samples, validate on 130 samples
Epoch 1/10
524/524 [==============================] - 154s 293ms/sample - loss: 50.7519 - acc: 0.0973 - val_loss: 6.9916 - val_acc: 0.0692
Epoch 2/10
524/524 [==============================] - 80s 152ms/sample - loss: 3.9502 - acc: 0.1069 - val_loss: 2.6364 - val_acc: 0.0308
Epoch 3/10
524/524 [==============================] - 76s 146ms/sample - loss: 2.5499 - acc: 0.1622 - val_loss: 2.5642 - val_acc: 0.0846
Epoch 4/10
524/524 [==============================] - 78s 150ms/sample - loss: 2.5421 - acc: 0.2996 - val_loss: 2.5617 - val_acc: 0.1692
Epoch 5/10
524/524 [==============================] - 79s 150ms/sample - loss: 2.5472 - acc: 0.3683 - val_loss: 2.5601 - val_acc: 0.2385
Epoch 6/10
524/524 [==============================] - 76s 146ms/sample - loss: 2.5351 - acc: 0.3359 - val_loss: 2.5542 - val_acc: 0.1923
Epoch 7/10
524/524 [==============================] - 77s 147ms/sample - loss: 2.4849 - acc: 0.2748 - val_loss: 2.5781 - val_acc: 0.2000
Epoch 8/10
524/524 [==============================] - 78s 150ms/sample - loss: 2.3697 - acc: 0.2538 - val_loss: 2.5191 - val_acc: 0.2154
Epoch 9/10
524/524 [==============================] - 76s 144ms/sample - loss: 2.2402 - acc: 0.2405 - val_loss: 2.5792 - val_acc: 0.1846
Epoch 10/10
524/524 [==============================] - 74s 141ms/sample - loss: 2.1129 - acc: 0.3550 - val_loss: 2.5157 - val_acc: 0.2154
524/524 [==============================] - 15s 30ms/sample - loss: 1.9208 - acc: 0.3874
130/130 [==============================] - 4s 30ms/sample - loss: 2.5157 - acc: 0.2154
Train loss : 1.920761760864549
Train accuracy : 0.3874046
validation loss : 2.5156759188725397
validation accuracy : 0.21538462
出力を見ると
このシンプルなモデルでは21%程度のaccになるようです。
これをベースラインとして改善してみましょう。
学習したモデルにテストデータを入力し提出ファイルを作成します。
test_imgs = np.load('./christ-test-imgs.npz')['arr_0']
test_imgs = Preprocessor().transform(test_imgs)
predict_lbls = model.predict(test_imgs, batch_size=batch_size)
上のコードでは学習データのときと同様にデータの読み込みと前処理を行い、model.predict()
を用いてテストデータに対する出力を得ています。
最後に提出データのフォーマットに合わせるため、pandas
にnumpy
のデータを渡し、インデックスとカラム名を付加します。
最後にcsvファイルに書き出すことで提出ファイルが作成されます。
import pandas as pd
df = pd.DataFrame(np.argmax(predict_lbls, axis=1), columns=['y'])
df.index.name = 'id'
df.index = df.index + 1
df.to_csv('predict.csv')
そこで,誤識別した画像に限ってプロットしてみましょう。
class MisclassifiedDataPlotter(object):
"""
このクラスへの入力はpreprocess処理済みのデータを仮定する.
"""
def __init__(self):
self.label_char = ["0", "1", "2", "3",\
"4", "5", "6", "7",\
"8", "9", "10", "11", "12"]
plt.rcParams['font.family'] = 'IPAPGothic'
def _convert_onehot2intvec(self, labels):
labels_int_vec = np.argmax(labels, axis=1)
return labels_int_vec
def _get_mixclassified_idx_list(self, labels_intvec, pred_labels_intvec):
misclassified = labels_intvec != pred_labels_intvec
mis_idxs_list = np.where(misclassified == True)[0]
return mis_idxs_list
def plot(self, images, labels, pred_labels, plot_num: int=5):
"""
Parameters
----------
images : np.ndarray
train_imgs or validation_imgs
labels : np.ndarray
train_lbls or validation_lbls
pred_labels : np.ndarray
predicted labels by trained model
plot_num : int
number of plot images
"""
labels_intvec = self._convert_onehot2intvec(labels)
pred_labels_intvec = self._convert_onehot2intvec(pred_labels)
mis_idxs_list = self._get_mixclassified_idx_list(labels_intvec, pred_labels_intvec)
random_idx_list = list(np.random.choice(mis_idxs_list, size=plot_num, replace=False))
fig = plt.figure(figsize=(15, 10))
for i, idx in enumerate(random_idx_list):
ax = fig.add_subplot(1, plot_num, i+1)
ax.tick_params(labelbottom=False, bottom=False)
ax.tick_params(labelleft=False, left=False)
img = images[idx].reshape((224, 224, 3))
ax.imshow(img)
actual_label = self.label_char[labels_intvec[idx]]
pred_label = self.label_char[pred_labels_intvec[idx]]
ax.set_title(f"{pred_label} : actual {actual_label}")
fig.show()
以下が識別ミスをした画像になります。
学習データにクラス2の画像が多く含まれるため、クラス2を出力してしまうことが多いようです。
ダウンサンプリングなどの対策が必要かもしれませんね。
prediction = model.predict(validation_imgs) # このmodelは上で作成したkerasのNNです.
mis_plotter = MisclassifiedDataPlotter()
mis_plotter.plot(validation_imgs, validation_lbls, prediction, plot_num=5)
コンペティションへの参加に際しては、ProbSpace利用規約(以下、「利用規約」といいます。)に加え、本ProbSpace参加規約(以下「本規約」といいます。)に同意いただく必要があります。利用規約にて定義された用語は、本規約においても同様の意味で用いられるものとします。
第1条(適用)
第2条(定義)
本規約において次の各用語の定義は、それぞれ以下に定めるとおりとします。
第3条(権利の帰属)
第4条(入賞者の義務)
第5条(禁止事項)
第6条(本コンペの変更、中断、終了等)
第7条(損害賠償)
第8条(本規約の変更)
当社は、必要と判断した場合には、参加者に対して事前に通知する(本コンペにかかる当社ウェブサイト上での告知その他当社が適当と認める方法を含みます。)ことにより、いつでも本規約を変更することができるものとします。なお、変更内容の通知後、参加者が当社の定める期間内に本コンペへの参加を取り消す手続をとらなかった場合には、当該参加者は変更後の規約に同意したものとみなされます。当社は、本規約の変更により参加者に生じたすべての損害について一切の責任を負いません。
第9条(その他)
本契約の準拠法は日本法とし、本契約に起因し又は関連する一切の紛争については、当社の本店所在地を管轄する裁判所を第一審の専属的合意管轄裁判所とします。
(制定)2020年6月22日