You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mxnet.apache.org by ns...@apache.org on 2018/10/21 04:07:37 UTC
[incubator-mxnet] branch master updated: Fix Batch input issue with
Scala Benchmark (#12848)
This is an automated email from the ASF dual-hosted git repository.
nswamy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-mxnet.git
The following commit(s) were added to refs/heads/master by this push:
new 58f4117 Fix Batch input issue with Scala Benchmark (#12848)
58f4117 is described below
commit 58f411747f10b7bfe3ff5d80895ace2e2508f7ec
Author: Lanking <la...@live.com>
AuthorDate: Sat Oct 20 21:07:24 2018 -0700
Fix Batch input issue with Scala Benchmark (#12848)
* add initial change
* add fix
* improved usage of Shape as well as warning message on performance
* change into parallel
* drop dropBack
* apply Andrew's comments
* remove add dim inside img 2 pixel
* addressed Naveen's comment
* update comments
---
.../test/scala/org/apache/mxnet/ShapeSuite.scala | 15 +++++++++++
.../scala/org/apache/mxnetexamples/InferBase.scala | 2 +-
.../benchmark/ScalaInferenceBenchmark.scala | 8 +++---
.../imageclassifier/ImageClassifierExample.scala | 6 +++--
.../objectdetector/SSDClassifierExample.scala | 5 ++--
.../org/apache/mxnetexamples/rnn/TestCharRnn.scala | 2 +-
.../org/apache/mxnet/infer/ImageClassifier.scala | 29 +++++++++++++---------
.../org/apache/mxnet/infer/ObjectDetector.scala | 24 +++++++++++-------
.../scala/org/apache/mxnet/infer/Predictor.scala | 1 +
.../apache/mxnet/infer/ImageClassifierSuite.scala | 4 +--
10 files changed, 63 insertions(+), 33 deletions(-)
diff --git a/scala-package/core/src/test/scala/org/apache/mxnet/ShapeSuite.scala b/scala-package/core/src/test/scala/org/apache/mxnet/ShapeSuite.scala
index b4b7486..b186653 100644
--- a/scala-package/core/src/test/scala/org/apache/mxnet/ShapeSuite.scala
+++ b/scala-package/core/src/test/scala/org/apache/mxnet/ShapeSuite.scala
@@ -29,4 +29,19 @@ class ShapeSuite extends FunSuite with BeforeAndAfterAll {
assert(Shape(1, 2, 3) === Shape(1, 2, 3))
assert(Shape(1, 2) != Shape(1, 2, 3))
}
+
+ test("drop") {
+ val s = Shape(1, 2, 3)
+ val s2 = s.drop(1)
+ assert(s == Shape(1, 2, 3))
+ assert(s2 == Shape(2, 3))
+ val s3 = s.drop(2)
+ assert(s3 == Shape(3))
+ }
+
+ test("slice") {
+ val s = Shape(1, 2, 3)
+ val s2 = s.slice(0, 1)
+ assert(s2 == Shape(1))
+ }
}
diff --git a/scala-package/examples/src/main/scala/org/apache/mxnetexamples/InferBase.scala b/scala-package/examples/src/main/scala/org/apache/mxnetexamples/InferBase.scala
index 85d5c85..36a85c2 100644
--- a/scala-package/examples/src/main/scala/org/apache/mxnetexamples/InferBase.scala
+++ b/scala-package/examples/src/main/scala/org/apache/mxnetexamples/InferBase.scala
@@ -21,7 +21,7 @@ import org.apache.mxnet._
trait InferBase {
- def loadModel(context: Array[Context]): Any
+ def loadModel(context: Array[Context], batchInference : Boolean): Any
def loadSingleData(): Any
def loadBatchFileList(batchSize: Int): List[Any]
def loadInputBatch(source: Any): Any
diff --git a/scala-package/examples/src/main/scala/org/apache/mxnetexamples/benchmark/ScalaInferenceBenchmark.scala b/scala-package/examples/src/main/scala/org/apache/mxnetexamples/benchmark/ScalaInferenceBenchmark.scala
index dad2b53..dc2faec 100644
--- a/scala-package/examples/src/main/scala/org/apache/mxnetexamples/benchmark/ScalaInferenceBenchmark.scala
+++ b/scala-package/examples/src/main/scala/org/apache/mxnetexamples/benchmark/ScalaInferenceBenchmark.scala
@@ -31,9 +31,9 @@ object ScalaInferenceBenchmark {
private val logger = LoggerFactory.getLogger(classOf[CLIParserBase])
- def loadModel(objectToRun: InferBase, context: Array[Context]):
+ def loadModel(objectToRun: InferBase, context: Array[Context], batchInference : Boolean):
Any = {
- objectToRun.loadModel(context)
+ objectToRun.loadModel(context, batchInference)
}
def loadDataSet(objectToRun: InferBase):
@@ -134,7 +134,7 @@ object ScalaInferenceBenchmark {
logger.info("Running single inference call")
// Benchmarking single inference call
NDArrayCollector.auto().withScope {
- val loadedModel = loadModel(exampleToBenchmark, context)
+ val loadedModel = loadModel(exampleToBenchmark, context, false)
val dataSet = loadDataSet(exampleToBenchmark)
val inferenceTimes = runInference(exampleToBenchmark, loadedModel, dataSet, baseCLI.count)
printStatistics(inferenceTimes, "single_inference")
@@ -144,7 +144,7 @@ object ScalaInferenceBenchmark {
logger.info("Running for batch inference call")
// Benchmarking batch inference call
NDArrayCollector.auto().withScope {
- val loadedModel = loadModel(exampleToBenchmark, context)
+ val loadedModel = loadModel(exampleToBenchmark, context, true)
val batchDataSet = loadBatchDataSet(exampleToBenchmark, baseCLI.batchSize)
val inferenceTimes = runBatchInference(exampleToBenchmark, loadedModel, batchDataSet)
printStatistics(inferenceTimes, "batch_inference")
diff --git a/scala-package/examples/src/main/scala/org/apache/mxnetexamples/infer/imageclassifier/ImageClassifierExample.scala b/scala-package/examples/src/main/scala/org/apache/mxnetexamples/infer/imageclassifier/ImageClassifierExample.scala
index 9b6f19a..c7f2fda 100644
--- a/scala-package/examples/src/main/scala/org/apache/mxnetexamples/infer/imageclassifier/ImageClassifierExample.scala
+++ b/scala-package/examples/src/main/scala/org/apache/mxnetexamples/infer/imageclassifier/ImageClassifierExample.scala
@@ -175,9 +175,11 @@ class CLIParser extends CLIParserBase{
class ImageClassifierExample(CLIParser: CLIParser) extends InferBase{
- override def loadModel(context: Array[Context]): Classifier = {
+ override def loadModel(context: Array[Context],
+ batchInference : Boolean = false): Classifier = {
val dType = DType.Float32
- val inputShape = Shape(1, 3, 224, 224)
+ val batchSize = if (batchInference) CLIParser.batchSize else 1
+ val inputShape = Shape(batchSize, 3, 224, 224)
val inputDescriptor = IndexedSeq(DataDesc("data", inputShape, dType, "NCHW"))
diff --git a/scala-package/examples/src/main/scala/org/apache/mxnetexamples/infer/objectdetector/SSDClassifierExample.scala b/scala-package/examples/src/main/scala/org/apache/mxnetexamples/infer/objectdetector/SSDClassifierExample.scala
index a8d40c9..f752ef6 100644
--- a/scala-package/examples/src/main/scala/org/apache/mxnetexamples/infer/objectdetector/SSDClassifierExample.scala
+++ b/scala-package/examples/src/main/scala/org/apache/mxnetexamples/infer/objectdetector/SSDClassifierExample.scala
@@ -203,9 +203,10 @@ class CLIParser extends CLIParserBase {
class SSDClassifierExample(CLIParser: CLIParser)
extends InferBase {
- override def loadModel(context: Array[Context]): Any = {
+ override def loadModel(context: Array[Context], batchInference: Boolean = false): Any = {
val dType = DType.Float32
- val inputShape = Shape(1, 3, 512, 512)
+ val batchSize = if (batchInference) CLIParser.batchSize else 1
+ val inputShape = Shape(batchSize, 3, 512, 512)
val inputDescriptors = IndexedSeq(DataDesc("data", inputShape, dType, "NCHW"))
new ObjectDetector(CLIParser.modelPathPrefix, inputDescriptors, context)
}
diff --git a/scala-package/examples/src/main/scala/org/apache/mxnetexamples/rnn/TestCharRnn.scala b/scala-package/examples/src/main/scala/org/apache/mxnetexamples/rnn/TestCharRnn.scala
index 25bf479..bf2eba6 100644
--- a/scala-package/examples/src/main/scala/org/apache/mxnetexamples/rnn/TestCharRnn.scala
+++ b/scala-package/examples/src/main/scala/org/apache/mxnetexamples/rnn/TestCharRnn.scala
@@ -115,7 +115,7 @@ class TestCharRnn(CLIParser: CLIParser) extends InferBase {
private var vocab : Map[String, Int] = null
- override def loadModel(context: Array[Context]): Any = {
+ override def loadModel(context: Array[Context], batchInference : Boolean = false): Any = {
val batchSize = 32
val buckets = List(129)
val numHidden = 512
diff --git a/scala-package/infer/src/main/scala/org/apache/mxnet/infer/ImageClassifier.scala b/scala-package/infer/src/main/scala/org/apache/mxnet/infer/ImageClassifier.scala
index 8d31d1f..96be121 100644
--- a/scala-package/infer/src/main/scala/org/apache/mxnet/infer/ImageClassifier.scala
+++ b/scala-package/infer/src/main/scala/org/apache/mxnet/infer/ImageClassifier.scala
@@ -76,13 +76,16 @@ class ImageClassifier(modelPathPrefix: String,
topK: Option[Int] = None): IndexedSeq[IndexedSeq[(String, Float)]] = {
val scaledImage = ImageClassifier.reshapeImage(inputImage, width, height)
- val pixelsNDArray = ImageClassifier.bufferedImageToPixels(scaledImage, inputShape)
+ val imageShape = inputShape.drop(1)
+ val pixelsNDArray = ImageClassifier.bufferedImageToPixels(scaledImage, imageShape)
+ val imgWithBatchNum = NDArray.api.expand_dims(pixelsNDArray, 0)
inputImage.flush()
scaledImage.flush()
+ handler.execute(pixelsNDArray.dispose())
- val output = super.classifyWithNDArray(IndexedSeq(pixelsNDArray), topK)
+ val output = super.classifyWithNDArray(IndexedSeq(imgWithBatchNum), topK)
- handler.execute(pixelsNDArray.dispose())
+ handler.execute(imgWithBatchNum.dispose())
IndexedSeq(output(0))
}
@@ -97,14 +100,16 @@ class ImageClassifier(modelPathPrefix: String,
def classifyImageBatch(inputBatch: Traversable[BufferedImage], topK: Option[Int] = None):
IndexedSeq[IndexedSeq[(String, Float)]] = {
- val imageBatch = ListBuffer[NDArray]()
- for (image <- inputBatch) {
- val scaledImage = ImageClassifier.reshapeImage(image, width, height)
- val pixelsNDArray = ImageClassifier.bufferedImageToPixels(scaledImage, inputShape)
- imageBatch += pixelsNDArray
- }
+ val inputBatchSeq = inputBatch.toIndexedSeq
+ val imageBatch = inputBatchSeq.indices.par.map(idx => {
+ val scaledImage = ImageClassifier.reshapeImage(inputBatchSeq(idx), width, height)
+ val imageShape = inputShape.drop(1)
+ val imgND = ImageClassifier.bufferedImageToPixels(scaledImage, imageShape)
+ val imgWithBatch = NDArray.api.expand_dims(imgND, 0).get
+ handler.execute(imgND.dispose())
+ imgWithBatch
+ }).toList
val op = NDArray.concatenate(imageBatch)
-
val result = super.classifyWithNDArray(IndexedSeq(op), topK)
handler.execute(op.dispose())
handler.execute(imageBatch.foreach(_.dispose()))
@@ -147,9 +152,9 @@ object ImageClassifier {
* returned by this method after the use.
* </p>
* @param resizedImage BufferedImage to get pixels from
- * @param inputImageShape Input shape; for example for resnet it is (1,3,224,224).
+ * @param inputImageShape Input shape; for example for resnet it is (3,224,224).
Should be same as inputDescriptor shape.
- * @return NDArray pixels array
+ * @return NDArray pixels array with shape (3, 224, 224) in CHW format
*/
def bufferedImageToPixels(resizedImage: BufferedImage, inputImageShape: Shape): NDArray = {
// Get height and width of the image
diff --git a/scala-package/infer/src/main/scala/org/apache/mxnet/infer/ObjectDetector.scala b/scala-package/infer/src/main/scala/org/apache/mxnet/infer/ObjectDetector.scala
index ce84f53..a9b21f8 100644
--- a/scala-package/infer/src/main/scala/org/apache/mxnet/infer/ObjectDetector.scala
+++ b/scala-package/infer/src/main/scala/org/apache/mxnet/infer/ObjectDetector.scala
@@ -72,9 +72,12 @@ class ObjectDetector(modelPathPrefix: String,
: IndexedSeq[IndexedSeq[(String, Array[Float])]] = {
val scaledImage = ImageClassifier.reshapeImage(inputImage, width, height)
- val pixelsNDArray = ImageClassifier.bufferedImageToPixels(scaledImage, inputShape)
- val output = objectDetectWithNDArray(IndexedSeq(pixelsNDArray), topK)
+ val imageShape = inputShape.drop(1)
+ val pixelsNDArray = ImageClassifier.bufferedImageToPixels(scaledImage, imageShape)
+ val pixelsNDWithBatch = NDArray.api.expand_dims(pixelsNDArray, 0)
handler.execute(pixelsNDArray.dispose())
+ val output = objectDetectWithNDArray(IndexedSeq(pixelsNDWithBatch), topK)
+ handler.execute(pixelsNDWithBatch.dispose())
output
}
@@ -147,13 +150,16 @@ class ObjectDetector(modelPathPrefix: String,
def imageBatchObjectDetect(inputBatch: Traversable[BufferedImage], topK: Option[Int] = None):
IndexedSeq[IndexedSeq[(String, Array[Float])]] = {
- val imageBatch = ListBuffer[NDArray]()
- for (image <- inputBatch) {
- val scaledImage = ImageClassifier.reshapeImage(image, width, height)
- val pixelsNdarray = ImageClassifier.bufferedImageToPixels(scaledImage, inputShape)
- imageBatch += pixelsNdarray
- }
- val op = NDArray.concatenate(imageBatch)
+ val inputBatchSeq = inputBatch.toIndexedSeq
+ val imageBatch = inputBatchSeq.indices.par.map(idx => {
+ val scaledImage = ImageClassifier.reshapeImage(inputBatchSeq(idx), width, height)
+ val imageShape = inputShape.drop(1)
+ val pixelsND = ImageClassifier.bufferedImageToPixels(scaledImage, imageShape)
+ val pixelsNDWithBatch = NDArray.api.expand_dims(pixelsND, 0).get
+ handler.execute(pixelsND.dispose())
+ pixelsNDWithBatch
+ })
+ val op = NDArray.concatenate(imageBatch.toList)
val result = objectDetectWithNDArray(IndexedSeq(op), topK)
handler.execute(op.dispose())
diff --git a/scala-package/infer/src/main/scala/org/apache/mxnet/infer/Predictor.scala b/scala-package/infer/src/main/scala/org/apache/mxnet/infer/Predictor.scala
index 3987c64..e2a0e7c 100644
--- a/scala-package/infer/src/main/scala/org/apache/mxnet/infer/Predictor.scala
+++ b/scala-package/infer/src/main/scala/org/apache/mxnet/infer/Predictor.scala
@@ -181,6 +181,7 @@ class Predictor(modelPathPrefix: String,
// rebind with the new batchSize
if (batchSize != inputBatchSize) {
+ logger.info(s"Latency increased due to batchSize mismatch $batchSize vs $inputBatchSize")
val desc = iDescriptors.map((f : DataDesc) => new DataDesc(f.name,
Shape(f.shape.toVector.patch(batchIndex, Vector(inputBatchSize), 1)), f.dtype, f.layout) )
mxNetHandler.execute(mod.bind(desc, forceRebind = true,
diff --git a/scala-package/infer/src/test/scala/org/apache/mxnet/infer/ImageClassifierSuite.scala b/scala-package/infer/src/test/scala/org/apache/mxnet/infer/ImageClassifierSuite.scala
index 948764e..1c291e1 100644
--- a/scala-package/infer/src/test/scala/org/apache/mxnet/infer/ImageClassifierSuite.scala
+++ b/scala-package/infer/src/test/scala/org/apache/mxnet/infer/ImageClassifierSuite.scala
@@ -65,9 +65,9 @@ class ImageClassifierSuite extends ClassifierSuite with BeforeAndAfterAll {
val image1 = new BufferedImage(100, 200, BufferedImage.TYPE_BYTE_GRAY)
val image2 = ImageClassifier.reshapeImage(image1, 2, 2)
- val result = ImageClassifier.bufferedImageToPixels(image2, Shape(1, 3, 2, 2))
+ val result = ImageClassifier.bufferedImageToPixels(image2, Shape(3, 2, 2))
- assert(result.shape == inputDescriptor(0).shape)
+ assert(result.shape == inputDescriptor(0).shape.drop(1))
}
test("ImageClassifierSuite-testWithInputImage") {