日本画の登場人物分類

古来の絵巻物/絵本の画像から、登場人物の身分を推測しよう!

賞金: 100,000 参加ユーザー数: 171 2年以上前に終了

ホワイトリストルール追加のお知らせ
Imagenet等汎用的に使われる学習済みモデルが、テストデータ使用不可の制約にかかる可能性があるとのご指摘を受け、ルールを追加いたしました。下記ホワイトリストについては、たとえテストデータとの被りが含まれる場合も使用可とさせていただきます。

ホワイトリスト

なお、本コンペにおいては、当初通り外部データ・学習済みモデル使用にあたる運営確認は不要です。ホワイトリストにないモデルの使用について、ご心配な場合はトピック等でお気軽にお問い合わせください。運営にて判断させていただきます。

テーマの背景

日本では古くから源氏物語や伊勢物語などの文学作品が、絵巻物や絵本として出版されており、時代背景を反映した様々な人間模様が描かれてきました。

中でも登場人物の描かれ方は、当時の性差への考え方の他、平民、武士、貴族といった身分制度に強く影響されており、現代とは大きく異なる、特徴的な描かれ方がされています。

例えば、貴族や皇族、その従者などの人物は、「下膨れの顔」「一重の目」「小さな口」等の、引目鉤鼻(ひきめかぎはな)と呼ばれる共通の特徴をもって描かれることが一般的です。この特徴は身分の低い人物の肖像画では見られ無いものになります。

引目鉤鼻は、「読者である貴族に対して、自分と近しい登場人物を親しみやすく描いた」「抽象的な表現であることが高貴さを表す表現として認識されていた」等、所以については諸説あります。

引目鉤鼻の例(源氏物語「夕霧」より)
f6a2ceec-c1b2-4ad5-83f4-04ec0261ef8e.png

こうした人物の描き方の特徴は、人文科学の分野では考察が進められており、当時の風俗や価値観に対して理解を深める手掛かりになることもあります。

今回は、絵巻物や絵本のデータから登場人物を分類するタスクに取り組んでいただきます。コンペティションで扱うデータとしては、人文学オープンデータ共同利用センター(CODH)の提供する、顔貌データを用いております。

賞金

1位 100,000円

※ 対象者には、コンペティション終了後メールにて連絡いたします

締め切り

終了 2022/8/7 22:00 JST
LB公開 2022/8/7 24:00 JST

ダウンロード

データをダウンロードするにはログインまたはユーザー登録して下さい

概要

コンペに使用するデータは2つに分けられます。

  • 訓練データ(train_data.npz)
  • テストデータ(test_data.npz)
  • サンプル提出データ(submission.csv)

これらのデータは『顔コレデータセット』(CODHが国文学研究資料館・ROIS-DS人文学オープンデータ共同利用センター、慶應義塾大学、京都大学附属図書館から収集、DOI:10.20676/00000353)を訓練データとテストデータに分割し、訓練データにラベルを付加したものです。

訓練データとテストデータはそれぞれ6,446件、2,000件のデータが含まれております。

訓練データ (train_data.npz)

npzファイルのarr_0には256x256x3の画像が含まれます。
arr_1にはデータラベル(0: noble, 1: warrior, 2: incarnation, 3: commoner)が含まれます。

テストデータ (test_data.npz)

npzファイルのarr_0には256x256x3の画像が含まれます。

※顔コレデータセットを活用した研究成果を発表する際には、以下の論文の引用をご検討下さい。
Yingtao Tian, Chikahiko Suzuki, Tarin Clanuwat, Mikel Bober-Irizar, Alex Lamb, Asanobu Kitamoto, "KaoKore: A Pre-modern Japanese Art Facial Expression Dataset", arXiv:2002.08595.

評価指標

各画像中の人物の身分(y)について、整数値で予測してください。

  • モデルの予測性能はMacro-F1で評価されます。
    $precision_k = \frac{TP_k}{TP_k + FP_k}$
    $recall_k = \frac{TP_k}{TP_k + FN_k}$
    $F1_{macro} = \frac{1}{8}\sum_{k=0}^{7} \frac{2 * precision_k * recall_k}{precision_k + recall_k}$
    ここで$TP_k$, $FP_k$, $FN_k$は各クラスについてのTrue Positive, False Positive, False Negativeとします。
  • 評価値は0以上1以下の値をとり、精度が高いほど大きな値となります。

提出ファイルの形式

回答用のsubmission.csvを用意する(エントリーとヘッダー行を含む) 。
提出されたファイルに余分な行や列(idとy以外)が含まれていた場合はエラーとなります。

提出ファイルは以下の列のみを含んでください:

  • id(テストデータセットと同じ順序)
  • y(予測された身分、0: noble, 1: warrior, 2: incarnation, 3: commoner)

以下は提出ファイルの例です。

id,y
1, 0
2, 1
3, 3
4, 0
...

コンペティションルール

■Open Review Competition

本コンペでは、開催期間終了後 賞金対象者のコードを公開し、ユーザーの皆様にチーティング有無をレビューしていただき順位確定させる、オープンレビュー方式のコンペティションを行います。


賞金対象ユーザー

コンペ終了後1週間以内:
トピックにて、学習過程の分かるコードの公開をお願いいたします。 (簡易解説までつけていただけると助かります。)

コード公開後1週間:
レビュアー(ユーザー)より、チーティングの疑いに関するコメントがある場合は、ご回答をお願いいたします。
※チーティングとは無関係のコメント(ノウハウに関する質疑 等)についてもご回答いただけると幸いですが、順位確定の判断材料とは致しません。


レビュアー(ユーザーの皆様)
コード公開後1週間: 公開コードを確認いただき、チーティングが疑われる場合は、トピックを通して質疑の投稿をお願いいたします。

レビュアーからの質疑と、回答状況をふまえて、最終的に運営側で順位確定を判断します。

■順位決定ロジック
  1. コンペ期間中はPublicリーダーボード(以下LB)により暫定評価を、最終結果についてはPrivate LBにより評価します。
    ※ Private LBはコンペ終了と同時に表示されます。
  2. Private スコア計算に使われるファイルについては、2つまで選択可能です。
    ※ 未選択の場合は、Public スコアの上位ファイルが提出上限まで自動選択されます。
  3. スコアが同値の場合は、早い日時に提出いただいたユーザーが上位となります。
  4. コンペ終了後であっても、不正が発覚の際は、対象ユーザーは失格となり、全体の順位が繰り上がります。
    順位繰上げにより賞金対象者となられた場合は、繰上げ日より一週間以内に、トピックにてコードを公開いただき、「Open Review Competition」と同様のフローにて順位を確定させていただきます。
■タイムライン

開始日 2022/5/16 0:00 JST
終了日 2022/8/7 22:00 JST
LB公開 2022/8/7 24:00 JST

エントリー締め切り なし

■システム利用
  • 参加者ごとに1つのアカウントでご参加ください
  • チーム参加の場合は、最大5名までエントリー可能です
  • 1日あたり、最大5回までの提出が可能です
■禁止事項
  • ユーザー間での情報共有
    コンペティションに関連するコード・データを、チーム外のユーザーと共有することはできません。全参加者が利用できる場合に限り、共有可能です。

  • 外部データ/学習済みモデルの使用
    本コンペティションの基本情報/データから取得できるデータのみを用いてチャレンジして下さい。
    ただし、コンペ外データ(人文学オープンデータ共同利用センター公開データが明示的に含まれているものは除く)を用いて学習された学習済みモデルの使用は可能とします。

※コンペ期間中であっても、不正が疑われる場合は、運営より確認のためメール連絡させていただくことがございます。一週間以内にご回答いただけない場合も、不正と判断させていただきます。

■ホワイトリストの使用について(2022/7/31更新)

以下ライブラリについては、ホワイトリストとし、たとえテストデータとの被りが含まれる場合も、使用に際して不正とはみなされないものとします。
ホワイトリストにつきましては下記URLより参照ください。

・ホワイトリスト
https://docs.google.com/spreadsheets/d/1GSOeYEl0inJdrbt00ERrKpNWJf2sTMwggOG0crvP49Y/edit?usp=sharing

本コンペにおいては、ライブラリの使用にあたる運営確認は不要ですが、ホワイトリストにないツールの使用に際してご心配になられることもあるかと存じます。
その場合は運営にて、ホワイトリストへの追加を判断いたしますので、お気軽にお問い合わせいただけましたらと存じます。

※注意事項

  • 上記をラップしたツールキットは申請不要で使用可能
  • データを追加し再学習されたモデルについては原則使用不可(要申請)
■運営からのお願い

公平性の担保、チーティング等の不正防止のため、予告なくルールの追加・変更を行う場合がございます。
ご不便をおかけすることもあるかと思いますが、サービス向上のためご了承ください。


FAQ

このコンペティションでは賞金はでますか?

はい。
最も精度の高い学習モデルを作成した優勝者には、賞金10万円を贈呈します。
順位確定までのプロセスについては、ルール「Open Review Competition」を参照ください。

チームで参加できますか?

可能です。チームページから作成いただけます。

どこでアカウントをつくればいいですか?

こちらから作成いただけます。

コンペティション参加にはアカウント登録が必要となりますのでご注意ください。

コードを提出するにあたって Seed を固定する必要はありますか?

Seed を固定することが推奨です。
ただし、Seed を固定しなくても提出用コードとしては認めています。

提出回数はいつリセットされますか?

ファイル提出後、23時間ごとにリセットとなります。
グローバル展開していくにあたり、居住国(時差)による有利・不利を最小化するため、一定時間でリセットする仕様としております。

このチュートリアルではkaokoreデータに対して

  • データの読み込み
  • データのプロットと確認
  • pytorchを用いたCNNモデルの作成、学習
  • 誤識別したデータの確認
  • 提出データの作成

を行います

まずは必要なライブラリをインポートしましょう。

import numpy as np
import pandas as pd

import torch
from torch import nn, optim
import torchvision
from torchvision import models
import torchvision.transforms as transforms

import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline

環境

! python --version
Python 3.7.4
print('numpy', np.__version__)
print('pandas', pd.__version__)
print('matplotlib', matplotlib.__version__)
print('torch', torch.__version__)
print('torchvision', torchvision.__version__)
numpy 1.17.4
pandas 1.0.2
matplotlib 3.1.3
torch 1.4.0
torchvision 0.5.0

データの読み込み

まずはデータの読み込みをしてみましょう。
このコンペでは画像とラベルの組み合わせからなる学習データ(train_data.npz)と
画像のみを含むテストデータ(test_data.npz)が提供されています。
npzファイルをnp.load関数を用いて読み込みます。

data_dir = '../compe_data/'
train_X, train_Y = np.load(data_dir + 'train_data.npz').values()

読み込まれたデータは(データ数, 高さ, 幅, チャンネル)の順番で格納されています。
pytorchで利用できる形式である(データ数, チャンネル, 高さ, 幅)の順に変更します。

train_X = train_X.transpose((0, 3, 1, 2))

pytorchではDataLoaderを用いることで、バッチごとにデータを取り出すことができます。

train_data = torch.utils.data.TensorDataset(torch.from_numpy(train_X).float(), torch.from_numpy(train_Y.astype(np.int64)))
train_loader = torch.utils.data.DataLoader(train_data, batch_size=64, shuffle=True)

データをプロットして確認

作成したtrain_loaderを用いていくつかデータを表示してみます。ここではmatplotlibを用いてプロットをします。

class_names = ('noble', 'warrior', 'incarnation', 'commoner')
def imshow(data, title=None):
    """Imshow for Tensor."""
    data = data.numpy().transpose((1, 2, 0))
    data = (data / 255)
    data = np.clip(data, 0, 1)
    plt.imshow(data)
    if title is not None:
        plt.title(title)


# DataLoaderからバッチを取り出す
inputs, classes = next(iter(train_loader))

# 4つだけ表示する
out = torchvision.utils.make_grid(inputs[:4])

imshow(out, title=[class_names[x] for x in classes[:4]])

782b3092-1dd3-402a-864c-6b511b8e77db.JPG

pytorchを用いたCNNモデルの作成、学習

DNNのフレームワークであるpytorchを用いてCNNを作成して分類をおこなっていきます。

まず、GPUを用いてCNNの学習を行いたいのでCUDAが利用可能な場合にはCUDAを有効にします。

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

torchvisionはpytorchのパッケージで画像認識において頻繁に使われるネットワークアーキテクチャや学習済みモデル、データセット、前処理などの機能を提供しています。
今回はtorchvisionに含まれるresnet18というモデルを用いて学習を行います。

model = models.resnet18()

今回は4クラスの分類を行うのでネットワークの最終層の出力の次元数を変更します。

num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, 4)

作成したmodelをGPUへ転送します。

model = model.to(device)

損失関数と最適化アルゴリズムを設定します。分類問題のためクロスエントロピー損失関数を利用し、
最適化アルゴリズムにはSGDを利用します。

criterion = nn.CrossEntropyLoss()

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

ここから、実際にモデルの学習を行っていきます。
toメソッドによって入力とラベルをGPUへ転送しています。
optimizer.zero_grad()を呼び出して、ネットワークの各パラメータに保存されている勾配情報を初期化します。
モデルの出力outputsと正答ラベルlabelsから
損失関数の値を計算します。
loss.backward()によって誤差逆伝播を行い各パラメータの勾配を更新します。
optimizer.step()によって更新された勾配を元にパラメータの値を更新します。

log_interval = 10
for epoch in range(10):
    running_loss = 0.0
    for i, data in enumerate(train_loader, 0):
        inputs, labels = data
        inputs /= 127.5
        inputs -= 1.0
        inputs, labels = inputs.to(device), labels.to(device)
        optimizer.zero_grad()

        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        if i % log_interval == (log_interval - 1):
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / (log_interval)))
            running_loss = 0.0

print('Finished Training')
[1,    10] loss: 1.333
[1,    20] loss: 1.195
[1,    30] loss: 1.009
[1,    40] loss: 1.346
[1,    50] loss: 1.267
[1,    60] loss: 1.018
[1,    70] loss: 1.146
[1,    80] loss: 1.160
[1,    90] loss: 1.046
[1,   100] loss: 1.219
[1,   110] loss: 1.264
[1,   120] loss: 1.119
[1,   130] loss: 1.164
[1,   140] loss: 1.089
[1,   150] loss: 1.310
[1,   160] loss: 1.244
[1,   170] loss: 1.220
Finished Training

学習したモデルを用いて学習データに対する正答率を見てみましょう。
モデルの出力はあるクラスに属する確率値のようなものなのでtorch.max関数を用いて各出力で最も大きい値を持つインデックスを取得します。
この予測されたラベルを用いて正答率を計算します。

correct = 0
total = 0
wrong_data = []
with torch.no_grad():
    for data in train_loader:
        images, labels = data
        images /= 127.5
        images -= 1.0        
        images, labels = images.to(device), labels.to(device)        
        outputs = model(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
print('accuracy', 100 * correct / total)
accuracy 79.59975178405213

学習データにおける正答率は80%程度でした。

誤識別したデータを確認

続いて誤識別したデータを確認します。
正答率を求めたときとは逆に、予測されたラベルが正答ラベルとことなるデータのインデックスを取得し、プロットします。

grid = torchvision.utils.make_grid(images[predicted != labels].cpu()[:5])
grid += 1.0
grid *= 127.5
imshow(grid, title=['predict:'+ str(pred.item())+' actual:' + str(truth.item()) for pred, truth in zip(predicted[predicted != labels][:10], labels[predicted != labels].data)][:5])

6ed0477f-323b-4a07-8e85-a76b2d09ccc5.JPG

このモデルでは、後姿を誤認識してしまい”化身”と認識してしまうことがあるようです。

提出データの作成

最後にテストデータを用いて提出データを作成します。
学習データと同様にtest_data.npzを読み込み、DataLoaderを作成します。

test_X = np.load(data_dir + 'test_data.npz')['arr_0']
test_X = test_X.transpose((0, 3, 1, 2))
test_data = torch.utils.data.TensorDataset(torch.from_numpy(test_X).float())
test_loader = torch.utils.data.DataLoader(test_data, batch_size=64, shuffle=True)
predicts = []
with torch.no_grad():
    for x in test_loader:
        x = x[0]
        x /= 127.5
        x -= 1.0
        x = x.to(device)
        out = model(x)
        _, predicted = torch.max(out.data, 1)
        predicts.append(predicted.cpu().numpy())

提出データはid,yのカラムを持つcsvファイルとします。

sub = pd.DataFrame(np.concatenate(predicts), columns=['y'])
sub.index.name = 'id'
sub.index += 1
sub.to_csv('submission.csv')

「日本画の登場人物分類」コンペティション参加規約

コンペティションへの参加に際しては、ProbSpace利用規約(以下、「利用規約」といいます。)に加え、本ProbSpace参加規約(以下「本規約」といいます。)に同意いただく必要があります。利用規約にて定義された用語は、本規約においても同様の意味で用いられるものとします。

第1条(適用)

  1. 参加者(第2条に定義します。)は、コンペティションに参加した時点で、本規約、利用規約、その他ご同意いただいた規約のすべて、及びコンペティションサイトに掲載されているコンペティションに関するルールの一切に同意したものとみなされます。
  2. 本規約、利用規約、その他ご同意いただいた規約のすべて、及びコンペティションサイトに掲載されているコンペティションに関するルールは、コンペティションの終了後も参加者に適用されます。

第2条(定義)
本規約において次の各用語の定義は、それぞれ以下に定めるとおりとします。

  1. 「本コンペ」とは、当社ウェブサイト上で開催されるAI開発又はデータ分析等に関するコンペティションのうち、本規約に紐づく特定のコンペティションを意味します。
  2. 「主催者」とは、当社またはユーザーのうち、本コンペを主催する者を意味します。また、本コンペが、当社の顧客又は提携先の企業、学校その他の団体等がスポンサードするものである場合は、当該団体等も主催者の定義に含まれます。
  3. 「参加者」とは、ユーザーのうち、主催者側以外の立場で本コンペに参加する方を意味します。
  4. 「成果物」とは、本コンペにおいて参加者により開発される学習済みモデル、そのソースコード及び乱数シード等の設定値を意味します。
  5. 「入賞者」とは、当社より本コンペに入賞した旨の通知を受けた参加者を意味します。
  6. 「知的財産権」とは、著作権(著作権法第27条及び第28条に定める権利を含みます。)、特許権、実用新案権、商標権、意匠権、その他のノウハウ及び技術情報等の知的財産権(それらの権利を取得し、又はそれらの権利につき登録等を出願する権利を含みます。)を意味します。

第3条(権利の帰属)

  1. 本コンペで発生した成果物に関する知的財産権は、参加者に帰属します。

第4条(入賞者の義務)

  1. 入賞者は、本コンペで公開した成果物を、MITライセンスを適用し、商用利用の許諾条項及び著作権人格権の包括的不行使条項をライセンス条項に付与した形式で、オープンソースソフトウェアとして公開する義務を負うものとします。その前提として、入賞者は、成果物について本項に基づく方法でオープンソース化する権利を有していることを当社に対して表明保証するものとします。
    ※第三者が、授業・研修・セミナー等で活用できるようにするための規約となります。ご理解のほどよろしくお願いいたします。
  2. 当社は、以下の3点の確認が完了した時点で、本コンペの賞金または商品を、入賞者に対して授与するものとします。
    1. 入賞者が、前項に基づいて成果物のオープンソース化を実施したこと
    2. 入賞者が、本規約、利用規約、その他ご同意いただいた規約のすべて、及びコンペティションサイトに掲載されているコンペティションに関するルールの一切に違反していないこと
    3. 当社が定める方法による本人確認
  3. 当社は、入賞者が第1項に基づいてオープンソース化した成果物を、自由に商用利用することができます。

第5条(禁止事項)

  1. 参加者は、本コンペにおいて、以下の各号のいずれかに該当する行為を行ってはならないものとします。
    1. クラッキングやチート行為、なりすまし、盗用等の不正行為
    2. 第三者の知的財産権その他の権利を侵害する内容ないし態様で、参加者公開事項を公開する行為
    3. 主催者(当社以外の者に限ります。)に対する直接連絡、相談、依頼、勧誘、勧誘対応等の活動(但し、当社を介して当社が認めた方法により行うものは除きます。)
    4. 本コンペにおいて、当該コンペと直接関係のない成果物等を提出すること
    5. 本規約における参加者としての地位又は参加者としての権利義務について、譲渡、移転、担保設定、その他の処分をすること
    6. その他、本規約、参加ルール及び利用規約に違反する行為
  2. 参加者が前項に規定する禁止行為を行ったと当社が認める場合、当社は、当該参加者に事前に通知することなく、当該参加者の本コンペにおける失格処分、当社サービスの全部又は一部の利用停止、ユーザー登録の抹消、その他当社が必要と判断した措置をとることができるものとします。

第6条(本コンペの変更、中断、終了等)

  1. 当社は、参加者に事前の通知をすることなく本規約に基づく本コンペの開催内容の変更、本コンペの一時的な中断又は終了を行うことができます。
  2. 当社は、本条に基づき当社が行った措置により生じた結果及び損害について、一切の責任を負わないものとします。

第7条(損害賠償)

  1. 参加者は、本コンペに関連して、自らの責に帰すべき事由により、当社、主催者その他の第三者に損害を与えた場合には、その一切の損害(逸失利益、弁護士費用を含みます。)を賠償するものとします。
  2. 参加者が本規約の規定に違反したことにより主催者(当社を除きます。)その他の第三者が当社に対して何らかの訴え、異議、請求等がなされた場合において、当社から処理の要請がなされたときは、参加者は自己の責任と費用負担において、当社に代わって当該第三者との紛争を処理するとともに、当社がかかる訴え、異議、請求等により被った一切の損害(逸失利益、弁護士費用を含みます。)を賠償するものとします。

第8条(本規約の変更)
当社は、必要と判断した場合には、参加者に対して事前に通知する(本コンペにかかる当社ウェブサイト上での告知その他当社が適当と認める方法を含みます。)ことにより、いつでも本規約を変更することができるものとします。なお、変更内容の通知後、参加者が当社の定める期間内に本コンペへの参加を取り消す手続をとらなかった場合には、当該参加者は変更後の規約に同意したものとみなされます。当社は、本規約の変更により参加者に生じたすべての損害について一切の責任を負いません。

第9条(その他)
本契約の準拠法は日本法とし、本契約に起因し又は関連する一切の紛争については、当社の本店所在地を管轄する裁判所を第一審の専属的合意管轄裁判所とします。

(制定)2020年6月22日