使用Accelerate框架执行归一化

时间:2020-08-02 17:29:26

标签: swift accelerate-framework

我需要对包含RGB像素数据的Data执行简单的数学运算。目前,我正在这样做:

let imageMean: Float = 127.5
let imageStd: Float = 127.5
let rgbData: Data // Some data containing RGB pixels 
let floats = (0..<rgbData.count).map {
    (Float(rgbData[$0]) - imageMean) / imageStd
}
return Data(bytes: floats, count: floats.count * MemoryLayout<Float>.size)

这有效,但是太慢了。我希望可以使用Accelerate框架来更快地进行计算,但不知道如何执行此操作。我保留了一些空间,以便每次执行此功能时都不会分配它,就像这样:

inputBufferDataNormalized = malloc(width * height * 3) // 3 channels RGB

我尝试了很少的功能,例如vDSP_vasm,但无法使其正常工作。有人可以指导我如何使用它吗?基本上,我需要替换此地图函数,因为它花费的时间太长。一直使用预先分配的空间可能很棒。

2 个答案:

答案 0 :(得分:0)

紧随我对您其他相关问题的评论。您可以使用SIMD并行化操作,但是需要将原始数组拆分为多个块。

这是一个简化的示例,假定该数组可以被64整除,例如,一个1024个元素的数组:

let arr: [Float] = (0 ..< 1024).map { _ in Float.random(in: 0...1) }
let imageMean: Float = 127.5
let imageStd: Float = 127.5

var chunks = [SIMD64<Float>]()
chunks.reserveCapacity(arr.count / 64)

for i in stride(from: 0, to: arr.count, by: 64) {
   let v = SIMD64.init(arr[i ..< i+64])

   chunks.append((v - imageMean) / imageStd) // same calculation using SIMD

}

您现在可以使用下标访问每个chunk

var results: [Float] = []
results.reserveCapacity(arr.count)

for chunk in chunks {
   for i in chunk.indices {
      results.append(chunk[i])
   }
}

当然,如果数组不能被64整除,则需要处理余数。

答案 1 :(得分:0)

我找到了一种使用Accelerate的方法。首先,我像这样为转换后的缓冲区保留空间

var inputBufferDataRawFloat = [Float](repeating: 0, count: width * height * 3)

然后我可以像这样使用它:

let rawBytes = [UInt8](rgbData)
vDSP_vfltu8(rawBytes, 1, &inputBufferDataRawFloat, 1, vDSP_Length(rawBytes.count))
            
vDSP.add(inputBufferDataRawScalars.mean, inputBufferDataRawFloat, result: &inputBufferDataRawFloat)
vDSP.multiply(inputBufferDataRawScalars.std, inputBufferDataRawFloat, result: &inputBufferDataRawFloat)

return Data(bytes: inputBufferDataRawFloat, count: inputBufferDataRawFloat.count * MemoryLayout<Float>.size)

工作非常快。 Accelerate中也许有更好的功能,如果有人知道它,请告诉我。它需要执行功能(A[n] + B) * C(或者确切地说是(A[n] - B) / C,但第一个可以转换为该功能)。