Esempio n. 1
0
        /// <summary>
        /// Get the total cost from a certain network using a certain computation handler and put the relevant information in the cost registry (total, partial, importances).
        /// </summary>
        /// <param name="network">The network to get the costs from.</param>
        /// <param name="handler">The handler to use.</param>
        /// <param name="costRegistry">The registry to put relevant information in.</param>
        /// <returns>The total cost of the given network (0.0 if none).</returns>
        protected virtual INumber GetTotalCost(INetwork network, IComputationHandler handler, IRegistry costRegistry)
        {
            INumber totalCost = handler.Number(0);

            foreach (ILayerBuffer layerBuffer in network.YieldExternalOutputsLayerBuffers())
            {
                if (layerBuffer.Outputs.ContainsKey(ExternalCostAlias))
                {
                    IRegistry externalCostRegistry = layerBuffer.Outputs[ExternalCostAlias];

                    INumber partialCost       = externalCostRegistry.Get <INumber>("cost");
                    double  partialImportance = externalCostRegistry.Get <double>("importance");

                    costRegistry["partial_" + layerBuffer.Layer.Name] = partialCost.GetValueAs <double>();
                    costRegistry["partial_" + layerBuffer.Layer.Name + "_importance"] = partialImportance;

                    totalCost = handler.Add(totalCost, handler.Multiply(partialCost, partialImportance));
                }
            }

            costRegistry["total"] = totalCost.GetValueAs <double>();

            return(totalCost);
        }
        /// <summary>
        /// Invoke this hook with a certain parameter registry if optional conditional criteria are satisfied.
        /// </summary>
        /// <param name="registry">The registry containing the required values for this hook's execution.</param>
        /// <param name="resolver">A helper resolver for complex registry entries (automatically cached).</param>
        public override void SubInvoke(IRegistry registry, IRegistryResolver resolver)
        {
            // we need copies of network and optimiser as to not affect the current internal state
            INetwork network = (INetwork)resolver.ResolveGetSingle <INetwork>("network.self").DeepCopy();
            BaseGradientOptimiser optimiser    = (BaseGradientOptimiser)resolver.ResolveGetSingle <BaseGradientOptimiser>("optimiser.self").ShallowCopy();
            INDArray            desiredTargets = ParameterRegistry.Get <INDArray>("desired_targets");
            IComputationHandler handler        = new DebugHandler(Operator.Handler);

            long[] inputShape = network.YieldExternalInputsLayerBuffers().First().Parameters.Get <long[]>("shape");

            IDictionary <string, INDArray> block = DataUtils.MakeBlock("targets", desiredTargets);            // desired targets don't change during execution

            double   desiredCost = ParameterRegistry.Get <double>("desired_cost"), currentCost = Double.MaxValue;
            int      maxOptimisationAttempts = ParameterRegistry.Get <int>("max_optimisation_attempts");
            int      maxOptimisationSteps    = ParameterRegistry.Get <int>("max_optimisation_steps");
            int      optimisationSteps       = 0;
            INDArray maximisedInputs         = CreateRandomisedInput(handler, inputShape);

            for (int i = 0; i < maxOptimisationAttempts; i++)
            {
                optimisationSteps = 0;

                do
                {
                    // trace current inputs and run network as normal
                    uint traceTag = handler.BeginTrace();
                    block["inputs"] = handler.Trace(maximisedInputs.Reshape(ArrayUtils.Concatenate(new[] { 1L, 1L }, inputShape)), traceTag);

                    handler.BeginSession();

                    DataUtils.ProvideExternalInputData(network, block);
                    network.Run(handler, trainingPass: false);

                    // fetch current outputs and optimise against them (towards desired targets)
                    INDArray currentTargets = network.YieldExternalOutputsLayerBuffers().First(b => b.ExternalOutputs.Contains("external_default"))
                                              .Outputs["external_default"].Get <INDArray>("activations");
                    INumber squaredDifference = handler.Sum(handler.Pow(handler.Subtract(handler.FlattenTimeAndFeatures(currentTargets), desiredTargets), 2));

                    handler.ComputeDerivativesTo(squaredDifference);

                    handler.EndSession();

                    INDArray gradient = handler.GetDerivative(block["inputs"]);
                    maximisedInputs = handler.ClearTrace(optimiser.Optimise("inputs", block["inputs"], gradient, handler));

                    currentCost = squaredDifference.GetValueAs <double>();

                    if (currentCost <= desiredCost)
                    {
                        goto Validation;
                    }
                } while (++optimisationSteps < maxOptimisationSteps);

                maximisedInputs = CreateRandomisedInput(handler, inputShape);                 // reset input
            }

Validation:
            maximisedInputs.ReshapeSelf(inputShape);

            string sharedResultInput   = ParameterRegistry.Get <string>("shared_result_input_key");
            string sharedResultSuccess = ParameterRegistry.Get <string>("shared_result_success_key");

            if (optimisationSteps >= maxOptimisationSteps)
            {
                _logger.Debug($"Aborted target maximisation for {desiredTargets}, failed after {maxOptimisationSteps} optimisation steps in {maxOptimisationAttempts} attempts (exceeded limit, current cost {currentCost} but desired {desiredCost}).");

                resolver.ResolveSet(sharedResultSuccess, false, addIdentifierIfNotExists: true);
            }
            else
            {
                _logger.Debug($"Successfully finished target optimisation for {desiredTargets} after {optimiser} optimisation steps.");

                resolver.ResolveSet(sharedResultSuccess, true, addIdentifierIfNotExists: true);
                resolver.ResolveSet(sharedResultInput, maximisedInputs, addIdentifierIfNotExists: true);
            }
        }
Esempio n. 3
0
        public void Run(INetwork network, IComputationHandler handler)
        {
            if (network == null)
            {
                throw new ArgumentNullException(nameof(network));
            }
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            if (!_prepared)
            {
                throw new InvalidOperationException($"Cannot run network optimisation on network {network} in optimiser {this} before {nameof(PrepareRun)} is called.");
            }

            ISet <string> filteredIdentifiers = Registry.Get <ISet <string> >("filtered_identifiers");
            IRegistry     costRegistry        = new Registry(Registry, tags: "costs");
            IRegistry     gradientRegistry    = new Registry(Registry, tags: "gradients");
            INumber       cost = GetTotalCost(network, handler, costRegistry);

            Registry["cost_total"]    = cost.GetValueAs <double>();
            Registry["cost_partials"] = costRegistry;
            Registry["gradients"]     = gradientRegistry;

            handler.ComputeDerivativesTo(cost);

            foreach (ILayerBuffer layerBuffer in network.YieldLayerBuffersOrdered())
            {
                string layerIdentifier = layerBuffer.Layer.Name;

                foreach (string trainableParameter in layerBuffer.Layer.TrainableParameters)
                {
                    object parameter           = layerBuffer.Parameters[trainableParameter];
                    string parameterIdentifier = layerIdentifier + "." + trainableParameter;

                    if (filteredIdentifiers.Contains(parameterIdentifier))
                    {
                        continue;
                    }

                    INumber  asNumber = parameter as INumber;
                    INDArray asArray  = parameter as INDArray;

                    if (asNumber == null && asArray == null)
                    {
                        throw new InvalidOperationException($"Cannot optimise non-ndarray and non-number parameter \"{parameter}\" (identifier \"{parameterIdentifier}\"" +
                                                            $" in layer \"{layerBuffer.Layer.Name}\") but it is marked as trainable.");
                    }

                    if (asNumber != null)
                    {
                        // boxing the numbers to ndarrays is easier to work with and the performance difference is completely negligible
                        //  (especially considering that ndarrays are far more common as trainable parameters).
                        //  if you think otherwise, implement your own gradient optimiser and do it your way
                        INDArray convertedNumber   = handler.ClearTrace(handler.AsNDArray(asNumber));
                        INDArray convertedGradient = handler.ClearTrace(handler.AsNDArray(handler.GetDerivative(asNumber)));

                        gradientRegistry[parameterIdentifier] = convertedGradient;

                        layerBuffer.Parameters[trainableParameter] = handler.AsNumber(Optimise(parameterIdentifier, convertedNumber, convertedGradient, handler), 0, 0);
                    }
                    else
                    {
                        INDArray gradient = handler.ClearTrace(handler.GetDerivative(asArray));

                        gradientRegistry[parameterIdentifier] = gradient;

                        handler.FreeLimbo(asArray);

                        INDArray newParameter = Optimise(parameterIdentifier, handler.ClearTrace(asArray), gradient, handler);

                        handler.MarkLimbo(newParameter);

                        layerBuffer.Parameters[trainableParameter] = newParameter;
                    }

                    layerBuffer.Parameters[trainableParameter] = handler.ClearTrace(layerBuffer.Parameters.Get <ITraceable>(trainableParameter));
                }

                // outputs might have a trace as well, clear everything
                _InternalClearAllTraces(layerBuffer.Inputs, handler);
                _InternalClearAllTraces(layerBuffer.Outputs, handler);
            }
        }