Bu karmaşık ifade numpy dilimleri kullanarak nasıl ifade edilir


14

Python'da aşağıdaki ifadeyi uygulamak istiyorum: burada x ve y n boyutunda nümerik dizilerdir ve k nümerik bir dizidir n × n boyutunda . N boyutu yaklaşık 10000 olabilir ve fonksiyon birçok kez değerlendirilecek bir iç döngünün parçasıdır, bu nedenle hız önemlidir.

xi=j=1i1kij,jaijaj,
xynkn×nn

İdeal olarak bir for döngüsünden tamamen kaçınmak istiyorum, ancak sanırım bu bir dünyanın sonu değil. Sorun şu ki, birkaç iç içe döngü olmadan nasıl yapılacağını görmekte sorun yaşıyorum ve bu oldukça yavaş hale getirecek.

Yukarıdaki denklemi numpy'yi verimli ve tercihen de okunabilir bir şekilde nasıl ifade edebileceğini bilen var mı? Daha genel olarak, bu tür şeylere yaklaşmanın en iyi yolu nedir?


Birkaç gün önce benzer bir sorum vardı. Ben stackoverflow de sordum. Bu gönderiye göz atın . Cython yerine scipy.weave kullanıyorum. Bunun herhangi bir (önemli) performans farkı yaratıp yaratmadığını bilen var mı?
seb

Yanıtlar:


17

İşte Numba çözümü. Makinemde Numba versiyonu, dekoratörsüz python versiyonundan> 1000x daha hızlıdır (200x200 matris, 'k' ve 200 uzunluk vektörü 'a' için). Aynı kodun birden fazla türle çalışabilmesi için arama başına yaklaşık 10 mikrosaniye ekleyen @ auutojit dekoratörü de kullanabilirsiniz.

from numba import jit, autojit

@jit('f8[:](f8[:,:],f8[:])')
#@autojit
def looped_ver(k, a):
    x = np.empty_like(a)
    for i in range(x.size):
        sm = 0.0
        for j in range(0, i+1):
            sm += k[i-j,j] * a[i-j] * a[j]
        x[i] = sm
    return x

Açıklama: Ben Numba geliştiricilerinden biriyim.


Teşekkürler, bu oldukça basit görünüyor. Numba'yı bile bilmiyordum! Cython, PyPy, Numba ... kafa karıştırıcı bir dünya.
Nathaniel

3
Travis, çok havalı, cevabının altına numba geliştiricilerinden biri olduğun için bir açıklama eklemeyi düşünüyor musun?
Aron Ahmadia

1
n=200

@NatWilson - bunu scicomp'da bir soru olarak sorarsanız, denemek ve sizin için mücadele etmekten mutluluk duyarım :)
Aron Ahmadia

4

İşte bir başlangıç. İlk olarak, hatalar için özür dilerim.

ii1

Düzenleme: Hayır, üst sınır soruda belirtildiği gibi doğruydu. Burada olduğu gibi bıraktım çünkü başka bir cevap şimdi aynı kodu kullanıyor, ancak düzeltme basit.

İlk önce ilmekli sürüm:

def looped_ver(k, a):
    x = np.empty_like(a)
    for i in range(x.size):
        sm = 0
        for j in range(0, i+1):
            sm += k[i-j,j] * a[i-j] * a[j]
        x[i] = sm
    return x

Numpy dilimleri ile tek bir döngü yaptım:

def vectorized_ver(k, a):
    ktr = zeros_like(k)
    ar = zeros_like(k)
    sz = len(a)
    for i in range(sz):
        ktr[i,:i+1] = k[::-1].diagonal(-sz+i+1)
        a_ = a[:i+1]
        ar[i,:i+1] = a_[::-1] * a_
    return np.sum(ktr * ar, 1)

n=5000

Sonra (daha okunabilir) döngü kodunun bir Cython sürümünü yazdım.

import numpy as np
import cython
cimport numpy as np

@cython.boundscheck(False)
@cython.wraparound(False)
def cyth_ver(double [:, ::1] k not None,
              double [:] a not None):
    cdef double[:] x = np.empty_like(a)
    cdef double sm
    cdef int i, j

    for i in range(len(a)):
        sm = 0.0
        for j in range(i+1):
            sm = sm + k[i-j,j] * a[i-j] * a[j]
        x[i] = sm
    return x

Dizüstü bilgisayarımda bu, ilmekli sürümden yaklaşık 200 kat daha hızlı (ve 1 döngü vektörleştirilmiş sürümden 8 kat daha hızlı). Eminim başkaları daha iyisini yapabilir.

Julia versiyonu ile oynadım ve Cython koduyla karşılaştırılabilir (doğru şekilde zamanladıysam).


x0i1 terim olmadığı anlamına geliyor - ama bu küçük detay.
Nathaniel

Ah, anlıyorum. Bunu orijinal özetinden topladım, ancak niyetin bu olduğundan emin değildim.
Nat Wilson

1

İstediğiniz şey bir evrişimdir; Bunu başarmanın en hızlı yolunun numpy.convolveişlev olacağını düşünüyorum .

Endeksleri tam ihtiyaçlarınıza göre düzeltmek zorunda kalabilirsiniz ancak bence aşağıdaki gibi bir şey denemek istersiniz:

import numpy as np
a = [1, 2, 3, 4, 5]
k = [2, 4, 6, 8, 10]

result = np.convolve(a, k*a[::-1])
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.