iOS開發之高性能數值計算利器Accelerate

介紹

在進行數值計算、音頻處理或者圖像分析時,性能往往是影響用戶體驗的關鍵因素。為了讓開發者能更方便地利用底層硬件的高性能向量計算能力,Apple 提供了Accelerate框架。它封裝了底層的 SIMD 指令集與高效的數學計算函數,可以用極少的代碼實現高效、并行的計算操作,同時還能節省電量。Accelerate支持在 iOS、macOS、tvOS 與 watchOS 上運行。常用子模塊如下。

  • vDSP:用于數字信號處理。
  • vForce:用于向量化的數學函數。
  • BNNS/BNNSGraph:基礎神經網絡子系統。
  • LAPACK/BLAS:用于線性代數計算。

vDSP使用

  • 求平均數。
import Accelerate

let values: [Float] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
let mean = vDSP.mean(values)
print(mean)
  • 求標準差。
import Accelerate

let values: [Float] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
let sd = vDSP.standardDeviation(values)
print(sd)
  • 向量加法。
import Accelerate

let a: [Float] = [1, 2, 3]
let b: [Float] = [4, 5, 6]
let result = vDSP.add(a, b)
print(result)

vForce使用

  • 計算正弦函數。
import Accelerate

let angles: [Float] = [0, .pi / 4, .pi / 2, .pi]
let sins = vForce.sin(angles)
print(sins)
  • 計算對數。
import Accelerate

let inputs: [Float] = [1, 2.71828, 10]
let logs = vForce.log(inputs)
print(logs)
  • 計算指數。
import Accelerate

let values: [Float] = [0, 1, 2]
let exps = vForce.exp(values)
print(exps)

BNNS/BNNSGraph使用

  • 構造神經網絡。
import Accelerate

let input: [Float] = [1.0, 2.0, 3.0]
var weights: [Float] = [0.1, 0.2, 0.3,
                        0.4, 0.5, 0.6]
var bias: [Float] = [0.1, 0.2]
var output = [Float](repeating: 0, count: 2)

var inDesc = BNNSVectorDescriptor(size: 3, data_type: .float, data_scale: 1.0, data_bias: 0.0)
var outDesc = BNNSVectorDescriptor(size: 2, data_type: .float, data_scale: 1.0, data_bias: 0.0)

let weightData = BNNSLayerData(data: &weights, data_type: .float)
let biasData = BNNSLayerData(data: &bias, data_type: .float)

var layer = BNNSFullyConnectedLayerParameters(
    in_size: 3,
    out_size: 2,
    weights: weightData,
    bias: biasData,
    activation: BNNSActivation(function: .identity, alpha: 0, beta: 0)
)

var filterParams = BNNSFilterParameters()
let layerFilter = BNNSFilterCreateFullyConnectedLayer(&inDesc, &outDesc, &layer, &filterParams)
BNNSFilterApply(layerFilter!, input, &output)
print("BNNS Output:", output)

BNNSFilterDestroy(layerFilter)

LAPACK/BLAS使用

  • 矩陣乘法。
import Accelerate

let A: [Float] = [1, 2, 
                  3, 4]
let B: [Float] = [5, 6, 
                  7, 8]
var C: [Float] = [0, 0, 
                  0, 0]
let m = 2, n = 2, k = 2

cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
            Int32(m), Int32(n), Int32(k), 1.0, 
            A, Int32(k), B, Int32(n), 0.0, &C, Int32(n))
print(C)

應用:圖像高斯模糊處理

  • 代碼。
import Accelerate
import UIKit

class ViewController: UIViewController {
    lazy var imageView: UIImageView = {
        let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
        imageView.image = UIImage(named: "sample")
        imageView.center = view.center
        return imageView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(imageView)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        blurImage()
    }

    func blurImage() {
        if let image = UIImage(named: "sample") {
            if let blurredImage = ImageProcessor.applyGaussianBlur(to: image, withRadius: 30) {
                imageView.image = blurredImage
            } else {
                print("無法應用高斯模糊效果")
            }
        }
    }
}

class ImageProcessor {
    /// 使用vImage對圖像進行高斯模糊處理
    static func applyGaussianBlur(to image: UIImage, withRadius radius: Float) -> UIImage? {
        guard let cgImage = image.cgImage else { return nil }
        // 創建圖像格式
        var format = vImage_CGImageFormat(
            bitsPerComponent: 8,
            bitsPerPixel: 32,
            colorSpace: Unmanaged.passRetained(CGColorSpaceCreateDeviceRGB()),
            bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue | CGBitmapInfo.byteOrder32Little.rawValue),
            version: 0,
            decode: nil,
            renderingIntent: .defaultIntent
        )
        // 創建vImage緩沖區
        var sourceBuffer = vImage_Buffer()
        var error = vImageBuffer_InitWithCGImage(&sourceBuffer, &format, nil, cgImage, vImage_Flags(kvImageNoFlags))
        guard error == kvImageNoError else { return nil }
        // 創建目標緩沖區
        var destinationBuffer = vImage_Buffer()
        destinationBuffer.data = malloc(sourceBuffer.rowBytes * Int(sourceBuffer.height))
        destinationBuffer.width = sourceBuffer.width
        destinationBuffer.height = sourceBuffer.height
        destinationBuffer.rowBytes = sourceBuffer.rowBytes
        guard destinationBuffer.data != nil else {
            free(sourceBuffer.data)
            return nil
        }
        // 卷積核大小
        let kernelSize = UInt32(max(3, Int(radius) | 1))
        // 應用高斯模糊
        error = vImageTentConvolve_ARGB8888(&sourceBuffer,
                                            &destinationBuffer,
                                            nil,
                                            0, 0,
                                            kernelSize, kernelSize,
                                            nil,
                                            vImage_Flags(kvImageEdgeExtend))
        guard error == kvImageNoError else {
            free(sourceBuffer.data)
            free(destinationBuffer.data)
            return nil
        }
        // 從vImage緩沖區創建新的CGImage
        guard let blurredImage = vImageCreateCGImageFromBuffer(&destinationBuffer,
                                                               &format,
                                                               nil,
                                                               nil,
                                                               vImage_Flags(kvImageNoFlags),
                                                               &error) else {
            free(sourceBuffer.data)
            free(destinationBuffer.data)
            return nil
        }
        // 釋放內存
        free(sourceBuffer.data)
        free(destinationBuffer.data)
        if error != kvImageNoError {
            return nil
        }
        // 從CGImage創建UIImage
        return UIImage(cgImage: blurredImage.takeRetainedValue())
    }
}
  • 效果。
效果.gif

總結

Accelerate框架雖然接口相對底層,但非常適合需要處理大量浮點數據的場景,它提供了系統級別的性能優化支持,是開發高性能 App 的得力工具。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容