2015-07-16 2 views
2

Моей средой является ОС: Ubuntu и язык: Python + Cython.Cython: производительность в Python view_as_windows против ручного алгоритма?

У меня есть немного затруднительное положение относительно того, какой путь преследовать. Я использую view_as_windows, чтобы нарезать изображение и возвращать мне массив всех патчей, созданных нарезкой. Я также создал алгоритм, который делает почти то же самое, чтобы иметь больший контроль над срезом. Я тестировал оба алгоритма, и они создают точно те результаты, которые я хочу, теперь моя проблема заключается в том, что мне требуется гораздо более высокая производительность, поэтому я пытаюсь использовать cythonize. Я очень новичок в Cython, поэтому я пока ничего не сделал.

view_as_windows время за изображение: время 0.0033s

patches_by_col за изображение: 0.057s


Вопрос:

Учитывая эти времена хода, я мог бы получить более высокую производительность от cythonizing ручного алгоритма или просто продолжать использовать view_as_windows? Я спрашиваю, потому что я не думаю, что могу cythonize view_as_windows, так как он вызван из numpy. Я тестирую переменную stride disabled (strideDivisor == 0 и imgRegion == 0). Размеры изображений в 1200 на 800.

GetPatchesAndCoordByRow (ручной код)

Параметры:

#Patch Image Settings: Should be 3x2 ratio for width to height 
WIDTH = 60 
HEIGHT = 40 
CHANNELS = 1 
ITERATIONS = 7 
MULTIPLIER = 1.31 
#Stride will be how big of a step each crop takes. 
#If you dont want to crops to overlap, do same stride as width of image. 
STRIDE = 6 
# STRIDE_IMREG_DIV decreases normal stride inside an image region 
    #Set amount by which to divide stride. 
     #Ex: 2 would reduce stride by 50%, and generate 200% data 
     #Ex contd: So it would output 40K patches instead of 20K 
    #strideDivisor = 1.5 
# IMG_REGION determines what % of image region will produce additional patches 
    #Region of image to focus by decreasing stride. Ex: 0.5 would increase patches in inner 50% of image 
    #imgRegion = 0.5 
# Set STRIDE_IMREG_DIV and IMG_REGION = 0 to disable functionality. 
STRIDE_IMREG_DIV = 0 
IMG_REGION = 0 

Исходный код:

def setVarStride(x2, y2, maxX, maxY, stride, div, imgReg, var): 
    imgFocReg1 = imgReg/2 
    imgFocReg2 = 1 - imgFocReg1 

    if (var == 'x'): 
     if ((x2 >= maxX*imgFocReg1) and (x2 <= maxX*imgFocReg2) and (y2 >= maxY*imgFocReg1) and (y2 <= maxY*imgFocReg2)): 
      vStride = stride/div 
     else: 
      vStride = stride 
    elif (var == 'y'): 
     if ((y2 >= maxY*imgFocReg1) and (y2 <= maxY*imgFocReg2)): 
      vStride = stride/div 
     else: 
      vStride = stride 
    return vStride 

def GetPatchesAndCoordByRow(image, patchHeight, patchWidth, stride, strideDivisor, imgRegion): 
    x1 = 0 
    y1 = 0 
    x2 = patchWidth 
    y2 = patchHeight 
    croppedImageList = [] 
    maxX, maxY = image.size 

    #Set variable stride to collect more data in a region of the image 
    varStride = stride 
    useVaraibleStride = True 
    if (strideDivisor == 0 and imgRegion == 0): 
     useVaraibleStride = False 
    else: 
     imgConcentration = (1 - imgRegion)*100 
     print("Variable Stride ENABLED: Create more patches inside {0}% of the image.".format(imgConcentration)) 

    while y2 <= (maxY): 
     while x2 <= (maxX): 
      croppedImage = image.crop((x1,y1,x2,y2)) 
      croppedImageList.append((croppedImage,(x1, y1, x2, y2))) 
      #Get 2x more patches in the center of the image 
      if (useVaraibleStride): 
       varStride = setVarStride(x2, y2, maxX, maxY, stride, strideDivisor, imgRegion, 'x') 
      #Rows 
      x1 += varStride 
      x2 += varStride 
      #--DEBUG 
      #iX += 1 
      #print("Row_{4} -> x1: {0}, y1: {1}, x2: {2}, y2: {3}".format(x1, y1, x2, y2,iX)) 

     #Get 2x more patches in the center of the image 
     if (useVaraibleStride): 
      varStride = setVarStride(x2, y2, maxX, maxY, stride, strideDivisor, imgRegion, 'y') 
     #Columns 
     x1 = 0 
     x2 = patchWidth 
     y1 += varStride 
     y2 += varStride 
     #--DEBUG 
     #iY += 1 
     #print(" Column_{4} -> x1: {0}, y1: {1}, x2: {2}, y2: {3}".format(x1, y1, x2, y2, iY)) 

    #Get patches at edge of image 
    x1 = 0 
    x2 = patchWidth 
    y1 = maxY - patchHeight 
    y2 = maxY 
    #Bottom edge patches 
    while x2 <= (maxX): 
     #--DEBUG 
     #iX += 1 
     #print("Row_{4} -> x1: {0}, y1: {1}, x2: {2}, y2: {3}".format(x1, y1, x2, y2,iX)) 
     #--DEBUG 
     croppedImage = image.crop((x1,y1,x2,y2)) 
     croppedImageList.append((croppedImage,(x1, y1, x2, y2))) 
     #Rows 
     x1 += stride 
     x2 += stride 
    #Right edge patches 
    x1 = maxX - patchWidth 
    x2 = maxX 
    y1 = 0 
    y2 = patchHeight 
    while y2 <= (maxY): 
     #--DEBUG 
     #iY += 1 
     #print(" Column_{4} -> x1: {0}, y1: {1}, x2: {2}, y2: {3}".format(x1, y1, x2, y2, iY)) 
     #--DEBUG 
     croppedImage = image.crop((x1,y1,x2,y2)) 
     croppedImageList.append((croppedImage,(x1, y1, x2, y2))) 
     #Columns 
     y1 += stride 
     y2 += stride 
    #--DEBUG 
    print("GetPatchesAndCoordByRow (Count={0}, W={1}, H={2}, Stride={3})".format(len(croppedImageList), int(patchWidth), int(patchHeight), int(stride))) 

    return croppedImageList 

view_as_windows код

def CreatePatches(image, patchHeight, patchWidth, stride = 1): 
    imageArray = numpy.asarray(image) 
    patches = view_as_windows(imageArray, (patchHeight, patchWidth), stride) 
    print("Raw Patches initial shape: {0}".format(patches.shape)) 
    return patches 

ответ

3

Я не думаю, что вы можете сделать гораздо лучше, чем view_as_windows, как это уже очень эффективно до тех пор, пока массив входных смежный. Я сомневаюсь, что даже cythonizing это будет иметь большое значение. Я рассмотрел его реализацию и был на самом деле немного впечатлен:

Массив numpy состоит из базового массива данных (например, char *) и массива «шагов», по одному для каждого измерения, который показывает, насколько далеко для перемещения по базовому массиву для каждого отдельного шага по этому измерению. The implementation of view_as_windows использует это, создавая новый массив, который использует тот же массив данных, что и его вход, и просто вставляет новые «шаги», чтобы добавить размеры, которые можно использовать для выбора патча. Это означает, что он не возвращает «массив всех патчей», как вы говорите, но он возвращает только один массив, чьи первые измерения действуют как индексы в массив патчей.

Таким образом, view_as_windows не нужно копировать любые данные на вашем изображении для создания патчей и не нужно создавать дополнительные объекты ndarray для каждого патча. Единственный раз, когда нужно копировать данные, - это когда его входной массив не является смежным (например, это фрагмент большего массива). Даже с Китоном я не понимаю, как вы можете сделать это намного лучше.

В вашей реализации, даже если предположить, что image.crop способен обмениваться данными с изображением, вы по-прежнему создаете массив того, что выглядит как 1199x799 различных объектов image.

Вы подтвердили, что view_as_windows где ваш алгоритм проводит большую часть своего времени?

+0

Я добавил дополнительную информацию, в частности часть параметров, используемую для вызова функции. Таким образом, вы можете видеть, что эта функция находится внутри цикла, который выполняет итерацию 7 раз и увеличивает размер патча в 1,31 раза каждый раз с шагом 6. Таким образом, в итоге оба алгоритма создают примерно 20 тыс. Патчей. Основная причина, по которой я создал ручной алгоритм, - это сохранить координаты каждого патча. Поэтому моя единственная забота - получить правильные координаты за патч вне view_as_windows. И есть другие части программы для оптимизации, но я делаю каждый из них за один раз. – alfredox

+0

При использовании 'view_as_windows', похоже, было бы быстрее вычислить абсолютные координаты каждого патча, используя' numpy.linspace' (или возможно, 'numpy.arange') и' numpy.mgrid', а не вычислять их в чистом питоне с использованием циклов while. – codewarrior

+0

На самом деле, я думаю, вам нужно использовать 'numpy.mgrid [: width: stride,: height: stride]'. чтобы получить абсолютные координаты ... – codewarrior

Смежные вопросы