按键

时间:2017-09-12 02:37:55

标签: scala apache-spark

我正在研究一种需要对大矩阵进行数学运算的算法。基本上,该算法涉及以下步骤:

输入:两个向量u和v的大小为n

  1. 对于每个向量,计算向量中元素之间的成对欧几里德距离。返回两个矩阵E_u和E_v

  2. 对于两个矩阵中的每个条目,应用函数f。返回两个矩阵M_u,M_v

  3. 求出M_u的特征值和特征向量。返回e_i,ev_i表示i = 0,...,n-1

  4. 计算每个特征向量的外积。返回矩阵O_i = e_i * transpose(e_i),i = 0,...,n-1

  5. 用e_i = e_i + delta_i调整每个特征值,其中delta_i =求和所有元素(O_i和M_v的元素乘积)/ 2 * mu,其中mu是参数

  6. 最终返回矩阵A =元素和(e_i * O_i)i = 0,...,n-1

  7. 我面临的问题主要是当n很大(15000或更多)时的内存,因为这里的所有矩阵都是密集矩阵。我目前实现这一目标的方式可能不是最好的,而且部分有效。

    我使用RowMatrix作为M_u并使用SVD进行特征分解。

    得到的SVD的U因子是一个行矩阵,其列是ev_i' s,因此我必须手动转置它,使其行变为ev_i。得到的e矢量是特征值e_i。

    由于先前尝试将每行ev_i直接映射到O_i因内存不足而失败,我现在正在做

    R = U.map{
        case(i,ev_i) => {
          (i, ev_i.toArray.zipWithIndex)
        }
      }//add index for each element in a vector
      .flatMapValues(x=>x)}
      .join(U)//eigen vectors column is appended
      .map{case(eigenVecId, ((vecElement,elementId), eigenVec))=>(elementId, (eigenVecId, vecElement*eigenVec))}
    

    为了在上面的步骤5中计算调整的e_i,将M_v存储为元组的rdd(i,denseVector)。然后

    deltaRdd = R.join(M_v)
      .map{
        case(j,((i,row_j_of_O_i),row_j_of_M_v))=>
        (i,row_j_of_O_i.t*DenseVector(row_j_of_M_v.toArray)/(2*mu))
      }.reduceByKey(_+_)
    

    最后,为了计算A,再次由于内存问题,我必须先从不同的rdds加入行,然后按键减少。具体来说,

    R_rearranged = R.map{case(j, (i, row_j_of_O_i))=>(i,(j,row_j_of_O_i))}
    termsForA = R_rearranged.join(deltaRdd)
    A = termsForA.map{
      case(i,(j,row_j_of_O_i), delta_i)) => (j, (delta_i + e(i))*row_j_of_O_i)
    }
    .reduceByKey(_+_)
    

    上述实现适用于termsForA的步骤,这意味着如果我在termsForA上执行一个actionForA.take(1).foreach(println),它就成功了。但是如果我在A上执行一个动作,比如A.count(),那么驱动程序就会出现OOM错误。

    我尝试调整sparks配置以增加驱动程序内存以及并行级别,但都失败了。

2 个答案:

答案 0 :(得分:0)

使用IndexedRowMatrix而不是RowMatrix,它将有助于转换和转置。 假设您的IndexedRowMatrix是Irm

svd = Irm.computeSVD(k, True)
U = svd.U
U =  U.toCoordinateMatrix().transpose().toIndexedRowMatrix()

您可以将Irm转换为BlockMatrix,以便与另一个分布式BlockMatrix进行相乘。

答案 1 :(得分:0)

我想在某些时候Spark决定不需要对执行程序进行操作,并且在驱动程序上做所有的工作。实际上,termsForA会像count一样失败。不知怎的,我通过广播deltaRdd和e来实现它。