def _forward(self, arguments, outputs, device=None, outputs_to_retain=None): ''' Computes the values of speficied variables in ``outputs``, using values provided in ``arguments`` that correspond to each input `Variable` of the function whose ``is_input`` is `True`. This function calls :func:`forward`, which is to be implemented by the user. Args: arguments (tuple): Value objects of the Function's input outputs (iterable): outputs to fetch values for. device (:class:`~cntk.device.DeviceDescriptor`, default `None`): the device descriptor that contains the type and id of the device on which the computation is. If `None`, the default device is used. Returns: A BackPropState instance, which is used by :func:`backward`. ''' if self.as_numpy: arguments = tuple( variable_value_to_seq(v, self.inputs[i]) for i, v in enumerate(arguments)) map_if_possible(outputs) map_if_possible(outputs_to_retain) args = arguments if len(arguments) > 1 else arguments[0] if len(outputs) <= 1: state, result = self.forward(args, device, outputs_to_retain) for k in outputs: outputs[k] = result else: state = self.forward(args, outputs, device, outputs_to_retain) if state is None: state = self._none_state elif not isinstance(state, cntk_py.BackPropState): state = cntk_py.UserBackPropState(self, device, state) if self.as_numpy: for k, v in outputs.items(): if v is None: raise ValueError('not all outputs have been provided') # FIXME: seq_starts outputs[k] = sanitize_batch(k, v, None, device) return state, outputs
def __init__(self, inputs, as_numpy=True, name=''): super(UserFunction, self).__init__(inputs, name) self.as_numpy = as_numpy # Since the state will frequently not be used, we cache the None-state # to speed up. self._none_state = cntk_py.UserBackPropState( self, DeviceDescriptor.cpu_device(), None) # Memory management for user defined functions has to be controlled by # the C++ side. For more information: # http://www.swig.org/Doc3.0/Python.html#Python_nn35 self.__disown__()