python - 并行化只需要在每 X 次迭代中运行的慢速函数,以免降低循环速度
问题描述
该项目
我正在进行一个项目,我需要检测人脸(边界框和地标)并执行人脸识别(识别人脸)。检测速度非常快(在我的笔记本电脑上甚至不需要几毫秒),但识别速度可能非常慢(在我的笔记本电脑上大约需要 0.4 秒)。我正在使用face_recognition
Python 库来执行此操作。经过几次测试,我发现是图像的嵌入速度慢。
这是一个示例代码,您可以自己尝试一下:
# Source : https://pypi.org/project/face-recognition/
import face_recognition
known_image = face_recognition.load_image_file("biden.jpg")
biden_encoding = face_recognition.face_encodings(known_image)[0]
image = face_recognition.load_image_file("your_file.jpg")
face_locations = face_recognition.face_locations(image)
face_landmarks_list = face_recognition.face_landmarks(image)
unknown_encoding = face_recognition.face_encodings(image)[0]
results = face_recognition.compare_faces([biden_encoding], unknown_encoding)
问题
我需要做的是处理视频(30 FPS),因此 0.4s 的计算是不可接受的。我的想法是识别只需要运行几次而不是每一帧,因为从一帧到另一帧,如果视频中没有剪辑,给定的头部将接近其先前的位置。因此,第一次出现头部时,我们运行识别非常慢,但是对于接下来的 X 帧,我们不必这样做,因为我们会检测到位置接近前一个,因此它必须是那个感动的人。当然,这种方法并不完美,但似乎是一个很好的折衷方案,我想尝试一下。
唯一的问题是,通过这样做,视频在出现头部之前是流畅的,然后视频由于识别而冻结,然后再次变得流畅。这就是我想介绍多处理的地方,我希望能够在循环遍历视频帧的同时计算识别。如果我能做到这一点,我将只需要提前处理几帧,这样当一张脸出现时,它已经在几秒钟前在几帧期间计算了它的识别,这样我们就不会看到帧速率降低了。
简单的配方
因此,这就是我所拥有的(在 python 伪代码中,以便更清晰):
def slow_function(image):
# This function takes a lot of time to compute and would normally slow down the loop
return Recognize(image)
# Loop that we need to maintain at a given speed
person_name = "unknown"
frame_index = -1
while True:
frame_index += 1
frame = new_frame() # this is not important and therefore not detailes
# Every ten frames, we run a heavy function
if frame_index % 10 == 0:
person_name = slow_function(image)
# each frame we use the person_name even if we only compute it every so often
frame.drawText(person_name)
我想做这样的事情:
def slow_function(image):
# This function takes a lot of time to compute and would normally slow down the loop
return Recognize(image)
# Loop that we need to maintain at a given speed
person_name = "unknown"
frame_index = -1
while True:
frame_index += 1
frame = new_frame() # this is not important and therefore not detailes
# Every ten frames, we run a heavy function
if frame_index % 10 == 0:
DO slow_function(image) IN parallel WITH CALLBACK(person_name = result)
# each frame we use the person_name even if we only compute it every so often
frame.drawText(person_name)
目标是在循环的多次迭代中计算一个慢速函数。
我试过的
我抬头看了看multiprocessing
,Ray
但没有找到我想做的事的例子。大多数时候,我发现人们使用multiprocessing
同时计算不同输入的函数的结果。这不是我想要的。我希望有一个并行的循环和一个从循环(帧)接受数据的进程,进行一些计算,然后在不中断或减慢循环的情况下向循环返回一个值(或者至少传播减慢速度而不是而不是一个非常慢的迭代和 9 个快速的迭代)。
解决方案
我想我几乎找到了如何做我想做的事。这是一个例子:
from multiprocessing import Pool
import time
# This seems to me more precise than time.sleep()
def sleep(duration, get_now=time.perf_counter):
now = get_now()
end = now + duration
while now < end:
now = get_now()
def myfunc(x):
time.sleep(1)
return x
def mycallback(x):
print('Callback for i = {}'.format(x))
if __name__ == '__main__':
pool=Pool()
# Approx of 5s in total
# Without parallelization, this should take 15s
t0 = time.time()
titer = time.time()
for i in range(100):
if i% 10 == 0: pool.apply_async(myfunc, (i,), callback=mycallback)
sleep(0.05) # 50ms
print("- i =", i, "/ Time iteration:", 1000*(time.time()-titer), "ms")
titer = time.time()
print("\n\nTotal time:", (time.time()-t0), "s")
t0 = time.time()
for i in range(100):
sleep(0.05)
print("\n\nBenchmark sleep time time:", 10*(time.time()-t0), "ms")
当然,我需要添加标志,这样我就不会在循环中读取回调的同时写入值。
推荐阅读
- node.js - Solana 糖果机使用 metaplex / yarn install / node-gyp 错误?
- flutter - 如何在 Flutter 中使用 StreamBuilder 为类似聊天的应用程序监听新数据
- laravel - 在 Laravel 8 中成功登录后我在哪里运行代码?
- reactjs - 如何将 Cloudfront 和 S3 设置为指向每条路由的 index.html?
- codeigniter - 如何在 CodeIgniter 4 中多次渲染部分?
- angular - 在根脚本文件角度中找不到 404
- c++ - 如何使用 C++ 套接字编程同时向多个服务器发送数据?
- mysql - mysql查找聚合表的每条记录来自哪个子表
- node.js - @tensorflow/tfjs-node 在 windows 系统中安装失败
- django - 根据 In Query 返回不同的订单