public FloatWithFloat3VectorConvolveJob(Convolution2D <float> convolution,
                                         Image <float3> input, Image <float3> output)
 {
     Convolution = convolution;
     Input       = input;
     Output      = output;
 }
Exemple #2
0
        private void btnBrowseImage_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                OpenFileDialog dialog = new OpenFileDialog();
                dialog.Multiselect = false;
                dialog.Title       = "Please select an image";
                bool?result = dialog.ShowDialog();
                if (result == null || !result.Value)
                {
                    return;
                }

                BitmapSource bitmap = new BitmapImage(new Uri(dialog.FileName));

                int limit;
                if (chkLimitImageSize.IsChecked.Value && int.TryParse(txtSizeLimit.Text, out limit))
                {
                    bitmap = UtilityWPF.ResizeImage(bitmap, limit);       // this will only resize if it's too big
                }

                originalImage.Source = bitmap;
                _origImageGrays      = null;
            }
            catch (NotSupportedException)
            {
                MessageBox.Show("Not an image file", this.Title, MessageBoxButton.OK, MessageBoxImage.Warning);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
Exemple #3
0
 public ByteWithShortConvolveJob(Convolution2D <short> convolution,
                                 Image <byte> input, Image <short> output)
 {
     Convolution = convolution;
     Input       = input;
     Output      = output;
 }
Exemple #4
0
 public FloatWithShortConvolveJob(Convolution2D <short> convolution,
                                  Image <float> input, Image <float> output)
 {
     Convolution = convolution;
     Input       = input;
     Output      = output;
 }
Exemple #5
0
        private void RefreshStatsPanel()
        {
            if (_selectedKernelIndex < 0)
            {
                lblSelectedSize.Content      = "";
                lblSelectedReduction.Content = "";
            }

            VectorInt totalReduce = new VectorInt();

            for (int cntr = 0; cntr < _kernels.Count; cntr++)
            {
                VectorInt childReduce = _kernels[cntr].GetReduction();

                totalReduce += childReduce;

                if (cntr == _selectedKernelIndex)
                {
                    if (_kernels[cntr] is Convolution2D)
                    {
                        Convolution2D childSingle = (Convolution2D)_kernels[cntr];
                        lblSelectedSize.Content = string.Format("{0}x{1}", childSingle.Width, childSingle.Height);
                    }
                    else
                    {
                        lblSelectedSize.Content = "";
                    }

                    lblSelectedReduction.Content = string.Format("{0}x{1}", childReduce.X, childReduce.Y);
                }
            }

            lblTotalReduction.Content = string.Format("{0}x{1}", totalReduce.X, totalReduce.Y);
        }
Exemple #6
0
        private void trkIterations_ValueChanged(object sender, EventArgs e)
        {
            try
            {
                if (!_initialized || _isProgramaticallyChanging || _selectedKernelIndex < 0)
                {
                    return;
                }

                Convolution2D selected = _kernels[_selectedKernelIndex] as Convolution2D;
                if (selected == null)
                {
                    return;
                }

                Convolution2D changed = new Convolution2D(selected.Values, selected.Width, selected.Height, selected.IsNegPos, selected.Gain, Convert.ToInt32(trkIterations.Value), selected.ExpandBorder);

                _kernels[_selectedKernelIndex] = changed;

                RefreshStatsPanel();        // iterations affects the stats
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
Exemple #7
0
        private static Convolution2D Convolute(Convolution2D conv, ToVectorInstructions instr)
        {
            Convolution2D retVal = conv;

            if (retVal.Width != retVal.Height)
            {
                int max = Math.Max(retVal.Width, retVal.Height);
                retVal = Convolutions.ExtendBorders(retVal, max, max);      // make it square
            }

            if (instr.ShouldNormalize)
            {
                retVal = Convolutions.Normalize(retVal);
            }

            if (instr.Convolution != null)
            {
                retVal = Convolutions.Convolute(retVal, instr.Convolution);
            }

            retVal = Convolutions.MaxPool(retVal, instr.ToSize, instr.ToSize);
            retVal = Convolutions.Abs(retVal);

            return(retVal);
        }
Exemple #8
0
        public static Model ConvolutionalNeuralNetworkModel()
        {
            var images = Variable <float>();
            var labels = Variable <float>();

            ILayer <float> net = new Reshape <float>(images, PartialShape.Create(-1, 1, 28, 28));

            net = new Convolution2D <float>(net.Output, 5, 5, 16);
            net = new ActivationReLU <float>(net.Output);
            net = new Pooling2D <float>(net.Output, PoolingMode.MAX, 2, 2, 2, 2);

            net = new Convolution2D <float>(net.Output, 5, 5, 32);
            net = new ActivationTanh <float>(net.Output);
            net = new Pooling2D <float>(net.Output, PoolingMode.MAX, 2, 2, 2, 2);

            net = new Reshape <float>(net.Output, PartialShape.Create(-1, net.Output.Shape.Skip(1).Aggregate(ScalarOps.Mul)));
            net = new FullyConnected <float>(net.Output, 50);
            net = new ActivationTanh <float>(net.Output);
            net = new FullyConnected <float>(net.Output, 10);

            return(new Model {
                Loss = new SoftmaxCrossEntropy <float>(net.Output, labels),
                Images = images,
                Labels = labels
            });
        }
Exemple #9
0
        private static double[] GetTrainingImage(FeatureRecognizer_Image image, ConvolutionBase2D kernel)
        {
            // Enlarge the initial image by the kernel's reduction so that after convolution, it is the desired size
            VectorInt reduction = kernel.GetReduction();

            if (reduction.X != reduction.Y)
            {
                throw new ApplicationException(string.Format("Kernel should be square: {0}x{1}", reduction.X, reduction.Y));
            }

            BitmapSource bitmap = new BitmapImage(new Uri(image.Filename));

            bitmap = UtilityWPF.ResizeImage(bitmap, IMAGESIZE + reduction.X, true);

            Convolution2D retVal = UtilityWPF.ConvertToConvolution(bitmap, 1d);

            if (retVal.Width != retVal.Height)
            {
                retVal = Convolutions.ExtendBorders(retVal, IMAGESIZE + reduction.X, IMAGESIZE + reduction.X);        //NOTE: width or height is already the desired size, this will just enlarge the other to make it square
            }

            retVal = Convolutions.Convolute(retVal, kernel);
            retVal = Convolutions.Abs(retVal);

            // It looks better when it's black on white
            double[] inverted = retVal.Values.
                                Select(o => 1d - o).
                                ToArray();

            return(inverted);
        }
Exemple #10
0
        public Convolution2d3x3Node()
        {
            title = "3x3 2D Convolution";
            SetSize(new Vector2(224, 132));

            m_Convolution = new Convolution2D <TKernel>(new Kernel2D <TKernel>(3, 3));

            input           = VisionPort.Create <Edge, Image <TImage> >(Orientation.Horizontal, Direction.Input, Port.Capacity.Single);
            input.onUpdate += OnInputUpdate;

            input.portName       = string.Format("Image<{0}>", typeof(TImage).Name);
            input.style.fontSize = 9;

            inputContainer.Add(input);
            inputContainer.style.width = this.style.width / 2;

            output = VisionPort.Create <Edge, Image <TImage> >(Orientation.Horizontal, Direction.Output, Port.Capacity.Multi);

            output.portName       = string.Format("Image<{0}>", typeof(TImage).Name);
            output.style.fontSize = 9;

            outputContainer.Add(output);
            outputContainer.style.width = this.style.width / 2;

            SetupInputFields();
            contentContainer.Add(extensionContainer);
        }
Exemple #11
0
        public void ConvolveWithSameZeroPad <T>(Image <byte> input, Convolution2D <T> convolution,
                                                Image <byte> expected)
            where T : struct
        {
            var paddedInput = Pad.ConvolutionInput(input, convolution);

            expected.Buffer.AssertDeepEqual(paddedInput.Buffer);
        }
Exemple #12
0
        public void GetSamePadCases <T>(Image <byte> input, Convolution2D <T> convolution, Padding expected)
            where T : struct
        {
            var output = Pad.GetSamePad(input, convolution);

            Debug.Log(output.ToString());
            Assert.IsTrue(expected.Equals(output));
        }
Exemple #13
0
        private static SOMItem GetSOMItem_2D_Gray(VectorND item, ToVectorInstructions instr)
        {
            Convolution2D conv = new Convolution2D(item.VectorArray, instr.FromSizes[0], instr.FromSizes[1], false);

            conv = Convolute(conv, instr);

            return(new SOMItem(item, conv.Values.ToVectorND()));
        }
Exemple #14
0
        public void ConvolutionWithIdentityKernel_OutputEqualsInput_1x1()
        {
            var kernel      = new Kernel2D <short>(Kernels.Short.Identity1x1);
            var convolution = new Convolution2D <short>(kernel, 1, 0);

            convolution.Convolve(m_InputImage, m_IntermediateImage);
            m_InputImage.Buffer.AssertDeepEqual(m_IntermediateImage.Buffer);
            convolution.Dispose();
        }
Exemple #15
0
        public void ConvolutionWithIdentityKernel_OutputEqualsInput_3x3()
        {
            var kernel      = new Kernel2D <short>(Kernels.Short.Identity3x3);
            var convolution = new Convolution2D <short>(kernel, 1, 1);

            convolution.Convolve(m_InputImage, m_IntermediateImage);
            // TODO - iterate through, check padding ?
            convolution.Dispose();
        }
Exemple #16
0
        private void ApplyFilter(ConvolutionBase2D kernel)
        {
            // Convert the original image to grayscale
            Convolution2D image = GetOriginalImageGrays();

            if (image == null)
            {
                // The original image is empty
                return;
            }

            Convolution2D filtered = null;

            if (kernel is Convolution2D)
            {
                #region Single

                Convolution2D kernelSingle = (Convolution2D)kernel;

                // This window builds kernels without gain or iterations, so make a clone with those tacked on
                Convolution2D kernelFinal = new Convolution2D(
                    kernelSingle.Values,
                    kernelSingle.Width,
                    kernelSingle.Height,
                    kernelSingle.IsNegPos,
                    trkGain.Value,
                    Convert.ToInt32(trkIterations.Value),
                    chkExpandBorder.IsChecked.Value);

                filtered = Convolutions.Convolute(image, kernelFinal);

                if (chkSubtract.IsChecked.Value)
                {
                    filtered = Convolutions.Subtract(image, filtered);
                }

                #endregion
            }
            else if (kernel is ConvolutionSet2D)
            {
                #region Set

                ConvolutionSet2D kernelSet = (ConvolutionSet2D)kernel;

                filtered = Convolutions.Convolute(image, kernelSet);

                #endregion
            }
            else
            {
                throw new ArgumentException("Unknown type of kernel: " + kernel.GetType().ToString());
            }

            // Show Filtered
            modifiedImage.Source = Convolutions.GetBitmap(filtered, (ConvolutionResultNegPosColoring)cboEdgeColors.SelectedValue);
        }
Exemple #17
0
 private void Painter_SaveRequested(object sender, Convolution2D e)
 {
     try
     {
         AddKernel(e);
     }
     catch (Exception ex)
     {
         MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
     }
 }
Exemple #18
0
        public static void Run()
        {
            sw = new Stopwatch();

            Console.WriteLine("Generating Test Data...");
            NdArray input      = new NdArray(BenchDataMaker.GetRealArray(INPUT_SIZE));
            NdArray inputImage = new NdArray(BenchDataMaker.GetRealArray(3 * 256 * 256 * 5), new[] { 3, 256, 256 }, 5);

            Console.WriteLine("Generated Test Data");

            Console.WriteLine("Init Linear");
            Linear linear = new Linear(INPUT_SIZE, OUTPUT_SIZE);

            Console.WriteLine("Init Tanh");
            Tanh tanh = new Tanh();

            Console.WriteLine("Init Sigmoid");
            Sigmoid sigmoid = new Sigmoid();

            Console.WriteLine("Init ReLU");
            ReLU relu = new ReLU();

            Console.WriteLine("Init LeakyReLU");
            LeakyReLU leakyRelu = new LeakyReLU();

            Console.WriteLine("Init MaxPooling");
            MaxPooling maxPooling = new MaxPooling(2);

            Console.WriteLine("Init Convolution2D");
            Convolution2D conv2d = new Convolution2D(3, 32, 3);

            Console.WriteLine("Init Deconvolution2D");
            Deconvolution2D deconv2d = new Deconvolution2D(32, 3, 3);

            Dropout dropout = new Dropout();

            TestLayer(linear, input);
            Console.WriteLine("aaaaaaaaaaaa");
            Console.ReadLine();

            TestLayer(tanh, input);
            TestLayer(sigmoid, input);
            TestLayer(relu, input);
            TestLayer(leakyRelu, input);

            TestLayer(maxPooling, inputImage);
            TestLayer(conv2d, inputImage);
            TestLayer(deconv2d, inputImage);

            TestLayer(dropout, input);
        }
Exemple #19
0
        private static SOMItem GetSOMItem_2D_Color(VectorND item, ToVectorInstructions instr)
        {
            int width  = instr.FromSizes[0];
            int height = instr.FromSizes[1];

            #region build arrays

            double[] r = new double[width * height];
            double[] g = new double[width * height];
            double[] b = new double[width * height];

            //double scale = 1d / 255d;
            double scale = 1d;

            for (int y = 0; y < height; y++)
            {
                int yOffsetDest   = y * width;          // offset into the return array
                int yOffsetSource = y * width * 3;

                for (int x = 0; x < width; x++)
                {
                    int xOffsetSource = x * 3;

                    r[yOffsetDest + x] = item[yOffsetSource + xOffsetSource + 0] * scale;
                    g[yOffsetDest + x] = item[yOffsetSource + xOffsetSource + 1] * scale;
                    b[yOffsetDest + x] = item[yOffsetSource + xOffsetSource + 2] * scale;
                }
            }

            #endregion

            Convolution2D convR = Convolute(new Convolution2D(r, width, height, false), instr);
            Convolution2D convG = Convolute(new Convolution2D(g, width, height, false), instr);
            Convolution2D convB = Convolute(new Convolution2D(b, width, height, false), instr);

            #region merge arrays

            double[] merged = new double[convR.Values.Length * 3];

            for (int cntr = 0; cntr < convR.Values.Length; cntr++)
            {
                int index = cntr * 3;
                merged[index + 0] = convR.Values[cntr];
                merged[index + 1] = convG.Values[cntr];
                merged[index + 2] = convB.Values[cntr];
            }

            #endregion

            return(new SOMItem(item, merged.ToVectorND()));
        }
Exemple #20
0
        public ILayer CreateProduct(IKernelDescriptor descriptor)
        {
            if (descriptor is Convolution2D)
            {
                Convolution2D conv = descriptor as Convolution2D;

                ILayer layer = new Conv2DLayer(conv.PaddingVertical, conv.PaddingHorizontal,
                                               conv.StrideVertical, conv.StrideHorizontal);

                return(layer);
            }

            return(null);
        }
Exemple #21
0
        private void SelectKernel(int index)
        {
            #region Set the effect

            int childIndex = 0;
            foreach (UIElement child in panel.Children)
            {
                if (childIndex == index)
                {
                    child.Effect = _selectEffect;
                }
                else
                {
                    child.Effect = null;
                }

                childIndex++;
            }

            #endregion

            _selectedKernelIndex = index;

            #region Update left panel

            if (_selectedKernelIndex >= 0 && _selectedKernelIndex < _kernels.Count && _kernels[_selectedKernelIndex] is Convolution2D)
            {
                _isProgramaticallyChanging = true;

                Convolution2D selectedSingle = (Convolution2D)_kernels[_selectedKernelIndex];

                trkGain.Value       = selectedSingle.Gain;
                trkIterations.Value = selectedSingle.Iterations;

                grdSelectedSingle.Visibility = Visibility.Visible;

                _isProgramaticallyChanging = false;
            }
            else
            {
                grdSelectedSingle.Visibility = Visibility.Hidden;
            }

            #endregion

            // Stats panel
            RefreshStatsPanel();
        }
Exemple #22
0
        public void validate_RollFilter_returns_correct_values()
        {
            var input = new float[200].InitializeTo(1f);

            var result = Convolution2D.RollFilter(input, 10, 20, 2);

            Assert.IsTrue(result.Skip(2).Take(6).All(f => f == 0f));
            Assert.IsTrue(result.Skip(12).Take(6).All(f => f == 0f));

            Assert.IsTrue(result.Skip(22).Take(6).All(f => f == 1f));
            Assert.IsTrue(result.Skip(32).Take(6).All(f => f == 1f));
            // ...
            Assert.IsTrue(result.Skip(172).Take(6).All(f => f == 1f));

            Assert.IsTrue(result.Skip(182).Take(6).All(f => f == 0f));
            Assert.IsTrue(result.Skip(192).Take(6).All(f => f == 0f));
        }
Exemple #23
0
        /// <summary>
        /// Converts the original image into a grayscale
        /// </summary>
        private Convolution2D GetOriginalImageGrays()
        {
            if (originalImage.Source == null)
            {
                return(null);
            }

            int?limit = null;
            int limitInt;

            if (chkLimitImageSize.IsChecked.Value && int.TryParse(txtSizeLimit.Text, out limitInt))
            {
                limit = limitInt;
            }

            bool shouldBuild = false;

            if (_origImageGrays == null)
            {
                shouldBuild = true;
            }
            else if (limit != null && (_origImageGrays.Width > limit.Value || _origImageGrays.Height > limit.Value))
            {
                // The current one is the wrong size
                shouldBuild = true;
            }

            if (shouldBuild)
            {
                BitmapSource bitmap = (BitmapSource)originalImage.Source;

                BitmapCustomCachedBytes colors = null;

                if (limit != null)
                {
                    bitmap = UtilityWPF.ResizeImage(bitmap, limit.Value);       // this will only resize if it's too big
                }

                colors = (BitmapCustomCachedBytes)UtilityWPF.ConvertToColorArray(bitmap, false, Colors.Transparent);

                _origImageGrays = colors.ToConvolution();
            }

            return(_origImageGrays);
        }
Exemple #24
0
        void Awake()
        {
            m_Convolution = new Convolution2D <float>(Kernels.Short.Sobel.X.ToFloat());

            SetupTextures();

            var inputData = new Image <Color24>(m_InputTexture);

            m_GreyscaleJob = new GreyscaleByLuminanceFloatJob24(inputData.Buffer,
                                                                m_GrayscaleInput.Buffer, LuminanceWeights.FloatNormalized);

            m_ConvolveJob   = new FloatWithFloatConvolveJob(m_Convolution, m_GrayscaleInput, m_Convolved);
            m_BiasedReluJob = new BiasedReluActivationCopyJob(m_Convolved.Buffer, m_Activated.Buffer, 0f);

            m_JobHandle = m_GreyscaleJob.Schedule(m_GrayscaleInput.Buffer.Length, 4096);
            m_JobHandle = m_ConvolveJob.Schedule(m_JobHandle);
            m_JobHandle = m_BiasedReluJob.Schedule(m_Convolved.Buffer.Length, 4096, m_JobHandle);
        }
        public static void Convolve(this Convolution2D <short> convolution,
                                    Image <short> image, Image <short> output)
        {
            var outputBuffer = output.Buffer;
            var imageWidth   = image.Width;
            var stride       = convolution.Stride;
            var kernel       = convolution.Kernel2D;
            var pad          = convolution.Padding;

            for (var r = pad.y; r < image.Height - pad.y; r += stride.y)
            {
                var rowIndex = r * imageWidth;
                for (var c = pad.x; c < imageWidth - pad.x; c += stride.x)
                {
                    var i = rowIndex + c;
                    outputBuffer[i] = kernel.Accumulate(image, i);
                }
            }
        }
        public void ExecuteTest()
        {
            int inchannels = 4, outchannels = 6, inwidth = 13, inheight = 17, kwidth = 3, kheight = 5, stride = 2, batch = 7;

            VariableField x = new Tensor(Shape.Map2D(inchannels, inwidth, inheight, batch));

            Layer layer = new Convolution2D(inchannels, outchannels, kwidth, kheight, stride, use_bias: true, pad_mode: PaddingMode.Edge, "conv");

            Field y = layer.Forward(x);

            (Flow flow, Parameters parameters) = Flow.Optimize(y);
            flow.Execute();

            Assert.AreEqual(2, parameters.Count);
            Assert.AreEqual(inchannels, layer.InChannels);
            Assert.AreEqual(outchannels, layer.OutChannels);
            Assert.AreEqual(kwidth, layer.Width);
            Assert.AreEqual(kheight, layer.Height);
        }
Exemple #27
0
        private void Browse_Click(object sender, RoutedEventArgs e)
        {
            const double MAXMULT = 2;

            try
            {
                var dialog = new Microsoft.Win32.OpenFileDialog();
                dialog.Multiselect = false;
                dialog.Title       = "Please select an image";
                bool?result = dialog.ShowDialog();
                if (result == null || !result.Value)
                {
                    return;
                }

                _origConv = UtilityWPF.ConvertToConvolution(new BitmapImage(new Uri(dialog.FileName)));

                lblOrigWidth.Text  = _origConv.Width.ToString("N0");
                lblOrigHeight.Text = _origConv.Height.ToString("N0");

                double max = Math.Max(_origConv.Width, _origConv.Height) * MAXMULT;

                trkWidth.Minimum = _origConv.Width;
                trkWidth.Maximum = max;
                trkWidth.Value   = _origConv.Width;

                trkHeight.Minimum = _origConv.Height;
                trkHeight.Maximum = max;
                trkHeight.Value   = _origConv.Height;

                _timer.IsEnabled = false;       // touching the sliders causes the timer to be enabled

                grdSize.Visibility = Visibility.Visible;

                ShowConvolution(_origConv);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
Exemple #28
0
        private void Timer_Tick(object sender, EventArgs e)
        {
            try
            {
                if (!chkContinuous.IsChecked.Value)
                {
                    _timer.IsEnabled = false;
                }

                int width  = trkWidth.Value.ToInt_Round();
                int height = trkHeight.Value.ToInt_Round();

                Convolution2D conv = Convolutions.ExtendBorders(_origConv, width, height);

                ShowConvolution(conv);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
Exemple #29
0
        //Got this here:
        //http://www.dotnetspider.com/resources/42565-Download-images-from-URL-using-C.aspx
        private BitmapSource DownloadImage(string imageUrl)
        {
            try
            {
                _origImageGrays = null;

                HttpWebRequest webRequest = (HttpWebRequest)System.Net.HttpWebRequest.Create(imageUrl);
                webRequest.AllowWriteStreamBuffering = true;
                webRequest.Timeout = 30000;

                if (_webResponse != null)
                {
                    _webResponse.Close();
                    _webResponse = null;
                }

                var retVal = new BitmapImage();

                retVal.DownloadCompleted += webResponse_DownloadCompleted;

                _webResponse = webRequest.GetResponse();

                Stream stream = _webResponse.GetResponseStream();

                retVal.BeginInit();
                retVal.CacheOption  = BitmapCacheOption.OnLoad;
                retVal.StreamSource = stream;
                retVal.EndInit();
                //retVal.Freeze();      // this throws an exception

                // Can't close yet.  It seems to be downloading async, so wait for the finished event
                //webResponse.Close();

                return(retVal);
            }
            catch (Exception)
            {
                return(null);
            }
        }
Exemple #30
0
        public static Field Forward(Field x, int classes)
        {
            Convolution2D conv1 =
                new Convolution2D(
                    inchannels: 1, outchannels: 4,
                    kwidth: 3, kheight: 3,
                    stride: 1, use_bias: true,
                    pad_mode: PaddingMode.Zero, label: "conv1");

            Convolution2D conv2 =
                new Convolution2D(
                    inchannels: 4, outchannels: 8,
                    kwidth: 3, kheight: 3,
                    stride: 1, use_bias: true,
                    pad_mode: PaddingMode.Zero, label: "conv2");

            Convolution2D conv3 =
                new Convolution2D(
                    inchannels: 8, outchannels: 16,
                    kwidth: 3, kheight: 3,
                    stride: 1, use_bias: true,
                    pad_mode: PaddingMode.Zero, label: "conv3");

            Field h1 = Relu(conv1.Forward(x));
            Field h2 = MaxPooling2D(h1, stride: 2);

            Field h3 = Relu(conv2.Forward(h2));
            Field h4 = MaxPooling2D(h3, stride: 2);

            Field h5 = Relu(conv3.Forward(h4));

            Dense fc =
                new Dense(
                    inchannels: h5.Shape.DataSize, outchannels: classes,
                    use_bias: true, label: "fc");

            Field y = fc.Forward(h5);

            return(y);
        }