Saya memiliki kesenangan hebat menulis perangkat lunak jaringan saraf di tahun 90-an, dan saya ingin mencoba membuat beberapa menggunakan tensorflow.
Kerangka kerja intelijen mesin Google adalah panas baru sekarang. Dan ketika TensorFlow menjadi dapat diinstal pada Raspberry PI, bekerja dengannya menjadi sangat mudah dilakukan. Dalam waktu singkat saya membuat jaringan saraf yang diperhitungkan dalam biner. Jadi saya pikir saya akan meneruskan apa yang telah saya pelajari sejauh ini. Semoga ini memudahkan orang lain yang ingin mencobanya, atau bagi siapa saja yang hanya menginginkan wawasan tentang jaringan saraf.
Apa itu Tensorflow?
Untuk mengutip situs TensorFlow, Tensorflow adalah “pustaka perangkat lunak sumber terbuka untuk perhitungan numerik menggunakan grafik aliran data”. Apa yang kami maksud dengan “Grafik aliran data”? Yah, itu bagian yang sangat menakjubkan. Tetapi sebelum kita dapat menjawabnya, kita harus berbicara sedikit tentang struktur untuk jaringan saraf sederhana.
Jaringan Saraf Biner Counter
Dasar-dasar dari jaringan saraf
Jaringan saraf sederhana memiliki beberapa unit input di mana input berjalan. Ini juga memiliki unit tersembunyi, disebut karena dari perspektif pengguna mereka benar-benar tersembunyi. Dan ada unit output, dari mana kita mendapatkan hasilnya. Pergi ke samping juga merupakan unit bias, yang ada untuk membantu mengontrol nilai yang dipancarkan dari unit tersembunyi dan output. Menghubungkan semua unit ini adalah banyak bobot, yang hanya angka, yang masing-masing dikaitkan dengan dua unit.
Cara kita menanamkan kecerdasan ke dalam jaringan saraf ini adalah untuk menetapkan nilai-nilai untuk semua bobot tersebut. Itulah yang dilakukan pelatihan jaringan saraf, temukan nilai yang sesuai untuk bobot tersebut. Setelah dilatih, dalam contoh kami, kami akan mengatur unit input ke digit biner 0, 0, dan 0 masing-masing, tensorflow akan melakukan hal-hal dengan segala sesuatu di antaranya, dan unit output akan secara ajaib mengandung angka biner 0, 0, dan 1 masing-masing. Jika Anda melewatkan itu, ia tahu bahwa nomor berikutnya setelah biner 000 adalah 001. Untuk 001, itu harus meludah 010, dan seterusnya hingga 111, di mana itu akan memuntahkan 000. Setelah bobot itu ditetapkan dengan tepat, itu Saya tahu cara menghitung.
Binary Counter Neural Network dengan Matriks
Satu langkah dalam “menjalankan” jaringan saraf adalah untuk mengalikan nilai setiap bobot dengan nilai unit inputnya, dan kemudian menyimpan hasilnya di unit tersembunyi yang terkait.
Kita dapat menggambar ulang unit dan bobot sebagai array, atau apa yang disebut daftar di Python. Dari sudut pandang matematika, mereka adalah matriks. Kami telah menggambar ulang hanya sebagian dari mereka dalam diagram. Mengalikan matriks input dengan matriks berat melibatkan multiplikasi matriks sederhana yang menghasilkan lima elemen tersembunyi matriks / daftar / array.
Dari matriks hingga tensor
Dalam tensorflow, daftar itu disebut tensor. Dan langkah perkalian matriks disebut operasi, atau op dalam bahasa programmer, istilah Anda harus terbiasa jika Anda berencana membaca dokumentasi TensorFlow. Selanjutnya, seluruh jaringan saraf adalah kumpulan tensor dan OP yang beroperasi pada mereka. Secara keseluruhan mereka membuat grafik.
Grafik Penuh Binary Counter
Layer1 diperluas
Tampil di sini adalah snapshots yang diambil dari Tensorboard, alat untuk memvisualisasikan grafik serta memeriksa nilai tensor selama dan setelah pelatihan. Tensor adalah garis, dan ditulis pada garis adalah dimensi tensor. Menghubungkan tensor adalah semua ops, meskipun beberapa hal yang Anda lihat dapat diklik dua kali untuk memperluas untuk lebih detail, seperti yang telah kami lakukan untuk Layer1 di snapshot kedua.
Di bagian paling bawah adalah X, nama yang kami berikan untuk OP placeholder yang memungkinkan kami untuk memberikan nilai untuk tensor input. Garis naik dan ke kiri darinya adalah tensor input. Lanjutkan setelah baris itu dan Anda akan menemukan Matmul OP, yang mana perkalian matriks dengan tensor input itu dan tensor yang merupakan baris lain yang mengarah ke OP Matmul. Tensor itu mewakili bobot.
Semua ini hanya untuk memberi Anda perasaan untuk apa grafik dan tensor dan opsnya, memberi Anda ide yang lebih baik tentang apa yang kami maksud dengan tensorflow menjadi “perpustakaan perangkat lunak untuk perhitungan numerik menggunakan grafik aliran data”. Tetapi mengapa kami ingin membuat grafik ini?
Mengapa membuat grafik?
API yang saat ini stabil adalah satu untuk Python, bahasa yang ditafsirkan. Jaringan saraf adalah komputasi intensif dan yang besar dapat memiliki ribuan atau bahkan jutaan bobot. Komputasi dengan menafsirkan setiap langkah akan berlangsung selamanya.
Jadi kami malah membuat grafik yang terdiri dari tensor dan ops, menggambarkan tata letak jaringan saraf, semua operasi matematika, dan bahkan nilai awal untuk variabel. Hanya setelah kami membuat grafik ini, kami kemudian meneruskannya ke apa yang disebut TensorFlow sesi. Ini dikenal sebagai eksekusi yang ditangguhkan. Sesi menjalankan grafik menggunakan kode yang sangat efisien. Tidak hanya itu, tetapi banyak operasi, seperti perkalian matriks, adalah yang dapat dilakukan pada GPU yang didukung (unit pemrosesan grafis) dan sesi akan melakukan itu untuk Anda. Juga, tensorflow adalah built untuk dapat mendistribusikan pemrosesan di beberapa mesin dan / atau GPU. memberikannya grafik lengkap memungkinkannya untuk melakukan itu.
Membuat grafik counter biner
Dan inilah kode untuk jaringan saraf counter biner kami. Anda dapat menemukan kode sumber lengkap pada halaman github ini. Perhatikan bahwa ada kode tambahan di dalamnya untuk menyimpan informasi untuk digunakan dengan tensorboard.
Kami akan mulai dengan kode untuk membuat grafik tensor dan ops.
impor tensorflow sebagai tf
sess = tf.interactivession ()
Num_inputs = 3.
Num_hidden = 5.
Num_outputs = 3.
Kami pertama-tama mengimpor modul TensorFlow, membuat sesi untuk digunakan nanti, dan, untuk membuat kode kami lebih dapat dimengerti, kami membuat beberapa variabel yang berisi jumlah unit di jaringan kami.
x = tf.placeolder (tf.foto32, bentuk = [tidak ada, num_inputs], nama = ‘x’)
y_ = tf.placeolder (tf.float32, bentuk = [tidak ada, num_outputs], nama = ‘y_’)
Kemudian kami membuat placeholder untuk unit input dan output kami. Placeholder adalah OP tensorflow untuk hal-hal yang akan kami berikan nilai nanti. X dan Y_ sekarang tensor dalam grafik baru dan masing-masing memiliki OP placeholder yang terkait dengannya.
Anda mungkin bertanya-tanya mengapa kita mendefinisikan bentuk sebagai [tidak ada, num_inputs] dan [tidak ada, num_outputs], daftar dua dimensi, dan mengapa tidak ada untuk dimensi pertama? Dalam ikhtisar jaringan saraf di atas sepertinya kami akan memberikan satu input pada satu waktu dan melatihnya untuk menghasilkan output yang diberikan. Ini lebih efisien, jika kita memberikannya beberapa pasangan input / output pada satu waktu, apa yang disebut batch. Dimensi pertama adalah untuk jumlah pasangan input / output di setiap batch. Kami tidak akan tahu berapa banyak dalam batch sampai kami benar-benar memberikannya nanti. Dan pada kenyataannya, kami menggunakan grafik yang sama untuk pelatihan, pengujian, dan untuk penggunaan aktual sehingga ukuran batch tidak akan selalu sama. Jadi kami menggunakan objek Placeholder Python tidak ada untuk ukuran dimensi pertama untuk saat ini.
W_fc1 = tf.truncated_normal ([num_inputs, num_hidden], mean = 0,5, stddev = 0.707)
W_fc1 = tf.variable (w_fc1, name = ‘w_fc1’)
b_fc1 = tf.truncated_normal ([num_hidden], mean = 0,5, stddev = 0.707)
b_fc1 = tf.variable (b_fc1, name = ‘b_fc1’)
h_fc1 = tf.nn.relu (tf.matmul (x, w_fc1) + b_fc1)
Itu diikuti dengan membuat layer salah satu grafik jaringan saraf: bobot w_fc1, bias b_fc1, dan unit tersembunyi h_fc1. “FC” adalah konvensi yang berarti “terhubung penuh”, karena bobot menghubungkan setiap unit input ke setiap unit tersembunyi.
tf.truncated_normal menghasilkan sejumlah ops dan tensor yang nantinya akan menetapkan angka acak yang dinormalisasi ke semua bobot.
Ops variabel diberi nilai untuk melakukan inisialisasi dengan, angka acak dalam hal ini, dan menyimpan data mereka di beberapa run. Mereka juga berguna untuk menyelamatkan jaringan saraf ke file, sesuatu yang ingin Anda lakukan setelah dilatih.
Anda dapat melihat di mana kita akan melakukan multiplikasi matriks menggunakan matmul op. Kami juga menyisipkan add op yang akan menambah bobot bias. Relu OP melakukan apa yang kami sebut fungsi aktivasi. Penggandaan matriks dan penambahan adalah operasi linear. Ada sejumlah hal yang sangat terbatas, jaringan saraf dapat belajar menggunakan operasi linear yang adil. Fungsi aktivasi menyediakan beberapa non-linearitas. Dalam hal fungsi aktivasi relu, itu menetapkan nilai apa pun yang kurang dari nol ke nol, dan semua nilai lainnya dibiarkan tidak berubah. Percaya atau tidak, melakukan yang membuka dunia lain dari hal-hal lain yang dapat dipelajari.
W_fc2 = tf.truncated_normal ([num_hidden, num_outputs], mean = 0,5, stddev = 0.707)
W_fc2 = tf.variable (w_fc2, name = ‘w_fc2’)
b_fc2 = tf.truncated_normal ([num_outputs], mean = 0,5, stddev = 0.707)
b_fc2 = tf.variable (b_fc2, name = ‘b_fc2’)
y = tf.matmul (h_fc1, w_fc2) + b_fc2
Bobot dan bias untuk layer dua diatur sama dengan untuk layer one tetapi lapisan outputnya berbeda. Kami lagi akan melakukan multiplikasi matriks, kali ini mengalikan bobot dan unit tersembunyi, dan kemudian menambahkan bobot bias. Kami telah meninggalkan fungsi aktivasi untuk bit kode berikutnya.
Hasil = tf.sigmoid (y, name = ‘Hasil’)
cross_entropy = tf.reduce_mean (
tf.nn.sigmoid_cross_entropy_with_logits (log = y, label = y_))
Sigmoid adalah fungsi aktivasi lain, seperti relu yang kami temui di atas, ada untuk menyediakan non-linearitas. Saya menggunakan sigmoid di sini sebagian karena persamaan sigmoid menghasilkan nilai antara 0 dan 1, ideal untuk contoh counter biner kami. Saya juga menggunakannya karena baik untuk output di mana lebih dari satu unit output dapat memiliki nilai besar. Dalam kasus kami, untuk mewakili angka biner 111, semua unit output dapat memiliki nilai besar. Saat melakukan klasifikasi gambar, kami ingin sesuatu yang sangat berbeda, kami hanya ingin satu unit keluaran untuk menembak dengan nilai besar. Misalnya, kami ingin unit keluaran mewakili jerapah untuk memiliki nilai besar jika suatu gambar berisi jerapah. Sesuatu seperti Softmax akan menjadi pilihan yang baik untuk klasifikasi gambar.
Pada inspeksi dekat, sepertinya ada beberapa duplikasi. Kami tampaknya memasukkan sigmoid dua kali. Kami benar-benar membuat dua yang berbeda, paralel output di sini. Tensor cross_entropy akan digunakan selama pelatihan jaringan netral. Hasil tensor akan digunakan ketika kami menjalankan jaringan saraf terlatih kami nanti untuk tujuan apa pun yang diciptakan, untuk bersenang-senang dalam kasus kami. Saya tidak tahu apakah ini cara terbaik untuk melakukan ini, tapi itu cara saya datang.
train_step = tf.train.rmspropoptimizer (0.25, momentum = 0.5) .Minimize (cross_entropy)
Bagian terakhir yang kami tambahkan ke grafik kami adalah pelatihan. Ini adalah OP atau OP yang akan menyesuaikan semua bobot berdasarkan data pelatihan. Ingat, kami masih hanya membuat grafik di sini. Pelatihan yang sebenarnya akan terjadi nanti ketika kita menjalankan grafik.
Ada beberapa pengoptimal untuk dipilih. Saya memilih tf.train.rmspropoptimizer karena, seperti sigmoid, itu bekerja dengan baik untuk kasus-kasus di mana semua nilai output bisa besar. Untuk mengklasifikasikan hal-hal seperti saat melakukan klasifikasi gambar, TF.Train.GradientDescentOptimizer mungkin lebih baik.
Pelatihan dan menggunakan konter biner
Setelah membuat grafik, saatnya untuk melakukan pelatihan. Setelah dilatih, kami kemudian dapat menggunakannya.
InputVals = [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 0, 1] ,
[1, 1, 0], [1, 1, 1]]
targetvals = [[0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 0], [1, 1, 0] ,
[1, 1, 1], [0, 0, 0]]
Pertama, kami memiliki beberapa data pelatihan: inputvals dan targetvals. Inputvals berisi input, dan untuk masing-masing ada nilai target targetvals yang sesuai. Untuk inputvals [0] kami memiliki [0, 0, 0], dan output yang diharapkan adalah targetvals [0], yang [0, 0, 1], dan sebagainya.
Jika do_training == 1:
sess.run (tf.global_variables_initializer ())
Untuk saya dalam jangkauan (10001):
Jika i% 100 == 0:
train_error = cross_entropy.eval (feed_dict = {x: inputvals, y_: targetvals})
Cetak (“langkah% d, pelatihan kesalahan% g”% (i, train_error))
Jika Train_Error <0,0005:
merusak
sess.run (train_step, feed_dict = {x: inputvals, y_: targetvals})
Jika save_trained == 1:
Cetak ("menghemat jaringan saraf ke% s. *"% (save_file))
saver = tf.train.saver ()
saver.save (sess, save_file)
do_training dan save_trained dapat hardcoded, dan diubah untuk setiap penggunaan, atau dapat diatur menggunakan argumen baris perintah.
Pertama-tama kita melalui semua operasi variabel itu dan meminta mereka menginisialisasi tensor mereka.
Kemudian, hingga 10001 kali kami menjalankan grafik dari bawah ke atas tensor train_step, hal terakhir yang kami tambahkan ke grafik kami. Kami melewati inputvals dan targetvals untuk melatih op atau ops atau ops, yang kami tambahkan menggunakan RMSPropOptimizer. Ini adalah langkah yang menyesuaikan semua bobot sehingga input yang diberikan akan menghasilkan sesuatu yang dekat dengan output target yang sesuai. Jika kesalahan antara output target dan output aktual menjadi cukup kecil lebih cepat, lalu kita keluar dari loop.
Jika Anda memiliki ribuan pasangan input / output maka Anda bisa memberikan subset dari mereka pada satu waktu, batch yang kami bicarakan sebelumnya. Tapi di sini kita hanya memiliki delapan, dan jadi kita memberi mereka semua setiap kali.
Jika kita mau, kita juga bisa menyimpan jaringan ke file. Setelah dilatih dengan baik, kita tidak perlu melatihnya lagi.
lain: # Jika kita tidak berlatih maka kita harus memuat dari file
Cetak ("Memuat Jaringan Saraf dari% s"% (save_file))
saver = tf.train.saver ()
saver.restore (sess, save_file)
# Catatan: Kembalikan kedua muatan dan inisialisasi variabel
Jika kami tidak melatihnya maka kami malah memuat jaringan terlatih dari file. File hanya berisi nilai untuk tensor yang memiliki operasi variabel. Itu tidak mengandung struktur grafik. Jadi bahkan ketika menjalankan grafik yang sudah terlatih, kami masih membutuhkan kode untuk membuat grafik. Ada cara untuk menyimpan dan memuat grafik dari file menggunakan metagraf tetapi kami tidak melakukan itu di sini.
Cetak ('\ ncounting dimulai dengan: 0 0 0')
res = sess.run (hasil, feed_dict = {x: [[0, 0, 0]]})
cetak ('% g% g% g'% (res [0] [0], res [0] [1], res [0] [2]))