如何显着降低 iOS 应用中的能源影响?
How to significantly reduce Energy Impact in iOS app?
我正在开发具有 Vision 框架功能(处理 CoreML 模型)的 ARKit 应用程序。
loopCoreMLUpdate()
函数形成一个循环,导致 非常高的能量影响 (CPU=70%,GPU=66%)。
如何处理这个任务并将能量影响降低到低水平?
有什么解决此循环问题的方法可以帮助我减少 CPU/GPU 工作量?
这是我的代码:
import UIKit
import SpriteKit
import ARKit
import Vision
class ViewController: UIViewController, ARSKViewDelegate {
@IBOutlet weak var sceneView: ARSKView!
let dispatchQueueML = DispatchQueue(label: "AI")
var visionRequests = [VNRequest]()
// .........................................
// .........................................
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let configuration = AROrientationTrackingConfiguration()
sceneView.session.run(configuration)
loopCoreMLUpdate()
}
func loopCoreMLUpdate() {
dispatchQueueML.async {
self.loopCoreMLUpdate() // SELF-LOOP LEADS TO A VERY HIGH IMPACT
self.updateCoreML()
}
}
func updateCoreML() {
let piBuffer: CVPixelBuffer? = (sceneView.session.currentFrame?.capturedImage)
if piBuffer == nil { return }
let ciImage = CIImage(cvPixelBuffer: piBuffer!)
let imageRequestHandler = VNImageRequestHandler(ciImage: ciImage, options: [:])
do {
try imageRequestHandler.perform(self.visionRequests)
} catch {
print(error)
}
}
// .........................................
// .........................................
}
是的,您标记的行肯定是个大问题。你不是在这里循环;您正在尽可能快地生成新的异步任务,甚至在前一个任务完成之前。在任何情况下,您都试图在创建 CVPixelBuffers 之后更快地捕获它们,这是一种巨大的浪费。
如果你想捕捉帧,你不需要创建一个紧密的循环来对它们进行采样。您将自己设置为 ARSessionDelegate 并实现 session(_:didUpdate:)
。当有可用的新框架时,系统会告诉您。 (可以创建您自己的渲染循环,但您不会在这里这样做,除非您真的需要自己的渲染管道,否则您不应该这样做。)
请记住,您很快就会收到很多帧。 30fps 或 60fps 很常见,但也可以高达 120fps。您不能使用所有的时间片(其他事情也需要处理器时间)。关键是您通常无法跟上帧速率,并且需要缓冲以供以后处理,或丢帧,或两者兼而有之。这是实时处理中非常正常的部分。
对于这种分类系统,您可能需要选择实际的帧率,可能低至 10-20fps,并跳帧以保持该速率。对几十个几乎相同的帧进行分类可能没有帮助。
也就是说,请确保您已阅读 Recognizing Objects in Live Capture。感觉这就是您要尝试做的事情,并且有很好的示例代码可用。
我正在开发具有 Vision 框架功能(处理 CoreML 模型)的 ARKit 应用程序。
loopCoreMLUpdate()
函数形成一个循环,导致 非常高的能量影响 (CPU=70%,GPU=66%)。
如何处理这个任务并将能量影响降低到低水平?
有什么解决此循环问题的方法可以帮助我减少 CPU/GPU 工作量?
这是我的代码:
import UIKit
import SpriteKit
import ARKit
import Vision
class ViewController: UIViewController, ARSKViewDelegate {
@IBOutlet weak var sceneView: ARSKView!
let dispatchQueueML = DispatchQueue(label: "AI")
var visionRequests = [VNRequest]()
// .........................................
// .........................................
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let configuration = AROrientationTrackingConfiguration()
sceneView.session.run(configuration)
loopCoreMLUpdate()
}
func loopCoreMLUpdate() {
dispatchQueueML.async {
self.loopCoreMLUpdate() // SELF-LOOP LEADS TO A VERY HIGH IMPACT
self.updateCoreML()
}
}
func updateCoreML() {
let piBuffer: CVPixelBuffer? = (sceneView.session.currentFrame?.capturedImage)
if piBuffer == nil { return }
let ciImage = CIImage(cvPixelBuffer: piBuffer!)
let imageRequestHandler = VNImageRequestHandler(ciImage: ciImage, options: [:])
do {
try imageRequestHandler.perform(self.visionRequests)
} catch {
print(error)
}
}
// .........................................
// .........................................
}
是的,您标记的行肯定是个大问题。你不是在这里循环;您正在尽可能快地生成新的异步任务,甚至在前一个任务完成之前。在任何情况下,您都试图在创建 CVPixelBuffers 之后更快地捕获它们,这是一种巨大的浪费。
如果你想捕捉帧,你不需要创建一个紧密的循环来对它们进行采样。您将自己设置为 ARSessionDelegate 并实现 session(_:didUpdate:)
。当有可用的新框架时,系统会告诉您。 (可以创建您自己的渲染循环,但您不会在这里这样做,除非您真的需要自己的渲染管道,否则您不应该这样做。)
请记住,您很快就会收到很多帧。 30fps 或 60fps 很常见,但也可以高达 120fps。您不能使用所有的时间片(其他事情也需要处理器时间)。关键是您通常无法跟上帧速率,并且需要缓冲以供以后处理,或丢帧,或两者兼而有之。这是实时处理中非常正常的部分。
对于这种分类系统,您可能需要选择实际的帧率,可能低至 10-20fps,并跳帧以保持该速率。对几十个几乎相同的帧进行分类可能没有帮助。
也就是说,请确保您已阅读 Recognizing Objects in Live Capture。感觉这就是您要尝试做的事情,并且有很好的示例代码可用。