遗传算法(Genetic Algorithm)之deap学习笔记(六):多层感知机MLP

这篇博客将演化一个简单 MLP 的权重解决“异或”问题 (XOR)。 众所周知,MLP 中需要一个隐藏层来解决这个问题,因为它不是线性可分的。 XOR 问题接受两个二进制输入,如果其中一个是 1,则输出 1,但不是两个都是

Python有专门用于生成神经网络的软件包,例如 Tensorflow 和 Pytorch。 然而,为了简单起见,我们将实现我们自己的基本 MLP,只有一个隐藏层。

定义神经网络

首先,先定义MLP函数

import numpy as np
import math

class MLP(object):
    def __init__(self, numInput, numHidden, numOutput):
        self.fitness = 0
        self.numInput = numInput + 1 # 添加bias节点到数入
        self.numHidden = numHidden
        self.numOutput = numOutput

        self.wh = np.random.randn(self.numHidden, self.numInput) 
        self.wo = np.random.randn(self.numOutput, self.numHidden)

        self.ReLU = lambda x : max(0,x)

    def sigmoid(self,x):
        try:
            ans = (1 / (1 + math.exp(-x)))
        except OverflowError:
            ans = float('inf')
        return ans

接下来我们定义网络的前馈函数。 为此,我们只需将输入数组的点积与该输入的权重计算到下一层节点。 然后我们通过隐藏层中的 ReLU 函数和最后一层中的 sigmoid 运行这些加权和。 这使得它类似于非线性回归问题。

class MLP(MLP):
    def feedForward(self, inputs):
        inputsBias = inputs[:]
        inputsBias.insert(len(inputs),1)                 # 添加bias
        h1 = np.dot(self.wh, inputsBias)                 # 传输至隐藏层
        h1 = [self.ReLU(x) for x in h1]              # 激活隐藏层
        output = np.dot(self.wo, h1)                 # 传输至输出层
        output = [self.sigmoid(x) for x in output]   # 激活输出层
        return output

接下来我们定义允许遗传算法获取和设置权重的函数作为一个简单的一维列表。 这意味着我们可以只使用内置运算符,而不必担心定义我们自己的运算符来处理多维数组。

class MLP(MLP):
    
    def getWeightsLinear(self):
        flat_wh = list(self.wh.flatten())
        flat_wo = list(self.wo.flatten())
        return( flat_wh + flat_wo )

    def setWeightsLinear(self, Wgenome):
        numWeights_IH = self.numHidden * (self.numInput)
        self.wh = np.array(Wgenome[:numWeights_IH])
        self.wh = self.wh.reshape((self.numHidden, self.numInput))
        self.wo = np.array(Wgenome[numWeights_IH:])
        self.wo = self.wo.reshape((self.numOutput, self.numHidden))

这里我们将创建一个具有 2 个输入、3 个隐藏节点(此处为单个隐藏层)和 1 个输出的多层感知器。

myNet = MLP(2,3,1)

a = myNet.getWeightsLinear()

它接受一个大小为 2 的列表,并给出一个列表作为输出,列表中的每个元素都是输出节点(这里我们只有 1 个)。

inputs = [0,1]

outcome = myNet.feedForward(inputs)

由于 sigmoid 函数,结果将介于 0 和 1 之间。 为了制作这个二进制文件,我们可以添加一个阶跃函数。

print(outcome)
# [0.5431873319595386]

int(outcome[0] > 0.5)

遗传算法

一种方法可能是创建大量神经网络。 但是,这可能会很慢(并且涉及使用 copy.deepcopy)并且不允许使用 DEAP 的内置运算符。

相反,我们将演化出一组平面列表,代表神经网络权重。 我们只需要实例化一个神经网络来评估这些权重的适合度。

import random

from deap import base
from deap import creator
from deap import tools

numInputNodes = 2 + 1
numHiddenNodes = 3
numOutputNodes = 1

IND_SIZE = (numInputNodes * numHiddenNodes) + (numHiddenNodes * numOutputNodes)

# 以下代码解释可以看第一篇文章
creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
creator.create("Individual", list, fitness=creator.FitnessMin)

toolbox = base.Toolbox()
toolbox.register("attr_float", random.uniform, -1, 1)
toolbox.register("individual", tools.initRepeat, creator.Individual,
                 toolbox.attr_float, n=IND_SIZE)

def evaluate(indiv, myNet):
    fitness = 0
    myNet.setWeightsLinear(indiv)
    output = myNet.feedForward([0,0])
    fitness += abs( 0 - output[0] ) 
    output = myNet.feedForward([0,1])
    fitness += abs( 1 - output[0] ) 
    output = myNet.feedForward([1,0])
    fitness += abs( 1 - output[0] ) 
    output = myNet.feedForward([1,1])
    fitness += abs( 0 - output[0] ) 
    return fitness,

toolbox.register("evaluate", evaluate)
toolbox.register("select", tools.selTournament, tournsize=3)

toolbox.register("mutate", tools.mutGaussian, mu=0.0, sigma=0.5, indpb=0.1)

toolbox.register("population", tools.initRepeat, list, toolbox.individual)

stats = tools.Statistics(key=lambda ind: ind.fitness.values)
stats.register("avg", np.mean)
stats.register("std", np.std)
stats.register("min", np.min)
stats.register("max", np.max)

logbook = tools.Logbook()

pop = toolbox.population(n=500)

fitnesses = [toolbox.evaluate(indiv, myNet) for indiv in pop]
for ind, fit in zip(pop, fitnesses):
    ind.fitness.values = fit

NGEN, CXPROB = 200, 0.0

for g in range(NGEN):
    print("-- Generation %i --" % g)
      
    offspring = toolbox.select(pop, len(pop))
    offspring = list(map(toolbox.clone, offspring))


    for mutant in offspring:
        toolbox.mutate(mutant)
        del mutant.fitness.values
                         
    invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
    fitnesses = [toolbox.evaluate(indiv, myNet) for indiv in invalid_ind]
    for ind, fit in zip(invalid_ind, fitnesses):
         ind.fitness.values = fit

    pop[:] = offspring
    record = stats.compile(pop)
    logbook.record(gen=g, **record)

快速检查算法

logbook.header = "gen", "avg", "evals", "std", "min", "max"

import matplotlib.pyplot as plt
%matplotlib inline
gen = logbook.select("gen")
avgs = logbook.select("avg")
stds = logbook.select("std")

plt.rc('axes', labelsize=14)
plt.rc('xtick', labelsize=14)
plt.rc('ytick', labelsize=14) 
plt.rc('legend', fontsize=14)

fig, ax1 = plt.subplots()
#line1 = ax1.plot(gen, avgs)
line1 = ax1.errorbar(gen, avgs, yerr=stds, errorevery=2)
ax1.set_xlabel("Generation")
ax1.set_ylabel("Mean Fitness")

测试结果

indiv1 = tools.selBest(pop, 1)[0]
myNet.setWeightsLinear(indiv1)

outcome = myNet.feedForward([0,0])
int(outcome[0] > 0.5)
# 0

outcome = myNet.feedForward([0,1])
int(outcome[0] > 0.5)
# 1

outcome = myNet.feedForward([1,0])
int(outcome[0] > 0.5)
# 1

outcome = myNet.feedForward([1,1])
int(outcome[0] > 0.5)
# 0

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值