Python — Cython: транспонировать просмотр памяти

Некоторые предпосылки для вопроса:

Я пытаюсь оптимизировать пользовательский код нейронной сети.
Он сильно зависит от циклов, и я решил использовать Cython для ускорения вычислений.

Я следовал обычным онлайн-советам: объявляйте все локальные переменные с соответствующими cdefs, отключайте boundscheck и nonecheck. Это едва дало мне 10% производительности.

Ну, мой код опирается на множество учеников. Поэтому я решил преобразовать весь класс в класс cdef. Оказывается, что Cython не допускает пустые ndarrays в качестве типов для членов класса. Вместо этого нужно использовать виды памяти.
К сожалению, эти два типа кажутся несовместимыми.

Я уже столкнулся с этой проблемой: Cython memoryview transpose: Typeerror

Подводя итог: вы можете сохранить np.ndarray в памяти. Вы можете транспонировать его и сохранить возвращенный массив в memview. Но не в том случае, если это memview является членом класса. Затем вы должны создать промежуточный memview, сохранить в нем результат и назначить промежуточный memview члену класса.

Вот код (большое спасибо DavidW)

def double[:,:,:,:] temporary_view_of_transpose

# temporary_view_of_transpose now "looks at" the memory allocated by transpose
# no square brackets!
temporary_view_of_transpose = out_image.transpose(1, 0, 2, 3)

# data is copied from temporary_view_of_transpose to self.y
self.y[...] = temporary_view_of_transpose # (remembering that self.y must be the correct shape before this assignment).

Теперь у меня новая проблема.
Код выше взят из так называемого «прямого прохода». Существует также соответствующий обратный проход, который выполняет все вычисления в обратном направлении (для аналитических градиентов).

Это означает, что для обратного прохода я должен транспонировать представление памяти и сохранить его в массивном массиве:

cdef np.ndarray[DTYPE_t, ndim=4] d_out_image = self.d_y.transpose(1, 0, 2,3)

d_y должен быть членом класса, поэтому он должен быть представлением памяти. Взгляды на память не позволяют транспонировать. У них есть метод .T, но это мне не помогает.

Актуальный вопрос:

  • Как правильно хранить массив numpy как член класса cdef?
  • Если ответ: «как просмотр памяти», как мне перенести просмотр памяти?

1

Решение

Я думаю, что лучший ответ: «Вы храните NumPy как нетипизированный объект Python»

cdef class C:
cdef object array

def example_function(self):
# if you want to use the fast Cython array indexing in a function
# you can do:
cdef np.ndarray[np.float64_t,ndim=4] self_array = self.array
# or
cdef np.float64_t[:,:,:,:] self_array2 = self.array

# note that neither of these are copies - they're references
# to exactly the same array and so if you modify one it'll modify
# self.array too

def function2(self):
return self.array.transpose(1,0,2,3) # works fine!

Небольшая цена для этого заключается в том, что в начале example_function чтобы проверить, что это на самом деле 4D-массив с правильным dtype. При условии, что вы выполняете приличную работу в функции, которая не должна иметь значения.


В качестве альтернативы (если вы решите, что вы действительно хотите сохранить их в виде памяти), вы можете использование np.asarray преобразовать его обратно в массив Numpy, не делая копию (то есть они обмениваются данными).

например

cdef np.ndarray[DTYPE_t, ndim=4] d_out_image = np.asarray(self.d_y).transpose(1, 0, 2,3)
3

Другие решения

Других решений пока нет …