Deteksi Wajah pada Video: Raspberry Pi dan Neural Compute Stick

Sekitar setahun yang lalu, Intel Movidius merilis perangkat untuk inferensi efisien jaringan saraf convolutional - Movidius Neural Compute Stick (NCS). Perangkat ini memungkinkan penggunaan jaringan saraf untuk pengenalan atau deteksi objek dalam kondisi konsumsi energi yang terbatas, termasuk dalam tugas robotika. NCS memiliki antarmuka USB dan mengkonsumsi tidak lebih dari 1 watt. Pada artikel ini, saya akan berbicara tentang pengalaman menggunakan NCS dengan Raspberry Pi untuk tugas mendeteksi wajah dalam video, termasuk melatih detektor Mobilenet-SSD dan menjalankannya di Raspberry.

Semua kode dapat ditemukan di dua repositori saya: pelatihan detektor dan demo deteksi wajah .



Dalam artikel pertama saya, saya sudah menulis tentang deteksi wajah menggunakan NCS: kemudian saya berbicara tentang detektor YOLOv2 , yang saya konversi dari format Darknet ke format Caffe , dan kemudian diluncurkan di NCS. Proses konversi berubah menjadi non-sepele: karena dua format ini mengatur lapisan terakhir detektor dengan cara yang berbeda, output dari jaringan saraf harus diurai secara terpisah, pada CPU, menggunakan sepotong kode dari Darknet. Selain itu, detektor ini tidak memuaskan saya baik dalam kecepatan (hingga 5,1 FPS di laptop saya) dan dalam akurasi - kemudian saya yakin bahwa karena sensitivitasnya terhadap kualitas gambar, sulit untuk mendapatkan hasil yang baik pada Raspberry Pi.

Pada akhirnya, saya memutuskan untuk hanya melatih detektor saya. Pilihan jatuh pada detektor SSD dengan Mobilenet encoder: konvolusi ringan Mobilenet memungkinkan Anda untuk mencapai kecepatan tinggi tanpa kehilangan kualitas, dan detektor SSD tidak kalah dengan YOLO dan bekerja pada NCS di luar kotak.

Bagaimana Detektor Mobilenet-SSD Bekerja
Mari kita mulai dengan Mobilenet. Dalam arsitektur ini selesai 3 k a l i 3  konvolusi (pada semua saluran) diganti oleh dua konvolusi ringan: pertama 3 k a l i 3  secara terpisah untuk setiap saluran dan kemudian selesai 1 k a l i 1  konvolusi. Setelah setiap konvolusi, BatchNorm dan Non-linearitas (ReLU) digunakan. Konvolusi jaringan pertama yang menerima gambar sebagai input biasanya dibiarkan lengkap. Arsitektur ini dapat secara signifikan mengurangi kompleksitas perhitungan karena sedikit penurunan kualitas prediksi. Ada opsi yang lebih maju , tetapi saya belum mencobanya.

SSD (Single Shot Detector) bekerja seperti ini: pada output beberapa encoder konvolusi digantung menjadi dua 1 k a l i 1  lapisan konvolusional: satu memprediksi probabilitas kelas, yang lain - koordinat kotak pembatas. Ada lapisan ketiga yang memberikan koordinat dan posisi frame default di level saat ini. Artinya adalah: output dari setiap lapisan secara alami dibagi menjadi sel-sel; lebih dekat ke ujung jaringan saraf, mereka menjadi lebih kecil (dalam hal ini, karena konvolusi dengan stride=2 ), dan bidang pandang setiap sel meningkat. Untuk setiap sel pada masing-masing beberapa lapisan yang dipilih, kami menetapkan beberapa bingkai default dengan ukuran yang berbeda dan dengan rasio aspek yang berbeda, dan menggunakan lapisan konvolusional tambahan untuk mengoreksi koordinat dan memprediksi probabilitas kelas untuk setiap bingkai tersebut. Oleh karena itu, detektor SSD (seperti YOLO) selalu mempertimbangkan jumlah bingkai yang sama. Objek yang sama dapat dideteksi pada lapisan yang berbeda: selama pelatihan, sinyal dikirim ke semua frame yang bersinggungan dengan objek cukup kuat, dan selama aplikasi, deteksi dikombinasikan menggunakan non maksimum suppression (NMS). Lapisan terakhir menggabungkan deteksi dari semua lapisan, mempertimbangkan koordinat penuhnya, memotong ambang probabilitas dan menghasilkan NMS.

Pelatihan pendeteksi


Arsitektur


Kode untuk melatih pendeteksi terletak di sini .

Saya memutuskan untuk menggunakan detektor Mobilenet-SSD siap pakai yang dilatih pada PASCAL VOC0712 dan melatihnya untuk mendeteksi wajah. Pertama, membantu melatih jaring lebih cepat, dan kedua, Anda tidak perlu menemukan kembali roda.

Proyek asli termasuk skrip gen.py , yang secara harfiah mengumpulkan file model .prototxt , menggantikan parameter input. Saya memindahkannya ke proyek saya, sedikit memperluas fungsionalitasnya. Script ini memungkinkan Anda untuk menghasilkan empat jenis file konfigurasi:

  • kereta : di pintu masuk - basis pelatihan LMDB, di output - lapisan dengan perhitungan fungsi kerugian dan gradiennya, ada BatchNorm
  • tes : pada input - basis uji LMDB, pada output - layer dengan perhitungan kualitas (rata-rata presisi), ada BatchNorm
  • menyebarkan : pada input - gambar, pada output - layer dengan prediksi, BatchNorm hilang
  • deploy_bn : pada input - gambar, pada output - layer dengan prediksi, ada BatchNorm

Saya menambahkan opsi yang terakhir nanti, sehingga dalam skrip Anda dapat memuat dan mengonversi kisi dari BatchNorm tanpa menyentuh basis data LMDB - jika tidak, dengan tidak adanya basis data, tidak ada yang akan berhasil. (Secara umum, tampaknya aneh bagi saya bahwa dalam Caffe sumber data diatur dalam arsitektur jaringan - ini setidaknya tidak terlalu praktis).

Seperti apa arsitektur jaringan (pendek)
  • Login: 300 k a l i 300 k a l i 3  
  • Konv penuh konv : 32 saluran, stride=2
  • Konvolusi Mobilenet conv1 - conv11 : 64, 128, 128, 256, 256, 512 ... 512 saluran, beberapa telah stride=2
  • Lapisan deteksi: 19 k a l i 19 k a l i 512  
  • Konvolusi konvoi Mobilenet, conv13 : 1024 saluran, conv12 telah stride=2
  • Lapisan deteksi: 10 k a l i 10 k a l i 1024  
  • Konvolusi penuh conv14_1, conv14_2 : 256, 512 saluran, kernel_size=1 pertama kernel_size=1 , stride=2 kedua stride=2
  • Lapisan deteksi: 5 kali5 kali$51
  • Konvolusi penuh conv15_1, conv15_2 : 128, 256 saluran, kernel_size=1 pertama kernel_size=1 , stride=2 kedua stride=2
  • Lapisan deteksi: 3 kali3 kali256
  • Lengkapi conv16_1, konvolusi conv16_2 : 128, 256 saluran, kernel_size=1 pertama kernel_size=1 , stride=2 kedua stride=2
  • Lapisan deteksi: 2 kali2 kali256
  • Konvolusi penuh conv17_1, conv17_2 : 64, 128 saluran, kernel_size=1 pertama kernel_size=1 , stride=2 kedua stride=2
  • Lapisan deteksi: 1 kali1 kali128
  • Output Deteksi lapisan akhir


Saya sedikit memperbaiki arsitektur jaringan. Daftar perubahan:

  • Jelas, jumlah kelas telah berubah menjadi 1 (tidak termasuk latar belakang).
  • Keterbatasan rasio aspek tambalan potong selama pelatihan: diubah dari [0,5,2.0] pada [0,7,1,4] (Saya memutuskan untuk menyederhanakan tugas sedikit dan tidak belajar dari gambar yang terlalu melebar).
  • Dari bingkai default, hanya yang persegi yang tersisa, dua untuk setiap sel. Saya sangat mengurangi ukurannya, karena wajah jauh lebih kecil daripada objek dalam masalah pendeteksian objek klasik.

Caffe menghitung ukuran bingkai default sebagai berikut: memiliki ukuran bingkai minimum s dan maksimal L , itu menciptakan bingkai kecil dan besar dengan dimensi s dan  sqrtsL . Karena saya ingin mendeteksi wajah sekecil mungkin, saya menghitung stride penuh untuk setiap lapisan deteksi dan menyamakan ukuran bingkai minimum untuk itu. Dengan parameter ini, frame default kecil akan terletak berdekatan satu sama lain dan tidak akan berpotongan. Jadi setidaknya kita memiliki jaminan bahwa persimpangan dengan objek akan ada untuk beberapa jenis kerangka kerja. Saya mengatur ukuran maksimum dua kali lipat. Untuk layer conv16_2, conv17_2, saya mengatur dimensi pada mata menjadi sama. Dengan cara ini s,L untuk semua lapisan adalah: (16,32),(32,64),(64.128),(128.214),(214.300),(214.300)

Bagaimana beberapa frame default terlihat (noise for clarity)


Data


Saya menggunakan dua dataset : WIDER Face dan FDDB . WIDER berisi banyak gambar dengan wajah yang sangat kecil dan buram, dan FDDB lebih cenderung ke gambar wajah yang besar (dan urutan besarnya lebih kecil dari WIDER). Format anotasi sedikit berbeda di dalamnya, tetapi ini sudah detail.

Untuk pelatihan, saya tidak menggunakan semua data: Saya membuang wajah terlalu kecil (kurang dari enam piksel atau kurang dari 2% dari lebar gambar), membuang semua gambar dengan rasio aspek kurang dari 0,5 atau lebih dari 2, membuang semua gambar yang ditandai "buram" dalam dataset WIDER, karena mereka berkorespondensi sebagian besar dengan orang-orang yang sangat kecil, dan aku setidaknya harus menyelaraskan rasio wajah kecil dan besar. Setelah itu, saya membuat semua bingkai persegi, memperluas sisi terkecil: Saya memutuskan bahwa saya tidak terlalu tertarik pada proporsi wajah, dan tugas untuk jaringan saraf sedikit disederhanakan. Saya juga membuang semua gambar hitam dan putih, yang ada beberapa, dan di mana database membangun skrip crash.

Untuk menggunakannya untuk pelatihan dan pengujian, Anda perlu mengumpulkan basis LMDB dari mereka. Bagaimana cara melakukannya:

  • Untuk setiap gambar, markup dibuat dalam format .xml .
  • File train.txt dengan garis-garis bentuk "path/to/image.png path/to/labels.xml" , yang sama dibuat untuk pengujian.
  • File test_name_size.txt dengan garis-garis bentuk "test_image_name height width"
  • Membuat file labelmap.prototxt dengan kecocokan labelmap.prototxt numerik


ssd-caffe/scripts/create_annoset.py (contoh dari Makefile):

 python3 /opt/movidius/ssd-caffe/scripts/create_annoset.py --anno-type=detection \ --label-map-file=$(wider_dir)/labelmap.prototxt --min-dim=0 --max-dim=0 \ --resize-width=0 --resize-height=0 --check-label --encode-type=jpg --encoded \ --redo $(wider_dir) \ $(wider_dir)/trainval.txt $(wider_dir)/WIDER_train/lmdb/wider_train_lmdb ./data 

labelmap.prototxt
 item { name: "none_of_the_above" label: 0 display_name: "background" } item { name: "face" label: 1 display_name: "face" } 



Contoh markup .xml
 <?xml version="1.0" ?> <annotation> <size> <width>348</width> <height>450</height> <depth>3</depth> </size> <object> <name>face</name> <bndbox> <xmin>161</xmin> <ymin>43</ymin> <xmax>241</xmax> <ymax>123</ymax> </bndbox> </object> </annotation> 


Menggunakan dua kumpulan data pada saat yang sama hanya berarti bahwa Anda perlu menggabungkan file yang terkait secara hati-hati berpasangan, tidak lupa untuk mendaftarkan jalur dengan benar, serta mengocok file untuk pelatihan.

Setelah itu, Anda bisa memulai pelatihan.

Pelatihan


Kode untuk pelatihan model dapat ditemukan di Colab Notebook saya.

Saya melakukan pelatihan di Google Colaboratory, karena laptop saya hampir tidak melakukan pengujian grid, dan biasanya menutup telepon di pelatihan. Kolaborasi memungkinkan saya untuk melatih jaring dengan cukup cepat dan gratis. Satu-satunya hasil adalah bahwa saya harus menulis skrip kompilasi SSD-Caffe untuk Colaboratory (termasuk hal-hal aneh seperti mengkompilasi ulang dorongan dan mengedit sumbernya), yang membutuhkan waktu sekitar 40 menit. Rincian lebih lanjut dapat ditemukan di publikasi saya sebelumnya .

Colaboratory memiliki satu fitur lagi: setelah 12 jam, mobil mati, menghapus semua data secara permanen. Cara terbaik untuk menghindari kehilangan data adalah dengan memasang cakram Google Anda di sistem dan menyimpan bobot jaringan di sana setiap 500-1000 iterasi pelatihan.

Adapun detektor saya, dalam satu sesi di Colaboratory ia berhasil melepaskan 4,500 iterasi, dan sepenuhnya terlatih dalam dua sesi.

Kualitas prediksi (rata-rata presisi) pada set data uji yang saya sorot (digabung WIDER dan FDDB dengan pembatasan yang tercantum di atas) adalah sekitar 0,87 untuk model terbaik. Untuk mengukur MAP pada skala yang disimpan selama pelatihan, ada skrip scripts/plot_map.py .

Detektor bekerja pada contoh (sangat aneh) dari dataset:


Luncurkan di NCS


Demo deteksi wajah ada di sini .

Untuk mengkompilasi jaringan neural untuk Neural Compute Stick, Anda memerlukan Movidius NCSDK : ini berisi utilitas untuk mengkompilasi dan membuat profil jaringan saraf, serta API C ++ dan Python. Perlu dicatat bahwa versi kedua, tidak sesuai dengan yang pertama, baru-baru ini dirilis: semua fungsi API diganti nama karena beberapa alasan, format internal jaringan saraf diubah, FIFO ditambahkan untuk berinteraksi dengan NCS, dan (akhirnya) ada konversi otomatis dari float 32 bit ke mengapung 16 bit, yang sangat kurang dalam C ++. Saya memperbarui semua proyek saya ke versi kedua, tetapi meninggalkan beberapa kruk untuk kompatibilitas dengan yang pertama.

Setelah melatih detektor, ada baiknya menggabungkan lapisan BatchNorm dengan konvolusi yang berdekatan untuk mempercepat jaringan saraf. Script merge_bn.py ini dari sini , yang saya pinjam dari proyek Mobilenet-SSD.

Maka Anda perlu memanggil utilitas mvNCCompile , misalnya:

 mvNCCompile -s 12 -o graph_ssd -w ssd-face.caffemodel ssd-face.prototxt 

Ada target graph_ssd untuk ini di Makefile proyek. File graph_ssd dihasilkan adalah deskripsi jaringan saraf dalam format yang dipahami oleh NCS.

Sekarang tentang cara berinteraksi dengan perangkat itu sendiri. Prosesnya tidak terlalu rumit, tetapi membutuhkan jumlah kode yang cukup besar. Urutan tindakan kira-kira sebagai berikut:

  • Dapatkan deskriptor perangkat dengan nomor seri
  • Buka perangkat
  • Baca file jaringan saraf yang dikompilasi ke buffer (sebagai file biner)
  • Buat grafik perhitungan kosong untuk NCS
  • Tempatkan grafik pada perangkat menggunakan data dari file dan pilih FIFO untuk itu pada input / output; buffer dengan konten file sekarang dapat dibebaskan
  • Detektor mulai:
    • Dapatkan gambar dari kamera (atau dari sumber lain mana pun)
    • Memprosesnya: skala ke ukuran yang diinginkan, dikonversi ke float32 dan dilemparkan ke kisaran [-1,1]
    • Unggah gambar ke perangkat dan minta inferensi
    • Minta hasil (program akan diblokir hingga hasilnya diterima)
    • Parsing hasilnya, pilih bingkai objek (tentang format - lebih lanjut)
    • Prediksi tampilan

  • Bebaskan semua sumber daya: hapus FIFO dan grafik kalkulasi, tutup perangkat dan lepas pegangannya

Hampir setiap tindakan dengan NCS memiliki fungsi tersendiri, dan dalam C ++ ini terlihat sangat rumit, dan Anda harus dengan cermat memantau pelepasan semua sumber daya. Agar tidak membebani kode, saya membuat kelas wrapper untuk bekerja dengan NCS . Di dalamnya, semua pekerjaan inisialisasi tersembunyi di konstruktor dan fungsi load_file , dan pada rilis sumber daya - di destruktor, dan bekerja dengan NCS dikurangi menjadi memanggil 2-3 metode kelas. Selain itu, ada fungsi yang mudah untuk menjelaskan kesalahan yang telah terjadi.

Buat pembungkus dengan meneruskan ukuran input dan ukuran output (jumlah elemen) ke konstruktor:

 NCSWrapper NCS(NETWORK_INPUT_SIZE*NETWORK_INPUT_SIZE*3, NETWORK_OUTPUT_SIZE); 

Kami memuat file yang dikompilasi dengan jaringan saraf, secara bersamaan menginisialisasi semua yang kami butuhkan:

 if (!NCS.load_file("./models/face/graph_ssd")) { NCS.print_error_code(); return 0; } 

Kami mengonversi gambar ke float32 ( image adalah cv::Mat dalam format CV_32FC3 ) dan mengunduhnya ke perangkat:

 if(!NCS.load_tensor_nowait((float*)image.data)) { NCS.print_error_code(); break; } 

Kami mendapatkan hasilnya ( result adalah free float pointer, buffer hasil didukung oleh pembungkus); sampai akhir perhitungan, program diblokir:

 if(!NCS.get_result(result)) { NCS.print_error_code(); break; } 

Bahkan, pembungkus juga memiliki metode yang memungkinkan Anda memuat data dan mendapatkan hasilnya pada saat yang bersamaan: load_tensor((float*)image.data, result) . Saya menolak untuk menggunakannya karena alasan: menggunakan metode terpisah, Anda dapat sedikit mempercepat eksekusi kode. Setelah memuat gambar, CPU akan diam sampai hasil eksekusi dengan NCS tiba (dalam hal ini sekitar 100 ms), dan saat ini Anda dapat melakukan pekerjaan yang bermanfaat: membaca bingkai baru dan mengonversinya, serta menampilkan deteksi sebelumnya . Ini persis bagaimana program demo diimplementasikan, dalam kasus saya ini sedikit meningkatkan FPS. Anda dapat melangkah lebih jauh dan memulai pemrosesan gambar dan detektor wajah secara serempak dalam dua aliran berbeda - ini benar-benar berfungsi dan memungkinkan Anda untuk mempercepat sedikit lagi, tetapi itu tidak diterapkan dalam program demo.

Detektor sebagai hasilnya mengembalikan array float ukuran 7*(keep_top_k+1) . Di sini, keep_top_k adalah parameter yang ditentukan dalam file .prototxt model dan menunjukkan berapa banyak deteksi (dalam urutan kepercayaan menurun) yang harus dikembalikan. Parameter ini, serta parameter yang bertanggung jawab untuk memfilter deteksi dengan nilai kepercayaan minimum, dan parameter penindasan maksimum tidak dapat dikonfigurasi dalam file .prototxt model di lapisan terakhir. Perlu dicatat bahwa jika Caffe mengembalikan deteksi sebanyak yang ditemukan pada gambar, maka NCS selalu mengembalikan keep_top_k deteksi sehingga ukuran array konstan.

Array hasil itu sendiri diatur sebagai berikut: jika kita menganggapnya sebagai matriks dengan keep_top_k+1 baris dan 7 kolom, maka di baris pertama, di elemen pertama akan ada jumlah deteksi, dan mulai dari baris kedua akan ada deteksi sendiri dalam format "garbage, class_index, class_probability, x_min, y_min, x_max, y_max" . Koordinat ditentukan dalam kisaran [0,1], sehingga koordinat tersebut perlu dikalikan dengan tinggi / lebar gambar. Elemen yang tersisa dari array akan menjadi sampah. Dalam hal ini, penindasan non maksimum dilakukan secara otomatis, bahkan sebelum hasilnya diperoleh (tampaknya, tepat di NCS).

Parsing Detektor
 void get_detection_boxes(float* predictions, int w, int h, float thresh, std::vector<float>& probs, std::vector<cv::Rect>& boxes) { int num = predictions[0]; float score = 0; float cls = 0; for (int i=1; i<num+1; i++) { score = predictions[i*7+2]; cls = predictions[i*7+1]; if (score>thresh && cls<=1) { probs.push_back(score); boxes.push_back(Rect(predictions[i*7+3]*w, predictions[i*7+4]*h, (predictions[i*7+5]-predictions[i*7+3])*w, (predictions[i*7+6]-predictions[i*7+4])*h)); } } } 


Fitur Peluncuran Raspberry Pi


Program demo itu sendiri dapat dijalankan di komputer atau laptop biasa dengan Ubuntu, atau di Raspberry Pi dengan Raspbian Stretch. Saya menggunakan Raspberry Pi 2 model B, tetapi demo harus bekerja pada model lain juga. Makefile proyek berisi dua tujuan untuk beralih mode: make switch_desk untuk komputer / laptop dan make switch_rpi untuk Raspberry Pi. Perbedaan mendasar dalam kode program adalah bahwa dalam kasus pertama, OpenCV digunakan untuk membaca data dari kamera, dan dalam kasus kedua, perpustakaan RaspiCam . Untuk menjalankan demo di Raspberry, Anda harus mengkompilasi dan menginstalnya.

Sekarang poin yang sangat penting: menginstal NCSDK. Jika Anda mengikuti petunjuk instalasi standar pada Raspberry Pi, tidak ada yang baik akan berakhir: installer akan mencoba untuk menyeret dan mengkompilasi SSD-Caffe dan Tensorflow. Sebaliknya, NCSDK harus dikompilasi dalam mode API-only . Dalam mode ini, hanya C ++ dan Python API yang akan tersedia (artinya, tidak mungkin untuk mengkompilasi dan profil grafik jaringan saraf). Ini berarti bahwa grafik jaringan syaraf pertama-tama harus dikompilasi pada komputer biasa, dan kemudian disalin ke Raspberry. Untuk kenyamanan, saya menambahkan dua file yang dikompilasi ke repositori, untuk YOLO dan untuk SSD.

Hal lain yang menarik adalah koneksi fisik NCS ke Raspberry. Tampaknya tidak sulit untuk menghubungkannya ke konektor USB, tetapi Anda harus ingat bahwa kasingnya akan memblokir tiga konektor lainnya (cukup sehat, karena berfungsi sebagai radiator). Jalan keluar termudah adalah menghubungkannya melalui kabel USB.

Perlu juga diingat bahwa kecepatan eksekusi akan bervariasi untuk versi USB yang berbeda (untuk jaringan saraf khusus ini: 102 ms untuk USB 3.0, 92 ms untuk USB 2.0).

Sekarang tentang kekuatan NCS. Menurut dokumentasi, itu mengkonsumsi hingga 1 watt (pada 5 volt pada konektor USB akan sampai 200 ma; untuk perbandingan: kamera Raspberry mengkonsumsi hingga 250 ma). Ketika ditenagai oleh charger 5 volt reguler, 2 ampere, semuanya bekerja dengan baik. Namun, mencoba menghubungkan dua atau lebih NCS ke Raspberry dapat menyebabkan masalah. Dalam hal ini, disarankan untuk menggunakan pembagi USB dengan kemungkinan daya eksternal.

Di Raspberry, demo lebih lambat daripada di komputer / laptop: 7,2 FPS dibandingkan 10,4 FPS. Ini disebabkan oleh beberapa faktor: pertama, tidak mungkin untuk menyingkirkan perhitungan pada CPU, tetapi mereka dilakukan jauh lebih lambat; kedua, kecepatan transfer data mempengaruhi (untuk USB 2.0).

Juga, sebagai perbandingan, saya mencoba menjalankan pendeteksi wajah pada Raspberry YOLOv2 dari artikel pertama saya, tetapi bekerja dengan sangat buruk: pada kecepatan 3,6 FPS, ia kehilangan banyak wajah bahkan pada bingkai sederhana. Rupanya, sangat sensitif terhadap parameter gambar input, yang kualitasnya dalam kasus kamera Raspberry jauh dari ideal. SSD berfungsi jauh lebih stabil, meskipun saya harus sedikit mengubah pengaturan video dalam pengaturan RapiCam. dia juga terkadang merindukan wajah-wajah dalam bingkai, tetapi melakukan ini sangat jarang. Untuk meningkatkan stabilitas dalam aplikasi nyata, Anda dapat menambahkan pelacak centroid sederhana.

By the way: hal yang sama dapat direproduksi dalam Python, ada tutorial tentang PyImageSearch (Mobilenet-SSD digunakan untuk tugas deteksi objek).

Ide lain


Saya juga mencoba beberapa ide untuk mempercepat jaringan saraf itu sendiri:

Ide pertama: Anda hanya dapat meninggalkan deteksi lapisan conv11 dan conv13 , dan menghapus semua lapisan tambahan. Anda akan mendapatkan detektor yang hanya mendeteksi wajah kecil dan bekerja sedikit lebih cepat. Semua dalam semua, tidak sepadan.

Gagasan kedua menarik, tetapi tidak berhasil: Saya mencoba membuang konvolusi dari jaringan saraf dengan bobot mendekati nol, berharap itu akan menjadi lebih cepat. Namun, ada beberapa konvolusi seperti itu, dan penghapusannya hanya sedikit memperlambat jaringan saraf (satu-satunya firasat: ini karena fakta bahwa jumlah saluran telah berhenti menjadi kekuatan dua).

Kesimpulan


Saya berpikir tentang mendeteksi wajah pada Raspberry untuk waktu yang lama, sebagai subtugas dari proyek robot saya. Saya tidak suka detektor klasik dalam hal kecepatan dan kualitas, dan saya memutuskan untuk mencoba metode jaringan saraf, pada saat yang sama menguji Neural Compute Stick, sebagai hasilnya ada dua proyek pada GitHub dan tiga artikel tentang Habrรฉ (termasuk yang sekarang). Secara umum, hasilnya cocok untuk saya - kemungkinan besar, saya akan menggunakan detektor ini di robot saya (mungkin akan ada artikel lain tentang itu). Perlu dicatat bahwa solusi saya mungkin tidak optimal - namun, ini adalah proyek pelatihan, dibuat sebagian karena penasaran NCS. Meskipun demikian, saya berharap artikel ini bermanfaat bagi seseorang.

Source: https://habr.com/ru/post/id424973/


All Articles