Часто в машинном обучении нам всегда нужно оптимизировать функции или параметры. Вот почему использование алгоритмов оптимизации в нескольких методах машинного обучения становится очень распространенным. Существует несколько алгоритмов оптимизации, но генетический алгоритм нашел применение во многих областях машинного обучения. В этом уроке я попытаюсь объяснить, что такое генетический алгоритм. Мы также реализуем простую версию генетического алгоритма и объясним его интуицию. После этого мы попытаемся понять некоторые варианты использования генетического алгоритма в машинном обучении.

Что такое генетический алгоритм?

Генетический алгоритм - это алгоритм оптимизации, основанный на теории эволюции. Он сосредоточен на выборе лучших параметров или составляющих популяции на основе функции приспособленности, которая показывает, насколько хорошо они удовлетворяют желаемой задаче оптимизации. Затем эти параметры видоизменяются в надежде, что они дадут более здоровое потомство. По сути, это основная интуиция, лежащая в основе генетического алгоритма.

Реализация генетического алгоритма с нуля

Базовый генетический алгоритм состоит из следующих этапов:

  1. Инициализировать популяцию
  2. Создать функцию расчета фитнеса
  3. Определить брачный пул
  4. Выберите родителей
  5. Перейти к мату
  6. Мутировать
  7. Получите потомство, которое будет новой популяцией для шага 1.
  8. Вернитесь к 2 и повторяйте, пока не будет выполнено условие остановки.

Вот простая блок-схема, объясняющая

Теперь приступим к реализации генетического алгоритма с нуля. Мы будем стремиться оптимизировать простое линейное уравнение, которое - F (X) = A1X1 + A2X2 + A3X3 + A4X4. Где X1 = 4, X2 = -2, X3 = 3,5 и X4 = -4,2

Все выбрано случайно.

Генетический алгоритм поможет нам определить лучшие множители - значения A - которые дадут максимальное значение F (X) в количестве данного поколения. Мы создали несколько функций, которые помогают нам выполнять расчет пригодности, родительский отбор, кроссовер и мутацию.

Мы проведем нашу аналитическую оценку на протяжении десяти поколений и будем иметь по 6 решений в каждом поколении.

Наш основной генетический алгоритм будет состоять из следующих этапов:

Инициализация популяции: это включает в себя инициализацию вашего образца решения. Для нашей совокупности решений они инициализируются между -5 и плюс 5 (выбираются случайным образом), как показано ниже:

#Import numpy library import numpy as np 
#Set seed for reproducability 
np.random.seed(100)

Создание функции расчета пригодности. Теперь мы перейдем к циклическому перебору количества поколений и вычислению пригодности каждого решения в поколении, начиная с нашего первоначального решения. Эта фитнес-функция будет рассчитана с помощью нашей уже созданной фитнес-функции, которая помогает нам максимизировать линейное уравнение F (X). Расчет пригодности для каждого поколения можно увидеть ниже:

#Calcuate fitness of population

def calculate_fitness(inputs, population):
    
    '''
    Description: This function calculates the fitness of our solutions
    
    Input Arguments: input values and a population of weights
    
    Output: Fitness - a fitness value
    
    '''
    
    fitness = np.sum(population*inputs, axis=1)
    return fitness

Выберите родителей для спаривания: мы перейдем к выбору родительского пула для создания следующего поколения на основе функции пригодности. Это означает, что мы выберем наиболее подходящих родителей в каждом поколении и будем использовать их для создания потомков следующего поколения. Мы сделаем это с помощью нашей функции choose_mating. Из каждого поколения мы выберем трех наиболее приспособленных родителей, как показано ниже:

#Choose parents to mate 

def choose_mating(population, fitness, number_of_parents):
    
    '''
    Description: This function chooses the most fit solutions to mate in order to yield the next generation
    
    Input Arguments: a population, the fitness and the number of parents required to mate
    
    Output: 
    
    the parents to mate
    '''
    
    #initialize empty numpy array to hold parents
    parents = np.empty((number_of_parents, population.shape[1]))
    
    #loop to fill the created parents array with the fittest solutions and stop at the required number of parents
    for number in range(number_of_parents):
        maximum_fitness_index = np.where(fitness == np.max(fitness))
        maximum_fitness_index = maximum_fitness_index[0][0]
        parents[number, :] = population[maximum_fitness_index, :]
        fitness[maximum_fitness_index] = -99999999999
        
    
    return parents

Спаривание родителей. Затем мы приступим к спариванию родителей, выбранных из предыдущего поколения, чтобы создать следующее поколение. Мы воспользуемся пересечением в одну точку и выберем точку пересечения в центре родителей. Это означает, что ген первой половины первого родителя будет первым геном потомства и таким же геном второй половины второго родителя. Это выполняется с помощью кода ниже:

#Perform cross over

def crossingover(parents, size_of_offspring):
    '''
    Description: This function performs a one point cross over operation on the parents. 
    
    Input Arguments:
    Parents - the parents pool to be crossed over
    size of offspring - the size of offspring required
    
    Output: 
    
    offspring - the crossed over offspring
    '''
    # initialize an empty numpy array to hold the offsprings
    offspring = np.empty(size_of_offspring)
    
    # specify the point of cross over - at the center in our case
    point_of_crossover = np.uint8(size_of_offspring[1]/2)
    
    #loop over the number of offspring required to get the required offsprings
    
    for k in range(size_of_offspring[0]):
        # get index of first parent to be mated
        parent1_index = k%parents.shape[0]
        # get index of second parent to be mated
        parent2_index = (k+1)%parents.shape[0]
        # proceed to assign the first half of the first parents gene to the first half gene of the offspring
        offspring[k, 0:point_of_crossover] = parents[parent1_index, 0:point_of_crossover]
        # proceed to assign the second half of the second parents gene to the second half gene of the offspring
        offspring[k, point_of_crossover:] = parents[parent2_index, point_of_crossover:]
        
    return offspring
  • Выполните мутацию. Затем мы вызовем небольшие случайные изменения в гене потомства, чтобы уменьшить чрезмерную симметрию между родителями и потомками. Это делается ниже:
#perform mutation

def mutation(cross_over_offspring):
    
    '''
    Description: This function performs some random variation to the genes of the 
    solutions by adding a random bias number.
    
    Input - 
    cross_over_offspring - offspring obtained from the cross over function
    
    Output -
    Mutated offspring 
    
    '''
    
    #loop over the offsprings and add a random bias number to their genes
    for number in range(cross_over_offspring.shape[0]):
        # Create the random bias number to be used for muation. The arguments taken are the limits(low and high) and the size
        random_bias_number = np.random.uniform(-1.5, 1.5, 1)
        
        #Proceed to mutate by adding the bias number
        
        cross_over_offspring[number, 3] = cross_over_offspring[number, 3] + random_bias_number
    return cross_over_offspring

Получить наилучшее решение: пройдя цикл по каждому поколению, мы перейдем к получению наиболее подходящего решения из решений в последнем поколении. Это будет нашим наиболее подходящим решением, полученным с помощью генетического алгоритма. Теперь мы приступим к выполнению генетического алгоритма на простом примере функции, стремясь максимизировать ее.

Это уравнение задается как F (X) = A1X1 + A2X2 + A3X3 + A4X4F (X) = A1X1 + A2X2 + A3X3 + A4X4, где X1 = 4 X2 = -2 X3 = 3,5 X4 = -4,2 Все выбираются случайным образом.

Мы будем стремиться оптимизировать значения - A1, A2, A3 и A4, чтобы максимизировать функцию F (X). Мы начнем с набора входных данных X, а затем укажем количество весов. Затем мы указываем количество поколений, через которые будет происходить спаривание, и в конце выбираем лучшие решения.

Созданные ранее функции будут объединены для создания генетического алгоритма, который поможет нам получить максимум за указанные поколения.

'''
Implementing the GA

'''
# Specify inputs of the equation ( X values)
inputs = [4,-2,3.5,-4.2]

# Specify the number of weights or multipliers (A values, in our case) for each input which we are looking to optimize
number_of_weights = 4

# Specify the number of solutions in each generation. Each solution will have the number of weights
solutions = 6

#Specify the number of parents mating to yield the specified number of solutions
number_of_parents_mating = 3

# Define the population size based on the number of parents mating and the number of solutions
population_size = (solutions,number_of_weights)

#randomly create the inital population according to the specified population size
new_population = np.random.uniform(low=-5.0, high=5.0, size=population_size)

#Print out the initialized population
print(new_population)


#Specify the number of generations to mutate through 
number_of_generations = 10

#Loop over the specified number of generations

for generation in range(number_of_generations):
    
    #Print the generation in which we are currently looping through to keep track
    print("Generation : ", generation)
    
    # Calculate the fitness of the population in the current generation
    fitness = calculate_fitness(inputs, new_population)

    # Proceed to select the most fit parents to mate
    parents = choose_mating(new_population, fitness, 
                                      number_of_parents_mating)

    # Proceed to create offsprings via the one point cross over
    crossover = crossingover(parents,
                                       size_of_offspring=(population_size[0]-parents.shape[0], number_of_weights))

    # Proceed to add random bias to the genes of the created offspring via the mutation function
    mutated = mutation(crossover)

    # Proceed to create the new population from the parents and the mutated
    new_population[0:parents.shape[0], :] = parents
    new_population[parents.shape[0]:, :] = mutated

    # Get the best or most fit solution in this current generation
    print("Best result : ", np.max(np.sum(new_population*inputs, axis=1)))
#Calculate fitness of final generation
fitness = calculate_fitness(inputs, new_population)

# Get most fit solution of final generation
most_fit_index = np.where(fitness == np.max(fitness))

#Print out the best solution 
print("Best solution : ", new_population[most_fit_index, :])
print("Best solution fitness : ", fitness[most_fit_index])

Использование генетического алгоритма в машинном обучении

  • Выбор функций. Генетический алгоритм (GA) можно использовать для выбора функций для обучения алгоритмов машинного обучения. GA будет стремиться оптимизировать показатель производительности модели машинного обучения, выбирая лучшие функции, которые дают это. Учеными было выполнено много работ по использованию GA для выбора функций в алгоритмах машинного обучения - здесь и
  • Настройка гиперпараметров: гиперпараметры алгоритмов машинного обучения и нейронных сетей могут быть настроены для оптимизации производительности модели с использованием генетического алгоритма. Это потребует использования ГА для поиска наиболее подходящих гиперпараметров, которые оптимизируют производительность модели и уменьшают функцию затрат.
  • Обучение с подкреплением. Обучение с подкреплением идеально подходит для генетического алгоритма, поскольку оба они направлены на оптимизацию решений на основе предыдущих. Было много применений генетического алгоритма в обучении с подкреплением, например, здесь и

Генетический алгоритм - один из самых популярных алгоритмов оптимизации. Как видите, он также имеет широкий спектр областей применения в машинном обучении. Области применения ограничены только вашим воображением. Теперь, когда вы знаете все, что нужно знать о генетическом алгоритме, вы можете эффективно использовать его для оптимизации своих моделей машинного обучения.

Вот путь к Jupyter Notebook

Первоначально опубликовано на www.tech-quantum.com 7 октября 2018 г.