/
githubmirror
/
incubator-mxnet
Обзор
Документация
Войти
/
githubmirror
/
incubator-mxnet
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
python/mxnet/numpy_op_fallback.py
229 строк
9 KB
hankaj
Fix multivariate normal bug (#21105)
29 июл 2022, 14:06
Не верифицирован
29 июл 2022, 14:06
db39bb1
Код
Авторство
О чём код?
# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """Fallback-to-NumPy operator implementation.""" from distutils.version import StrictVersion import functools import ast import numpy as np from . import operator from . import numpy as _mx_np # pylint: disable=reimported from .util import np_array, use_np from .numpy.utils import _STR_2_DTYPE_ from .ndarray.numpy import _internal as _nd_npi from .symbol.numpy import _internal as _sym_npi def register(op_name, imperative=True, symbolic=True): """Register operators that fallback to NumPy in modules ``mxnet.ndarray.numpy._internal`` and ``mxnet.symbol.numpy._internal``.""" def _save_op(mod): if hasattr(mod, op_name): raise ValueError('Duplicate name {} found in module {}'.format(op_name, str(mod))) op = functools.partial(mod.Custom, op_type=op_name) setattr(mod, op_name, op) def _register_helper(prop_cls): with np_array(): prop_cls = operator.register(op_name)(prop_cls) if imperative: _save_op(_nd_npi) if symbolic: _save_op(_sym_npi) return prop_cls return _register_helper @use_np # enforce np shape and array semantics for all the methods in this class class EmptyLike(operator.CustomOp): """Fallback to NumPy empty_like operator.""" def __init__(self, dtype, order, subok, shape): super(EmptyLike, self).__init__() self._dtype = dtype self._order = order self._subok = subok self._shape = shape def forward(self, is_train, req, in_data, out_data, aux): np_version = np.version.version if StrictVersion(np_version) >= StrictVersion('1.6.0'): out = np.empty_like(in_data[0].asnumpy(), dtype=self._dtype, order=self._order, subok=self._subok) else: out = np.empty_like(in_data[0].asnumpy()) self.assign(out_data[0], req[0], _mx_np.array(out, device=in_data[0].device)) def backward(self, req, out_grad, in_data, out_data, in_grad, aux): raise NotImplementedError('Operator empty_like does not support gradient computation') @register('empty_like_fallback') class EmptyLikeProp(operator.CustomOpProp): """Fallback empty_like operator properties.""" def __init__(self, dtype, order, subok, shape): super(EmptyLikeProp, self).__init__(need_top_grad=True) self._dtype = None if dtype == 'None' else dtype self._order = order self._subok = ast.literal_eval(subok) self._shape = ast.literal_eval(shape) def list_arguments(self): return ['prototype'] def infer_shape(self, in_shape): return (in_shape[0],), (in_shape[0],), () def infer_type(self, in_type): if self._dtype is None: return (in_type[0],), (in_type[0],), () else: return (in_type[0],), (_STR_2_DTYPE_[self._dtype],), () def create_operator(self, ctx, in_shapes, in_dtypes): return EmptyLike(self._dtype, self._order, self._subok, self._shape) @use_np # enforce np shape and array semantics for all the methods in this class class Resize(operator.CustomOp): """Fallback to NumPy resize operator.""" def __init__(self, new_shape): super(Resize, self).__init__() self._new_shape = new_shape def forward(self, is_train, req, in_data, out_data, aux): out = np.resize(in_data[0].asnumpy(), self._new_shape) self.assign(out_data[0], req[0], _mx_np.array(out, dtype=out.dtype, device=out_data[0].device)) def backward(self, req, out_grad, in_data, out_data, in_grad, aux): raise NotImplementedError('Operator resize does not support gradient computation') @register('resize_fallback') class ResizeProp(operator.CustomOpProp): """Fallback resize operator properties.""" def __init__(self, new_shape): super(ResizeProp, self).__init__(need_top_grad=True) self._new_shape = ast.literal_eval(new_shape) def list_arguments(self): return ['a'] def infer_shape(self, in_shape): out_shape = (self._new_shape,) if np.isscalar(self._new_shape) else self._new_shape return (in_shape[0],), (out_shape,), () def create_operator(self, ctx, in_shapes, in_dtypes): return Resize(self._new_shape) @use_np class Unravel_index(operator.CustomOp): """Fallback to NumPy Unravel_index operator.""" def __init__(self, shape): super(Unravel_index, self).__init__() self._shape = shape def forward(self, is_train, req, in_data, out_data, aux): out = np.unravel_index(in_data[0].asnumpy(), self._shape) self.assign(out_data[0], req[0], _mx_np.array(out, dtype=out[0].dtype, device=out_data[0].device)) def backward(self, req, out_grad, in_data, out_data, in_grad, aux): raise NotImplementedError('Operator Unravel_index does not support gradient computation') @register('unravel_index_fallback') class Unravel_indexProp(operator.CustomOpProp): """Fallback unravel_index operator properties.""" def __init__(self, shape): super(Unravel_indexProp, self).__init__(need_top_grad=True) self._shape = ast.literal_eval(shape) def list_arguments(self): return ['indices'] def infer_shape(self, in_shape): dim_list = (1,) if np.isscalar(self._shape) else (len(self._shape),) out_shape = dim_list + tuple(in_shape[0]) return (in_shape[0],), (out_shape,), () def create_operator(self, ctx, in_shapes, in_dtypes): return Unravel_index(self._shape) @use_np class MultivariateNormal(operator.CustomOp): """Fallback to the front-end implementation of random.multivariate_normal.""" def __init__(self, size=None): super(MultivariateNormal, self).__init__() self._size = size def forward(self, is_train, req, in_data, out_data, aux): loc = in_data[0] cov = in_data[1] if cov.dtype == np.float16: scale = _mx_np.linalg.cholesky(cov.astype(np.float32)).astype(np.float16) else: scale = _mx_np.linalg.cholesky(cov) #set context noise = _mx_np.random.normal(size=out_data[0].shape, dtype=loc.dtype, device=loc.device) out = loc + _mx_np.einsum('...jk,...k->...j', scale, noise) self.assign(out_data[0], req[0], out) def backward(self, req, out_grad, in_data, out_data, in_grad, aux): raise NotImplementedError('Operator random.multivariate_normal' ' does not support gradient computation') @register('mvn_fallback') class MultivariateNormalProp(operator.CustomOpProp): """Fallback np.random.multivariate_normal operator properties.""" def __init__(self, size=None): super(MultivariateNormalProp, self).__init__(need_top_grad=True) self._size = ast.literal_eval( size) if size is not None else None def list_arguments(self): return ['mean', 'cov'] def infer_shape(self, in_shape): loc_shape = in_shape[0] cov_shape = in_shape[1] if len(loc_shape) < 1: raise ValueError("mean must be at least 1 dimensional") if len(cov_shape) < 2: raise ValueError("cov must be at least 2 dimensional") if cov_shape[-1] != cov_shape[-2]: raise ValueError("the last two dimentions of the parameter cov have to be the same," " whereas the shape of cov is {}".format(cov_shape)) if cov_shape[-1] != loc_shape[-1]: raise ValueError("mean and cov must have same length." "The shape of mean is {} but the shape of cov is {}" .format(loc_shape[-1:], cov_shape[-2:])) # handle shape mismatch here out_shape = np.broadcast(np.empty(loc_shape), np.empty(cov_shape[:-1])).shape if self._size is not None: self._size = (self._size,) if np.isscalar( self._size) else self._size out_shape = self._size + out_shape return in_shape, (out_shape,), () def create_operator(self, ctx, in_shapes, in_dtypes): return MultivariateNormal(self._size)