/// <summary> /// /// Scala listę kroków stosując średnią ważoną gdzie wagą jest długość kroku /// </summary> /// <param name="st1"></param> /// <param name="newAlphas"></param> /// <param name="a1"></param> /// <param name="modAlphas">new merged alpha</param> /// <param name="weighSum"></param> /// <returns>average value for a1</returns> private float WeightedDistMerge(AlphaInfo st1, List <StepPairVariable> newAlphas, AlphaInfo[] modAlphas) { int size = modAlphas.Length; float weighSum = 0; float a1 = 0f; float[] weights = new float[size]; modAlphas[0] = new AlphaInfo(st1.Index, 0, st1.Y, st1.Error, st1.Product); for (int k = 1; k < size; k++) { var secAlpha = newAlphas[k - 1].Second; modAlphas[k] = new AlphaInfo(secAlpha.Index, 0, secAlpha.Y, secAlpha.Error, secAlpha.Product); var it = newAlphas[k - 1]; //we compute change in distance for two alphas float sq1 = it.First.Alpha - alpha[it.First.Index]; sq1 *= sq1; float sq2 = it.Second.Alpha - alpha[it.Second.Index]; sq2 *= sq2; weights[k] = sq1 + sq2; weighSum += weights[k]; } weighSum = Math.Abs(weighSum); a1 = MergeWithWeight(newAlphas, modAlphas, weighSum, weights); return(a1); }
private float AvgMerge(AlphaInfo st1, List <StepPairVariable> newAlphas, AlphaInfo[] modAlphas) { int size = modAlphas.Length; float weighSum = 0; float a1 = 0f; modAlphas[0] = new AlphaInfo(st1.Index, 0, st1.Y, st1.Error, st1.Product); float[] weights = new float[size]; float weight = 1.0f / newAlphas.Count; for (int k = 1; k < size; k++) { var secAlpha = newAlphas[k - 1].Second; modAlphas[k] = new AlphaInfo(secAlpha.Index, 0, secAlpha.Y, secAlpha.Error, secAlpha.Product); weights[k] = weight; } weighSum = 1; a1 = MergeWithWeight(newAlphas, modAlphas, weighSum, weights); return(a1); }
/// <summary> /// /// </summary> /// <param name="i1">index for first alpha</param> /// <param name="E1">decision error for first alpah</param> /// <param name="y1">label coresponding to first alpha</param> /// <param name="alph1">alpha</param> /// <param name="i2">index second alpha</param> /// <returns></returns> private StepPairVariable ComputeAlphaStep(AlphaInfo step1, int i2) { float y1 = 0, y2 = 0, s = 0; float alph1, alph2 = 0; /* old_values of alpha_1, alpha_2 */ float a1 = 0, a2 = 0; /* new values of alpha_1, alpha_2 */ float E1 = 0, E2 = 0, //error for second alpha L = 0, H = 0, //lower upper bounds k11 = 0, k22 = 0, k12 = 0, //kernel products eta = 0, // step taken, Lobj = 0, Hobj = 0; int i1 = step1.Index; if (i1 == i2) { return(null); // no step taken } alph1 = step1.Alpha; y1 = step1.Y; E1 = step1.Error; alph2 = alpha[i2]; y2 = problem.Y[i2]; E2 = ErrorForAlpha(i2); s = y1 * y2; //compute bounds if (y1 == y2) { float gamma = alph1 + alph2; if (gamma > C) { L = gamma - C; H = C; } else { L = 0; H = gamma; } } else { float gamma = alph2 - alph1; if (gamma > 0) { L = gamma; H = C; } else { L = 0; H = C - gamma; } } if (L == H) { return(null); // no step take } k11 = step1.Product; k12 = Product(i1, i2); k22 = Product(i2, i2); eta = 2 * k12 - k11 - k22; if (eta < 0) { //original version with plus //a2 = alph2 + y2 * (E2 - E1) / eta; a2 = alph2 - y2 * (E1 - E2) / eta; if (a2 < L) { a2 = L; } else if (a2 > H) { a2 = H; } } else { { float c1 = eta / 2; float c2 = y2 * (E1 - E2) - eta * alph2; Lobj = c1 * L * L + c2 * L; Hobj = c1 * H * H + c2 * H; } if (Lobj > Hobj + epsilon) { a2 = L; } else if (Lobj < Hobj - epsilon) { a2 = H; } else { a2 = alph2; } } if (Math.Abs(a2 - alph2) < epsilon * (a2 + alph2 + epsilon)) { return(null); // no step taken } a1 = alph1 - s * (a2 - alph2); if (a1 < 0) { a2 += s * a1; a1 = 0; } else if (a1 > C) { float t = a1 - C; a2 += s * t; a1 = C; } var st1 = new AlphaInfo(i1, a1, y1, E1, k11); var st2 = new AlphaInfo(i2, a2, y2, E2, k22); return(new StepPairVariable(st1, st2, k12, s, eta)); }
private AlphaInfo[] MergeSteps(AlphaInfo st1, List <StepPairVariable> newAlphas) { //a1 - new alpha, alpha1-old alpha float a1 = 0f, alpha1 = 0; int index1 = st1.Index; float y1 = st1.Y; alpha1 = alpha[st1.Index]; float k11 = st1.Product, E1 = st1.Error; int size = newAlphas.Count + 1; AlphaInfo[] modAlphas = new AlphaInfo[size]; a1 = WeightedEtaMerge(st1, newAlphas, modAlphas); //a1 = WeightedSmallEtaMerge(st1, newAlphas, modAlphas); //a1 = AvgMerge(st1, newAlphas, modAlphas); //a1 = WeightedDistMerge(st1, newAlphas, modAlphas); if (a1 < 0) { for (int i = 1; i < size; i++) { modAlphas[i].Alpha += newAlphas[i - 1].Si * a1; } //a2 += s * a1; a1 = 0; } else if (a1 > C) { float t = a1 - C; for (int i = 1; i < size; i++) { modAlphas[i].Alpha += newAlphas[i - 1].Si * t; } //a2 += s * t; a1 = C; } // modAlphas.AddFirst(new Pair<int, float>(index1, a1)); modAlphas[0].Alpha = a1; //float b1 = 0, b2 = 0; float bnew = 0; if (a1 > 0 && a1 < C) { // bnew = b + E1 + y1 * (a1 - alph1) * k11 + y2 * (a2 - alph2) * k12; bnew = b + E1 + y1 * (a1 - alpha1) * k11; // int j = 0; for (int i = 1; i < size; i++) { var item = modAlphas[i]; float al2 = item.Alpha; int ind = item.Index; float oldAl = alpha[ind]; bnew += item.Y * (al2 - oldAl) * newAlphas[i - 1].Product; } } else { for (int i = 1; i < size; i++) { var item = modAlphas[i]; float prodI1 = newAlphas[i - 1].Product; if (item.Alpha > 0 && item.Alpha < C) { int mIndex = item.Index; bnew = item.Error + b + y1 * (a1 - alpha1) * prodI1; for (int j = 1; j < modAlphas.Length; j++) { var st = modAlphas[j]; //if (mIndex == st.Index) // bnew += st.Error; bnew += st.Y * (st.Alpha - alpha[st.Index]) * Product(mIndex, st.Index); } //we compute new B; break; } } //if (a2 > 0 && a2 < C) //{ // bnew = b + E2 + y1 * (a1 - alph1) * k12 + y2 * (a2 - alph2) * k22; //} //else //{ // b1 = b + E1 + y1 * (a1 - alph1) * k11 + y2 * (a2 - alph2) * k12; // b2 = b + E2 + y1 * (a1 - alph1) * k12 + y2 * (a2 - alph2) * k22; // bnew = (b1 + b2) / 2; //} } //todo: plus or minus? delta_b = bnew - b; b = bnew; return(modAlphas); }
private List <StepPairVariable> FindAlphaSteps(int cores, AlphaInfo st1) { List <StepPairVariable> newAlphas = new List <StepPairVariable>(cores); object lockObj = new object(); int k = st1.Index; //foreach (var i2 in GlobalHeuristic(k)) //{ // StepPairVariable ap = ComputeAlphaStep(st1, i2); // if (ap == null) continue; // newAlphas.Add(ap); // if (newAlphas.Count >= cores) // break; //} #region Parallel version Parallel.ForEach(GlobalHeuristic(k), (i2, loopState) => { if (loopState.ShouldExitCurrentIteration) { return; } StepPairVariable ap = ComputeAlphaStep(st1, i2); if (ap == null) { return; } lock (lockObj) { if (newAlphas.Count >= cores) { //stop searching loopState.Stop(); return; } else { newAlphas.Add(ap); if (newAlphas.Count >= cores) { loopState.Stop(); } } } }); #endregion return(newAlphas); }
/* * public override Model<TProblemElement> ComputeModel() * { * errorCache = new float[problem.ElementsCount]; * alpha = new float[problem.ElementsCount]; * // SMO algorithm * int numChange = 0; * int examineAll = 1; * int kktViolatiors = 0; * int cores = System.Environment.ProcessorCount; * * while (numChange > 0 || examineAll > 0) * { * numChange = 0; * * for (int k = 0; k < problem.ElementsCount; k++) * { * * int i2 = -1; * //find first index * if (ExamineExample(k)) * { * List<AlphaPair> newAlphasPair = FindSubIndexes(cores, k); * * if (newAlphasPair.Count == 0) * continue; * else * numChange += newAlphasPair.Count; * * * * var newAlphas= MergeSteps(newAlphasPair); * * * * int modSize = newAlphas.Count; * //list of modified alphas * //list for changes in alpha_i - = y1 * (a1 - alph1); * //key - alpha index, value- alpha step * List<KeyValuePair<int, float>> alphaStep = new List<KeyValuePair<int, float>>(); * * * int index = k; * float yi, oldAlpha, newAlpha; * //error for first index * //errors for second indexes, we start from One to #cores+1 * //in order to fill up the alphaStep array, we have to remeber * //that modAlphas start form 0 to #cores so its is nessesary to substrac One * foreach (var item in newAlphas) * { * index = item.First; * newAlpha = item.Second; * yi = problem.Labels[index]; * oldAlpha = alpha[index]; * * alphaStep.Add(new KeyValuePair<int, float>(index, yi * (newAlpha - oldAlpha))); * } * * * //float t1 = y1 * (a1 - alph1); * //float t2 = y2 * (a2 - alph2); * * for (int i = 0; i < problem.ElementsCount; i++) * { * if (0 < alpha[i] && alpha[i] < C) * { * for (int j = 0; j < alphaStep.Count; j++) * { * int alphaIndex = alphaStep[j].Key; * errorCache[i] += alphaStep[j].Value * Product(i, alphaIndex); * } * errorCache[i] -= delta_b; * //old version -errorCache[i] +=t1 * Product(i1, i)+ t2 * Product(i2, i) - delta_b; * } * } * * //update erroCache for alpha's * for (int j = 0; j < alphaStep.Count; j++) * { * int alphaIndex = alphaStep[j].Key; * //zero error on modified alphas * errorCache[alphaIndex] = 0f; * } * //errorCache[i1] = 0f; * //errorCache[i2] = 0f; * * //update alphas * foreach (var item in newAlphas) * { * //take arithmetic average of alphas * alpha[item.First] = item.Second; * } * * //update alpha, first index * //alpha[k] = avgAlpha1; * } * } * if (examineAll == 1) * { * examineAll = 0; * } * else if (numChange == 0) * { * examineAll = 1; * } #region Old code * //else * //{ * // for (int k = 0; k < problem.ElementsCount; k++) * // { * // if (alpha[k] != 0 && alpha[k] != C) * // { * // if (ExamineExample(k)) numChange++; * // } * // } * //} * * //if (examineAll == 1) * //{ * // examineAll = 0; * //} * //else if (numChange == 0) * //{ * // examineAll = 1; * //} #endregion * } * * // cleaning * errorCache = null; * #region Building Model * Model<TProblemElement> model = new Model<TProblemElement>(); * model.NumberOfClasses = 2; * model.Alpha = alpha; * model.Rho = b; * * * List<TProblemElement> supportElements = new List<TProblemElement>(); * List<int> suporrtIndexes = new List<int>(alpha.Length); * for (int i = 0; i < alpha.Length; i++) * { * if (alpha[i] > 0) * { * supportElements.Add(problem.Elements[i]); * suporrtIndexes.Add(i); * } * * } * model.SupportElements = supportElements.ToArray(); * model.SupportElementsIndexes = suporrtIndexes.ToArray(); #endregion * * return model; * } */ public override Model <TProblemElement> ComputeModel() { errorCache = new float[problem.ElementsCount]; alpha = new float[problem.ElementsCount]; // SMO algorithm int numChange = 0; int examineAll = 1; //int kktViolatiors = 0; int cores = System.Environment.ProcessorCount; float E1 = float.MinValue; float y1, alpha1; long mainIter = 0; long subIter = 0; while (numChange > 0 || examineAll > 0) { numChange = 0; mainIter++; //if (examineAll > 0) //{ // for (int k = 0; k < problem.ElementsCount; k++) // { // if (ExamineExample(k)) // { // numChange++; // subIter++; // } // } //} //else //{ // for (int k = 0; k < problem.ElementsCount; k++) // { // if (alpha[k] != 0 && alpha[k] != C) // { // if (ExamineExample(k)) // { // numChange++; // subIter++; // } // } // } //} if (examineAll > 0) { for (int k = 0; k < problem.ElementsCount; k++) { y1 = problem.Y[k]; alpha1 = alpha[k]; E1 = ErrorForAlpha(k); //find first index if (!KKTViolator(E1, y1, alpha1)) { continue; } subIter++; AlphaInfo st1 = new AlphaInfo(k, alpha1, y1, E1, Product(k, k)); var newSteps = FindAlphaSteps(cores, st1); if (newSteps.Count == 0) { continue; } else { numChange += newSteps.Count; } var newAlphas = MergeSteps(st1, newSteps); UpdateAlpha(newAlphas); } } else { for (int k = 0; k < problem.ElementsCount; k++) { if (alpha[k] == 0 || alpha[k] == C) { continue; } y1 = problem.Y[k]; alpha1 = alpha[k]; E1 = ErrorForAlpha(k); //find first index if (!KKTViolator(E1, y1, alpha1)) { continue; } subIter++; AlphaInfo st1 = new AlphaInfo(k, alpha1, y1, E1, Product(k, k)); var newSteps = FindAlphaSteps(cores, st1); if (newSteps.Count == 0) { continue; } else { numChange += newSteps.Count; } var newAlphas = MergeSteps(st1, newSteps); UpdateAlpha(newAlphas); } } if (examineAll == 1) { examineAll = 0; } else if (numChange == 0) { examineAll = 1; } } // cleaning errorCache = null; #region Building Model Model <TProblemElement> model = new Model <TProblemElement>(); model.NumberOfClasses = 2; model.Alpha = alpha; model.Bias = b; //List<TProblemElement> supportElements = new List<TProblemElement>(); //List<int> suporrtIndexes = new List<int>(alpha.Length); //for (int i = 0; i < alpha.Length; i++) //{ // if (alpha[i] > 0) // { // supportElements.Add(problem.Elements[i]); // suporrtIndexes.Add(i); // } //} //model.SupportElements = supportElements.ToArray(); //model.SupportElementsIndexes = suporrtIndexes.ToArray(); List <TProblemElement> supportElements = new List <TProblemElement>(alpha.Length); List <int> suporrtIndexes = new List <int>(alpha.Length); List <float> supportLabels = new List <float>(alpha.Length); for (int j = 0; j < alpha.Length; j++) { if (Math.Abs(alpha[j]) > 0) { supportElements.Add(problem.Elements[j]); suporrtIndexes.Add(j); supportLabels.Add(problem.Y[j]); } } model.SupportElements = supportElements.ToArray(); model.SupportElementsIndexes = suporrtIndexes.ToArray(); model.Y = supportLabels.ToArray(); #endregion Debug.WriteLine("Main iteration=" + mainIter + " subIteration=" + subIter); Console.WriteLine("Main iteration=" + mainIter + " subIteration=" + subIter); Console.WriteLine("SV=" + model.SupportElementsIndexes.Length); return(model); }