轴承故障分类方法之CNN+SVM和ELM

一直想写这个方法,CNN+SVM是我一开始学习的时候想复现的,结果学了很久才达到目标。主要还是太急于求成了,而且现成的资料很难查到,等对CNN和SVM模型以及训练方法有了一定了解以后,我才真正复现。但是实际上这个方法效果一般,只是给大家提供一种思路而已。

0.相关原理

大家都知道CNN是通过梯度下降法,不断正向加反向传播来实现参数优化的,而SVM则更像是一次性的方法,只能正向传播,并不能同样进行反向传播,极限学习ELM也是一样的。因此,二者不能同步,CNN+SVM是无法直接进行训练的,这是必须首先认识到的一点。

因此CNN+SVM的典型过程就是CNN训练、保存参数、载入参数并输出特征值、再次训练加测试这几个步骤。

1.CNN训练和保存参数

这个过程比较常规,以普通1DCNN模型为例,我们首先进行训练,而后保存模型参数:

def CNN_1D():
    inputs1 = Input(shape=(2048, 1))
    conv1 = Conv1D(filters=16, kernel_size=6, strides=2)(inputs1)
    BN1 = BatchNormalization()(conv1)
    act1 = Activation('relu')(BN1)
    pool1 = MaxPooling1D(pool_size=2, strides=2)(act1)
    conv4 = Conv1D(filters=24, kernel_size=3, padding='same')(pool1)
    BN2 = BatchNormalization()(conv4)
    act2 = Activation('relu')(BN2)
    pool2 = MaxPooling1D(pool_size=2, strides=2)(act2)
    conv6 = Conv1D(filters=36, kernel_size=3, padding='same',
                   activation='relu')(pool2)
    BN3 = BatchNormalization()(conv6)
    act3 = Activation('relu')(BN3)
    pool3 = MaxPooling1D(pool_size=2, strides=2)(act3)
    flat1 = Flatten()(pool3)
    dense1 = Dense(100)(flat1)
    BN4 = BatchNormalization()(dense1)
    # drop1 = Dropout(0.4)(BN4)
    outputs = Dense(10, activation='softmax')(BN4)
    model = Model(inputs=inputs1, outputs=outputs)
    return model

def model_evaluate_one(base_data1, base_model, path, save_name,epochs=30,rate=0.001): 
    trainX, trainy, valX, valy, testX, testy = base_data1
    model = base_model
    model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
                  optimizer=tf.keras.optimizers.Adam(lr=rate),
                  metrics=['accuracy'])

    checkpoint_save_path = path + save_name + ".h5"
    lr_reducer = ReduceLROnPlateau(monitor='val_loss', factor=0.7, patience=5,
                                   mode='min', min_lr=1e-20)
    checkpointer = tf.keras.callbacks.ModelCheckpoint(
        filepath=checkpoint_save_path, monitor='val_loss', verbose=0, save_best_only=True, save_weights_only=True)
    model.fit(trainX, trainy, epochs=epochs, batch_size=128, verbose=0, validation_data=(valX, valy),
              callbacks=[checkpointer,lr_reducer])

    model.load_weights(checkpoint_save_path)
    _,accuracy1 = model.evaluate(testX, testy, batch_size=128, verbose=0)
    return accuracy1 * 100

这里保存模型是为了下一步载入重构

2.载入参数并输出特征值

CNN+SVM其实本质上就是将CNN模型里的全连接层用SVM代替,原始CNN部分的结构起到处理数据集的作用。因此这一步我们首先载入训练好的模型,将CNN模型从flat1 = Flatten()(pool3)处截断,输入训练数据,输出特征值作为SVM的输入。

svm_model = Model(inputs=model.input, outputs=model.get_layer(index=13).output) #截取CNN的一部分
feat_train = svm_model.predict(trainX)  #通过CNN的前半部分输出特征值
feat_train = feat_train.reshape(feat_train.shape[0], -1)
feat_train = case10.BN(feat_train)  #将特征值0-1标准化
trainy_svm = np.argmax(trainy, axis=1)  #将one-hot标签改为常规模式

3.再次训练加测试

新模型构建完成后还需要进行训练,使得SVM部分的参数通过正向传播过程变为最优,而后输入测试数据得出结果。

model_svm = svm.SVC(C=0.9, kernel='rbf')
model_svm.fit(feat_train, trainy_svm)    #训练SVM
feat_test = svm_model.predict(testX)  #通过CNN的前半部分输出特征值
feat_test = feat_test.reshape(feat_test.shape[0], -1)
feat_test = case10.BN(feat_test)  #将特征值0-1标准化
testy_svm = np.argmax(testy, axis=1)  #将one-hot标签改为常规模式
accuracy2 = model_svm.score(feat_test, testy_svm)

运行2次我们看看结果如何:

>第1次 cnn: 100.00 cnn+svm: 100.00 耗时72.9 sec
>第2次 cnn: 100.00 cnn+svm: 100.00 耗时73.7 sec
总用时:146.7sec 
训练平均用时: 73.3sec 
Accuracy1: 100.00% (+/-0.00) Accuracy2: 100.00% (+/-0.00)

结果比较好,但是看不出差距。确实单工况数据集就是这样,只有在三种工况交叉测试时才能看出差别,看过我之前文章的小伙伴们应该不难理解。

下一篇我计划把ELM的内容加入进来,然后在多工况请条件下让大家看看这种方法到底效果如何。

你可能感兴趣的:(故障诊断,西储大学,分类,cnn,cnn+svm)