} // end method public async Task<byte[,]> fdenoiseNeural2(byte[,] noisyIm, int step, string fileName, int layer, int[] networkSize,int[] inputsPerSample, int numberofsectors, CancellationToken cancelToken, PauseToken pauseToken, int progressBar1, int progressBar1Max) { /* * noisyIm: an image corrupted by AWG noise * the sliding window stride of the denoising process (a smaller stride will usually provide better results). The pixels of the clean image are assumed to be approximately in the range 0..255. */ #region Initialization form1.SetText1("Using the new patch method.\r\n" + Environment.NewLine); form1.SetText1("Initializing Components...\r\n" + Environment.NewLine); int testval = 0; form1.SetProgress1(2); form1.SetText1("Loading weights... "); // load the weights Complex[][,] weights = loadMlmvnWeights(fileName, layer, networkSize, inputsPerSample); form1.SetText1("Done." + Environment.NewLine); form1.SetText1("Configuring Patch Size... "); // size of input / output patch int patchSz = (int)Math.Sqrt(weights[0].GetLength(1)); int patchSzOut = (int)Math.Sqrt(weights[layer - 1].GetLength(0)); // Size of each sector on unit circle form1.SetText1("Done.\r\n" + Environment.NewLine); form1.SetText1("Input patch size is: " + patchSz + Environment.NewLine); form1.SetText1("Output patch size is: " + patchSzOut + Environment.NewLine); // calculate the difference of the patches int p_diff = (patchSz - patchSzOut) / 2; // check if input is larger than output. If so, extend the image int height = noisyIm.GetLength(0); int origHeight = height; int width = noisyIm.GetLength(1); int origWidth = width; if (p_diff > 0) { noisyIm = new byte[height + p_diff * 2, width + p_diff * 2]; noisyIm = functions.MirrorImage(noisyIm, height, width, p_diff); // if extended the image, update the size height = noisyIm.GetLength(0); width = noisyIm.GetLength(1); } #region Patch range configuration // interval determines how many pixels would be skipped before new patch will be placed. // For example, if step is 3 and patch size is 13, 3 * 2 = 6 pixels would be overlapped for non-edge patches. // Therefore, 13 - 6 = 7 pixels will be skipped. int interval = patchSz - (step * 2); // offsetX and offsetY determine the number of "leftover" pixels on the right and bottom edges. // For example, if 512 * 512 image will be filled by 13 * 13 patches, 512 - ((13-3) % interval int offsetX = (width - (patchSz - step)) % interval; int offsetY = (height - (patchSz - step)) % interval; // reserve the array to indicate the index of patches. include one position for the fist patch. And reserve extra one position just in case // we need to fill the offset int[] range_x = new int[(width - (patchSz - step)) / interval + 2]; int[] range_y = new int[(height - (patchSz - step)) / interval + 2]; int pos = 0; // fill the arrays with intervals. ignore the last element because we don't know if it's necessary yet for (int i = 0; i < range_x.GetLength(0) - 1; i++) { range_x[i] = pos; pos += interval; } pos = 0; for (int i = 0; i < range_y.GetLength(0) - 1; i++) { range_y[i] = pos; pos += interval; } // end for // correct last index if necessary // if offsetX and Y are equal to 0, that means no fitting is necessary. Therefore, just resize the array to have // one less length. Else, fill the last element of the array with the index according to the offsets if (offsetX == 0) Array.Resize(ref range_x, range_x.GetLength(0) - 1); else range_x[range_x.GetLength(0) - 1] = width - patchSz; // end if if (offsetY == 0) Array.Resize(ref range_y, range_y.GetLength(0) - 1); else range_y[range_y.GetLength(0) - 1] = height - patchSz; // end if #endregion form1.SetText1("\r\nDifference of the patche size is: " + p_diff + Environment.NewLine); form1.SetText1("Beginning variable initialization... "); // pre-instantiate complex 2d-arrays // patch of interest byte[,] cleanIm = new byte[origHeight, origWidth]; //byte[,] counter = new byte[origHeight, origWidth]; // counts the overlapped patch, then later store the processed image. double[,] inputArray = new double[patchSz, patchSz]; Complex[,] CinputArray = new Complex[patchSz, patchSz]; // output patch to be stored to actual image byte[,] outputArray = new byte[patchSz, patchSz]; byte[] output = new byte[(int)Math.Pow(patchSz, 2)]; // used when patch needs to be transformed to 1d array Complex[] S = new Complex[inputArray.Length]; // store outputs of network Complex[][] outputNeurons = new Complex[layer][]; double[] dOutputNeurons = new double[networkSize[layer - 1]]; // instanciate a jagged array to store outputs for (int i = 0; i < layer; i++) outputNeurons[i] = new Complex[networkSize[i]]; // end for Complex sum = new Complex(0, 0); S[0] = new Complex(1, 0); // instantiate imaginary unit Complex complex1 = new Complex(0.0, 1.0); // processIndex as in old code int offset = ((patchSzOut - 3) / 2) + 1; double bb = (2 * Math.PI) / numberofsectors; form1.SetText1("Done.\r\n" + Environment.NewLine); form1.SetText1("Beginning Processing... \r\n" + Environment.NewLine); #endregion // --------------- Processing Begins ------------------------------ // process each samples for (int row = 0; row < range_y.GetLength(0); row++) // for each row { for (int col = 0; col < range_x.GetLength(0); col++) // for each column { #region process first layer // process first layer int ii = 0; byte[,] src = Functions.CreatePatch(noisyIm, range_y[row], range_x[col], patchSz); // upcast to double Array.Copy(src, inputArray, src.Length); // transformation of inputs into complex plane for (int i = 0; i < patchSz; i++) for (int j = 0; j < patchSz; j++) CinputArray[i, j] = Exp(complex1 * 2 * Math.PI * inputArray[i, j] / numberofsectors); // end nested for loop // transform to 1d array for (int i = 0; i < patchSz; i++) for (int j = 0; j < patchSz; j++) S[i * patchSz + j] = CinputArray[i, j]; // end for loop #endregion #region calculate weighted sum of first layer and its activation // calculate weighted sum & activation for (int i = 0; i < networkSize[0]; i++) { for (int j = 1; j < inputsPerSample[0]; j++) { sum = sum + weights[ii][i, j] * S[j - 1]; } sum = sum + weights[ii][i, 0]; outputNeurons[ii][i] = sum; sum = new Complex(0, 0); } // end for // apply continuous activation for (int t = 0; t < networkSize[ii]; t++) outputNeurons[ii][t] /= Complex.Abs(outputNeurons[ii][t]); // end for #endregion #region calculate weighted sum of second to last layer // ----------------- Process second to last hidden layers, then output layer for (ii = 1; ii < layer - 1; ii++) { for (int i = 0; i < networkSize[ii]; i++) { for (int j = 1; j < inputsPerSample[ii]; j++) { sum = sum + weights[ii][i, j] * outputNeurons[ii - 1][j - 1]; } sum = sum + weights[ii][i, 0]; outputNeurons[ii][i] = sum; sum = new Complex(0, 0); } // end for // apply contiunous activation for (int t = 0; t < networkSize[ii]; t++) outputNeurons[ii][t] /= Complex.Abs(outputNeurons[ii][t]); // end for } // end for ii // output layer ii = layer - 1; // set to last layer // calculate the weighted sum for (int i = 0; i < networkSize[ii]; i++) { for (int j = 1; j < inputsPerSample[ii]; j++) { sum = sum + weights[ii][i, j] * outputNeurons[ii - 1][j - 1]; } sum = sum + weights[ii][i, 0]; outputNeurons[ii][i] = sum; sum = new Complex(0, 0); } // end for for (int jj = 0; jj < networkSize[ii]; jj++) { // calculate discrete output // get angle dOutputNeurons[jj] = Math.Atan2(outputNeurons[ii][jj].Imaginary, outputNeurons[ii][jj].Real); if (dOutputNeurons[jj] < 0) dOutputNeurons[jj] = 2 * Math.PI + dOutputNeurons[jj]; // end if // round dOutputNeurons[jj] = Math.Truncate(dOutputNeurons[jj] / bb); //dOutputNeurons[jj] = Math.Floor(dOutputNeurons[jj]/bb); if (dOutputNeurons[jj] > 255) if (dOutputNeurons[jj] < 320) dOutputNeurons[jj] = 255; else dOutputNeurons[jj] = 0; // end if // convert results to byte output[jj] = Convert.ToByte(dOutputNeurons[jj]); } // end for #endregion second to last layer #region Process image // resize for (int i = 0; i < patchSzOut; i++) for (int j = 0; j < patchSzOut; j++) outputArray[i, j] = output[p_diff + j + (i * patchSz)]; // end for // Output to an acutal image. /* Codes below outputs the calculated patch into the output image. Although the size of patch is 13 x 13, only center 7 * 7 will be copied to the * image because of overlapping method, with the only exception of when the patch touches the edge of the image. In order to determine this, we will * first check whether the coordinate of the patch is either 0 or width(height) - patchSz. if so, we need to take the borders into account. Otherwise, * we just need to copy center 7 x 7 pixels onto corresponding coordinates. */ // check if (range_y[row] == 0 || range_y[row] == height - patchSz || range_x[col] == 0 || range_x[col] == width - patchSz) { // startY and startX determines the starting coordinate of the local patch; it's initialized with step. if the patch is touching the edge, we need to // set them to 0, so whole patch side will be copied. The same for endY and endX. int startY, startX; startY = startX = step; int endY, endX; endY = endX = patchSzOut - step; // All outer patches if (range_y[row] == 0) startY = 0; // end if if (range_y[row] == height - patchSz) { // startY = patchSzOut - (height - (range_y[row - 1] + patchSz - (step * 2))); startY = patchSzOut - offsetY; endY = patchSzOut; } // end if if (range_x[col] == 0) startX = 0; // end if if (range_x[col] == width - patchSz) { startX = patchSzOut - offsetX; endX = patchSzOut; } // end if // Place patches for (int i = startY; i < endY; i++) { for (int j = startX; j < endX; j++) { cleanIm[range_y[row] + i, range_x[col] + j] = outputArray[i, j]; } // end for } //end } else { // All Inner Patches have outer edges cut off for (int i = step; i < patchSzOut - step; i++) { for (int j = step; j < patchSzOut - step; j++) { cleanIm[range_y[row] + i, range_x[col] + j] = outputArray[i, j]; } // end for } //end } #endregion testval = form1.SetProgress1(1); } // end col for loop if (cancelToken.IsCancellationRequested) cancelToken.ThrowIfCancellationRequested(); // Action when pause button is clicked await pauseToken.WaitWhilePausedAsync(); // Increasing Progress bar values TaskbarManager.Instance.SetProgressValue(testval, progressBar1Max); form1.SetText1("Patches in row " + (row + 1) + " of " + range_y.Length + " done." + Environment.NewLine); } // end row for loop return cleanIm; } // end method
/* -------------------------- Denoise by Pixels ----------------------------------------------------------------- */ public async Task<byte[,]> Activation(byte[,] noisyImage, int kernel, string weights, int numberofsectors, int inLayerSize, int hidLayerSize, CancellationToken cancelToken, PauseToken pauseToken, int progressBar1, int progressBar1Max) { // get height and width int height = noisyImage.GetLength(0); int width = noisyImage.GetLength(1); int offset; switch (kernel) { case 3: offset = 1; break; case 5: offset = 2; break; case 7: offset = 3; break; default: offset = 0; break; } // end switch if (offset == 0) { form1.SetText1("Value of kernel is not properly set." + Environment.NewLine); return null; } // extend the image byte[,] image = new byte[height + offset * 2, width + offset * 2]; image = functions.MirrorImage(noisyImage, height, width, offset); form1.SetProgress1(4); progressBar1 += 4; TaskbarManager.Instance.SetProgressValue(progressBar1, progressBar1Max); // pre-instantiate complex 2d-array double[,] inputArray = new double[kernel, kernel]; var CinputArray = new Complex[kernel, kernel]; // instantiate imaginary unit var complex1 = new Complex(0.0, 1.0); // pass to neural network byte[,] src; //int FirstQ = offset; //Parallel.For(FirstQ, height + offset, Q => for (int Q = offset; Q < height + offset; Q++) { for (int P = offset; P < width + offset; P++) { src = Functions.CreateWindow(image, Q, P, kernel, offset); Array.Copy(src, inputArray, src.Length); // transformation of inputs into complex plane for (int i = 0; i < kernel; i++) { for (int j = 0; j < kernel; j++) CinputArray[i, j] = Exp(complex1 * 2 * Math.PI * inputArray[i, j] / numberofsectors); } // end nested for loop // process noisyImage[Q - offset, P - offset] = NeuralNetwork(CinputArray, weights, numberofsectors, inLayerSize, hidLayerSize); } // Action when cancel button is clicked if (cancelToken.IsCancellationRequested) cancelToken.ThrowIfCancellationRequested(); // Action when pause button is clicked await pauseToken.WaitWhilePausedAsync(); // Increments progress bar TaskbarManager.Instance.SetProgressValue(form1.SetProgress1(1), progressBar1Max); };//); return noisyImage; }// end method
/* -------------------------- Denoise by Patch ----------------------------------------------------------------- */ public async Task<byte[,]> fdenoiseNeural(byte[,] noisyIm, int step, string fileName, int layer, int[] networkSize, int[] inputsPerSample, int numberofsectors, CancellationToken cancelToken, PauseToken pauseToken, int progressBar1, int progressBar1Max) { /* noisyIm: an image corrupted by AWG noise the sliding window stride of the denoising process (a smaller stride will usually provide better results). The pixels of the clean image are assumed to be approximately in the range 0..255. */ #region Initialization form1.SetText1("Initializing components...\r\n" + Environment.NewLine); int testval = 0; form1.SetProgress1(2); form1.SetText1("Loading weights... "); // load the weights Complex[][,] weights = loadMlmvnWeights(fileName, layer, networkSize, inputsPerSample); form1.SetText1("Done." + Environment.NewLine); form1.SetText1("Configuring patch size... "); // size of input / output patch int patchSz = (int)Math.Sqrt(weights[0].GetLength(1) - 1); // <-- Implement outside of function to determine type of weights int patchSzOut = (int)Math.Sqrt(weights[layer - 1].GetLength(0)); // Size of each sector on unit circle form1.SetText1("Done.\r\n" + Environment.NewLine); form1.SetText1("Input patch size is: " + patchSz + Environment.NewLine); form1.SetText1("Output patch size is: " + patchSzOut + Environment.NewLine); // calculate the difference of the patches int p_diff = (patchSz - patchSzOut) / 2; // check if input is larger than output. If so, extend the image int height = noisyIm.GetLength(0); int origHeight = height; int width = noisyIm.GetLength(1); int origWidth = width; if (p_diff > 0) { noisyIm = new byte[height + p_diff * 2, width + p_diff * 2]; noisyIm = functions.MirrorImage(noisyIm, height, width, p_diff); // if extended the image, update the size height = noisyIm.GetLength(0); width = noisyIm.GetLength(1); } #region Patch range configuration int pos = 0; // create arrays that contain the index ranges for row and column int[] range_y = new int[(height - patchSz) / step + 2]; int[] range_x = new int[(width - patchSz) / step + 2]; for (int i = 0; i < height - patchSz; i = i + step) { range_y[pos] = i; pos++; } // end for pos = 0; for (int i = 0; i < width - patchSz; i = i + step) { range_x[pos] = i; pos++; } // end for if (range_y[range_y.Length - 2] != height - patchSz) { range_y[range_y.Length - 1] = height - patchSz; } else Array.Resize(ref range_y, range_y.GetLength(0) - 1); // end if if (range_x[range_x.Length - 2] != height - patchSz) { range_x[range_x.Length - 1] = height - patchSz; } else Array.Resize(ref range_x, range_x.GetLength(0) - 1); // end if #endregion form1.SetText1("\r\nDifference of the patche size is: " + p_diff + Environment.NewLine); form1.SetText1("Beginning variable initialization... "); // pre-instantiate complex 2d-arrays // patch of interest int[,] cleanIm = new int[origHeight, origWidth]; byte[,] counter = new byte[origHeight, origWidth]; // counts the overlapped patch, then later store the processed image. double[,] inputArray = new double[patchSz, patchSz]; Complex[,] CinputArray = new Complex[patchSz, patchSz]; // output patch to be stored to actual image byte[,] outputArray = new byte[patchSz, patchSz]; byte[] output = new byte[(int)Math.Pow(patchSz, 2)]; // used when patch needs to be transformed to 1d array Complex[] S = new Complex[inputArray.Length]; // store outputs of network Complex[][] outputNeurons = new Complex[layer][]; double[] dOutputNeurons = new double[networkSize[layer - 1]]; // instanciate a jagged array to store outputs for (int i = 0; i < layer; i++) outputNeurons[i] = new Complex[networkSize[i]]; // end for Complex sum = new Complex(0, 0); S[0] = new Complex(1, 0); // instantiate imaginary unit Complex complex1 = new Complex(0.0, 1.0); // processIndex as in old code int offset = ((patchSzOut - 3) / 2) + 1; double bb = (2 * Math.PI) / numberofsectors; form1.SetText1("Done.\r\n" + Environment.NewLine); form1.SetText1("Beginning the processing... \r\n" + Environment.NewLine); #endregion //int increment = 0; //double test2 = range_x.GetLength(0)/2; //double test3 = Math.Floor(test2); // --------------- Processing Begins ------------------------------ // process each samples for (int row = 0; row < range_y.GetLength(0); row++) // for each row { for (int col = 0; col < range_x.GetLength(0); col++) // for each column { #region process first layer // process first layer int ii = 0; byte[,] src = Functions.CreatePatch(noisyIm, range_y[row], range_x[col], patchSz); // upcast to double Array.Copy(src, inputArray, src.Length); // transformation of inputs into complex plane for (int i = 0; i < patchSz; i++) for (int j = 0; j < patchSz; j++) CinputArray[i, j] = Exp(complex1 * 2 * Math.PI * inputArray[i, j] / numberofsectors); // end nested for loop // transform to 1d array for (int i = 0; i < patchSz; i++) for (int j = 0; j < patchSz; j++) S[i * patchSz + j] = CinputArray[i, j]; // end for loop #endregion #region calculate weighted sum of first layer and its activation // calculate weighted sum & activation for (int i = 0; i < networkSize[0]; i++) { for (int j = 1; j < inputsPerSample[0]; j++) { sum = sum + weights[ii][i, j] * S[j - 1]; } sum = sum + weights[ii][i, 0]; outputNeurons[ii][i] = sum; sum = new Complex(0, 0); } // end for // apply continuous activation for (int t = 0; t < networkSize[ii]; t++) outputNeurons[ii][t] /= Complex.Abs(outputNeurons[ii][t]); // end for #endregion #region calculate weighted sum of second to last layer // ----------------- Process second to last hidden layers, then output layer for (ii = 1; ii < layer - 1; ii++) { for (int i = 0; i < networkSize[ii]; i++) { for (int j = 1; j < inputsPerSample[ii]; j++) { sum = sum + weights[ii][i, j] * outputNeurons[ii - 1][j - 1]; } sum = sum + weights[ii][i, 0]; outputNeurons[ii][i] = sum; sum = new Complex(0, 0); } // end for // apply contiunous activation for (int t = 0; t < networkSize[ii]; t++) outputNeurons[ii][t] /= Complex.Abs(outputNeurons[ii][t]); // end for } // end for ii // output layer ii = layer - 1; // set to last layer // calculate the weighted sum for (int i = 0; i < networkSize[ii]; i++) { for (int j = 1; j < inputsPerSample[ii]; j++) { sum = sum + weights[ii][i, j] * outputNeurons[ii - 1][j - 1]; } sum = sum + weights[ii][i, 0]; outputNeurons[ii][i] = sum; sum = new Complex(0, 0); } // end for for (int jj = 0; jj < networkSize[ii]; jj++) { // calculate discrete output // get angle dOutputNeurons[jj] = Math.Atan2(outputNeurons[ii][jj].Imaginary, outputNeurons[ii][jj].Real); if (dOutputNeurons[jj] < 0) dOutputNeurons[jj] = 2 * Math.PI + dOutputNeurons[jj]; // end if // round dOutputNeurons[jj] = Math.Truncate(dOutputNeurons[jj] / bb); //dOutputNeurons[jj] = Math.Floor(dOutputNeurons[jj]/bb); if (dOutputNeurons[jj] > 255) if (dOutputNeurons[jj] < 320) dOutputNeurons[jj] = 255; else dOutputNeurons[jj] = 0; // end if // convert results to byte output[jj] = Convert.ToByte(dOutputNeurons[jj]); } // end for #endregion second to last layer #region Process image // resize for (int i = 0; i < patchSzOut; i++) for (int j = 0; j < patchSzOut; j++) outputArray[i, j] = output[p_diff + j + (i * patchSz)]; // end for // add to the actual image for (int i = 0; i < patchSzOut; i++) for (int j = 0; j < patchSzOut; j++) { //if (counter[range_y[row] + i, range_x[col] + j] == 0) //{ cleanIm[range_y[row] + i, range_x[col] + j] += outputArray[i, j]; counter[range_y[row] + i, range_x[col] + j]++; //} } // end for // end for #endregion #region GUI incrementation //increment += 1; //if (range_x.GetLength(0)/2 <= increment) //{ // testval = form1.SetProgress1(1); // increment = 0; //} testval = form1.SetProgress1(1); #endregion }//); // end col for loop // Action when cancel button is clicked if (cancelToken.IsCancellationRequested) cancelToken.ThrowIfCancellationRequested(); // Action when pause button is clicked await pauseToken.WaitWhilePausedAsync(); // Increasing Progress bar values TaskbarManager.Instance.SetProgressValue(testval, progressBar1Max); form1.SetText1("Patches in row " + (row + 1) + " of " + range_y.Length + " done." + Environment.NewLine); }//); // end row for loop #region Average // Average for (int row = 0; row < origHeight; row++) // for each row { for (int col = 0; col < origWidth; col++) // for each column { cleanIm[row, col] /= counter[row, col]; counter[row, col] = Convert.ToByte(cleanIm[row, col]); } } #endregion #region Old code //double[,] pixel_weights = new double[patchSzOut, patchSzOut]; //// median pixel ceiling(17/2) = 9 //int mid = (int)Math.Ceiling((double)patchSzOut/2); //// floor(17/2) / 2 = 4 //int sig = (int)Math.Floor((double)patchSzOut / 2) / weightSig; //// initialize pixel_weights //double d = 0; //for (int i = 0; i < patchSzOut; i++) // for (int j = 0; j < patchSzOut; j++) // { // d = Math.Sqrt(Math.Pow((i - mid),2) + Math.Pow((j - mid), 2)); // pixel_weights[i, j] = Math.Exp(Math.Pow(-d,2) / (2 * Math.Pow(sig, 2))) / (sig * Math.Sqrt(2 * Math.PI)); // } //// end for //// obtain the max of pixel_weights and subtract each element with it //// to achieve mean zero //double max = pixel_weights.Cast<double>().Max(); //for (int i = 0; i < patchSzOut; i++) // for (int j = 0; j < patchSzOut; j++) // pixel_weights[i, j] = pixel_weights[i, j] - max; //// end for //// Upcast byte to double //double[,] dnoisyIm = new double[noisyIm.GetLength(0), noisyIm.GetLength(1)]; //Array.Copy(noisyIm, dnoisyIm, noisyIm.Length); //// subract 0.5 and multiply by 0.2 to achieve approximately mean zero and //// variance close to one //for (int i = 0; i < dnoisyIm.GetLength(0); i++) // for (int j = 0; j < dnoisyIm.GetLength(1); j++ ) // dnoisyIm[i, j] = (((dnoisyIm[i, j] / 255) - 0.5) / 0.2); //// end for //int chunkSize = 1000; //int pos = 0; //// create arrays that contain the index ranges for row and column //int[] range_y = new int[(dnoisyIm.GetLength(0) - patchSz)/step + 2]; //int[] range_x = new int[(dnoisyIm.GetLength(1) - patchSz)/step + 2]; //for (int i = 0; i < noisyIm.GetLength(0) - patchSz; i = i + step) //{ // range_y[pos] = i; // pos++; //} //// end for //pos = 0; //for (int i = 0; i < noisyIm.GetLength(1) - patchSz; i = i + step) //{ // range_x[pos] = i; // pos++; //} //// end for //// if the ranges do not include the last available row / column, include them //if (range_y[range_y.GetLength(0) - 2] != noisyIm.GetLength(0) - patchSz) // range_y[range_y.GetLength(0) - 1] = noisyIm.GetLength(0) - patchSz; //else // Array.Resize(ref range_y, range_y.GetLength(0) - 1); //// end if //if (range_x[range_x.GetLength(0) - 2] != noisyIm.GetLength(1) - patchSz) // range_x[range_y.GetLength(0) - 1] = noisyIm.GetLength(1) - patchSz; //else // Array.Resize(ref range_x, range_x.GetLength(0) - 1); //// end if //double[,] res = new double[(int)Math.Pow(patchSz, 2), chunkSize]; //double[,] part = new double[(int)Math.Pow(patchSz, 2) + layer - 1, chunkSize]; //int[,] positions_out = new int[2, chunkSize]; //byte[,] denoisedIm = new byte[noisyIm.GetLength(0),noisyIm.GetLength(1)]; //Complex[,] wIm = new Complex[noisyIm.GetLength(0), noisyIm.GetLength(1)]; //byte[,] p = new byte[patchSz, patchSz]; //byte[] p1 = new byte[(int)Math.Pow(patchSz,2)]; // --------------------- Processing Image Begin --------------------------------------- //int idx = -1; //for (int y = 0; y < range_y.GetLength(0); y++) //{ // for (int x = 0; x < range_x.GetLength(0); x++) // { // // copy particular input patch from noisy image // for (int i = 0; i < patchSz; i++) // for (int j = 0; j < patchSz; j++) // p[i, j] = noisyIm[range_y[y] + i, range_x[x] + j]; // // end for // // increment index // idx++; // // convert p to 1d array // Buffer.BlockCopy(p,0, p1, 0, p1.Length * sizeof(byte)); // // copy whole patch as a row to the indexed row of res; // for (int i = 0; i < res.GetLength(0); i++) // res[i, idx] = p1[i]; // // end for // // copy the index of the particular iteration // positions_out[0, idx] = y; // positions_out[1, idx] = x; // // every time idx reaches 1000, below executes. after that, idx is reset to 0 // // ------------------------ Prediction -------------------------------------- // if ( idx >= chunkSize - 1 ) // { // // copy res to part // Array.Copy(res, part, res.Length); // for ( int i = 0; i<layer;i++) // { // for (int j = 0; j < part.GetLength(1);j++ ) // part[part.GetLength(0) - layer + 1, j] = 1; // // end for // } // end for // } // end if // } //} #endregion return counter; } // end method
public async Task<Complex[][,]> Learning(string fileNameSamples, int numberOfInputSamples, string fileNameWeights, int layer, int[] networkSize, int[] inputsPerSample, int numberofsectors, double globalThreasholdValue, double localThresholdValue, bool randomWeights, CancellationToken cancelToken, PauseToken pauseToken) { #region Initialization int twoInputsPerSample = networkSize[layer - 1] * 2; form1.SetText2("Initializing components..." + Environment.NewLine); // load the samples form1.SetText2("Loading learning samples... "); byte[,] samples = loadLearningSamples(fileNameSamples, numberOfInputSamples, twoInputsPerSample); form1.SetText2("Done." + Environment.NewLine); // Initial Weights Initialization #region Weights Initialization Random random = new Random(); double real; double imag; Complex[][,] weights = new Complex[layer][,]; if (randomWeights) { // generate random weights // initialize weights matrix for (int ii = 0; ii < layer; ii++) { weights[ii] = new Complex[networkSize[ii], inputsPerSample[ii]]; //if (ii == 0) // weights[ii] = new Complex[networkSize[ii], inputsPerSample[ii]]; //else // weights[ii] = new Complex[networkSize[ii], networkSize[ii - 1]]; // now generate random numbers for (int i = 0; i < weights[ii].GetLength(0); i++) for (int j = 0; j < weights[ii].GetLength(1); j++) { real = random.NextDouble() - 0.5; imag = random.NextDouble() - 0.5; weights[ii][i, j] = new Complex(real, imag); } // end for j // end for i } // end for ii } else { form1.SetText2("Loading weights... "); // load the weights weights = loadMlmvnWeights(fileNameWeights, layer, networkSize, inputsPerSample); form1.SetText2("Done.\n" + Environment.NewLine); } // end if #endregion double twoPi = Math.PI * 2; Complex complex1 = new Complex(0.0, 1.0); double sectorSize = twoPi / numberofsectors; Complex[] Sector = new Complex[numberofsectors]; for (int i = 0; i < numberofsectors; i++) { double angSector = twoPi * i / numberofsectors; Sector[i] = Complex.Exp(complex1 * angSector); } int numberOfOutputs = networkSize[layer - 1]; int rowInputs = samples.GetLength(0); int colInputs = samples.GetLength(1) / 2; // Desired outputs byte[,] desiredOutputs = new byte[rowInputs, colInputs]; for (int i = 0; i < rowInputs; i++) for (int j = 0; j < colInputs; j++) desiredOutputs[i, j] = samples[i, j + colInputs]; // end for loops // Resized Inputs byte[,] inputs = new byte[rowInputs, colInputs]; for (int i = 0; i < rowInputs; i++) for (int j = 0; j < colInputs; j++) inputs[i, j] = samples[i, j]; // end for loops Complex[,] Cinputs = new Complex[rowInputs, colInputs]; int[,] networkOutputs = new int[rowInputs, colInputs]; //for (int i = 0; i < rowInputs; i++) // for (int j = 0; j < colInputs; j++) // networkOutputs[i, j] = new Complex(0, 0); // end double[] networkErrors = new double[rowInputs]; Complex[][] neuronOutputs = new Complex[layer][]; // instanciate a jagged array to store outputs for (int i = 0; i < layer; i++) neuronOutputs[i] = new Complex[networkSize[i]]; // end for double[] dNeuronOutputs = new double[networkSize[layer - 1]]; Complex[][] neuronErrors = neuronOutputs; Complex[][] weightedSum = new Complex[layer][]; // instanciate a jagged array to store outputs for (int i = 0; i < layer; i++) weightedSum[i] = new Complex[networkSize[i]]; // end for Complex sum = new Complex(0, 0); // transformation of inputs into complex plane for (int i = 0; i < rowInputs; i++) for (int j = 0; j < colInputs; j++) Cinputs[i, j] = Exp(complex1 * 2 * Math.PI * inputs[i, j] / numberofsectors); // end nested for loop // initialize error criteria double mse = 0; double rmse = 0; double[] learningRate; // check if learning is finished bool finishedLearning = false; // counts each cycle int iteration = 0; // output calculation Complex[,] temp; Complex[,] a1; Complex[] b1; Complex[] c1; Complex d1; Complex[,] e1; Complex[,] f1; form1.SetText2("Beginning the learning of the weights...\r\n" + Environment.NewLine); #endregion #region RMSE ALGORITHM // repeats process until learning converges while (!finishedLearning) { // increment iteration iteration++; // --------------- BEGIN OUTPUT CALCULATION ------------------------------ #region OUTPUT CALCULATION // process each samples for (int aa = 0; aa < numberOfInputSamples; aa++) // for each row { #region calculate weighted sum of first layer and its activation // process first layer int ii = 0; // calculate weighted sum & activation for (int i = 0; i < networkSize[0]; i++) { for (int j = 1; j < inputsPerSample[0]; j++) { sum = sum + weights[ii][i, j] * Cinputs[aa, j - 1]; } sum = sum + weights[ii][i, 0]; neuronOutputs[ii][i] = sum; //weightedSum[ii][i] = sum; sum = new Complex(0, 0); } // end for // apply continuous activation for (int t = 0; t < networkSize[ii]; t++) neuronOutputs[ii][t] /= Complex.Abs(neuronOutputs[ii][t]); // end for #endregion #region calculate weighted sum of second to last layer // ----------------- Process second to last hidden layers --------------- for (ii = 1; ii < layer - 1; ii++) { for (int i = 0; i < networkSize[ii]; i++) { for (int j = 1; j < inputsPerSample[ii]; j++) { sum = sum + weights[ii][i, j] * neuronOutputs[ii - 1][j - 1]; } sum = sum + weights[ii][i, 0]; neuronOutputs[ii][i] = sum; //weightedSum[ii][i] = sum; sum = new Complex(0, 0); } // end for // apply contiunous activation for (int t = 0; t < networkSize[ii]; t++) neuronOutputs[ii][t] /= Complex.Abs(neuronOutputs[ii][t]); // end for } // end for ii // ----------------- Process output layer -------------------------------- ii = layer - 1; // set to last layer // calculate the weighted sum for (int i = 0; i < networkSize[ii]; i++) { for (int j = 1; j < inputsPerSample[ii]; j++) { sum = sum + weights[ii][i, j] * neuronOutputs[ii - 1][j - 1]; } sum = sum + weights[ii][i, 0]; neuronOutputs[ii][i] = sum; //weightedSum[ii][i] = sum; sum = new Complex(0, 0); } // end for for (int jj = 0; jj < networkSize[ii]; jj++) { // calculate discrete output // get angle dNeuronOutputs[jj] = Math.Atan2(neuronOutputs[ii][jj].Imaginary, neuronOutputs[ii][jj].Real); // if output is less than 0, add 2 pi to make it positive if (dNeuronOutputs[jj] < 0) dNeuronOutputs[jj] = 2 * Math.PI + dNeuronOutputs[jj]; // end if // round dNeuronOutputs[jj] = Math.Truncate(dNeuronOutputs[jj] / sectorSize); //dOutputNeurons[jj] = Math.Floor(dOutputNeurons[jj]/bb); // convert results to byte... did not work correctly, because it could be more than 255. So let it be integer. networkOutputs[aa, jj] = Convert.ToInt32(dNeuronOutputs[jj]); } // end for #endregion second to last layer } // end row for loop #endregion // -------------- END OUTPUT CALCULATION ----------------------------- // -------------- BEGIN NET ERROR CALCULATION ------------------------ #region GLOBAL ERROR CALCULATION // calculate NET error for (int aa = 0; aa < numberOfInputSamples; aa++) { for (int i = 0; i < colInputs; i++) { networkErrors[aa] += Math.Pow((networkOutputs[aa, i] - desiredOutputs[aa, i]), 2); } networkErrors[aa] /= numberOfOutputs; mse += networkErrors[aa]; } // end for aa // calculate mse mse /= numberOfInputSamples; // calculate rmse rmse = Math.Sqrt(mse); form1.SetText2("Iteration " + iteration + " done. RMSE: " + rmse + Environment.NewLine); // Check if learning has converged TaskbarManager.Instance.SetProgressState(TaskbarProgressBarState.Indeterminate); // Action when cancel button is clicked if (cancelToken.IsCancellationRequested) cancelToken.ThrowIfCancellationRequested(); // Action when pause button is clicked await pauseToken.WaitWhilePausedAsync(); if (rmse <= globalThreasholdValue) { finishedLearning = true; form1.SetText2("\r\nLearning Converged!!!" + Environment.NewLine); } // end if #endregion // --------------- BEGIN LEARNING / MODIFICATION OF WEIGHTS --------------------------- // LEARNING / MODIFICATION OF WEIGHTS // if the algorithm has not finished learning then output of the // network needs to be calculated again to start correction of // errors #region OUTPUT CALCULATION if (!finishedLearning) { // calculating the output of the network for each sample and // correcting weights if output is > localThresholdValue for (int aa = 0; aa < numberOfInputSamples; aa++) // for each row { #region calculate weighted sum of first layer and its activation // ii holds current layer index. Process first layer int ii = 0; // calculate weighted sum for 1st hidden layer for (int i = 0; i < networkSize[ii]; i++) { for (int j = 1; j < inputsPerSample[ii]; j++) { sum = sum + weights[ii][i, j] * Cinputs[aa, j - 1]; // <-- 7.2 of processing done here } sum = sum + weights[ii][i, 0]; //neuronOutputs[ii][i] = sum; weightedSum[ii][i] = sum; sum = new Complex(0, 0); } // end for // apply continuous activation for (int t = 0; t < networkSize[ii]; t++) neuronOutputs[ii][t] = weightedSum[ii][t] / Complex.Abs(weightedSum[ii][t]); // end for #endregion #region calculate weighted sum of second to last hidden layer // ----------------- Process second to last hidden layers, then output layer // ii holds current layer for (ii = 1; ii < layer - 1; ii++) { for (int i = 0; i < networkSize[ii]; i++) { for (int j = 1; j < inputsPerSample[ii]; j++) { sum = sum + weights[ii][i, j] * neuronOutputs[ii - 1][j - 1]; } sum = sum + weights[ii][i, 0]; //neuronOutputs[ii][i] = sum; weightedSum[ii][i] = sum; sum = new Complex(0, 0); } // end for // apply continuous activation for (int t = 0; t < networkSize[ii]; t++) neuronOutputs[ii][t] = weightedSum[ii][t] / Complex.Abs(weightedSum[ii][t]); // end for } // end for ii #endregion #region calculate output layer and network output calculation // output layer ii = layer - 1; // set to last layer // calculate the weighted sum for (int i = 0; i < networkSize[ii]; i++) { for (int j = 1; j < inputsPerSample[ii]; j++) { sum = sum + weights[ii][i, j] * neuronOutputs[ii - 1][j - 1]; // <-- 5.8 of processing is done here } sum = sum + weights[ii][i, 0]; neuronOutputs[ii][i] = sum; weightedSum[ii][i] = sum; sum = new Complex(0, 0); } // end for // apply the activation function for discrete outputs for (int jj = 0; jj < networkSize[ii]; jj++) { // Action when cancel button is clicked if (cancelToken.IsCancellationRequested) cancelToken.ThrowIfCancellationRequested(); // Action when pause button is clicked await pauseToken.WaitWhilePausedAsync(); // calculate discrete output // get angle dNeuronOutputs[jj] = Math.Atan2(weightedSum[ii][jj].Imaginary, weightedSum[ii][jj].Real); // if output is less than 0, add 2 pi to make it positive if (dNeuronOutputs[jj] < 0) dNeuronOutputs[jj] = 2 * Math.PI + dNeuronOutputs[jj]; // end if // round dNeuronOutputs[jj] = Math.Truncate(dNeuronOutputs[jj] / sectorSize); //dOutputNeurons[jj] = Math.Floor(dOutputNeurons[jj]/bb); // convert results to byte... did not work correctly, because it could be more than 255. So let it be integer. networkOutputs[aa, jj] = Convert.ToInt32(dNeuronOutputs[jj]); } // end for #endregion second to last layer #region R/MSE SPECIFIC CALCULATION OF ERROR // calculate NET error for (int i = 0; i < colInputs; i++) { networkErrors[aa] += Math.Pow((networkOutputs[aa, i]) - desiredOutputs[aa, i], 2); } networkErrors[aa] /= numberOfOutputs; // calculate rmse networkErrors[aa] = Math.Sqrt(networkErrors[aa]); #endregion #region Weights Modification // check agains local threshold // if localThresholdValue is greater, then the weights are corrected if (localThresholdValue < networkErrors[aa]) { // Action when cancel button is clicked if (cancelToken.IsCancellationRequested) cancelToken.ThrowIfCancellationRequested(); // Action when pause button is clicked await pauseToken.WaitWhilePausedAsync(); #region ERROR CALCULATION // CALCULATE THE ERROR OF THE NEURONS // calculation of the errors of neurons starts at last layer // and moves to first layer ii = layer - 1; // outputs will contain normalized weighted sums for all output neurons for (int t = 0; t < networkSize[ii]; t++) neuronOutputs[ii][t] = weightedSum[ii][t] / Complex.Abs(weightedSum[ii][t]); // end for // the global error for the jjj-th output neuron // equals a root of unity corresponding to the // desired output - normalized weighted sum for // the corresponding output neuron for (int jjj = 0; jjj < networkSize[ii]; jjj++) neuronErrors[ii][jjj] = Sector[desiredOutputs[aa, jjj]] - neuronOutputs[ii][jjj]; // end for // finally we obtain the output neurons' errors // normalizing the global errors (dividing them // by the (number of neurons in the preceding // layer+1) for (int t = 0; t < networkSize[ii]; t++) neuronErrors[ii][t] = neuronErrors[ii][t] / (networkSize[ii - 1] + 1); // end for // ------------- HANDLING THE REST OF LAYERS - ERROR BACKPROPAGATION ------------ for (ii = layer - 2; -1 < ii; ii--) { // calculate the reciprocal weights for the layer ii and putting them in // a vector-row temp = new Complex[weights[ii + 1].GetLength(1) - 1, weights[ii + 1].GetLength(0)]; for (int i = 1; i < temp.GetLength(0) + 1; i++) //511 for (int j = 0; j < temp.GetLength(1); j++) //169 temp[i - 1, j] = 1 / weights[ii + 1][j, i]; // <-- 23.5 of processing done here //end fors // confirmed bug free above this point... 5/2/2014 0:48 sum = new Complex(0, 0); // backpropagation of weights if (0 < ii) // all hidden layers except the 1st for (int row = 0; row < temp.GetLength(0); row++) { for (int col = 0; col < temp.GetLength(1); col++) { sum = sum + temp[row, col] * neuronErrors[ii + 1][col]; } neuronErrors[ii][row] = sum / (networkSize[ii - 1] + 1); sum = new Complex(0, 0); // end for } // end for else for (int row = 0; row < temp.GetLength(0); row++) { for (int col = 0; col < temp.GetLength(1); col++) { sum = sum + temp[row, col] * neuronErrors[ii + 1][col]; } neuronErrors[ii][row] = sum / (inputsPerSample[0]); sum = new Complex(0, 0); // end for } // end for // end if } // end ii for loop over the layers #endregion #region WEIGHTS CORRECTION // -------------- CORRECTS THE WEIGHTS OF THE NETWORK ---------------------------------- // HANDLING THE 1ST HIDDEN LAYER // learning rate is a reciprocal absolute value of the weighted sum learningRate = new double[weightedSum[0].GetLength(0)]; for (int i = 0; i < learningRate.GetLength(0); i++) learningRate[i] = (1 / Complex.Abs(weightedSum[0][i])); // end for // take learning rate into account // for all weights except bias w0 for (int row = 0; row < networkSize[0]; row++) for (int col = 1; col < inputsPerSample[0]; col++) weights[0][row, col] = weights[0][row, col] + (learningRate[row] * neuronErrors[0][row]) * Complex.Conjugate(Cinputs[aa, col - 1]); // end for for (int row = 0; row < networkSize[0]; row++) weights[0][row, 0] = weights[0][row, 0] + (learningRate[row] * neuronErrors[0][row]); // end for // correct the following layers for (ii = 1; ii < layer; ii++) { sum = new Complex(0, 0); // calculate the new output of preceding layer // if preceding layer is the 1st one if (ii == 1) { // calculate weighted sum for (int i = 0; i < networkSize[0]; i++) { for (int j = 1; j < inputsPerSample[0]; j++) { sum = sum + weights[0][i, j] * Cinputs[aa, j - 1]; } sum = sum + weights[0][i, 0]; weightedSum[0][i] = sum; sum = new Complex(0, 0); } // end for } // end if else // if a preceding layer is not the 1st one { // calculate weighted sum & activation for (int i = 0; i < networkSize[ii - 1]; i++) { for (int j = 1; j < inputsPerSample[ii - 1]; j++) { sum = sum + weights[ii - 1][i, j] * neuronOutputs[ii - 2][j - 1]; } sum = sum + weights[ii - 1][i, 0]; weightedSum[ii - 1][i] = sum; sum = new Complex(0, 0); } // end for } // end if // CONTINUOUS OUTPUT CALCULATION for (int t = 0; t < networkSize[ii - 1]; t++) neuronOutputs[ii - 1][t] = weightedSum[ii - 1][t] / Complex.Abs(weightedSum[ii - 1][t]); // end for // learning rate is the reciprocal absolute value of the weighted sum learningRate = new double[weightedSum[ii].GetLength(0)]; for (int i = 0; i < learningRate.GetLength(0); i++) learningRate[i] = (1 / Complex.Abs(weightedSum[ii][i])); // end for // learning rate not used for the output layer neurons if (ii < layer) // <-- ~10 of processing done here (partly due to complex calculations) { // do last things a1 = (Complex[,])weights[ii].Clone(); b1 = (Complex[])neuronErrors[ii].Clone(); for (int i = 0; i < b1.GetLength(0); i++) b1[i] = b1[i] * learningRate[i]; // end for c1 = (Complex[])neuronOutputs[ii - 1].Clone(); for (int i = 0; i < c1.GetLength(0); i++) c1[i] = Complex.Conjugate(c1[i]); // end for e1 = (Complex[,])a1.Clone(); for (int i = 0; i < networkSize[ii]; i++) { d1 = b1[i]; for (int j = 1; j < a1.GetLength(1); j++) e1[i, j] = d1 * c1[j - 1]; } f1 = new Complex[a1.GetLength(0), a1.GetLength(1) - 1]; for (int i = 0; i < a1.GetLength(0); i++) for (int j = 1; j < a1.GetLength(1); j++) f1[i, j - 1] = a1[i, j] + e1[i, j]; // end for for (int i = 0; i < weights[ii].GetLength(0); i++) for (int j = 1; j < weights[ii].GetLength(1); j++) weights[ii][i, j] = f1[i, j - 1]; // end for for (int i = 0; i < weights[ii].GetLength(0); i++) weights[ii][i, 0] = weights[ii][i, 0] + (learningRate[i] * neuronErrors[ii][i]); // end for } else { // do last things a1 = (Complex[,])weights[ii].Clone(); b1 = (Complex[])neuronErrors[ii].Clone(); c1 = (Complex[])neuronOutputs[ii - 1].Clone(); for (int i = 0; i < c1.GetLength(0); i++) c1[i] = Complex.Conjugate(c1[i]); // end for e1 = (Complex[,])a1.Clone(); for (int i = 0; i < networkSize[ii]; i++) { d1 = b1[i]; for (int j = 1; j < a1.GetLength(1); j++) e1[i, j] = d1 * c1[j - 1]; } f1 = new Complex[a1.GetLength(0), a1.GetLength(1) - 1]; for (int i = 0; i < a1.GetLength(0); i++) for (int j = 1; j < a1.GetLength(1); j++) f1[i, j - 1] = a1[i, j] + e1[i, j]; // end for for (int i = 0; i < weights[ii].GetLength(0); i++) for (int j = 1; j < weights[ii].GetLength(1); j++) weights[ii][i, j] = f1[i, j - 1]; // end for for (int i = 0; i < weights[ii].GetLength(0); i++) weights[ii][i, 0] = weights[ii][i, 0] + neuronErrors[ii][i]; // end for } // end if } // end ii for #endregion #endregion } // end localThresholdValue if check } // end aa for loop } // end ~finishedLearning if statement #endregion }// end ~finishedLearning while loop #endregion return weights; }