コンサルでデータサイエンティスト

仕事でPythonを書いてます。機械学習、Webマーケティングに興味があります。趣味は旅です。

Apache Spark: PythonとScalaのどっちを使うべきか比較する

データサイエンスプロジェクトで Spark を使う場合、必ず議論に上がるのがPythonScalaのどちらのプログラミング言語を採用すべきかということです。

Sparkは元来Scalaで書かれているため、Scalaで処理コードを書いていくのが直感的にも自然なことです。しかし、データサイエンティストの多くはPythonに親しみがあるため、Sparkから取得したデータに対してPythonで書いた機械学習モデルや処理コードをそのまま適用したいということがあります。

そこで、近年台頭してきたのがPySparkです。PySparkとは、PythonApache Sparkを実行するためのAPIです。PySparkの発展により、PythonによるSparkの扱いやすさは劇的に改善してきており、ScalaPythonのどちらを使うべきかという論争は大きな盛り上がりをみせています。

本記事では、PythonScalaのどちらでSparkを扱うべきかということについて、それぞれのメリットとデメリットを紹介しながら比較していきます。

apache_spark


Apache Spark とは

どのプログラミング言語を扱うべきかという比較に入る前に、Apache Sparkの概要について確認していきましょう。

Apache Sparkとは大量のデータに対して高速に分散処理を行うOSSフレームワークです。APIとしてはPython, Java, Scala, R などのプログラミング言語が用意されています。大規模データを扱う分散アプリケーションを開発する際にはSparkの利用が必ず検討されるといってもよいでしょう。

類似の分散処理フレームワークとしてHadoopがありますが、HadoopJavaで書かれているのに対して、SparkはScalaで書かれています。また、HadoopとSparkの大きな違いとして、HadoopではMapReduceにおける入出力のたびにストレージにアクセスする必要があったのに対して、Sparkではデータをメモリに保存することで高速化を図っています。これはインメモリ処理と呼ばれ、機械学習などのように入出力処理が頻繁に発生するようなアプリケーションでは実行性能が100倍程度改善することもあります。

www.graffe.jp


Apache SparkではSpark MLという機械学習ライブラリが備わっているのも特徴です。これによって、ユーザは複雑な分散処理を考えることなく、高速で動作する機械学習手法を実装することが可能です。

SparkML以外にも、Spark上で使える機械学習パッケージがいくつかあるので詳しく知りたい方は別記事を参照してみてください。
hktech.hatenablog.com


Python vs Scala

Sparkを扱う際に、PythonScalaのどちらを選択すればよいのでしょうか。それぞれのメリットとデメリットを比較していきます。

実行速度

まずは、PythonScalaを実行速度の観点で比較します。

平均的に、ScalaPythonより約10倍の速さで実行することが可能です。Scalaは実行時にJava Virtual Machine (JVM) を使用するのに対して、Pythonは動的型変換を伴うインタプリタ言語であるため、その実行速度の差は歴然です。さらにSparkのライブラリはすべてScalaで書かれているため、Pythonでこれらを使用しようとすれば、Scalaそのものでライブラリを扱うよりは実行速度が遅くなることは明らかです。

したがって、実行速度の観点ではScalaが圧倒的に優位です。

扱いやすさ

次にPythonScalaを扱いやすさの観点で比較していきます。

まずは、実装のしやすさという点では、Pythonに圧倒的な軍配が上がります。ご存知の通り、Pythonは学習コストが低いプログラミング言語のひとつとして知られており、データを扱う多くのエンジニアやデータサイエンティストはPythonに慣れているということがあります。一方で、ScalaをマスターするためにはJavaの基本的な理解が必要であるため、情報系出身者ではない多くのデータサイエンティストがここで脱落します。さらに厄介なことに、Javaに習熟しているものでもScalaの特殊な構文に慣れるには時間がかかるといわれています。このようなことから、チーム全体の実装スピード運用コストという点でもPythonのほうが優れているといえるでしょう。

Scalaの実装が簡単ではないということを説明しましたが、Scalaを扱えることができればSparkのフレームワークをより簡単に活用することができます。SparkのライブラリはScalaAPIコレクションを活用しているため、これを理解しておけば内部的な動作を把握することができるほか、用途に応じた修正をすることが可能です。また、動的型変換を行うPythonと比較すると、Scalaは静的に型が定義されるため、コンパイル時にエラーを発見することができるという点で安全性が高いです。

結論

実行速度では、ScalaのほうがPythonより早く、扱いやすさという点では、Pythonのほうがやや優勢であるということがわかりました。

結局、PythonScalaのどちらを使えばよいのでしょうか?

例えば、大規模データを処理してレポーティングをしたいという場合にはPythonが有効です。商用システムでない場合、実行速度は大きな問題ではないため、すばやく実装でき、可視化ライブラリなどが充実しているPythonを選ぶのがおすすめです。特に、機械学習系の案件であれば、データサイエンティストの多くはPythonに慣れているはずなので、こちらを使うのが無難でしょう。

商用のシステムでSparkを活用したい場合、PythonScalaのどちらを選ぶかは会社の形態やリソース状況によって変わると思います。

事業会社で、大規模データを扱うシステムまたはサービスを長期的に開発する場合はScalaがよいでしょう。学習コストがかかってしまうものの、Sparkを本質的に理解するためにはScalaの理解は欠かせないほか、パフォーマンス観点や最新のSparkライブラリにアクセスしやすさからもScalaを選択することが賢明です。

一方で、コンサルや短納期での実装が求められるような会社においてはPythonを選択するのがよいでしょう。特に、受注をするような場合は保守がしやすく、実装できる人材が多いプログラミング言語を選択することが一般的であり、Sparkにおいてもこれは当てまります。


まとめ

Apache Sparkを扱う際にPythonScala のどっちを使うべきかということについてまとめました。実行速度や扱いやすさの観点から、それぞれのメリットとデメリットがあることがわかりました。

Pythonコモディティ化してきている部分があるので個人的にはScalaに挑戦してみるのもよいかと思います。

コンサルでデータサイエンティストとして働く

コンサルティングファーム(会社)におけるデータサイエンティストの求人が近年増加しています。かつては経営戦略などに力を入れていた外資コンサルティングファームや、大規模なシステム開発などに強みがあった IT 系コンサルティング企業も、デジタル領域でのデータを活用したビジネスに大きな期待を寄せています。本記事ではコンサルタントとデータサイエンティストの役割の違いについて触れながら

  • コンサルでデータサイエンティストとして働くために必要なスキル
  • データサイエンティストが求められている理由

ということについて、実際にコンサルでデータサイエンティストとして働いている立場からご紹介します。コンサルにデータサイエンティストとして入社したい就活中の学生や、転職を考えている方にとって少しでも参考になれば幸いです。


目次

データサイエンティストとは

データサイエンティストの定義は個人や企業によって解釈が様々となっています。専門職としてのデータサイエンティストの役割は、統計学または機械学習 ×プログラミングによる課題解決をすることであると考えています。


Excelでピボットテーブルを組んでクロス集計をしたり、BIツールでユーザーの行動を解析するといった仕事もデータアナリティクスの重要な仕事ではあるものの、これらはコンサルティングファームコンサルタントであれば順当に持っているスキルであるため、このような仕事を専門に行う職種は本記事におけるデータサイエンティストのスコープ外とします。


data_scientist

データサイエンティストの分類

データサイエンティストとは大きくデータアナリスト機械学習エンジニアの2種類の職種に分けて考えることができます。

machine_learning_engineer

データサイエンティストと機械学習エンジニアは別物として解釈する場合もありますが、コンサルでははっきりと区別されていないことが多いです。そもそもコンサルティングファームにおいては、データアナリストの方が機械学習エンジニアよりもはるかに数が多いというのがその理由であるともいえます。しかし、人工知能を画像認識システムやチャットボットのサービスなどに実装していくような案件が増えつつある昨今のコンサル界隈では、後者の機械学習エンジニアへの需要も高まっています。ここでは、データアナリストと機械学習エンジニアの違いについて説明していきます。


データアナリストとは、データ分析で得た示唆を通してビジネス上の意思決定を支援する職種です。彼らはクライアントの業務やサービスを深く理解し、クライアントと密にコミュニケーションをしながら分析を企画、設計、実行していきます。場合によっては、データ分析で得た示唆を施策に落とし込んでいくサポート役を担うこともあります。

機械学習エンジニアとは、サービスやシステムに機械学習を用いた機能を実装していく職種です。彼らは機械学習モデルを商用のサービスやシステムに耐えうるレベルで実装を行います。人工知能やAIと言われるようなシステムの開発は彼らが担っていると考えてよいでしょう。


これらの2つの職種は、重複があるものの求められているスキルが微妙に異なります。データサイエンティストに必要なスキルにはどういったものがあるのでしょうか。


データサイエンティストに必要なスキル

データサイエンティストに必要なスキルは、一般的に以下の3軸で考えることができます。

  1. 機械学習・統計
  2. ビジネス(コンサルティングスキル・コミュニケーション力)
  3. エンジニアリング(プログラミング力・インフラの知識)


data_scientist_skill


優れたデータサイエンティストはこの三角形に示されたスキルを一定レベルで満たしていることが条件となります。機械学習・統計はデータアナリスト及び機械学習エンジニアの両方に必要な必須スキルであるものの、データアナリストは左側のビジネス寄り機械学習エンジニアは右側のエンジニアリング寄りといったように、多少のスキルの偏りがあることが一般的です。


機械学習・統計のスキル

機械学習・統計のスキルとは、データを適切に解釈し、様々な機械学習や統計的手法のなかから問題解決に結びつくものを取捨選択し、実装・分析を進めていく力です。こちらはデータサイエンティストとして当然持っておくべきスキルであり、これが欠けている場合は他のエンジニアやコンサルタントとの違いが無いと言えるでしょう。基本的な数学の知識から、統計学機械学習に関する知識に加え、最新の論文を読解するリサーチ力や特定の分野(自然言語処理、画像認識、異常検知、時系列データなど)に関する理解など、多くが求められています。しかし、データ分析のみで価値を生み出すことは年々難しくなっているため、近年では機械学習や統計のスキルが突き抜けているからといって、一流のデータサイエンティストを名乗れるような状況ではなくなってきています。

② エンジニアリングスキル

エンジニアリングスキルとは、プログラミングやサーバ・データベースなどのインフラに関する知識をはじめとしたスキルを指します。イメージとしては、情報工学科の授業で学ぶような内容に加え、実務で使用するWebフレームワークや、AWSGCPなどのクラウドサービス、ビッグデータを扱うソフトウェア(Spark, Hadoop, Hive)に関する知識が求められています。

③ ビジネススキル

ビジネススキルとは、データ分析を通して顧客に価値を提供するスキルを指します。事業会社であれば自社サービス、コンサルであればクライアントのサービスやドメインについて深く理解した上で、社内外とコミュニケーションをとりながらデータアナリティクスプロジェクトを円滑に進めることが求められています。また、データ分析を完璧に理解していないような方に対して、分析の方針や結果をわかりやすく説明するといった能力も必要です。




コンサルでデータサイエンティストとして働く場合、高いビジネススキルは当然のように求められることが多いです。機械学習・統計やエンジニアリングのスキルについては、関わる案件によって求められるレベルに大きな幅があります。案件ごとに技術を素早くキャッチアップできるような高い学習意欲や、手戻りが発生しないように分析を設計できる力が重要視されるといってよいでしょう。


コンサルでデータサイエンティストが求められる理由

データサイエンティストという職種は、幅広いスキルセットと深い知見が求められるということがわかりました。このような役割が、なぜいまコンサルティングファームで求められているのでしょうか。
コンサルでデータサイエンティストが必要とされている理由について考えていきます。


コンサルタントとは従来よりクライアントの課題に対して、深い知見と高いスキルによって解決策を提示し、変革を推し進めるという役割を担っています。コンサルにおけるデータサイエンティストはデータ分析という強力な武器をもったコンサルタントです。

データ分析が課題解決のひとつの手段として確立した背景には、冒頭でご紹介した通り、国内・国外のコンサルティングファームの売上の多くが経営・戦略コンサルティング事業から、デジタルやITといったドメインでのソリューション提供といった事業にシフトしているということがあります。そのような状況のなかで、昨今のデータ分析や人工知能ブームが火をつける形で、データ分析や機械学習システムの開発に関連する案件が急激に増えています。例えば、従来ではExcelなどで行っていた要因分析は、PythonやRによる多変量分析に取って代わられたり、多くのコンサルティングファームが得意としていたオペレーションの自動化は、機械学習を含むアルゴリズムによってより高度化されています。

また、より上流の意思決定に携わるコンサルティングにおいてもデータという武器は極めて有効です。クライアントの役員になにかを提案しようとするとき、その業界に関する知識では到底勝つことができません。しかし、データによる示唆を説明すれば新たな発見を与えることができます。客観的な情報であるデータとクライアントのドメイン知識を繋ぐ役割として、データサイエンティストが必要不可欠な存在となっています。

データサイエンティストとしてコンサルに就職する

コンサルティングファームでいかにデータサイエンティストが求められているかということが伝わったかと思います。読者の方の中には、データサイエンティストとして就職先を探している学生の方や、転職先の候補としてコンサルでデータサイエンティストを視野に入れている方もいるでしょう。


データサイエンティストは多くのスキルや知識を必要とする職種です。しかし、就職や転職をするタイミングですべてのスキルが必要であるというわけではありません。多くの業界でデータサイエンティストが不足している状況にあり、未経験に近い形で採用される方も会社によっては一定数いると聞きます。コンサルティングファームでは、多くの場合にプロジェクトにいきなりアサインされることが多いため、最低限のスキルとして以下は身につけておきたいです。


私自身は paiza というオンライン学習サイトを中心に python を学びました。現在では、UdemyAidemyといったデータ分析や機械学習プログラミングに特化したオンラインコースを提供するサイトも増えてきているので、一通りやってみるというのもよいかもしれません。上記スキルに加えて、学習意欲が最も大切です。これがあればコンサルティングファームでもやっていけるでしょう。

データサイエンティストとしてコンサルで働くメリット

データサイエンティストは多くの会社で求められていますが、コンサルでデータサイエンティストとして働くメリットとして、多様な業界のデータ分析プロジェクトに触れることができるということがあります。また、プロジェクトベースで動くため、自らが立ち上げメンバーとなってより実践的なスキルが身につけることができるという利点もあります。

一方で、多くのコンサルティングファームでは分析だけでプロジェクトが終わってしまい、実装に入れないケースも多々あります。先にも述べた通り、まだまだ機械学習のエンジニアリングが強くない会社も多く、開発は外注していることも多々あります。

したがって、現時点でデータサイエンティストとして機械学習エンジニア寄りのスキルを伸ばしていきたい方に、コンサルでデータサイエンティスト職に就くことは強くおすすめできません。そのような方は、ウェブ系のサービスを持ったメガベンチャーで働くほうが、エンジニアリングスキルを成長させていくことができるように思います。(あくまで、個人的な意見です)


まとめ

コンサルティングファームでデータサイエンティストとして働く立場から、データサイエンティストという職種の役割や、データサイエンティストが求められている背景についてご紹介しました。データサイエンスに必要なスキルは多岐にわたりますが、コンサルティングファームではプロジェクトごとに必要なスキルを身につけていくのが一般的です。本記事を読んで、データサイエンティストという職種に興味を持っていただける方がいれば幸いです。

pandasのTimestampで決まった範囲の時刻リストを作る

Python で日時関連のデータ操作をするときにdatetime モジュールを使用されている方も多いと思いますが、pandasを使ったTimestamp関連の操作が便利なので個人的にはおすすめです。本記事は時刻を含むデータを処理する際に、決まった範囲の時刻リストを作りたいというときに見返すためのメモ記事となります。

時刻リストとは次のようなイメージです。

['2018-12-19 08:00:00+00:00',
 '2018-12-19 08:01:00+00:00',
 '2018-12-19 08:02:00+00:00',
 '2018-12-19 08:03:00+00:00',
 '2018-12-19 08:04:00+00:00']


ある時刻範囲のループをまわして、なにかしらの処理をしたい場合などにご活用ください。

現在の時刻を取得

Python での実装をご紹介します。
まず、次のように現在の時刻を取得します。

$ time = pd.Timestamp.now(tz='GMT').floor(freq='T')



このとき、用途にあわせて時刻のタイムゾーンを指定することができます。

  • 世界標準時(GMT)で設定したい場合: tz='GMT'
  • 日本時刻で設定したい場合: tz=’Asia/Tokyo’

とします。

また .floor を指定することで細かい時刻の端数を丸めることができます。
ここでは、freq=’T’ としているので分単位に丸めています。(ちなみに H が1時間単位、Dが1日単位になります)

このように、GMTタイムゾーンで現在時刻を取得することができました。

$ time
Timestamp('2018-12-19 11:02:00+0000', tz='GMT')


時刻リストの取得

時刻リストを取得します。
今回は、現在の時刻の2分前から、現在の時刻の2分後までの時刻リストを取得したい場合を考えます。

ここではpandasの date_rangeメソッドを使って配列を作っていきます。

$ time_range = pd.date_range(pd.Timestamp(time, tz='GMT') - pd.offsets.Minute(2), pd.Timestamp(time, tz='GMT') + pd.offsets.Minute(2), freq='T')


pandasの date_rangeでは、開始時刻、終了時刻、周期を引数に指定します。
今回は分単位のリストがほしいので freq=’T’ としています。

また時刻の指定においては、pd.offsets を使用して時間単位で分数を足したり引いたりしています。datetimeモジュールなどと比較すると、かなり直感的に時刻を加算・減算することができます。

ちなみにdatetimeモジュールでは下記のように記述する必要がありました。

$ from dateutil.relativedelta import relativedelta
$ dt + relativedelta(minutes=1)



実際に取得したリストをみてみましょう。

$ time_range
 ['2018-12-19 11:00:00+00:00',
  '2018-12-19 11:01:00+00:00',
  '2018-12-19 11:02:00+00:00',
  '2018-12-19 11:03:00+00:00',
  '2018-12-19 11:04:00+00:00']


現在時刻の11:02から前後2分の時刻リストが取得できていることが確認できました。

Timestamp型から UNIX time に変換

pandas の Timestamp型データは簡単にUNIX timeにも変換することができます。
取得したリストを一気に変換したい場合は、リスト内包表記を使って次のように変換可能です。

$ [t.value // 1000000 for t in time_range]
   [1545217200000,
    1545217260000,
    1545217320000,
    1545217380000,
    1545217440000]


まとめ

pandas の Timestamp で時刻リストを作る方法について簡単に紹介しました。特定の時刻範囲のループをまわす処理を書きたいときには、本記事でご紹介したpandasのTimestampを利用してみてはいかがでしょうか。

【3D物体検出論文】Orthographic Feature Transform for Monocular 3D Object Detection をまとめた

3D object detection (3D 物体検出) に関する2018-2019期の最新の論文『Orthographic Feature Transform for Monocular 3D Object Detection』*1について読んでまとめました。

3D Object detection とは、自動運転などにおいて 3次元空間における物体の位置情報を画像データから予測する物体検出タスクです。本記事では、3D object detection の概念について通常の物体検出と比較しながら紹介した後に、提案された最新の3D物体検出手法について解説していきます。

3d_object_detection
目次

3D Object detection とは

3D Object detection (3D 物体検出) とはどういったものなのでしょうか。実際の予測画像を紹介しながら、ほかの一般的な画像認識タスクと比較をしていきます。


画像認識タスクには一般的に以下の4種類があります。

  • Classification(分類)
  • Classification + Localization(分類 + 位置推定)
  • Object Detection(物体検出)
  • Semantic segmentation(領域分割)


image_recognition_task



3D Object detection はこれらのいずれにも含まれない新たな画像認識タスクとして、近年注目され始めています。

通常の物体検出 (2D Object detection) は様々な用途におけるニーズを伸ばしており、多くのアプリケーションで実用化されています。しかし、自動運転などにおいては通常の物体検出では不足している部分があります。例えば、下図の左画像のような2次元の物体検出では画像内に自動車が映っていることはわかりますが、画像に映っている自動車までの距離情報を認識できないという問題があります。


3d_object_detection_compare


そこで、物体の奥行き情報も考慮した3D Object detection(3次元物体検出) が登場しました。3D Object detection とは、物体の3次元空間における位置情報(3次元の直方体の位置、大きさ、角度)を予測するタスクです。

自動運転などでは、従来 LiDARと呼ばれる光を用いたリモートセンシング技術を用いて周辺の車両の位置推定を行っていました。


lidar_object_detection
画像: https://medium.com/@jhkoh/object-detection-with-lidar-point-cloud-algorithm-94a241fd3f49

しかし、LiDARが精密機械ゆえに自動車搭載に不向きであることや、安いものでも50万円程度と高価であることから、カメラ画像から 3D 空間の物体検出を行いたいというニーズが高まっています。

このような理由から、カメラ画像による 3D Object detection タスクが誕生しました。

論文の要旨

3D Object detection の概念をお伝えしたところで、ここから論文『Orthographic Feature Transform for Monocular 3D Object Detection』の解説に入っていきたいと思います。


本論文の特徴は以下の通りです。

  • 1台のカメラで撮影した画像から 3D Object detection を行う
  • 2次元画像空間における特徴を現実の 3D 空間にマッピングすることで3次元空間の特徴を捉える
  • 3D 空間における特徴マップに対して Orthographic space(正投影空間)に変換する機構を加えることで計算量削減


本論文は、2018年11月に arxiv に登場した時点では 1台のカメラ画像による 3D 物体検出手法で State-of-the-art を達成しています。つまり、共通のデータセットで評価を比較した際には最も良い精度が出ているということになります。

3D 物体検出までの流れ

本論文の提案手法について、ネットワークの学習および推論までのステップについて解説していきます。

提案手法では、複数のネットワークを組み合わせた大きなネットワーク構成となっています。共通の損失関数からすべてのネットワークの重みを学習することができることから、本ネットワークは End-to-end network であるといえます。

提案手法のネットワークアーキテクチャは下図の通りです。

3d_object_detection_architecture


この図に書かれている各ネットワークの詳細について、ひとつずつ解説していきます。


ResNet による特徴抽出

はじめに、画像が入力される最初のネットワークについて説明いたします。
ここでは、一般的な画像認識タスクでも多く使われている ResNet という Convolutional Neural Network (CNN) に画像を入力し、入力画像の特徴マップを抽出します。

このとき、入力画像に対してマルチスケールな特徴マップを抽出することで、画像の大まかな特徴から細かな特徴といった多様な特徴を捉えた特徴マップを得ることができます。


画像特徴マップを 3D 空間へマッピング

提案手法では、現実空間の特徴をより捉えるために画像空間ではなく 3D 空間で物体検出を行います。ここでは1つ目の CNN で抽出された特徴マップを 3D 空間にマッピングしていきます。

画像の最小の解像度はピクセルで表されるように、筆者らは現実の 3D 空間の最小の解像度をボクセルで表しています。


orthographic_feature_transform


1つのボクセルを1辺の長さが r の立方体だとすると、カメラで撮影した立方体のボクセルは画像空間内では下図のような六角形に映ります。


object_detection_cube


ボクセルの中心座標を (x, y, z)、カメラの位置を( (c_u, c_v))、カメラの焦点距離fとすると、画像空間内に映るボクセルのバウンディングボックス座標は下式で求めることができます。


bounding_box_equation


ボクセルが画像空間内でどのような映るかがわかったところで、画像空間における特徴マップを 3D 空間にマッピングしていきます。

中心座標が (x, y, z) のボクセルの特徴マップ g(x, y, z) は、上記で求めたバウンディングボックスに含まれる範囲の特徴マップに対して Average pooling(平均プーリング)をかけることで求めることができます。


mapping_equation


特徴マップのテンソルを繰り返し足し合わせる処理は計算量増大の原因になってしまいます。そこで、提案手法では Integral images(積分画像)による高速化を図っています。ピクセル (u, v) の Integral map を F(u, v) は、再帰関数の利用により下式のように表すことができます。


recursive_integral_image


求めた積分画像を用いると、ボクセルの特徴マップ g(x, y, z) は下式のように書き換えることができます。

speedy_feature_mapping


積分画像については、こちらの方の記事を読んでみるといいかもしれません。

画像処理 Integral Image(積分画像) - のんびりしているエンジニアの日記


Orthographic Feature Transform(正投影空間への変換)

3次元空間に特徴をマッピングすることで 3D 空間の情報を抽出することができました。しかし、このまま 3次元空間の特徴マップを用いて物体検出をしようとすると計算量が膨大になってしまうことは明らかです。
そこで、提案手法では 3次元の特徴マップを高さ方向で圧縮して 2次元にマッピングしています。これを Orthographic Feature Transform と呼んでいます。

実空間にマッピングした特徴マップ (Voxel features) のy軸方向の高さを Hとすると、正投影空間における特徴マップ h(x, z) は下式で求めることができます。
orthographic_feature_transform_h


求めた正投影空間における特徴マップ h(x, z) を再び CNN に入力し、出力に対して Confidence map、位置、大きさ、向きに関する 4つの損失関数を最小化するようにネットワーク全体を学習していきます。


topdown_network

画像空間ではなく実空間に対応する特徴マップを入力するため、カメラから遠い物体をカメラから近い物体と同様に扱うことができるというのが提案手法の大きな特徴です。


3D 物体の位置推定

物体の位置推定ステップでは一般的な背景・物体の分類問題を解く手法ではなく、物体の中心座標の存在確率を表す Confidence map を回帰する手法を利用します。

confidence_map


下記の中心座標を持つ N 個の既知の物体(学習データ)があるとすると


training_data_equation

正投影空間における点(x, z) の ground truth Confidence score は次のガウス関数で表現することができます。

confidence_map_equation

ここで定義した ground truth Confidence map と予測した Confidence map の差を l1 損失関数で表し、学習時にはこの損失関数を最小化するように学習していく。


さらに、位置・大きさ・向きについても損失関数を用意することで精度向上を図ります。

f:id:hktech:20181217225719p:plain



評価

KITTI の 3D Object detection データセットを用いて学習・テストを実施し、評価を行っています。
KITTI データセットの中身については、次の方がまとめてくださっています。

kitti関連の覚え書き - 八谷大岳の覚え書きブログ

評価実験は下記の諸元で実施しています。

*Features
Front-end network ResNet-18
Feature map scales 1/8, 1/16, 1/32
3次元空間のグリッドサイズ 80m × 4m × 80m
グリッド解像度 r 0.5 m
Topdown network 16-layer ResNet
Data Number (Training, Validation) 3712, 3769
Data augmentation Random cropping, scaling, flipping, camera parameters
Training epochs 600

物体検出結果を画像で確認していきます。ご覧のとおり、画像上に正投影空間に投影した Confidence map が描画されているのが確認できると思います。また、bird-eye's-view(鳥瞰図)でみると、画像内の車両位置と対応するように、Confidence mapで描かれた円がプロットされていることがわかります。

object_detection_result



定量的に結果を確認していきます。ここでは、カメラを2台使った従来手法である
3DOP*2 と、1台のカメラ画像を使った従来手法であるMono3D*3を比較します。


evaluation_result


KITTI ベンチマークでは正解と予測の重複が 0.7 以上のものを予測成功と定義されています。
Mono3D と比較すると精度が改善していることがわかります。また、2台のカメラを使用する 3DOP に近い精度を達成しています。特に、物体の重複がある場合や物体が遠方なときの Hard カテゴリでは精度が大きく改善していることがわかります。これは、画像空間ではなく実空間に対応する特徴マップを入力するため、カメラから遠い物体をカメラから近い物体と同様に扱うことが可能だからです。

まとめ

3D Object detection の最新論文についてまとめました。
対象論文『Orthographic Feature Transform for Monocular 3D Object Detection』では単一のカメラで撮影した画像を使って3次元空間における物体の位置情報を検出する 3D 物体検出手法が提案され、2018年末時点での State-of-the-art を達成しました。
まだまだ実用化に向けて精度を改善していかなければいけないフェーズですが、カメラ画像を使った 3D Object detection は今後も注目され続ける分野だと思います。今後も画像認識に関連した新しい手法について調べてまとめていきたいので、ご期待ください。

高い圧縮率を誇るbz2拡張子ファイルを圧縮・解凍する方法

サーバ上やローカルのLinuxで作業していると、直近で必要のないファイルが溜まって容量が不足してしまうことがありますよね。

そんな問題を解決してくれるのが圧縮・展開系のコマンドです。
zipやgzipなどさまざまなコマンドがありますが、それらと比較して高い圧縮率で圧縮できるのがbzip2コマンドです。
bzip2コマンドや、bz2拡張子を持つファイルに馴染みのない方も多いと思いますが、サーバの容量を圧迫したくないときなどにはおすすめなコマンドです。

今回はそんなbzip2による圧縮・解凍コマンドを備忘録としてまとめておきます。

 

目次

f:id:hktech:20181126222606j:plain
 

bz2ファイルへの圧縮方法

bzip2 コマンドによる圧縮方法は次の通りです。

$ bzip2 compression.log


圧縮後は以下のように拡張子.bz2を持つファイルに圧縮されます。

compression.log.bz2


圧縮処理自体に時間はかかりますが、ファイルによっては50倍以上の小ささに圧縮することができます。

また、ディレクトリ(フォルダ)ごと圧縮したい場合は以下のように圧縮することができます。

tar cvjf compression.tar.bz2 logs/

 

bz2ファイルの解凍方法

bz2拡張子を持つファイルの解凍方法は2通りあります。

bunzip2コマンドを使う場合は以下の通りです。bunzip2は解凍専用コマンドなので特にオプションは必要ありません。

$ bunzip2 compression.png.bz2

 

bzip2コマンドを使う場合は以下の通りです。d オプション (decompression) をつけることでファイルを解凍・展開することができます。

$ bzip2 -d compression.png.bz2

 

さきほどディレクトリごと圧縮する方法を紹介しましたが、このような場合の解凍方法は以下の通りです。

$ tar xvjf compression.tar.bz2

 

まとめ

bzip2 コマンドを使ったbz2拡張子ファイルの圧縮・解凍方法について紹介しました。さまざまな圧縮コマンドがありますが、Linux環境ではbzip2をおすすめします。実際の業務では、サーバの容量に制約条件があったりするので覚えておいて損はないと思います。容量があふれそうだけどファイルを消したくない、そんなときに試してみてはいかがでしょうか。

SSH先でJupyter notebook を使用する方法

Raspberry PiAWS EC2など、ローカルからリモートサーバに接続してPythonのプログラムを書く際にJupyter notebookを使いたくなることがあると思います。今回はSSH先でJupyter notebookを立ち上げて、ローカルで使用する方法についてご紹介します。

目次

SSH接続したリモート先の設定

リモートサーバ側の設定方法について確認していきます。
RaspberryPi でJupyter notebookを使用したい方は こちらの記事AWS EC2で使用したい方は こちらの記事を参考にしていただいてもよいかもしれません。


まずは外部接続環境用のJupyter notebook 設定ファイルを作成します。

mkdir ~/.jupyter


設定ファイル (config file) をviエディタで編集していきます。

vi ~/.jupyter/jupyter_notebook_config.py


ファイルが空の場合は下記の2行を書き込みましょう。

c.NotebookApp.ip = '0.0.0.0'
c.NotebookApp.port = 8888


ほとんどの場合、このファイルは空ではないので、該当行を探して編集しましょう。

vi ではスラッシュで文字列を検索できます。先頭のコメントアウト文字列#を消して、上の例のように2行分を編集しましょう。

/c.NotebookApp.ip


編集が完了したらファイルを保存してエディタを終了します。

:wq


最後に、Jupyter notebookを作成したいディレクトリに移動し下記のコマンドを実行します。

jupyter notebook


正常に起動できていれば、下記のようなメッセージが表示されます。

Copy/paste this URL into your browser when you connect for the first time,
to login with a token:
http://(raspberrypi or 127.0.0.1):8888/?token=abcabc123efg456xyz


リモート側の設定は以上となります。


ローカルの設定

ローカル側では特に設定は必要ありません。

適当なブラウザを開いて、URL欄に先ほどのURLを入力しましょう。

以下の画面が表示されれば無事にすべてのステップが完了です!

f:id:hktech:20181118231958p:plain

まとめ

SSH先でJupyter notebookを使用する方法についてご紹介しました。Python でプログラムを実装したり、データ解析などをしたい場合はJupyter notebookをリモートサーバだからJupyter notebookが使えないというのももったいないので、この記事を参考にしながら設定をしてみてはいかがでしょうか。


参考記事

RaspberryPi の場合

RaspberryPiでJupyter notebookを使う場合の設定方法はこちら
qiita.com

AWS EC2 の場合

AWS EC2でJupyter notebookを使う場合の設定方法はこちら
blog.roy29fuku.com

Pythonでk-NNをフルスクラッチで実装してみた

Scikit-learnを始めとしたパッケージが充実してきているおかげで、データ分析に関わる人もスクラッチから機械学習モデルを実装する機会が少なくなっています。

しかし、機械学習モデルを理解するためにはそのモデルを実装してみるのが一番早いと言われています。たとえパラメータをいじるだけの作業であったとしても、モデルの理解が深い人とそうでない人では、問題解決の質が変わってきます。

本記事では、最も基本的な分類モデルである k-NN (k-Nearest Neighbor) 法をフルスクラッチで実装したのでご紹介します。

目次

k-Nearest Neighbor法

k-Nearest Neighbor 法 (k-NN)k近傍法とも呼ばれ、分類モデルの中でももっともシンプルに実装できるものとして広く知られています。

k-NNとは、特徴量空間にデータをプロットしたときに、プロットと距離が近い学習データを近いものから順にk個選び出し、それらの学習データのクラスを多数決することでデータのクラスを決定する分類モデルです。

図のように、青四角クラス赤丸クラスの学習データが配置された特徴量空間を考えます。

k-NNのkは、テストデータ(星型)から何個の近傍点をクラス予測時に考慮するかということを決定するパラメータです。この例の場合、k=3のときは赤い学習データのほうが多いため赤クラスに分類されます。一方で、k=5のときは青のほうが多数となるため、テストデータは青クラスに分類されます。

f:id:hktech:20180926093820p:plain

k-NNをPythonで実装する

k-NNの概要については理解していただけたと思います。実にシンプルなモデルであるため、スクラッチから実装することはさほど難しくないです。それどころか、データサイエンティストであればこれくらいは実装できるのが最低要件だと思います。


シンプルである一方で、テストデータと複数の学習データとの距離をそれぞれ計算する必要があるため、計算量が多いという欠点があります。

こちらが実装したコードです。

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import f1_score
import time


def load_data():
    iris = load_iris()
    return train_test_split(iris.data, iris.target, test_size=0.3)

def predict(k, test_plot, X_train,  y_train):
    dist_dict = {}

    for i, train_plot in enumerate(X_train):
        dist = np.linalg.norm(train_plot - test_plot)

        if len(dist_dict) <  k:
            dist_dict[dist] = y_train[i]    
        elif dist < np.max(list(dist_dict)) and len(dist_dict) == k:
            dist_dict.pop(np.max(list(dist_dict)))
            dist_dict[dist] = y_train[i]     

    count = np.bincount(list(dist_dict.values()))
    pred = np.argmax(count)
    return pred

def predict_test_data(k, X_train, X_test, y_train, y_test):
    pred_list = []
    
    for test_plot in X_test:
        pred = predict(k, test_plot, X_train, y_train)
        pred_list.append(pred)
    return f1_score(y_test, pred_list, average='macro')

if __name__ == '__main__':
    X_train, X_test, y_train, y_test = load_data()
    start_time = time.time()
    fscore = predict_test_data(3, X_train, X_test, y_train, y_test)
    process_time = time.time() - start_time
    print('F-score: {:.3f}'.format(fscore))
    print('Process time: {:.3f} sec'.format(process_time))

実装したモデルをirisデータセットを用いてF値で評価すると、次のような結果となりました。

F-score: 0.978
Process time: 0.118 sec

クラスの分類がうまくいっていることを確認することができました。

k-NNの特徴としてすべての点との距離を求める処理が必要となることから計算量が大きくなってしまうということがあります。そのため、プログラムの実行時間を計測できるような処理を実装しています。今回は何も考えずに最も単純な方法で実装したため計算量がかなり大きくなってしまっています。

Scikit-learnなどで実装されているk-NNは、この問題をできるだけ解決するように実装の工夫がなされています。実装を工夫した際のコードについてはまた別の機会にご紹介できればと思います。

まとめ

k-Nearest Neighbor法をフルスクラッチで実装してみました。まずは計算量などを考慮せずに最低限の精度が出るモデルの実装ができたので、次のステップとして高速化を考えていきたいです。k-NNは最も単純な機械学習モデルのひとつです。この記事を参考にしつつ、一から実装してみてはいかがでしょうか。


関連記事
決定木分類器をフルスクラッチで実装した際の記事です。
hktech.hatenablog.com