/// <summary> /// Solves the SMO considering no previous knowledge about the problem /// </summary> /// <param name="problemSolution">Solution of the problem</param> /// <returns>Solution of the problem with alphas and threshold</returns> public static SVM solveSMOStartingFromZero(SVM problemSolution) { problemSolution.initializeWithZeros(); // Solve it return(solveSMOStartingFromPreviousSolution(problemSolution)); }
/// <summary> /// Solves the SMO considering no previous knowledge about the problem /// </summary> /// <param name="problemSolution">Solution of the problem</param> /// <returns>Solution of the problem with alphas and threshold</returns> public static SVM solveSMOStartingFromZero(SVM problemSolution) { problemSolution.initializeWithZeros(); // Solve it return solveSMOStartingFromPreviousSolution(problemSolution); }
/// <summary> /// Solves the SMO considering no previous knowledge about the problem /// </summary> /// <param name="problemSolution">Known solution</param> /// <returns>Solution of the problem with alphas and threshold</returns> public static SVM solveSMOStartingFromPreviousSolution(SVM problemSolution) { System.Diagnostics.Stopwatch swTotalTime = new System.Diagnostics.Stopwatch(); System.Diagnostics.Stopwatch swHeuristica = new System.Diagnostics.Stopwatch(); System.Diagnostics.Stopwatch swComputeKernel = new System.Diagnostics.Stopwatch(); System.Diagnostics.Stopwatch swUpdateError = new System.Diagnostics.Stopwatch(); swTotalTime.Start(); ProblemConfig problemConfig = problemSolution.ProblemCfg; if (problemSolution.alphaList == null) problemSolution.initializeWithZeros(); ProblemSolver.calculateErrors(problemSolution); //Initializes GPU error vector if (OpenCLTemplate.CLCalc.CLAcceleration == OpenCLTemplate.CLCalc.CLAccelerationType.UsingCL) WriteCLErr(problemSolution); TrainingSet trainingSet = problemSolution.TrainingSet; int passes = 0; int m = trainingSet.getN; while (passes < problemConfig.maxPasses) { int changedAlphas = 0; for (int i = 0; i < m; i++) { float yi = trainingSet.trainingArray[i].y; float alpha_i = problemSolution.alphaList[i]; // Error between the SVM output on the ith training unit and the true ith output float ei = trainingSet.errors[i]; // KKT conditions for ith element if ( ((yi * ei < -problemConfig.tol && alpha_i < problemConfig.c) || (yi * ei > problemConfig.tol && alpha_i > 0)) ) { swHeuristica.Start(); #region Computes J using maximum variation heuristics // Get a number from 0 to m - 1 not equal to i int j = 0; if (trainingSet.errors[i] >= 0) { if (OpenCLTemplate.CLCalc.CLAcceleration == OpenCLTemplate.CLCalc.CLAccelerationType.UsingCL) { j = CLFindMinError(problemSolution); } else { float minError = trainingSet.errors[0]; for (int k = 1; k < trainingSet.getN; k++) { if (minError > trainingSet.errors[k]) { minError = trainingSet.errors[k]; j = k; } } } } else { if (OpenCLTemplate.CLCalc.CLAcceleration == OpenCLTemplate.CLCalc.CLAccelerationType.UsingCL) { j = CLFindMaxError(problemSolution); } else { float maxError = trainingSet.errors[0]; for (int k = 1; k < trainingSet.getN; k++) { if (maxError < trainingSet.errors[k]) { maxError = trainingSet.errors[k]; j = k; } } } } #endregion swHeuristica.Stop(); float yj = trainingSet.trainingArray[j].y; float alpha_j = problemSolution.alphaList[j]; // Error between the SVM output on the jth training unit and the true jth output float ej = trainingSet.errors[j]; // Save old alphas float oldAlpha_i = problemSolution.alphaList[i]; float oldAlpha_j = problemSolution.alphaList[j]; #region Compute lower and higher bounds of alpha_j float lowerBound; float higherBound; if (yi != yj) { lowerBound = Math.Max(0, alpha_j - alpha_i); higherBound = Math.Min(problemConfig.c, problemConfig.c + alpha_j - alpha_i); } else { lowerBound = Math.Max(0, alpha_j + alpha_i - problemConfig.c); higherBound = Math.Min(problemConfig.c, alpha_j + alpha_i); } #endregion // Nothing to adjust if we can't set any value between those bounds if (lowerBound == higherBound) continue; #region Compute eta float kernel_xi_xj; float kernel_xi_xi; float kernel_xj_xj; if (trainingSet.IsKernelCalculated[i]) kernel_xi_xj = trainingSet.kernels[i][j]; else if (trainingSet.IsKernelCalculated[j]) kernel_xi_xj = trainingSet.kernels[j][i]; else kernel_xi_xj = calculateSingleKernel(trainingSet.trainingArray[i], trainingSet.trainingArray[j], problemSolution);//trainingSet.kernels[i][j]; if (trainingSet.IsKernelCalculated[i]) kernel_xi_xi = trainingSet.kernels[i][i]; else kernel_xi_xi = calculateSingleKernel(trainingSet.trainingArray[i], trainingSet.trainingArray[i], problemSolution);//trainingSet.kernels[i][i]; if (trainingSet.IsKernelCalculated[j]) kernel_xj_xj = trainingSet.kernels[j][j]; else kernel_xj_xj = calculateSingleKernel(trainingSet.trainingArray[j], trainingSet.trainingArray[j], problemSolution);//trainingSet.kernels[j][j]; float eta = 2 * kernel_xi_xj - kernel_xi_xi - kernel_xj_xj; #endregion if (eta >= 0) continue; // Compute new alpha_j alpha_j = alpha_j - yj * (ei - ej) / eta; // Clip alpha_j if necessary if (alpha_j > higherBound) alpha_j = higherBound; else if (alpha_j < lowerBound) alpha_j = lowerBound; // If the changes are not big enough, just continue if (Math.Abs(oldAlpha_j - alpha_j) < MIN_ALPHA_CHANGE) continue; swComputeKernel.Start(); //Needs to compute lines K[i][] and K[j][] since the alphas will change if (OpenCLTemplate.CLCalc.CLAcceleration == OpenCLTemplate.CLCalc.CLAccelerationType.UsingCL) { CLComputeKernels(problemSolution, i); CLComputeKernels(problemSolution, j); } else { ComputeKernels(problemSolution, i); ComputeKernels(problemSolution, j); } swComputeKernel.Stop(); // Compute value for alpha_i alpha_i = alpha_i + yi * yj * (oldAlpha_j - alpha_j); // Compute b1, b2 and new b (threshold) float oldB = problemSolution.b; if (0 < alpha_i && alpha_i < problemConfig.c) { // b1 is enough in this case float b1 = problemSolution.b - ei - yi * (alpha_i - oldAlpha_i) * kernel_xi_xi - yj * (alpha_j - oldAlpha_j) * kernel_xi_xj; problemSolution.b = b1; } else if (0 < alpha_j && alpha_j < problemConfig.c) { // b2 is enough in this case float b2 = problemSolution.b - ej - yi * (alpha_i - oldAlpha_i) * kernel_xi_xj - yj * (alpha_j - oldAlpha_j) * kernel_xj_xj; problemSolution.b = b2; } else { // b is the average between b1 and b2 float b1 = problemSolution.b - ei - yi * (alpha_i - oldAlpha_i) * kernel_xi_xi - yj * (alpha_j - oldAlpha_j) * kernel_xi_xj; float b2 = problemSolution.b - ej - yi * (alpha_i - oldAlpha_i) * kernel_xi_xj - yj * (alpha_j - oldAlpha_j) * kernel_xj_xj; problemSolution.b = (b1 + b2) * 0.5f; } // Update the changed alphas in the solution problemSolution.alphaList[i] = alpha_i; problemSolution.alphaList[j] = alpha_j; // Update errors cache swUpdateError.Start(); if (OpenCLTemplate.CLCalc.CLAcceleration == OpenCLTemplate.CLCalc.CLAccelerationType.UsingCL) CLupdateErrorsCache(trainingSet, problemSolution, oldAlpha_i, alpha_i, i, oldAlpha_j, alpha_j, j, oldB, problemSolution.b); else updateErrorsCache(trainingSet, problemSolution, oldAlpha_i, alpha_i, i, oldAlpha_j, alpha_j, j, oldB, problemSolution.b); swUpdateError.Stop(); changedAlphas++; } } if (changedAlphas == 0) { passes++; } else { passes = 0; } } return problemSolution; }
/// <summary> /// Solves the SMO considering no previous knowledge about the problem /// </summary> /// <param name="problemSolution">Known solution</param> /// <returns>Solution of the problem with alphas and threshold</returns> public static SVM solveSMOStartingFromPreviousSolution(SVM problemSolution) { System.Diagnostics.Stopwatch swTotalTime = new System.Diagnostics.Stopwatch(); System.Diagnostics.Stopwatch swHeuristica = new System.Diagnostics.Stopwatch(); System.Diagnostics.Stopwatch swComputeKernel = new System.Diagnostics.Stopwatch(); System.Diagnostics.Stopwatch swUpdateError = new System.Diagnostics.Stopwatch(); swTotalTime.Start(); ProblemConfig problemConfig = problemSolution.ProblemCfg; if (problemSolution.alphaList == null) { problemSolution.initializeWithZeros(); } ProblemSolver.calculateErrors(problemSolution); //Initializes GPU error vector if (OpenCLTemplate.CLCalc.CLAcceleration == OpenCLTemplate.CLCalc.CLAccelerationType.UsingCL) { WriteCLErr(problemSolution); } TrainingSet trainingSet = problemSolution.TrainingSet; int passes = 0; int m = trainingSet.getN; while (passes < problemConfig.maxPasses) { int changedAlphas = 0; for (int i = 0; i < m; i++) { float yi = trainingSet.trainingArray[i].y; float alpha_i = problemSolution.alphaList[i]; // Error between the SVM output on the ith training unit and the true ith output float ei = trainingSet.errors[i]; // KKT conditions for ith element if ( ((yi * ei < -problemConfig.tol && alpha_i < problemConfig.c) || (yi * ei > problemConfig.tol && alpha_i > 0)) ) { swHeuristica.Start(); #region Computes J using maximum variation heuristics // Get a number from 0 to m - 1 not equal to i int j = 0; if (trainingSet.errors[i] >= 0) { if (OpenCLTemplate.CLCalc.CLAcceleration == OpenCLTemplate.CLCalc.CLAccelerationType.UsingCL) { j = CLFindMinError(problemSolution); } else { float minError = trainingSet.errors[0]; for (int k = 1; k < trainingSet.getN; k++) { if (minError > trainingSet.errors[k]) { minError = trainingSet.errors[k]; j = k; } } } } else { if (OpenCLTemplate.CLCalc.CLAcceleration == OpenCLTemplate.CLCalc.CLAccelerationType.UsingCL) { j = CLFindMaxError(problemSolution); } else { float maxError = trainingSet.errors[0]; for (int k = 1; k < trainingSet.getN; k++) { if (maxError < trainingSet.errors[k]) { maxError = trainingSet.errors[k]; j = k; } } } } #endregion swHeuristica.Stop(); float yj = trainingSet.trainingArray[j].y; float alpha_j = problemSolution.alphaList[j]; // Error between the SVM output on the jth training unit and the true jth output float ej = trainingSet.errors[j]; // Save old alphas float oldAlpha_i = problemSolution.alphaList[i]; float oldAlpha_j = problemSolution.alphaList[j]; #region Compute lower and higher bounds of alpha_j float lowerBound; float higherBound; if (yi != yj) { lowerBound = Math.Max(0, alpha_j - alpha_i); higherBound = Math.Min(problemConfig.c, problemConfig.c + alpha_j - alpha_i); } else { lowerBound = Math.Max(0, alpha_j + alpha_i - problemConfig.c); higherBound = Math.Min(problemConfig.c, alpha_j + alpha_i); } #endregion // Nothing to adjust if we can't set any value between those bounds if (lowerBound == higherBound) { continue; } #region Compute eta float kernel_xi_xj; float kernel_xi_xi; float kernel_xj_xj; if (trainingSet.IsKernelCalculated[i]) { kernel_xi_xj = trainingSet.kernels[i][j]; } else if (trainingSet.IsKernelCalculated[j]) { kernel_xi_xj = trainingSet.kernels[j][i]; } else { kernel_xi_xj = calculateSingleKernel(trainingSet.trainingArray[i], trainingSet.trainingArray[j], problemSolution); //trainingSet.kernels[i][j]; } if (trainingSet.IsKernelCalculated[i]) { kernel_xi_xi = trainingSet.kernels[i][i]; } else { kernel_xi_xi = calculateSingleKernel(trainingSet.trainingArray[i], trainingSet.trainingArray[i], problemSolution); //trainingSet.kernels[i][i]; } if (trainingSet.IsKernelCalculated[j]) { kernel_xj_xj = trainingSet.kernels[j][j]; } else { kernel_xj_xj = calculateSingleKernel(trainingSet.trainingArray[j], trainingSet.trainingArray[j], problemSolution); //trainingSet.kernels[j][j]; } float eta = 2 * kernel_xi_xj - kernel_xi_xi - kernel_xj_xj; #endregion if (eta >= 0) { continue; } // Compute new alpha_j alpha_j = alpha_j - yj * (ei - ej) / eta; // Clip alpha_j if necessary if (alpha_j > higherBound) { alpha_j = higherBound; } else if (alpha_j < lowerBound) { alpha_j = lowerBound; } // If the changes are not big enough, just continue if (Math.Abs(oldAlpha_j - alpha_j) < MIN_ALPHA_CHANGE) { continue; } swComputeKernel.Start(); //Needs to compute lines K[i][] and K[j][] since the alphas will change if (OpenCLTemplate.CLCalc.CLAcceleration == OpenCLTemplate.CLCalc.CLAccelerationType.UsingCL) { CLComputeKernels(problemSolution, i); CLComputeKernels(problemSolution, j); } else { ComputeKernels(problemSolution, i); ComputeKernels(problemSolution, j); } swComputeKernel.Stop(); // Compute value for alpha_i alpha_i = alpha_i + yi * yj * (oldAlpha_j - alpha_j); // Compute b1, b2 and new b (threshold) float oldB = problemSolution.b; if (0 < alpha_i && alpha_i < problemConfig.c) { // b1 is enough in this case float b1 = problemSolution.b - ei - yi * (alpha_i - oldAlpha_i) * kernel_xi_xi - yj * (alpha_j - oldAlpha_j) * kernel_xi_xj; problemSolution.b = b1; } else if (0 < alpha_j && alpha_j < problemConfig.c) { // b2 is enough in this case float b2 = problemSolution.b - ej - yi * (alpha_i - oldAlpha_i) * kernel_xi_xj - yj * (alpha_j - oldAlpha_j) * kernel_xj_xj; problemSolution.b = b2; } else { // b is the average between b1 and b2 float b1 = problemSolution.b - ei - yi * (alpha_i - oldAlpha_i) * kernel_xi_xi - yj * (alpha_j - oldAlpha_j) * kernel_xi_xj; float b2 = problemSolution.b - ej - yi * (alpha_i - oldAlpha_i) * kernel_xi_xj - yj * (alpha_j - oldAlpha_j) * kernel_xj_xj; problemSolution.b = (b1 + b2) * 0.5f; } // Update the changed alphas in the solution problemSolution.alphaList[i] = alpha_i; problemSolution.alphaList[j] = alpha_j; // Update errors cache swUpdateError.Start(); if (OpenCLTemplate.CLCalc.CLAcceleration == OpenCLTemplate.CLCalc.CLAccelerationType.UsingCL) { CLupdateErrorsCache(trainingSet, problemSolution, oldAlpha_i, alpha_i, i, oldAlpha_j, alpha_j, j, oldB, problemSolution.b); } else { updateErrorsCache(trainingSet, problemSolution, oldAlpha_i, alpha_i, i, oldAlpha_j, alpha_j, j, oldB, problemSolution.b); } swUpdateError.Stop(); changedAlphas++; } } if (changedAlphas == 0) { passes++; } else { passes = 0; } } return(problemSolution); }