英特尔oneAPI人工智能黑客松
英特尔举办了oneAPI人工智能黑客松比赛,需要选手使用英特尔的官方套件去解决一些计算机视觉领域的问题,活动分为3个赛道:
计算机视觉挑战:检测并清除杂草
机器学习:预测淡水质量
oneAPI开放创新:使用oneAPI人工智能分析工具包实现任何创意
我计划参加oneAPI开放创新赛道。去实现X光违禁物识别。
痛点分析
X光安检机是目前我国使用最广泛的安检技术手段,广泛应用于城市轨交、铁路、机场、重点场馆、物流寄递等场景。使用人工智能技术,辅助一线安检员进行X光安检判图,可以有效降低因为人员疲劳或注意力不集中带来的漏报等问题。但在实际场景中,因物品的多样性、成像角度、遮挡等问题,为算法的开发带来了一定的挑战。
目前高准确率的图像识别多用卷积神经网络实现,但是当前基于卷积神经网络训练的模型有一定局限性,违禁品多种多样,场景也复杂多变,这就需要设计的卷积神经网络模型的层数要足够多,训练集样本数要足够大,才能保证准确率。
为了解决上述问题,提出了一种基于intel oneAI kit 建立统一模型来实现违禁品的通用识别。
设计思路
- 准备数据集:准备包含违禁物品和正常物品图像的数据集,并标记每张图像中违禁物品的位置和类别。
- 构建形状模型:使用intel 拓展 PyTorch包 搭建一个形状模型,如卷积神经网络(CNN),用于对违禁物品进行分类。我们可以使用预训练的模型,如ResNet等,并进行微调以适应我们的数据集。
- 构建颜色模型:使用intel 拓展 PyTorch包 搭建一个颜色模型,如全连接神经网络,用于对图像颜色信息进行分类。我们可以使用预训练的模型,如VGG等,并进行微调以适应我们的数据集。
- 数据处理与输入:对形状模型输出的数据进行处理,提取出违禁物品的位置和类别信息,并将其输入到颜色模型中进行分类。
- 联合识别:将形状模型输出的数据和颜色模型输出的数据进行计算,通过融合两个模型的结果,得出哪些区域是何种违禁品的概率。
- 训练和测试:使用准备好的数据集对模型进行训练和测试,评估模型的性能指标,如准确率、召回率等。
方案实现
数据集准备:
准备一个包含两种违禁物品(刀和枪)和正常物品的图像数据集。数据集中的每张图像都标记了违禁物品的位置和类别。文件内容格式为“文件名-违禁品矩形框左上角坐标-违禁品矩形框右下角坐标”;
读取上述裁切后的图片,每张图片随机读取N个像素的Lab颜色空间上的值,输出到描述文件中,文件内容为“颜色-L分量值-a分量值-b分量值”;
# 数据集转换器
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
# 定义数据集
dataset = torchvision.datasets.ImageFolder(root='dataset', transform=transform)
dataloader = DataLoader(dataset, batch_size=4, shuffle=True)
构建形状模型:
使用PyTorch搭建一个简单的卷积神经网络(CNN),用于对违禁物品进行分类。我们使用ResNet18进行微调以适应我们的数据集。
# 构建卷积神经网络结构
def build_resnet18():
model = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(inplace=True),
nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),
nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(512),
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(512),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(512, 1024, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(1024),
nn.ReLU(inplace=True),
nn.Conv2d(1024, 1024, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(1024),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Flatten(),
nn.Linear(1024 * 8 * 8, 512),
nn.ReLU(inplace=True),
nn.Linear(512, 3)
)
return model
这个网络结构包括了多个卷积层、批归一化层、激活层、池化层和全连接层。我们使用了PyTorch内置的ResNet模块来构建这个网络结构,通过调用nn.Sequential将各个层顺序连接起来。
接着,我们导入了CIFAR10数据集,并使用transforms对数据进行预处理,包括归一化、缩放和转换图像格式等操作。然后,我们使用DataLoader来加载数据集,并迭代处理每个批次的数据。
构建颜色模型:
使用PyTorch搭建一个全连接神经网络,用于对图像颜色信息进行分类。我们可以使用VGG16等进行微调
# 读取数据并进行Z-score归一化处理
train_transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
val_transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
train_dataset = YourDataset(data_path='train', transform=train_transform)
val_dataset = YourDataset(data_path='val', transform=val_transform)
# 划分训练集和验证集
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True)
val_loader = torch.utils.data.DataLoader(val_dataset, batch_size=32, shuffle=False)
# 定义损失函数和优化器
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
# 训练模型
model.train()
for epoch in range(num_epochs):
for i, (inputs, labels) in enumerate(train_loader):
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
# 在每个epoch结束时,计算验证集的准确率和损失
model.eval()
with torch.no_grad():
correct = 0
total = 0
val_loss = 0
for inputs, labels in val_loader:
outputs = model(inputs)
val_loss += criterion(outputs, labels).item()
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
accuracy = 100 * correct / total
print('Epoch [{}/{}], Loss: {:.4f}, Accuracy: {:.2f}%'.format(epoch+1, num_epochs, val_loss/len(val_loader), accuracy))
model.train()
在模型微调过程中,我们读取数据并进行Z-score归一化处理:从数据集中读取图像数据,并使用Z-score归一化方法将每个通道的数据缩放到均值为0,标准差为1的范围内。
使用训练集对模型进行训练,并使用验证集进行调优。在每个epoch结束时,计算验证集的准确率和损失,以便调整模型参数。最后在验证集上使用不同的K值进行测试,选择具有最高准确率的K值。
联合识别:
将形状模型输出的数据和颜色模型输出的数据进行计算,通过融合两个模型的结果,得出哪些区域是何种违禁品的概率。
# 定义融合模型
merged_model = torch.nn.Sequential(
shape_model,
torch.nn.ReLU(),
color_model,
torch.nn.ReLU(),
torch.nn.Linear(4096, 3) # 修改输出层
)
# 定义损失函数和优化器
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(merged_model.parameters(), lr=0.001)
# 训练融合模型
for epoch in range(10):
running_loss = 0.0
with ThreadPoolExecutor() as executor:
for i, data in enumerate(dataloader, 0):
inputs, labels = data
optimizer.zero_grad()
outputs = executor.submit(merged_model, inputs)
loss = criterion(outputs.get(), labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
print(f"Epoch {epoch+1} Loss: {running_loss/len(dataloader)}")
训练和测试:
使用准备好的数据集对模型进行训练和测试,评估模型的性能指标,评测方式采用计算box 加权AP的方式,对IoU = 0.5计算各类AP后加权。
首先计算每个类的AP:
(1)根据预测框和标注框的IoU是否达到阈值0.5判断该预测框是真阳性还是假阳性;
(2)根据每个预测框的置信度进行从高到低排序;
(3)在不同置信度阈值下计算精确率和召回率,得到若干组PR值;
(4)绘制PR曲线并计算AP值。
然后计算加权AP:把所有类的AP值按照权重加权得到wAP。
总结
最终我们实现了一个demo案例,根据输出的违禁品概率,按照概率高低依次告警级别为必须核查、一般性核查、建议人工核查、正常,输出可能的违禁品种类和告警级别,提示安检员做针对性的处理。
在训练阶段,我们使用 Intel® Extension for Pytorch 等加速库提高模型的响应速度。并计划后续使用Intel® Distribution of Modin库来加速pandas库,对原始数据集进行数据清洗和默认值的填充。