机器学习项目-智能鞋垫开发项目记录(自用)七---上手2(更错版)

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。下面是对代码的详细解释以及如何显示输出结果的方法:

代码解释

  1. 导入库:

    Python

    import 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 (用于数据处理) 等库。

  2. 数据参数:

    Python

    WINDOW_SIZE = 60  # 滑动窗口大小
    BATCH_SIZE = 64   # 批处理大小
    

    定义了滑动窗口大小和批处理大小。

  3. SensorDataset 类:

    Python

    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__ 方法返回指定索引的窗口数据。
  4. prepare_data 函数:

    Python

    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 进行标准化。
    • 最后创建 SensorDatasetDataLoader
  5. 使用示例:

    Python

    file_path1=r"E:\gxy\gxy\D\teach\footbed\Data processing\20250121.csv"
    train_loader, scaler = prepare_data(file_path1)
    

    调用 prepare_data 函数加载和预处理数据。

如何显示输出结果

要在代码中显示输出结果,可以使用 print 函数。以下是一些可以添加 print 语句的位置以及可以打印的内容:

  • 打印数据集长度:

    Python

    dataset = SensorDataset(scaled_data, WINDOW_SIZE)
    print("Dataset length:", len(dataset))
    
  • 打印dataloader中的数据:

    Python

    for batch in train_loader:
        print("Batch shape:", batch.shape)
        #print("Batch data:", batch) # 如果batch较小,可以打印batch内容,否则不建议打印,会刷屏
        break # 打印第一个batch后退出循环,如果需要遍历所有batch,去掉break即可
    
    
  • 打印预处理后的数据形状:

    Python

    print("Scaled data shape:", scaled_data.shape)
    
  • 打印一个batch的数据:

    Python

    for batch in train_loader:
        print("First batch:", batch.shape)
        print(batch[0]) # 打印第一个batch的第一个数据
        break
    
  • 打印scaler参数:

    Python

    print("Scaler center:", scaler.center_)
    print("Scaler scale:", scaler.scale_)
    

修改后的代码示例 (包含打印语句):

Python

import 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

# ... (使用示例)

通过在代码中添加这些 print 语句,你可以更好地了解数据的形状、内容和预处理过程。请根据你的需求选择要打印的内容。

显示结果:

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 模型核心设计
  1. Conv1d处理传感器关系

    • 使用in_channels=18对传感器维度进行卷积

    • 通过kernel_size=3捕捉相邻传感器的局部模式

  2. 双向LSTM捕捉时间依赖

    • 双向结构同时考虑过去和未来信息

    • 使用两层LSTM增强非线性建模能力

  3. 注意力机制

    • 通过多头注意力自动学习不同时间点的重要性

    • 使用4个注意力头增强多样性

  4. 特征压缩

    • 全局最大池化保留最显著特征

    • 全连接层将特征映射到指定维度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值