キーポイント
- Standards to develop machine learning applications in Java have been lacking
- JSR 381 has been developed in order to address this gap
- Amazon's Deep Java Library (DJL) is one of several implementations of this new standard
- One part of JSR 381 is VisRec for visual recognition of images
- DJL includes a collection of pre-trained models
https://www.deepnetts.com/blog/deep-netts-community-edition マシンラーニングに対する関心は、ここ数年間、着実に高まっています。特に企業では、マシンラーニングを使用した画像認識が幅広いユースケースで用いられるようになりました。自動車産業、医療、警備、販売、倉庫での自動製品追跡、農業および畜産業、食物認知、さらには携帯のカメラを用いたリアルタイム翻訳など、さまざまなアプリケーションが存在します。マシンラーニングと画像認識によって、MRIやCTスキャンから癌やCOVID-19を機械的に検出することも可能になりました。
現在、これらのソリューションの多くはPythonで開発されていて、オープンソースあるいはプロプライエタリなMLツールキットを使用しています。ツールキットはそれぞれ独自のAPIを持っています。企業内ではJavaが広く使用されているにも関わらず、マシンラーニングアプリケーションをJavaで開発するための標準は存在しません。JSR-381は、画像分類(image classification)やオブジェクト検出(object detection)といった画像認識(VisRec)アプリケーションのための、フレキシブルでJavaフレンドリな標準APIをJavaアプリケーション開発者に提供することにより、このギャップを埋める目的で開発されました。JSR-381にはTensorFlowやMXNet、DeepNettsなど、依存するマシンラーニングプラットフォームによっていくつかの実装が存在します。このような実装のひとつとして、Javaでマシンラーニングを構築するためにAmazonが開発したオープンソースライブラリである、Deep Java Library(DJL)をベースとするものがあります。DILはTensorFlowやMXNet、PyTorchといった一般的なマシンラーニングフレームワーク内のイメージ処理ルーチンをバンドルし、フレームワークへのフックを提供することによって、JSR-381ユーザにフレキシブルかつシンプルな選択肢を提供しています。
この記事ではDJLのトレーニング済モデルを使用して、JSR-381 VisRec APIを使った10行未満のコードで画像分類やオブジェクト検出を行う方法を紹介します。さらに、トレーニング済モデルを10分以内に使用する方法についても、2つの例で紹介したいと思います。では始めましょう!
トレーニング済モデルを使用した手書き数字の認識
画像認識の"hello world"にあたる有用なアプリケーションは手書き数字の認識です。手書き数字を認識する作業は、人にとっては容易なものに見えます。私たちの脳にある処理能力と、視覚およびパターンマッチングサブシステムの共同作業のおかげで、粗雑に書かれたドキュメントであっても、正確な数字を正しく識別することが可能です。しかしながら、一見単純そうなこのタスクは、そのバリエーションの多さから、マシンにとっては極めて複雑な仕事なのです。マシンラーニング、特に視覚認識において、これは適切なユースケースになります。JSR 381リポジトリには、JSR-381 VisRec APIを使って手書き文字を正確に認識する、優れたサンプルがあります。このサンプルでは、手書き文字を、6万以上の画像による公開データベースのMNIST handwrittern digiti datasetと比較します。画像が何を表現しているかを予測する作業は、画像分類(image classification)と呼ばれます。私たちのサンプルであれば、新しい画像を見て、それが何の数字であるかを判断することがこれに当たります。
このタスクのためにVisRec APIには、ImageClassifierというインターフェースが用意されています。これを所定のJavaクラスに特殊化することで、ジェネリックなパラメータを使った画像入力と、画像分類を実行して、可能性のあるすべての画像クラスと確度(probability)をMapとして返すclassify()メソッドが利用可能になります。VisRec APIの決まりとして、各モデルは、対応するビルダオブジェクトを返すstaticなbuilder()メソッドを提供すると同時に、imageHeightやimageWidthのような関連する設定を構成できるようになっています。
私たちの手書き数字のサンプルで使用する画像分類器(image classifier)を定義するために、inputClass(BufferedImage.class)
を使って入力処理を構成し、その画像を表現するクラスを指定します。さらにimageHeight(28)
とimageWidth(28)
を使用して入力イメージを28x28にサイズ変更します。これは、モデルのトレーニングに使用したオリジナル画像のサイズが28x28であるためです。
Classifierオブジェクトが構築できたならば、入力イメージを渡してイメージ認識を実行します。
File input = new File("../jsr381/src/test/resources/0.png");
// Use the pre-trained model from mlp folder
Path modelPath = Paths.get("../jsr381/src/test/resources/mlp");
ImageClassifier<BufferedImage> classifier =
NeuralNetImageClassifier.builder()
// The input is an image file and should be handled as BufferImage
.inputClass(BufferedImage.class)
// the image should be resize to 28 x 28
.imageHeight(28)
.imageWidth(28)
.importModel(modelPath)
.build();
// run inference and get classification result
Map<String, Float> result = classifier.classify(input);
// print out the result
for (Map.Entry<String, Float> entry : result.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
このコードを実行すると、次のような出力が得られます。
0: 0.9997633
2: 6.915607E-5
5: 2.7744078E-5
6: 6.1097984E-5
9: 3.8322916E-5
モデルは、イメージ内に埋め込まれた数字に対する選択肢を5つ、それぞれの確度と共に特定しました。該当する数字が0、確度が99.98パーセントと極めて大きな値となっていて、正しい推測が行われています。
このケースを一般化する上で、明らかに問題になるのは、同じイメージ内の異なるオブジェクトを検出する必要がある場合はどうするのか、という疑問です。
トレーニング済SSD(Single Shot Detector)モデルを使用したオブジェクト認識
SSD(Single Shot Detector)は、単一ディープニューラルネットワーク(single deep neural network)を用いて、イメージ内のオブジェクトを検出するメカニズムです。今回のサンプルでは、トレーニング済のSSDモデルを使用してイメージ内のオブジェクトを認識します。オブジェクト検出は視覚認識よりも難しいタスクです。イメージ内のオブジェクトの分類に加えて、オブジェクト検出では、イメージ内のオブジェクトの位置も識別します。対象とする各オブジェクトの周辺に境界ボックスを描画して、クラスの(テキスト)ラベルを付加することも可能です。
SSDメカニズムはマシンラーニングにおいて最近開発されたもので、非常に短時間でオブジェクトを検出すると同時に、より計算集約的な他のモデルと同等の正確性も維持しています。SSDについてより詳しく学ぶためには、ブログ記事"Understanding SSD MultiBox ― Real-Time Object Detection In Deep Learning"や、書籍"Dive into Deep Learning"中の演習があります。
DJLのJSR-381実装では、トレーニング済のSSDモデルの実装にアクセスして、すぐに使うことができます。DJLでは、モデルのデプロイを簡略化するためにModelZooを使用しています。以下のコードブロックでは、ModelZoo.loadModel()でトレーニング済モデルをロードし、Object検出クラスをインスタンス化して、このモデルをサンプルイメージに適用します。
// Define a criteria to search a model that matches user's need
Criteria<BufferedImage, DetectedObjects> criteria =
Criteria.builder()
.setTypes(BufferedImage.class, DetectedObjects.class)
// search for an object detection model
.optApplication(Application.CV.OBJECT_DETECTION)
.build();
// Load the model and create a SimpleObjectDectector
try (ZooModel<BufferedImage, DetectedObjects> model = ModelZoo.loadModel(criteria)) {
// SimpleObjectDetector is a high level JSR-381 API in charge of detect object
SimpleObjectDetector objectDetector = new SimpleObjectDetector(model);
// Load image
BufferedImage input =
BufferedImageUtils.fromUrl(
"https://djl-ai.s3.amazonaws.com/resources/images/dog_bike_car.jpg");
// detect objects
Map<String, List<BoundingBox>> result = objectDetector.detectObject(input);
for (List<BoundingBox> boundingBoxes : result.values()) {
for (BoundingBox boundingBox : boundingBoxes) {
System.out.println(boundingBox.toString());
}
}
}
私たちの使用する新しいイメージはこちらです。
このイメージで私たちのコードを実行すると、次の結果が得られます。
BoundingBox{id=0, x=124.0, y=119.0, width=456.45093, height=338.8393, label=bicycle, score=0.9538524}
BoundingBox{id=0, x=469.0, y=78.0, width=225.19464, height=92.147675, label=car, score=0.99991035}
BoundingBox{id=0, x=128.0, y=201.0, width=210.51933, height=341.7647, label=dog, score=0.9375212}
イメージ上で検出された各オブジェクトに境界ボックスを追加したい場合は、数行のコードを追加するだけで可能です。詳細な情報は、完全なGitHubのサンプルを参照してください。モデルは対象とする3つのオブジェクト(自転車、自動車、犬)を分類し、それぞれの周囲に境界ボックスを描いて、確度を反映した信頼レベル(confidence level)を提供します。
トレーニング済モデルの検出精度は、モデルのトレーニングに使用したイメージに依存する点に注意してください。モデルを再トレーニングするか、エンドアプリケーションを表現するものにより近いイメージセットを使って独自のモデルを開発すれば、モデルの精度を向上することができます。しかしこのアプローチには時間が掛かる上、大規模なトレーニングデータへのアクセスが必要になります。多くのMLアプリケーションでは、トレーニング済のモデルでベースラインを確立する価値のあることが多々あります。これによって、データを収集し準備して、モデルをスクラッチからトレーニングする時間を大幅に節約することが可能になるのです。
その次は?
今回の記事は、JSR-381 APIのDJL実装を使ってできることの、ほんの一部を取り上げたに過ぎません。ModelZooのトレーニング済モデルのリポジトリにあるたくさんのモデルを探して実装したり、あるいは独自のモデルに発展させることができます。
DJLにもぜひ注目してください。AmazonのJava開発者たちがコミュニティのために開発した、オープンソースのライブラリです。私たちは、Javaによるマシンラーニングの開発やデプロイを簡単なものにしたいと思っています。私たちの活動に加わってください。
DJLにはユースケースがたくさんあります。カスタマサービス用のQAアプリケーションの開発、ヨガポーズ用の姿勢推定モデルの実装、裏庭の侵入者を検出する独自モデルのトレーニングなどが考えられます。私たちのSpring Bootスターターキットも、Spring BootアプリケーションへのML統合を容易にしてくれます。DJLの詳細を学ぶには、私たちの紹介ブログやWebサイト、サンプルリポジトリなどを利用してください。私たちのGitHubリポジトリにアクセスして、Slackのチャネルで一緒に活動しましょう。
引用文献
- Getting Started Guide — Visual Recognition (VisRec) JSR #381
- VisRec API JSR381 implementation with DJL
- JSR381公式ページ
著者について
Frank Liu氏はAWS AIのソフトウェアエンジニアです。氏が注目するのは、ソフトウェアエンジニアと科学者を対象とした、画期的なディープラーニングツールの開発です。自由な時間は、友人や家族とハイキングを楽しんでいます。
Xinyu Liu氏はAWS AIのソフトウェア開発マネージャです。氏はマシンラーニングと大規模分散システムに情熱を持っています。
Frank Greco氏はCrossroads Technologiesの創業者兼CEOです。シニアクラウドコンサルタント、およびエンタープライズアーキテクトとして、クラウドや開発者向けAI/MLツールの開発に従事しています。氏はJava ChampionでNYJavaSIGのチェアマンであり、International Machine Learning for the Enterprise conference in Europeを運営しています。余暇はギターに没頭しています。
Zoran Sevarac氏はDeep NettsのCEOです。Java開発者向けのユーザフレンドリなディープラーニングツールの開発とAIのJava標準の確立に従事しています。氏はベオグラード大学の教授で、Java Championです。余暇にはギターを弾いています。
Balaji Kamakoti氏はAWS AIのシニアプロダクトマネージャです。ディープラーニングを開発者にとってよりアクセスしやすくするためのプロダクトを開発しています。余暇はテニスをしたり、フレットのない弦楽器であるSarodを演奏したりしています。
JCPおよびJSR-381チームの以下の方々による価値ある協力に感謝します。
Kevin Berendsen、 Sandhya Kapoor、 Werner Keil、 Constantin Drabo、 Ankara Parida、 Melissa Mckay、 Buddha Jyoti Prasad、 Shreya Gupta、 Amit Nagesh、 Heather VanCura、 Harold Ogle各氏