神经网络拟合离散标签值
- 1. 数据预处理
- 1.1 添加参数解析
- 1.2 数据预处理逻辑
- 1.3 标签处理逻辑
- 1.4 构建特征和标签
- 1.5 数据归一化、转torch
- 1.6 实现Dataset类
- 2. 定义model
- 3. 定义train脚本
- 3.1 loss和optimizer
- 3.2 train
- 3.3 predict
1. 数据预处理
1.1 添加参数解析
为了方便管理模型和训练等参数,统一用参数解析。
def parse_args():
"""
解析命令行参数并返回参数对象。
返回:
- args (argparse.Namespace): 解析后的参数对象
"""
parser = argparse.ArgumentParser(description='命令行参数解析示例')
# 添加参数
#代表输入文件的名称:g0-25%.xlsx、l0.4-2.6.xlsx、s0.4-1.6.xlsx、y0.8-4.0.xlsx
parser.add_argument('--input', type=str, default='g0-25%.xlsx', help='数据文件路径')
#代表预测excel中哪一列的参数值,比如要预测g0-25%.xlsx中g取0的这一列
parser.add_argument('--predict_para', type=float, default=12.5, help='代表预测excel中哪一列的参数值')
parser.add_argument('--batch_size', type=int, default=4, help='每批次的样本数量,默认值是 4')
parser.add_argument('--epochs', type=int, default=100, help='训练的轮数,默认值是100')
parser.add_argument('--learning_rate', type=float, default=0.001, help='学习率,默认值是 0.001')
# 解析参数
args = parser.parse_args()
return args
1.2 数据预处理逻辑
最近一个小项目需要搭建神经网络
根据输入数据
的特征去拟合
对应的标签值
。
输入是excel的.xlsx
文件,一共是1400x12
的12列数据,第一列是时间,第2-第12列都是对应的数据,第一行是对应的标签值;使用pandas库读取。
args = parse_args()
file_path = args.input # 请替换为实际的数据文件路径
# 读取 Excel 文件
df = pd.read_excel(file_path)
data = df.to_numpy()[:, 1:]
# 标签就是第一行对应的离散标签值
labels = np.array(df.columns)[1:].astype(np.float32)
labels = np.round(labels, 2)
1.3 标签处理逻辑
从第一行的标签值来看,每个标签真实值都是离散值,我们可以将其映射
为0、1、2…,把回归问题
当成分类问题
来,更有利于模型的拟合。
scaler = StandardScaler()
train_features = train_df.iloc[:, :-output_df.shape[1]]
train_labels = train_df.iloc[:, -output_df.shape[1]:]
test_features = test_df.iloc[:, :-output_df.shape[1]]
test_labels = test_df.iloc[:, -output_df.shape[1]:]
X_train = scaler.fit_transform(train_features)
y_train = np.array(train_labels)
X_val = scaler.transform(test_features)
y_val = np.array(test_labels)
1.4 构建特征和标签
这里,data是1400x11维度的数据,将其转置``,则表示成11组(1400, 1)
的数据,刚好对应11个离散标签值
。标签y则是(11, 1),对应11个映射好的标签值
。
# 构建特征和标签
X: object = data.T # [样本数, 特征数]
y = label_indices # 标签
1.5 数据归一化、转torch
# 数据预处理:标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 创建 Dataset 对象
dataset = CustomDataset(X_scaled, label_indices)
# 创建 DataLoader 对象
batch_size = args.batch_size
dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)
#实例化网络模型,output对应预测的标签值的数量
model = CNNClassifier(fc1_channels=44544, output=11)
1.6 实现Dataset类
这里,对data添加维度,为(11, 1, 1400)
,labels 转int型
,最后都转tensor
。
经过上述的转置
后,这里的__len__
,就是return的11,正好是11组数据,__getitem__
正好根据索引idx返回对应的每一组数据。
# 自定义 Dataset 类
class CustomDataset(Dataset):
def __init__(self, data, labels):
self.data = torch.tensor(data, dtype=torch.float32).unsqueeze(1) # Add channel dimension
self.labels = torch.tensor(labels, dtype=torch.int64) # Long for classification
def __len__(self):
return self.data.size(0) # Number of samples
def __getitem__(self, idx):
# return self.data[:, idx, :], self.labels[idx]
return self.data[idx], self.labels[idx]
2. 定义model
这里我定义了1个CNN结合FC的网络结构。
# 定义 CNN 模型
class CNNClassifier(nn.Module):
def __init__(self, fc1_channels, output):
super(CNNClassifier, self).__init__()
self.conv1 = nn.Conv1d(in_channels=1, out_channels=16, kernel_size=5)
self.conv2 = nn.Conv1d(in_channels=16, out_channels=32, kernel_size=5)
self.fc1 = nn.Linear(fc1_channels, 128) # Flattened feature size is 32 * 1390
self.fc2 = nn.Linear(128, output) # classes
def forward(self, x):
x = self.conv1(x)
x = nn.ReLU()(x)
x = self.conv2(x)
x = nn.ReLU()(x)
x = x.view(x.size(0), -1) # Flatten
x = self.fc1(x)
x = nn.ReLU()(x)
x = self.fc2(x)
return x
3. 定义train脚本
3.1 loss和optimizer
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=args.learning_rate)
3.2 train
# 训练模型
num_epochs = args.epochs
for epoch in range(num_epochs):
model.train()
running_loss = 0.0
for batch_data, batch_labels in dataloader:
outputs = model(batch_data)
loss = criterion(outputs, batch_labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
running_loss += loss.item() * batch_data.size(0)
epoch_loss = running_loss / len(dataset)
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {epoch_loss:.4f}')
3.3 predict
最后在预测的时候别忘了根据上述映射关系
,将预测的标签值映射回去
。
# 进行预测
model.eval()
with torch.no_grad():
# 选择一个样本进行预测
# sample_idx = 10
sample_labels_list = [round(label, 2) for label in labels.tolist()]
sample_idx = sample_labels_list.index(args.predict_para)
eval_data = torch.tensor(X_scaled[sample_idx], dtype=torch.float32).unsqueeze(0).unsqueeze(0)
predictions = model(eval_data)
_, predicted_label_idx = torch.max(predictions, 1)
predicted_label = labels[predicted_label_idx.item()]