/// <summary> /// Runs through a single convolution layer. /// </summary> /// <param name="layerInfo">The layer info used for this layer.</param> /// <param name="inputImages"> /// A matrix of all the images that will be convolved. Each row is an image. /// </param> /// <returns>A matrix of all the resulting images. Each row is an image.</returns> internal Matrix <double> Convolve(ConvolutionalLayerInformation layerInfo, Matrix <double> inputImages) { // Construct out return matrix that will include all layers of our images. Matrix <double> _outputImages = null; foreach (Tuple <int, Vector <double> > _imageDimensionAndIndex in inputImages.EnumerateRowsIndexed()) { // Create the matrix so we can do all of the convolutions at once. Matrix <double> _preConvolutionMap = this.CreateMaskingMap(layerInfo.KernelSize, layerInfo.Stride, _imageDimensionAndIndex.Item2); Matrix <double> _filtersForThisDimension = CreateMatrix.Dense <double>(layerInfo.FlattenedFilters.Count, layerInfo.FlattenedFilters[0].ColumnCount); foreach (Matrix <double> _filter in layerInfo.FlattenedFilters) { _filtersForThisDimension.InsertRow(_imageDimensionAndIndex.Item1, _filter.Row(_imageDimensionAndIndex.Item1)); } // Create the result image matrix if it's not created yet if (_outputImages == null) { _outputImages = CreateMatrix.Dense <double>(layerInfo.FilterCount, _preConvolutionMap.ColumnCount, 0.0); } // Store off the result of our filters multiplied by our map. This ends up being every filter passing over // the entire image, and returning a dimentions for each kernel in the layer. We sum all the dimensional results in one dimension. _outputImages = _outputImages.Add(_filtersForThisDimension.Multiply(_preConvolutionMap)); } // Return all the resulting dimensions of the images after convolution return(_outputImages); }
/// <summary> /// Runs through the network and makes a prediction. /// </summary> /// <param name="input">The input image to run the prediction on.</param> /// <returns>The values from the final layer. The largest value is the networks prediction.</returns> public double[] FeedForward(double[] input) { Matrix <double> _currentImages = CreateMatrix.DenseOfRowVectors(CreateVector.DenseOfArray <double>(input)); foreach (ILayerInformation _layerInformation in this.LayerInformation) { switch (_layerInformation.LayerType) { case (LayerType.Convolutional): ConvolutionalLayerInformation _convInfo = _layerInformation as ConvolutionalLayerInformation; _currentImages = this.Convolve(_convInfo, _currentImages); break; case (LayerType.Pooling): PoolingLayerInformation _poolInfo = _layerInformation as PoolingLayerInformation; _currentImages = this.Pool(_poolInfo, _currentImages); break; case (LayerType.NonLinear): NonLinearLayerInformation _nonLinearInfo = _layerInformation as NonLinearLayerInformation; _currentImages = this.NonLinear(_nonLinearInfo, _currentImages); break; } } double[] _fullyConnectedInput = CreateVector.DenseOfEnumerable <double>(_currentImages.EnumerateRows().SelectMany(a => a)).ToArray(); return(this.FullyConnectedNetwork.FeedForward(_currentImages.Enumerate().ToArray())); }
/// <summary> /// Adds a convolutional layer to the network. /// </summary> /// <param name="filterCount">The number of filters this layer should use.</param> /// <param name="kernelSize"> /// A side length of each kernel (all kernels are square, so if you want a 5x5 kernel this /// parameter should be 5) /// </param> /// <param name="stride">The stride used for the filters.</param> public void AddConvolutionalLayer(int filterCount, int kernelSize, int stride) { ConvolutionalLayerInformation _previousConvolutionLayer = this.LayerInformation.LastOrDefault(p => p.LayerType == LayerType.Convolutional) as ConvolutionalLayerInformation; int _previousDimensions = _previousConvolutionLayer == null ? this.InputDimensions : _previousConvolutionLayer.FilterCount; List <Matrix <double> > _flattenedFilters = new List <Matrix <double> >(filterCount); for (int i = 0; i < filterCount; i++) { _flattenedFilters.Add(Matrix <double> .Build.Random(_previousDimensions, (int)Math.Pow(kernelSize, 2), new Normal(0.0, 1.0))); } this.LayerInformation.Add(new ConvolutionalLayerInformation { FilterCount = filterCount, Stride = stride, KernelSize = kernelSize, FlattenedFilters = _flattenedFilters }); }