cangoxina

生産性向上見習いのブログ的な何かです

正答率ほぼ100%だった数字カード識別が全国大会ではダメダメになった話【ETロボコン2019】

f:id:korosuke613:20191202222315p:plain

こんにちは。僕は、ETロボコン2019のデベロッパー部門アドバンスドクラスに出場したK-Labというチームの平木場です。

今年の大会には、ブロックビンゴというゲームがあり、「数字カード」というアナログ数字が書かれたカードをカメラで読み取り*1、数字を当てる必要がありました。

今回は、開発環境(研究室に敷いたコース)、地区大会ではほぼ100%正答できたのに、全国大会ではまったく正答できなくなった話をします。

個人的には来年もカメラシステムは存在すると考えてますので、反面教師にしていただければと思います。

ETロボコン&EV3 Advent Calendar 2019 3日目の記事です。


目次


TL;DR(要約)

  • 数字認識を4層ニューラルネットワークを構築して識別した。とてもうまく識別できていた
  • 数字カードを入れているクリアファイルに光りが反射することがあった
  • まさか全国大会では光の反射なんてないだろうと思っていた
  • 全国大会会場でがっつり光の反射があり、数字カードの識別はぜんぜんうまくいかなかった
  • 光の反射対策をしていたチームは問題なくゲーム攻略できていた

K-Labの数字識別方法

僕たちは、数字の識別のために、4層ニューラルネットワークの分類器を用意し、自前で作成したデータセットを学習させました。

分類器

f:id:korosuke613:20191202184943p:plain

PythonでChainer利用しました。

import chainer.links as L
import chainer.functions as F
import chainer


# Network definition
class MLP(chainer.Chain):

    def __init__(self, n_units, n_out):
        super(MLP, self).__init__()
        with self.init_scope():
            # the size of the inputs to each layer will be inferred
            self.l1 = L.Linear(None, n_units)  # n_in -> n_units
            self.l2 = L.Linear(None, n_units)  # n_units -> n_units
            self.l3 = L.Linear(None, n_out)  # n_units -> n_out

    def forward(self, x):
        h1 = F.relu(self.l1(x))
        h2 = F.relu(self.l2(h1))
        return self.l3(h2)

これ実は、ChainerのMNIST分類サンプルのコードまんまです。

ただ、MNISTのデータセットは手書き数字のセットなので、ETロボコンの数字カード識別には利用できませんでした。 そこで、学習データを自前で用意しました。

データセット生成

あらかじめ撮影しておいた数字カード画像に前処理を施し、1つの数字につき1000枚の画像を自動生成しました。 前処理の際に、明るさ変更、拡大縮小、回転をランダムに行うことで、データを水増ししました。

f:id:korosuke613:20191202195221p:plain

コード全体はこちら

これらの処理を行うことで、カメラの角度や部屋の明るさが少しくらい変わっても柔軟に対応できるようになりました。

研究室ではほぼ100%正答できていた

上記の前処理を行って作ったデータセットを分類器で学習し、研究室に用意したコースで動作確認、実験をしたところ、ほぼ100%動作していました。

しかし、蛍光灯の明かりが数字カードを入れているクリアファイルに大きく反射した場合、失敗していました。

僕たちは、蛍光灯の明かりが反射してしまうのは選んだクリアファイルが良くなかったからで、大会の環境では光の反射は存在しないと思い込んでしまっていました。

だから、光の反射は無いものとして扱ってしまいました

全国大会会場でまったく正答できない

地区大会でも数字カードはいつも正しく正答できていたので、全国大会まで一切コードをいじることはありませんでした。

しかし、全国大会の試走時にさっぱり識別できなくなりました。

全国大会会場では、数字カードのクリアファイルに光ががっつり反射し、数字の一部が欠損していました。

全国大会の会場では光が反射するわけはないと考えていたのはとんでもない思い込みでした。

実際、光の反射対策をしているチームは(モデルを見る限り)いくつかあって、そういったチームはブロックビンゴでボーナスサークル設置を達成していました*2...

反省と教訓

僕たちは、数字カードに光が反射するわけがないと思い込み、光の反射対策をまったく行っていませんでした。

でも結局、運営側はわざわざそんな親切なことはしてくれないわけです。たぶん「参加チームが未知の環境にどれだけ対応できるのか」という部分も試しているんじゃないかなと思います。

今回の反省は、光が反射するわけないと思い込んでしまっていたことです。

得られた教訓は、思い込み(楽観視)は良くない本番環境をもっと考察して、要求定義はするべきだということです。

おわりに

組込み系においては、本番環境とテスト環境の差を縮めることはとても大変だと思います。毎年ETロボコンに参加して、毎年テスト環境でうまくいってたのに本番環境でこけます。

環境の差を縮めるのは限界があるので、それよりも、あらゆる環境に適用できるようなソフトウェアを作るほうが近道かもしれません。

僕は来年に就職するので、ロボコンからは身を引きますが、この記事が、後輩やこれからロボコンに参加する人への反面教師になればいいなと思います。

github.com


*1:カメラで読まずに走行体で走査するのもありですが、カメラを使った方がメリットがあると判断し、カメラを使いました。

*2:あるチームは用意しておいた数字カードの画像から取得した光の反射の形を取り除き、それを取得した数字カードの画像とパターンマッチングする?という感じの方法でやっていました。


スポンサーリンク