apache / mxnet

Lightweight, Portable, Flexible Distributed/Mobile Deep Learning with Dynamic, Mutation-aware Dataflow Dep Scheduler; for Python, R, Julia, Scala, Go, Javascript and more
https://mxnet.apache.org
Apache License 2.0
20.77k stars 6.8k forks source link

NDarray slicing #2127

Closed hariag closed 8 years ago

hariag commented 8 years ago

Hi all,

I have some trouble when accessing NDArray, I have a NDArray which store multi-labels for my data,

>>> import mxnet as mx
>>> label=mx.nd.array([[0,0],[0,1],[1,0]])
>>> label1,label2=label.T
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/hxf/mxnet/python/mxnet/ndarray.py", line 212, in __getitem__
    raise ValueError('NDArray only support continuous slicing on axis 0')
ValueError: NDArray only support continuous slicing on axis 0
>>> 

but it seems label field request a list object, so I have to separate label object.

mx.io.DataBatch(data=batch.data, label=[label1, label2],  pad=batch.pad, index=batch.index) 

currently I use a ugly implementation as below.

>>> import mxnet as mx
>>> label=mx.nd.array([[0,0],[0,1],[1,0]])
>>> label1,label2=label.T.asnumpy()
>>> label1=mx.nd.array(label1)
>>> label2=mx.nd.array(label2)
>>> 

I would like to know is there any more elegant way to satisfy my request? Thank you very much!

tornadomeet commented 8 years ago

you do not need to separate the label into multi part, for the ioiter supports label_width(=2 here), so you can just input your original label.

hariag commented 8 years ago

Hi @tornadomeet

I refer to multi-task sample exists in mxnet samples folder.


class Multi_mnist_iterator(mx.io.DataIter):
    '''multi label mnist iterator'''

    def __init__(self, data_iter):
        super(Multi_mnist_iterator, self).__init__()
        self.data_iter = data_iter
        self.batch_size = self.data_iter.batch_size

    @property
    def provide_data(self):
        return self.data_iter.provide_data

    @property
    def provide_label(self):
        provide_label = self.data_iter.provide_label[0]
        # Different labels should be used here for actual application
        return [('softmax1_label', (self.batch_size,)), \
                ('softmax2_label', (self.batch_size,))]

    def hard_reset(self):
        self.data_iter.hard_reset()

    def reset(self):
        self.data_iter.reset()

    def next(self):
        batch = self.data_iter.next()
        print batch.label[0].asnumpy()
        return mx.io.DataBatch(data=batch.data, label=[label, label], \
                pad=batch.pad, index=batch.index)

seen "next" function I added a print, and the result as below [[ 50. 1.] [ 51. 1.] [ 9. 1.] [ 22. 0.] [ 77. 0.] [ 70. 0.] [ 74. 0.] [ 35. 0.] [ 44. 1.] [ 67. 0.] [ 15. 0.] [ 0. 1.] [ 32. 0.] [ 69. 1.] [ 27. 1.] [ 76. 0.] [ 16. 0.] [ 52. 1.] [ 39. 1.] [ 66. 1.] [ 77. 0.] [ 38. 0.] [ 58. 1.] [ 39. 1.] [ 41. 1.] [ 32. 0.] [ 58. 1.] [ 0. 1.] [ 46. 0.] [ 58. 1.] [ 52. 1.] [ 11. 1.] [ 69. 1.] [ 9. 1.] [ 2. 0.] [ 25. 1.] [ 52. 1.] [ 39. 1.] [ 46. 0.] [ 77. 0.] [ 5. 0.] [ 38. 0.] [ 49. 0.] [ 61. 0.] [ 40. 1.] [ 4. 0.] [ 66. 1.] [ 28. 1.] [ 70. 0.] [ 1. 0.] [ 63. 1.] [ 20. 0.] [ 23. 1.] [ 1. 0.] [ 27. 1.] [ 28. 1.] [ 37. 1.] [ 23. 1.] [ 49. 0.] [ 50. 1.] [ 80. 0.] [ 37. 1.] [ 59. 1.] [ 46. 0.] [ 46. 0.] [ 43. 1.] [ 56. 0.] [ 42. 0.] [ 74. 0.] [ 8. 0.] [ 40. 1.] [ 18. 1.] [ 45. 0.] [ 33. 0.] [ 60. 0.] [ 79. 1.] [ 30. 0.] [ 20. 0.] [ 66. 1.] [ 22. 0.] [ 61. 0.] [ 14. 0.] [ 48. 0.] [ 82. 1.] [ 49. 0.] [ 38. 0.] [ 26. 0.] [ 28. 1.] [ 11. 1.] [ 23. 1.] [ 78. 0.] [ 65. 1.] [ 22. 0.] [ 63. 1.] [ 68. 1.] [ 23. 1.] [ 34. 1.] [ 22. 0.] [ 73. 0.] [ 24. 0.] [ 57. 0.] [ 19. 1.] [ 39. 1.] [ 61. 0.] [ 41. 1.] [ 23. 1.] [ 19. 1.] [ 5. 0.] [ 34. 1.] [ 77. 0.] [ 57. 0.] [ 79. 1.] [ 57. 0.] [ 46. 0.] [ 76. 0.] [ 68. 1.] [ 25. 1.] [ 37. 1.] [ 19. 1.] [ 63. 1.] [ 27. 1.] [ 10. 1.] [ 67. 0.] [ 18. 1.] [ 23. 1.] [ 72. 0.] [ 75. 1.] [ 5. 0.]]

so I think the two label is loaded correctly. But I am not sure how to set label below without ugly convertion.

 mx.io.DataBatch(data=batch.data, label=[label,label], pad=batch.pad, index=batch.index)

the original code use a list of two 1dim NDArray, but on my case the label is a one 2dim NDArray

I tried modify "next" function as below

    def next(self):
        batch = self.data_iter.next()
        return mx.io.DataBatch(data=batch.data, label=batch.label, \
                pad=batch.pad, index=batch.index)

but got a error

INFO:root:Start training with [gpu(0)] [21:40:42] /home/haria/mxnet/dmlc-core/include/dmlc/logging.h:235: [21:40:42] src/ndarray/ndarray.cc:227: Check failed: from.shape() == to->shape() operands shape mismatch Traceback (most recent call last): File "example_multi_task.py", line 147, in epoch_end_callback = checkpoint File "/home/haria/mxnet/python/mxnet/model.py", line 784, in fit sym_gen=self.sym_gen) File "/home/haria/mxnet/python/mxnet/model.py", line 222, in _train_multi_device executor_manager.load_data_batch(data_batch) File "/home/haria/mxnet/python/mxnet/executor_manager.py", line 394, in load_data_batch self.curr_execgrp.load_data_batch(data_batch) File "/home/haria/mxnet/python/mxnet/executor_manager.py", line 246, in load_data_batch _load_label(data_batch, self.label_arrays) File "/home/haria/mxnet/python/mxnet/executor_manager.py", line 91, in _load_label _load_general(batch.label, targets) File "/home/haria/mxnet/python/mxnet/executor_manager.py", line 83, in _load_general d_src[slice_idx].copyto(d_dst) File "/home/haria/mxnet/python/mxnet/ndarray.py", line 434, in copyto return NDArray._copyto(self, out=other) File "/home/haria/mxnet/python/mxnet/ndarray.py", line 1081, in unary_ndarray_function c_array(ctypes.c_char_p, []))) File "/home/haria/mxnet/python/mxnet/base.py", line 77, in check_call raise MXNetError(py_str(_LIB.MXGetLastError())) mxnet.base.MXNetError: [21:40:42] src/ndarray/ndarray.cc:227: Check failed: from.shape() == to->shape() operands shape mismatch

So my question is how to set proper value to "label" field? label = batch.label label = batch.label[0] label = batch.label[0].T label = [batch.label[0].T] all of them are failed.

Thank you!

tornadomeet commented 8 years ago

Because of the current NDArray do not support slice, so you need to convert it to numpy array to do slice, and then convert it back to NDArray, if you need two label in one list, i think can use your first post code, it's not ugly.
the reason you use like return mx.io.DataBatch(data=batch.data, label=batch.label, pad=batch.pad, index=batch.index) failed, is that your loss layer do not support multi-label, so the shape is not matched.

hariag commented 8 years ago

@tornadomeet thank you very much for your explain. I would like to make clear whether mxnet default implementation loss layer can support multi-label?

tornadomeet commented 8 years ago

it depends what's loss do you use, as i know, the SoftmaxOutput support multi-output(which is one of multi-label), you can check the fcn-xs examples for how to use it.

hariag commented 8 years ago

Hi @tornadomeet

Thank you very much for your help! I would like to know the input data shape of SoftmaxOutput after I specify "multi_output=True"

before multi-output code likes below

    flatten = mx.symbol.Flatten(data=pool, name="flatten1")
    fc1 = mx.symbol.FullyConnected(data=flatten, num_hidden=10, name="fc1")
    sm1 = mx.symbol.SoftmaxOutput(data=fc1, name="softmax1")
    fc2 = mx.symbol.FullyConnected(data=flatten, num_hidden=2, name="fc2")
    sm2 = mx.symbol.SoftmaxOutput(data=fc2, name="softmax2")
    softmax = mx.symbol.Group([sm1, sm2])

    return softmax

after multi-output added,

    flatten = mx.symbol.Flatten(data=pool, name="flatten1")
    fc1 = mx.symbol.FullyConnected(data=flatten, num_hidden=10, name="fc1")
    fc2 = mx.symbol.FullyConnected(data=flatten, num_hidden=2, name="fc2")
    #TODO fc = fc1+fc2 ?
    softmax = mx.symbol.SoftmaxOutput(data=fc, name="softmax", multi_output=True)
    return softmax

Since the num_hidden in fc1 and fc2 are different, I don't know how to set the "data" field for the SoftmaxOutput here.

thank you very much!

tornadomeet commented 8 years ago

@haria yours is more like multi-task application, less like multi-label(Although it has many label for each instance), and softmax with mulit-output is not fit your problem, so you can check the multi-task example, like https://github.com/haria/mxnet-multi-task-example/blob/master/multi-task.ipynb and https://github.com/dmlc/mxnet/tree/e75660f70e0e92ed8f4c48bf1f05eee597b5705f/example/multi-task

hariag commented 8 years ago

Hi @tornadomeet thank you for your explain, actually the first link you provide is created by myself. I am able to train multi-task. the original problems of this issue is to confirm whether there is a better way to slicing NDArray. Now I understand the situation.

Thank you for your patient explain!

Haria