Skip to content
This repository has been archived by the owner on Nov 17, 2023. It is now read-only.

[MXNET-689] add DataDesc type for the Scala Package #11844

Merged
merged 25 commits into from
Aug 17, 2018

Conversation

lanking520
Copy link
Member

@lanking520 lanking520 commented Jul 20, 2018

Description

This PR includes massive changes on all Iterators that extends DataIter, two new fields are added (dtype and layout).

@nswamy @yzhliu @andrewfayres

It intends to solve some issues about the layout information missing in DataDesc. For example: RNN based networks require different layouts(“TNC”/”NTC”). Current implementation of DataBatch, DataIter does not support different layouts and assumes a fixed layout based on the shape of the NDArray returned in the next() call to the iterator.

However I found it hard to have a general solution that both address backward compatibility as well as adding this information. Currently, there are several ways to address this issue:

  1. Assume Shape == 2 follows NT format, Shape == 3 follows TNC, Shape == 4 follows NCHW and only change the implicit function in here.

  2. Add Layout and DType defs for all iterator, then users can pass these information to create DataDesc instead of ListMap[Name, Shape]. However, it breaks the input args for NDArrayIter as well as other iterators. Users are required to add more inputs. However, if the iterator are passed in with dynamic shapes (shapes are not determined), it will break the DataDesc checking scheme.

  3. Do what 2 contains and create this constructor to make sure BC.

Test

  • IOSuite
  • ModuleSuite
  • DataIterSuite

Historical issues

Checklist

Essentials

Please feel free to remove inapplicable items for your PR.

  • The PR title starts with [MXNET-$JIRA_ID], where $JIRA_ID refers to the relevant JIRA issue created (except PRs with tiny changes)
  • Changes are complete (i.e. I finished coding on this PR)
  • All changes have test coverage:
  • Unit tests are added for small changes to verify correctness (e.g. adding a new operator)
  • Nightly tests are added for complicated/long-running ones (e.g. changing distributed kvstore)
  • Build tests will be added for build configuration changes (e.g. adding a new build option with NCCL)
  • Code is well-documented:
  • For user-facing API changes, API doc string has been updated.
  • For new C++ functions in header files, their functionalities and arguments are documented.
  • For new examples, README.md is added to explain the what the example does, the source of the dataset, expected performance on test set and reference to the original paper if applicable
  • Check the API doc at http:https://mxnet-ci-doc.s3-accelerate.dualstack.amazonaws.com/PR-$PR_ID/$BUILD_ID/index.html
  • To the my best knowledge, examples are either not affected by this change, or have been fixed to be compatible with this change

@lanking520
Copy link
Member Author

When I am in the middle of changes, some parts looks confusing to me. Are we defining these field in the dataiter class or we fetch these information through databatch. There are different solution in different DataIters' child classes. The currently issue that failing the test is actually here:

  /**
   * DataIter creator
   * @param handle native memory ptr for the iterator
   * @param params parameter passed to the iterator
   * @return created DataIter
   */
  private def creator(handle: DataIterCreator)(
    params: Map[String, String]): DataIter = {
    val out = new DataIterHandleRef
    val keys = params.keys.toArray
    val vals = params.values.toArray
    checkCall(_LIB.mxDataIterCreateIter(handle, keys, vals, out))
    val dataName = params.getOrElse("data_name", "data")
    val labelName = params.getOrElse("label_name", "label")
    new MXDataIter(out.value, dataName, labelName)
  }

This creator did not pass in the layout and dtype information and MXDataIter extends DataIter. By default, the layout are set a "NCHW" that causing the problem.

(null, null)
}

private val (_provideDataDesc: IndexedSeq[DataDesc],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we only keep DataDesc and construct ListMap from DataDesc? or at least combine it with L45-58

* @param dtype The dtype of the label, default is Float32
* @return this
*/
def setDType(dtype: DType): Builder = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you specify the default value here

@@ -140,7 +140,9 @@ class DataBatch(val data: IndexedSeq[NDArray],
// use ListMap to indicate the order of data/label loading
// (must match the order of input data/label)
private val providedData: ListMap[String, Shape] = null,
private val providedLabel: ListMap[String, Shape] = null) {
private val providedLabel: ListMap[String, Shape] = null,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should replace this constructor with provideDataShape, provideLabelShape that DataDesc instead ListMap[String, Shape] and constructor(this) another to preserve ListMap so we don't break backwards compatibility

@@ -170,6 +172,8 @@ object DataBatch {
private var label: IndexedSeq[NDArray] = null
private var index: IndexedSeq[Long] = null
private var pad: Int = 0
private var layout: String = "NCHW"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we wouldn't need this if add a new constructor with DataDesc

@@ -314,6 +351,12 @@ abstract class DataIter extends Iterator[DataBatch] {
// The name and shape of label provided by this iterator
def provideLabel: ListMap[String, Shape]

// Provide type:DataDesc of the data
def provideDataDesc: IndexedSeq[DataDesc]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we deprecate the old ones?

* Get the DType
* @return DType
*/
def getDType(): DType = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggest to add two new parameters to the constructor dataDescriptor and labelDescriptor.
Make sure not break API backwards compatibility

@lanking520 lanking520 changed the title [MXNET-689][WIP] add DataDesc type for the Scala Package [MXNET-689] add DataDesc type for the Scala Package Jul 24, 2018
@lanking520
Copy link
Member Author

After some days spent on the issues, I finally figure out the fix on the issues we have. @nswamy and @yzhliu thanks for your comments on the changes and things I am about to apply is:

  • Depreciate provideData and provideLabel methods
  • disable implicit transformation in IO to use DataDesc everywhere
    @andrewfayres please join the review if you have time :-)
    Please provide a secondary review before I apply these changes. There will be a final review session once changes are applied and everything I felt is settled.

@@ -59,10 +61,12 @@ class NDArrayIter(data: IndexedSeq[(String, NDArray)],
def this(data: IndexedSeq[NDArray], label: IndexedSeq[NDArray] = IndexedSeq.empty,
dataBatchSize: Int = 1, shuffle: Boolean = false,
lastBatchHandle: String = "pad",
dataName: String = "data", labelName: String = "label") {
dataName: String = "data", labelName: String = "label",
dType: DType = MX_REAL_TYPE, dataLayout: String = "NCHW",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to add this here. add the defaults to the new constructor above in L47

Copy link
Member

@nswamy nswamy Jul 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create another this constructor with the old set of constructor args to not break backwards compatibility.

thinking about it, can you first add default to the class constructor and test

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its ok to keep here. let all the defaults remain in one place.

@@ -170,6 +180,10 @@ object DataBatch {
private var label: IndexedSeq[NDArray] = null
private var index: IndexedSeq[Long] = null
private var pad: Int = 0
private var dataLayout: String = "NCHW"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For layouts I suggest to use extensible Enums similar to this https://blogs.oracle.com/darcy/mixing-in-an-enum.
free floating strings are generally not a good practice because it removes compile time type-checks.
WDYT? does it make sense?

@lanking520
Copy link
Member Author

Hi @benkamphaus, could you please take a look at the recent CI failure on Clojure. I believe these lines cause that failure: https://github.com/apache/incubator-mxnet/blob/master/contrib/clojure-package/src/org/apache/clojure_mxnet/io.clj#L194-L225. I have modified the input args for NDArrayIter and there will be more optional fields

@nswamy
Copy link
Member

nswamy commented Jul 26, 2018

@benkamphaus, from Clojure perspective are we breaking backwards compatibility. I am curious to know how it is handled, since we added new parameters with defaults.

@benkamphaus
Copy link

It appears to be the case that the new constructor arglist for NDArrayIter breaks backwards compatibility, which is the cause of the current Clojure CI broken message:

No matching ctor found for class org.apache.mxnet.io.NDArrayIter, compiling:(org/apache/clojure_mxnet/io.clj:216:4)

The cause is straight forward -- the constructor call here is no longer valid due to the change to the args required for NDArrayIter as declared here.

This constructor call on the clojure side backs ndarray-iter, and there are tests, specs, and examples and the changes in required args to ndarray-iter would need those to change as well. (i.e. this impacts the API/contract level, not just an implementation concern below those).

Note that the keyword args in the Clojure API means that ndarray-iter could back a call to both the previous NDArrayIter constructor and the form with the new args (using additional, optional args to the same function in the Clojure API). Otherwise, I'm not sure what the expectation/desire is here without more context.

I'll discuss with @gigasquid as well.

@lanking520
Copy link
Member Author

@benkamphaus thanks for your detailed analysis. I can tell how hard it is if we change the args in here since I also changed a lot of examples to match this change in Scala. Let's be cautious on this change and discuss if it is necessary here to introduce more parameters.

@lanking520
Copy link
Member Author

I have reverted the changes back to Strings. Next step is to add a default value to Layout section so we can bypass the require check

@lanking520 lanking520 force-pushed the dataiter branch 3 times, most recently from 6c8289a to f49eeca Compare August 7, 2018 02:17
@lanking520
Copy link
Member Author

In the recent two PR, add Backward Compatibility fix on DataIter as well as DataBatch. User can still go with the old defs...

@nswamy nswamy merged commit abbe283 into apache:master Aug 17, 2018
marcoabreu added a commit that referenced this pull request Aug 17, 2018
piyushghai added a commit to piyushghai/incubator-mxnet that referenced this pull request Aug 17, 2018
XinYao1994 pushed a commit to XinYao1994/incubator-mxnet that referenced this pull request Aug 29, 2018
* add dataDesc

* Add amend

* add changes with dataLayout and labelLayout

* add depreciate and example changes

* Gan and Customop fixes

* change the DType

* add one more class to convert Strings to DTypes

* convert layout to global

* scala style fix

* Revert to 8c7d1f8

* fix coding style issue

* print full stacktraces

* apply changes to new constructor

* add databatch bcc

* introduce undefined field

* Fix crashes when change provideData to provideDataDesc

It looks like if we want to force conversion from Float32 to Int32 will cause a crash on JVM. Need to be addressed.

* change spacing and revert test

* apply DataDesc on DataBatch

* unit test for NDArrayIter and MXDataiter

* apply changes on CR

* change NDArrayIter and revert the rest

* revert change on examples

* apply final changes

* remove the provideLabelShape

* add TODO about the findings
@lanking520 lanking520 deleted the dataiter branch September 19, 2018 23:00
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
pr-awaiting-response PR is reviewed and waiting for contributor to respond Scala
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants