public override float Predict(int user_id, int item_id) { string userIdOrg = UsersMap.ToOriginalID(user_id); string itemIdOrg = ItemsMap.ToOriginalID(item_id); List <Tuple <int, float> > features = new List <Tuple <int, float> >(); if (!IgnoreFeaturesOnPrediction && Split.Container.FeedbacksDic.ContainsKey(userIdOrg, itemIdOrg)) { var feedback = Split.Container.FeedbacksDic[userIdOrg, itemIdOrg]; features = feedback.GetAllAttributes().Select(a => FeatureBuilder.TranslateAttribute(a)).NormalizeSumToOne(Normalize).ToList(); } bool newUser = (user_id > MaxUserID); bool newItem = (item_id > MaxItemID); float userAttrsTerm = 0, itemAttrsTerm = 0; foreach (var feat in features) { // if feat_index is greater than MaxFeatureId it means that the feature is new in test set so its factors has not been learnt if (feat.Item1 < NumTrainFeaturs) { float x_z = feat.Item2; userAttrsTerm += newUser ? 0 : x_z *MatrixExtensions.RowScalarProduct(feature_factors, feat.Item1, user_factors, user_id); itemAttrsTerm += newItem ? 0 : x_z *MatrixExtensions.RowScalarProduct(feature_factors, feat.Item1, item_factors, item_id); } } float itemBias = newItem ? 0 : item_bias[item_id]; float userItemTerm = (newUser || newItem) ? 0 : MatrixExtensions.RowScalarProduct(user_factors, user_id, item_factors, item_id); return(itemBias + userItemTerm + userAttrsTerm + itemAttrsTerm); }
protected void _Iterate(IList <int> rating_indices, bool update_user, bool update_item) { foreach (int index in rating_indices) { int u = ratings.Users[index]; int i = ratings.Items[index]; int g_u = 0; //FeatureGroups[user_id]; int g_i = 1; //FeatureGroups[item_id]; float alpha_u = weights[g_u]; float alpha_i = weights[g_i]; // used by WrapRec-based logic string userIdOrg = UsersMap.ToOriginalID(u); string itemIdOrg = ItemsMap.ToOriginalID(i); List <Tuple <int, float> > features = new List <Tuple <int, float> >(); if (Split.SetupParameters.ContainsKey("feedbackAttributes")) { features = Split.Container.FeedbacksDic[userIdOrg, itemIdOrg].GetAllAttributes().Select(a => a.Translation) .NormalizeSumToOne(Normalize).ToList(); } var p = Predict(u, i); float err = (p - ratings[index]) * 2; float sum_u = 0, sum_i = 0; foreach (var feature in features) { int j = feature.Item1; float x_j = feature.Item2; int g_z = 2; // FeatureGroups[feature.Item1]; float alpha_z = weights[g_z]; sum_u += x_j * alpha_z * MatrixExtensions.RowScalarProduct(user_factors, u, feature_factors, j); sum_i += x_j * alpha_z * MatrixExtensions.RowScalarProduct(item_factors, i, feature_factors, j); } float ui = MatrixExtensions.RowScalarProduct(item_factors, i, user_factors, u); sum_u += alpha_i * ui; sum_i += alpha_u * ui; float sum_z = 0; float sum_z_bias = 0; for (int z = 0; z < features.Count; z++) { int z_ix = features[z].Item1; float x_z = features[z].Item2; float sum_j = 0; int g_z = 2; // FeatureGroups[z_ix]; float alpha_z = weights[g_z]; for (int j = z + 1; j < features.Count; j++) { int j_ix = features[j].Item1; float x_j = features[j].Item2; sum_j += x_j * MatrixExtensions.RowScalarProduct(feature_factors, z_ix, feature_factors, j_ix); } sum_z += 2 * alpha_z * x_z * sum_j; sum_z += x_z * alpha_u * MatrixExtensions.RowScalarProduct(feature_factors, z_ix, user_factors, u); sum_z += x_z * alpha_i * MatrixExtensions.RowScalarProduct(feature_factors, z_ix, item_factors, i); sum_z_bias += x_z * feature_biases[z_ix]; } float[] sum = new float[NumFactors]; foreach (var feature in features) { int j = feature.Item1; float x_j = feature.Item2; int g_z = 2; //FeatureGroups[feature.Item1]; float alpha_z = weights[g_z]; for (int f = 0; f < NumFactors; f++) { sum[f] += feature_factors[j, f] * x_j * alpha_z; } } for (int f = 0; f < NumFactors; f++) { sum[f] += user_factors[u, f] * alpha_u + item_factors[i, f] * alpha_i; } // adjust biases global_bias -= current_learnrate * (err + RegB * global_bias); if (update_user) { user_bias[u] -= current_learnrate * (err * alpha_u + RegU * user_bias[u]); } if (update_item) { item_bias[i] -= current_learnrate * (err * alpha_i + RegI * item_bias[i]); } foreach (var feature in features) { int j = feature.Item1; float x_j = feature.Item2; float w_j = feature_biases[j]; int g_z = 2; // FeatureGroups[feature.Item1]; float alpha_z = weights[g_z]; feature_biases[j] -= current_learnrate * (x_j * alpha_z * err + RegC * w_j); } // adjust latent factors for (int f = 0; f < NumFactors; f++) { double v_uf = user_factors[u, f]; double v_if = item_factors[i, f]; if (update_user) { double delta_u = alpha_u * (sum[f] - v_uf * alpha_u) * err + RegU * v_uf; user_factors.Inc(u, f, -current_learnrate * delta_u); } if (update_item) { double delta_i = alpha_i * (sum[f] - v_if * alpha_i) * err + RegI * v_if; item_factors.Inc(i, f, -current_learnrate * delta_i); } foreach (var feature in features) { int j = feature.Item1; float x_j = feature.Item2; float v_jf = feature_factors[j, f]; int g_z = 2; // FeatureGroups[feature.Item1]; float alpha_z = weights[g_z]; double delta_j = x_j * alpha_z * (sum[f] - v_jf * x_j * alpha_z) * err + RegC * v_jf; feature_factors.Inc(j, f, -current_learnrate * delta_j); } } // update alphas float update_alpha_u = (user_bias[u] + sum_u) * err + reg_w * weights[g_u]; weights[g_u] -= current_learnrate * update_alpha_u; float update_alpha_i = (item_bias[i] + sum_i) * err + reg_w * weights[g_i]; weights[g_i] -= current_learnrate * update_alpha_i; for (int g = 0; g < NumGroups - 2; g++) { float alpha_z_g = weights[g + 2]; float update_alpha_z = (sum_z + sum_z_bias) * err + reg_w * alpha_z_g; weights[g + 2] -= current_learnrate * update_alpha_z; } NormalizeWeights(); } Console.WriteLine($"alpha_u: {weights[0]}, alpha_i: {weights[1]}" + (weights.Length > 2 ? $", alpha_z: {weights[2]}" : "")); //_alphaWriter.WriteLine(++_iter + "," + weights[0] + "," + weights[1] + (weights.Length > 2 ? "," + weights[2] : "")); }
public override float Predict(int user_id, int item_id) { int u = user_id; int i = item_id; // used by WrapRec-based logic string userIdOrg = UsersMap.ToOriginalID(user_id); string itemIdOrg = ItemsMap.ToOriginalID(item_id); List <Tuple <int, float> > features = new List <Tuple <int, float> >(); if (Split.SetupParameters.ContainsKey("feedbackAttributes")) { features = Split.Container.FeedbacksDic[userIdOrg, itemIdOrg].GetAllAttributes().Select(a => a.Translation) .NormalizeSumToOne(Normalize).ToList(); } float alpha_u = weights[0]; float alpha_i = weights[1]; float alpha_z = weights.Length > 2 ? weights[2] : 0; float score = global_bias; if (u < user_bias.Length) { score += user_bias[u] * alpha_u; } if (i < item_bias.Length) { score += item_bias[i] * alpha_i; } foreach (var feat in features) { float x_z = feat.Item2; score += feature_biases[feat.Item1] * x_z * alpha_z; } for (int f = 0; f < NumFactors; f++) { float sum = 0, sum_sq = 0; float v_uf = 0, v_if = 0; if (u < user_bias.Length) { v_uf = user_factors[u, f]; } if (i < item_bias.Length) { v_if = item_factors[i, f]; } sum += v_uf * alpha_u + v_if * alpha_i; sum_sq += v_uf * v_uf * alpha_u * alpha_u + v_if * v_if * alpha_i * alpha_i; foreach (var feat in features) { int j = feat.Item1; float x_j = feat.Item2; float v_jf = feature_factors[j, f]; sum += x_j * v_jf * alpha_z; sum_sq += x_j * x_j * v_jf * v_jf * alpha_z * alpha_z; } score += 0.5f * (sum * sum - sum_sq); } if (score > MaxRating) { return(MaxRating); } if (score < MinRating) { return(MinRating); } return(score); }
protected override void UpdateFactors(int user_id, int item_id, int other_item_id, bool update_u, bool update_i, bool update_j) { // used by WrapRec-based logic string userIdOrg = UsersMap.ToOriginalID(user_id); string itemIdOrg = ItemsMap.ToOriginalID(item_id); List <Tuple <int, float> > features = new List <Tuple <int, float> >(); if (Split.SetupParameters.ContainsKey("feedbackAttributes")) { features = Split.Container.FeedbacksDic[userIdOrg, itemIdOrg].GetAllAttributes().Select(a => a.Translation).NormalizeSumToOne(Normalize).ToList(); } double item_bias_diff = item_bias[item_id] - item_bias[other_item_id]; int g_u = 0; //FeatureGroups[user_id]; int g_i = 1; //FeatureGroups[item_id]; float alpha_u = weights[g_u]; float alpha_i = weights[g_i]; double u_i_term = MatrixExtensions.RowScalarProductWithRowDifference( user_factors, user_id, item_factors, item_id, item_factors, other_item_id); double y_uij = item_bias_diff + alpha_u * alpha_i * u_i_term; double items_z_term_sum = 0; double[] items_z_terms = new double[features.Count]; double[] group_z_terms = new double[NumGroups - 2]; int z = 0; foreach (var feat in features) { int g_z = FeatureGroups[feat.Item1]; float alpha_z = weights[g_z]; items_z_terms[z] = feat.Item2 * MatrixExtensions.RowScalarProductWithRowDifference( feature_factors, feat.Item1, item_factors, item_id, item_factors, other_item_id); group_z_terms[g_z - 2] += items_z_terms[z]; items_z_term_sum += alpha_z * items_z_terms[z]; z++; } y_uij += alpha_i * items_z_term_sum; double exp = Math.Exp(y_uij); double sigmoid = 1 / (1 + exp); // adjust bias terms if (update_i) { double update = sigmoid - BiasReg * item_bias[item_id]; item_bias[item_id] += (float)(learn_rate * update); } if (update_j) { double update = -sigmoid - BiasReg * item_bias[other_item_id]; item_bias[other_item_id] += (float)(learn_rate * update); } // adjust factors for (int f = 0; f < num_factors; f++) { float v_uf = user_factors[user_id, f]; float v_if = item_factors[item_id, f]; float v_jf = item_factors[other_item_id, f]; if (update_u) { double update = alpha_u * alpha_i * (v_if - v_jf) * sigmoid - reg_u * v_uf; user_factors[user_id, f] = (float)(v_uf + learn_rate * update); } // update features latent factors and make a sum term to use later for updating item factors // sum = Sum_{l=1}{num_features} c_l * v_{c_l,f} float sum = 0f; foreach (var feat in features) { float v_zf = feature_factors[feat.Item1, f]; float x_z = feat.Item2; int g_z = FeatureGroups[feat.Item1]; float alpha_z = weights[g_z]; sum += x_z * v_zf * alpha_z; double update = alpha_i * alpha_z * x_z * (v_if - v_jf) * sigmoid - reg_c * v_zf; feature_factors[feat.Item1, f] = (float)(v_zf + learn_rate * update); } if (update_i) { double update = (alpha_u * alpha_i * v_uf + alpha_i * sum) * sigmoid - reg_i * v_if; item_factors[item_id, f] = (float)(v_if + learn_rate * update); } if (update_j) { double update = (alpha_u * alpha_i * -v_uf - alpha_i * sum) * sigmoid - reg_j * v_jf; item_factors[other_item_id, f] = (float)(v_jf + learn_rate * update); } } // update alphas double update_alpha_u = alpha_i * u_i_term * sigmoid - reg_w * alpha_u; weights[g_u] = (float)(alpha_u + learn_rate * update_alpha_u); //NormalizeWeights(); double update_alpha_i = (alpha_u * u_i_term + items_z_term_sum) * sigmoid - reg_w * alpha_i; weights[g_i] = (float)(alpha_i + learn_rate * update_alpha_i); for (int g = 0; g < NumGroups - 2; g++) { double alpha_z_g = weights[g + 2]; double update_alpha_z_g = alpha_i * group_z_terms[g] * sigmoid - reg_w * alpha_z_g; weights[g + 2] = (float)(alpha_z_g + learn_rate * update_alpha_z_g); } // normalize weights NormalizeWeights(); }
protected void _Iterate(IList <int> rating_indices, bool update_user, bool update_item) { foreach (int index in rating_indices) { int u = ratings.Users[index]; int i = ratings.Items[index]; // used by WrapRec-based logic string userIdOrg = UsersMap.ToOriginalID(u); string itemIdOrg = ItemsMap.ToOriginalID(i); List <Tuple <int, float> > features = new List <Tuple <int, float> >(); if (Split.SetupParameters.ContainsKey("feedbackAttributes")) { features = Split.Container.FeedbacksDic[userIdOrg, itemIdOrg].GetAllAttributes() .Select(a => a.Translation).NormalizeSumToOne(Normalize).ToList(); } var p = Predict(u, i); float err = (p - ratings[index]) * 2; float[] sum = new float[NumFactors]; foreach (var feature in features) { int j = feature.Item1; float x_j = feature.Item2; for (int f = 0; f < NumFactors; f++) { sum[f] += feature_factors[j, f] * x_j; } } for (int f = 0; f < NumFactors; f++) { sum[f] += user_factors[u, f] + item_factors[i, f]; } // adjust biases //global_bias -= current_learnrate*(err + RegB*global_bias); if (update_user) { user_bias[u] -= current_learnrate * (err + RegU * user_bias[u]); } if (update_item) { item_bias[i] -= current_learnrate * (err + RegI * item_bias[i]); } foreach (var feature in features) { int j = feature.Item1; float x_j = feature.Item2; float w_j = feature_biases[j]; feature_biases[j] -= BiasLearnRate * current_learnrate * (x_j * err + BiasReg * RegC * w_j); } // adjust latent factors for (int f = 0; f < NumFactors; f++) { double v_uf = user_factors[u, f]; double v_if = item_factors[i, f]; if (update_user) { double delta_u = (sum[f] - v_uf) * err + RegU * v_uf; user_factors.Inc(u, f, -current_learnrate * delta_u); } if (update_item) { double delta_i = (sum[f] - v_if) * err + RegI * v_if; item_factors.Inc(i, f, -current_learnrate * delta_i); } foreach (var feature in features) { int j = feature.Item1; float x_j = feature.Item2; float v_jf = feature_factors[j, f]; double delta_j = (sum[f] * x_j - v_jf * x_j * x_j) * err + RegC * v_jf; feature_factors.Inc(j, f, -current_learnrate * delta_j); } } } }
protected override void UpdateFactors(int user_id, int item_id, int other_item_id, bool update_u, bool update_i, bool update_j) { // used by WrapRec-based logic string userIdOrg = UsersMap.ToOriginalID(user_id); string itemIdOrg = ItemsMap.ToOriginalID(item_id); List <Tuple <int, float> > features = new List <Tuple <int, float> >(); if (Split.SetupParameters.ContainsKey("feedbackAttributes")) { features = Split.Container.FeedbacksDic[userIdOrg, itemIdOrg].GetAllAttributes().Select(a => a.Translation).NormalizeSumToOne(Normalize).ToList(); } double item_bias_diff = item_bias[item_id] - item_bias[other_item_id]; double y_uij = item_bias_diff + MatrixExtensions.RowScalarProductWithRowDifference( user_factors, user_id, item_factors, item_id, item_factors, other_item_id); foreach (var feat in features) { y_uij += feat.Item2 * MatrixExtensions.RowScalarProductWithRowDifference( feature_factors, feat.Item1, item_factors, item_id, item_factors, other_item_id); } double exp = Math.Exp(y_uij); double sigmoid = 1 / (1 + exp); // adjust bias terms if (update_i) { // TODO: check why -Bias double update = sigmoid - BiasReg * item_bias[item_id]; item_bias[item_id] += (float)(learn_rate * update); } if (update_j) { double update = -sigmoid - BiasReg * item_bias[other_item_id]; item_bias[other_item_id] += (float)(learn_rate * update); } // adjust factors for (int f = 0; f < num_factors; f++) { float v_uf = user_factors[user_id, f]; float v_if = item_factors[item_id, f]; float v_jf = item_factors[other_item_id, f]; if (update_u) { double update = (v_if - v_jf) * sigmoid - reg_u * v_uf; user_factors[user_id, f] = (float)(v_uf + learn_rate * update); } // update features latent factors and make a sum term to use later for updating item factors // sum = Sum_{l=1}{num_features} c_l * v_{c_l,f} float sum = 0f; foreach (var feat in features) { float v_zf = feature_factors[feat.Item1, f]; float x_z = feat.Item2; sum += x_z * v_zf; double update = x_z * (v_if - v_jf) * sigmoid - reg_c * v_zf; feature_factors[feat.Item1, f] = (float)(v_zf + learn_rate * update); } if (update_i) { double update = (v_uf + sum) * sigmoid - reg_i * v_if; item_factors[item_id, f] = (float)(v_if + learn_rate * update); } if (update_j) { double update = (-v_uf - sum) * sigmoid - reg_j * v_jf; item_factors[other_item_id, f] = (float)(v_jf + learn_rate * update); } } }