Deeplearning4J 1.0.0-beta4で追加された新機能のまとめ

# はじめに

今月（2019年5月）の頭に[DL4J](https://deeplearning4j.org/)の新バージョン1.0.0-beta4がリリースされましたね。
どんな機能が追加されたのかまとめてみたいと思います。

英語のリリースノートはこちら。
https://deeplearning4j.org/release-notes#onezerozerobeta4

# そもそもDL4Jって？

[DL4J](https://deeplearning4j.org/)こと[Deeplearning4J](https://deeplearning4j.org/)は、Java/Scala/KotlinといったJVM言語で開発できるオープンソースのディープラーニング用フレームワークです。
サンフランシスコに本社を置くスタートアップ企業の[スカイマインド社](https://skymind.ai/jp/)を筆頭に開発が進められています。

ディープラーニングといえばPythonというイメージがあります。しかし、

- 官公庁やエンタープライズ系のシステムではJavaが主に用いられている
- プログラミング言語でいうとJava開発者が一番多い
- DL4Jはビッグデータ基盤であるHadoop/Sparkをネイティブにサポートしている
- [スカイマインド社](https://skymind.ai/jp/)による商用サポートがある

といった背景から、ディープラーニングの世界でも実はJavaもそれなりのシェアを占めています。
2018年のデータですが、それぞれのフレームワークのGitHub上でのスター数（下図の横軸）で見ると真ん中あたりに位置しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135044/2d86d313-0cea-0621-129f-ffb61de9074e.png)
（画像出典：https://www.kdnuggets.com/2018/04/top-16-open-source-deep-learning-libraries.html）

TensorFlowやPyTorch、ChainerといったPythonのフレームワークは基本的に研究開発や実験用途を想定されており、私たちが日々目にする華々しい研究成果はこれらのフレームワークを用いて開発されていることが多いかと思います。
DL4Jは（もちろん無料で使えますが）商用という立ち位置にフォーカスして差別化を図っている印象があります。

なお、[Kerasで構築されたモデルをDL4Jにインポート](https://deeplearning4j.org/docs/latest/keras-import-overview)して利用することもできます。
その他、TensorFlowのモデルや、ONNX・PMML形式のモデルのインポートにも対応しています。

そのため、開発はPython、運用はJavaといった使い分けをすることも可能となっています。

# DL4J 1.0.0-beta4 の主な変更点

そんなDL4Jの新バージョン1.0.0-beta4で追加された機能のハイライトを見てみましょう。

- JVM用線形代数ライブラリ[ND4J](https://github.com/deeplearning4j/nd4j)における複数のデータ型のサポート
- Intelプロセッサ用高速化ライブラリ[MKL-DNN](https://github.com/intel/mkl-dnn)のサポート
- メモリ管理方法変更による[ND4J](https://github.com/deeplearning4j/nd4j)のパフォーマンス向上
- [DL4J](https://deeplearning4j.org/)にAttentionレイヤー追加
- [DL4J](https://deeplearning4j.org/)でBERTをサポート（ただし限定的）

以下でそれぞれの詳細について見ていきます。

## ND4Jにおける複数のデータ型のサポート

[ND4J](https://github.com/deeplearning4j/nd4j)というのはJVM向けの科学計算ライブラリです。
Pythonでいうところの[Numpy](https://www.numpy.org/)のJava版というとイメージしやすいかもしれません。
[ND4JはNumpyより２倍早いという報告](https://github.com/deeplearning4j/nd4j-benchmark/issues/3)もあります。
もちろんCUDAをサポートしており、GPUを用いて計算を高速化することもできます。

さて、以前までのバージョンのND4JではN次元行列（テンソル）の型はfloat/doubleに制限されていました。
1.0.0-beta4よりテンソルでも以下の一般的なデータ型はすべてサポートされるようになりました。

- DOUBLE: double precision floating point, 64-bit (8 byte)
- FLOAT: single precision floating point, 32-bit (4 byte)
- HALF: half precision floating point, 16-bit (2 byte), “FP16”
- LONG: long signed integer, 64 bit (8 byte)
- INT: signed integer, 32 bit (4 byte)
- SHORT: signed short integer, 16 bit (2 byte)
- UBYTE: unsigned byte, 8 bit (1 byte), 0 to 255
- BYTE: signed byte, 8 bit (1 byte), -128 to 127
- BOOL: boolean type, (0/1, true/false). Uses ubyte storage for easier op parallelization
- UTF8: String array type, UTF8 format

特にFP16やINT型のサポートによりニューラルネットワークの小型化、高速化が期待できそうですね。

## MKL-DNNのサポート

Intelプロセッサ用のディープニューラルネットワーク（DNN）の高速化ライブラリである[MKL-DNN](https://github.com/intel/mkl-dnn)のサポートも追加されました。

[MKL-DNN](https://github.com/intel/mkl-dnn)を用いて以下のレイヤーを高速化できます。

- `ConvolutionLayer` and `Convolution1DLayer` (and `Conv2D`/`Conv2DDerivative` ND4J ops)
- `SubsamplingLayer` and `Subsampling1DLayer` (and `MaxPooling2D`/`AvgPooling2D`/`Pooling2DDerivative` ND4J ops)
- `BatchNormalization` layer (and `BatchNorm` ND4J op)
- `LocalResponseNormalization` layer (and `LocalResponseNormalization` ND4J op)
- `Convolution3D` layer (and `Conv3D`/`Conv3DDerivative` ND4J ops)

なお、`LSTM`など、他のレイヤーのサポートは以降のリリースで対応予定とのことです。
以下の行を追加することで[MKL-DNN](https://github.com/intel/mkl-dnn)をグローバルに無効化することもできます。

```java:
Nd4jCpu.Environment.getInstance().setUseMKLDNN(false);
```

環境変数`ND4J_MKL_FALLBACK`をセットすることで特定の命令のみ無効化することも可能です。

```sh:
ND4J_MKL_FALLBACK=conv2d,conv2d_bp
```

## ND4J: メモリ管理方法変更によるパフォーマンス向上

[ND4J](https://github.com/deeplearning4j/nd4j)の以前までのリリースではメモリの自動解放のため周期的なガベージコレクションを利用していました。
（ガベージコレクションについてはQiitaの[「JavaのGCの仕組みを整理する」](https://qiita.com/e_tyubo/items/48398391a8ef0f24c1be)がわかりやすかったです。）

ただし、[ND4J](https://github.com/deeplearning4j/nd4j)では1.0.0-alphaより、追加のメモリ管理モデルとして[workspace](https://deeplearning4j.org/docs/latest/deeplearning4j-config-workspaces)という概念を導入していました。
workspace上ではガベージコレクタの介入なしにメモリを再利用することができます。

[DL4J](https://deeplearning4j.org/)でニューラルネットワークを訓練している最中では、基本的に解放対象となるメモリはないはずです。
そのため数秒ごとに周期的にガベージコレクションを行うことでパフォーマンスにオーバーヘッドが生じてしまっていました。

1.0.0-beta4からは周期的なガベージコレクションはデフォルトで無効化されることになりました。
（以下のようにして有効化することもできます。）

```java:
Nd4j.getMemoryManager().togglePeriodicGc(true);
Nd4j.getMemoryManager().setAutoGcWindow(5000);
```

## DL4J: Attentionレイヤーの追加

Googleから2017年に発表された[Attention Is All You Need](https://arxiv.org/abs/1706.03762)というGoogle翻訳（Transformer）の論文あたりから爆発的に流行り始めたAttention（注意）機構が[DL4J](https://deeplearning4j.org/)でネイティブに使えるようになりました。

- [AttentionVertex](https://github.com/deeplearning4j/deeplearning4j/blob/master/deeplearning4j/deeplearning4j-nn/src/main/java/org/deeplearning4j/nn/conf/graph/AttentionVertex.java)
- [LearnedSelfAttentionLayer](https://github.com/deeplearning4j/deeplearning4j/blob/master/deeplearning4j/deeplearning4j-nn/src/main/java/org/deeplearning4j/nn/conf/layers/LearnedSelfAttentionLayer.java)
- [RecurrentAttentionLayer](https://github.com/deeplearning4j/deeplearning4j/blob/master/deeplearning4j/deeplearning4j-nn/src/main/java/org/deeplearning4j/nn/conf/layers/RecurrentAttentionLayer.java)
- [SelfAttentionLayer](https://github.com/deeplearning4j/deeplearning4j/blob/master/deeplearning4j/deeplearning4j-nn/src/main/java/org/deeplearning4j/nn/conf/layers/SelfAttentionLayer.java)

Attentionの解説は[Ryobotさんのブログ](http://deeplearning.hatenablog.com/entry/transformer)がわかりやすいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135044/eacf1f98-271b-f8a0-5c29-b3894c51b801.png)
（画像出典：http://deeplearning.hatenablog.com/entry/transformer））

## DL4J: BERTのサポート

[BERT](https://github.com/google-research/bert)とは言語表現事前学習の新しい方法のことです。
広い範囲の自然言語処理タスクにおいてSOTA (state-of-the-art) の結果を叩き出し、大きな注目を集めています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135044/4ea86752-db23-5d13-28a8-a797db44458a.png)
（画像出典: https://twitter.com/_Ryobot/status/1050925881894400000）

DL4JでもBERTを試してみることができるようになりました。

- [BERT事前訓練モデルのインポート対応](https://github.com/deeplearning4j/deeplearning4j/pull/7245)
- [BERT訓練用のデータセットイテレータ`BertIterator`の追加](https://github.com/deeplearning4j/deeplearning4j/pull/7430)
- [BERTのWordPieceトークナイザーの追加](https://github.com/deeplearning4j/deeplearning4j/pull/7141)

# 最後に

こっそり以下のような面白い機能が追加されてたりもします。

- DL4Jに[CapsuleLayer](https://github.com/deeplearning4j/deeplearning4j/blob/master/deeplearning4j/deeplearning4j-nn/src/main/java/org/deeplearning4j/nn/conf/layers/CapsuleLayer.java)の追加（ただしGPUアクセラレーションは次回以降のリリースで対応）
- ND4Jに[NonMaximumSuppression](https://github.com/deeplearning4j/deeplearning4j/blob/master/nd4j/nd4j-backends/nd4j-api-parent/nd4j-api/src/main/java/org/nd4j/linalg/api/ops/impl/image/NonMaxSuppression.java)の追加（[NMSはYOLOなどの物体認識アルゴリズム内で利用されている](https://towardsdatascience.com/you-only-look-once-yolo-implementing-yolo-in-less-than-30-lines-of-python-code-97fb9835bfd2)）
- ベクトル化・ETLライブラリ[DataVec](https://deeplearning4j.org/docs/latest/datavec-overview)に[`PythonTransorfm`](https://github.com/deeplearning4j/deeplearning4j/blob/master/datavec/datavec-python/src/main/java/org/datavec/python/PythonTransform.java)の追加（Pythonのデータの前処理コードをJavaで利用）

他にも多数の機能追加・バグ修正があります。本稿で取り上げきれなかった内容に関しては[公式のリリースノート](https://deeplearning4j.org/release-notes#onezerozerobeta4)を参照してください。

このように定番化してきた新しい技術をネイティブにサポートするための新機能などが多数追加されたDL4J 1.0.0-beta4を使ってみてはいかがでしょうか。