Exemplo n.º 1
0
void nmf(viennacl::matrix_base<NumericT> const & V,
         viennacl::matrix_base<NumericT>       & W,
         viennacl::matrix_base<NumericT>       & H,
         viennacl::linalg::nmf_config const & conf)
{
  viennacl::hsa::context & ctx = const_cast<viennacl::hsa::context &>(viennacl::traits::hsa_context(V));

  const std::string NMF_MUL_DIV_KERNEL = "el_wise_mul_div";

  viennacl::linalg::opencl::kernels::nmf<NumericT, viennacl::hsa::context>::init(ctx);

  vcl_size_t k = W.size2();
  conf.iters_ = 0;

  if (viennacl::linalg::norm_frobenius(W) <= 0)
    W = viennacl::scalar_matrix<NumericT>(W.size1(), W.size2(), NumericT(1), ctx);

  if (viennacl::linalg::norm_frobenius(H) <= 0)
    H = viennacl::scalar_matrix<NumericT>(H.size1(), H.size2(), NumericT(1), ctx);

  viennacl::matrix_base<NumericT> wn(V.size1(), k, W.row_major(), ctx);
  viennacl::matrix_base<NumericT> wd(V.size1(), k, W.row_major(), ctx);
  viennacl::matrix_base<NumericT> wtmp(V.size1(), V.size2(), W.row_major(), ctx);

  viennacl::matrix_base<NumericT> hn(k, V.size2(), H.row_major(), ctx);
  viennacl::matrix_base<NumericT> hd(k, V.size2(), H.row_major(), ctx);
  viennacl::matrix_base<NumericT> htmp(k, k, H.row_major(), ctx);

  viennacl::matrix_base<NumericT> appr(V.size1(), V.size2(), V.row_major(), ctx);

  NumericT last_diff = 0;
  NumericT diff_init = 0;
  bool stagnation_flag = false;

  for (vcl_size_t i = 0; i < conf.max_iterations(); i++)
  {
    conf.iters_ = i + 1;
    {
      hn = viennacl::linalg::prod(trans(W), V);
      htmp = viennacl::linalg::prod(trans(W), W);
      hd = viennacl::linalg::prod(htmp, H);

      viennacl::hsa::kernel & mul_div_kernel = ctx.get_kernel(viennacl::linalg::opencl::kernels::nmf<NumericT>::program_name(), NMF_MUL_DIV_KERNEL);
      viennacl::hsa::enqueue(mul_div_kernel(H, hn, hd, cl_uint(H.internal_size1() * H.internal_size2())));
    }
    {
      wn = viennacl::linalg::prod(V, trans(H));
      wtmp = viennacl::linalg::prod(W, H);
      wd = viennacl::linalg::prod(wtmp, trans(H));

      viennacl::hsa::kernel & mul_div_kernel = ctx.get_kernel(viennacl::linalg::opencl::kernels::nmf<NumericT>::program_name(), NMF_MUL_DIV_KERNEL);

      viennacl::hsa::enqueue(mul_div_kernel(W, wn, wd, cl_uint(W.internal_size1() * W.internal_size2())));
    }

    if (i % conf.check_after_steps() == 0)  //check for convergence
    {
      appr = viennacl::linalg::prod(W, H);

      appr -= V;
      NumericT diff_val = viennacl::linalg::norm_frobenius(appr);

      if (i == 0)
        diff_init = diff_val;

      if (conf.print_relative_error())
        std::cout << diff_val / diff_init << std::endl;

      // Approximation check
      if (diff_val / diff_init < conf.tolerance())
        break;

      // Stagnation check
      if (std::fabs(diff_val - last_diff) / (diff_val * NumericT(conf.check_after_steps())) < conf.stagnation_tolerance()) //avoid situations where convergence stagnates
      {
        if (stagnation_flag)    // iteration stagnates (two iterates with no notable progress)
          break;
        else
          // record stagnation in this iteration
          stagnation_flag = true;
      } else
        // good progress in this iteration, so unset stagnation flag
        stagnation_flag = false;

      // prepare for next iterate:
      last_diff = diff_val;
    }
  }
}
Exemplo n.º 2
0
    void nmf(viennacl::matrix<ScalarType> const & v,
             viennacl::matrix<ScalarType> & w,
             viennacl::matrix<ScalarType> & h,
             std::size_t k,
             ScalarType eps = 0.000001,
             std::size_t max_iter = 10000,
             std::size_t check_diff_every_step = 100)
    {
      viennacl::linalg::kernels::nmf<ScalarType, 1>::init();
      
      w.resize(v.size1(), k);
      h.resize(k, v.size2());

      std::vector<ScalarType> stl_w(w.internal_size1() * w.internal_size2());
      std::vector<ScalarType> stl_h(h.internal_size1() * h.internal_size2());

      for (std::size_t j = 0; j < stl_w.size(); j++)
          stl_w[j] = static_cast<ScalarType>(rand()) / RAND_MAX;

      for (std::size_t j = 0; j < stl_h.size(); j++)
          stl_h[j] = static_cast<ScalarType>(rand()) / RAND_MAX;

      viennacl::matrix<ScalarType> wn(v.size1(), k);
      viennacl::matrix<ScalarType> wd(v.size1(), k);
      viennacl::matrix<ScalarType> wtmp(v.size1(), v.size2());

      viennacl::matrix<ScalarType> hn(k, v.size2());
      viennacl::matrix<ScalarType> hd(k, v.size2());
      viennacl::matrix<ScalarType> htmp(k, k);

      viennacl::matrix<ScalarType> appr(v.size1(), v.size2());
      viennacl::vector<ScalarType> diff(v.size1() * v.size2());

      viennacl::fast_copy(&stl_w[0], &stl_w[0] + stl_w.size(), w);
      viennacl::fast_copy(&stl_h[0], &stl_h[0] + stl_h.size(), h);

      ScalarType last_diff = 0.0f;


      
      for (std::size_t i = 0; i < max_iter; i++)
      {
        {
          hn = viennacl::linalg::prod(trans(w), v);
          htmp = viennacl::linalg::prod(trans(w), w);
          hd = viennacl::linalg::prod(htmp, h);

          viennacl::ocl::kernel & mul_div_kernel = viennacl::ocl::get_kernel(viennacl::linalg::kernels::nmf<ScalarType, 1>::program_name(), 
                                                                             NMF_MUL_DIV_KERNEL);
          viennacl::ocl::enqueue(mul_div_kernel(h, hn, hd, cl_uint(stl_h.size())));
        }
        {
          wn = viennacl::linalg::prod(v, trans(h));
          wtmp = viennacl::linalg::prod(w, h);
          wd = viennacl::linalg::prod(wtmp, trans(h));

          viennacl::ocl::kernel & mul_div_kernel = viennacl::ocl::get_kernel(viennacl::linalg::kernels::nmf<ScalarType, 1>::program_name(), 
                                                                             NMF_MUL_DIV_KERNEL);
          
          viennacl::ocl::enqueue(mul_div_kernel(w, wn, wd, cl_uint(stl_w.size())));
        }

        if (i % check_diff_every_step == 0)
        {
          appr = viennacl::linalg::prod(w, h);

         viennacl::ocl::kernel & sub_kernel = viennacl::ocl::get_kernel(viennacl::linalg::kernels::nmf<ScalarType, 1>::program_name(), 
                                                                        NMF_SUB_KERNEL);
          //this is a cheat. i.e save difference of two matrix into vector to get norm_2
          viennacl::ocl::enqueue(sub_kernel(appr, v, diff, cl_uint(v.size1() * v.size2())));
          ScalarType diff_val = viennacl::linalg::norm_2(diff);

          if((diff_val < eps) || (fabs(diff_val - last_diff) < eps))
          {
              //std::cout << "Breaked at diff - " << diff_val << "\n";
              break;
          }

          last_diff = diff_val;

          //printf("Iteration #%lu - %.5f \n", i, diff_val);
        }
      }
      
      
    }