Teknik Jedi untuk mengurangi jaringan konvolusional - pemangkasan

Teknik Jedi untuk mengurangi jaringan konvolusional - pemangkasan

Di hadapan Anda lagi adalah tugas mendeteksi objek. Prioritasnya adalah kecepatan operasi dengan akurasi yang dapat diterima. Anda mengambil arsitektur YOLOv3 dan melatihnya lebih lanjut. Akurasi (mAp75) lebih besar dari 0.95. Namun laju larinya masih rendah. Omong kosong.

Hari ini kita akan melewati kuantisasi. Dan di bawah potongan kita akan melihat Model Pemangkasan β€” memangkas bagian jaringan yang berlebihan untuk mempercepat Inferensi tanpa kehilangan akurasi. Jelas di mana, berapa banyak, dan bagaimana cara memotongnya. Mari kita cari tahu cara melakukannya secara manual dan di mana Anda dapat mengotomatiskannya. Pada akhirnya ada repositori keras.

pengenalan

Di tempat kerja saya sebelumnya, makroskop di Perm, saya memperoleh satu kebiasaan - untuk selalu memantau waktu eksekusi algoritma. Dan selalu periksa runtime jaringan melalui filter kecukupan. Biasanya produksi tercanggih tidak lolos filter ini, yang membawa saya ke Pemangkasan.

Pemangkasan adalah topik lama yang dibahas kuliah Stanford pada tahun 2017. Ide utamanya adalah untuk mengurangi ukuran jaringan yang dilatih tanpa kehilangan akurasi dengan menghapus berbagai node. Kedengarannya keren, tapi saya jarang mendengar kegunaannya. Mungkin, implementasinya tidak cukup, tidak ada artikel berbahasa Rusia, atau semua orang menganggapnya sebagai pemangkasan pengetahuan dan tetap diam.
Tapi mari kita pisahkan

Sekilas tentang biologi

Saya senang ketika Deep Learning melihat ide-ide yang berasal dari biologi. Mereka, seperti halnya evolusi, dapat dipercaya (tahukah Anda bahwa ReLU sangat mirip dengan fungsi aktivasi neuron di otak?)

Proses Model Pruning juga dekat dengan biologi. Respons jaringan di sini dapat dibandingkan dengan plastisitas otak. Ada beberapa contoh menarik dalam buku ini. Norman Dodge:

  1. Otak seorang wanita yang terlahir hanya dengan separuh bagian otaknya telah memprogram ulang dirinya untuk menjalankan fungsi dari separuh bagian yang hilang tersebut.
  2. Pria itu melepaskan bagian otaknya yang bertanggung jawab atas penglihatan. Seiring waktu, bagian lain dari otak mengambil alih fungsi-fungsi ini. (kami tidak mencoba mengulanginya)

Demikian pula, Anda dapat menghilangkan beberapa konvolusi lemah dari model Anda. Sebagai upaya terakhir, sisa bundel akan membantu menggantikan bundel yang dipotong.

Apakah Anda menyukai Pembelajaran Transfer atau Anda belajar dari awal?

Opsi nomor satu. Anda menggunakan Pembelajaran Transfer di Yolov3. Retina, Mask-RCNN atau U-Net. Namun seringkali kita tidak perlu mengenali 80 kelas objek seperti di COCO. Kalau praktek saya semuanya terbatas pada kelas 1-2. Orang mungkin berasumsi bahwa arsitektur untuk 80 kelas mubazir di sini. Hal ini menunjukkan bahwa arsitektur perlu dibuat lebih kecil. Selain itu, saya ingin melakukan ini tanpa kehilangan beban yang sudah dilatih sebelumnya.

Opsi nomor dua. Mungkin Anda memiliki banyak data dan sumber daya komputasi, atau hanya memerlukan arsitektur super-kustom. Tidak masalah. Tapi Anda mempelajari jaringan dari awal. Prosedur yang biasa dilakukan adalah dengan melihat struktur data, memilih arsitektur yang kekuatannya BERLEBIHAN, dan mendorong putus sekolah dari pelatihan ulang. Saya melihat 0.6 putus sekolah, Karl.

Dalam kedua kasus tersebut, jaringan dapat dikurangi. Termotivasi. Sekarang mari kita cari tahu apa itu pemangkasan sunat

Algoritma umum

Kami memutuskan bahwa kami dapat menghapus bundel tersebut. Ini terlihat cukup sederhana:

Teknik Jedi untuk mengurangi jaringan konvolusional - pemangkasan

Menghapus konvolusi apa pun akan menimbulkan stres bagi jaringan, yang biasanya menyebabkan peningkatan kesalahan. Di satu sisi, peningkatan kesalahan ini merupakan indikator seberapa benar kita menghilangkan konvolusi (misalnya, peningkatan yang besar menunjukkan bahwa kita melakukan sesuatu yang salah). Namun peningkatan kecil cukup dapat diterima dan sering kali dihilangkan dengan pelatihan tambahan ringan berikutnya dengan LR kecil. Tambahkan langkah pelatihan tambahan:

Teknik Jedi untuk mengurangi jaringan konvolusional - pemangkasan

Sekarang kita perlu mencari tahu kapan kita ingin menghentikan loop Pembelajaran<->Pemangkasan. Mungkin ada pilihan yang eksotis di sini ketika kita perlu mengurangi jaringan ke ukuran dan kecepatan tertentu (misalnya, untuk perangkat seluler). Namun, pilihan yang paling umum adalah melanjutkan siklus hingga kesalahan menjadi lebih tinggi dari yang dapat diterima. Tambahkan kondisi:

Teknik Jedi untuk mengurangi jaringan konvolusional - pemangkasan

Jadi, algoritmanya menjadi jelas. Masih mencari cara untuk menentukan konvolusi yang dihapus.

Cari paket yang dihapus

Kita perlu menghilangkan beberapa konvolusi. Terburu-buru dan β€œmenembak” siapa pun adalah ide yang buruk, meskipun itu akan berhasil. Namun karena Anda punya pikiran, Anda dapat berpikir dan mencoba memilih konvolusi yang "lemah" untuk dihilangkan. Ada beberapa pilihan:

  1. Ukuran L1 terkecil atau pemangkasan_magnitude_rendah. Gagasan bahwa konvolusi dengan bobot kecil memberikan kontribusi kecil pada keputusan akhir
  2. Ukuran L1 terkecil dengan memperhitungkan mean dan deviasi standar. Kami melengkapinya dengan penilaian terhadap sifat distribusinya.
  3. Menutupi konvolusi dan mengecualikan konvolusi yang paling tidak mempengaruhi akurasi akhir. Penentuan konvolusi yang tidak signifikan lebih akurat, tetapi sangat memakan waktu dan sumber daya.
  4. Lainnya

Masing-masing opsi memiliki hak hidup dan fitur implementasinya sendiri. Di sini kami mempertimbangkan opsi dengan ukuran L1 terkecil

Proses manual untuk YOLOv3

Arsitektur aslinya mengandung blok sisa. Tapi betapapun kerennya mereka untuk jaringan dalam, mereka akan menghalangi kita. Kesulitannya adalah Anda tidak dapat menghapus rekonsiliasi dengan indeks berbeda di lapisan berikut:

Teknik Jedi untuk mengurangi jaringan konvolusional - pemangkasan

Oleh karena itu, mari kita pilih lapisan yang rekonsiliasinya dapat kita hapus dengan bebas:

Teknik Jedi untuk mengurangi jaringan konvolusional - pemangkasan

Sekarang mari kita membangun siklus kerja:

  1. Mengunggah aktivasi
  2. Mencari tahu berapa banyak yang harus dipotong
  3. Hentikan
  4. Mempelajari 10 epoch dengan LR=1e-4
  5. Pengujian

Membongkar konvolusi berguna untuk memperkirakan berapa banyak bagian yang dapat kita hapus pada langkah tertentu. Contoh bongkar:

Teknik Jedi untuk mengurangi jaringan konvolusional - pemangkasan

Kami melihat bahwa hampir di semua tempat, 5% konvolusi memiliki norma L1 yang sangat rendah dan kami dapat menghilangkannya. Pada setiap langkah, pembongkaran muatan ini diulangi dan dilakukan penilaian terhadap lapisan mana dan berapa banyak yang dapat dipotong.

Seluruh proses diselesaikan dalam 4 langkah (angka di sini dan di mana saja untuk RTX 2060 Super):

Langkah peta75 Jumlah parameter, juta Ukuran jaringan, mb Dari awal, % Waktunya berjalan, Bu Kondisi sunat
0 0.9656 60 241 100 180 -
1 0.9622 55 218 91 175 5% dari semuanya
2 0.9625 50 197 83 168 5% dari semuanya
3 0.9633 39 155 64 155 15% untuk lapisan dengan 400+ konvolusi
4 0.9555 31 124 51 146 10% untuk lapisan dengan 100+ konvolusi

Satu efek positif ditambahkan ke langkah 2 - ukuran batch 4 dimasukkan ke dalam memori, yang sangat mempercepat proses pelatihan tambahan.
Pada langkah 4, proses dihentikan karena bahkan pelatihan tambahan jangka panjang tidak meningkatkan mAp75 ke nilai lama.
Hasilnya, kami berhasil mempercepat inferensi dengan 15%, kurangi ukurannya sebesar 35% dan tidak kalah persis.

Otomatisasi untuk arsitektur yang lebih sederhana

Untuk arsitektur jaringan yang lebih sederhana (tanpa blok tambahan, gabungan, dan sisa bersyarat), sangat mungkin untuk fokus pada pemrosesan semua lapisan konvolusional dan mengotomatiskan proses pemotongan konvolusi.

Saya menerapkan opsi ini di sini.
Sederhana saja: Anda hanya memerlukan fungsi kerugian, pengoptimal, dan generator batch:

import pruning
from keras.optimizers import Adam
from keras.utils import Sequence

train_batch_generator = BatchGenerator...
score_batch_generator = BatchGenerator...

opt = Adam(lr=1e-4)
pruner = pruning.Pruner("config.json", "categorical_crossentropy", opt)

pruner.prune(train_batch, valid_batch)

Jika perlu, Anda dapat mengubah parameter konfigurasi:

{
    "input_model_path": "model.h5",
    "output_model_path": "model_pruned.h5",
    "finetuning_epochs": 10, # the number of epochs for train between pruning steps
    "stop_loss": 0.1, # loss for stopping process
    "pruning_percent_step": 0.05, # part of convs for delete on every pruning step
    "pruning_standart_deviation_part": 0.2 # shift for limit pruning part
}

Selain itu, pembatasan berdasarkan standar deviasi juga diterapkan. Tujuannya adalah untuk membatasi bagian yang dihapus, tidak termasuk konvolusi dengan ukuran L1 yang sudah β€œcukup”:

Teknik Jedi untuk mengurangi jaringan konvolusional - pemangkasan

Oleh karena itu, kami mengizinkan Anda untuk menghapus hanya konvolusi lemah dari distribusi yang serupa dengan distribusi kanan dan tidak memengaruhi penghapusan dari distribusi yang serupa dengan distribusi kiri:

Teknik Jedi untuk mengurangi jaringan konvolusional - pemangkasan

Ketika distribusi mendekati normal, koefisien pemangkasan_standar_deviasi_bagian dapat dipilih dari:

Teknik Jedi untuk mengurangi jaringan konvolusional - pemangkasan
Saya merekomendasikan asumsi 2 sigma. Atau Anda dapat mengabaikan fitur ini, meninggalkan nilai <1.0.

Outputnya berupa grafik ukuran jaringan, kehilangan, dan runtime jaringan untuk keseluruhan pengujian, dinormalisasi ke 1.0. Misalnya, di sini ukuran jaringan berkurang hampir 2 kali lipat tanpa kehilangan kualitas (jaringan konvolusional kecil dengan bobot 100k):

Teknik Jedi untuk mengurangi jaringan konvolusional - pemangkasan

Kecepatan lari dapat mengalami fluktuasi normal dan hampir tidak berubah. Ada penjelasan untuk ini:

  1. Jumlah konvolusi berubah dari nyaman (32, 64, 128) menjadi tidak nyaman untuk kartu video - 27, 51, dll. Saya bisa saja salah di sini, tetapi kemungkinan besar hal itu berpengaruh.
  2. Arsitekturnya tidak luas, tapi konsisten. Dengan mengurangi lebarnya, kami tidak mempengaruhi kedalamannya. Jadi, kami mengurangi beban, tetapi tidak mengubah kecepatan.

Oleh karena itu, peningkatan tersebut dinyatakan dalam pengurangan beban CUDA selama pengoperasian sebesar 20-30%, tetapi tidak dalam pengurangan waktu pengoperasian.

Hasil

Mari kita renungkan. Kami mempertimbangkan 2 opsi pemangkasan - untuk YOLOv3 (saat Anda harus bekerja dengan tangan) dan untuk jaringan dengan arsitektur yang lebih sederhana. Dapat dilihat bahwa dalam kedua kasus dimungkinkan untuk mencapai pengurangan ukuran jaringan dan percepatan tanpa kehilangan akurasi. Hasil:

  • Mengurangi ukuran
  • Akselerasi dijalankan
  • Mengurangi Beban CUDA
  • Hasilnya, ramah lingkungan (Kami mengoptimalkan penggunaan sumber daya komputasi di masa depan. Ada yang senang Greta Thunberg)

Lampiran

  • Setelah langkah pemangkasan, Anda dapat menambahkan kuantisasi (misalnya dengan TensorRT)
  • Tensorflow menyediakan kemampuan untuk pemangkasan_magnitudo_rendah. Bekerja.
  • gudang Saya ingin berkembang dan dengan senang hati akan membantu

Sumber: www.habr.com

Tambah komentar