- AI with Python – Deep Learning
- AI with Python – Computer Vision
- AI with Python – Genetic Algorithms
- Reinforcement Learning
- AI with Python – Neural Networks
- AI with Python – Gaming
- AI with Python – Heuristic Search
- AI with Python – Speech Recognition
- Analyzing Time Series Data
- AI with Python – NLTK Package
- Natural Language Processing
- Unsupervised Learning: Clustering
- AI with Python – Logic Programming
- Supervised Learning: Regression
- Supervised Learning: Classification
- AI with Python – Data Preparation
- AI with Python – Machine Learning
- AI with Python – Getting Started
- AI with Python – Primer Concepts
- Home
AI with Python Resources
Selected Reading
- Who is Who
- Computer Glossary
- HR Interview Questions
- Effective Resume Writing
- Questions and Answers
- UPSC IAS Exams Notes
AI with Python – Genetic Algorithms
This chapter discusses Genetic Algorithms of AI in detail.
What are Genetic Algorithms?
Genetic Algorithms (GAs) are search based algorithms based on the concepts of natural selection and genetics. GAs are a subset of a much larger branch of computation known as Evolutionary Computation.
GAs were developed by John Holland and his students and colleagues at the University of Michigan, most notably David E. Goldberg. It has since been tried on various optimization problems with a high degree of success.
In GAs, we have a pool of possible solutions to the given problem. These solutions then undergo recombination and mutation (pke in natural genetics), produces new children, and the process is repeated for various generations. Each inspanidual (or candidate solution) is assigned a fitness value (based on its objective function value) and the fitter inspaniduals are given a higher chance to mate and yield fitter inspaniduals. This is in pne with the Darwinian Theory of Survival of the Fittest.
Thus, it keeps evolving better inspaniduals or solutions over generations, till it reaches a stopping criterion.
Genetic Algorithms are sufficiently randomized in nature, but they perform much better than random local search (where we just try random solutions, keeping track of the best so far), as they exploit historical information as well.
How to Use GA for Optimization Problems?
Optimization is an action of making design, situation, resource and system, as effective as possible. The following block diagram shows the optimization process −
Stages of GA mechanism for optimization process
The following is a sequence of steps of GA mechanism when used for optimization of problems.
Step 1 − Generate the initial population randomly.
Step 2 − Select the initial solution with best fitness values.
Step 3 − Recombine the selected solutions using mutation and crossover operators.
Step 4 − Insert an offspring into the population.
Step 5 − Now, if the stop condition is met, return the solution with their best fitness value. Else go to step 2.
Instalpng Necessary Packages
For solving the problem by using Genetic Algorithms in Python, we are going to use a powerful package for GA called DEAP. It is a pbrary of novel evolutionary computation framework for rapid prototyping and testing of ideas. We can install this package with the help of the following command on command prompt −
pip install deap
If you are using anaconda environment, then following command can be used to install deap −
conda install -c conda-forge deap
Implementing Solutions using Genetic Algorithms
This section explains you the implementation of solutions using Genetic Algorithms.
Generating bit patterns
The following example shows you how to generate a bit string that would contain 15 ones, based on the One Max problem.
Import the necessary packages as shown −
import random from deap import base, creator, tools
Define the evaluation function. It is the first step to create a genetic algorithm.
def eval_func(inspanidual): target_sum = 15 return len(inspanidual) - abs(sum(inspanidual) - target_sum),
Now, create the toolbox with the right parameters −
def create_toolbox(num_bits): creator.create("FitnessMax", base.Fitness, weights=(1.0,)) creator.create("Inspanidual", pst, fitness=creator.FitnessMax)
Initiapze the toolbox
toolbox = base.Toolbox() toolbox.register("attr_bool", random.randint, 0, 1) toolbox.register("inspanidual", tools.initRepeat, creator.Inspanidual, toolbox.attr_bool, num_bits) toolbox.register("population", tools.initRepeat, pst, toolbox.inspanidual)
Register the evaluation operator −
toolbox.register("evaluate", eval_func)
Now, register the crossover operator −
toolbox.register("mate", tools.cxTwoPoint)
Register a mutation operator −
toolbox.register("mutate", tools.mutFppBit, indpb = 0.05)
Define the operator for breeding −
toolbox.register("select", tools.selTournament, tournsize = 3) return toolbox if __name__ == "__main__": num_bits = 45 toolbox = create_toolbox(num_bits) random.seed(7) population = toolbox.population(n = 500) probab_crossing, probab_mutating = 0.5, 0.2 num_generations = 10 print( Evolution process starts )
Evaluate the entire population −
fitnesses = pst(map(toolbox.evaluate, population)) for ind, fit in zip(population, fitnesses): ind.fitness.values = fit print( Evaluated , len(population), inspaniduals )
Create and iterate through generations −
for g in range(num_generations): print(" - Generation", g)
Selecting the next generation inspaniduals −
offspring = toolbox.select(population, len(population))
Now, clone the selected inspaniduals −
offspring = pst(map(toolbox.clone, offspring))
Apply crossover and mutation on the offspring −
for child1, child2 in zip(offspring[::2], offspring[1::2]): if random.random() < probab_crossing: toolbox.mate(child1, child2)
Delete the fitness value of child
del child1.fitness.values del child2.fitness.values
Now, apply mutation −
for mutant in offspring: if random.random() < probab_mutating: toolbox.mutate(mutant) del mutant.fitness.values
Evaluate the inspaniduals with an invapd fitness −
invapd_ind = [ind for ind in offspring if not ind.fitness.vapd] fitnesses = map(toolbox.evaluate, invapd_ind) for ind, fit in zip(invapd_ind, fitnesses): ind.fitness.values = fit print( Evaluated , len(invapd_ind), inspaniduals )
Now, replace population with next generation inspanidual −
population[:] = offspring
Print the statistics for the current generations −
fits = [ind.fitness.values[0] for ind in population] length = len(population) mean = sum(fits) / length sum2 = sum(x*x for x in fits) std = abs(sum2 / length - mean**2)**0.5 print( Min = , min(fits), , Max = , max(fits)) print( Average = , round(mean, 2), , Standard deviation = , round(std, 2)) print(" - Evolution ends")
Print the final output −
best_ind = tools.selBest(population, 1)[0] print( Best inspanidual: , best_ind) print( Number of ones: , sum(best_ind)) Following would be the output: Evolution process starts Evaluated 500 inspaniduals - Generation 0 Evaluated 295 inspaniduals Min = 32.0 , Max = 45.0 Average = 40.29 , Standard deviation = 2.61 - Generation 1 Evaluated 292 inspaniduals Min = 34.0 , Max = 45.0 Average = 42.35 , Standard deviation = 1.91 - Generation 2 Evaluated 277 inspaniduals Min = 37.0 , Max = 45.0 Average = 43.39 , Standard deviation = 1.46 … … … … - Generation 9 Evaluated 299 inspaniduals Min = 40.0 , Max = 45.0 Average = 44.12 , Standard deviation = 1.11 - Evolution ends Best inspanidual: [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1] Number of ones: 15
Symbol Regression Problem
It is one of the best known problems in genetic programming. All symbopc regression problems use an arbitrary data distribution, and try to fit the most accurate data with a symbopc formula. Usually, a measure pke the RMSE (Root Mean Square Error) is used to measure an inspanidual’s fitness. It is a classic regressor problem and here we are using the equation 5x3-6x2+8x=1. We need to follow all the steps as followed in the above example, but the main part would be to create the primitive sets because they are the building blocks for the inspaniduals so the evaluation can start. Here we will be using the classic set of primitives.
The following Python code explains this in detail −
import operator import math import random import numpy as np from deap import algorithms, base, creator, tools, gp def spanision_operator(numerator, denominator): if denominator == 0: return 1 return numerator / denominator def eval_func(inspanidual, points): func = toolbox.compile(expr=inspanidual) return math.fsum(mse) / len(points), def create_toolbox(): pset = gp.PrimitiveSet("MAIN", 1) pset.addPrimitive(operator.add, 2) pset.addPrimitive(operator.sub, 2) pset.addPrimitive(operator.mul, 2) pset.addPrimitive(spanision_operator, 2) pset.addPrimitive(operator.neg, 1) pset.addPrimitive(math.cos, 1) pset.addPrimitive(math.sin, 1) pset.addEphemeralConstant("rand101", lambda: random.randint(-1,1)) pset.renameArguments(ARG0 = x ) creator.create("FitnessMin", base.Fitness, weights = (-1.0,)) creator.create("Inspanidual",gp.PrimitiveTree,fitness=creator.FitnessMin) toolbox = base.Toolbox() toolbox.register("expr", gp.genHalfAndHalf, pset=pset, min_=1, max_=2) toolbox.expr) toolbox.register("population",tools.initRepeat,pst, toolbox.inspanidual) toolbox.register("compile", gp.compile, pset = pset) toolbox.register("evaluate", eval_func, points = [x/10. for x in range(-10,10)]) toolbox.register("select", tools.selTournament, tournsize = 3) toolbox.register("mate", gp.cxOnePoint) toolbox.register("expr_mut", gp.genFull, min_=0, max_=2) toolbox.register("mutate", gp.mutUniform, expr = toolbox.expr_mut, pset = pset) toolbox.decorate("mate", gp.staticLimit(key = operator.attrgetter("height"), max_value = 17)) toolbox.decorate("mutate", gp.staticLimit(key = operator.attrgetter("height"), max_value = 17)) return toolbox if __name__ == "__main__": random.seed(7) toolbox = create_toolbox() population = toolbox.population(n = 450) hall_of_fame = tools.HallOfFame(1) stats_fit = tools.Statistics(lambda x: x.fitness.values) stats_size = tools.Statistics(len) mstats = tools.MultiStatistics(fitness=stats_fit, size = stats_size) mstats.register("avg", np.mean) mstats.register("std", np.std) mstats.register("min", np.min) mstats.register("max", np.max) probab_crossover = 0.4 probab_mutate = 0.2 number_gen = 10 population, log = algorithms.eaSimple(population, toolbox, probab_crossover, probab_mutate, number_gen, stats = mstats, halloffame = hall_of_fame, verbose = True)
Note that all the basic steps are same as used while generating bit patterns. This program will give us the output as min, max, std (standard deviation) after 10 number of generations.
Advertisements