コード例 #1
0
 /// <summary>
 /// 活性化関数(ReLU)を適用する
 /// </summary>
 /// <param name="layer">適用対象のLayerData2Dオブジェクト</param>
 public void ReLU(LayerData2D layer)
 {
     for (int i = 0; i < layer.Cells.Length; i++)
     {
         if (layer.Cells[i] < 0)
         {
             layer.Cells[i] = 0f;
         }
     }
 }
コード例 #2
0
        /// <summary>
        /// プーリング計算を行う
        /// </summary>
        /// <param name="outputLayer">出力層のデータを格納するLayerData2Dオブジェクト</param>
        /// <param name="inputLayer">入力層のデータが格納されたLayerData2Dオブジェクト</param>
        /// <param name="poolSize">プーリングサイズ</param>
        public static void Calc(LayerData2D outputLayer, LayerData2D inputLayer, int poolSize)
        {
            if (outputLayer.PlaneNum != inputLayer.PlaneNum)
            {
                throw new Exception("Plane数不整合");
            }
            if (outputLayer.PlaneWidth != inputLayer.PlaneWidth / poolSize)
            {
                throw new Exception("Planeサイズ不整合");
            }
            if (outputLayer.PlaneHeight != inputLayer.PlaneHeight / poolSize)
            {
                throw new Exception("Planeサイズ不整合");
            }

            for (int outputPlane = 0; outputPlane < outputLayer.PlaneNum; outputPlane++)
            {
                int outputPlaneStartIdx = outputLayer.PlaneHeight * outputLayer.PlaneWidth * outputPlane;
                int inputPlane          = outputPlane;
                int inputPlaneStartIdx  = inputLayer.PlaneHeight * inputLayer.PlaneWidth * inputPlane;
                for (int outputY = 0; outputY < outputLayer.PlaneHeight; outputY++)
                {
                    int outputRowStartIdx = outputPlaneStartIdx + outputLayer.PlaneWidth * outputY;
                    int inputY0           = outputY * poolSize;
                    for (int outputX = 0; outputX < outputLayer.PlaneWidth; outputX++)
                    {
                        int   outputCellIdx = outputRowStartIdx + outputX;
                        int   inputX0       = outputX * poolSize;
                        float maxVal        = float.MinValue;
                        for (int inputY = inputY0; inputY < inputY0 + poolSize; inputY++)
                        {
                            int inputRowStartIdx = inputPlaneStartIdx + inputLayer.PlaneWidth * inputY;
                            for (int inputX = inputX0; inputX < inputX0 + poolSize; inputX++)
                            {
                                int   inputCellIdx = inputRowStartIdx + inputX;
                                float inputVal     = inputLayer.Cells[inputCellIdx];
                                if (inputVal > maxVal)
                                {
                                    maxVal = inputVal;
                                }
                            }
                        }
                        outputLayer.Cells[outputCellIdx] = maxVal;
                    }
                }
            }
        }
コード例 #3
0
        static void Main(string[] args)
        {
            Console.WriteLine("<<<Mamecog sample>>>");

            // Conv2DとDenseのインスタンスを生成する
            Conv2D conv1 = new Conv2D(32, 1, 3, 3);
            Conv2D conv2 = new Conv2D(64, 32, 3, 3);
            Dense  dense = new Dense(10, 1600);

            // Conv2DとDenseのカーネルとバイアスをファイルから読み込む
            conv1.LoadKernelAndBias("conv2d_k.bin", "conv2d_b.bin");
            conv2.LoadKernelAndBias("conv2d_1_k.bin", "conv2d_1_b.bin");
            dense.LoadKernelAndBias("dense_k.bin", "dense_b.bin");

            // 各層の入出力の格納先を用意する
            LayerData2D input0      = new LayerData2D(1, 28, 28);
            LayerData2D conv1output = new LayerData2D(32, 26, 26);
            LayerData2D pool1output = new LayerData2D(32, 13, 13);
            LayerData2D conv2output = new LayerData2D(64, 11, 11);
            LayerData2D pool2output = new LayerData2D(64, 5, 5);

            float[] pool2flatten = new float[64 * 5 * 5];
            float[] denseOutput  = new float[10];

            // テスト用の入力データを用意する
            Console.WriteLine("<<<Input>>>");
            input0.Cells = testInput;
            input0.PrintCellValues();

            // 各層の出力を順に計算する
            conv1.Conv(conv1output, input0, false);
            conv1.ReLU(conv1output);
            MaxPool2D.Calc(pool1output, conv1output, 2);
            conv2.Conv(conv2output, pool1output, false);
            conv2.ReLU(conv2output);
            MaxPool2D.Calc(pool2output, conv2output, 2);
            pool2output.Flatten(pool2flatten);
            dense.Calc(denseOutput, pool2flatten);
            dense.Softmax(denseOutput);

            // Dense層の出力を表示する
            Console.WriteLine("<<<Output>>>");
            for (int i = 0; i < denseOutput.Length; i++)
            {
                Console.WriteLine("Dense[" + i.ToString() + "] = " + denseOutput[i].ToString("F4"));
            }
        }
コード例 #4
0
        /// <summary>
        /// 畳み込み計算を行う
        /// </summary>
        /// <param name="outputLayer">出力層のデータを格納するLayerData2Dオブジェクト</param>
        /// <param name="inputLayer">入力層のデータが格納されたLayerData2Dオブジェクト</param>
        /// <param name="withPadding">パディングありのときtrue、なしのときfalse</param>
        public void Conv(LayerData2D outputLayer, LayerData2D inputLayer, bool withPadding)
        {
            int outputPlaneWH    = outputLayer.PlaneWidth * outputLayer.PlaneHeight;
            int inputPlaneWH     = inputLayer.PlaneWidth * inputLayer.PlaneHeight;
            int kernelWH         = KernelWidth * KernelHeight;
            int kernelHalfWidth  = KernelWidth / 2;
            int kernelHalfHeight = KernelHeight / 2;

            if (outputLayer.PlaneNum != OutputPlaneNum)
            {
                throw new Exception("OutputPlaneNum不整合");
            }
            if (inputLayer.PlaneNum != InputPlaneNum)
            {
                throw new Exception("InputPlaneNum不整合");
            }
            if (withPadding)
            {
                if (outputLayer.PlaneHeight != inputLayer.PlaneHeight)
                {
                    throw new Exception("Planeサイズ不整合");
                }
                if (outputLayer.PlaneWidth != inputLayer.PlaneWidth)
                {
                    throw new Exception("Planeサイズ不整合");
                }
            }
            else
            {
                if (outputLayer.PlaneHeight != inputLayer.PlaneHeight - kernelHalfHeight * 2)
                {
                    throw new Exception("Planeサイズ不整合");
                }
                if (outputLayer.PlaneWidth != inputLayer.PlaneWidth - kernelHalfWidth * 2)
                {
                    throw new Exception("Planeサイズ不整合");
                }
            }

            //カーネル(重み行列)のそれぞれの重みを入出力面の縦横のどの範囲に適用するか
            int[] outputStartX = new int[KernelWidth];
            int[] outputStartY = new int[KernelHeight];
            int[] inputStartX  = new int[KernelWidth];
            int[] inputStartY  = new int[KernelHeight];
            int[] loopLengthX  = new int[KernelWidth];
            int[] loopLengthY  = new int[KernelHeight];
            if (withPadding)
            {
                for (int kernelY = 0; kernelY < KernelHeight; kernelY++)
                {
                    outputStartY[kernelY] = Math.Max(kernelHalfHeight - kernelY, 0);
                    inputStartY[kernelY]  = Math.Max(kernelY - kernelHalfHeight, 0);
                    loopLengthY[kernelY]  = outputLayer.PlaneHeight - Math.Abs(kernelHalfHeight - kernelY);
                }
                for (int kernelX = 0; kernelX < KernelWidth; kernelX++)
                {
                    outputStartX[kernelX] = Math.Max(kernelHalfWidth - kernelX, 0);
                    inputStartX[kernelX]  = Math.Max(kernelX - kernelHalfWidth, 0);
                    loopLengthX[kernelX]  = outputLayer.PlaneWidth - Math.Abs(kernelHalfWidth - kernelX);
                }
            }
            else
            {
                for (int kernelY = 0; kernelY < KernelHeight; kernelY++)
                {
                    outputStartY[kernelY] = 0;
                    inputStartY[kernelY]  = kernelY;
                    loopLengthY[kernelY]  = outputLayer.PlaneHeight;
                }
                for (int kernelX = 0; kernelX < KernelWidth; kernelX++)
                {
                    outputStartX[kernelX] = 0;
                    inputStartX[kernelX]  = kernelX;
                    loopLengthX[kernelX]  = outputLayer.PlaneWidth;
                }
            }

            Array.Clear(outputLayer.Cells, 0, outputLayer.Cells.Length);

            //for (int outputPlane = 0; outputPlane < outputLayer.PlaneNum; outputPlane++)
            Parallel.For(0, outputLayer.PlaneNum, outputPlane =>
            {
                int outputPlaneStartIdx = outputPlaneWH * outputPlane;
                for (int inputPlane = 0; inputPlane < inputLayer.PlaneNum; inputPlane++)
                {
                    int inputPlaneStartIdx = inputPlaneWH * inputPlane;
                    int kernelStartIdx     = kernelWH * (InputPlaneNum * outputPlane + inputPlane);
                    for (int kernelY = 0; kernelY < KernelHeight; kernelY++)
                    {
                        int kernelRowStartIdx = kernelStartIdx + KernelWidth * kernelY;
                        int outputY0          = outputStartY[kernelY];
                        int inputY0           = inputStartY[kernelY];
                        int loopLenY          = loopLengthY[kernelY];
                        for (int kernelX = 0; kernelX < KernelWidth; kernelX++)
                        {
                            //float w = GetKernelVal(outputPlane, inputPlane, kernelY, kernelX);
                            float w      = Kernel[kernelRowStartIdx + kernelX];
                            int outputX0 = outputStartX[kernelX];
                            int inputX0  = inputStartX[kernelX];
                            int loopLenX = loopLengthX[kernelX];
                            int outputY  = outputY0;
                            int inputY   = inputY0;
                            for (int y = 0; y < loopLenY; y++)
                            {
                                int outputRowStartIdx   = outputPlaneStartIdx + outputLayer.PlaneWidth * outputY;
                                int inputRowStartIdx    = inputPlaneStartIdx + inputLayer.PlaneWidth * inputY;
                                Span <float> outputSpan = new Span <float>(outputLayer.Cells, outputRowStartIdx + outputX0, loopLenX);
                                Span <float> inputSpan  = new Span <float>(inputLayer.Cells, inputRowStartIdx + inputX0, loopLenX);
                                for (int x = 0; x < loopLenX; x++)
                                {
                                    outputSpan[x] += w * inputSpan[x];
                                }
                                outputY++;
                                inputY++;
                            }
                        }
                    }
                }
            });
        }
コード例 #5
0
        static void Main(string[] args)
        {
            // テスト用の入力データを用意する
            Console.WriteLine("テスト画像読み込み");
            LayerData2D input1        = new LayerData2D(3, 224, 224);
            string      inputFilename = "test_input.png"; // 224x224ピクセルのRGB画像

            using (Bitmap inputImage = new Bitmap(Image.FromFile(inputFilename)))
            {
                Debug.Assert(inputImage.Height == 224);
                Debug.Assert(inputImage.Width == 224);
                for (int y = 0; y < inputImage.Height; y++)
                {
                    for (int x = 0; x < inputImage.Width; x++)
                    {
                        Color pixelData = inputImage.GetPixel(x, y);
                        float r         = (float)pixelData.R - 123.68f;
                        float g         = (float)pixelData.G - 116.779f;
                        float b         = (float)pixelData.B - 103.939f;
                        input1.SetVal(0, y, x, b);     // BGR
                        input1.SetVal(1, y, x, g);
                        input1.SetVal(2, y, x, r);
                    }
                }
            }

            // Conv2DとDenseのインスタンスを生成する
            Conv2D block1Conv1 = new Conv2D(64, 3, 3, 3);
            Conv2D block1Conv2 = new Conv2D(64, 64, 3, 3);
            Conv2D block2Conv1 = new Conv2D(128, 64, 3, 3);
            Conv2D block2Conv2 = new Conv2D(128, 128, 3, 3);
            Conv2D block3Conv1 = new Conv2D(256, 128, 3, 3);
            Conv2D block3Conv2 = new Conv2D(256, 256, 3, 3);
            Conv2D block3Conv3 = new Conv2D(256, 256, 3, 3);
            Conv2D block4Conv1 = new Conv2D(512, 256, 3, 3);
            Conv2D block4Conv2 = new Conv2D(512, 512, 3, 3);
            Conv2D block4Conv3 = new Conv2D(512, 512, 3, 3);
            Conv2D block5Conv1 = new Conv2D(512, 512, 3, 3);
            Conv2D block5Conv2 = new Conv2D(512, 512, 3, 3);
            Conv2D block5Conv3 = new Conv2D(512, 512, 3, 3);
            Dense  fc1         = new Dense(4096, 25088);
            Dense  fc2         = new Dense(4096, 4096);
            Dense  predictions = new Dense(1000, 4096);

            // Conv2DとDenseのカーネルとバイアスをファイルから読み込む
            Console.WriteLine("学習済みモデル読み込み");
            block1Conv1.LoadKernelAndBias("block1_conv1_k.bin", "block1_conv1_b.bin");
            block1Conv2.LoadKernelAndBias("block1_conv2_k.bin", "block1_conv2_b.bin");
            block2Conv1.LoadKernelAndBias("block2_conv1_k.bin", "block2_conv1_b.bin");
            block2Conv2.LoadKernelAndBias("block2_conv2_k.bin", "block2_conv2_b.bin");
            block3Conv1.LoadKernelAndBias("block3_conv1_k.bin", "block3_conv1_b.bin");
            block3Conv2.LoadKernelAndBias("block3_conv2_k.bin", "block3_conv2_b.bin");
            block3Conv3.LoadKernelAndBias("block3_conv3_k.bin", "block3_conv3_b.bin");
            block4Conv1.LoadKernelAndBias("block4_conv1_k.bin", "block4_conv1_b.bin");
            block4Conv2.LoadKernelAndBias("block4_conv2_k.bin", "block4_conv2_b.bin");
            block4Conv3.LoadKernelAndBias("block4_conv3_k.bin", "block4_conv3_b.bin");
            block5Conv1.LoadKernelAndBias("block5_conv1_k.bin", "block5_conv1_b.bin");
            block5Conv2.LoadKernelAndBias("block5_conv2_k.bin", "block5_conv2_b.bin");
            block5Conv3.LoadKernelAndBias("block5_conv3_k.bin", "block5_conv3_b.bin");
            fc1.LoadKernelAndBias("fc1_k.bin", "fc1_b.bin");
            fc2.LoadKernelAndBias("fc2_k.bin", "fc2_b.bin");
            predictions.LoadKernelAndBias("predictions_k.bin", "predictions_b.bin");

            // 各層の入出力の格納先を用意する
            LayerData2D block1Conv1Output = new LayerData2D(64, 224, 224);
            LayerData2D block1Conv2Output = new LayerData2D(64, 224, 224);
            LayerData2D block1PoolOutput  = new LayerData2D(64, 112, 112);
            LayerData2D block2Conv1Output = new LayerData2D(128, 112, 112);
            LayerData2D block2Conv2Output = new LayerData2D(128, 112, 112);
            LayerData2D block2PoolOutput  = new LayerData2D(128, 56, 56);
            LayerData2D block3Conv1Output = new LayerData2D(256, 56, 56);
            LayerData2D block3Conv2Output = new LayerData2D(256, 56, 56);
            LayerData2D block3Conv3Output = new LayerData2D(256, 56, 56);
            LayerData2D block3PoolOutput  = new LayerData2D(256, 28, 28);
            LayerData2D block4Conv1Output = new LayerData2D(512, 28, 28);
            LayerData2D block4Conv2Output = new LayerData2D(512, 28, 28);
            LayerData2D block4Conv3Output = new LayerData2D(512, 28, 28);
            LayerData2D block4PoolOutput  = new LayerData2D(512, 14, 14);
            LayerData2D block5Conv1Output = new LayerData2D(512, 14, 14);
            LayerData2D block5Conv2Output = new LayerData2D(512, 14, 14);
            LayerData2D block5Conv3Output = new LayerData2D(512, 14, 14);
            LayerData2D block5PoolOutput  = new LayerData2D(512, 7, 7);

            float[] flattenOutput     = new float[25088];
            float[] fc1Output         = new float[4096];
            float[] fc2Output         = new float[4096];
            float[] predictionsOutput = new float[1000];

            // 各層の出力を順に計算する
            Console.WriteLine("CNN実行開始");
            var sw = new System.Diagnostics.Stopwatch();

            sw.Start();
            Console.WriteLine("Block 1");
            block1Conv1.Conv(block1Conv1Output, input1, true);
            block1Conv1.ReLU(block1Conv1Output);
            block1Conv2.Conv(block1Conv2Output, block1Conv1Output, true);
            block1Conv2.ReLU(block1Conv2Output);
            MaxPool2D.Calc(block1PoolOutput, block1Conv2Output, 2);
            Console.WriteLine("Block 2");
            block2Conv1.Conv(block2Conv1Output, block1PoolOutput, true);
            block2Conv1.ReLU(block2Conv1Output);
            block2Conv2.Conv(block2Conv2Output, block2Conv1Output, true);
            block2Conv2.ReLU(block2Conv2Output);
            MaxPool2D.Calc(block2PoolOutput, block2Conv2Output, 2);
            Console.WriteLine("Block 3");
            block3Conv1.Conv(block3Conv1Output, block2PoolOutput, true);
            block3Conv1.ReLU(block3Conv1Output);
            block3Conv2.Conv(block3Conv2Output, block3Conv1Output, true);
            block3Conv2.ReLU(block3Conv2Output);
            block3Conv3.Conv(block3Conv3Output, block3Conv2Output, true);
            block3Conv3.ReLU(block3Conv3Output);
            MaxPool2D.Calc(block3PoolOutput, block3Conv3Output, 2);
            Console.WriteLine("Block 4");
            block4Conv1.Conv(block4Conv1Output, block3PoolOutput, true);
            block4Conv1.ReLU(block4Conv1Output);
            block4Conv2.Conv(block4Conv2Output, block4Conv1Output, true);
            block4Conv2.ReLU(block4Conv2Output);
            block4Conv3.Conv(block4Conv3Output, block4Conv2Output, true);
            block4Conv3.ReLU(block4Conv3Output);
            MaxPool2D.Calc(block4PoolOutput, block4Conv3Output, 2);
            Console.WriteLine("Block 5");
            block5Conv1.Conv(block5Conv1Output, block4PoolOutput, true);
            block5Conv1.ReLU(block5Conv1Output);
            block5Conv2.Conv(block5Conv2Output, block5Conv1Output, true);
            block5Conv2.ReLU(block5Conv2Output);
            block5Conv3.Conv(block5Conv3Output, block5Conv2Output, true);
            block5Conv3.ReLU(block5Conv3Output);
            MaxPool2D.Calc(block5PoolOutput, block5Conv3Output, 2);
            Console.WriteLine("FC");
            block5PoolOutput.Flatten(flattenOutput);
            fc1.Calc(fc1Output, flattenOutput);
            fc1.ReLU(fc1Output);
            fc2.Calc(fc2Output, fc1Output);
            fc2.ReLU(fc2Output);
            predictions.Calc(predictionsOutput, fc2Output);
            predictions.Softmax(predictionsOutput);
            sw.Stop();
            TimeSpan ts = sw.Elapsed;

            Console.WriteLine("CNN実行完了:実行時間 = {0}", ts);

            // VGG16モデルの学習済み1000カテゴリのうち先頭10カテゴリ分の確率を出力
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("カテゴリ[{0}] = {1}", i, predictionsOutput[i]);
            }
        }