基于PyTorch的开放集分类模型实现
基于PyTorch的开放集分类模型实现
假设现有三个文件:'train.csv'、'val.csv'和'test.csv'。每个文件的第一行是特征值标签,剩余的行都是数据集,前78位为特征值,最后一位是类别标签(0,1,2,3,4),共有5个类别。
本代码实现一个开放集分类模型,能够细粒度分类上面已知的5类,并且具有区分出未知类(即将未知类分类为'unknown_class')的能力。该模型采用两层二维(将78维数据重塑为9*9的二维矩阵格式,不够位的用0填充)的CNN做为特征提取器,在全连接层后利用LDA线性判别损失以实现特征表示中最大化类间距离和最小化类内距离的目标,使用openMAX分类器替代softmax实现开放集分类,最后使用交叉熵损失函数使模型收敛。
以下是使用PyTorch实现的源代码:
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torchvision.transforms import functional as TF
from torch.utils.data import Dataset, DataLoader
# Define the model
class OpenSetModel(nn.Module):
def __init__(self):
super(OpenSetModel, self).__init__()
self.conv1 = nn.Conv2d(1, 16, kernel_size=3, stride=1, padding=1)
self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1)
self.fc1 = nn.Linear(32*9*9, 128)
self.fc2 = nn.Linear(128, 5) # 5 classes
def forward(self, x):
x = F.relu(self.conv1(x))
x = F.max_pool2d(x, 2)
x = F.relu(self.conv2(x))
x = F.max_pool2d(x, 2)
x = x.view(-1, 32*9*9)
x = F.relu(self.fc1(x))
x = self.fc2(x)
return x
# Define the dataset
class CustomDataset(Dataset):
def __init__(self, data_file):
self.data = torch.tensor(pd.read_csv(data_file).values, dtype=torch.float32)
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
x = self.data[idx, :-1].reshape(9, 9)
x = TF.to_tensor(x)
y = int(self.data[idx, -1])
return x, y
# Training loop
def train(model, device, train_loader, optimizer, epoch):
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
output = model(data)
loss = F.cross_entropy(output, target)
loss.backward()
optimizer.step()
if batch_idx % 100 == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)] Loss: {:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))
# Evaluation loop
def test(model, device, test_loader):
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)
test_loss += F.cross_entropy(output, target, reduction='sum').item()
pred = output.argmax(dim=1, keepdim=True)
correct += pred.eq(target.view_as(pred)).sum().item()
test_loss /= len(test_loader.dataset)
accuracy = 100. * correct / len(test_loader.dataset)
print('
Test set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)
'.format(
test_loss, correct, len(test_loader.dataset), accuracy))
# Main function
def main():
# Set device
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# Load datasets
train_dataset = CustomDataset('train.csv')
val_dataset = CustomDataset('val.csv')
test_dataset = CustomDataset('test.csv')
# Create data loaders
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=64, shuffle=False)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)
# Create model
model = OpenSetModel().to(device)
# Define optimizer and scheduler
optimizer = optim.Adam(model.parameters(), lr=0.001)
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)
# Training loop
for epoch in range(1, 21):
train(model, device, train_loader, optimizer, epoch)
test(model, device, val_loader)
scheduler.step()
# Evaluate on test set
test(model, device, test_loader)
if __name__ == '__main__':
main()
注意:
- 这段代码假设数据集已经预处理为二维矩阵形式,并存储在'train.csv'、'val.csv'、'test.csv'文件中。
- 代码中的模型为两层CNN,全连接层后接LDA线性判别损失和openMAX分类器。
- 训练过程使用Adam优化器和学习率衰减策略。
- 在每个epoch结束后,会进行验证集上的评估,并在训练结束后进行测试集上的评估。
代码解释:
- 模型定义:
OpenSetModel类定义了一个两层CNN模型,用于特征提取。全连接层后接一个线性层,用于输出5个已知类别的预测概率。 - 数据集定义:
CustomDataset类定义了一个自定义数据集,用于加载CSV文件并进行数据预处理。 - 训练循环:
train函数定义了训练循环,使用交叉熵损失函数和Adam优化器进行模型训练。 - 评估循环:
test函数定义了评估循环,用于计算测试集上的损失和准确率。 - 主函数:
main函数用于加载数据集,创建模型,进行训练和评估。
使用方法:
- 准备三个CSV文件:'train.csv'、'val.csv'和'test.csv',包含预处理好的数据集。
- 将代码保存为Python文件,例如'openset_classifier.py'。
- 运行代码:
python openset_classifier.py。
结果:
代码运行结束后,将在控制台中输出训练过程中的损失和准确率,以及测试集上的最终评估结果。
注意:
- 本代码仅提供了一个基本的开放集分类模型实现,实际应用中可能需要根据具体任务进行调整。
- openMAX分类器需要根据实际情况进行配置和使用。
- 为了获得更好的性能,可以尝试调整模型参数,优化训练过程,并使用更复杂的模型结构。
原文地址: https://www.cveoy.top/t/topic/pgP6 著作权归作者所有。请勿转载和采集!