Beispiel #1
0
    /// <summary>
    /// Activate the network. Activation reads input signals from InputSignalArray and writes output signals
    /// to OutputSignalArray.
    /// </summary>
    public void Activate()
    {
        ReadOnlySpan <int>    srcIds      = _connIds.GetSourceIdSpan();
        ReadOnlySpan <int>    tgtIds      = _connIds.GetTargetIdSpan();
        ReadOnlySpan <double> weights     = _weightArr.AsSpan();
        Span <double>         activations = _activationArr.AsSpan();

        // Reset hidden and output node activation levels, ready for next activation.
        // Note. this reset is performed here instead of after the below loop because this resets the output
        // node values, which are the outputs of the network as a whole following activation; hence
        // they need to be remain unchanged until they have been read by the caller of Activate().
        activations.Slice(_inputCount).Clear();

        // Process all layers in turn.
        int conIdx  = 0;
        int nodeIdx = _inputCount;

        // Loop through network layers.
        for (int layerIdx = 0; layerIdx < _layerInfoArr.Length - 1; layerIdx++)
        {
            LayerInfo layerInfo = _layerInfoArr[layerIdx];

            // Push signals through the current layer's connections to the target nodes (that are all in 'downstream' layers).
            for (; conIdx < layerInfo.EndConnectionIdx; conIdx++)
            {
                // Get the connection source signal, multiply it by the connection weight, add the result
                // to the target node's current pre-activation level, and store the result.
                activations[tgtIds[conIdx]] =
                    Math.FusedMultiplyAdd(
                        activations[srcIds[conIdx]],
                        weights[conIdx],
                        activations[tgtIds[conIdx]]);
            }

            // Activate the next layer's nodes. This is possible because we know that all connections that
            // target these nodes have been processed, either during processing on the current layer's
            // connections, or earlier layers. This means that the final output value/signal (i.e post
            // activation function output) is available for all connections and nodes in the lower/downstream
            // layers.
            //
            // Pass the pre-activation levels through the activation function.
            // Note. The resulting post-activation levels are stored in _activationArr.
            layerInfo = _layerInfoArr[layerIdx + 1];
            _activationFn(
                ref activations[nodeIdx],
                layerInfo.EndNodeIdx - nodeIdx);

            // Update nodeIdx to point at first node in the next layer.
            nodeIdx = layerInfo.EndNodeIdx;
        }

        // Copy the output signals from _activationArr into _outputArr.
        // These signals are scattered through _activationArr, and here we bring them together into a
        // contiguous segment of memory that is indexable by output index.
        for (int i = 0; i < _outputNodeIdxArr.Length; i++)
        {
            _outputArr[i] = _activationArr[_outputNodeIdxArr[i]];
        }
    }
Beispiel #2
0
    /// <summary>
    /// Activate the network. Activation reads input signals from InputSignalArray and writes output signals
    /// to OutputSignalArray.
    /// </summary>
    public void Activate()
    {
        ReadOnlySpan <int>    srcIds      = _connIds.GetSourceIdSpan();
        ReadOnlySpan <int>    tgtIds      = _connIds.GetTargetIdSpan();
        ReadOnlySpan <double> weights     = _weightArr.AsSpan();
        Span <double>         activations = _activationMem.Span;
        Span <double>         outputs     = _outputMem.Span;

        ref int    srcIdsRef      = ref MemoryMarshal.GetReference(srcIds);
Beispiel #3
0
    /// <summary>
    /// Activate the network for a fixed number of iterations defined by the 'maxIterations' parameter
    /// at construction time. Activation reads input signals from InputSignalArray and writes output signals
    /// to OutputSignalArray.
    /// </summary>
    public void Activate()
    {
        ReadOnlySpan <int>    srcIds          = _connIds.GetSourceIdSpan();
        ReadOnlySpan <int>    tgtIds          = _connIds.GetTargetIdSpan();
        ReadOnlySpan <double> weights         = _weightArr.AsSpan();
        Span <double>         preActivations  = _preActivationMem.Span;
        Span <double>         postActivations = _postActivationMem.Span;

        // Note. Here we skip over the activations corresponding to the input neurons, as these have no
        // incoming connections, and therefore have fixed post-activation values and are never activated.
        int           nonInputCount            = _totalNodeCount - _inputCount;
        Span <double> preActivationsNonInputs  = preActivations.Slice(_inputCount);
        Span <double> postActivationsNonInputs = postActivations.Slice(_inputCount);

        ref int    srcIdsRef                   = ref MemoryMarshal.GetReference(srcIds);
    private static ConnectionIds CopyAndMapIds(
        Span <DirectedConnection> connSpan,
        INodeIdMap nodeIdMap)
    {
        int count   = connSpan.Length;
        var connIds = new ConnectionIds(count);
        var srcIds  = connIds.GetSourceIdSpan();
        var tgtIds  = connIds.GetTargetIdSpan();

        for (int i = 0; i < count; i++)
        {
            srcIds[i] = nodeIdMap.Map(connSpan[i].SourceId);
            tgtIds[i] = nodeIdMap.Map(connSpan[i].TargetId);
        }

        return(connIds);
    }
Beispiel #5
0
    private static void CopyAndMapIds(
        DirectedConnection[] connArr,
        INodeIdMap nodeIdMap,
        out ConnectionIds connIds)
    {
        int count = connArr.Length;

        connIds = new ConnectionIds(count);
        var srcIds = connIds.GetSourceIdSpan();
        var tgtIds = connIds.GetTargetIdSpan();

        for (int i = 0; i < count; i++)
        {
            srcIds[i] = nodeIdMap.Map(connArr[i].SourceId);
            tgtIds[i] = nodeIdMap.Map(connArr[i].TargetId);
        }
    }
Beispiel #6
0
    /// <summary>
    /// Split each IWeightedDirectedConnection in a list into an array of DirectedConnections(s), and an array of weights.
    /// Map the node IDs to indexes as we go.
    /// </summary>
    private static void CopyAndMapIds(
        Span <WeightedDirectedConnection <T> > connSpan,
        INodeIdMap nodeIdMap,
        out ConnectionIds connIds,
        out T[] weightArr)
    {
        int count = connSpan.Length;

        connIds = new ConnectionIds(count);
        var srcIds = connIds.GetSourceIdSpan();
        var tgtIds = connIds.GetTargetIdSpan();

        weightArr = new T[count];

        for (int i = 0; i < count; i++)
        {
            srcIds[i]    = nodeIdMap.Map(connSpan[i].SourceId);
            tgtIds[i]    = nodeIdMap.Map(connSpan[i].TargetId);
            weightArr[i] = connSpan[i].Weight;
        }
    }
Beispiel #7
0
    /// <summary>
    /// Activate the network for a fixed number of iterations defined by the 'maxIterations' parameter
    /// at construction time. Activation reads input signals from InputSignalArray and writes output signals
    /// to OutputSignalArray.
    /// </summary>
    public void Activate()
    {
        ReadOnlySpan <int>    srcIds          = _connIds.GetSourceIdSpan();
        ReadOnlySpan <int>    tgtIds          = _connIds.GetTargetIdSpan();
        ReadOnlySpan <double> weights         = _weightArr.AsSpan();
        Span <double>         preActivations  = _preActivationArr.AsSpan();
        Span <double>         postActivations = _postActivationArr.AsSpan();

        // Note. Here we skip over the activations corresponding to the input neurons, as these have no
        // incoming connections, and therefore have fixed post-activation values and are never activated.
        int           nonInputCount            = _preActivationArr.Length - _inputCount;
        Span <double> preActivationsNonInputs  = preActivations.Slice(_inputCount);
        Span <double> postActivationsNonInputs = postActivations.Slice(_inputCount);

        // Activate the network for a fixed number of timesteps.
        for (int i = 0; i < _cyclesPerActivation; i++)
        {
            // Loop connections. Get each connection's input signal, apply the weight and add the result to
            // the pre-activation signal of the target neuron.
            for (int j = 0; j < srcIds.Length; j++)
            {
                preActivations[tgtIds[j]] =
                    Math.FusedMultiplyAdd(
                        postActivations[srcIds[j]],
                        weights[j],
                        preActivations[tgtIds[j]]);
            }

            // Pass the pre-activation levels through the activation function, storing the results in the
            // post-activation span/array.
            _activationFn(
                ref preActivationsNonInputs[0],
                ref postActivationsNonInputs[0],
                nonInputCount);

            // Reset the elements of _preActivationArray that represent the output and hidden nodes.
            preActivationsNonInputs.Clear();
        }
    }