Apache Spark 2.4におけるビルトイン画像データソースのご紹介

[Introducing Built\-in Image Data Source in Apache Spark 2\.4 \- The Databricks Blog](https://databricks.com/blog/2018/12/10/introducing-built-in-image-data-source-in-apache-spark-2-4.html)の翻訳です。

# はじめに

画像分類、物体検知におけるディープラーニングフレームワークの発展に伴い、Apache Sparkにおける標準的な画像処理への要望が高まっています。異なる画像フォーマット(jpeg/pngなど)、サイズ、カラースキーマを取り扱う必要があること、正確性を確認するのが困難(エラーを出すことなしに処理に失敗する)であることなど画像処理には固有の課題があります。

画像データソースを用いることで、特定の画像表現を抽象化し、コーディングしやすい標準的な画像表現を提供することで、上記の課題を解決します。

Apache Spark 2.3では、元々は[MMLSparkライブラリ](https://github.com/Azure/mmlspark)で提供されていた**ImageSchema.readImages** API(Microsoftの[Apache Sparkの画像データサポートに関する記事](https://blogs.technet.microsoft.com/machinelearning/2018/03/05/image-data-support-in-apache-spark/)を参照ください)をサポートしました。[Apache Spark 2.4](https://databricks.com/blog/2018/11/08/introducing-apache-spark-2-4.html)では、ビルトインのデータソースとなったので、より使いやすくなっています。画像データソースを用いることで、ディレクトリから画像を読み込み、単一の画像カラムを持つデータフレームを作成することができます。

この記事では、画像データソースがどのようなものか、[Databricksレイクハウスプラットフォーム](https://databricks.com/product/data-lakehouse)における[ディープラーニングのパイプライン](https://databricks.com/blog/2017/06/06/databricks-vision-simplify-large-scale-deep-learning.html)でどのように使うのかを説明します。

# 画像のインポート

画像データソースを用いて、どのように画像をSparkに画像を読み込むのかを見ていきましょう。[PySpark](https://databricks.com/glossary/pyspark)では、以下のように画像をインポートできます。

**Python**

```python
image_df = spark.read.format("image").load("/path/to/images")
```

Scala、Java、Rでも同様のAPIを提供しています。

画像データソースを用いることで、ネストされたディレクトリ構造(例えば、`/path/to/dir/**`のようなパス)をインポートすることができます。特定の画像に対しては、パーティションディレクトリ(`/path/to/dir/date=2018-01-02/category=automobile`のようなパス)のパスを指定することで、パーティションディスカバリーを使用することもできます。

# 画像のスキーマ

画像は"image"という列を持つデータフレームに読み込まれます。"image"は以下のフィールドを持つstruct型のカラムとなります。

```
image: struct containing all the image data
 |    |-- origin: string representing the source URI
 |    |-- height: integer, image height in pixels
 |    |-- width: integer, image width in pixels
 |    |-- nChannels: integer, number of color channels
 |    |-- mode: integer, OpenCV type
 |    |-- data: binary, the actual image
```

多くのフィールドは自明ですが、いくつかのフィールドには説明が必要かと思います。

**nChannels**: カラーチャンネルの数。典型的な値はグレースケールの画像場合は1、RGBのようなカラーイメージは3、アルファチャネルを持つカラーイメージは4となります。

**Mode**: データフィールドを解釈するための整数値の情報を提供します。格納されているデータのデータ型とチャンネルオーダーを保持しています。フィールドの値は、以下の[OpenCV](https://opencv.org/)タイプにマッピングされることを期待されます(強制はされません)。OpenCVタイプは1、2、3、4のチャネル、画素値に対するいくつかのデータタイプを定義します。

OpenCVの値(データタイプ x チャンネルの数)に対するタイプのマッピングは以下の通りとなります。
![](https://databricks.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-10-at-9.19.49-AM.png)

**data**: バイナリー形式で格納された画像データです。画像データは、次元の形状(height, width, nChannels)の3次元の配列、modeで指定されるt型の配列値となります。配列は行優先(row-major)で格納されます。

[Row\- and column\-major order \- Wikipedia](https://en.wikipedia.org/wiki/Row-_and_column-major_order)

## チャンネルのオーダー

チャンネルのオーダーは色が格納される順序を指定します。例えば、赤、青、緑から構成される典型的な3チャンネルの画像の場合、取りうる順序は6種類あります。多くのライブラリはRGBやBGRを使用します。3(あるいは4)チャンネルのOpenCVタイプは、BGR(A)の順序であることが期待されます。

# コードサンプル

[ディープラーニングパイプライン](https://databricks.com/blog/2017/06/06/databricks-vision-simplify-large-scale-deep-learning.html)を用いることで、画像を用いた機械学習に容易に着手できます。バージョン0.4以降では、ディープラーニングパイプラインプロジェクトで定義された以前の画像スキーマは、上述した画像フォーマットとしての画像スキーまで置き換えられています。

このPythonの例では、カスタムの画像分類器を構築するのに転移学習を使用します。

**Python**

```python
# path to your image source directory
sample_img_dir = ...
# Read image data using new image scheme
image_df = spark.read.format("image").load(sample_img_dir)

# Databricks display includes built-in image display support
display(image_df) 

# Split training and test datasets
train_df, test_df = image_df.randomSplit([0.6, 0.4])

# train logistic regression on features generated by InceptionV3:
featurizer = DeepImageFeaturizer(inputCol="image", outputCol="features", modelName="InceptionV3")
# Build logistic regression transform
lr = LogisticRegression(maxIter=20, regParam=0.05, elasticNetParam=0.3, labelCol="label")
# Build ML pipeline
p = Pipeline(stages=[featurizer, lr])
# Build our model
p_model = p.fit(train_df)
# Run our model against test dataset
tested_df = p_model.transform(test_df)
# Evaluate our model
evaluator = MulticlassClassificationEvaluator(metricName="accuracy")
print("Test set accuracy = " + str(evaluator.evaluate(tested_df.select("prediction", "label"))))
```

**注意**: (ディープラーニングパイプラインの方向け)新たな画像スキーマではカラーチャンネルのオーダーがBGRからRGBへと変更になっています。混乱を避けるために、内部的なAPIのいくつかはオーダーを明示的に指定することを要求します。

# 次のステップ

`df.sample`を用いてデータフレームからサンプリングすることが有効なケースがありますが、サンプリングは最適化されていません。これを改善するためには、毎回画像ファイルを読み込まないように、画像データソースにサンプリングオペレーターをプッシュダウンする必要があります。この機能はデータソースV2でサポート予定です。

その他、画像処理に関する新たな機能は、DatabricksおよびApache Sparkでリリースされる予定ですので楽しみにしていてください。

# 参考情報
- [Image \- Azure Databricks \- Workspace \| Microsoft Docs](https://docs.microsoft.com/en-us/azure/databricks/data/data-sources/image)
- [Image \| Databricks on AWS](https://docs.databricks.com/data/data-sources/image.html#image-limitations)
- [Databricksランタイム 5.0 ML以降](https://databricks.com/blog/2018/11/27/introducing-databricks-runtime-5-0-for-machine-learning.html)で、[サンプルノートブック](https://docs.databricks.com/_static/notebooks/image-data-source.html)を試す。
- [ディープラーニングパイプライン](https://docs.databricks.com/applications/machine-learning/train-model/deep-learning-pipelines.html)を学ぶ。
- GitHubの[ディープラーニングパイプラインのサンプル](https://github.com/databricks/spark-deep-learning)を試す。

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)