[MXNET-349] Histogram Operator#10931
Conversation
a1bf838 to
49a9ae4
Compare
| return _internal._histogram(data=a, bins=bins) | ||
| elif isinstance(bins, int): | ||
| if range_ is None: | ||
| range_ = (float(a.min().asnumpy()[0]), float(a.max().asnumpy()[0])) |
There was a problem hiding this comment.
don't do this in the frontend.
| elif isinstance(bins, int): | ||
| if range_ is None: | ||
| range_ = (float(a.min().asnumpy()[0]), float(a.max().asnumpy()[0])) | ||
| return _internal._histogram(data=a, bins=array([]), bin_cnt=bins, range=range_) |
There was a problem hiding this comment.
why make an invalid array/
There was a problem hiding this comment.
bins is not used in this version of _histogram, but it's one of the inputs so I need a mock array.
There was a problem hiding this comment.
You can define a mode variable in HistogramParam for distinguishing the cases of 1 and 2 ndarray inputs. When register the op, use set_num_inputs([](const NodeAttrs& attrs) to define the number of inputs based upon the mode.
See example:
https://github.com/apache/incubator-mxnet/blob/master/src/operator/nn/convolution.cc#L471
| .add_argument("bins", "NDArray-or-Symbol", "Input ndarray") | ||
| .add_arguments(HistogramParam::__FIELDS__()); | ||
|
|
||
| NNVM_REGISTER_OP(_backward_histogram) |
There was a problem hiding this comment.
Historgram op is not differentiable. Don't register backward op.
There was a problem hiding this comment.
Sure, will get rid of it.
7c44e7f to
b17585a
Compare
| return NDArray(handle=_new_alloc_handle(shape, ctx, False, dtype)) | ||
|
|
||
|
|
||
| def histogram(a, bins=10, range_=None): |
There was a problem hiding this comment.
Why underscore suffix for range?
There was a problem hiding this comment.
pylint complains if we override the keyword range
There was a problem hiding this comment.
@piiswrong numpy.histogram has parameter range. Should we disable pylint check here to make mx.nd.histogram parameter naming consistent with numpy?
| """ | ||
|
|
||
| # pylint: disable= no-member, protected-access | ||
| if isinstance(bins, NDArray): |
There was a problem hiding this comment.
Need to check whether bins is a 1d array?
There was a problem hiding this comment.
That's checked inside the op
| # pylint: disable= no-member, protected-access | ||
| if isinstance(bins, NDArray): | ||
| return _internal._histogram(data=a, bins=bins) | ||
| elif isinstance(bins, int): |
There was a problem hiding this comment.
Replace int with integer_types.
| def f(x, bins=10, range=None): | ||
| return np.histogram(x, bins, range=range) | ||
|
|
||
| shape = (3, 3, 3) |
There was a problem hiding this comment.
Randomize shape and test ndarrays from 1D-5D.
| x = rand_ndarray(shape, stype='default') | ||
| mx_bins = mx.nd.array([-1.0, 0.5, 2.0, 4.5, 50.0]) | ||
| np_bins = mx_bins.asnumpy() | ||
| bin_cnt = 5 |
There was a problem hiding this comment.
Should test more settings of bin_cnt.
| elif isinstance(bins, int): | ||
| if range_ is None: | ||
| range_ = (float(a.min().asnumpy()[0]), float(a.max().asnumpy()[0])) | ||
| return _internal._histogram(data=a, bins=array([]), bin_cnt=bins, range=range_) |
There was a problem hiding this comment.
You can define a mode variable in HistogramParam for distinguishing the cases of 1 and 2 ndarray inputs. When register the op, use set_num_inputs([](const NodeAttrs& attrs) to define the number of inputs based upon the mode.
See example:
https://github.com/apache/incubator-mxnet/blob/master/src/operator/nn/convolution.cc#L471
| SHAPE_ASSIGN_CHECK(*out_attrs, 1, in_attrs->at(1)); | ||
| } | ||
|
|
||
| return out_attrs->at(0).ndim() == 1U && out_attrs->at(0).Size() != 0U && |
There was a problem hiding this comment.
Call shape_is_none to simplify the code. ndim == 1 should have been guaranteed before this line.
|
|
||
| TYPE_ASSIGN_CHECK(*out_attrs, 0, mshadow::kInt64); | ||
| TYPE_ASSIGN_CHECK(*out_attrs, 1, in_attrs->at(0)); | ||
| return out_attrs->at(0) != -1 && out_attrs->at(1) != -1; |
There was a problem hiding this comment.
Call !type_is_none(out_attrs->at(i))
26a9d38 to
c2a9f1d
Compare
240eecc to
55d6ccb
Compare
|
@reminisce @piiswrong @anirudh2290 @rahul003 Unit tests added, this is ready, please give a review if you have time. Thanks! |
| res, bin_bounds = np.histogram(a.asnumpy(), bins=bins) | ||
| return array(res), array(bin_bounds) | ||
| return _internal._histogram(data=a, bin_cnt=bins, range=range) | ||
| return None |
There was a problem hiding this comment.
why return None? Shouldn't this cause an error?
There was a problem hiding this comment.
Do you mean that I should throw an exception?
There was a problem hiding this comment.
Added an exception for the illegal input case.
39fe74e to
c53e477
Compare
| .set_attr<nnvm::FInferShape>("FInferShape", HistogramOpShape) | ||
| .set_attr<nnvm::FInferType>("FInferType", HistogramOpType) | ||
| .set_attr<FCompute>("FCompute<cpu>", HistogramOpForward<cpu>) | ||
| .set_attr<nnvm::FInplaceOption>("FInplaceOption", |
There was a problem hiding this comment.
No need to register this if it's empty.
| } | ||
| } | ||
|
|
||
| template<typename cpu> |
There was a problem hiding this comment.
Should this be a template specialization? Same for other places.
template<>
void HistogramForwardImpl<cpu>()| } | ||
|
|
||
| template<> | ||
| void HistogramForwardImpl<cpu>(const OpContext& ctx, |
There was a problem hiding this comment.
Why change this back to using OpContext? If using Stream for dispatching, you can get rid of the templates.
There was a problem hiding this comment.
I'm not using OpContext, I'm just getting rid of the stream argument here.
8689ebd to
ee38e0c
Compare
|
@piiswrong Should be ready for merge, please take a look when you have time, thanks! |
|
So symbolic is not supported? |
|
@piiswrong There's no backward pass for this function, I wonder if symbolic is necessary in this case? |
|
@piiswrong symbol is added for histogram. |
8bc8e18 to
4595fd9
Compare
* implementation of histogram operator * address code reviews and code re-design * add exception for invalid inputs * address code reviews * add symbol and symbolic forward check for histogram
Description
This PR implements histogram operator.
Checklist
Essentials
Changes
Comments
The user-facing interface resembles basic behaviors of Numpy's histogram: https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.histogram.html.
Three versions are supported:
histogram(x, bins=7) - divided into 7 equal bins in the range of [x.min, x.max]
histogram(x, bins=7, range=(a,b)) - divided into 7 equal bins in the range of [a, b], anything outside the range is ignored
histogram(x, bins=NDArray) - bin bounds are specified by the bins NDArray.