エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

機械学習で逆ストリートビューを作り、写真から港区らしさを判定する

f:id:Hi_king:20211207223201g:plain
テストデータでの予測結果

先日新橋を散歩していたときの会話。

妻 "こういう路地って新橋らしさあるよねー"

私 "本当です?どういうところで当てられるの?"

妻 "歩道の雰囲気?"

私 "うーん"

ということで、MLエンジニアたるもの、そんなことが本当にできるのか機械学習で検証してみましょう。

写真から撮影場所を当てる

こんにちは、AI・機械学習チームリーダーの大垣(id:Hi_king)です。 これは エムスリー Advent Calendar 2021 の11日目の記事です。 前日は山本さんによる、クラウド電子カルテに頑張らないデザインシステムを導入する でした。

さて、今日は普段の業務とは関係のない、日常の興味をMLエンジニアリングで解決していきます!

作るもの

f:id:Hi_king:20211210140420p:plain

道端で撮影した写真を入れて、それがどこの市区町村かを当てられるモデルを作ることができれば、冒頭の疑問の検証は完了ということになります。 ここでは、図示したようなCNNモデルを作成します。

そのためには、 市区町村 -> 写真を手に入れるにはGoogle Mapsのストリートビューを使えばいいということが思いつきますね。 ということで詳細は後述しますが、今回はストリートビューを通じて集めたデータを用いて学習し、逆に写真 -> 市区町村を出力する逆ストリートビューモデルを作成しました。

ということでデータセットを集めることができ、ともかく、GPUを回して部屋を温めること1週間(データやaugmentationの試行錯誤)、完成しました。

github.com

コードは学習データの作成から全て公開してますので、皆さんも是非作ってみてください。

港区らしさとは

さて、まずはテストセットでの性能を見てみます。

f:id:Hi_king:20211210141857p:plain
予測性能

思ったより当たりますねー。 ちなみに、自分の出身地であるという理由だけで入れた北海道旭川市は、あまりに東京と違いすぎて、ほとんど混同されることはありませんでした。精度が出て悲しい気持ちになったのは初めてかもしれない。

混同しやすいのは港区と渋谷区のペア、中央区と千代田区のペアですね。どちらもお隣の区同士なので納得です。

さて、じゃあどうして当てられるのか、を考えてみましょう。まずは、最初の会話で、当てやすいかもなーと思っていた港区はどういう特徴を持ってるのかを見るために、港区スコアTOP7の場所を見てみます。

f:id:Hi_king:20211210155733p:plain f:id:Hi_king:20211210155747p:plain
港区らしさTOP7

予想していたキラキラ感とは違い、なんと、1位も2位も塀!ですね。

f:id:Hi_king:20211210162920p:plain
私が港区らしいと思う写真

ちゃんと港区らしい写真もスコア高いので、もちろん塀だけが特徴ではないのですがw

柵でわかる中央区・千代田区・江東区

さて、ニューラルネットワークは、この日常的な風景からどのようにその地域らしさを判定しているのでしょうか? 他の区ついても上位を見てみます

f:id:Hi_king:20211210132739p:plain f:id:Hi_king:20211210132759p:plain
江東区らしさTOP7

お気づきでしょうか。

他の区も見てみます

f:id:Hi_king:20211210132245p:plain f:id:Hi_king:20211210132259p:plain f:id:Hi_king:20211210132413p:plain
f:id:Hi_king:20211210132318p:plain f:id:Hi_king:20211210132334p:plain

そう、おそらくを見てるみたいなんです。

気になって調べてみると、やはり

gazoo.com

ということで冒頭の会話の、"歩道の雰囲気"は当たらずとも遠からずであることがわかりました!

最もXX区に間違えそうなYY区の写真とは

さて先ほどは数値で性能を検証したわけですが、実際他の区と間違われちゃう場所ってどこなんでしょうか。

f:id:Hi_king:20211210210338p:plain

先ほど混同の多かった港区と渋谷区のペアは、背が低めの住宅街という雰囲気の共通みたいですね。 中央区と千代田区のペアはその逆で、無機質なビル街という感じです。

千代田区だと間違われる新宿区では桜が咲いていたり、江東区だと間違われる旭川市では立体駐車場(倉庫っぽく見える?)だったり、なんとなくニューラルネットワークのお気持ちがわかる結果となっていますね。

ストリートビューには室内の画像も入ってしまっており、今回は特に屋外に制限せずに学習したのですが、当たり前に室内の方が場所を当てるのは難しいようです。旭川らしい東京の土地がないが故に、旭川らしいX区の写真は結構室内のよくわからない場所が選ばれてしまってます。次やるときは屋外に限定した方が良さそうですね。

技術的な話

参考論文: PlaNet

実は今回のタスクには、参考にしている偉大な論文があります。

research.google

Is it possible to build a system to determine the location where a photo was taken using just its pixels?

Abstractの一文目が刺激的な書き出しで始まっている通り、このネタの開拓者です。

この論文では、全世界を対象にし、なんと26263クラス分類問題として解いてます。今回の柵みたいな、世界中の位置の手がかりが一つのニューラルネットのパラメータの中に閉じ込められてると考えると浪漫がありますよね *1 *2

www.geoguessr.com

この論文では最終的にGeoguessrのゲームで人間*3と競わせて、人間よりエラーが少ないという結果も出しています。 Geoguessrのゲームの発想がなかったらこの研究もなかったし私の記事もなかったかもなので、こちらも偉大ですね。

私はこの論文の話が非常に好きなので、冒頭の会話から、このモデルを自作しようという発想になったのです。

Google Streetview API と Geolonia API

さて、画像 -> 区を当てるモデルを作るためには、画像と区のペアワイズデータセットが必要になるわけです。

この段階で、先行研究などから考えて大きく2つの方法が考えられると思いました。

  1. 大量のEXIFタグ付き画像を収集して -> EXIFタグから緯度・経度を取得 -> 緯度・経度から市区町村に変換
  2. 市区町村から緯度・経度をランダムサンプリングして -> その位置の写真をGoogle Streetviewで取得する

方法1については、よく撮影される場所のよく撮影される角度の写真が集まりやすく、用途から考えて理想的かなとも思ったのですが、どこから写真データをクローリングしようか、というのがパッと思いつかなかったので一旦保留しました。

2については最初に論文を調査した段階で、おそらくStreetView APIが使えるだろうと知っていたので、そこは解決、 市区町村の緯度・経度サンプリング方法をどうしようかな、と考えました。

ベクトルマップ的なものから厳密にやる方法もあると思うのですが、個人的な過去の経験から、日本の地図においては、"字(あざ)"の情報が便利に使えることを知っていたため、字ごとに均等にサンプリングする手法を取りました。

学習について

深層学習にはデータ数が命、な訳ですが、今回の問題設定では基本的には前述の方法で、お金の許す限りデータを集めることができます。 とはいえお金は有限ですので*4、最終的に私は各地域5000~10000枚程度で、計30000枚ほどの画像を集めました。

加えて、風景画像であるという性質上、拡大やcropが強力なaugmentationとして効くので、RandomResizedCropのaugmentationを入れて学習すれば、あとはそこまでこみいったことをせずとも十分な学習ができました。

他の地域の分類機を作る

github.com

今回のコードはデータセット作成から学習まで公開しているので、ぜひ他の地域のモデルも作ってみてください! 北海道旭川市が入っているように、基本的に日本のどの自治体でも対応できると思いますので、私だけでは(お金の問題で)全地域はできませんが、他の地域の結果も見てみたいです!

リポジトリをクローンして以下の3行で学習ができます。

poetry install
KEY="....." poetry run python scripts/create_dataset.py # KEYはstreetview APIのkeyです
poetry run python scripts/train.py --model resnet50 --batch_size 30 --lr 0.00001 --weight_decay 0 --epoch 40

自分の撮った写真の地域を当てる

f:id:Hi_king:20211211101113p:plain
著者が撮影した虎の門の写真

今回学習した7地域についてでしたら、学習済みモデルもアップロードしていますので、下記のスクリプトでお手元の写真でのテストができます。

poetry install
poetry run python scripts/predict.py ${your_image_path}

エムスリーは溜池山王に本社があるんですが、2年前の出社していた頃に近くで撮った写真があったので入れてみると、ちゃんと高スコアで港区と認識されました。我々はとても港区っぽいところで働いているようです。

Limitation

今回はサクッとやるために、ストリートビューでランダムに集めたものをtrain/testスプリットして性能検証するということをしているのですが、これは、

  • 同じ地域のものは同じ車両が撮影しているため当てやすいバイアス
  • さらに同じ街区だと同じランドマークが入ってることがたまにあるので、それを覚えることもできる(一方でランドマーク認識をしてはいけないってこともなさそうですが)

という点で、多少有利には思います。本当はtestはストリートビューではない画像でやるのがベストですし、ストリートビューでも、同じ区の中の一部地域をtestとして切り出す方がより、"地域性"みたいなものがちゃんと見られてるかのtestには良さそうです。

最低限私の手元の写真でpredictを動かしてみて、ちゃんと当てられてることと、まぁ定性的にリーズナブルな特徴を得られてそうなところから一旦はOKとしてますが、もっと別の写真での検証をたくさんやると限界がよくわかるだろうなと感じます。

まとめ

  • 機械学習で写真から場所を当てられる? -> できらぁ
  • 柵は場所を知る手がかりになる
  • ストリートビューAPIは最高の機械学習データセット(お金には気をつけて)

We are hiring!

エムスリーでは、ふとした疑問をMLエンジニアリングによって解決できるエンジニアを募集中です。

社内外問わず、基盤を使ったシステムの開発や施策により世の中にインパクトを与える機会が多数ありますので、是非我こそは!という方はカジュアル面談、ご応募お待ちしています!

jobs.m3.com

最近のAI・機械学習チームの取り組み紹介の資料はこちら。

speakerdeck.com

おまけ: モデルと勝負!

この9枚の画像がどこの画像か考えてみてください

f:id:Hi_king:20211210220123p:plain

*1:Our Inception model has a total of 97,321,048 parameters. We train the model for 2.5 months on 200 CPU cores

*2:ちなみに、ニューラルネットのパラメータに入れるのではなく、画像検索して類似画像のlocationを使うというアプローチの研究もあります

*3:10 well-traveled humanという実験条件を見たのはこの論文しかないw

*4:Streetview APIは1call ¥0.67(2021/12/10現在) ですので、ご利用は計画的に。ちなみに私は最初、ダウンロードから全てコンテナに入れることで単一のコンテナでどこでも動くクリーンなデプロイ!という誤った設計をしていたのでヤバかったです。