/** * Vertex update function. */ void update(CE_Graph_vertex<VertexDataType, EdgeDataType> &vertex, CE_Graph_context &gcontext) { if ( vertex.num_outedges() > 0){ vertex_data & user = latent_factors_inmem[vertex.id()]; memset(&user.weight[0], 0, sizeof(double)*D); for(int e=0; e < vertex.num_outedges(); e++) { vertex_data & movie = latent_factors_inmem[vertex.edge(e)->vertex_id()]; user.weight += movie.weight; } // sqrt(|N(u)|) float usrNorm = double(1.0/sqrt(vertex.num_outedges())); //sqrt(|N(u)| * sum_j y_j user.weight *= usrNorm; vec step = zeros(D); // main algorithm, see Koren's paper, just below below equation (16) for(int e=0; e < vertex.num_outedges(); e++) { vertex_data & movie = latent_factors_inmem[vertex.edge(e)->vertex_id()]; float observation = vertex.edge(e)->get_data(); double estScore; rmse_vec[omp_get_thread_num()] += svdpp_predict(user, movie,observation, estScore); // e_ui = r_ui - \hat{r_ui} float err = observation - estScore; assert(!std::isnan(rmse_vec[omp_get_thread_num()])); vec itmFctr = movie.pvec; vec usrFctr = user.pvec; //q_i = q_i + gamma2 *(e_ui*(p_u + sqrt(N(U))\sum_j y_j) - gamma7 *q_i) for (int j=0; j< D; j++) movie.pvec[j] += svdpp.itmFctrStep*(err*(usrFctr[j] + user.weight[j]) - svdpp.itmFctrReg*itmFctr[j]); //p_u = p_u + gamma2 *(e_ui*q_i -gamma7 *p_u) for (int j=0; j< D; j++) user.pvec[j] += svdpp.usrFctrStep*(err *itmFctr[j] - svdpp.usrFctrReg*usrFctr[j]); step += err*itmFctr; //b_i = b_i + gamma1*(e_ui - gmma6 * b_i) movie.bias += svdpp.itmBiasStep*(err-svdpp.itmBiasReg* movie.bias); //b_u = b_u + gamma1*(e_ui - gamma6 * b_u) user.bias += svdpp.usrBiasStep*(err-svdpp.usrBiasReg* user.bias); } step *= float(svdpp.itmFctr2Step*usrNorm); //gamma7 double mult = svdpp.itmFctr2Step*svdpp.itmFctr2Reg; for(int e=0; e < vertex.num_edges(); e++) { vertex_data& movie = latent_factors_inmem[vertex.edge(e)->vertex_id()]; //y_j = y_j + gamma2*sqrt|N(u)| * q_i - gamma7 * y_j movie.weight += step - mult * movie.weight; } } }
/** * Vertex update function - computes the least square step */ void update(graphchi_vertex<VertexDataType, EdgeDataType> &vertex, graphchi_context &gcontext) { //compute only for user nodes if (vertex.id() >= std::min(M,(uint)end_user) || vertex.id() < (uint)start_user) return; vertex_data & vdata = latent_factors_inmem[vertex.id()]; int howmany = (int)(N*knn_sample_percent); assert(howmany > 0 ); if (vertex.num_outedges() == 0){ mymutex.lock(); users_without_ratings++; mymutex.unlock(); } vec distances = zeros(howmany); ivec indices = ivec::Zero(howmany); for (int i=0; i< howmany; i++){ indices[i]= -1; } std::vector<bool> curratings; curratings.resize(N); for(int e=0; e < vertex.num_edges(); e++) { //no need to calculate this rating since it is given in the training data reference assert(vertex.edge(e)->vertex_id() - M >= 0 && vertex.edge(e)->vertex_id() - M < N); curratings[vertex.edge(e)->vertex_id() - M] = true; } if (knn_sample_percent == 1.0){ for (uint i=M; i< M+N; i++){ if (curratings[i-M]) continue; vertex_data & other = latent_factors_inmem[i]; double dist; if (algo == SVDPP) svdpp_predict(vdata, other, 0, dist); else if (algo == BIASSGD) biassgd_predict(vdata, other, 0, dist); else if (algo == RBM) rbm_predict(vdata, other, 0, dist); else assert(false); indices[i-M] = i-M; distances[i-M] = dist + 1e-10; } } else for (int i=0; i<howmany; i++){ int random_other = ::randi(M, M+N-1); vertex_data & other = latent_factors_inmem[random_other]; double dist; if (algo == SVDPP) svdpp_predict(vdata, other, 0, dist); else if (algo == BIASSGD) biassgd_predict(vdata, other, 0, dist); else if (algo == RBM) rbm_predict(vdata, other, 0, dist); else assert(false); indices[i] = random_other-M; distances[i] = dist; } vec out_dist(num_ratings); ivec indices_sorted = reverse_sort_index2(distances, indices, out_dist, num_ratings); assert(indices_sorted.size() <= num_ratings); assert(out_dist.size() <= num_ratings); vdata.ids = indices_sorted; vdata.ratings = out_dist; if (debug) printf("Closest is: %d with distance %g\n", (int)vdata.ids[0], vdata.ratings[0]); if (vertex.id() % 1000 == 0) printf("Computing recommendations for user %d at time: %g\n", vertex.id()+1, mytimer.current_time()); }