You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 08:05:13