Android Neural Networks API (NNAPI), Android cihazlarda makine öğrenimi için işlem açısından yoğun işlemler gerçekleştirmek üzere tasarlanmış bir Android C API'dir. NNAPI, nöral ağlar oluşturup eğiten TensorFlow Lite ve Caffe2 gibi daha üst düzey makine öğrenimi çerçeveleri için bir temel işlev katmanı sunmak üzere tasarlanmıştır. API, Android 8.1 (API düzeyi 27) veya sonraki sürümleri çalıştıran tüm Android cihazlarda kullanılabilir.
NNAPI, daha önce eğitilmiş, geliştirici tarafından tanımlanmış modellere Android cihazlardan veri uygulayarak çıkarımı destekler. Çıkarım yapmaya örnek olarak görselleri sınıflandırma, kullanıcı davranışını tahmin etme ve bir arama sorgusu için uygun yanıtları seçme verilebilir.
Cihaz üzerinde çıkarım yapmanın birçok avantajı vardır:
- Gecikme: Ağ bağlantısı üzerinden istek göndermenize ve yanıt beklemenize gerek yoktur. Örneğin bu, bir kameradan gelen ardışık kareleri işleyen video uygulamaları için kritik öneme sahip olabilir.
- Kullanılabilirlik: Uygulama, ağ kapsamının dışında olsa bile çalışır.
- Hız: Sinir ağı işlemeye özgü yeni donanım, tek başına genel amaçlı bir CPU'ya kıyasla çok daha hızlı hesaplama sağlar.
- Gizlilik: Veriler Android cihazdan dışarı çıkmaz.
- Maliyet: Tüm hesaplamalar Android cihazda gerçekleştirildiğinde sunucu grubu gerekmez.
Geliştiricilerin göz önünde bulundurması gereken bazı ödünler de vardır:
- Sistem kullanımı: Nöral ağların değerlendirilmesi için çok fazla hesaplama yapılması gerekir. Bu durum pil gücü kullanımını artırabilir. Bu durum, özellikle uzun süreli hesaplamalar için uygulamanız açısından bir sorun teşkil ediyorsa pil sağlığını izlemeyi düşünebilirsiniz.
- Uygulama boyutu: Modellerinizin boyutuna dikkat edin. Modeller birkaç megabayt alan kaplayabilir. APK'nızda büyük modelleri gruplandırmak kullanıcılarınızı gereksiz yere etkileyecekse modelleri uygulama yüklendikten sonra indirmeyi, daha küçük modeller kullanmayı veya hesaplamalarınızı bulutta çalıştırmayı düşünebilirsiniz. NNAPI, modelleri bulutta çalıştırmak için işlev sağlamaz.
NNAPI'nin nasıl kullanılacağına dair bir örnek görmek için Android Neural Networks API örneğine bakın.
Neural Networks API çalışma zamanını anlama
NNAPI'nin amacı, geliştiricilerin modellerini cihaz dışında eğitip Android cihazlara dağıtmasını sağlayan makine öğrenimi kitaplıkları, çerçeveler ve araçlar tarafından çağrılmasıdır. Uygulamalar genellikle NNAPI'yi doğrudan kullanmaz, bunun yerine daha yüksek seviyedeki makine öğrenimi çerçevelerini kullanır. Bu çerçeveler de desteklenen cihazlarda donanım hızlandırmalı çıkarım işlemleri gerçekleştirmek için NNAPI'yi kullanabilir.
Android'in nöral ağ çalışma zamanı, uygulamanın gereksinimlerine ve Android cihazdaki donanım özelliklerine bağlı olarak, işlem iş yükünü özel nöral ağ donanımı, grafik işleme birimleri (GPU) ve dijital sinyal işlemcileri (DSP'ler) dahil cihaz üzerindeki mevcut işlemciler arasında verimli bir şekilde dağıtabilir.
Özel bir tedarikçi sürücüsü bulunmayan Android cihazlarda NNAPI çalışma zamanı, istekleri CPU üzerinde yürütür.
Şekil 1'de NNAPI için üst düzey sistem mimarisi gösterilmiştir.
![](https://developer.android.google.cn/static/ndk/images/nnapi/nnapi_architecture.png?authuser=5&hl=tr)
Neural Networks API programlama modeli
NNAPI kullanarak hesaplamalar yapmak için öncelikle gerçekleştirilecek hesaplamaları tanımlayan bir yönlendirilmiş grafik oluşturmanız gerekir. Giriş verilerinizle (örneğin, bir makine öğrenimi çerçevesinden aktarılan ağırlıklar ve sapmalar) birlikte bu hesaplama grafiği, NNAPI çalışma zamanı değerlendirmesi için bir model oluşturur.
NNAPI dört ana özetleme kullanır:
- Model: Matematiksel işlemlerin ve eğitim sürecinde öğrenilen sabit değerlerin bir hesaplama grafiği. Bu işlemler nöral ağlara özgüdür. 2 boyutlu (2D) konvolüsyon, mantıksal (sigmoid) etkinleştirme, düzeltilmiş doğrusal (ReLU) etkinleştirme ve daha fazlasını içerir. Model oluşturma, eşzamanlı bir işlemdir.
Başarılı bir şekilde oluşturulduktan sonra ileti dizilerinde ve derlemelerde yeniden kullanılabilir.
NNAPI'de model,
ANeuralNetworksModel
örneği olarak temsil edilir. - Derleme: Bir NNAPI modelini alt düzey kodda derlemek için bir yapılandırmayı temsil eder. Derleme oluşturma eşzamanlı bir işlemdir. Başarıyla oluşturulduktan sonra iş parçacıklarında ve yürütmelerde yeniden kullanılabilir. NNAPI'de her derleme bir
ANeuralNetworksCompilation
örneği olarak temsil edilir. - Bellek: Paylaşılan belleği, bellekle eşlenen dosyaları ve benzer bellek arabelleklerini temsil eder. Bellek arabelleği kullanmak, NNAPI çalışma zamanı verilerinin sürücülere daha verimli bir şekilde aktarılmasını sağlar. Uygulamalar genellikle bir model tanımlamak için gereken her tensörü içeren bir paylaşılan bellek arabelleği oluşturur. Yürütme örneğinin giriş ve çıkışlarını depolamak için bellek arabelleklerini de kullanabilirsiniz. NNAPI'de her bellek arabelleği bir
ANeuralNetworksMemory
örneği olarak temsil edilir. Yürütme: Bir dizi girişe NNAPI modeli uygulamak ve sonuçları toplamak için kullanılan arayüz. Yürütme işlemi eşzamanlı veya eşzamansız olarak gerçekleştirilebilir.
Eşzamansız yürütme için birden fazla iş parçacığı aynı yürütmede bekleyebilir. Bu yürütme işlemi tamamlandığında tüm iş parçacıkları serbest bırakılır.
NNAPI'de her yürütme bir
ANeuralNetworksExecution
örneği olarak temsil edilir.
Şekil 2'de temel programlama akışı gösterilmektedir.
![](https://developer.android.google.cn/static/ndk/images/nnapi/nnapi_flow.png?authuser=5&hl=tr)
Bu bölümün geri kalanında; hesaplama yapmak, modeli derlemek ve derlenen modeli yürütmek için NNAPI modelinizi ayarlama adımları açıklanmaktadır.
Eğitim verilerine erişim sağlama
Eğitilen ağırlık ve ağırlıklandırma verileriniz büyük olasılıkla bir dosyada depolanır. NNAPI çalışma zamanına bu verilere etkili erişim sağlamak için ANeuralNetworksMemory_createFromFd()
işlevini çağırıp açılan veri dosyasının dosya tanımlayıcısını ileterek bir ANeuralNetworksMemory
örneği oluşturun. Ayrıca, bellek koruma bayraklarını ve paylaşılan bellek bölgesinin dosyada başladığı ofseti belirtirsiniz.
// Create a memory buffer from the file that contains the trained data
ANeuralNetworksMemory* mem1 = NULL;
int fd = open("training_data", O_RDONLY);
ANeuralNetworksMemory_createFromFd(file_size, PROT_READ, fd, 0, &mem1);
Bu örnekte tüm ağırlıklarımız için yalnızca bir ANeuralNetworksMemory
örneği kullansak da birden fazla dosya için birden fazla ANeuralNetworksMemory
örneği kullanmak mümkündür.
Yerel donanım arabelleklerini kullan
Model girişleri, çıkışlar ve sabit işlenen değerleri için yerel donanım arabelleklerini kullanabilirsiniz. Belirli durumlarda bir NNAPI hızlandırıcı, sürücünün verileri kopyalamasına gerek kalmadan AHardwareBuffer
nesnelerine erişebilir. AHardwareBuffer
birçok farklı yapılandırmaya sahiptir ve her NNAPI hızlandırıcı bu yapılandırmaların hepsini desteklemeyebilir. Bu sınırlama nedeniyle, ANeuralNetworksMemory_createFromAHardwareBuffer
referans belgelerinde listelenen kısıtlamaları inceleyin ve AHardwareBuffer
kullanan derleme ile yürütmelerin beklendiği gibi çalıştığından emin olmak için hızlandırıcıyı belirtmek üzere cihaz atamasını kullanarak hedef cihazlarda önceden test edin.
NNAPI çalışma zamanının bir AHardwareBuffer
nesnesine erişmesine izin vermek için aşağıdaki kod örneğinde gösterildiği gibi ANeuralNetworksMemory_createFromAHardwareBuffer
işlevini çağırıp AHardwareBuffer
nesnesini ileterek bir ANeuralNetworksMemory
örneği oluşturun:
// Configure and create AHardwareBuffer object AHardwareBuffer_Desc desc = ... AHardwareBuffer* ahwb = nullptr; AHardwareBuffer_allocate(&desc, &ahwb); // Create ANeuralNetworksMemory from AHardwareBuffer ANeuralNetworksMemory* mem2 = NULL; ANeuralNetworksMemory_createFromAHardwareBuffer(ahwb, &mem2);
NNAPI'nin artık AHardwareBuffer
nesnesine erişmesi gerekmediğinde karşılık gelen ANeuralNetworksMemory
örneğini serbest bırakın:
ANeuralNetworksMemory_free(mem2);
Not:
AHardwareBuffer
öğesini yalnızca arabelleğin tamamı için kullanabilirsiniz;ARect
parametresiyle kullanamazsınız.- NNAPI çalışma zamanı arabelleği temizlemez. Yürütmeyi planlamadan önce giriş ve çıkış arabelleklerine erişilebildiğinden emin olmanız gerekir.
- Senkronizasyon gizli dosya tanımlayıcıları için destek yoktur.
- Tedarikçiye özel biçimlere ve kullanım bitlerine sahip bir
AHardwareBuffer
için önbelleğin temizlenmesinden istemcinin mi yoksa sürücünün mi sorumlu olduğunu belirlemek tedarikçi firmanın uygulamasına bağlıdır.
Model
Model, NNAPI'deki temel hesaplama birimidir. Her model, bir veya daha fazla işlenen ve işlemle tanımlanır.
İşlem görenler
İşlemciler, grafiği tanımlamada kullanılan veri nesneleridir. Bunlar arasında modelin giriş ve çıkışları, bir işlemden diğerine aktarılan verileri içeren ara düğümler ve bu işlemlere aktarılan sabit değerler bulunur.
NNAPI modellerine eklenebilecek iki tür işlenen vardır: skalerler ve tensörler.
Skaler, tek bir değeri temsil eder. NNAPI; boole, 16 bit kayan nokta, 32 bit kayan nokta, 32 bit tam sayı ve imzasız tam sayı biçimlerinde skaler değerleri destekler.
NNAPI'deki çoğu işlem tensörleri içerir. Tensörler, n boyutlu dizilerdir. NNAPI; 16 bit kayan nokta, 32 bit kayan nokta, 8 bit nicel, 16 bit nicelikli, 32 bit tam sayı ve 8 bit boole değerlerine sahip tensörleri destekler.
Örneğin, Şekil 3'te toplama ve ardından çarpma olmak üzere iki işlem içeren bir model gösterilmektedir. Model, bir giriş tensörü alır ve bir çıkış tensörü üretir.
![](https://developer.android.google.cn/static/ndk/images/nnapi/nnapi_operands.png?authuser=5&hl=tr)
Yukarıdaki modelin yedi işleneni vardır. Bu işlenenler, modele eklendikleri sıranın diziniyle dolaylı olarak tanımlanır. Eklenen ilk işlemde dizin 0, ikinci işlemde 1 dizin ve bu şekilde devam eder. İşlem gören 1, 2, 3 ve 5, sabit işlenendir.
İşlem görenleri hangi sırayla eklediğiniz önemli değildir. Örneğin, model çıkış işleneni, eklenen ilk öğe olabilir. Önemli olan, bir işlenene atıfta bulunurken doğru dizin değerinin kullanılmasıdır.
İşlem görenlerin türleri vardır. Bunlar modele eklendiklerinde belirtilir.
İşlem gören, bir modelin hem girişi hem çıkışı olarak kullanılamaz.
Her işlem gören; model girişi, sabit veya tam olarak bir işlemin çıkış işleneni olmalıdır.
İşlem görenleri kullanma hakkında daha fazla bilgi için İşlenenler hakkında daha fazla bilgi bölümüne bakın.
İşlemler
Bir işlem, yapılacak hesaplamaları belirtir. Her işlem şu öğelerden oluşur:
- bir işlem türü (ör. toplama, çarpma, evrişim),
- İşlemin giriş için kullandığı işlem görenlerin dizinlerinin listesi ve
- işlemin çıkış için kullandığı işlenenlerin dizinlerinin listesi.
Bu listelerdeki sıra önemlidir. Her işlem türünde beklenen girişler ve çıkışlar için NNAPI API referansına göz atın.
İşlemi eklemeden önce, bir işlemin kullandığı veya ürettiği işlem görenleri modele eklemeniz gerekir.
İşlemleri ekleme sıranız önemli değildir. NNAPI, işlemlerin yürütülme sırasını belirlemek için işlem görenlerin ve işlemlerin işlem grafiğinin oluşturduğu bağımlılıklardan yararlanır.
NNAPI'nin desteklediği işlemler aşağıdaki tabloda özetlenmiştir:
API düzeyi 28'de bilinen sorun: ANEURALNETWORKS_TENSOR_QUANT8_ASYMM
tensörleri Android 9 (API düzeyi 28) ve sonraki sürümlerde kullanılabilen ANEURALNETWORKS_PAD
işlemine aktarılırken NNAPI'den alınan çıkış, TensorFlow Lite gibi üst düzey makine öğrenimi çerçevelerinden elde edilen çıkışla eşleşmeyebilir. Bunun yerine yalnızca ANEURALNETWORKS_TENSOR_FLOAT32
testini geçmeniz gerekir.
Bu sorun, Android 10 (API düzeyi 29) ve sonraki sürümlerde çözülmüştür.
Modeller oluşturun
Aşağıdaki örnekte, şekil 3'te bulunan iki işlemli modeli oluşturduk.
Modeli oluşturmak için aşağıdaki adımları izleyin:
Boş bir model tanımlamak için
ANeuralNetworksModel_create()
işlevini çağırın.ANeuralNetworksModel* model = NULL; ANeuralNetworksModel_create(&model);
ANeuralNetworks_addOperand()
çağrısı yaparak işlenenleri modelinize ekleyin. Veri türleri,ANeuralNetworksOperandType
veri yapısı kullanılarak tanımlanır.// In our example, all our tensors are matrices of dimension [3][4] ANeuralNetworksOperandType tensor3x4Type; tensor3x4Type.type = ANEURALNETWORKS_TENSOR_FLOAT32; tensor3x4Type.scale = 0.f; // These fields are used for quantized tensors tensor3x4Type.zeroPoint = 0; // These fields are used for quantized tensors tensor3x4Type.dimensionCount = 2; uint32_t dims[2] = {3, 4}; tensor3x4Type.dimensions = dims;
// We also specify operands that are activation function specifiers ANeuralNetworksOperandType activationType; activationType.type = ANEURALNETWORKS_INT32; activationType.scale = 0.f; activationType.zeroPoint = 0; activationType.dimensionCount = 0; activationType.dimensions = NULL;
// Now we add the seven operands, in the same order defined in the diagram ANeuralNetworksModel_addOperand(model, &tensor3x4Type); // operand 0 ANeuralNetworksModel_addOperand(model, &tensor3x4Type); // operand 1 ANeuralNetworksModel_addOperand(model, &activationType); // operand 2 ANeuralNetworksModel_addOperand(model, &tensor3x4Type); // operand 3 ANeuralNetworksModel_addOperand(model, &tensor3x4Type); // operand 4 ANeuralNetworksModel_addOperand(model, &activationType); // operand 5 ANeuralNetworksModel_addOperand(model, &tensor3x4Type); // operand 6Uygulamanızın eğitim sürecinden aldığı ağırlıklar ve sapmalar gibi sabit değerlere sahip işlem görenler için
ANeuralNetworksModel_setOperandValue()
veANeuralNetworksModel_setOperandValueFromMemory()
işlevlerini kullanın.Aşağıdaki örnekte, eğitim veri dosyasından Eğitim verilerine erişim sağlama bölümünde oluşturduğumuz bellek arabelleğine karşılık gelen sabit değerler belirledik.
// In our example, operands 1 and 3 are constant tensors whose values were // established during the training process const int sizeOfTensor = 3 * 4 * 4; // The formula for size calculation is dim0 * dim1 * elementSize ANeuralNetworksModel_setOperandValueFromMemory(model, 1, mem1, 0, sizeOfTensor); ANeuralNetworksModel_setOperandValueFromMemory(model, 3, mem1, sizeOfTensor, sizeOfTensor);
// We set the values of the activation operands, in our example operands 2 and 5 int32_t noneValue = ANEURALNETWORKS_FUSED_NONE; ANeuralNetworksModel_setOperandValue(model, 2, &noneValue, sizeof(noneValue)); ANeuralNetworksModel_setOperandValue(model, 5, &noneValue, sizeof(noneValue));Yönlendirilmiş grafikteki hesaplama yapmak istediğiniz her işlem için
ANeuralNetworksModel_addOperation()
işlevini çağırarak işlemi modelinize ekleyin.Bu çağrının parametreleri olarak uygulamanız şunları sağlamalıdır:
- işlem türü
- giriş değerlerinin sayısı
- giriş işlenenleri için dizin dizisi
- çıkış değerlerinin sayısı
- çıkış işlenenleri için dizin dizisi
Operatörün, aynı işlemin hem girişi hem de çıkışı için kullanılamayacağını unutmayın.
// We have two operations in our example // The first consumes operands 1, 0, 2, and produces operand 4 uint32_t addInputIndexes[3] = {1, 0, 2}; uint32_t addOutputIndexes[1] = {4}; ANeuralNetworksModel_addOperation(model, ANEURALNETWORKS_ADD, 3, addInputIndexes, 1, addOutputIndexes);
// The second consumes operands 3, 4, 5, and produces operand 6 uint32_t multInputIndexes[3] = {3, 4, 5}; uint32_t multOutputIndexes[1] = {6}; ANeuralNetworksModel_addOperation(model, ANEURALNETWORKS_MUL, 3, multInputIndexes, 1, multOutputIndexes);ANeuralNetworksModel_identifyInputsAndOutputs()
işlevini çağırarak modelin hangi işlenenleri giriş ve çıkış olarak değerlendirmesi gerektiğini belirleyin.// Our model has one input (0) and one output (6) uint32_t modelInputIndexes[1] = {0}; uint32_t modelOutputIndexes[1] = {6}; ANeuralNetworksModel_identifyInputsAndOutputs(model, 1, modelInputIndexes, 1 modelOutputIndexes);
İsteğe bağlı olarak,
ANeuralNetworksModel_relaxComputationFloat32toFloat16()
çağrısı yaparakANEURALNETWORKS_TENSOR_FLOAT32
öğesinin aralık veya hassasiyetle (IEEE 754 16 bit kayan nokta biçimi kadar düşük) hesaplanmasına izin verilip verilmeyeceğini belirtin.Modelinizin tanımını kesinleştirmek için
ANeuralNetworksModel_finish()
numaralı telefonu arayın. Hata yoksa bu işlev,ANEURALNETWORKS_NO_ERROR
sonuç kodunu döndürür.ANeuralNetworksModel_finish(model);
Model oluşturduktan sonra bu modeli istediğiniz sayıda derleyebilir ve her derlemeyi istediğiniz sayıda çalıştırabilirsiniz.
Akışı kontrol etme
NNAPI modeline kontrol akışı eklemek için aşağıdakileri yapın:
İlgili yürütme alt grafiklerini (
IF
ifadesi içinthen
veelse
alt grafikleri,WHILE
döngüsü içincondition
vebody
alt grafikleri) bağımsızANeuralNetworksModel*
modelleri olarak oluşturun:ANeuralNetworksModel* thenModel = makeThenModel(); ANeuralNetworksModel* elseModel = makeElseModel();
Kontrol akışını içeren modelin içindeki bu modellere referans veren işlem görenler oluşturun:
ANeuralNetworksOperandType modelType = { .type = ANEURALNETWORKS_MODEL, }; ANeuralNetworksModel_addOperand(model, &modelType); // kThenOperandIndex ANeuralNetworksModel_addOperand(model, &modelType); // kElseOperandIndex ANeuralNetworksModel_setOperandValueFromModel(model, kThenOperandIndex, &thenModel); ANeuralNetworksModel_setOperandValueFromModel(model, kElseOperandIndex, &elseModel);
Kontrol akışı işlemini ekleyin:
uint32_t inputs[] = {kConditionOperandIndex, kThenOperandIndex, kElseOperandIndex, kInput1, kInput2, kInput3}; uint32_t outputs[] = {kOutput1, kOutput2}; ANeuralNetworksModel_addOperation(model, ANEURALNETWORKS_IF, std::size(inputs), inputs, std::size(output), outputs);
Derleme
Derleme adımı, modelinizin hangi işlemcilerin yürütüleceğini belirler ve ilgili sürücülerden modelin yürütülmesi için hazırlanmalarını ister. Modelinizin çalıştırılacağı işlemcilere özel makine kodunun oluşturulması bu kapsamda yer alabilir.
Model derlemek için şu adımları uygulayın:
Yeni bir derleme örneği oluşturmak için
ANeuralNetworksCompilation_create()
işlevini çağırın.// Compile the model ANeuralNetworksCompilation* compilation; ANeuralNetworksCompilation_create(model, &compilation);
İsteğe bağlı olarak, hangi cihazlarda yürütüleceğini açıkça seçmek için cihaz ataması özelliğini kullanabilirsiniz.
İsterseniz çalışma zamanının pil gücü kullanımı ile yürütme hızı arasındaki dengeyi değiştirebilirsiniz. Bu işlemi,
ANeuralNetworksCompilation_setPreference()
numaralı telefonu arayarak yapabilirsiniz.// Ask to optimize for low power consumption ANeuralNetworksCompilation_setPreference(compilation, ANEURALNETWORKS_PREFER_LOW_POWER);
Belirtebileceğiniz tercihler şunlardır:
ANEURALNETWORKS_PREFER_LOW_POWER
: İşlemi, pil tüketimini en aza indirecek şekilde tercih edin. Bu, sık yürütülen derlemeler için tercih edilir.ANEURALNETWORKS_PREFER_FAST_SINGLE_ANSWER
: Daha fazla güç tüketimine neden olsa bile en kısa sürede tek bir yanıt vermeyi tercih edin. Bu, varsayılan ayardır.ANEURALNETWORKS_PREFER_SUSTAINED_SPEED
: Birbirini izleyen karelerin işleme hızını (ör. kameradan gelen ardışık kareleri işlerken) en üst düzeye çıkarmayı tercih edin.
İsterseniz
ANeuralNetworksCompilation_setCaching
çağrısı yaparak derleme önbelleğe almayı ayarlayabilirsiniz.// Set up compilation caching ANeuralNetworksCompilation_setCaching(compilation, cacheDir, token);
cacheDir
içingetCodeCacheDir()
değerini kullanın. Belirtilentoken
, uygulamadaki her model için benzersiz olmalıdır.ANeuralNetworksCompilation_finish()
çağrısı yaparak derleme tanımını tamamlayın. Hata yoksa bu işlev,ANEURALNETWORKS_NO_ERROR
sonuç kodunu döndürür.ANeuralNetworksCompilation_finish(compilation);
Cihaz bulma ve atama
NNAPI, Android 10 (API düzeyi 29) ve sonraki sürümleri çalıştıran Android cihazlarda makine öğrenimi çerçeve kitaplıklarının ve uygulamalarının mevcut cihazlar hakkında bilgi almasını ve yürütme için kullanılacak cihazları belirtmesini sağlayan işlevler sağlar. Mevcut cihazlar hakkında bilgi sağlamak, uygulamaların bilinen uyumsuzlukları önlemek için bir cihazda bulunan sürücülerin tam sürümünü almalarına olanak tanır. Uygulamalara, bir modelin farklı bölümlerini hangi cihazların çalıştıracağını belirtme olanağı sağlayarak uygulamalar, dağıtıldıkları Android cihaz için optimize edilebilir.
Cihaz bulma
Kullanılabilir cihazların sayısını almak için ANeuralNetworks_getDeviceCount
kullanın. Her cihazda ANeuralNetworks_getDevice
kullanarak söz konusu cihaza bir referans ANeuralNetworksDevice
örneği ayarlayın.
Cihaz referansınızı aldıktan sonra, aşağıdaki işlevleri kullanarak söz konusu cihazla ilgili ek bilgiler edinebilirsiniz:
ANeuralNetworksDevice_getFeatureLevel
ANeuralNetworksDevice_getName
ANeuralNetworksDevice_getType
ANeuralNetworksDevice_getVersion
Cihaz ataması
Bir modelin belirli cihazlarda hangi işlemlerin çalıştırılabileceğini keşfetmek için ANeuralNetworksModel_getSupportedOperationsForDevices
aracını kullanın.
Yürütme için hangi hızlandırıcıların kullanılacağını kontrol etmek için ANeuralNetworksCompilation_create
yerine ANeuralNetworksCompilation_createForDevices
çağrısı yapın.
Oluşturulan ANeuralNetworksCompilation
nesnesini normal şekilde kullanın.
Sağlanan model, seçili cihazlar tarafından desteklenmeyen işlemler içeriyorsa işlev bir hata döndürür.
Birden fazla cihaz belirtilirse çalışma zamanı, işin cihazlar arasında dağıtılmasından sorumludur.
Diğer cihazlara benzer şekilde, NNAPI CPU uygulaması nnapi-reference
adında ve ANEURALNETWORKS_DEVICE_TYPE_CPU
türünde bir ANeuralNetworksDevice
ile temsil edilir. ANeuralNetworksCompilation_createForDevices
çağrılırken CPU uygulaması, model derleme ve yürütme hata durumlarını işlemek için kullanılmaz.
Bir modeli, belirtilen cihazlarda çalışabilen alt modellere bölmek uygulamanın sorumluluğundadır. Manuel bölümlendirme yapması gerekmeyen uygulamalar, modeli hızlandırmak için mevcut tüm cihazları (CPU dahil) kullanacak şekilde daha basit olan ANeuralNetworksCompilation_create
yöntemini kullanmaya devam etmelidir. Model, ANeuralNetworksCompilation_createForDevices
kullanarak belirttiğiniz cihazlar tarafından tam olarak desteklenemezse ANEURALNETWORKS_BAD_DATA
döndürülür.
Model bölümlendirme
Model için birden fazla cihaz mevcut olduğunda NNAPI çalışma zamanı, çalışmayı cihazlar arasında dağıtır. Örneğin, ANeuralNetworksCompilation_createForDevices
adlı iş ortağına birden fazla cihaz sağlanmışsa çalışmanın tahsis edilmesi sırasında belirtilen tüm cihazlar dikkate alınır. CPU cihazı listede yoksa CPU yürütme özelliğinin devre dışı bırakılacağını unutmayın. ANeuralNetworksCompilation_create
kullanılırken CPU dahil tüm mevcut cihazlar dikkate alınır.
Dağıtım, kullanılabilir cihazlar listesinden seçim yapılarak modeldeki her işlem için işlemi destekleyen ve en iyi performansı bildiren cihaz (istemci tarafından belirtilen yürütme tercihine bağlı olarak en hızlı yürütme süresi veya en düşük güç tüketimi) belirtilerek yapılır. Bu bölümlendirme algoritması, farklı işleyenler arasındaki KS'nin neden olduğu olası verimsizliği dikkate almaz. Bu nedenle, birden fazla işlemci belirtirken (açık olarak ANeuralNetworksCompilation_createForDevices
kullanılırken veya dolaylı olarak ANeuralNetworksCompilation_create
kullanıldığında) sonuçta ortaya çıkan uygulamanın profilini çıkarmak önemlidir.
Modelinizin NNAPI tarafından nasıl bölümlendirildiğini anlamak için Android günlüklerinde bir mesaj olup olmadığını kontrol edin (ExecutionPlan
etiketiyle bilgi düzeyinde):
ModelBuilder::findBestDeviceForEachOperation(op-name): device-index
op-name
, grafikteki işlemin açıklayıcı adıdır. device-index
ise cihaz listesindeki aday cihazın dizinidir.
Bu liste, ANeuralNetworksCompilation_createForDevices
veya ANeuralNetworksCompilation_createForDevices
kullanılıyorsa ANeuralNetworks_getDeviceCount
ve ANeuralNetworks_getDevice
kullanılarak tüm cihazlarda yineleme yapılırken döndürülen cihazların listesidir.
Mesaj (ExecutionPlan
etiketiyle bilgi düzeyinde):
ModelBuilder::partitionTheWork: only one best device: device-name
Bu mesaj, device-name
cihazında tüm grafiğin hızlandırıldığını gösterir.
Uygulama
Yürütme adımı, modeli bir dizi girişe uygular ve hesaplama çıkışlarını, uygulamanızın ayırdığı bir veya daha fazla kullanıcı arabelleğine veya bellek alanına depolar.
Derlenmiş bir modeli yürütmek için şu adımları izleyin:
Yeni bir yürütme örneği oluşturmak için
ANeuralNetworksExecution_create()
işlevini çağırın.// Run the compiled model against a set of inputs ANeuralNetworksExecution* run1 = NULL; ANeuralNetworksExecution_create(compilation, &run1);
Uygulamanızın hesaplama için giriş değerlerini nerede okuyacağını belirtin. Uygulamanız, sırasıyla
ANeuralNetworksExecution_setInput()
veyaANeuralNetworksExecution_setInputFromMemory()
öğesini çağırarak kullanıcı arabelleğinden veya ayrılan bellek alanından giriş değerlerini okuyabilir.// Set the single input to our sample model. Since it is small, we won't use a memory buffer float32 myInput[3][4] = { ...the data... }; ANeuralNetworksExecution_setInput(run1, 0, NULL, myInput, sizeof(myInput));
Uygulamanızın çıkış değerlerini nereye yazacağını belirtin. Uygulamanız, sırasıyla
ANeuralNetworksExecution_setOutput()
veyaANeuralNetworksExecution_setOutputFromMemory()
çağrısı yaparak kullanıcı arabelleğine veya ayrılmış bellek alanına çıkış değerleri yazabilir.// Set the output float32 myOutput[3][4]; ANeuralNetworksExecution_setOutput(run1, 0, NULL, myOutput, sizeof(myOutput));
ANeuralNetworksExecution_startCompute()
işlevini çağırarak yürütme işlemini başlayacak şekilde planlayın. Hata yoksa bu işlev,ANEURALNETWORKS_NO_ERROR
sonuç kodunu döndürür.// Starts the work. The work proceeds asynchronously ANeuralNetworksEvent* run1_end = NULL; ANeuralNetworksExecution_startCompute(run1, &run1_end);
Yürütmenin tamamlanmasını beklemek için
ANeuralNetworksEvent_wait()
işlevini çağırın. Yürütme başarılı olduysa bu işlev,ANEURALNETWORKS_NO_ERROR
sonuç kodunu döndürür. Bekleme, yürütmeyi başlatandan farklı bir iş parçacığında yapılabilir.// For our example, we have no other work to do and will just wait for the completion ANeuralNetworksEvent_wait(run1_end); ANeuralNetworksEvent_free(run1_end); ANeuralNetworksExecution_free(run1);
İsterseniz yeni bir
ANeuralNetworksExecution
örneği oluşturmak için aynı derleme örneğini kullanarak derlenen modele farklı bir giriş grubu uygulayabilirsiniz.// Apply the compiled model to a different set of inputs ANeuralNetworksExecution* run2; ANeuralNetworksExecution_create(compilation, &run2); ANeuralNetworksExecution_setInput(run2, ...); ANeuralNetworksExecution_setOutput(run2, ...); ANeuralNetworksEvent* run2_end = NULL; ANeuralNetworksExecution_startCompute(run2, &run2_end); ANeuralNetworksEvent_wait(run2_end); ANeuralNetworksEvent_free(run2_end); ANeuralNetworksExecution_free(run2);
Eşzamanlı yürütme
Eşzamansız yürütme, iş parçacıklarını oluşturmak ve senkronize etmek için zaman harcar. Dahası, gecikme büyük ölçüde değişken olabilir. Bir iş parçacığının bilgilendirildiği veya uyandırıldığı zaman ile nihayetinde bir CPU çekirdeğine bağlı olduğu zaman arasındaki en uzun gecikmeler 500 mikrosaniyeye kadar çıkabilir.
Gecikmeyi iyileştirmek için bunun yerine bir uygulamayı çalışma zamanına eşzamanlı çıkarım çağrısı yapmaya yönlendirebilirsiniz. Bu çağrı, bir çıkarım başlatıldığında değil, yalnızca çıkarım tamamlandığında döndürülür. Uygulama, çalışma zamanına eşzamansız bir çıkarım çağrısı için ANeuralNetworksExecution_startCompute
yerine, çalışma zamanına eşzamanlı bir çağrı yapmak için ANeuralNetworksExecution_compute
çağrısı yapar. ANeuralNetworksExecution_compute
için yapılan bir çağrı ANeuralNetworksEvent
kabul etmez ve ANeuralNetworksEvent_wait
çağrısıyla eşlenmez.
Seri çekim yürütmeler
NNAPI, Android 10 (API düzeyi 29) ve sonraki sürümleri çalıştıran Android cihazlarda ANeuralNetworksBurst
nesnesi üzerinden seri işlem yürütmeyi destekler. Seri çekim yürütmeler, aynı derlemenin hızlı bir şekilde arka arkaya yürütülmesinden oluşan bir dizi yürütmedir (ör. bir kamera yakalamanın kareleri veya ardışık ses örneklerinde çalışırlar). ANeuralNetworksBurst
nesnelerinin kullanılması, hızlandırıcılara kaynakların yürütmeler arasında yeniden kullanılabileceği ve hızlandırıcıların patlama süresince yüksek performans durumunda kalması gerektiğini belirttiği için yürütmelerin daha hızlı olmasını sağlayabilir.
ANeuralNetworksBurst
, normal yürütme yolunda yalnızca küçük bir değişiklik sunar. Aşağıdaki kod snippet'inde gösterildiği gibi, ANeuralNetworksBurst_create
kullanarak bir seri çekim nesne oluşturursunuz:
// Create burst object to be reused across a sequence of executions ANeuralNetworksBurst* burst = NULL; ANeuralNetworksBurst_create(compilation, &burst);
Seri çekim yürütmeler eşzamanlıdır. Ancak her bir çıkarımı gerçekleştirmek için ANeuralNetworksExecution_compute
yerine çeşitli ANeuralNetworksExecution
nesneleri ANeuralNetworksExecution_burstCompute
işlevine yapılan çağrılarda aynı ANeuralNetworksBurst
ile eşlersiniz.
// Create and configure first execution object // ... // Execute using the burst object ANeuralNetworksExecution_burstCompute(execution1, burst); // Use results of first execution and free the execution object // ... // Create and configure second execution object // ... // Execute using the same burst object ANeuralNetworksExecution_burstCompute(execution2, burst); // Use results of second execution and free the execution object // ...
Artık gerekli olmadığında ANeuralNetworksBurst
nesnesini ANeuralNetworksBurst_free
ile serbest bırakın.
// Cleanup ANeuralNetworksBurst_free(burst);
Eşzamansız komut sıraları ve sınırlı yürütme
NNAPI, Android 11 ve sonraki sürümlerde ANeuralNetworksExecution_startComputeWithDependencies()
yöntemi aracılığıyla eşzamansız yürütmeyi planlamak için ek bir yöntem destekler. Bu yöntemi kullandığınızda yürütme, değerlendirmeye başlamadan önce tüm bağlı etkinliklerin sinyal gönderilmesini bekler. Yürütme tamamlandıktan ve çıkışlar kullanıma hazır olduğunda döndürülen etkinlik için sinyal gönderilir.
Yürütmeyi hangi cihazların gerçekleştirdiğine bağlı olarak etkinlik bir senkronizasyon parmaklığı ile desteklenebilir. Etkinliği beklemek ve yürütmede kullanılan kaynakları kurtarmak için ANeuralNetworksEvent_wait()
yöntemini çağırmanız gerekir. ANeuralNetworksEvent_createFromSyncFenceFd()
kullanarak senkronize çitleri bir etkinlik nesnesine içe aktarabilir ve ANeuralNetworksEvent_getSyncFenceFd()
kullanarak bir etkinlik nesnesindeki senkronize çitleri dışa aktarabilirsiniz.
Dinamik olarak boyutlandırılmış çıkışlar
Çıkış boyutunun giriş verilerine bağlı olduğu, yani model yürütme zamanında boyutun belirlenemediği modelleri desteklemek için ANeuralNetworksExecution_getOutputOperandRank
ve ANeuralNetworksExecution_getOutputOperandDimensions
kullanın.
Aşağıdaki kod örneğinde bunun nasıl yapılacağı gösterilmektedir:
// Get the rank of the output uint32_t myOutputRank = 0; ANeuralNetworksExecution_getOutputOperandRank(run1, 0, &myOutputRank); // Get the dimensions of the output std::vector<uint32_t> myOutputDimensions(myOutputRank); ANeuralNetworksExecution_getOutputOperandDimensions(run1, 0, myOutputDimensions.data());
Temizle
Temizleme adımı, hesaplamanız için kullanılan dahili kaynakların serbest bırakılmasını sağlar.
// Cleanup ANeuralNetworksCompilation_free(compilation); ANeuralNetworksModel_free(model); ANeuralNetworksMemory_free(mem1);
Hata yönetimi ve CPU yedeği
Bölümlendirme sırasında hata oluşursa sürücü bir modelin (bir parçası) derleyemez veya sürücü derlenmiş (bir parçası) bir modeli yürütemezse NNAPI bir veya daha fazla işlemin kendi CPU uygulamasını kullanabilir.
NNAPI istemcisi, işlemin optimize edilmiş sürümlerini (ör. TFLite) içeriyorsa CPU yedeğini devre dışı bırakmak ve hataları istemcinin optimize edilmiş işlem uygulaması ile ele almak avantajlı olabilir.
Android 10'da derleme ANeuralNetworksCompilation_createForDevices
kullanılarak yapılırsa CPU yedeği devre dışı bırakılır.
Android P'de, sürücüde yürütme başarısız olursa NNAPI yürütme işlemi CPU'ya geri döner.
Bu durum, ANeuralNetworksCompilation_createForDevices
yerine ANeuralNetworksCompilation_create
kullanıldığında Android 10'da da geçerlidir.
İlk yürütme bu tek bölüm için geri çekilir ve bu da başarısız olursa modelin tamamı CPU'da yeniden denenir.
Bölümlendirme veya derleme başarısız olursa modelin tamamı CPU'da denenir.
Bazı işlemlerin CPU'da desteklenmediği durumlar vardır ve bu durumlarda derleme veya yürütme, geri çekilmeden başarısız olur.
CPU yedeğini devre dışı bıraktıktan sonra bile modelde CPU'da planlanmış işlemler olabilir. CPU, ANeuralNetworksCompilation_createForDevices
adlı iş ortağına sağlanan işlemciler listesindeyse ve bu işlemleri destekleyen tek işlemciyse veya bu işlemler için en iyi performansı sunan işlemciyse birincil (yedek olmayan) yürütücü olarak seçilir.
CPU yürütülmediğinden emin olmak için nnapi-reference
öğesini cihaz listesinden hariç tutarken ANeuralNetworksCompilation_createForDevices
kullanın.
Android P'den başlayarak debug.nn.partition
özelliği 2 olarak ayarlanarak HATA AYIKLAMA derlemelerinde yürütme sırasında yedek devre dışı bırakılabilir.
Bellek alanları
NNAPI, Android 11 ve sonraki sürümlerde opak bellekler için ayırıcı arayüzler sağlayan bellek alan adlarını destekler. Bu, uygulamaların yürütmeler arasında cihazda yerel anıları iletmesine olanak tanır. Böylece NNAPI, aynı sürücüde art arda yürütme gerçekleştirirken gereksiz yere veri kopyalamaz veya dönüştürmez.
Bellek alanı özelliği, çoğunlukla sürücünün içinde bulunan ve istemci tarafına sık erişim gerektirmeyen tensörler için tasarlanmıştır. Bu tensörlere örnek olarak dizi modellerindeki durum tensörleri verilebilir. İstemci tarafında sık CPU erişimine ihtiyaç duyan tensörler için bunun yerine paylaşılan bellek havuzlarını kullanın.
Opak bellek ayırmak için aşağıdaki adımları uygulayın:
Yeni bir bellek tanımlayıcısı oluşturmak için
ANeuralNetworksMemoryDesc_create()
işlevini çağırın:// Create a memory descriptor ANeuralNetworksMemoryDesc* desc; ANeuralNetworksMemoryDesc_create(&desc);
ANeuralNetworksMemoryDesc_addInputRole()
veANeuralNetworksMemoryDesc_addOutputRole()
çağrılarını yaparak amaçlanan tüm giriş ve çıkış rollerini belirtin.// Specify that the memory may be used as the first input and the first output // of the compilation ANeuralNetworksMemoryDesc_addInputRole(desc, compilation, 0, 1.0f); ANeuralNetworksMemoryDesc_addOutputRole(desc, compilation, 0, 1.0f);
İsteğe bağlı olarak,
ANeuralNetworksMemoryDesc_setDimensions()
çağrısı yaparak bellek boyutlarını belirtin.// Specify the memory dimensions uint32_t dims[] = {3, 4}; ANeuralNetworksMemoryDesc_setDimensions(desc, 2, dims);
ANeuralNetworksMemoryDesc_finish()
yöntemini çağırarak açıklayıcı tanımını tamamlayın.ANeuralNetworksMemoryDesc_finish(desc);
Açıklayıcıyı
ANeuralNetworksMemory_createFromDesc()
öğesine ileterek ihtiyaç duyduğunuz kadar anı ayırın.// Allocate two opaque memories with the descriptor ANeuralNetworksMemory* opaqueMem; ANeuralNetworksMemory_createFromDesc(desc, &opaqueMem);
Artık ihtiyacınız kalmadığında bellek tanımlayıcısını boşaltın.
ANeuralNetworksMemoryDesc_free(desc);
İstemci, oluşturulan ANeuralNetworksMemory
nesnesini yalnızca ANeuralNetworksMemoryDesc
nesnesinde belirtilen rollere göre ANeuralNetworksExecution_setInputFromMemory()
veya ANeuralNetworksExecution_setOutputFromMemory()
ile kullanabilir. Ofset ve uzunluk bağımsız değişkenleri, tüm belleğin kullanıldığını gösterecek şekilde 0 olarak ayarlanmalıdır. İstemci ayrıca ANeuralNetworksMemory_copy()
kullanarak belleğin içeriğini açıkça ayarlayabilir veya çıkarabilir.
Belirtilmemiş boyut veya sıralama rollerine sahip opak anılar oluşturabilirsiniz.
Bu durumda, temel sürücü tarafından desteklenmeyen bellek oluşturma işlemi ANEURALNETWORKS_OP_FAILED
durumuyla başarısız olabilir. Müşterinin Ashmem veya BLOB modu AHardwareBuffer
ile desteklenen yeterince büyük bir tampon ayırarak yedek mantığı uygulaması önerilir.
NNAPI'nin artık opak bellek nesnesine erişmesi gerekmediğinde karşılık gelen ANeuralNetworksMemory
örneğini serbest bırakın:
ANeuralNetworksMemory_free(opaqueMem);
Performans ölçme
Yürütme süresini ölçerek veya profili çıkararak uygulamanızın performansını değerlendirebilirsiniz.
Yürütme süresi
Çalışma zamanı boyunca toplam yürütme süresini belirlemek istediğinizde eşzamanlı yürütme API'sini kullanabilir ve çağrının aldığı süreyi ölçebilirsiniz. Toplam yürütme süresini yazılım yığınının daha düşük bir düzeyinde belirlemek istediğinizde ANeuralNetworksExecution_setMeasureTiming
ve ANeuralNetworksExecution_getDuration
araçlarını kullanarak şunları elde edebilirsiniz:
- yürütme süresini bir hızlandırıcıda (ana makine işlemcisinde çalışan sürücüde değil) çalıştırmanız gerekir.
- hızlandırıcıdaki süre de dahil olmak üzere sürücüdeki yürütme süresi.
Sürücüdeki yürütme süresine, çalışma zamanının kendisininki ve çalışma zamanının sürücüyle iletişim kurması için gereken IPC gibi ek yük dahil edilmez.
Bu API'ler, bir sürücünün veya hızlandırıcının çıkarımı yapmak için ayırdığı (muhtemelen bağlam değişikliği nedeniyle kesintiye uğrar) süre yerine, gönderilen çalışma ile tamamlanan iş etkinlikleri arasındaki süreyi ölçer.
Örneğin, çıkarım 1 başlarsa sürücü, çıkarım 2'yi gerçekleştirmek için çalışmayı durdurur, sonra çıkarım 1'i devam ettirir ve çıkarım 1'i tamamlar. Çıkarım 1'in yürütme süresi, çıkarım 2'yi gerçekleştirmek için çalışmanın durdurulduğu süreyi içerir.
Bu zamanlama bilgileri, çevrimdışı kullanım için telemetri toplamak üzere bir uygulamanın üretim dağıtımı sırasında faydalı olabilir. Uygulamayı daha yüksek performans için değiştirmek üzere zamanlama verilerini kullanabilirsiniz.
Bu işlevi kullanırken aşağıdakileri göz önünde bulundurun:
- Zamanlama bilgilerinin toplanmasının performans maliyeti olabilir.
- NNAPI çalışma zamanında ve IPC'de harcanan süre hariç olmak üzere, yalnızca sürücüler kendi başına veya hızlandırıcıda harcanan zamanı hesaplayabilir.
- Bu API'leri yalnızca
numDevices = 1
ileANeuralNetworksCompilation_createForDevices
ile oluşturulan birANeuralNetworksExecution
ile kullanabilirsiniz. - Zamanlama bilgilerini bildirebilmek için herhangi bir sürücüye gerek yoktur.
Android Systrace ile uygulamanızın profilini oluşturun
NNAPI, Android 10'dan itibaren uygulamanızın profilini çıkarmak için kullanabileceğiniz systrace etkinliklerini otomatik olarak oluşturur.
NNAPI Kaynağı, uygulamanız tarafından oluşturulan sistem izleme etkinliklerini işlemek ve model yaşam döngüsünün farklı aşamalarında (Örnekleme, Hazırlama, Derleme Yürütme ve Sonlandırma) ve uygulamaların farklı katmanlarında harcanan süreyi gösteren bir tablo görünümü oluşturmak için bir parse_systrace
yardımcı programıyla birlikte gelir. Uygulamanızın bölündüğü katmanlar şunlardır:
Application
: ana uygulama koduRuntime
: NNAPI Çalışma ZamanıIPC
: NNAPI Çalışma Zamanı ile Sürücü kodu arasındaki işlemler arası iletişimDriver
: hızlandırıcı sürücü işlemi.
Profil çıkarma analiz verilerini oluşturma
$ANDROID_BUILD_TOP adresindeki AOSP kaynak ağacını incelediğinizi ve hedef uygulama olarak TFLite görüntü sınıflandırma örneğini kullandığınızı varsayarsak aşağıdaki adımlarla NNAPI profil oluşturma verilerini oluşturabilirsiniz:
- Aşağıdaki komutla Android sistem izlemeyi başlatın:
$ANDROID_BUILD_TOP/external/chromium-trace/systrace.py -o trace.html -a org.tensorflow.lite.examples.classification nnapi hal freq sched idle load binder_driver
-o trace.html
parametresi, izlerin trace.html
içine yazılacağını gösterir. Kendi uygulamanızın profilini oluştururken org.tensorflow.lite.examples.classification
kodunu uygulama manifestinizde belirtilen işlem adıyla değiştirmeniz gerekir.
Bu işlem, kabuk konsollarınızdan birini meşgul tutacaktır. Etkileşimli olarak enter
komutunun sona ermesini beklediğinden komutu arka planda çalıştırmayın.
- Sistem izleme toplayıcısı başlatıldıktan sonra uygulamanızı başlatın ve karşılaştırma testinizi çalıştırın.
Bizim örneğimizde, Görüntü Sınıflandırma uygulamasını Android Studio'dan veya uygulama zaten yüklenmişse doğrudan test telefonunuzun kullanıcı arayüzünden başlatabilirsiniz. NNAPI verileri oluşturmak için uygulama yapılandırma iletişim kutusunda NNAPI'yi hedef cihaz olarak seçerek uygulamayı NNAPI kullanacak şekilde yapılandırmanız gerekir.
Test tamamlandığında, 1. adımdan itibaren etkin olan konsol terminalinde
enter
tuşuna basarak sistem izlemeyi sonlandırın.Kümülatif istatistikler oluşturmak için
systrace_parser
yardımcı programını çalıştırın:
$ANDROID_BUILD_TOP/frameworks/ml/nn/tools/systrace_parser/parse_systrace.py --total-times trace.html
Ayrıştırıcı şu parametreleri kabul eder:
- --total-times
: Temel katmana yapılan bir çağrıda yürütmeyi beklerken harcanan süre dahil olmak üzere bir katmanda harcanan toplam süreyi gösterir
- --print-detail
: systrace'den toplanan tüm etkinlikleri yazdırır
- --per-execution
: Tüm aşamalar için istatistikler yerine yalnızca yürütmeyi ve alt aşamalarını yazdırır (yürütme sürelerine göre)
- --json
: çıktıyı JSON biçiminde üretir
Çıkışın bir örneği aşağıda gösterilmiştir:
===========================================================================================================================================
NNAPI timing summary (total time, ms wall-clock) Execution
----------------------------------------------------
Initialization Preparation Compilation I/O Compute Results Ex. total Termination Total
-------------- ----------- ----------- ----------- ------------ ----------- ----------- ----------- ----------
Application n/a 19.06 1789.25 n/a n/a 6.70 21.37 n/a 1831.17*
Runtime - 18.60 1787.48 2.93 11.37 0.12 14.42 1.32 1821.81
IPC 1.77 - 1781.36 0.02 8.86 - 8.88 - 1792.01
Driver 1.04 - 1779.21 n/a n/a n/a 7.70 - 1787.95
Total 1.77* 19.06* 1789.25* 2.93* 11.74* 6.70* 21.37* 1.32* 1831.17*
===========================================================================================================================================
* This total ignores missing (n/a) values and thus is not necessarily consistent with the rest of the numbers
Toplanan etkinlikler tam bir uygulama izlemeyi temsil etmiyorsa ayrıştırıcı başarısız olabilir. Özellikle bir bölümün sonunu işaretlemek için oluşturulan sistem izleme etkinlikleri, ilişkili bir bölüm başlangıç etkinliği olmadan izde mevcutsa başarısız olabilir. Bu genellikle sistem izleme toplayıcısını başlattığınızda önceki bir profil çıkarma oturumuna ait bazı etkinlikler oluşturuluyorsa ortaya çıkar. Bu durumda, profil oluşturma işleminizi tekrar çalıştırmanız gerekir.
Uygulama kodunuzun istatistiklerini systrace_parser çıkışına ekleyin
ayrıştır_systrace uygulaması, yerleşik Android sistem izleme işlevine dayanır. Özel etkinlik adlarıyla systrace API'yi (Java için, yerel uygulamalar için) kullanarak uygulamanızdaki belirli işlemler için izler ekleyebilirsiniz.
Özel etkinliklerinizi Uygulama yaşam döngüsünün aşamalarıyla ilişkilendirmek için etkinlik adınızın başına aşağıdaki dizelerden birini ekleyin:
[NN_LA_PI]
: Başlatma için uygulama düzeyinde etkinlik[NN_LA_PP]
: Hazırlık için uygulama düzeyinde etkinlik[NN_LA_PC]
: Derleme için uygulama düzeyinde etkinlik[NN_LA_PE]
: Yürütme için uygulama düzeyinde etkinlik
Execution
aşaması için bir runInferenceModel
bölümü ve NNAPI izlerinde dikkate alınmayacak başka bölümleri preprocessBitmap
içeren Application
katmanı ekleyerek TFLite görüntü sınıflandırma örnek kodunu nasıl değiştirebileceğinize dair bir örneği burada bulabilirsiniz. runInferenceModel
bölümü, nnapi systrace ayrıştırıcısı tarafından işlenen sistem izleme etkinliklerinin bir parçası olacaktır:
Kotlin
/** Runs inference and returns the classification results. */ fun recognizeImage(bitmap: Bitmap): List{ // This section won’t appear in the NNAPI systrace analysis Trace.beginSection("preprocessBitmap") convertBitmapToByteBuffer(bitmap) Trace.endSection() // Run the inference call. // Add this method in to NNAPI systrace analysis. Trace.beginSection("[NN_LA_PE]runInferenceModel") long startTime = SystemClock.uptimeMillis() runInference() long endTime = SystemClock.uptimeMillis() Trace.endSection() ... return recognitions }
Java
/** Runs inference and returns the classification results. */ public ListrecognizeImage(final Bitmap bitmap) { // This section won’t appear in the NNAPI systrace analysis Trace.beginSection("preprocessBitmap"); convertBitmapToByteBuffer(bitmap); Trace.endSection(); // Run the inference call. // Add this method in to NNAPI systrace analysis. Trace.beginSection("[NN_LA_PE]runInferenceModel"); long startTime = SystemClock.uptimeMillis(); runInference(); long endTime = SystemClock.uptimeMillis(); Trace.endSection(); ... Trace.endSection(); return recognitions; }
Hizmet kalitesi
Android 11 ve sonraki sürümlerde NNAPI, uygulamanın modellerinin göreli önceliklerini, belirli bir modeli hazırlamak için beklenen maksimum süreyi ve belirli bir hesaplamayı tamamlaması için beklenen maksimum süreyi belirtmesine izin vererek daha iyi hizmet kalitesi (QoS) sağlar. Android 11, uygulamaların, yürütme son tarihlerinin kaçırılması gibi hataları anlamasını sağlayan ek NNAPI sonuç kodları da sunar.
İş yükünün önceliğini ayarlama
Bir NNAPI iş yükünün önceliğini ayarlamak için ANeuralNetworksCompilation_finish()
çağrısından önce ANeuralNetworksCompilation_setPriority()
yöntemini çağırın.
Son tarihler belirleyin
Uygulamalar hem model derleme hem de çıkarım için son tarihler ayarlayabilir.
- Derleme zaman aşımını ayarlamak için
ANeuralNetworksCompilation_finish()
çağrısından önceANeuralNetworksCompilation_setTimeout()
çağrısı yapın. - Çıkarım zaman aşımını ayarlamak için derlemeyi başlatmadan önce
ANeuralNetworksExecution_setTimeout()
yöntemini çağırın.
İşlem görenler hakkında daha fazla bilgi
Aşağıdaki bölümde, işlenenlerin kullanımıyla ilgili ileri düzey konular ele alınmaktadır.
Nicel tensörler
Nicelleştirilmiş tensör, n boyutlu bir kayan nokta değerleri dizisini temsil etmenin kompakt bir yoludur.
NNAPI, 8 bit asimetrik nicelenmiş tensörleri destekler. Bu tensörler için her hücrenin değeri 8 bitlik bir tam sayı ile temsil edilir. Tensörle ilişkili olarak bir ölçek ve sıfır puan değeri bulunur. Bunlar, 8 bitlik tam sayıları temsil edilen kayan nokta değerlerine dönüştürmek için kullanılır.
Formül şöyledir:
(cellValue - zeroPoint) * scale
Burada sıfırPoint değeri 32 bitlik bir tam sayı, ölçek ise 32 bitlik bir kayan nokta değeridir.
32 bitlik kayan nokta değerlerinin tensörlerine kıyasla 8 bitlik nicelenmiş tensörlerin iki avantajı vardır:
- Eğitilen ağırlıklar 32 bit tensörlerin dörtte birini kullandığından uygulamanız daha küçüktür.
- Hesaplamalar genellikle daha hızlı yürütülebilir. Bunun nedeni, bellekten alınması gereken daha az veri miktarı ve tamsayı hesaplaması yaparken TTP'ler gibi işlemcilerin verimliliğidir.
Kayan nokta modelini sayısallaştırılmış bir modele dönüştürmek mümkün olsa da deneyimimiz, nicelenmiş bir modelin doğrudan eğitilmesiyle daha iyi sonuçlar elde edildiğini göstermiştir. Aslında nöral ağ, her bir değerin artan ayrıntı düzeyini dengelemeyi öğrenir. Ölçülen her tens için ölçek ve sıfır noktası değerleri eğitim sürecinde belirlenir.
NNAPI'de, ANeuralNetworksOperandType
veri yapısının tür alanını ANEURALNETWORKS_TENSOR_QUANT8_ASYMM
olarak ayarlayarak miktarlandırılmış tensör türlerini tanımlarsınız.
Bu veri yapısındaki tensörün ölçeğini ve zeroPoint değerini de belirtirsiniz.
NNAPI, 8 bit asimetrik nicelenmiş tensörlere ek olarak şunları da destekler:
ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL
. AğırlıklarıCONV/DEPTHWISE_CONV/TRANSPOSED_CONV
işlemlerine göstermek için kullanabilirsiniz.QUANTIZED_16BIT_LSTM
öğesinin dahili durumu için kullanabileceğinizANEURALNETWORKS_TENSOR_QUANT16_ASYMM
.ANEURALNETWORKS_TENSOR_QUANT8_SYMM
,ANEURALNETWORKS_DEQUANTIZE
için giriş olabilir.
İsteğe bağlı işlenenler
ANEURALNETWORKS_LSH_PROJECTION
gibi birkaç işlem, isteğe bağlı işlenenler alır. Modelde isteğe bağlı işlenenin atlandığını belirtmek için ANeuralNetworksModel_setOperandValue()
işlevini çağırarak arabellek için NULL
ve uzunluk için 0 değerini iletin.
İşlenenin mevcut olup olmadığına dair karar her yürütme için değişiyorsa ANeuralNetworksExecution_setInput()
veya ANeuralNetworksExecution_setOutput()
işlevlerini kullanarak işlenenin atlandığını belirtir ve arabellek için NULL
, uzunluk için 0 değerini iletirsiniz.
Bilinmeyen derecedeki tensörler
Android 9 (API düzeyi 28), bilinmeyen boyutlara ancak bilinen sıralamaya (boyut sayısı) sahip model işlem görenlerini kullanıma sundu. ANeural NetworksType bölümünde gösterildiği gibi, Android 10 (API düzeyi 29), bilinmeyen sıra tensörlerini kullanıma sunmuştur.
NNAPI karşılaştırması
NNAPI karşılaştırmasını AOSP'de platform/test/mlts/benchmark
(karşılaştırma uygulaması) ve platform/test/mlts/models
(modeller ve veri kümeleri) üzerinde bulabilirsiniz.
Bu karşılaştırma, gecikme ve doğruluğu değerlendirir ve sürücüleri, aynı modeller ve veri kümeleri için CPU üzerinde çalışan Tensorflow Lite kullanılarak yapılan işle karşılaştırır.
Karşılaştırmayı kullanmak için aşağıdakileri yapın:
Bilgisayarınıza hedef bir Android cihaz bağlayın, bir terminal penceresi açın ve cihaza adb ile erişilebildiğinden emin olun.
Birden fazla Android cihaz bağlıysa hedef cihaz
ANDROID_SERIAL
ortam değişkenini dışa aktarın.Android'in üst düzey kaynak dizinine gidin.
Şu komutları çalıştırın:
lunch aosp_arm-userdebug # Or aosp_arm64-userdebug if available ./test/mlts/benchmark/build_and_run_benchmark.sh
Karşılaştırma çalıştırmasının sonunda, sonuçları
xdg-open
ürününe iletilen bir HTML sayfası olarak sunulur.
NNAPI günlükleri
NNAPI, sistem günlüklerinde yararlı teşhis bilgileri oluşturur. Günlükleri analiz etmek için logcat yardımcı programını kullanın.
debug.nn.vlog
özelliğini (adb shell
kullanarak) boşluk, iki nokta veya virgülle ayrılmış olarak aşağıdaki değer listesine ayarlayarak belirli aşamalar veya bileşenler için ayrıntılı NNAPI günlük kaydını etkinleştirin:
model
: Model oluşturmacompilation
: Model yürütme planı ve derlemesinin oluşturulmasıexecution
: Model yürütmecpuexe
: NNAPI CPU uygulamasını kullanarak işlemlerin yürütülmesimanager
: NNAPI uzantıları, kullanılabilir arayüzler ve özelliklerle ilgili bilgilerall
veya1
: Yukarıdaki tüm öğeler
Örneğin, tam ayrıntılı günlük kaydını etkinleştirmek için adb shell setprop debug.nn.vlog all
komutunu kullanın. Ayrıntılı günlük kaydını devre dışı bırakmak için adb shell setprop debug.nn.vlog '""'
komutunu kullanın.
Etkinleştirildiğinde ayrıntılı günlük kaydı, aşama veya bileşen adına ayarlanmış bir etiket ile INFO düzeyinde günlük girişleri oluşturur.
NNAPI API bileşenleri, debug.nn.vlog
kontrollü mesajların yanında her biri belirli bir günlük etiketi kullanan çeşitli düzeylerde başka günlük girişleri sağlar.
Bileşen listesini almak için aşağıdaki ifadeyi kullanarak kaynak ağacında arama yapın:
grep -R 'define LOG_TAG' | awk -F '"' '{print $2}' | sort -u | egrep -v "Sample|FileTag|test"
Bu ifade şu anda aşağıdaki etiketleri döndürmektedir:
- Patlama Oluşturucu
- Geri çağırma işlevleri
- Derleme Oluşturucu
- CPU Yürütücü
- Yürütme Oluşturucu
- YürütmeBurstDenetleyicisi
- YürütmeBurstSunucusu
- Yürütme Planı
- FibonacciSürücü
- GraphDump
- Dizine Eklenmiş Şekil Sarmalayıcı
- IonWatcher
- Müdür
- Hafıza
- Bellek Utilleri
- MetaModel
- ModelArgumentBilgisi
- Model Oluşturucu
- Sinir Ağları
- İşlem Çözücü
- İşlemler
- İşlem Yardımcıları
- Paket Bilgileri
- TokenHasher
- Tür Yöneticisi
- Yardımcı programlar
- Doğrulama
- Sürümlü Arayüzler
logcat
tarafından gösterilen günlük mesajlarının düzeyini kontrol etmek için ANDROID_LOG_TAGS
ortam değişkenini kullanın.
NNAPI günlük mesajlarının tümünü göstermek ve diğerlerini devre dışı bırakmak için ANDROID_LOG_TAGS
öğesini aşağıdaki şekilde ayarlayın:
BurstBuilder:V Callbacks:V CompilationBuilder:V CpuExecutor:V ExecutionBuilder:V ExecutionBurstController:V ExecutionBurstServer:V ExecutionPlan:V FibonacciDriver:V GraphDump:V IndexedShapeWrapper:V IonWatcher:V Manager:V MemoryUtils:V Memory:V MetaModel:V ModelArgumentInfo:V ModelBuilder:V NeuralNetworks:V OperationResolver:V OperationsUtils:V Operations:V PackageInfo:V TokenHasher:V TypeManager:V Utils:V ValidateHal:V VersionedInterfaces:V *:S.
Aşağıdaki komutu kullanarak ANDROID_LOG_TAGS
öğesini ayarlayabilirsiniz:
export ANDROID_LOG_TAGS=$(grep -R 'define LOG_TAG' | awk -F '"' '{ print $2 ":V" }' | sort -u | egrep -v "Sample|FileTag|test" | xargs echo -n; echo ' *:S')
Bunun yalnızca logcat
için geçerli bir filtre olduğunu unutmayın. Ayrıntılı günlük bilgileri oluşturmak için yine de debug.nn.vlog
özelliğini all
olarak ayarlamanız gerekir.