2016-05-06 40 views
6

'da Android RenderScript kodunun doğru zamanlaması nasıl yapılır RenderScript'te küçük bir CNN uyguladı ve farklı donanımlardaki performansı izlemek istiyorum. Nexus 7 cihazımda zamanlar anlamlı geliyor, ancak NVIDIA Kalkanı üzerinde değiller.Nvidia Shield

CNN (LeNet) bir sırada yer alan 9 katmanda uygulanır, hesaplama sırayla gerçekleştirilir. Her katman ayrı ayrı zamanlanır.

 conv1 pool1 conv2 pool2 resh1 ip1 relu1 ip2 softmax 
nexus7 11.177 7.813 13.357 8.367 8.097 2.1 0.326 1.557 2.667 
shield 13.219 1.024 1.567 1.081 0.988 14.588 13.323 14.318 40.347 

kez dağıtım conv1 ve conv2 (konvolüsyon tabakaları) ile bağ için sağ ilgili olan çoğu zaman yapılmıştır: Burada

bir örnektir. Ancak kalkanın üzerindeki zamanlar, 2-4 katmanları için makul olanın ötesine geçiyor ve sonuna doğru toplanıyor gibi görünüyor. Softmax tabakası nispeten küçük bir iştir, bu yüzden 40ms çok büyüktür. Zamanlama yöntemim hatalı olmalı veya başka bir şey devam etmeli.

double[] times = new double[layers.size()]; 
int layerindex = 0; 
for (Layer a : layers) { 

    double t = SystemClock.elapsedRealtime(); 
    //long t = System.currentTimeMillis(); // makes no difference 

    blob = a.forward(blob); // here we call renderscript forEach_(), invoke_() etc 

    //mRS.finish(); // makes no difference 

    t = SystemClock.elapsedRealtime() - t; 
    //t = System.currentTimeMillis() - t; // makes no difference 

    times[layerindex] += t; // later we take average etc 

    layerindex++; 
} 

Bir zamanlar forEach_() döndüğünde, iş bitmiş olması gerekiyordu benim anlayış: katmanlarını çalışan

kod şöyle görünür. Her durumda, mRS.finish() son bir engel sağlamalıdır. Ama zamanlara bakıldığında, tek mantıklı açıklama, işlerin arka planda hala işlenmesidir.

Uygulama çok basit, sadece MainActivity'den testi çalıştırıyorum ve logcat'e yazdırıyorum. Android Studio, uygulamayı bir sürüm olarak oluşturur ve USB ile bağlanan cihazda çalıştırır.

(1) RenderScript işlemlerinin doğru yolu nedir? (2) forEach_() öğesi döndüğünde, betik tarafından oluşturulan konuların yapılmasının garanti edildiği doğru mu? (3) Test uygulamamda, doğrudan MainActivity'den çalışıyorum. Bu bir sorun mu (UI iş parçacığının engellenmesi ve uygulamanın yanıt vermemesi dışında)? Bu zamanlamayı etkiliyorsa veya garipliğe neden oluyorsa, böyle bir test uygulaması oluşturmak için uygun bir yol nedir?

+0

CNN açılımı Ve kolay kullanmaktır? –

+0

Konvolüstal Sinir Ağı. – frankhond

cevap

3

RenderScript'te CNN'leri kendim uyguladım ve açıkladığınız gibi, her biri farklı bir çekirdek olarak uygularsanız, her katman için çeşitli süreçleri zincirleme ve forEach_*()'u çeşitli zamanlarda çağırmayı gerektirir. Bu şekilde, geri dönen her bir aramanın, sürecin tamamlandığını garanti etmediğinden emin olabilirsiniz. Teoride, bu yalnızca çekirdeği zamanlayacaktır ve tüm sıraya alınmış talepler, özellikle sistemin tabletin GPU'sunda işlenirse, sistem en iyi şekilde belirlediğinde çalışacaktır.

Genellikle, bir çekirdek üzerinde gerçekten denetime sahip olduğunuzdan emin olmanızın tek yolu, RS çekirdeğinin çıktılarını, örneğin, .copyTo() çıkış çıktı nesnesi üzerinde kullanarak çekirdek. Bu, henüz çalıştırılmayan sıraya alınmış RS işlerini (bu katmanın çıktı tahsisinin bağlı olduğu) o anda yürütülmesini "zorlar". Verilmiş, bu veri aktarım ek yüklerini tanıtabilir ve zamanlamanız tam olarak doğru olmayacaktır - aslında, tam ağın yürütme süresi, bu şekilde zamanlanmışsa, kesinlikle bireysel katmanların toplamından daha düşük olacaktır. Ama bildiğim kadarıyla, bir zincirdeki tek bir kerneli incelemek için tek güvenilir yoldur ve darboğazların nerede olduğunu bulmak için size bazı geribildirimler verir ve optimizasyonunuzu daha iyi yönlendirir, eğer peşindeyseniz buysa.

+0

Teşekkürler! RenderScript anlayışımıma katkıda bulunan diğer sorularınızı okudum. Beynini biraz daha alabilir miyim? Böyle bir şeyi Shield gibi bir GPU ile bir tablet üzerinde test ederken, kodun aslında GPU'da çalışıp çalışmadığını öğrenmek için iyi bir yol ne olurdu? – frankhond

+0

Hmm, her zamanki gibi, bir RS çekirdeğinin nerede çalışacağını söylemek biraz zor, ancak zamanlama kurulumunuz sabitse, normal olarak çalışan çekirdeklerinizle testleri test edebilir ve RS'yi CPU’yu kullanmaya zorlarken bunları çalıştırabilirsiniz sadece 'adb shell setprop debug.rs.default-CPU-driver 1' ile (ve geri kapatmak için 0, bu uygulamayı değiştirmek için bunu değiştirmek arasında düzgün sonlandırmak için emin olun). Eğer çekirdeğiniz iyi yapılandırılmışsa ve GPU'yu gerçekten kullanıyorsa, özellikle karmaşalarda, sadece CPU moduna göre en az 4-6x hızlanma elde etmeniz gerekir. – monoeci

+0

Güzel, Bunu deneyeceğim! Bir yerde bir profiler olduğunu umuyordum, ama bu kesinlikle bir işaret verecekti. Yardımın için tekrar teşekkürler! – frankhond

3

Belki konu dışı biraz: Temel bilgisayar blokları olarak matris-matris çarpımı kullanarak algoritma yapısı eğer ancak CNN için, aslında RenderScript IntrinsicBLAS, özellikle BNNM ve SGEMM kullanabilirsiniz.

Artıları: 8bit Matris Çarpma (BNNM) ait

  1. Yüksek performanslı uygulanması N Preview mevcuttur.
  2. Geri Yükleme desteği 24.0.0 rc3 ve üzeri sürümleri kullanılarak, Android 2.3'ten RenderScript Support lib'a geri.
  3. Nexus5X'te ve N Önizleme NPC91K ile 6P'de SGEMM'nin yüksek performanslı GPU hızlandırması.
  4. Yalnızca RenderScript Intrinsics kullanıyorsanız, her şeyi java'da kodlayabilirsiniz.

Eksileri:

  1. Kişisel algoritması refactored gerekir ve 2d matris çarpma dayalı olması gerekebilir.
  2. Android 6.0 sürümünde kullanılabilir, ancak 6.0'da BNNM performansı tatmin edici değildir. Dolayısıyla, BNNM için destek lib'inin kullanılması ve targetSdkVersion'ın 24 olarak ayarlanması daha iyidir. Şu anda yalnızca Nexus5X ve Nexus6P'de mevcut olan SGEMM GPU hızlandırması.
  3. . Ve şu anda Matrislerin genişliği ve yüksekliğini 8'in katları olarak gerektirmektedir.

BLAS, algoritmanıza uyuyorsa denemeye değer.

import android.support.v8.renderscript.*; 
    // if you are not using support lib: 
    // import android.renderscript.*; 

    private void runBNNM(int m, int n, int k, byte[] a_byte, byte[] b_byte, int c_offset, RenderScript mRS) { 
     Allocation A, B, C; 
     Type.Builder builder = new Type.Builder(mRS, Element.U8(mRS)); 
     Type a_type = builder.setX(k).setY(m).create(); 
     Type b_type = builder.setX(k).setY(n).create(); 
     Type c_type = builder.setX(n).setY(m).create(); 

     // If you are reusing the input Allocations, just create and cache them somewhere else. 
     A = Allocation.createTyped(mRS, a_type); 
     B = Allocation.createTyped(mRS, b_type); 
     C = Allocation.createTyped(mRS, c_type); 
     A.copyFrom(a_byte); 
     B.copyFrom(b_byte); 

     ScriptIntrinsicBLAS blas = ScriptIntrinsicBLAS.create(mRS); 
     // Computes: C = A * B.Transpose 
     int a_offset = 0; 
     int b_offset = 0; 
     int c_offset = 0; 
     int c_multiplier = 1; 
     blas.BNNM(A, a_offset, B, b_offset, C, c_offset, c_multiplier); 
    } 

SGEMM benzer::

 ScriptIntrinsicBLAS blas = ScriptIntrinsicBLAS.create(mRS); 
     // Construct the Allocations: A, B, C somewhere and make sure the dimensions match. 
     // Computes: C = 1.0f * A * B + 0.0f * C 
     float alpha = 1.0f; 
     float beta = 0.0f; 
     blas.SGEMM(ScriptIntrinsicBLAS.NO_TRANSPOSE, ScriptIntrinsicBLAS.NO_TRANSPOSE, 
        alpha, A, B, beta, C); 
+0

Örnekler için teşekkürler. Zaten imbcol ve SGEMM ile matris çarpımını kullanarak, aynı zamanda hareketli bir çekirdek versiyonunu kullanarak konvolüsyonu gerçekleştirdim. Benim sorumun sebebi, bu iki algoritmayı birbiriyle ilişkilendirmeye çalışıyorum. Donanıma bağlı olarak, çılgınca farklı sonuçlar alıyorum ve nedenini anlamaya çalışıyorum. BNNM örneğiniz, bir sonraki aşamaya geçeceğimde çok kullanışlıdır. – frankhond

+0

Ayrıca, GPU hakkında bilgi için çok yararlı, teşekkürler. Bu çevrimiçi bir yerde bulunabilir mi? – frankhond

+0

Henüz değil. Ancak bu konuda daha fazla öğretici ve dokümantasyon olacak. Uygun olan bir kez burada güncelleyeceğim, bizi izlemeye devam edin. Ayrıca, RenderScript için herhangi bir öneri veya özellik isteğiniz varsa lütfen bana bildirin. RenderScript ekibine iletebilirim. Teşekkürler! –