【问题标题】:Python performance using Boost Python doesn't improve使用 Boost Python 的 Python 性能没有提高
【发布时间】:2014-01-21 05:28:06
【问题描述】:

我正在从事一个大型计算机视觉项目,我需要对来自多个摄像头的每一帧进行一些处理。它很重,我想提高速度。所以我想到了使用 boost python 在 c++ 中包装一个 python 函数。

这里是我想用 c++ 包装的函数:

def computeSumInboundingbox(self, cameraTable, integral):   
   for line in cameraTable:
        minX, minY, maxX, maxY = line[2], line[3], line[4], line[5]
        # sum of the pixel in the bounding box according to integral image
        sumBox = integral[(minY,minX)] + integral[(maxY, maxX)] - integral[(maxY,minX)] - integral[(minY,maxX)]
        # we scale the sumBox
        if sumBox != 0: 
            self.bitmap[line[0],line[1]] = \
                float(sumBox) / ((maxX - minX) * (maxY - minY))

此函数正在从 2D 列表 cameraTable(查找表)中读取一些坐标。该表已在我的课程初始化期间加载。 Integralbitmap 是 2d numpy 数组。 我有很多坐标,所以每一帧都这样做有点慢。

然后我将函数包装在 c++ 中。

boost::python::numeric::array computeSumInboundingbox(boost::python::numeric::array integral, list cameraTable, boost::python::numeric::array bitmap)
{
 list currCameraTable;
 float sumBox;
 for (int i = 0 ; i < len(cameraTable) ; i++)
 {   
    int x = extract<float>(cameraTable[i][0]);
    int y = extract<float>(cameraTable[i][1]);
    float minX = extract<float>(cameraTable[i][2]);
    float minY = extract<float>(cameraTable[i][3]);
    float maxX = extract<float>(cameraTable[i][4]);
    float maxY = extract<float>(cameraTable[i][5]);

    // // sum of the pixel in the bounding box according of integral image
    sumBox = extract<float>(integral[make_tuple(minY, minX)] + integral[make_tuple(maxY, maxX)] - 
            integral[make_tuple(maxY, minX)] - integral[make_tuple(minY, maxX)]);
    // we scale the sumBox 
    if (sumBox != 0)
        bitmap[make_tuple(y,x)] = sumBox / ((maxX - minX) * (maxY - minY));
 }

return bitmap;
}

但是我的性能很差,一个 2000 帧的视频,运行时间多 45 秒!

然后我认为提取函数可能需要一段时间来处理,所以首先我将我的二维列表转换为 python 中的一维 std::vector(我并没有真正找到创建二维向量的方法)

boost::python::numeric::array computeSumInboundingbox(boost::python::numeric::array integral, std::vector<float> cameraTable, boost::python::numeric::array bitmap)
{
 list currCameraTable;
 float sumBox;
 int x;
 int y;
 float minX, minY, maxX, maxY;

 for (int i = 0 ; i < cameraTable.size() ; i+=6)
 {   
    int x = cameraTable[i];
    int y = cameraTable[i+1];
    float minX = cameraTable[i+2];
    float minY = cameraTable[i+3];
    float maxX = cameraTable[i+4];
    float maxY = cameraTable[i+5];

    // // sum of the pixel in the bounding box according of integral image
    sumBox = extract<float>(integral[make_tuple(minY, minX)] + integral[make_tuple(maxY, maxX)] - 
            integral[make_tuple(maxY, minX)] - integral[make_tuple(minY, maxX)]);
    // we scale the sumBox
    if (sumBox != 0)
        bitmap[make_tuple(y,x)] = sumBox / ((maxX - minX) * (maxY - minY));
 }

return bitmap;
}

仅供参考:

BOOST_PYTHON_MODULE(Mapper_ext)
{
    using namespace boost::python;
    using namespace std;

    boost::python::numeric::array::set_module_and_type("numpy", "ndarray");

    class_<vector<float> >("VectorFloat")
    .def(vector_indexing_suite<vector<float> > ());

    def("computeSumInboundingbox", computeSumInboundingbox);
}

这是2000帧这三个函数的处理时间

  • python 函数 = 100s
  • 第一个 c++ 函数 = 145s
  • 第二个 c++ 函数 = 121s

即使第二个 c++ 函数也比第一个好,它仍然比只使用 python 慢。为什么?我认为使用 C++ 会更快,尤其是使用 for 循环。无论如何我可以让 c++ 比 python 执行得更快,还是我在这里浪费时间?

这是我的 numba 版本。一开始我的 createFloorBitmap 方法在我的类中,我将 numba 装饰器添加到类中,但我无法让它工作,所以我将该方法移出类。 setup() 和 execute() 继承自对象 Node。

class Mapper(Node):
 def setup(self):
 # initialise some parameters self.bitmap, self.coordTable
 def execute(self,data):
 # main function
  integral = data['image']
  self.bitmap[:] = 0
  self.bitmap = createFloorBitmap(self.bitmap, self.coordTable, integral)
  return self.bitmap

@jit(f8[:,::1](f8[:,::1], f8[:,::1], f8[:,::1]))       
def createFloorBitmap(bitmap, lines, integral):
 for row in range(lines.shape[0]):
    minX, minY, maxX, maxY = lines[row, 2], lines[row, 3], lines[row, 4], lines[row, 5]
    sumBox = integral[minY,minX] + integral[maxY, maxX] - integral[maxY,minX] - integral[minY,maxX]
    if sumBox != 0:
        bitmap[lines[row, 1],lines[row, 0]] = float(sumBox) / ((maxX - minX) * (maxY - minY))   
return bitmap 

感谢您的帮助

【问题讨论】:

    标签: python c++ performance boost numpy


    【解决方案1】:

    使用数组作为索引可以提高速度,代码如下:

    w = 600
    
    integral = np.random.randint(0, 255, (w, w))
    bitmap = np.zeros_like(integral)
    
    lines = np.random.randint(0, w, (10000, 6))
    
    def computeSumInboundingbox(bitmap, cameraTable, integral):   
       for line in cameraTable:
            minX, minY, maxX, maxY = line[2], line[3], line[4], line[5]
            sumBox = integral[(minY,minX)] + integral[(maxY, maxX)] - integral[(maxY,minX)] - integral[(minY,maxX)]
            if sumBox != 0: 
                bitmap[line[0],line[1]] = float(sumBox) / ((maxX - minX) * (maxY - minY))
    
    def computeSumInboundingbox2(bitmap, line, integral):
        tx, ty, minx, miny, maxx, maxy = line.T
        sumBox = integral[miny, minx] + integral[maxy, maxx] - integral[maxy, minx] - integral[miny, maxx]
        mask = sumBox != 0
        bitmap[tx[mask], ty[mask]] = (sumBox.astype(float)[mask] / ((maxx - minx) * (maxy - miny))[mask])    
    
    bitmap1 = np.zeros_like(integral)
    bitmap2 = np.zeros_like(integral)
    computeSumInboundingbox(bitmap1, lines, integral)
    computeSumInboundingbox2(bitmap2, lines, integral)
    print np.allclose(bitmap1, bitmap2)
    

    时间到了:

    computeSumInboundingbox: 10 loops, best of 3: 42.4 ms per loop
    computeSumInboundingbox2: 100 loops, best of 3: 2.36 ms per loop
    

    为什么 c++ 很慢,因为你使用 python 对象级别的方法来做数组索引。您可以使用 cython,它知道如何访问 c 级别的数据。

    编辑

    这是一个 numba 版本:

    import numba
    @numba.jit("void(i4[:,::1], i4[:,::1], i4[:,::1])")
    def computeSumInboundingbox3(bitmap, lines, integral):
        for row in range(lines.shape[0]):
            minX, minY, maxX, maxY = lines[row, 2], lines[row, 3], lines[row, 4], lines[row, 5]
            sumBox = integral[minY,minX] + integral[maxY, maxX] - integral[maxY,minX] - integral[minY,maxX]
            if sumBox != 0:
                bitmap[lines[row, 0],lines[row, 1]] = float(sumBox) / ((maxX - minX) * (maxY - minY))
    

    还有速度:

    10000 loops, best of 3: 119 µs per loop
    

    【讨论】:

    • 或者,使用 Numpy C-API 函数直接从 c++ 访问数据。
    • 感谢 HYRY,这真的更快!我对 numpy 不够熟悉,认为我可以做到这一点。你认为我仍然可以使用 python 来提高性能吗?
    • 如果正确使用 cython 可以提高性能,但我认为computeSumInboundingbox2 非常接近编译速度,如果速度足够,不需要让你的代码复杂。跨度>
    • 实际上,如果我能获得更快的速度会更好,因为我正在尝试为我的位图图像使用更高的分辨率
    • 我加了一个numba版本,比computeSumInboundingbox2快10倍左右。
    猜你喜欢
    • 2013-01-26
    • 1970-01-01
    • 2017-07-05
    • 1970-01-01
    • 2011-09-15
    • 2013-06-20
    • 1970-01-01
    • 1970-01-01
    • 2018-11-08
    相关资源
    最近更新 更多