優勝作品:

ReadToMe

インスピレーション

ReadToMe を思いついたきっかけは、自分の子供たちです。具体的には、3 歳と 5 歳の下の 2 人の子供たちです。2 人とも本が好きなのですが、まだ自分で読むことができません。親が本を読んでやれないときに、この 2 人が使用できて、読書を楽しめるものを作りたいと思いました。

内容

ReadToMe では、深層学習とコンピュータビジョンを AWS で利用できるサービスと組み合わせています。AWS DeepLens に読んでもらいたいページを見せると、AWS DeepLens によってそのページが読み上げられます。

作成者: Alex Schultz 氏

Alex 氏と ReadToMe プロジェクトの詳細については、AWS Machine Learning のブログ記事を参照してください。

構築方法

ワークフローは単純に聞こえますが、このプロジェクトを機能させるために多数の課題を克服する必要がありました。解決する必要があった問題を以下に挙げます。

  • 読み上げる必要があるページがカメラのフレームに入ったときを判断する
  • OpenCV を使用してテキストブロックを分離し、画像をきれいにする
  • OCR (光学文字認識) を実行する
  • テキストを音声に変換する
  • スピーカーから音声を再生する

上記のステップ 1 つ 1 つで想定外の課題が発生しました (そのいくつかの課題では、このプロジェクトを期限内に終わらせることができるだろうかと思ったほどです)。

読み上げる必要があるページがカメラのフレームに入ったときを判断する

ReadToMe では、深層学習とコンピュータビジョンを AWS で利用できるサービスと組み合わせています。AWS DeepLens に読んでもらいたいページを見せると、AWS DeepLens によってそのページが読み上げられます。 DeepLens によってページを読み上げることができるようにするには、カメラのフレームに読み上げる必要がある何かがあるということを認識させるための方法が必要でした。ここで深層学習モデルを使用しました。

オンラインで検索しましたが、本のページを分類できるよう事前にトレーニングされたモデルを見つけることはできませんでした。このため、このようなタイプのオブジェクトを分類するには、新しいデータを使用してモデルをトレーニングする必要があることがわかりました。

トレーニングデータを取得するために、オンラインで検索し、子供の本の画像を見つけました。本の表紙の画像は大量にありましたが、実際には、トレーニングに使用できるように私に向けて正しい向きで誰かが本を持っている画像はありませんでした。テキストが書かれている実際のページの画像が必要でした。幸いなことに、私には子供が 4 人いて、子供向けの本が数百冊ありました。ある夜、私は約 40 冊の本を手にし、さまざまな向き、照明でさまざまな本を持ち、ページの他の部分を自分の手で隠した自分の写真を大量に撮影し始めました。

この過程で、子供向けの本のテキストブロックは本によって大きく異なることに気が付き始めました。テキストが白色で背景が黒色の場合もあれば、テキストが黒色で背景が白色の場合もあります。さまざまな色の背景に色付きのテキストが使用されている場合もあります。テキストがページの一番下に並んでいることもあれば、テキストがページの至る所に並んでいて、並び方も論理的ではない本もあります。このため、焦点を絞り込み、テキストが「なんとなく普通の」位置にある本の画像のみを取り込むことにしました。非常に幅広いデータセットを取得しようとしていたら、すべてをテキストのブロックだと考えるモデルができていただろうと思いました。この先、さまざまなタイプのデータで実験できると思いますが、このプロジェクトではタイプを限定することにしました。

データを取り込んだ後、labelImg を使用してトレーニングで使用する Pascal VOC xml ファイルを生成しました。この時点で、正しく書式設定されたデータを MXNet でトレーニングする方法を考え出すことに苦労していました。TensorFlow を使用している例を見つけたので、その方法を利用しました。プロジェクトが完成したら、最後に時間があればいつでも戻って MXNet を使用して機能させることができると考えました。YouTube で見つけた例の 1 つに倣い、ページのテキストを検出するために使用できるモデルを完成させることができました。 

光学文字認識を実行する

Tesseract をプロジェクトに簡単に統合できたことに驚きました。デバイスにインストールし、pip を使って python パッケージをインストールするだけで、ワークフローが 1 つの関数呼び出しになりました。処理する画像を指定すると、テキストが出力されます。当初は個別の Lambda 関数とインストールした Tesseract を使用して OCR を実行する予定でしたが、最終的にメインの Lambda 関数にその関数を組み込みました。より簡単で、AWS との間のトラフィックを減らすことができるためです。実際の OCR では、あまり多くの処理能力を使用しているようには見えませんが、AWS とのラウンドトリップと比較すると、時間は同程度のように見えました。加えて、現在は「エッジで」より多くのことを行っているため、効率を向上させ、コストを抑えることができます。

Tesseract に関して 1 つわかったことがあります。それは、画像の品質にうるさいということです。はっきりと読み取ることができる程度に画像をきれいにする方法を見つけるのに相当な時間がかかりました。また、テキストはほぼ完全に水平にする必要があります (就学前の子供が使えるようにしたいと考えているため、これはほとんど不可能です)。この画像の事前処理のほとんどに OpenCV を使用し、試行錯誤した結果、単色の黒色と白色のテキストで、ノイズを最小限に抑えた画像を生成することに成功しました。これは、このプロジェクトを成功させるうえで重要なポイントでした。最終的には予想よりも良い結果となりましたが、この部分についてはまだ改善の余地があります。

テキストを音声に変換する

このステップはプロジェクト全体の中で最も簡単なものでした。デバイスで再生する音声を入手したら、このロジックを 1 つの関数呼び出しにカプセル化することができました。この関数呼び出しでは、AWS Polly を呼び出して音声ファイルを生成します。ファイルをディスクに書き込むことはせず、バイトストリームを音声ライブラリに提供し、再生が終わったら破棄します。私は、Greengrass サービスの開始時に再生される静的な mp3 ファイルをいくつか持っています。この音声ファイルを使用してユーザーに手順を説明し、ユーザーがデバイスの使用方法を理解できるようにします。この説明が変更されることはないため、Polly を呼び出してこの音声を生成する理由はないと判断し、事前に音声を生成して Lambda でデプロイしました(AWS の既存のサービスをプロジェクトに簡単に統合できる点が気に入りました)。

スピーカーから音声を再生する

Greengrass では、コードによってアクセスするすべてのハードウェアを明示的に認可する必要があります。これを設定する方法の 1 つとして、AWS IoT コンソールの [Group Resources (グループリソース)] セクションを使用する方法があります。設定したら、これらの設定を DeepLens にデプロイします。その結果、greengrass ディレクトリの JSON ファイルがデバイスにデプロイされます。

Lambda から音声を再生できるようにするには、2 つのリソースを追加する必要があります。DeepLens のサウンドカードはパス "/dev/snd/" にあります。音を再生するには "/dev/snd/pcmC0D0p""/dev/snd/controlC0" の両方を追加する必要があります。

ちなみに、これらのリソースはプロジェクトをデバイスにデプロイするたびに追加し直す必要があります。これを書いている時点では、プロジェクトを DeepLens にデプロイするたびに Greengrass によって事前設定済みの group.json を使用してリソースファイルが上書きされます。 

成果

このプロジェクトの最終結果に非常に満足しています。フルタイムで仕事をし、4 人の子供を育てながら、わずか数か月ですばらしいプロジェクトを実際にまあまあ機能するように作ることができました。このデバイスを使用した今後のプロジェクトについてもさらにアイデアがあり、ぜひ学び続けたいと思っています。 

学んだこと

このプロジェクトを開始するまで、深層学習や AI 全般に関する経験はありませんでした。このトピックには常に関心を持っていましたが、「普通の開発者」にとっては近寄りがたいものだと考えていました。この過程を通じて、数学の博士号を取得していなくても、実際に役立つ深層学習のプロジェクトを作成でき、頑張って根気よく取り組めば、普通の開発経験の持ち主でも使い始めることができることがわかりました。 

ReadToMe の次のステップ

このプロジェクトを改善するためのアイデアがいくつかあり、読み上げるテキストを翻訳する機能を追加したいと考えています(Amazon の新しい Translate サービスの早期利用を申し込みましたが、まだ承認されていません)。 また、モデルを改善し続け、モデルの精度を少し向上させることができるのか、さまざまな本で機能するようにできるのかを確認する予定です。

最後に、Tesseract に直接送信されるテキスト画像のクリーンアップ機能は改善できます。具体的には、Tesseract に送信する前に画像を回転させたり、変形させたりできる方が便利です。そうすることで、子供が本を正しく持っていなくても、テキストを読み取ることができます。モーションブラーも画像のクリーンアップで取り組む必要があった問題でした。本を持ち上げているときに本が数秒間少しでも動いてしまうと、画像がぼやけ、OCR が機能しなくなります。複数のフレームにわたって画像の平均化を使用する、画像にさまざまなフィルターを適用してピクセルをなめらかにするなど、この問題を解決するためのさまざまな手法について読みました。今よりも良い結果をすばやく達成できるという自信はあるのですが、リソースに制約があるデバイスでは難しい作業です。

役立つリソース

多数のオンラインリソースの助けを借りましたが、中でも以下のリンクは最も役に立ちました。

(順序に意味はありません)

https://becominghuman.ai/an-introduction-to-the-mxnet-api-part-1-848febdcf8ab
http://gluon.mxnet.io/chapter08_computer-vision/object-detection.html?highlight=ssd
https://github.com/apache/incubator-mxnet/blob/master/example/image-classification/README.md
https://github.com/zhreshold/mxnet-ssd
https://pythonprogramming.net/introduction-use-tensorflow-object-detection-api-tutorial/

また、フォーラムで質問に答えてくださった参加者の皆さん、特に何度も助けてくれた AWS DeepLens チームに感謝します。:)

使用したもの

OpenCV
DeepLens
Python
Polly
tesseract-ocr
Lambda
MXNet
TensorFlow