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 的得力工具。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容