轴承故障诊断是工业设备健康管理的重要环节。传统的振动信号分析方法依赖人工特征提取,而深度学习技术能够自动学习信号特征,显著提升诊断效率。本文将带您从零开始,使用TensorFlow 1.x和Keras构建一个完整的1D-CNN模型,处理西储大学的.mat格式振动数据。
对于TensorFlow 1.x项目,环境配置需要特别注意版本兼容性。推荐使用conda创建隔离的Python环境:
bash复制conda create -n tf1_env python=3.7
conda activate tf1_env
pip install tensorflow==1.15.0 keras==2.3.1 h5py==2.10.0 scipy==1.2.1
关键库版本说明:
| 库名称 | 推荐版本 | 作用说明 |
|---|---|---|
| TensorFlow | 1.15.0 | 深度学习框架基础 |
| Keras | 2.3.1 | 高层API接口 |
| h5py | 2.10.0 | 处理.mat格式数据 |
| scipy | 1.2.1 | 科学计算与.mat文件读取 |
注意:TensorFlow 1.x与2.x在API设计上有显著差异,本文所有代码均基于1.x版本实现。
西储大学轴承数据集包含多种故障状态下的振动信号,存储为.mat格式。我们先了解数据结构:
python复制from scipy.io import loadmat
import numpy as np
def load_mat_file(filepath):
"""加载单个.mat文件并提取振动信号"""
data = loadmat(filepath)
for key in data.keys():
if 'DE' in key: # DE表示驱动端振动数据
return data[key].ravel()
raise ValueError("未找到振动信号数据")
典型的数据结构特征:
原始振动信号通常很长,需要切分为适合CNN处理的片段:
python复制def slice_signal(signal, window_size=864, step=28):
"""将长信号切分为固定长度的片段"""
slices = []
for start in range(0, len(signal)-window_size, step):
slices.append(signal[start:start+window_size])
return np.array(slices)
数据增强技巧:
采用分层抽样保证各类别比例一致:
python复制from sklearn.preprocessing import OneHotEncoder
from sklearn.model_selection import StratifiedShuffleSplit
def prepare_labels(filenames):
"""根据文件名生成类别标签"""
labels = []
for name in filenames:
if 'Normal' in name: labels.append(0)
elif 'IR' in name: labels.append(1) # 内圈故障
elif 'OR' in name: labels.append(2) # 外圈故障
elif 'Ball' in name: labels.append(3) # 滚动体故障
return np.array(labels).reshape(-1, 1)
# One-hot编码
encoder = OneHotEncoder(categories='auto')
one_hot_labels = encoder.fit_transform(labels).toarray()
数据集划分比例建议:
| 数据集 | 比例 | 作用 |
|---|---|---|
| 训练集 | 60% | 模型参数训练 |
| 验证集 | 20% | 超参数调优 |
| 测试集 | 20% | 最终性能评估 |
对于振动信号这种一维时序数据,1D卷积能有效捕捉局部特征:
python复制from keras.layers import Conv1D, BatchNormalization, MaxPooling1D
def build_conv_block(input_layer, filters=64, kernel_size=3):
"""构建卷积块:Conv1D + BatchNorm + ReLU + MaxPooling"""
x = Conv1D(filters, kernel_size, padding='same')(input_layer)
x = BatchNormalization()(x)
x = Activation('relu')(x)
x = MaxPooling1D(pool_size=2)(x)
return x
关键参数选择依据:
构建包含三个卷积块的深层网络:
python复制from keras.models import Model
from keras.layers import Input, Dense, Flatten, Dropout
def build_model(input_shape=(864,1)):
"""构建完整CNN模型"""
inputs = Input(shape=input_shape)
# 卷积模块
x = build_conv_block(inputs, filters=64)
x = build_conv_block(x, filters=128)
x = build_conv_block(x, filters=256)
# 分类头
x = Flatten()(x)
x = Dense(128, activation='relu')(x)
x = Dropout(0.5)(x)
outputs = Dense(4, activation='softmax')(x) # 4类故障
return Model(inputs, outputs)
网络结构可视化:
code复制Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) (None, 864, 1) 0
_________________________________________________________________
conv1d_1 (Conv1D) (None, 864, 64) 256
_________________________________________________________________
batch_normalization_1 (Batch (None, 864, 64) 256
_________________________________________________________________
max_pooling1d_1 (MaxPooling1 (None, 432, 64) 0
_________________________________________________________________
conv1d_2 (Conv1D) (None, 432, 128) 24704
_________________________________________________________________
... (中间层省略) ...
_________________________________________________________________
dense_2 (Dense) (None, 4) 516
=================================================================
Total params: 210,180
Trainable params: 209,924
Non-trainable params: 256
使用动态学习率和模型检查点:
python复制from keras.callbacks import ModelCheckpoint, ReduceLROnPlateau
def get_callbacks():
"""配置训练回调函数"""
checkpoint = ModelCheckpoint(
'best_model.h5',
monitor='val_accuracy',
save_best_only=True,
mode='max'
)
lr_reducer = ReduceLROnPlateau(
monitor='val_loss',
factor=0.5,
patience=5,
verbose=1
)
return [checkpoint, lr_reducer]
优化器参数设置:
python复制from keras.optimizers import Adam
model.compile(
optimizer=Adam(lr=0.001),
loss='categorical_crossentropy',
metrics=['accuracy']
)
启动训练并可视化结果:
python复制history = model.fit(
x_train, y_train,
batch_size=64,
epochs=100,
validation_data=(x_val, y_val),
callbacks=get_callbacks()
)
# 绘制训练曲线
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(history.history['accuracy'], label='Train')
plt.plot(history.history['val_accuracy'], label='Validation')
plt.title('Accuracy over epochs')
plt.legend()
plt.subplot(1, 2, 2)
plt.plot(history.history['loss'], label='Train')
plt.plot(history.history['val_loss'], label='Validation')
plt.title('Loss over epochs')
plt.legend()
典型训练曲线分析:
问题1:梯度消失/爆炸
问题2:类别不平衡
python复制from sklearn.utils.class_weight import compute_class_weight
class_weights = compute_class_weight('balanced', np.unique(labels), labels)
class_weights = dict(enumerate(class_weights))
问题3:模型收敛慢
python复制def warmup_scheduler(epoch, lr):
if epoch < 10:
return lr * (epoch + 1) / 10
return lr
除了准确率,还应关注:
python复制from sklearn.metrics import classification_report
y_pred = model.predict(x_test)
y_pred_classes = np.argmax(y_pred, axis=1)
y_true = np.argmax(y_test, axis=1)
print(classification_report(
y_true, y_pred_classes,
target_names=['Normal', 'IR', 'OR', 'Ball']
))
关键指标解读:
为工业部署考虑,可以进行模型压缩:
python复制from keras import backend as K
def prune_weights(model, pruning_percent=0.2):
"""权重剪枝"""
weights = model.get_weights()
for i in range(len(weights)):
if len(weights[i].shape) > 1: # 只剪枝非偏置项
threshold = np.percentile(np.abs(weights[i]), pruning_percent*100)
mask = np.abs(weights[i]) > threshold
weights[i] = weights[i] * mask
model.set_weights(weights)
其他优化手段:
在工业场景中部署时:
python复制def detect_anomaly(signal, model, threshold=0.9):
"""检测未知故障类型"""
prob = model.predict(np.expand_dims(signal, axis=0))
if np.max(prob) < threshold:
return "Unknown Fault"
return "Known Fault"