Reka Algoritma Genetik di Jawa

1. Pengenalan

Tujuan siri ini adalah untuk menerangkan idea algoritma genetik .

Algoritma genetik dirancang untuk menyelesaikan masalah dengan menggunakan proses yang sama seperti di alam semula jadi - mereka menggunakan kombinasi pemilihan, penggabungan, dan mutasi untuk mengembangkan penyelesaian masalah.

Mari mulakan dengan menerangkan konsep algoritma tersebut menggunakan contoh algoritma genetik binari termudah.

2. Bagaimana Algoritma Genetik Berfungsi

Algoritma genetik adalah bahagian pengkomputeran evolusi , yang merupakan kawasan kecerdasan buatan yang berkembang pesat.

Algoritma bermula dengan sekumpulan penyelesaian (diwakili oleh individu ) yang disebut populasi . Penyelesaian dari satu populasi diambil dan digunakan untuk membentuk populasi baru , kerana ada kemungkinan populasi baru akan lebih baik daripada yang lama.

Individu yang dipilih untuk membentuk penyelesaian baru ( keturunan ) dipilih mengikut kesesuaian mereka - semakin sesuai, semakin besar peluang mereka untuk menghasilkan semula.

3. Algoritma Genetik Binari

Mari kita lihat proses asas untuk algoritma genetik sederhana.

3.1. Permulaan

Pada langkah inisialisasi, kami menghasilkan Populasi rawak yang berfungsi sebagai penyelesaian pertama . Pertama, kita perlu memutuskan seberapa besar jumlah Penduduk dan apakah penyelesaian terakhir yang kita harapkan:

SimpleGeneticAlgorithm.runAlgorithm(50, "1011000100000100010000100000100111001000000100000100000000001111");

Dalam contoh di atas, ukuran Populasi adalah 50, dan penyelesaian yang betul ditunjukkan oleh rentetan bit binari yang mungkin kita ubah pada bila-bila masa.

Pada langkah seterusnya kita akan menyimpan penyelesaian yang kita inginkan dan membuat Populasi secara rawak :

setSolution(solution); Population myPop = new Population(populationSize, true);

Sekarang kita sudah bersedia untuk menjalankan gelung utama program.

3.2. Pemeriksaan Kecergasan

Dalam gelung utama program, kita akan menilai setiap Individu dengan fungsi kecergasan (dengan kata mudah, semakin baik Individu , semakin tinggi nilai fungsi kecergasan yang diperolehnya):

while (myPop.getFittest().getFitness() < getMaxFitness()) { System.out.println( "Generation: " + generationCount + " Correct genes found: " + myPop.getFittest().getFitness()); myPop = evolvePopulation(myPop); generationCount++; }

Mari kita mulakan dengan menerangkan bagaimana kita mendapatkan Individu yang paling tepat :

public int getFitness(Individual individual) { int fitness = 0; for (int i = 0; i < individual.getDefaultGeneLength() && i < solution.length; i++) { if (individual.getSingleGene(i) == solution[i]) { fitness++; } } return fitness; }

Seperti yang dapat kita perhatikan, kita membandingkan dua objek Individu sedikit demi sedikit. Sekiranya kita tidak dapat mencari jalan penyelesaian yang sempurna, kita harus melangkah ke langkah berikutnya, yang merupakan evolusi Penduduk .

3.3. Keturunan

Dalam langkah ini, kita perlu membuat Populasi baru . Pertama, kita perlu Pilih dua ibubapa Individu objek dari Penduduk, mengikut kecergasan mereka. Harap maklum bahawa adalah bermanfaat untuk membiarkan Individu terbaik dari generasi sekarang terus menerus ke yang berikutnya, tidak berubah. Strategi ini disebut Elitisme:

if (elitism) { newPopulation.getIndividuals().add(0, pop.getFittest()); elitismOffset = 1; } else { elitismOffset = 0; }

Untuk memilih dua objek Individu terbaik , kami akan menerapkan strategi pemilihan kejohanan :

private Individual tournamentSelection(Population pop) { Population tournament = new Population(tournamentSize, false); for (int i = 0; i < tournamentSize; i++) { int randomId = (int) (Math.random() * pop.getIndividuals().size()); tournament.getIndividuals().add(i, pop.getIndividual(randomId)); } Individual fittest = tournament.getFittest(); return fittest; }

Pemenang setiap kejohanan (satu dengan kecergasan terbaik) dipilih untuk peringkat seterusnya, iaitu Crossover :

private Individual crossover(Individual indiv1, Individual indiv2) { Individual newSol = new Individual(); for (int i = 0; i < newSol.getDefaultGeneLength(); i++) { if (Math.random() <= uniformRate) { newSol.setSingleGene(i, indiv1.getSingleGene(i)); } else { newSol.setSingleGene(i, indiv2.getSingleGene(i)); } } return newSol; }

Dalam crossover, kami menukar bit dari setiap Individu yang dipilih di tempat yang dipilih secara rawak. Seluruh proses berjalan di dalam gelung berikut:

for (int i = elitismOffset; i < pop.getIndividuals().size(); i++) { Individual indiv1 = tournamentSelection(pop); Individual indiv2 = tournamentSelection(pop); Individual newIndiv = crossover(indiv1, indiv2); newPopulation.getIndividuals().add(i, newIndiv); }

Seperti yang dapat kita lihat, setelah berlakunya crossover, kita menempatkan keturunan baru dalam Populasi baru . Langkah ini dipanggil Penerimaan.

Akhirnya, kita dapat melakukan Mutasi . Mutasi digunakan untuk mengekalkan kepelbagaian genetik dari satu generasi Populasi ke generasi berikutnya. Kami menggunakan jenis mutasi penyongsangan bit , di mana bit rawak hanya terbalik:

private void mutate(Individual indiv) { for (int i = 0; i < indiv.getDefaultGeneLength(); i++) { if (Math.random() <= mutationRate) { byte gene = (byte) Math.round(Math.random()); indiv.setSingleGene(i, gene); } } }

Semua jenis Mutasi dan Crossover dijelaskan dengan baik dalam tutorial ini.

Kami kemudian mengulangi langkah dari subseksyen 3.2 dan 3.3, sehingga kami mencapai keadaan penamatan, sebagai contoh, penyelesaian terbaik.

4. Petua dan Trik

Untuk melaksanakan algoritma genetik yang cekap , kita perlu menyesuaikan satu set parameter. Bahagian ini akan memberi anda beberapa cadangan asas bagaimana memulakan dengan parameter yang paling banyak mengimport:

  • Kadar crossover - semestinya tinggi, sekitar 80% -95%
  • Kadar mutasi - semestinya sangat rendah, sekitar 0.5% -1% .
  • Saiz populasi - ukuran populasi yang baik adalah sekitar 20-30 , namun, untuk beberapa masalah ukuran 50-100 lebih baik
  • Pemilihan - pemilihan roda rolet asas boleh digunakan dengan konsep elitisme
  • Jenis crossover dan mutasi - ia bergantung pada pengekodan dan masalahnya

Harap maklum bahawa cadangan penalaan selalunya merupakan hasil kajian empirik pada algoritma genetik, dan mereka mungkin berbeza, berdasarkan masalah yang dicadangkan.

5. Kesimpulan

Tutorial ini memperkenalkan asas algoritma genetik . Anda boleh belajar mengenai algoritma genetik tanpa pengetahuan sebelumnya mengenai bidang ini, yang hanya mempunyai kemahiran pengaturcaraan komputer asas.

Kod sumber lengkap untuk coretan kod dalam tutorial ini terdapat di projek GitHub.

Perlu diketahui juga bahawa kami menggunakan Lombok untuk menghasilkan pemula dan pengatur. Anda boleh menyemak cara mengkonfigurasinya dengan betul di IDE anda dalam artikel ini.

Untuk contoh algoritma genetik lebih lanjut, lihat semua artikel siri kami:

  • Bagaimana Merangka Algoritma Genetik? (yang ini)
  • Masalah Penjual Perjalanan di Jawa