【问题标题】:Parallelizing the element wise multiplication of two matrices in F#在 F# 中并行化两个矩阵的元素乘法
【发布时间】:2010-06-04 00:22:25
【问题描述】:

我正在尝试并行化 F# 中两个矩阵的元素乘法。我想不通。我一直在尝试创建任务,但它从不想编译。我的非工作混乱代码如下:

let myBigElemMultiply (m:matrix) (n:matrix) = 
  let AddTwoRows (row:int) (destination:matrix) (source1:matrix) (source2:matrix) =
      for i in 0 .. destination.NumCols
          destination.[row, i] <- source1.[row,i] + source2.[row,i]
      destination
  let result = Matrix.zero(m.NumRows)
  let operations = [ for i in 0 .. m.NumRows -> AddTwoRows i result m n ]
  let parallelTasks = Async.Parallel operations
  Async.RunSynchronously parallelTasks
  result

【问题讨论】:

    标签: f# matrix parallel-processing matrix-multiplication


    【解决方案1】:

    您犯了几个小错误,例如,您还没有弄清楚如何进行矩阵乘法。

    let myBigElemMultiply (m:matrix) (n:matrix) = 
      let AddTwoRows (row:int) (destination:matrix) (source1:matrix) (source2:matrix) =
          for col=0 to destination.NumCols-1 do
            let mutable sum = 0.0
            for k=0 to m.NumCols-1 do
              sum <- sum + source1.[row,k] * source2.[k,col]
            destination.[row,col] <- sum
    
      let result = Matrix.zero m.NumRows n.NumCols
      let operations = [ for i=0 to m.NumRows-1 do yield async { AddTwoRows i result m n} ]
      let parallelTasks = Async.Parallel operations
      Async.RunSynchronously parallelTasks |> ignore
      result
    

    需要注意的一点是,这段代码的性能会很差,因为m.[i,j] 是一种访问矩阵中元素的低效方式。你最好使用二维数组:

    let myBigElemMultiply2 (m:matrix) (n:matrix) = 
      let AddTwoRows (row:int) (destination:matrix) (source1:matrix) (source2:matrix) =
          let destination = destination.InternalDenseValues
          let source1 = source1.InternalDenseValues
          let source2 = source2.InternalDenseValues
          for col=0 to Array2D.length2 destination - 1 do
            let mutable sum = 0.0
            for k=0 to Array2D.length1 source2 - 1 do
              sum <- sum + source1.[row,k] * source2.[k,col]
            destination.[row,col] <- sum
    
      let result = Matrix.zero m.NumRows n.NumCols
      let operations = [ for i=0 to m.NumRows-1 do yield async { AddTwoRows i result m n} ]
      let parallelTasks = Async.Parallel operations
      Async.RunSynchronously parallelTasks |> ignore
      result
    

    测试:

    let r = new Random()
    let A = Matrix.init 280 10340 (fun i j -> r.NextDouble() )
    let B = A.Transpose
    

    一些时间:

    > myBigElemMultiply A B;;
    Real: 00:00:22.111, CPU: 00:00:41.777, GC gen0: 0, gen1: 0, gen2: 0
    val it : unit = ()
    > myBigElemMultiply2 A B;;
    Real: 00:00:08.736, CPU: 00:00:15.303, GC gen0: 0, gen1: 0, gen2: 0
    val it : unit = ()
    > A*B;;
    Real: 00:00:13.635, CPU: 00:00:13.166, GC gen0: 0, gen1: 0, gen2: 0
    val it : unit = ()
    > 
    

    使用 ParallelFor 检查here,它应该比异步有更好的性能。

    【讨论】:

    • OP 实际上确实要求逐元素乘法,即 .* 运算符的作用,而不是我认为您描述的矩阵-矩阵乘法。
    【解决方案2】:

    这里至少有一些可以编译的代码,也许这会让你朝着正确的方向前进?

    let myBigElemMultiply (m:matrix) (n:matrix) =  
        let AddTwoRows (row:int) (destination:matrix) (source1:matrix) (source2:matrix) = 
            async {    
                for i in 0 .. destination.NumCols do
                    destination.[row, i] <- source1.[row,i] + source2.[row,i] 
            }
        let result = Matrix.zero m.NumRows m.NumCols 
        let operations = [ for i in 0 .. m.NumRows -> AddTwoRows i result m n ] 
        let parallelTasks = Async.Parallel operations 
        Async.RunSynchronously parallelTasks |> ignore
        result 
    

    【讨论】:

      【解决方案3】:

      没有意义。一对矩阵的异地元素乘法与复制相比,单个内核将愉快地最大化机器的整个内存带宽,并且添加更多内核不会提高性能。所以这几乎可以肯定是浪费时间。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-08-30
        • 2013-06-02
        • 1970-01-01
        • 2015-01-06
        • 2017-09-14
        • 1970-01-01
        • 1970-01-01
        • 2014-06-17
        相关资源
        最近更新 更多