如何优化CNN回归模型提升测力台数据预测拟合度?
优化CNN回归模型提升测力台数据预测拟合度
问题背景
使用智能鞋垫数据预测测力台数据,已搭建CNN回归模型但预测结果与真实数据拟合度不足。数据情况如下:
- 测力台数据:形状为
(2050,2),示例值为[4.06604 -63.9543] - 智能鞋垫原始数据:形状为
(2050,89),已转换为(2050,19,9)的图像格式
当前可运行模型代码:
import math import numpy as np import pandas as pd import tensorflow as tf import seaborn as sns import matplotlib.pyplot as plt from sklearn.preprocessing import MinMaxScaler from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error, r2_score from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Conv2D, MaxPooling2D, Conv1D, MaxPooling1D, Flatten, Dropout from tensorflow.keras.losses import sparse_categorical_crossentropy from tensorflow.keras.optimizers import Adam %matplotlib inline ## Load Data Insole = pd.read_csv('1119_Rwalk40s1_list.txt', header=None, low_memory=False) SIData = np.asarray(Insole) df = pd.read_csv('1119_Rwalk40s1.csv', low_memory=False) columns = ['Fx','Fz'] selected_df = df[columns] FCDatas = selected_df[:2050] ## End Load Data # Transform Data to Picture SIData2D = SIData def list2matR(SIData2D): t=np.zeros((19,6)) rows = 18 cols = 5 col4=[10,9,8,7,6,5,4,3,2] col4idx=0 col5=[8,7,6,5,4,3] col5idx=0 for idx, val in enumerate(SIData2D): if idx <=56: t[rows-(idx%19)][math.floor(idx/19)]=val elif idx<=73: if (idx%19!=0 or idx%19!=18): # print(rows-(idx%19)-1) # print(math.floor(idx/19)) t[rows-(idx%19)-1][math.floor(idx/19)]=val elif (idx<=82 and col4idx<9): # print(val) t[col4[col4idx]][4]=val col4idx+=1 elif col5idx<6: # print(val) t[col5[col5idx]][5]=val col5idx+=1 return t def lplusr(R): z = np.zeros((19,3)) return np.concatenate((z,R), axis=1) def formPic(SIData2D): return lplusr(list2matR(SIData2D)) # data preprocess to train r1 = SIData train = [] for i in range(0,len(r1)): train.append(formPic(r1[i])) SmartInsole = np.array(train[:2050]) FCData = np.array(FCDatas) xX = SmartInsole yY = FCData scalers = {} for i in range(xX.shape[1]): scalers[i] = MinMaxScaler(feature_range=(0, 1)) xX[:, i, :] = scalers[i].fit_transform(xX[:, i, :]) scaler_y = MinMaxScaler(feature_range=(0, 1)) scaler_y.fit(yY) yscale = scaler_y.transform(yY) X_train, X_test, y_train, y_test = train_test_split(xX, yscale, test_size=0.25, random_state=2) img_width, img_height, img_num_channels = 19, 9, 1 input_shape = (img_width, img_height, img_num_channels) model = Sequential() model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=input_shape)) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(64, kernel_size=(3, 3), activation='relu')) model.add(MaxPooling2D(pool_size=(1, 1))) model.add(Flatten()) model.add(Dense(64, activation='relu')) model.add(Dense(32, activation='relu')) model.add(Dense(16, activation='relu')) model.add(Dense(2, activation='sigmoid')) model.compile(loss='huber', optimizer='adam', metrics=['mse']) history = model.fit(X_train, y_train, batch_size=64, epochs=50, validation_data=(X_test, y_test), verbose=2,shuffle=True) ypred = model.predict(xX) plt.figure() plt.plot(history.history['loss']) plt.plot(history.history['val_loss']) plt.title('Model Loss') plt.ylabel('Loss') plt.xlabel('epoch') plt.legend(['train', 'validation'], loc='upper right') # plt.show() plt.savefig('Loss Result.png') print('MSE: ',mean_squared_error(yscale, ypred)) print('RMSE: ',math.sqrt(mean_squared_error(yscale, ypred))) print('Coefficient of determination (r2 Score): ', r2_score(yscale, ypred)) ypred = scaler_y.inverse_transform(ypred) yscale = scaler_y.inverse_transform(yscale) x=[] colors=['red','green','brown','teal','gray','black','maroon','orange','purple'] colors2=['green','red','orange','black','maroon','teal','blue','gray','brown'] for i in range(0,2050): x.append(i) for i in range(0,2): plt.figure(figsize=(15,6)) # plt.figure() plt.plot(x,yscale[0:2050,i], color=colors[i]) plt.plot(x,ypred[0:2050,i], markerfacecolor='none',color=colors2[i]) plt.title('Result for ResNet Regression') plt.ylabel('Y value') plt.xlabel('Instance') plt.legend(['Real value', 'Predicted Value'], loc='upper right') plt.savefig('Regression Result.png'[i]) plt.show()
优化方案
1. 修正输出层激活函数
回归任务中,sigmoid会将输出限制在(0,1)区间,严重限制模型拟合能力,替换为linear激活函数:
model.add(Dense(2, activation='linear'))
2. 调整网络结构与容量
- 优化卷积与池化策略:移除无效的
MaxPooling2D(pool_size=(1,1)),增加卷积层深度提取更复杂特征:
model = Sequential() model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=input_shape, padding='same')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(64, kernel_size=(3, 3), activation='relu', padding='same')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(128, kernel_size=(3, 3), activation='relu', padding='same')) model.add(MaxPooling2D(pool_size=(2, 2)))
- 简化全连接层:减少冗余层数,加入Dropout防止过拟合:
model.add(Flatten()) model.add(Dense(128, activation='relu')) model.add(Dropout(0.3)) model.add(Dense(64, activation='relu')) model.add(Dense(2, activation='linear'))
3. 统一数据预处理策略
当前对输入数据逐行归一化会导致特征分布不一致,改为全局归一化:
# 替换原xX归一化代码 scaler_x = MinMaxScaler(feature_range=(0,1)) # 展平后归一化再恢复形状 xX_flat = xX.reshape(xX.shape[0], -1) xX_flat_scaled = scaler_x.fit_transform(xX_flat) xX = xX_flat_scaled.reshape(xX.shape[0], 19, 9)
同时需严格确认智能鞋垫数据与测力台数据的时序对齐,避免样本错位。
4. 调整训练参数
- 增加训练轮次并加入早停:提升epochs到200,用EarlyStopping防止过拟合并保留最优权重:
from tensorflow.keras.callbacks import EarlyStopping early_stop = EarlyStopping(monitor='val_loss', patience=15, restore_best_weights=True) history = model.fit(X_train, y_train, batch_size=64, epochs=200, validation_data=(X_test, y_test), verbose=2, shuffle=True, callbacks=[early_stop])
- 优化学习率:调整Adam优化器的学习率,避免收敛过快或过慢:
model.compile(loss='huber', optimizer=Adam(learning_rate=0.0001), metrics=['mse'])
5. 添加正则化约束
- 加入Dropout层:在卷积或全连接层后添加Dropout,比例设为0.2-0.5:
model.add(Conv2D(64, kernel_size=(3, 3), activation='relu')) model.add(Dropout(0.3)) model.add(MaxPooling2D(pool_size=(2, 2)))
- 添加L2正则化:约束权重大小,防止模型过拟合:
from tensorflow.keras.regularizers import l2 model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=input_shape, kernel_regularizer=l2(0.001)))
6. 尝试混合模型结构
考虑到数据兼具空间(鞋垫压力分布)与时序特性,可尝试CNN+LSTM混合结构捕捉时序关联:
# 转换为时序输入格式 xX_seq = xX.reshape(xX.shape[0], 19, 9) model = Sequential() model.add(Conv1D(64, kernel_size=3, activation='relu', input_shape=(19,9))) model.add(MaxPooling1D(pool_size=2)) model.add(LSTM(64, return_sequences=True)) model.add(LSTM(32)) model.add(Dense(2, activation='linear'))
内容的提问来源于stack exchange,提问作者stack offer
相关产品推荐
相关产品推荐

