Beispiel #1
0
        static (double, double) RankOneUpdate(smat_t R, long j, double[] u, double lambda, double vj, long do_nmf)
        {
            double g = 0, h = lambda;

            if (R.col_ptr[j + 1] == R.col_ptr[j])
            {
                return(0, 0);
            }
            for (long idx = R.col_ptr[j]; idx < R.col_ptr[j + 1]; ++idx)
            {
                long i = R.row_idx[idx];
                g += u[i] * R.val[idx];
                h += u[i] * u[i];
            }

            double newvj = g / h, delta = 0, fundec = 0;

            if (do_nmf > 0 & newvj < 0)
            {
                newvj  = 0;
                fundec = -2 * g * vj;
            }
            else
            {
                delta  = vj - newvj;
                fundec = h * delta * delta;
            }

            return(newvj, fundec);
        }
Beispiel #2
0
        public static smat_t load(string dataFolderName, string metaFileName, smat_t R, bool with_weights)
        {
            var metaInfo           = File.ReadAllLines(Path.Combine(dataFolderName, metaFileName));
            var rowsAndColumnsData = metaInfo[0].Split(' ');

            var(rowsCount, columnsCount) = (long.Parse(rowsAndColumnsData[0]), long.Parse(rowsAndColumnsData[1]));

            var trainingSetData = metaInfo[1].Split(' ');

            var(nonZeroNumbersCount, trainingFileName) = (long.Parse(trainingSetData[0]), trainingSetData[1]);

            R.load(rowsCount, columnsCount, nonZeroNumbersCount, Path.Combine(dataFolderName, trainingFileName),
                   with_weights);
            return(R);
        }
Beispiel #3
0
        static double UpdateRating(smat_t R, double[] Wt2, double[] Ht2)
        {
            double loss = 0;

//#pragma omp parallel for schedule(kind) reduction(+:loss)
            for (long c = 0; c < R.cols; ++c)
            {
                double Htc = Ht2[2 * c], oldHtc = Ht2[2 * c + 1], loss_inner = 0;
                for (long idx = R.col_ptr[c]; idx < R.col_ptr[c + 1]; ++idx)
                {
                    R.val[idx] -= Wt2[2 * R.row_idx[idx]] * Htc - Wt2[2 * R.row_idx[idx] + 1] * oldHtc;
                    loss_inner += R.val[idx] * R.val[idx];
                }

                loss += loss_inner;
            }

            return(loss);
        }
Beispiel #4
0
        static double UpdateRating(smat_t R, double[] Wt, double[] Ht, bool add)
        {
            double loss = 0;

            var result = new ThreadSafe();

            if (add)
            {
                Parallel.For(0, R.cols, () => 0d, (c, y, innerLoss) =>
                {
                    double Htc = Ht[c];
                    for (long idx = R.col_ptr[c]; idx < R.col_ptr[c + 1]; ++idx)
                    {
                        R.val[idx] += Wt[R.row_idx[idx]] * Htc;
                        innerLoss  += (R.with_weights ? R.weight[idx] : 1.0) * R.val[idx] * R.val[idx];
                    }

                    return(innerLoss);
                },
                             innerLoss => { result.AddToTotal(innerLoss); });

                return(result.Total);
            }

            Parallel.For(0, R.cols, () => 0d, (c, y, innerLoss) =>
            {
                double Htc = Ht[c];
                for (long idx = R.col_ptr[c]; idx < R.col_ptr[c + 1]; ++idx)
                {
                    R.val[idx] -= Wt[R.row_idx[idx]] * Htc;
                    innerLoss  += (R.with_weights ? R.weight[idx] : 1.0) * R.val[idx] * R.val[idx];
                }

                return(innerLoss);
            },
                         innerLoss => { result.AddToTotal(innerLoss); });

            return(result.Total);
        }
Beispiel #5
0
        // Cyclic Coordinate Descent for Matrix Factorization
        public static void ccdr1(smat_t R, double[][] W, double[][] H, parameter param)
        {
            long k         = param.k;
            long maxiter   = param.maxiter;
            long inneriter = param.maxinneriter;
            //  long num_threads_old = omp_get_num_threads();
            double lambda = param.lambda;
            double eps = param.eps;
            double Itime = 0, Wtime = 0, Htime = 0, Rtime = 0, start = 0, oldobj = 0;
            long   num_updates = 0;
            double reg = 0, loss;

            // omp_set_num_threads(param.threads);

            // Create transpose view of R
            smat_t Rt        = R.transpose();
            var    stopwatch = new Stopwatch();

            // initial value of the regularization term
            // H is a zero matrix now.
            for (long t = 0; t < k; ++t)
            {
                for (long c = 0; c < R.cols; ++c)
                {
                    H[t][c] = 0;
                }
            }

            for (long t = 0; t < k; ++t)
            {
                for (long r = 0; r < R.rows; ++r)
                {
                    reg += W[t][r] * W[t][r] * R.nnz_of_row(r);
                }
            }

            Console.WriteLine("kek {0}", reg);

            var oldWt = new double[R.rows];
            var oldHt = new double[R.cols];
            var u     = new double[R.rows];
            var v     = new double[R.cols];

            for (long oiter = 1; oiter <= maxiter; ++oiter)
            {
                double gnorm = 0, initgnorm = 0;
                double rankfundec = 0;
                double fundec_max = 0;
                long   early_stop = 0;
                for (long tt = 0; tt < k; ++tt)
                {
                    long t = tt;
                    if (early_stop >= 5)
                    {
                        break;
                    }

                    //if(oiter>1) { t = rand()%k; }
                    stopwatch.Start();
                    double[] Wt = W[t], Ht = H[t];
                    for (int i = 0; i < R.rows; i++)
                    {
                        oldWt[i] = u[i] = Wt[i];
                    }

                    for (int i = 0; i < R.cols; i++)
                    {
                        v[i]     = Ht[i];
                        oldHt[i] = (oiter == 1) ? 0 : v[i];
                    }

                    // Create Rhat = R - Wt Ht^T
                    if (oiter > 1)
                    {
                        UpdateRating(R, Wt, Ht, true);
                        UpdateRating(Rt, Ht, Wt, true);
                    }

                    stopwatch.Stop();
                    Itime += stopwatch.ElapsedMilliseconds;

                    gnorm     = 0;
                    initgnorm = 0;
                    double innerfundec_max = 0;
                    long   maxit           = inneriter;
                    //	if(oiter > 1) maxit *= 2;
                    for (long iter = 1; iter <= maxit; ++iter)
                    {
                        // Update H[t]
                        stopwatch.Restart();
                        gnorm = 0;
                        var innerFunDecCur = 0d;

                        for (long c = 0; c < R.cols; ++c)
                        {
                            var(newV, innerfundec) = RankOneUpdate(R, c, u, lambda * (R.col_ptr[c + 1] - R.col_ptr[c]),
                                                                   v[c], param.do_nmf);
                            innerFunDecCur += innerfundec;
                            v[c]            = newV;
                        }

                        num_updates += R.cols;
                        stopwatch.Stop();
                        Htime += stopwatch.ElapsedMilliseconds;
                        // Update W[t]
                        stopwatch.Restart();

                        for (long c = 0; c < Rt.cols; ++c)
                        {
                            var(newU, innerfundec) = RankOneUpdate(Rt, c, v,
                                                                   lambda * (Rt.col_ptr[c + 1] - Rt.col_ptr[c]), u[c], param.do_nmf);
                            u[c]            = newU;
                            innerFunDecCur += innerfundec;
                        }

                        num_updates += Rt.cols;
                        if ((innerFunDecCur < fundec_max * eps))
                        {
                            if (iter == 1)
                            {
                                early_stop += 1;
                            }

                            break;
                        }

                        rankfundec     += innerFunDecCur;
                        innerfundec_max = Math.Max(innerfundec_max, innerFunDecCur);
                        // the fundec of the first inner iter of the first rank of the first outer iteration could be too large!!
                        if (!(oiter == 1 && t == 0 && iter == 1))
                        {
                            fundec_max = Math.Max(fundec_max, innerFunDecCur);
                        }
                        stopwatch.Stop();
                        Wtime += stopwatch.ElapsedMilliseconds;
                    }

                    // Update R and Rt
                    // start = omp_get_wtime();
                    stopwatch.Restart();
                    for (int i = 0; i < R.rows; i++)
                    {
                        Wt[i] = u[i];
                    }

                    for (int i = 0; i < R.cols; i++)
                    {
                        Ht[i] = v[i];
                    }

                    loss = UpdateRating(R, u, v, false);
                    loss = UpdateRating(Rt, v, u, false);
                    stopwatch.Stop();
                    Rtime += stopwatch.ElapsedMilliseconds;

                    for (long c = 0; c < R.cols; ++c)
                    {
                        reg += R.nnz_of_col(c) * Ht[c] * Ht[c];
                        reg -= R.nnz_of_col(c) * oldHt[c] * oldHt[c];
                    }

                    for (long c = 0; c < Rt.cols; ++c)
                    {
                        reg += Rt.nnz_of_col(c) * (Wt[c] * Wt[c]);
                        reg -= Rt.nnz_of_col(c) * (oldWt[c] * oldWt[c]);
                    }

                    double obj = loss + reg * lambda;

                    Console.WriteLine("iter {0} rank {1} time {2} loss {3} obj {4} diff {5} gnorm {6} reg {7} ",
                                      oiter, t + 1, Htime + Wtime + Rtime, loss, obj, oldobj - obj, initgnorm, reg);

                    oldobj = obj;
                }
            }
        }