LINUX.ORG.RU

пытаемся ускорять с cython


0

1

следуя вот этой статье http://sage.math.washington.edu/home/dagss/numerical-cython-preprint.pdf попытался ускорить тако код:

#!/usr/bin/python
from numpy import *
def matrix(bRow, bCol, out=None):
    for i in range(len(bRow)):
        for j in range(len(bCol)):
            tmp=0.0
            for k in range(len(bRow[i])):
                tmp+=0.000001*(linalg.norm(bRow[i][k]))
            for k in range(len(bCol[j])):
                tmp+=0.000001*(linalg.norm(bCol[j][k]))
            out[i][j]=tmp

в результате получи следующий код:

#!/usr/bin/python
import numpy as np
cimport numpy as np
cimport cython
ctypedef np.float64_t dtype_t
#ctypedef double dtype_t
@cython.boundscheck(False) 
@cython.wraparound(False)
def matrix(np.ndarray[dtype_t, ndim=3] bRow,np.ndarray[dtype_t, ndim=3] bCol,np.ndarray[dtype_t, ndim=2] out=None):
#    cdef long i,j,k
    cdef Py_ssize_t i,j,k
    cdef dtype_t tmp
    for i in range(bRow.shape[0]):
        for j in range(bCol.shape[0]):
            tmp=0.0
            for k in range(bRow.shape[1]):
                tmp+=0.000001*(np.linalg.norm(bRow[i][k]))
            for k in range(bCol.shape[1]):
                tmp+=0.000001*(np.linalg.norm(bCol[j][k]))
            out[i][j]=tmp

После замеров времени в среднем оказалось, что первый и второй вариант работают 2 с половиной минуты. Т.е ни о каком ускорении речи быть и не может. А в статье после типизации обещается ускорение в 130-150 раз, а после отмены проверок в 620 раз.

Что я сделал не так???

P.S. сборка so модуля выполнялась так

$ cython matrixx.pyx 
$ gcc -c -fPIC -I/usr/include/python2.7/ matrixx.c 
$ gcc -shared matrixx.o -o matrixx.so

Ответ на: комментарий от math-beginer

Насколько я могу судить по сгенерированной каше, обращения к объектам идут через Python API, так что ускорения ждать не приходится. Почему так - ХЗ, но в статье по ссылке обсуждаются относительно простые обращения к элементам массива, а у тебя делается вызов linalg в цикле.

Если это продолжение предыдущего разговора, мой совет остается тем же - используй ctypes и стандартную интеграцию ctypes и numpy.

tailgunner ★★★★★
()

может я не прав конечно, но первое, что надо как мне кажется надо оптимизнуть, это range -> xrange + подумать о yield и переводе кода на итераторы

real_maverick ★★★
()
Ответ на: комментарий от tailgunner

стандартную интеграцию ctypes и numpy.

да, действительно это продолжение поиска рабочих способов ускорения Питон скриптов. Что такое стандартная интеграция ctypes и numpy? Я так понимаю, что с помощью ctype можно ускориться за счет типизации? или Вы предлагаете загружать ккие-то библиотеки, обслуживающие Питон операторы numpy?

math-beginer
() автор топика
Ответ на: комментарий от dizza

Проще избавиться от повторяющихся вычислений

anonymous
()
Ответ на: комментарий от dizza

> А на Си питонячий модуль лапками написать не проще?

Не проще, но это и не нужно - можно просто дергать Си=библиотеку через ctypes.

tailgunner ★★★★★
()
Ответ на: комментарий от dizza

А на Си питонячий модуль лапками написать не проще?

в этом случае зачем Питон нужен?

Я перешел с С++ на Python из-за numpy. В большинстве случаев использование матричных операций и функционала numpy позволило упростить код и ускорить расчеты, но есть проблемные блоки (типа циклов в цикле, которые я привел) которые работают жутко медленно (сам пример конечно наигранный).

math-beginer
() автор топика
Ответ на: комментарий от math-beginer

кроме того, написание вот этих проблемных циклов на С++ связано с разработкой «своего numpy» что приводит к затруднениям. В С++ нет готовых инструментов для реализации внутренности циклов (поэтому я и обратился к linalg в примере).

math-beginer
() автор топика
Ответ на: комментарий от math-beginer

в этом случае зачем Питон нужен?

«Обвязку» писать.

dizza ★★★★★
()
Ответ на: комментарий от baverman

Ты вообще не в теме.

наверняка так и есть, но зато я в теме преждевременной оптимизации.

два одинаковых цикла независимых положить в gevent чтобы параллельно лопатились уже даст прирост.

real_maverick ★★★
()
Ответ на: комментарий от real_maverick

чтобы параллельно лопатились уже даст прирост.

Тут речь идет как ускорить раз в 300-500 по сравнению с чистым питоном. gevent здесь не у дел.

baverman ★★★
()
Ответ на: комментарий от baverman

> Тут речь идет как ускорить раз в 300-500

Скока, скока?)

Или предлагаешь переписать в распределенном стиле на С и запускать на кластере из 50-100 процов?)

anonymous
()
Ответ на: комментарий от anonymous

Скока, скока?)

Я не про конкретно этот случай говорю, а про вообще чистый питон.

А здесь хз сколько точно теряется на обертывание в питонячьи плавающие объекты и вызов numpy.linalg.norm, причем там еще getattr на каждый чих. Подозреваю дохрена, навскидку можно убыстрить на порядок-полтора.

baverman ★★★
()

Короче, надо linalg.norm заменить на простой цикл на cython-е, в нём юзать индексы типа bRow[i][j][k], тогда будет быстрее.

vasilenko ★★
()
Ответ на: комментарий от vasilenko

избавление от линалг дает небольшое ускорение, 2m25.312s --- чистый Питон, 1m41.053s --- so модуль из кода ниже. Но это не порядка 500 раз, как обещается в статейке.

#!/usr/bin/python
import numpy as np
cimport numpy as np
cimport cython

ctypedef np.float64_t dtype_t
#ctypedef double dtype_t

@cython.boundscheck(False) 
@cython.wraparound(False)

def matrix(np.ndarray[dtype_t, ndim=3] bRow,np.ndarray[dtype_t, ndim=3] bCol,np.ndarray[dtype_t, ndim=2] out=None):
#    cdef long i,j,k
    cdef Py_ssize_t i,j,k
    cdef dtype_t tmp
    for i in range(bRow.shape[0]):
        for j in range(bCol.shape[0]):
            tmp=0.0
            for k in range(bRow.shape[1]):
                tmp+=0.000001*(bRow[i][k][0]**2.+bRow[i][k][1]**2.+bRow[i][k][2]**2.)**.5
            for k in range(bCol.shape[1]):
                tmp+=0.000001*(bCol[j][k][0]**2.+bCol[j][k][1]**2.+bCol[j][k][2]**2.)**.5
            out[i][j]=tmp

math-beginer
() автор топика
Ответ на: комментарий от vasilenko

Хотя, есть одно подозрение. Насколько я понимаю работа ведеться в SAGE, может только в этом пакете (или как его правильно назвать) все будет работать.

math-beginer
() автор топика
Ответ на: комментарий от tailgunner

думай

0m2.356s

#!/usr/bin/python
##import numpy as np
cimport numpy as np
cimport cython

ctypedef np.float64_t dtype_t
#ctypedef double dtype_t

@cython.boundscheck(False) 
@cython.wraparound(False)

def matrix(np.ndarray[dtype_t, ndim=3, mode="c"] bRow, np.ndarray[dtype_t, ndim=3, mode="c"] bCol, np.ndarray[dtype_t, ndim=2] out=None):
#    cdef long i,j,k
    cdef Py_ssize_t i,j,k
    cdef dtype_t tmp
    for i in range(bRow.shape[0]):
        for j in range(bCol.shape[0]):
            tmp=0.0
            for k in range(bRow.shape[1]):
                tmp+=0.000001*(bRow[i,k,0]**2.+bRow[i,k,1]**2.+bRow[i,k,2]**2.)**.5
            for k in range(bCol.shape[1]):
                tmp+=0.000001*(bCol[j,k,0]**2.+bCol[j,k,1]**2.+bCol[j,k,2]**2.)**.5
            out[i,j]=tmp
math-beginer
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.