经典模型WDCNN中的AdaBN复现

最近自己的故障分类论文完成的差不多了,决定抽点时间复现一下引用比较多的WDCNN。之前都是直接用别人的实验数据,没有仔细阅读过相关论文,更没有考虑过复现的问题。仔细阅读这篇论文后,查阅了网上的资料才发现复现的帖子很少,且大部分只对WDCNN复现,有些里还有明显的错误,于是决定自己整一下。

原作者用的是tensorflow,我也是,但其实目前用pytorch复现更容易。

1.首先是WDCNN的模型代码

def WDCNN():
    inputs1 = Input(shape=(2048, 1))
    x = Conv1D(filters=16, kernel_size=64,strides=16,padding='same')(inputs1)
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    x = MaxPooling1D(pool_size=2, strides=2)(x)

    x = Conv1D(filters=32, kernel_size=3, strides=1, padding='same')(x)
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    x = MaxPooling1D(pool_size=2, strides=2, padding='valid')(x)

    x = Conv1D(filters=64, kernel_size=3, strides=1, padding='same')(x)
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    x = MaxPooling1D(pool_size=2, strides=2)(x)

    x = Conv1D(filters=64, kernel_size=3, strides=1, padding='same')(x)
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    x = MaxPooling1D(pool_size=2, strides=2)(x)

    x = Conv1D(filters=64, kernel_size=3, strides=1, padding='valid')(x)
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    x = MaxPooling1D(pool_size=2, strides=2)(x)

    x = Flatten()(x)
    x = Dense(100)(x)
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    outputs = Dense(10, activation='softmax')(x)
    model = Model(inputs=inputs1, outputs=outputs)
    # model.summary()  # 打印模型结构
    return model

模型比较简单,可以根据图中的结构进行查看和调整。

[En]

The model is relatively simple, and you can view and adjust it according to the structure in the diagram.

经典模型WDCNN中的AdaBN复现

2.AdaBN算法原理及实现

复现WDCNN其实没啥难度,但是AdaBN还是很有说头的。简单来讲,这是BN的一个变种,首先还得对BN的机理多一点了解。我以前只管用,毕竟放到现在已经是一个常规配置项了,不理解一般也不影响使用,但是要用AdaBN的话就不能一知半解了。

大家应该都知道BN实际上就是对隐藏层的参数做批量归一化,而归一化就要用到训练集的数据分布信息,均值和方差。模型中BN模块是个特殊的存在, 它不参与反向传播,查看模型时,你会发现它是不可训练的。但不可训练并不意味着不进行变化,在训练阶段它依据每一组batch的相关参数进行调整,之所以不用整个训练集的均值和方差是为了优化模型的适应能力,也可以理解为泛化能力或鲁棒性。

以上过程是 model.fit过程中发生的,但是在 model.evaluate中就不用了。这时大家一般用测试集来获得准确率,这里的BN用的则是之前fit过程中得到的 训练集相关的全局均值和方差

如果训练集和测试集属于同一工况,或者同分布的数据集,那么这样就很合适。但是当我们做迁移学习时就不一样了,我们当然希望用测试集的均值和方差来进行 model.evaluate,毕竟测试集的数据信息是我们已有的信息,这种方法就是AdaBN。

因此,整个AdaBN过程分3步实现。

1.使用训练集进行model.fit。这一步和常规训练一样, 但是绝对不能把测试集当验证集进行,这是常识性错误。就像下面这样的,结果肯定准确率能提高, 毕竟相当于偷看了答案。

model.fit(X_train, Y_train,validation_data=(X_test, Y_test),epochs=30,batch_size=64)

正确的应该是这样,必须 使用验证集。这里我加入了早停机制、模拟褪火和保存最佳模型模块,确保模型能够有效收敛。

model.fit(trainX, trainy, epochs=epochs, batch_size=64, verbose=0, validation_data=(valX, valy),
              callbacks=[earlystopper, checkpointer,lr_reducer])

2.再次进行model.fit。这一步是最关键的,上一步我们相当于进行了正向传播和反向传播,并且保存了最佳模型的参数。这次fit中我们需要 使用训练集进行正向传播,确保BN中的参数更新为训练集相关的 这里如果使用pytorch的话据说非常简单,直接将BN层track_running_stats=True参数,把它改成False,这样在model.eval()时就是用目标域样本的均值和方差。但是tensorflow中我没有找到类似的,也是我个人学的比较浅。这里我使用另外一种方法代替, 首先锁定所有模型参数,只允许BN层的参数进行训练,因为BN的机制本身就不参与反向更新,因此训练完成后相当于将目标域测试集的参数保留在了BN中。此时再次保存模型参数, 相当于上一步中非BN层的参数+本步骤中BN层的参数组成的一个新的模型参数。

model.load_weights(path)    #载入模型参数
model.trainable = False    #锁定所有层参数
    for i in [2, 6, 10, 14, 16, 20]:    #只允许特定层更新
        model.layers[i].trainable = True

这一步使用model.fit时需要训练集和标签信息,此时训练集就是我们目标域的测试集, 标签信息从原理上来讲可以随意设置,因为除了BN所有参数都被锁定了,不会变化,而BN只受此时的训练数据影响

np.random.shuffle(valy)

 label_te = np.array([1 for i in range(0, 1400)])
 label_te = label_te.reshape([1400, 1])
 label_te = label_te.reshape(label_te.shape[0], 1)
 label_te = label_te.astype(int)
 label_te = case10.to_one_hot(label_te)

 model.fit(testX, label_te, epochs=epochs, batch_size=64, verbose=0,
              callbacks=[lr_reducer, earlystopper2, checkpointer2])

为了验证理论的正确性,我在这一步中使用了一个随机标签和一个1标签的类别。让我们看看结果会是什么。取5次后的平均值

[En]

In order to verify the correctness of the theory, I used a random label and a category of 1 tag in this step. Let’s see what the result is. Take the average value after 5 times

WDCNN Accuracy: 92.764% (+/-1.967)
WDCNN_ada Accuracy: 96.202% (+/-1.447)

经典模型WDCNN中的AdaBN复现

可以看出,效果确实很好,改善非常明显,与论文中的结果接近。

[En]

It can be seen that the effect is really very good, and the improvement is very obvious, which is close to the results in the paper.

这个方法的好处就是适用性比较强,和很多使用BN的模型都适配,在我的ShuffleNet模型上效果更好,稳定性也更好。

shu Accuracy: 96.148% (+/-0.896)
shu_ada Accuracy: 98.129% (+/-0.445)

3.TICNN的复现

我还顺便试了一下TICNN的一部分,实际上这两个模型很接近,TICNN主要就是比WDCNN多了dropout模块,但是我个人测试中发现效果和原作者有出入。这里可能还涉及到原论文中的一点错误,我记录下来供大家参考。首先我们看模型结构

经典模型WDCNN中的AdaBN复现

然而,作者在上面显然提到,第一卷积层的步长已改为8,我猜这是作者在绘图时的疏忽。以下是原文

[En]

However, the author obviously mentioned above that the step size of the first convolution layer has been changed to 8, which I guess is the author’s negligence in drawing. Here is the original text * *

经典模型WDCNN中的AdaBN复现

但有趣的是,许多人在繁殖时仍然使用16的步长。据估计,他们没有很好地阅读这份报纸。

[En]

But what is interesting is that many people still use the step length of 16 when they reproduce. It is estimated that they did not read the paper well.

TICNN结合AdaBN的效果差一些,只提升1-2%,我个人估计是dropout的原因,因为它会随机丢弃一些参数,导致模型数据的一些不稳定。

写作到此结束,欢迎批评指正+点赞收藏!谢谢!

[En]

This is the end of the writing, welcome to criticize and correct + like collection! Thank you!

Original: https://blog.csdn.net/weixin_50642818/article/details/125354408
Author: 北漂炼丹青年
Title: 经典模型WDCNN中的AdaBN复现

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/514634/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球