1. 数据预处理(PyTorch版)
import numpy as np
import torch
from torch.utils.data import Dataset, DataLoader
from sklearn.preprocessing import RobustScaler
import pandas as pd
import numpy as np
# 数据参数
WINDOW_SIZE = 60 # 滑动窗口大小
BATCH_SIZE = 64 # 批处理大小
class SensorDataset(Dataset):
"""自定义数据集类,处理滑动窗口分割"""
def __init__(self, data, window_size):
self.data = torch.FloatTensor(data) # 原始形状:(12000, 18)
self.window_size = window_size
def __len__(self):
return len(self.data) - self.window_size
def __getitem__(self, idx):
# 返回形状:(window_size, 18)
return self.data[idx:idx+self.window_size]
# 数据加载与预处理流程
def prepare_data(file_path):
# 1.1 加载原始数据
df = pd.read_csv(file_path)
# 填充缺失值 (如果需要)
df.fillna(df.mean(), inplace=True) # 使用均值填充,你也可以选择其他策略
extracted_data = df.values # 转换为numpy
raw_data=extracted_data[:12000, 1:19]
#raw_data = np.loadtxt(raw_data1, delimiter=',', encoding='utf-8') # 假设CSV格式
# 1.2 缺失值处理(用前后均值填充)
for col in range(raw_data.shape[1]):
col_data = raw_data[:, col]
nan_mask = np.isnan(col_data)
col_data[nan_mask] = np.mean(col_data[~nan_mask])
raw_data[:, col] = col_data
# 1.3 标准化
scaler = RobustScaler()
scaled_data = scaler.fit_transform(raw_data) # 形状保持(12000,18)
# 1.4 创建数据集
dataset = SensorDataset(scaled_data, WINDOW_SIZE)
print("Dataset length:", len(dataset))
dataloader = DataLoader(dataset, batch_size=BATCH_SIZE, shuffle=True)
for batch in dataloader:
print("Batch shape:", batch.shape)
#print("Batch data:", batch) # 如果batch较小,可以打印batch内容,否则不建议打印,会刷屏
break # 打印第一个batch后退出循环,如果需要遍历所有batch,去掉break即可
print("Scaled data shape:", scaled_data.shape)
print("Scaler center:", scaler.center_)
print("Scaler scale:", scaler.scale_)
return dataloader, scaler
# 使用示例
file_path1=r"E:\gxy\gxy\D\teach\footbed\Data processing\20250121.csv"
train_loader, scaler = prepare_data(file_path1)
代码解释:
这段代码主要用于加载、预处理和准备传感器数据,以便用于机器学习模型的训练。它定义了一个自定义数据集类
SensorDataset
和一个数据准备函数prepare_data
。下面是对代码的详细解释以及如何显示输出结果的方法:代码解释
导入库:
Pythonimport numpy as np import torch from torch.utils.data import Dataset, DataLoader from sklearn.preprocessing import RobustScaler import pandas as pd
导入了 NumPy (用于数值计算)、PyTorch (用于深度学习)、scikit-learn (用于数据预处理) 和 Pandas (用于数据处理) 等库。
数据参数:
PythonWINDOW_SIZE = 60 # 滑动窗口大小 BATCH_SIZE = 64 # 批处理大小
定义了滑动窗口大小和批处理大小。
Python
SensorDataset
类:class SensorDataset(Dataset): def __init__(self, data, window_size): self.data = torch.FloatTensor(data) # 原始形状:(12000, 18) self.window_size = window_size def __len__(self): return len(self.data) - self.window_size def __getitem__(self, idx): return self.data[idx:idx+self.window_size] # 返回形状:(window_size, 18)
- 这是一个自定义的数据集类,用于将原始数据分割成滑动窗口。
__init__
方法用于初始化数据集,将数据转换为 PyTorch 张量并存储窗口大小。__len__
方法返回数据集的长度,即可以创建的窗口数量。__getitem__
方法返回指定索引的窗口数据。Python
prepare_data
函数:def prepare_data(file_path): df = pd.read_csv(file_path) df.fillna(df.mean(), inplace=True) raw_data = df.values for col in range(raw_data.shape[1]): col_data = raw_data[:, col] nan_mask = np.isnan(col_data) col_data[nan_mask] = np.mean(col_data[~nan_mask]) raw_data[:, col] = col_data scaler = RobustScaler() scaled_data = scaler.fit_transform(raw_data) dataset = SensorDataset(scaled_data, WINDOW_SIZE) dataloader = DataLoader(dataset, batch_size=BATCH_SIZE, shuffle=True) return dataloader, scaler
- 该函数用于加载和预处理数据。
- 首先使用 Pandas 读取 CSV 文件。
- 然后填充缺失值(使用列均值)。
- 接着使用
RobustScaler
进行标准化。- 最后创建
SensorDataset
和DataLoader
。使用示例:
Pythonfile_path1=r"E:\gxy\gxy\D\teach\footbed\Data processing\20250121.csv" train_loader, scaler = prepare_data(file_path1)
调用
prepare_data
函数加载和预处理数据。如何显示输出结果
要在代码中显示输出结果,可以使用
打印数据集长度:
Pythondataset = SensorDataset(scaled_data, WINDOW_SIZE) print("Dataset length:", len(dataset))
打印dataloader中的数据:
Pythonfor batch in train_loader: print("Batch shape:", batch.shape) #print("Batch data:", batch) # 如果batch较小,可以打印batch内容,否则不建议打印,会刷屏 break # 打印第一个batch后退出循环,如果需要遍历所有batch,去掉break即可
打印预处理后的数据形状:
Pythonprint("Scaled data shape:", scaled_data.shape)
打印一个batch的数据:
Pythonfor batch in train_loader: print("First batch:", batch.shape) print(batch[0]) # 打印第一个batch的第一个数据 break
打印scaler参数:
Pythonprint("Scaler center:", scaler.center_) print("Scaler scale:", scaler.scale_)
修改后的代码示例 (包含打印语句):
Pythonimport numpy as np import torch from torch.utils.data import Dataset, DataLoader from sklearn.preprocessing import RobustScaler import pandas as pd # ... (SensorDataset 类定义) def prepare_data(file_path): # ... (数据加载和预处理) dataset = SensorDataset(scaled_data, WINDOW_SIZE) print("Dataset length:", len(dataset)) dataloader = DataLoader(dataset, batch_size=BATCH_SIZE, shuffle=True) for batch in dataloader: print("Batch shape:", batch.shape) #print("Batch data:", batch) # 如果batch较小,可以打印batch内容,否则不建议打印,会刷屏 break # 打印第一个batch后退出循环,如果需要遍历所有batch,去掉break即可 print("Scaled data shape:", scaled_data.shape) print("Scaler center:", scaler.center_) print("Scaler scale:", scaler.scale_) return dataloader, scaler # ... (使用示例)
通过在代码中添加这些
显示结果:
Dataset length: 11940 Batch shape: torch.Size([64, 60, 18]) Scaled data shape: (12000, 18) Scaler center: [ 20.9 5.83 7.26 17.16 10.56 76.56 63.69 24.64 17.49 11.66 7.15 25.41 8.25 78.32 68.42 29.59 653.73 746.35] Scaler scale: [ 246.73 147.29 100.54 78.43 38.06 174.13 146.74 58.52 189.2 130.57 107.6075 125.4 27.5 195.03 186.12 74.69 967.56 1044.12 ]
2. 模型架构(PyTorch版)
输入输出说明:
-
输入形状:
(batch_size, window_size, 18)
-
编码器输出:
(batch_size, 128)
(特征向量) -
解码器输出:
(batch_size, window_size, 18)
(重建数据)
import torch.nn as nn
import torch.nn.functional as F
class Encoder(nn.Module):
"""编码器:提取时空特征"""
def __init__(self, input_dim=18, feat_dim=128):
super().__init__()
# CNN分支(处理传感器间关系)
self.conv_block = nn.Sequential(
nn.Conv1d(in_channels=input_dim, out_channels=64, kernel_size=3, padding=1),
nn.ReLU(),
nn.Conv1d(64, 128, kernel_size=3, padding=1),
nn.ReLU()
)
# LSTM分支(处理时间关系)
self.lstm = nn.LSTM(
input_size=input_dim,
hidden_size=128,
num_layers=2,
batch_first=True,
bidirectional=True
)
# 注意力机制
self.attn = nn.MultiheadAttention(embed_dim=384, num_heads=4)
# 特征压缩
self.fc = nn.Linear(384, feat_dim)
def forward(self, x):
# 输入x形状:(batch_size, window_size, 18)
batch_size = x.size(0)
# CNN分支处理
x_cnn = x.permute(0, 2, 1) # 转换为(batch, 18, window_size)
x_cnn = self.conv_block(x_cnn) # 输出(batch, 128, window_size)
x_cnn = x_cnn.permute(0, 2, 1) # 恢复为(batch, window_size, 128)
# LSTM分支处理
x_lstm, _ = self.lstm(x) # 输出(batch, window_size, 256)
# 合并特征
merged = torch.cat([x_cnn, x_lstm], dim=-1) # (batch, window_size, 384)
# 注意力机制(需要调整维度顺序)
attn_in = merged.permute(1, 0, 2) # (window_size, batch, 384)
attn_out, _ = self.attn(attn_in, attn_in, attn_in)
attn_out = attn_out.permute(1, 0, 2) # 恢复(batch, window_size, 384)
# 全局最大池化
features, _ = torch.max(attn_out, dim=1) # (batch, 384)
# 最终特征映射
return self.fc(features) # (batch, 128)
class Decoder(nn.Module):
"""解码器:重建原始序列"""
def __init__(self, feat_dim=128, output_dim=18, window_size=60):
super().__init__()
self.lstm = nn.LSTM(
input_size=feat_dim,
hidden_size=256,
num_layers=2,
batch_first=True
)
self.output_layer = nn.Sequential(
nn.Linear(256, 128),
nn.ReLU(),
nn.Linear(128, output_dim)
)
def forward(self, x):
# 输入x形状:(batch_size, 128)
batch_size = x.size(0)
# 扩展时间维度
x = x.unsqueeze(1).repeat(1, WINDOW_SIZE, 1) # (batch, window_size, 128)
# LSTM处理
x, _ = self.lstm(x) # (batch, window_size, 256)
# 逐时间步重建
return self.output_layer(x) # (batch, window_size, 18)
class Autoencoder(nn.Module):
"""完整自编码器"""
def __init__(self):
super().__init__()
self.encoder = Encoder()
self.decoder = Decoder()
def forward(self, x):
encoded = self.encoder(x)
decoded = self.decoder(encoded)
return decoded
3. 模型训练与特征提取
# 3.1 初始化模型与优化器
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = Autoencoder().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
criterion = nn.MSELoss()
# 3.2 训练循环
def train_model(epochs=100):
model.train()
for epoch in range(epochs):
total_loss = 0
for batch in train_loader:
inputs = batch.to(device) # (batch, window_size, 18)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, inputs)
loss.backward()
optimizer.step()
total_loss += loss.item()
print(f'Epoch {epoch+1}/{epochs}, Loss: {total_loss/len(train_loader):.4f}')
# 启动训练
train_model(epochs=50)
# 3.3 特征提取
def extract_features(dataloader):
model.eval()
all_features = []
with torch.no_grad():
for batch in dataloader:
inputs = batch.to(device)
features = model.encoder(inputs) # (batch, 128)
all_features.append(features.cpu())
return torch.cat(all_features, dim=0)
features = extract_features(train_loader) # 形状:(11940, 128)
训练结果:
Epoch 1/50, Loss: 0.2170 Epoch 2/50, Loss: 0.0501 Epoch 3/50, Loss: 0.0384 Epoch 4/50, Loss: 0.0501 Epoch 5/50, Loss: 0.0379 Epoch 6/50, Loss: 0.0364 Epoch 7/50, Loss: 0.0271 Epoch 8/50, Loss: 0.0267 Epoch 9/50, Loss: 0.0225 Epoch 10/50, Loss: 0.0232 Epoch 11/50, Loss: 0.0264 Epoch 12/50, Loss: 0.0564 Epoch 13/50, Loss: 0.0347 Epoch 14/50, Loss: 0.0412 Epoch 15/50, Loss: 0.0400 Epoch 16/50, Loss: 0.0368 Epoch 17/50, Loss: 0.0248 Epoch 18/50, Loss: 0.0203 Epoch 19/50, Loss: 0.0318 Epoch 20/50, Loss: 0.0325 Epoch 21/50, Loss: 0.0393 Epoch 22/50, Loss: 0.0339 Epoch 23/50, Loss: 0.0403 Epoch 24/50, Loss: 0.0364 Epoch 25/50, Loss: 0.0294 Epoch 26/50, Loss: 0.0261 Epoch 27/50, Loss: 0.0249 Epoch 28/50, Loss: 0.0226 Epoch 29/50, Loss: 0.0213 Epoch 30/50, Loss: 0.0222 Epoch 31/50, Loss: 0.0196 Epoch 32/50, Loss: 0.0190 Epoch 33/50, Loss: 0.0232 Epoch 34/50, Loss: 0.0194 Epoch 35/50, Loss: 0.0201 Epoch 36/50, Loss: 0.0178 Epoch 37/50, Loss: 0.0151 Epoch 38/50, Loss: 0.0153 Epoch 39/50, Loss: 0.0164 Epoch 40/50, Loss: 0.0319 Epoch 41/50, Loss: 0.0169 Epoch 42/50, Loss: 0.0143 Epoch 43/50, Loss: 0.0143 Epoch 44/50, Loss: 0.0164 Epoch 45/50, Loss: 0.0151 Epoch 46/50, Loss: 0.0151 Epoch 47/50, Loss: 0.0133 Epoch 48/50, Loss: 0.0140 Epoch 49/50, Loss: 0.0135 Epoch 50/50, Loss: 0.0130
解释:
这段输出结果展示了一个模型训练过程。具体来说,它显示了模型在每个训练周期(epoch)的损失值(Loss)。
解释
-
Epoch 1/50, Loss: 0.2170: 表示第一个训练周期(epoch)的损失值为 0.2170。
-
Epoch 2/50, Loss: 0.0501: 表示第二个训练周期的损失值为 0.0501。
-
...
-
Epoch 50/50, Loss: 0.0130: 表示第五十个训练周期的损失值为 0.0130。
含义
-
Epoch: 一个 epoch 指的是模型完整地遍历一次训练数据集。在这个例子中,模型总共训练了 50 个 epoch,也就是说它完整地遍历了训练数据集 50 次。
-
Loss: 损失函数是衡量模型预测值与真实值之间差异的指标。损失值越低,表示模型的预测越接近真实值。在训练过程中,我们的目标是最小化损失函数。
趋势分析
从输出结果可以看出,损失值总体上呈现下降趋势,这表明模型在不断地学习和改进,预测越来越准确。
-
开始阶段: 损失值下降较快,说明模型在快速学习数据中的模式。
-
中间阶段: 损失值下降速度减缓,说明模型学习逐渐进入稳定期。
-
后期阶段: 损失值趋于稳定,表明模型可能已经接近收敛。
一些观察
-
波动: 在某些 epoch,损失值会出现小幅上升,这可能是由于随机性因素或模型在训练过程中遇到了一些困难的样本。
-
收敛: 损失值在后期趋于稳定,表明模型可能已经接近收敛。但是,为了确保模型完全收敛,可能需要更多的训练周期,或者可以尝试调整模型的超参数。
总结
这段输出结果展示了模型训练的进展情况。通过观察损失值的变化趋势,我们可以了解模型的学习状态,并判断模型是否收敛。较低且稳定的损失值通常意味着模型具有较好的性能。
4. 关键组件说明
4.1 数据流维度变化
步骤 | 张量形状 | 说明 |
---|---|---|
原始输入 | (12000, 18) | 原始传感器数据 |
滑动窗口 | (11940, 60, 18) | 时间窗口分割 |
训练批次 | (64, 60, 18) | DataLoader生成的批次 |
编码器输出 | (64, 128) | 每个窗口的特征向量 |
解码器输出 | (64, 60, 18) | 重建后的窗口数据 |
4.2 模型核心设计
-
Conv1d处理传感器关系:
-
使用
in_channels=18
对传感器维度进行卷积 -
通过kernel_size=3捕捉相邻传感器的局部模式
-
-
双向LSTM捕捉时间依赖:
-
双向结构同时考虑过去和未来信息
-
使用两层LSTM增强非线性建模能力
-
-
注意力机制:
-
通过多头注意力自动学习不同时间点的重要性
-
使用4个注意力头增强多样性
-
-
特征压缩:
-
全局最大池化保留最显著特征
-
全连接层将特征映射到指定维度
-