Contoh jaringan saraf sederhana di C / C ++

Halo semuanya.

Saya memutuskan untuk berbagi solusi opini sederhana dari jaringan saraf di C ++.

Mengapa informasi ini menarik?

Jawaban: Saya mencoba memprogram pekerjaan multilayer perceptron dalam set minimal, sehingga dapat dikonfigurasi sesuai keinginan hanya dalam beberapa baris kode, dan penerapan algoritma dasar untuk bekerja pada "C" akan memungkinkan Anda untuk dengan mudah mentransfer bahasa berorientasi ke "C" (dalam dan ke yang lain) tanpa menggunakan perpustakaan pihak ketiga!

Silakan lihat apa yang terjadi


Saya tidak akan memberi tahu Anda tentang tujuan jaringan saraf , saya harap Anda belum dilarang dari google dan Anda dapat menemukan informasi yang Anda minati (tujuan, kemampuan, aplikasi, dan sebagainya).

Anda akan menemukan kode sumber di akhir artikel, tetapi untuk saat ini, secara berurutan.

Mari kita mulai analisisnya


1) Arsitektur dan detail teknis


- multilayer perceptron dengan kemampuan untuk mengkonfigurasi sejumlah lapisan dengan lebar yang diberikan. Di bawah ini disajikan

contoh konfigurasi
myNeuero.cpp

inputNeurons = 100; //   outputNeurons =2; //   nlCount = 4; //  (    3,      1 list = (nnLay*) malloc((nlCount)*sizeof(nnLay)); inputs = (float*) malloc((inputNeurons)*sizeof(float)); targets = (float*) malloc((outputNeurons)*sizeof(float)); list[0].setIO(100,20); //  INPUTS/OUTPUTS    list[1].setIO(20,6); // -//- list[2].setIO(6,3); // -//- list[3].setIO(3,2); // -//-   


Harap dicatat bahwa pengaturan lebar input dan output untuk setiap lapisan dilakukan sesuai dengan aturan tertentu - input dari layer saat ini = output dari yang sebelumnya. Pengecualian adalah lapisan input.

Dengan demikian, Anda memiliki kesempatan untuk mengkonfigurasi konfigurasi apa pun secara manual atau sesuai dengan aturan yang diberikan sebelum kompilasi atau setelah kompilasi untuk membaca data dari file sumber.

- implementasi mekanisme penyebaran kesalahan dengan kemampuan untuk mengatur kecepatan belajar

myNeuero.h

  #define learnRate 0.1 

- Pemasangan bobot awal

myNeuero.h

  #define randWeight (( ((float)qrand() / (float)RAND_MAX) - 0.5)* pow(out,-0.5)) 

Catatan : jika ada lebih dari tiga lapisan (nlCount> 4), maka pow (out, -0.5) perlu ditingkatkan sehingga ketika sinyal lewat langsung, energinya tidak berkurang menjadi 0. Contoh pow (out, -0.2)

- dasar kode dalam C. Algoritma dasar dan penyimpanan koefisien pembobotan diimplementasikan sebagai struktur dalam C, yang lainnya adalah shell dari fungsi pemanggilan struktur ini, juga merupakan refleksi dari setiap lapisan yang diambil secara terpisah

Struktur lapisan
myNeuero.h

  struct nnLay{ int in; int out; float** matrix; float* hidden; float* errors; int getInCount(){return in;} int getOutCount(){return out;} float **getMatrix(){return matrix;} void updMatrix(float *enteredVal) { for(int ou =0; ou < out; ou++) { for(int hid =0; hid < in; hid++) { matrix[hid][ou] += (learnRate * errors[ou] * enteredVal[hid]); } matrix[in][ou] += (learnRate * errors[ou]); } }; void setIO(int inputs, int outputs) { in=inputs; out=outputs; hidden = (float*) malloc((out)*sizeof(float)); matrix = (float**) malloc((in+1)*sizeof(float)); for(int inp =0; inp < in+1; inp++) { matrix[inp] = (float*) malloc(out*sizeof(float)); } for(int inp =0; inp < in+1; inp++) { for(int outp =0; outp < out; outp++) { matrix[inp][outp] = randWeight; } } } void makeHidden(float *inputs) { for(int hid =0; hid < out; hid++) { float tmpS = 0.0; for(int inp =0; inp < in; inp++) { tmpS += inputs[inp] * matrix[inp][hid]; } tmpS += matrix[in][hid]; hidden[hid] = sigmoida(tmpS); } }; float* getHidden() { return hidden; }; void calcOutError(float *targets) { errors = (float*) malloc((out)*sizeof(float)); for(int ou =0; ou < out; ou++) { errors[ou] = (targets[ou] - hidden[ou]) * sigmoidasDerivate(hidden[ou]); } }; void calcHidError(float *targets,float **outWeights,int inS, int outS) { errors = (float*) malloc((inS)*sizeof(float)); for(int hid =0; hid < inS; hid++) { errors[hid] = 0.0; for(int ou =0; ou < outS; ou++) { errors[hid] += targets[ou] * outWeights[hid][ou]; } errors[hid] *= sigmoidasDerivate(hidden[hid]); } }; float* getErrors() { return errors; }; float sigmoida(float val) { return (1.0 / (1.0 + exp(-val))); } float sigmoidasDerivate(float val) { return (val * (1.0 - val)); }; }; 


2) Aplikasi


Menguji proyek dengan set mnist berhasil, kami berhasil mencapai probabilitas pengenalan tulisan tangan bersyarat 0,9795 (nlCount = 4, learnRate = 0,03 dan beberapa era). Tujuan utama dari tes ini adalah untuk menguji kinerja jaringan saraf, yang digunakan untuk mengatasinya.

Di bawah ini kami mempertimbangkan pekerjaan pada "tugas bersyarat" .

Sumber data:

-2 vektor input acak dari 100 nilai
jaringan saraf dengan generasi bobot acak
-2 menetapkan tujuan

Kode dalam fungsi main ()

 { //!!!________    qDebug()   std::cout  std::cerr myNeuro *bb = new myNeuro(); //----------------------------------INPUTS----GENERATOR------------- /!  2    qsrand((QTime::currentTime().second())); float *abc = new float[100]; for(int i=0; i<100;i++) { abc[i] =(qrand()%98)*0.01+0.01; } float *cba = new float[100]; for(int i=0; i<100;i++) { cba[i] =(qrand()%98)*0.01+0.01; } //---------------------------------TARGETS----GENERATOR------------- //  2   float *tar1 = new float[2]; tar1[0] =0.01; tar1[1] =0.99; float *tar2 = new float[2]; tar2[0] =0.99; tar2[1] =0.01; //--------------------------------NN---------WORKING--------------- //    bb->query(abc); qDebug()<<"_________________________________"; bb->query(cba); //  int i=0; while(i<100000) { bb->train(abc,tar1); bb->train(cba,tar2); i++; } //   (   ) qDebug()<<"___________________RESULT_____________"; bb->query(abc); qDebug()<<"______"; bb->query(cba); } 

Hasil dari jaringan saraf

gambar

Ringkasan


Seperti yang Anda lihat, memanggil fungsi kueri (input) sebelum pelatihan untuk masing-masing vektor tidak memungkinkan kami untuk menilai perbedaan mereka. Selanjutnya, dengan memanggil fungsi kereta (input, target), untuk pelatihan dengan tujuan mengatur koefisien bobot sehingga jaringan saraf selanjutnya dapat membedakan antara vektor input.

Setelah menyelesaikan pelatihan, kami mengamati bahwa upaya untuk memetakan vektor "abc" ke "tar1", dan "cba" ke "tar2" gagal.

Anda diberi kesempatan, menggunakan kode sumber, untuk secara independen menguji kinerja dan bereksperimen dengan konfigurasi!

PS: kode ini ditulis dari QtCreator, saya harap Anda dapat dengan mudah mengganti output, tinggalkan komentar dan komentar Anda.

PPS: jika ada yang tertarik dengan analisis terperinci dari pekerjaan struct nnLay {} write, akan ada posting baru.

PPPS: Saya harap seseorang dapat menggunakan kode berorientasi "C" untuk porting ke alat lain.

Kode sumber
main.cpp

 #include <QCoreApplication> #include <QDebug> #include <QTime> #include "myneuro.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); myNeuro *bb = new myNeuro(); //----------------------------------INPUTS----GENERATOR------------- qsrand((QTime::currentTime().second())); float *abc = new float[100]; for(int i=0; i<100;i++) { abc[i] =(qrand()%98)*0.01+0.01; } float *cba = new float[100]; for(int i=0; i<100;i++) { cba[i] =(qrand()%98)*0.01+0.01; } //---------------------------------TARGETS----GENERATOR------------- float *tar1 = new float[2]; tar1[0] =0.01; tar1[1] =0.99; float *tar2 = new float[2]; tar2[0] =0.99; tar2[1] =0.01; //--------------------------------NN---------WORKING--------------- bb->query(abc); qDebug()<<"_________________________________"; bb->query(cba); int i=0; while(i<100000) { bb->train(abc,tar1); bb->train(cba,tar2); i++; } qDebug()<<"___________________RESULT_____________"; bb->query(abc); qDebug()<<"______"; bb->query(cba); qDebug()<<"_______________THE____END_______________"; return a.exec(); } 

myNeuro.cpp

 #include "myneuro.h" #include <QDebug> myNeuro::myNeuro() { //-------- inputNeurons = 100; outputNeurons =2; nlCount = 4; list = (nnLay*) malloc((nlCount)*sizeof(nnLay)); inputs = (float*) malloc((inputNeurons)*sizeof(float)); targets = (float*) malloc((outputNeurons)*sizeof(float)); list[0].setIO(100,20); list[1].setIO(20,6); list[2].setIO(6,3); list[3].setIO(3,2); //----------------- // inputNeurons = 100; // outputNeurons =2; // nlCount = 2; // list = (nnLay*) malloc((nlCount)*sizeof(nnLay)); // inputs = (float*) malloc((inputNeurons)*sizeof(float)); // targets = (float*) malloc((outputNeurons)*sizeof(float)); // list[0].setIO(100,10); // list[1].setIO(10,2); } void myNeuro::feedForwarding(bool ok) { list[0].makeHidden(inputs); for (int i =1; i<nlCount; i++) list[i].makeHidden(list[i-1].getHidden()); if (!ok) { qDebug()<<"Feed Forward: "; for(int out =0; out < outputNeurons; out++) { qDebug()<<list[nlCount-1].hidden[out]; } return; } else { // printArray(list[3].getErrors(),list[3].getOutCount()); backPropagate(); } } void myNeuro::backPropagate() { //-------------------------------ERRORS-----CALC--------- list[nlCount-1].calcOutError(targets); for (int i =nlCount-2; i>=0; i--) list[i].calcHidError(list[i+1].getErrors(),list[i+1].getMatrix(), list[i+1].getInCount(),list[i+1].getOutCount()); //-------------------------------UPD-----WEIGHT--------- for (int i =nlCount-1; i>0; i--) list[i].updMatrix(list[i-1].getHidden()); list[0].updMatrix(inputs); } void myNeuro::train(float *in, float *targ) { inputs = in; targets = targ; feedForwarding(true); } void myNeuro::query(float *in) { inputs=in; feedForwarding(false); } void myNeuro::printArray(float *arr, int s) { qDebug()<<"__"; for(int inp =0; inp < s; inp++) { qDebug()<<arr[inp]; } } 

myNeuro.h

 #ifndef MYNEURO_H #define MYNEURO_H #include <iostream> #include <math.h> #include <QtGlobal> #include <QDebug> #define learnRate 0.1 #define randWeight (( ((float)qrand() / (float)RAND_MAX) - 0.5)* pow(out,-0.5)) class myNeuro { public: myNeuro(); struct nnLay{ int in; int out; float** matrix; float* hidden; float* errors; int getInCount(){return in;} int getOutCount(){return out;} float **getMatrix(){return matrix;} void updMatrix(float *enteredVal) { for(int ou =0; ou < out; ou++) { for(int hid =0; hid < in; hid++) { matrix[hid][ou] += (learnRate * errors[ou] * enteredVal[hid]); } matrix[in][ou] += (learnRate * errors[ou]); } }; void setIO(int inputs, int outputs) { in=inputs; out=outputs; hidden = (float*) malloc((out)*sizeof(float)); matrix = (float**) malloc((in+1)*sizeof(float)); for(int inp =0; inp < in+1; inp++) { matrix[inp] = (float*) malloc(out*sizeof(float)); } for(int inp =0; inp < in+1; inp++) { for(int outp =0; outp < out; outp++) { matrix[inp][outp] = randWeight; } } } void makeHidden(float *inputs) { for(int hid =0; hid < out; hid++) { float tmpS = 0.0; for(int inp =0; inp < in; inp++) { tmpS += inputs[inp] * matrix[inp][hid]; } tmpS += matrix[in][hid]; hidden[hid] = sigmoida(tmpS); } }; float* getHidden() { return hidden; }; void calcOutError(float *targets) { errors = (float*) malloc((out)*sizeof(float)); for(int ou =0; ou < out; ou++) { errors[ou] = (targets[ou] - hidden[ou]) * sigmoidasDerivate(hidden[ou]); } }; void calcHidError(float *targets,float **outWeights,int inS, int outS) { errors = (float*) malloc((inS)*sizeof(float)); for(int hid =0; hid < inS; hid++) { errors[hid] = 0.0; for(int ou =0; ou < outS; ou++) { errors[hid] += targets[ou] * outWeights[hid][ou]; } errors[hid] *= sigmoidasDerivate(hidden[hid]); } }; float* getErrors() { return errors; }; float sigmoida(float val) { return (1.0 / (1.0 + exp(-val))); } float sigmoidasDerivate(float val) { return (val * (1.0 - val)); }; }; void feedForwarding(bool ok); void backPropagate(); void train(float *in, float *targ); void query(float *in); void printArray(float *arr,int s); private: struct nnLay *list; int inputNeurons; int outputNeurons; int nlCount; float *inputs; float *targets; }; #endif // MYNEURO_H 



UPD:

Sumber untuk memeriksa mnist adalah dengan
tautannya
1) Proyek
" Github.com/mamkin-itshnik/simple-neuro-network "
Ada juga deskripsi grafis dari karya tersebut. Secara singkat, ketika melakukan polling jaringan dengan data uji, Anda diberi nilai dari masing-masing neuron output (10 neuron sesuai dengan angka dari 0 hingga 9). Untuk membuat keputusan tentang sosok yang digambarkan, Anda perlu mengetahui indeks neuron maksimum. Digit = indeks + 1 (jangan lupa dari mana nomor dalam array diberi nomor dari))
2) MNIST
Www.kaggle.com/oddrationale/mnist-in-csv ” (jika Anda perlu menggunakan dataset yang lebih kecil, cukup batasi penghitung sementara saat membaca file CSV dari PS: ada contoh untuk git)

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


All Articles