我在不利地训练resnet-50时遇到了一个奇怪的问题,我不确定这是一个逻辑错误,还是代码/库中的某个bug。我正在对抗性地训练一个从Keras加载的resnet-50,使用来自cleverhans的FastGradientMethod,并期望对抗性准确率至少提高90% (可能是99.x%)。训练算法、训练参数和攻击参数应该在代码中可见。问题是,正如标题中已经指出的那样,在第一个时期训练了39002个训练输入中的3000个之后,准确率停留在5%.(GermanTrafficSignRecognitionBenchmark,GTSRB)。
当训练没有和对抗损失函数时,精度在3000个样本后不会卡住,但在第一个时期继续上升> 0.95。
当用lenet-5,alexnet和vgg19替换网络时,代码按预期工作,并且实现了与非对抗性的categorical_corssentropy损失功能绝对相当的准确性。我还尝试了单独使用tf-cpu和不同版本的tensorflow来运行该过程,结果总是相同的。
ResNet-50获取代码:
def build_resnet50(num_classes, img_size):
from tensorflow.keras.applications import ResNet50
from tensorflow.keras import Model
from tensorflow.keras.layers import Dense, Flatten
resnet = ResNet50(weights='imagenet', include_top=False, input_shape=img_size)
x = Flatten(input_shape=resnet.output.shape)(resnet.output)
x = Dense(1024, activation='sigmoid')(x)
predictions = Dense(num_classes, activation='softmax', name='pred')(x)
model = Model(inputs=[resnet.input], outputs=[predictions])
return model
培训:
def lr_schedule(epoch):
# decreasing learning rate depending on epoch
return 0.001 * (0.1 ** int(epoch / 10))
def train_model(model, xtrain, ytrain, xtest, ytest, lr=0.001, batch_size=32,
epochs=10, result_folder=""):
from cleverhans.attacks import FastGradientMethod
from cleverhans.utils_keras import KerasModelWrapper
import tensorflow as tf
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.callbacks import LearningRateScheduler, ModelCheckpoint
sgd = SGD(lr=lr, decay=1e-6, momentum=0.9, nesterov=True)
model(model.input)
wrap = KerasModelWrapper(model)
sess = tf.compat.v1.keras.backend.get_session()
fgsm = FastGradientMethod(wrap, sess=sess)
fgsm_params = {'eps': 0.01,
'clip_min': 0.,
'clip_max': 1.}
loss = get_adversarial_loss(model, fgsm, fgsm_params)
model.compile(loss=loss, optimizer=sgd, metrics=['accuracy'])
model.fit(xtrain, ytrain,
batch_size=batch_size,
validation_data=(xtest, ytest),
epochs=epochs,
callbacks=[LearningRateScheduler(lr_schedule)])
损失函数:
def get_adversarial_loss(model, fgsm, fgsm_params):
def adv_loss(y, preds):
import tensorflow as tf
tf.keras.backend.set_learning_phase(False) #turn off dropout during input gradient calculation, to avoid unconnected gradients
# Cross-entropy on the legitimate examples
cross_ent = tf.keras.losses.categorical_crossentropy(y, preds)
# Generate adversarial examples
x_adv = fgsm.generate(model.input, **fgsm_params)
# Consider the attack to be constant
x_adv = tf.stop_gradient(x_adv)
# Cross-entropy on the adversarial examples
preds_adv = model(x_adv)
cross_ent_adv = tf.keras.losses.categorical_crossentropy(y, preds_adv)
tf.keras.backend.set_learning_phase(True) #turn back on
return 0.5 * cross_ent + 0.5 * cross_ent_adv
return adv_loss
使用的版本: tf+tf-gpu: 1.14.0 keras: 2.3.1 cleverhans:> 3.0.1 -从github拉取的最新版本
发布于 2020-05-07 19:44:26
这是我们在BatchNormalization上估计移动平均线的方式的副作用。
您使用的训练数据的均值和方差与用于训练ResNet50的数据集的均值和方差不同。由于BatchNormalization上的动量的默认值为0.99,因此只需10次迭代,它就不能足够快地收敛到移动均值和方差的正确值。当learning_phase为1时,这在训练期间并不明显,因为BN使用批次的均值/方差。然而,当我们将learning_phase设置为0时,在训练过程中学习到的不正确的均值/方差值会显著影响准确性。
您可以通过以下方法解决此问题:
将批处理的大小从32减少到16(以每个时期执行更多更新),并将时期的数量从10增加到250。这样,移动平均值和方差将收敛到正确的值。
的发展势头
保持迭代次数不变,但更改BatchNormalization层的动量,以更积极地更新滚动平均值和方差(不建议用于生产模型)。
在原始代码段中,在读取base_model和定义新图层之间添加以下代码:
# ....
base_model = ResNet50(weights='imagenet', include_top=False, input_shape=input_shape)
# PATCH MOMENTUM - START
import json
conf = json.loads(base_model.to_json())
for l in conf['config']['layers']:
if l['class_name'] == 'BatchNormalization':
l['config']['momentum'] = 0.5
m = Model.from_config(conf['config'])
for l in base_model.layers:
m.get_layer(l.name).set_weights(l.get_weights())
base_model = m
# PATCH MOMENTUM - END
x = base_model.output
# ....
我也建议你尝试另一个由我们的here提供的黑客攻击。
https://stackoverflow.com/questions/61076672
复制相似问题