使用进化算法实现对抗性示例生成器的效果不佳

时间:2019-05-13 03:42:23

标签: python tensorflow machine-learning keras neural-network

我正在尝试使用MAP-Elites进化策略和多项式变异算子(如在here在第2点定义的)来实现进化算法,如this论文中所述。我创建了三个不同的MNIST模型,并使用Keras API使用tensorflow == 2.0.0a对其进行了训练。这些模型运行良好(准确率均在95%左右)。

我对上述进化策略的理解是,我们创建了一个初始种群,然后每次迭代都会突变一个随机选择的样本。如果在突变之后,新标本的确定性高于先前为该类别选择的最佳标本,则我们将其视为最佳标本,并将其添加到总体中。预期的结果是,算法完成后,我们应该为每个类别都拥有一个样本,该样本设法以高确定性在该类别中进行分类。使用均匀分布创建图像的初始填充。

问题是我的模型始终将具有均匀分布的随机输入归为同一类,并且具有很高的确定性(即CNN模型始终将其归类为8)。因此,即使经过大量的初始种群和迭代次数(即1000个初始样本和20000次迭代)之后,我最终得到的大多数或所有样本都被归为同一类(确定性属于其他类别)。

将输入样本归一化为[0.0,1.0]范围。为了简化起见,所有的推理只限于底部描述的Dense模型(CNN和简化的LeNet5产生相似的结果)。

使用均值= 0.0和stddev = 0.3或均值= 0.5和stddev = 0.3的正态分布生成起始种群和0.3的突变机会(而不是本文中的0.1)会产生相似的结果。

我尝试使用(1,λ)进化策略仅针对一个类别(起始种群100、100代),并且比MAP-Elites实现的波纹管产生更好的结果(我可以为多个类别生成标本)。

我尝试不对模型数据进行归一化,并再次使用[0,255]范围对其进行训练,但结果几乎相同。我还尝试使用高斯变异算子而不是多项式,但是似乎没有太大的区别。

在训练似乎没有效果时关闭数据增强。

这是我写的实现。

def evolutionary_attack(model, population_size, generations_nmb, min=0.0, max=1.0, mutation_chance=0.1, mutation_power=15):
    population = [] #
    best_in_class = {} #dictionary of specimen performing best for given class

    for x in range(population_size):
        population.append(np.random.uniform(min, max, model.get_input_shape())) #initialize specimens with random values
        # population.append(np.random.normal(0.0, 0.3, model.get_input_shape())) #initialize specimens with random values

    for i in range(generations_nmb):
        current_specimen = random.choice(population) #choose specimen at random from the population
        mutated_specimen = mutate_specimen(current_specimen, min, max, mutation_chance, mutation_power)
        logits = model(tf.expand_dims(tf.convert_to_tensor(mutated_specimen, dtype=tf.float32), 0))
        certainties_per_class = tf.squeeze(logits).numpy()

        for cur_class in range(len(certainties_per_class)):
            if cur_class in best_in_class:
                _, best_certainty = best_in_class[cur_class]
                if certainties_per_class[cur_class] > best_certainty:
                    #if the new specimen performs better in given class make it a new best and add it to the population
                    best_in_class[cur_class] = (mutated_specimen, certainties_per_class[cur_class])
                    population.append(mutated_specimen)
            else:
                best_in_class[cur_class] = (mutated_specimen, certainties_per_class[cur_class]) #handles the case when there is no best specimen for the given class

def mutate_specimen(specimen, min, max, mutation_chance, mutation_power=15):
    specimen = np.copy(specimen)
    with np.nditer(specimen, op_flags=['readwrite']) as it:
        for old_val in it:
            if np.random.uniform() < mutation_chance:
                u = np.random.uniform()
                if u <= 0.5:
                    delta = ((2.0 * u) ** (1.0 / (mutation_power))) - 1.0
                    new_val = old_val + delta * (old_val - min)
                else:
                    delta = 1.0 - (2 * (1 - u))** (1 / (1 + mutation_power))
                    new_val = old_val + delta * (max - old_val)
                old_val[...] = new_val
    return np.clip(specimen, min, max)

在论文中,作者说他们能够获得50代后以> 99.99%的置信度分类的每个数字的标本。这与我得到的结果有很大的不同。看来我做错了什么,但我无法查明问题。我不确定这是代码中的小错误还是实现错误的原因。

我的模型是这样构造的

DenseModel(除最后一层外,所有层上都为S型激活函数)

input_1(InputLayer)[(None,28,28,1)] 0


展平(展平)(无,784)0


密集(密集)(无,784)615440


dense_1(密集)(无,800)628000


dense_2(密集)(无,800)640800


dense_3(密集)(无,10)8010

已使用Adam优化器对它进行了多个数据扩展训练。

编辑:我只是注意到突变后我没有剪切标本的值。如果我这样做,那么使用正态分布将产生与使用均匀分布相似的结果。我在发布的代码中解决了这个问题。愚蠢的错误

1 个答案:

答案 0 :(得分:1)

我认为您误解了MAP-Elites。您正在跟踪精英群体之外的仅追加人口,但是根据this reference,您应该只跟踪精英阶层。所以我认为选择当前标本的行应该是:

current_specimen, _ = random.choice(list(best_in_class.values()))

因此,MNIST的最大人口规模为10。我不是100%肯定这是您的主要问题,但它至少应该使算法更加贪婪,从而使搜索脱离最早的解决方案。

对MAP-Elites的修改

再想一想,我不确定为什么这种方法应该在具有直接像素参数的MNIST上起作用。仅靠随机突变就不可能产生不同的数字,尤其是在经过针对同一类的优化步骤而其他所有类都为空的情况下。

根据本文,您的实现似乎实际上在正确地完成了这一部分:

  

[...]并替换当前目标的任何目标(如果新目标)   个人对此目标适应性更高。

但是在最初的MAP-Elites中,目标是跟踪整个人口的单一全球适应性指标。某些单元可能保持空是因为没有溶液映射到该单元。该论文实际上为每个单元格跟踪一个不同的适应度指标。这本来应该作为MAP-Elites的改进形式更为突出地说明。通过此修改,似乎可行,但允许空单元格不再有意义。