简体   繁体   中英

What is the most optimal way to apply a kernel to a large array in F#?

I have the following code:

// reduce by 25x
let smallOutput = Array2D.init (output.GetLength(0) / 5) (output.GetLength(1) / 5) (fun _ _ -> Int32.MinValue)
let weights =
    array2D [|
        [| 1; 1; 1; 1; 1 |]
        [| 1; 3; 3; 3; 1 |]
        [| 1; 3; 5; 3; 1 |]
        [| 1; 3; 3; 3; 1 |]
        [| 1; 1; 1; 1; 1 |]
    |]
let weightsSum = 45
for y in [0 .. smallOutput.GetLength(0) - 1] do
    for x in [0 .. smallOutput.GetLength(1) - 1] do
        let mutable v = 0
        for i in [0 .. 4] do
            for j in [0 .. 4] do
                v <- v + weights.[j, i] * output.[y * 5 + j, x * 5 + i]

        smallOutput.[y, x] <- v / weightsSum

It takes a large matrix (16k x 16k) and reduces it by 25x while applying weights.

I understand I can try to do this in a Parallel.ForEach loop, but I am wondering if there is anything built-in F# that would allow to make this faster in the first place.

I don't think there's much you can do to optimize it further, short of doing the summation already when you initialize the smallOutput variable; ie

let smallOutput = Array2D.init (output.GetLength(0) / 5) (output.GetLength(1) / 5) (fun y x -> 
    let mutable v = 0
    for i in [0 .. 4] do
        for j in [0 .. 4] do
            v <- v + weights.[j, i] * output.[y * 5 + j, x * 5 + i]
    v / weightsSum)

The thing is, that you need to loop over all entries in the larger array, there's no way getting around that. If you know beforehand the structure of the weighting-matrix, eg that it's symmetric in some way, you might be able to utilize that. Thought to be honest, I'm not sure how much of an optimization that would yield.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM