首页
人工智能
网络安全
手机
搜索
登录
搜索
golden81
累计撰写
154
篇文章
累计收到
0
条评论
首页
栏目
首页
人工智能
网络安全
手机
包含标签 【数据集】 的文章
2025-4-28
瓷砖缺陷检测数据集VOC+YOLO格式2871张7类别
数据集格式:Pascal VOC格式+YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):2871 标注数量(xml文件个数):2871 标注数量(txt文件个数):2871 标注类别数:6 标注类别名称(注意yolo格式类别顺序不和这个对应,而以labels文件夹classes.txt为准):["1","2","3","4","5","6"] { "0": "背景", "1": "边异常", "2": "角异常", "3": "白色点瑕疵", "4": "浅色块瑕疵", "5": "深色点块瑕疵", "6": "光圈瑕疵" } 每个类别标注的框数: 1 框数 = 279 2 框数 = 1146 3 框数 = 1185 4 框数 = 538 5 框数 = 4705 6 框数 = 187 总框数:8040 使用标注工具:labelImg 标注规则:对类别进行画矩形框 重要说明:暂无 特别声明:本数据集不对训练的模型或者权重文件精度作任何保证,数据集只提供准确且合理标注
2025年-4月-28日
9 阅读
0 评论
人工智能
2025-4-28
齿轮缺陷检测数据集VOC+YOLO格式7742张3类别
数据集格式:Pascal VOC格式+YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):7742 标注数量(xml文件个数):7742 标注数量(txt文件个数):7742 标注类别数:3 标注类别名称(注意yolo格式类别顺序不和这个对应,而以labels文件夹classes.txt为准):["break","lack","scratch"] 每个类别标注的框数: break 框数 = 2620 lack 框数 = 2568 scratch 框数 = 11045 总框数:16233 使用标注工具:labelImg 标注规则:对类别进行画矩形框 重要说明:暂无 特别声明:本数据集不对训练的模型或者权重文件精度作任何保证,数据集只提供准确且合理标注 图片预览: 标注例子:
2025年-4月-28日
7 阅读
0 评论
人工智能
2025-4-28
基于yolov11的瓷砖缺陷检测系统python源码+pytorch模型+评估指标曲线+精美GUI界面
【算法介绍】 基于YOLOv11的瓷砖缺陷检测系统,是针对瓷砖制造行业质量控制需求而设计的自动化检测解决方案。该系统利用YOLOv11这一尖端深度学习模型,能够高效、准确地识别瓷砖表面的多种缺陷类型,包括边缘崩裂(edge-chipping)、破洞(hole)和裂缝(line)。 YOLOv11作为YOLO系列的最新版本,在检测精度和速度上均有显著提升。其改进的骨干网络和颈部架构增强了特征提取能力,使得模型能够更准确地捕捉瓷砖表面的细微缺陷。同时,YOLOv11还通过优化训练方法和引入新的功能模块,进一步提高了模型的泛化能力和适应性。 在实际应用中,该系统能够实时处理瓷砖图像,并自动标注出缺陷位置和类型。检测结果可以实时显示在用户界面上,并提供详细的缺陷信息,如缺陷大小、形状和置信度等。这有助于瓷砖制造商及时发现并处理缺陷产品,提高生产效率和产品质量。基于YOLOv11的瓷砖缺陷检测系统为瓷砖制造行业提供了一种高效、准确的自动化检测手段,有助于提升产品质量和市场竞争力。 【效果展示】 【训练数据集介绍】 数据集格式:Pascal VOC格式+YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):888 标注数量(xml文件个数):888 标注数量(txt文件个数):888 标注类别数:3 标注类别名称(注意yolo格式类别顺序不和这个对应,而以labels文件夹classes.txt为准):["edge-chipping","hole","line"] 每个类别标注的框数: edge-chipping 框数 = 6054 hole 框数 = 6288 line 框数 = 4216 总框数:16558 使用标注工具:labelImg 标注规则:对类别进行画矩形框 重要说明:暂无 特别声明:本数据集不对训练的模型或者权重文件精度作任何保证,数据集只提供准确且合理标注 图片预览: 标注例子: 【训练信息】 参数 值 训练集图片数 835 验证集图片数 45 训练map 61.6% 训练精度(Precision) 67.3% 训练召回率(Recall) 55.1% 【验证集精度统计】 Class Images Instances P R mAP50 mAP50-95 all 45 660 0.673 0.551 0.616 0.326 edge-chipping 40 236 0.692 0.597 0.627 0.329 hole 39 250 0.898 0.648 0.801 0.438 line 28 174 0.428 0.408 0.42 0.21 【测试环境】 windows10anaconda3+python3.8torch==2.3.0ultralytics==8.3.81notallow==1.16.3 【界面设计】 class Ui_MainWindow(QtWidgets.QMainWindow): signal = QtCore.pyqtSignal(str, str) def setupUi(self): self.setObjectName("MainWindow") self.resize(1280, 728) self.centralwidget = QtWidgets.QWidget(self) self.centralwidget.setObjectName("centralwidget") self.weights_dir = './weights' self.picture = QtWidgets.QLabel(self.centralwidget) self.picture.setGeometry(QtCore.QRect(260, 10, 1010, 630)) self.picture.setStyleSheet("background:black") self.picture.setObjectName("picture") self.picture.setScaledContents(True) self.label_2 = QtWidgets.QLabel(self.centralwidget) self.label_2.setGeometry(QtCore.QRect(10, 10, 81, 21)) self.label_2.setObjectName("label_2") self.cb_weights = QtWidgets.QComboBox(self.centralwidget) self.cb_weights.setGeometry(QtCore.QRect(10, 40, 241, 21)) self.cb_weights.setObjectName("cb_weights") self.cb_weights.currentIndexChanged.connect(self.cb_weights_changed) self.label_3 = QtWidgets.QLabel(self.centralwidget) self.label_3.setGeometry(QtCore.QRect(10, 70, 72, 21)) self.label_3.setObjectName("label_3") self.hs_conf = QtWidgets.QSlider(self.centralwidget) self.hs_conf.setGeometry(QtCore.QRect(10, 100, 181, 22)) self.hs_conf.setProperty("value", 25) self.hs_conf.setOrientation(QtCore.Qt.Horizontal) self.hs_conf.setObjectName("hs_conf") self.hs_conf.valueChanged.connect(self.conf_change) self.dsb_conf = QtWidgets.QDoubleSpinBox(self.centralwidget) self.dsb_conf.setGeometry(QtCore.QRect(200, 100, 51, 22)) self.dsb_conf.setMaximum(1.0) self.dsb_conf.setSingleStep(0.01) self.dsb_conf.setProperty("value", 0.25) self.dsb_conf.setObjectName("dsb_conf") self.dsb_conf.valueChanged.connect(self.dsb_conf_change) self.dsb_iou = QtWidgets.QDoubleSpinBox(self.centralwidget) self.dsb_iou.setGeometry(QtCore.QRect(200, 160, 51, 22)) self.dsb_iou.setMaximum(1.0) self.dsb_iou.setSingleStep(0.01) self.dsb_iou.setProperty("value", 0.45) self.dsb_iou.setObjectName("dsb_iou") self.dsb_iou.valueChanged.connect(self.dsb_iou_change) self.hs_iou = QtWidgets.QSlider(self.centralwidget) self.hs_iou.setGeometry(QtCore.QRect(10, 160, 181, 22)) self.hs_iou.setProperty("value", 45) self.hs_iou.setOrientation(QtCore.Qt.Horizontal) self.hs_iou.setObjectName("hs_iou") self.hs_iou.valueChanged.connect(self.iou_change) self.label_4 = QtWidgets.QLabel(self.centralwidget) self.label_4.setGeometry(QtCore.QRect(10, 130, 72, 21)) self.label_4.setObjectName("label_4") self.label_5 = QtWidgets.QLabel(self.centralwidget) self.label_5.setGeometry(QtCore.QRect(10, 210, 72, 21)) self.label_5.setObjectName("label_5") self.le_res = QtWidgets.QTextEdit(self.centralwidget) self.le_res.setGeometry(QtCore.QRect(10, 240, 241, 400)) self.le_res.setObjectName("le_res") self.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(self) self.menubar.setGeometry(QtCore.QRect(0, 0, 1110, 30)) self.menubar.setObjectName("menubar") self.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(self) self.statusbar.setObjectName("statusbar") self.setStatusBar(self.statusbar) self.toolBar = QtWidgets.QToolBar(self) self.toolBar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) self.toolBar.setObjectName("toolBar") self.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar) self.actionopenpic = QtWidgets.QAction(self) icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap(":/images/1.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionopenpic.setIcon(icon) self.actionopenpic.setObjectName("actionopenpic") self.actionopenpic.triggered.connect(self.open_image) self.action = QtWidgets.QAction(self) icon1 = QtGui.QIcon() icon1.addPixmap(QtGui.QPixmap(":/images/2.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.action.setIcon(icon1) self.action.setObjectName("action") self.action.triggered.connect(self.open_video) self.action_2 = QtWidgets.QAction(self) icon2 = QtGui.QIcon() icon2.addPixmap(QtGui.QPixmap(":/images/3.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.action_2.setIcon(icon2) self.action_2.setObjectName("action_2") self.action_2.triggered.connect(self.open_camera) self.actionexit = QtWidgets.QAction(self) icon3 = QtGui.QIcon() icon3.addPixmap(QtGui.QPixmap(":/images/4.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionexit.setIcon(icon3) self.actionexit.setObjectName("actionexit") self.actionexit.triggered.connect(self.exit) self.toolBar.addAction(self.actionopenpic) self.toolBar.addAction(self.action) self.toolBar.addAction(self.action_2) self.toolBar.addAction(self.actionexit) self.retranslateUi() QtCore.QMetaObject.connectSlotsByName(self) self.init_all() 【模型可检测出3类】 边缘崩裂(edge-chipping)、破洞(hole)和裂缝(line) 【常用评估参数介绍】 在目标检测任务中,评估模型的性能是至关重要的。你提到的几个术语是评估模型性能的常用指标。下面是对这些术语的详细解释: Class: 这通常指的是模型被设计用来检测的目标类别。例如,一个模型可能被训练来检测车辆、行人或动物等不同类别的对象。 Images: 表示验证集中的图片数量。验证集是用来评估模型性能的数据集,与训练集分开,以确保评估结果的公正性。 Instances: 在所有图片中目标对象的总数。这包括了所有类别对象的总和,例如,如果验证集包含100张图片,每张图片平均有5个目标对象,则Instances为500。 P(精确度Precision): 精确度是模型预测为正样本的实例中,真正为正样本的比例。计算公式为:Precision = TP / (TP + FP),其中TP表示真正例(True Positives),FP表示假正例(False Positives)。 R(召回率Recall): 召回率是所有真正的正样本中被模型正确预测为正样本的比例。计算公式为:Recall = TP / (TP + FN),其中FN表示假负例(False Negatives)。 mAP50: 表示在IoU(交并比)阈值为0.5时的平均精度(mean Average Precision)。IoU是衡量预测框和真实框重叠程度的指标。mAP是一个综合指标,考虑了精确度和召回率,用于评估模型在不同召回率水平上的性能。在IoU=0.5时,如果预测框与真实框的重叠程度达到或超过50%,则认为该预测是正确的。 mAP50-95: 表示在IoU从0.5到0.95(间隔0.05)的范围内,模型的平均精度。这是一个更严格的评估标准,要求预测框与真实框的重叠程度更高。在目标检测任务中,更高的IoU阈值意味着模型需要更准确地定位目标对象。mAP50-95的计算考虑了从宽松到严格的多个IoU阈值,因此能够更全面地评估模型的性能。 这些指标共同构成了评估目标检测模型性能的重要框架。通过比较不同模型在这些指标上的表现,可以判断哪个模型在实际应用中可能更有效。 【使用步骤】 使用步骤:(1)首先根据官方框架ultralytics安装教程安装好yolov11环境,并安装好pyqt5(2)切换到自己安装的yolo11环境后,并切换到源码目录,执行python main.py即可运行启动界面,进行相应的操作即可 【提供文件】 python源码yolo11n.pt模型训练的map,P,R曲线图(在weights\results.png)测试图片(在test_img文件夹下面) 注意提供训练的数据集,请到mytxt.txt文件中找到地址
2025年-4月-28日
8 阅读
0 评论
人工智能
2025-4-28
基于昇腾用PyTorch实现CTR模型DIN(Deep interest Netwok)网络
本文主要介绍如何在昇腾上使用pytorch对推荐系统中经典的网络模型Din进行训练的实战讲解,使用数据集是Amazon中book数据集,主要内容分为以下几个模块: Din网络创新点介绍 Din网络架构剖析及搭建 Activation Unit介绍 Attention模块 Din网络构建 使用Amazon-book数据集训练Din网络实战 Amazon-book数据集介绍 Amazon-book数据集预处理 训练集与测试集划分 模型训练过程定义 使用Amazon-book训练wideWeep模型 评估模型性能 CTR(Click-through rate prediction)是工业应用(如在线广告)中的一项重要任务,处理这一类任务较为常用的方法是基于深度学习的方式,通过类似多层感知机的方式,将大规模的稀疏输入特征向量映射为低维的嵌入向量后以组为单位将其转化为固定长度的向量,最后将这些向量进行拼接输入到多层感知机中来学习特征之间的非线性关系。 在embedding阶段,所有的离散特征都要被映射成一个固定长度的低维稠密向量。离散特征一般有单值特征和多值特征,分别要做one-hot编码和multi-hot编码,单值特征没什么问题,直接映射成embedding向量即可,而对于多值特征,比如:用户点击过的item序列,用户点击过item类目的序列,通常的操作都是每个item映射成一个embedding向量,然后做一个sum/average pooling,最终得到一个embedding向量。 从图中可以看出在做多值特征pooling的时候并不会考虑每个item的重要性,但是在实际的应用过程中我们知道一个爱游泳的人,之前购买书籍、冰淇淋、薯片、游泳镜。给他推荐护目镜后他是否会点击这次推荐广告,跟之前购买的书籍、薯片与冰淇淋无关,而是跟他以前购买的游泳帽相关。也就是在这一次CTR预估中,部分历史数据(游泳镜)起到了决定作用,而其他的基本都无用,所以最好的方式就是给每个item一个权重。 DIN网络给每个item的权重是通过目标广告与该商品item之间的相关性决定,比如在上述例子中,候选广告推荐用户是否点击是护目镜,与用户购买的书籍、冰淇淋与薯片相关性较少,与游泳镜的相关性更大。 Din网络创新点介绍 将注意力机制应用于用户兴趣建模,可以更好评估不同项的重要性差异,自适应的学习用户每个历史行为项的权重,使能模型可以更好的捕捉用户对不同项的兴趣。 通过使用局部激活单元方式,来计算用户对每个历史行为的兴趣权重,是注意力机制中有效实现方式。 采用Mini-batch Perceptron Regularizer节省参数计算量,避免过拟合。 使用Data-dependent Activation Function也就是自适用的数据激活函数 Din网络架构剖析及搭建 当前广告模型基本上遵循的都是embedding\&MLP组合模式(图中basemodel部分),而Din网络通过在embedding层与MLP之间加入Attention机制有效的解决了推荐广告与用户历史购买行为之间相关性的问题,其网络架构重点由两部分组成,一个是激活模块(图中的Activation Unit),另一个是Attention模块(图中的Sumpooling),接下来将分别介绍这两部分的原理及如何使用pytorch搭建这两部分从而构建整个Din网络。 Activation Unit介绍 Activation Unit作为Din网络核心模块,通过将用户历史点击过的商品Id(Inputs from User)与候选广告商品的Id(Inputs from Ad)通过Out Product的方式计算相关性。计算相关性后通过concat的方式将原始输入与相关性计算后的输入进行shortcut连接载通过激活与线性层进行输出。关于'PRelu'与'Dice'模块也就是Din网络中引入的自适适应的数据激活函数。 Prelu激活函数计算公式: Dice激活函数计算公式: 两者计算表达式一致,其通过p(s)的计算公式不一样来控制激活的取值,关于两者p(s)的取值如下所示: Dice中p(s)计算公式: 式中E\[s\]和Var\[s\]分别是均值与方差,epsilon是一个常量,默认取值是10\^-8。 Dice是PReLu的推广,其核心思想是根据输入数据的分布自适应地调整校正点。Dice可以平滑地在两个通道之间切换,并且当E\[s\] = 0并Var\[s\]=0时,Dice退化为PReLU,Dice通过定义一个Dice类实现,'forward()'函数中实现了上述定义公式的功能。 # python自定义包 import os import pandas as pd import numpy as np # 导入pytorch相关包 import torch import torch.nn as nn # 根据公式计算p(s) class Dice(nn.Module): def __init__(self): super(Dice, self).__init__() self.alpha = nn.Parameter(torch.zeros((1,))) self.epsilon = 1e-9 def forward(self, x): # 公式中分母部分e的指数部分计算 norm_x = (x - x.mean(dim=0)) / torch.sqrt(x.var(dim=0) + self.epsilon) p = torch.sigmoid(norm_x) x = self.alpha * x.mul(1-p) + x.mul(p) return x 整个激活模块通过ActivationUnit类实现,该模块功能是计算用户购买行为与推荐目标之间的注意力系数,比如说用户虽然用户买了这个东西,但是这个东西实际上和推荐目标之间没啥关系,也不重要,所以要乘以一个小权重,如果购买的东西跟推荐目标之间有直接因果关系,则需要乘以一个较大的权重。 class ActivationUnit(nn.Module): def __init__(self, embedding_dim, dropout=0.2, fc_dims = [32, 16]): super(ActivationUnit, self).__init__() # 1.初始化fc层 fc_layers = [] # 2.输入特征维度这里将输入的embedding_dim乘以4是将中间层的节点数放大了4倍,因为将4个模块的向量进行了concat input_dim = embedding_dim*4 # 3.fc层内容:全连接层(4*embedding, 32)--->激活函数->dropout->全连接层(32,16)->.....->全连接层(16,1) for fc_dim in fc_dims: fc_layers.append(nn.Linear(input_dim, fc_dim)) fc_layers.append(Dice()) fc_layers.append(nn.Dropout(p = dropout)) input_dim = fc_dim fc_layers.append(nn.Linear(input_dim, 1)) # 4.将上面定义的fc层,整合到sequential中 self.fc = nn.Sequential(*fc_layers) def forward(self, query, user_behavior): """ query:targe目标的embedding ->(输入维度) batch*1*embed user_behavior:行为特征矩阵 ->(输入维度) batch*seq_len*embed out:预测目标与历史行为之间的注意力系数 """ # 1.获取用户历史行为序列长度 seq_len = user_behavior.shape[1] # 2.序列长度*embedding queries = torch.cat([query] * seq_len, dim=1) # 3.前面的把四个embedding合并成一个(4*embedding)的向量, # 第一个向量是目标商品的向量,第二个向量是用户行为的向量, # 至于第三个和第四个则是他们的相减和相乘(这里猜测是为了添加一点非线性数据用于全连接层,充分训练) attn_input = torch.cat([queries, user_behavior, queries - user_behavior, queries * user_behavior], dim = -1) out = self.fc(attn_input) return out Attention模块 Attention模块是Din网络中注意力序列层,其功能是计算用户行为与预测目标之间的系数,并将所有的向量进行相加,这里的目的是计算出用户的兴趣的向量。通过'AttentionPoolingLayer'这个类实现该功能。主要通过'active_unit()'引入了目标和历史行为之间的相关性。 class AttentionPoolingLayer(nn.Module): def __init__(self, embedding_dim, dropout): super(AttentionPoolingLayer, self).__init__() self.active_unit = ActivationUnit(embedding_dim = embedding_dim, dropout = dropout) def forward(self, query_ad, user_behavior, mask): """ query_ad:targe目标x的embedding -> (输入维度) batch*1*embed user_behavior:行为特征矩阵 -> (输入维度) batch*seq_len*embed mask:被padding为0的行为置为false -> (输入维度) batch*seq_len*1 output:用户行为向量之和,反应用户的爱好 """ # 1.计算目标和历史行为之间的相关性 attns = self.active_unit(query_ad, user_behavior) # 2.注意力系数乘以行为 output = user_behavior.mul(attns.mul(mask)) # 3.历史行为向量相加 output = user_behavior.sum(dim=1) return output Din网络构建 基于上述搭建好的Activation Unit与AttentionPoolingLayer模块,可以构建DeepInterestNet网络,本文实现的网络主要是用在Amazon-book数据集上进行测试,其主要功能是用户最近的历史40个购买物品是xxx时,购买y的概率是多少? class DeepInterestNet(nn.Module): def __init__(self, feature_dim, embed_dim, mlp_dims, dropout): super(DeepInterestNet, self).__init__() # 1.特征维度,就是输入的特征有多少个类 self.feature_dim = feature_dim # 2.embeding层,将特征数值转化为向量 self.embedding = nn.Embedding(feature_dim+1, embed_dim) # 3.注意力计算层(论文核心) self.AttentionActivate = AttentionPoolingLayer(embed_dim, dropout) # 4.定义fc层 fc_layers = [] # 5.该层的输入为历史行为的embedding,和目标的embedding,所以输入维度为2*embedding_dim # 全连接层(2*embedding,fc_dims[0])--->激活函数->dropout->全连接层(fc_dims[0],fc_dims[1])->.....->全连接层(fc_dims[n],1) input_dim = embed_dim * 2 for fc_dim in mlp_dims: fc_layers.append(nn.Linear(input_dim, fc_dim)) fc_layers.append(nn.ReLU()) fc_layers.append(nn.Dropout(p = dropout)) input_dim = fc_dim fc_layers.append(nn.Linear(input_dim, 1)) # 6.将所有层封装 self.mlp = nn.Sequential(*fc_layers) def forward(self, x): """ x输入(behaviors*40,ads*1) ->(输入维度) batch*(behaviors+ads) """ # 1.排除掉推荐目标 behaviors_x = x[:,:-1] # 2.记录之前填充为0的行为位置 mask = (behaviors_x > 0).float().unsqueeze(-1) # 3.获取推荐的目标 ads_x = x[:,-1] # 4.对推荐目标进行向量嵌入 query_ad = self.embedding(ads_x).unsqueeze(1) # 5.对用户行为进行embeding,注意这里的维度为(batch*历史行为长度*embedding长度) user_behavior = self.embedding(behaviors_x) # 6.矩阵相乘,将那些行为为空的地方全部写为0 user_behavior = user_behavior.mul(mask) # 7.将用户行为乘上注意力系数,再把所有行为记录向量相加 user_interest = self.AttentionActivate(query_ad, user_behavior, mask) # 8.将计算后的用户行为行为记录和推荐的目标进行拼接 concat_input = torch.cat([user_interest, query_ad.squeeze(1)], dim = 1) # 9.输入用户行为和目标向量,计算预测得分 out = self.mlp(concat_input) # 10.sigmoid激活函数 out = torch.sigmoid(out.squeeze(1)) return out 使用Amazon-book数据集训练Din网络实战 综上所述,我们已经构建好了一个Din模型,现在可以尝试使用Amazon数据集来训练该网络,首先我们先料了解一下什么Amazon数据集是什么? Amazon-book数据集介绍 Amazon-Book数据集是由亚马逊公司提供的大规模图书评论数据集,包含了亚马逊2000年至2014年之间大量的图书评论信息。是当前最大、最全面的图书评论数据集之一。 Amazon-Book数据集主要包括以下内容: 用户ID:标识每个参与评论的用户。 物品ID:标识每本书的唯一标识符。 评论文本:用户对书籍的具体评论内容。 评分:用户对书籍的评分,通常在1到5分之间。 这些数据提供了丰富的信息,可以用于分析用户行为、优化产品设计、改进营销策略等 # 使用padas库加载amazon-book数据集 data = pd.read_csv('/home/pengyongrong/workspace/DinModel/DIN-CODE/amazon-books-100k.txt') 将加载好的数据集进行打印,数据总共包含89999个样例,'label'表示用户是否会点击购买推荐的广告商品,0表示不点击、1表示点击;'userID'是用来标记用户的;'itemID'用来标识书籍;'cateID'标识书籍属的类别;'hit_item_list'指的是推荐给用户的商品或内容列表;hit_cate_list指的是推荐给用户的商品内容所述的类别。 data | | label | userID | itemID | cateID | hist_item_list | hist_cate_list | | 0 | 0 | AZPJ9LUT0FEPY | B00AMNNTIA | Literature \& Fiction | 0307744434\|0062248391\|0470530707\|0978924622\|15... | Books\|Books\|Books\|Books\|Books | | 1 | 1 | AZPJ9LUT0FEPY | 0800731603 | Books | 0307744434\|0062248391\|0470530707\|0978924622\|15... | Books\|Books\|Books\|Books\|Books | | 2 | 0 | A2NRV79GKAU726 | B003NNV10O | Russian | 0814472869\|0071462074\|1583942300\|0812538366\|B0... | Books\|Books\|Books\|Books\|Baking\|Books\|Books | | 3 | 1 | A2NRV79GKAU726 | B000UWJ91O | Books | 0814472869\|0071462074\|1583942300\|0812538366\|B0... | Books\|Books\|Books\|Books\|Baking\|Books\|Books | | 4 | 0 | A2GEQVDX2LL4V3 | 0321334094 | Books | 0743596870\|0374280991\|1439140634\|0976475731 | Books\|Books\|Books\|Books | | ... | ... | ... | ... | ... | ... | ... | | 89994 | 0 | A3CV7NJJC20JTB | 098488789X | Books | 034545197X\|0765326396\|1605420832\|1451648448 | Books\|Books\|Books\|Books | | 89995 | 1 | A3CV7NJJC20JTB | 0307381277 | Books | 034545197X\|0765326396\|1605420832\|1451648448 | Books\|Books\|Books\|Books | | 89996 | 0 | A208PSIK2APSKN | 0957496184 | Books | 0515140791\|147674355X\|B0055ECOUA\|B007JE1B1C\|B0... | Books\|Books\|Bibles\|Literature \& Fiction\|Litera... | | 89997 | 1 | A208PSIK2APSKN | 1480198854 | Books | 0515140791\|147674355X\|B0055ECOUA\|B007JE1B1C\|B0... | Books\|Books\|Bibles\|Literature \& Fiction\|Litera... | 89999 rows × 6 columns 通过对数据集分析发现,许多商品id只出现了一次,因此在编码的时候以类别作为编码和预测的目标输入给模型进行训练。由于每一个用户的历史购买行为均不一致,因此会导致长度也会不一样,这里截取了40个历史行为作为标准,用来获取用户历史购买信息与推荐广告商品的相关性,如果不足40则填充0到40,若大于40个行为,则截取最近40个行为(也就是后40个行为)。 'cate_encoder'是全局变量,用来编码类别标签的,在后续测试过程中也会用到。整个预处理过程分为8个步骤均在代码出注解。 Amazon-book数据集预处理 #导入sklearn相关包,主要用到LabelEncoder用来自动编码类别 from sklearn.preprocessing import LabelEncoder cate_encoder = None def AmazonBookPreprocess(dataframe, seq_len=40): """ 数据集处理 dataframe: 未处理的数据集 seq_len: 数据序列长度 data: 处理好的数据集 """ # 1.按'|'切割,用户历史购买数据,获取item的序列和类别的序列 data = dataframe.copy() data['hist_item_list'] = dataframe.apply(lambda x: x['hist_item_list'].split('|'), axis=1) data['hist_cate_list'] = dataframe.apply(lambda x: x['hist_cate_list'].split('|'), axis=1) # 2.获取cate的所有种类,为每个类别设置一个唯一的编码 cate_list = list(data['cateID']) _ = [cate_list.extend(i) for i in data['hist_cate_list'].values] # 3.将编码去重,'0' 作为padding的类别 cate_set = set(cate_list + ['0']) # 4.截取用户行为的长度,也就是截取hist_cate_list的长度,生成对应的列名 cols = ['hist_cate_{}'.format(i) for i in range(seq_len)] # 5.截取前40个历史行为,如果历史行为不足40个则填充0 def trim_cate_list(x): if len(x) > seq_len: # 5.1历史行为大于40, 截取后40个行为 return pd.Series(x[-seq_len:], index=cols) else: # 5.2历史行为不足40, padding到40个行为 pad_len = seq_len - len(x) x = x + ['0'] * pad_len return pd.Series(x, index=cols) # 6.预测目标的类别 labels = data['label'] data = data['hist_cate_list'].apply(trim_cate_list).join(data['cateID']) # 7.生成类别对应序号的编码器,如book->1,Russian->2这样 global cate_encoder cate_encoder = LabelEncoder().fit(list(cate_set)) print("cate_encoder is: ", cate_encoder) # 8.这里分为两步,第一步为把类别转化为数值,第二部为拼接上label data = data.apply(cate_encoder.transform).join(labels) return data # 对数据执行预处理操作,该操作由于是对表格逐行进行处理,因此可能会需要一点时间 data = AmazonBookPreprocess(data) cate_encoder is: LabelEncoder() 将data信息进行打印可以看到用户历史购买的序列与label数据集存储在data中总共包含40个用户历史行为类别信息,大部分用户历史购买数据长度均未达到40,因此在每一个用户后填充0。 每一行中具体的数字表示表示用户购买物品所属的类别,比如0行中138、138、138、138、138 表示用户0购买5个历史物品均属于138这个类别,推荐的商品类别是734,因此label值=0,表示用户不会点击购买推荐的734商品。 而第1行恰恰相反,138、138、138、138、138 表示用户1购买5个历史物品均属于138这个类别,推荐的商品类别是138,因此label值=1,表示用户很大概率会点击购买推荐的734商品。 data | | hist_cate_0 | hist_cate_1 | hist_cate_2 | hist_cate_3 | hist_cate_4 | hist_cate_5 | hist_cate_6 | hist_cate_7 | hist_cate_8 | hist_cate_9 | ... | hist_cate_32 | hist_cate_33 | hist_cate_34 | hist_cate_35 | hist_cate_36 | hist_cate_37 | hist_cate_38 | hist_cate_39 | cateID | label | | 0 | 138 | 138 | 138 | 138 | 138 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 734 | 0 | | 1 | 138 | 138 | 138 | 138 | 138 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 138 | 1 | | 2 | 138 | 138 | 138 | 138 | 95 | 138 | 138 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1071 | 0 | | 3 | 138 | 138 | 138 | 138 | 95 | 138 | 138 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 138 | 1 | | 4 | 138 | 138 | 138 | 138 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 138 | 0 | | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | | 89994 | 138 | 138 | 138 | 138 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 138 | 0 | | 89995 | 138 | 138 | 138 | 138 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 138 | 1 | | 89996 | 138 | 138 | 115 | 734 | 734 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 138 | 0 | | 89997 | 138 | 138 | 115 | 734 | 734 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 138 | 1 | 89999 rows × 42 columns 训练集与测试集划分 通过上述预处理后,我们得到了用户的历史输入数据与推商品的关联数据集,接下来我们需要将上述数据集进行划分以训练集、验证集与测试集。以便模型在训练好的能拥有更好泛化性与可靠性。 训练集与测试集的划分采用'train_test_split',该方法集成在'sklearn.model_selection'库中,提供了数据切分、交叉验证与网格搜索等功能,本文用到的是数据划分功能。 将模型输入与输出进行组合划分训练集、测试集与验证集三个集合,首先从总体数据量上将训练集与测试集以8:2(test_size = 0.2)的比例进行划分,然后再讲训练集中数据按照7.5:2.5(test_size = 0.25)比例划分训练集与验证集。 import torch.utils.data as Data from sklearn.model_selection import train_test_split #模型输入 data_X = data.iloc[:,:-1] #模型输出 data_y = data.label.values #划分训练集,测试集,验证集 tmp_X, test_X, tmp_y, test_y = train_test_split(data_X, data_y, test_size = 0.2, random_state=42, stratify=data_y) train_X, val_X, train_y, val_y = train_test_split(tmp_X, tmp_y, test_size = 0.25, random_state=42, stratify=tmp_y) dis_test_x = test_X dis_test_y = test_y # numpy转化为torch train_X = torch.from_numpy(train_X.values).long() val_X = torch.from_numpy(val_X.values).long() test_X = torch.from_numpy(test_X.values).long() train_y = torch.from_numpy(train_y).long() val_y = torch.from_numpy(val_y).long() test_y = torch.from_numpy(test_y).long() # 设置dataset train_set = Data.TensorDataset(train_X, train_y) val_set = Data.TensorDataset(val_X, val_y) test_set = Data.TensorDataset(test_X, test_y) # 设置数据集加载器,用于模型训练,按批次输入数据 train_loader = Data.DataLoader(dataset=train_set, batch_size=32, shuffle=True) val_loader = Data.DataLoader(dataset=val_set, batch_size=32, shuffle=False) test_loader = Data.DataLoader(dataset=test_set, batch_size=32, shuffle=False) 模型训练过程定义 上述步骤已经分别将模型构建与数据集处理完成,接下来就是需要对模型进行训练。由于本文实验数据与模型需要运行在npu上,因此需要指定'device'是'npu',此外,该模型实现使用pytorch,目前npu对pytorch适配度非常高,可以使用'transfer_to_npu'将pytorch模型无感迁移到npu上运行。 import torch_npu from torch_npu.contrib import transfer_to_npu device="npu" /home/pengyongrong/miniconda3/envs/ctrExperiments/lib/python3.9/site-packages/torch_npu/contrib/transfer_to_npu.py:211: ImportWarning: ************************************************************************************************************* The torch.Tensor.cuda and torch.nn.Module.cuda are replaced with torch.Tensor.npu and torch.nn.Module.npu now.. The torch.cuda.DoubleTensor is replaced with torch.npu.FloatTensor cause the double type is not supported now.. The backend in torch.distributed.init_process_group set to hccl now.. The torch.cuda.* and torch.cuda.amp.* are replaced with torch.npu.* and torch.npu.amp.* now.. The device parameters have been replaced with npu in the function below: torch.logspace, torch.randint, torch.hann_window, torch.rand, torch.full_like, torch.ones_like, torch.rand_like, torch.randperm, torch.arange, torch.frombuffer, torch.normal, torch._empty_per_channel_affine_quantized, torch.empty_strided, torch.empty_like, torch.scalar_tensor, torch.tril_indices, torch.bartlett_window, torch.ones, torch.sparse_coo_tensor, torch.randn, torch.kaiser_window, torch.tensor, torch.triu_indices, torch.as_tensor, torch.zeros, torch.randint_like, torch.full, torch.eye, torch._sparse_csr_tensor_unsafe, torch.empty, torch._sparse_coo_tensor_unsafe, torch.blackman_window, torch.zeros_like, torch.range, torch.sparse_csr_tensor, torch.randn_like, torch.from_file, torch._cudnn_init_dropout_state, torch._empty_affine_quantized, torch.linspace, torch.hamming_window, torch.empty_quantized, torch._pin_memory, torch.autocast, torch.load, torch.Generator, torch.Tensor.new_empty, torch.Tensor.new_empty_strided, torch.Tensor.new_full, torch.Tensor.new_ones, torch.Tensor.new_tensor, torch.Tensor.new_zeros, torch.Tensor.to, torch.nn.Module.to, torch.nn.Module.to_empty ************************************************************************************************************* warnings.warn(msg, ImportWarning) 通常来说,训练一个模型通常需要定义损失函数、定义优化器、定义模型参数可更新及遍历数据集训练模型四个步骤。前三个步骤比较直接,最后一个步骤在使用数据集训练模型过程中,需要根据输入数据给到模型获得预测的结果,计算损失、反向传播后进行参数更新。 据上述分析,我们定义了'train(model)'函数来实现整个模型的训练过程,入参为'model'表示需要训练的模型,具体的步骤解释均在代码中注解。 import torch.optim as optim import torch.nn.functional as F from sklearn.metrics import roc_auc_score def train(model): # 1.设置迭代次数训练模型 for epoch in range(epoches): train_loss = [] # 1.1设置二分类交叉熵损失函数 criterion = nn.BCELoss() # 1.2设置adam优化器 optimizer = optim.Adam(model.parameters(), lr = 0.001) # 1.3设置模型训练,此时模型参数可以更新 model.train() # 1.4遍历训练数据集,获取每个梯度的大小,输入输出 for batch, (x, y) in enumerate(train_loader): # 1.4.1如果有gpu则把数据放入显存中计算,没有的话用cpu计算 x=x.to(device) y=y.to(device) # 1.4.2数据输入模型 pred = model(x) # 1.4.3计算损失 loss = criterion(pred, y.float().detach()) # 1.4.4优化器梯度清空 optimizer.zero_grad() # 1.4.5方向传播,计算梯度 loss.backward() # 1.4.6优化器迭代模型参数 optimizer.step() # 1.4.7记录模型损失数据 train_loss.append(loss.item()) # 1.5模型固化,不修改梯度 model.eval() val_loss = [] prediction = [] y_true = [] with torch.no_grad(): # 1.6遍历验证数据集,获取每个梯度的大小,输入输出 for batch, (x, y) in enumerate(val_loader): # 1.6.1如果有gpu则把数据放入显存中计算,没有的话用cpu计算 x=x.to(device) y=y.to(device) # 1.6.2模型预测输入 pred = model(x) # 1.6.3计算损失函数 loss = criterion(pred, y.float().detach()) val_loss.append(loss.item()) prediction.extend(pred.tolist()) y_true.extend(y.tolist()) # 1.7计算auc得分 val_auc = roc_auc_score(y_true=y_true, y_score=prediction) # 1.8输出模型训练效果 print ("EPOCH %s train loss : %.5f validation loss : %.5f validation auc is %.5f" % (epoch, np.mean(train_loss), np.mean(val_loss), val_auc)) return train_loss, val_loss, val_auc 使用Amazon-book训练wideWeep模型 # 计算出现的最大类别编码是多少,目的为统计一共有多少个商品类别 fields = data.max().max() # 定义din模型 model = DeepInterestNet(feature_dim=fields, embed_dim=8, mlp_dims=[64,32], dropout=0.2).to(device) # 迭代次数 epoches = 5 # 模型训练 _= train(model) EPOCH 0 train loss : 0.69174 validation loss : 0.68478 validation auc is 0.53995 EPOCH 1 train loss : 0.68359 validation loss : 0.67958 validation auc is 0.57892 EPOCH 2 train loss : 0.67868 validation loss : 0.67763 validation auc is 0.58612 EPOCH 3 train loss : 0.67605 validation loss : 0.67401 validation auc is 0.59358 EPOCH 4 train loss : 0.67428 validation loss : 0.67516 validation auc is 0.59542 评估模型性能 通过上述步骤我们将整个模型在Amazon-book数据集上进行了训练,并且得到了较不错的准确率,接下来我们使用测试集中的某个样例对模型进行测试。 #从换分的测试数据集中取出一个数据,从该数据可以看出用户感兴趣的类别是Books,推荐的类别也是Books因此,用户很有可能会点击购买该商品对应label值是1。 dis_test_x.apply(cate_encoder.inverse_transform).reset_index().head(1) | | index | hist_cate_0 | hist_cate_1 | hist_cate_2 | hist_cate_3 | hist_cate_4 | hist_cate_5 | hist_cate_6 | hist_cate_7 | hist_cate_8 | ... | hist_cate_31 | hist_cate_32 | hist_cate_33 | hist_cate_34 | hist_cate_35 | hist_cate_36 | hist_cate_37 | hist_cate_38 | hist_cate_39 | cateID | 1 rows × 42 columns #由于本轮实验需要运行在npu上,因此需要将模型输入的向量加载到npu设备上 inputTensor = test_X[0].to(device) inputTensor tensor([138, 138, 138, 138, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138], device='npu:0') #将输入给到模型,得到预测购买的概率为0.4946,该值与标签label=1,有较大差距是因为模型只迭代训练5次,可以增加训练迭代次数以后再进行测试。 model(torch.unsqueeze(inputTensor, 0)) Warning: Device do not support double dtype now, dtype cast repalce with float. tensor([0.4946], device='npu:0', grad_fn=<SigmoidBackward0>) 内存使用情况: 整个训练过程的内存使用情况可以通过"npu-smi info"命令在终端查看,因此本文实验只用到了单个npu卡(也就是chip 0),内存占用约141M,对内存、精度或性能优化有兴趣的可以自行尝试进行优化,这里运行过程中也有其他程序在运行,因此本实验用到的网络所需要的内存已单独框出来。 Reference ========= \[1\] Zhou, Guorui , et al. "Deep Interest Network for Click-Through Rate Prediction." (2017).
2025年-4月-28日
8 阅读
0 评论
人工智能
2025-4-27
基于Pytorch Gemotric在昇腾上实现GAT图神经网络
本实验主要介绍了如何在昇腾上,使用pytorch对经典的图神经网络GAT在论文引用数据集Pubmed上进行分类训练的实战讲解。内容包括GAT网络创新点分析、图注意力机制原理与架构剖析、多头注意力机制分析与GAT网络模型代码实战分析等等。 本实验的目录结构安排如下所示: GAT网络创新点分析 图注意力机制原理与架构分析 多头注意力机制分析 GAT网络用于Pubmed数据集分类实战 GAT网络创新点分析 注意机制已成功用于许多基于序列的任务,例如机器翻译,机器阅读等等。与GCN平等对待节点的所有邻居相比,注意力机制可以为每个邻居分配不同的注意力得分,从而识别出更重要的邻居。将注意力机制纳入图谱神经网络的传播步骤是很直观的。图注意力网络也可以看作是图卷积网络家族中的一种方法。其创新点如下: GAT是一种图结构化数据上操作的新型神经网络架构,利用掩码自注意力层来解决基于图卷积或其近似值的现有方法的缺点。 GAT网络对不同的相邻节点分配相应的权重,既不需要矩阵运算,也不需要事先知道图结构。 GAT网络克服了基于谱神经网络的几个关键挑战,使得模型更加适用于归纳问题以及转导问题。 在Cora、Citeseer和Pubmed引文网络数据集上取得了非常好的效果。 图注意力机制原理与架构分析 图中输入由N个节点组成,每个节点feature数为F(也就是feature vector长度),下述两个公式分别表示输入的节点向量通过GAT网络进行注意力计算后得到的输出。 Input: $h = { \\vec{h_1}, \\vec{h_2}, . . . , \\vec{h_N} },\\vec h_i \\in R\^{F} $ Output: $h = { \\vec{h_1\^{'}}, \\vec{h_2\^{'}}, . . . , \\vec{h_N\^{'}} },\\vec h_i\^{'} \\in R\{F\{'}} $ 为了将输入的特征转换为高维的特征,这里至少需要一个科学系的线性转换。在 (Velickovic et al.,2017)中,作者对于每一个点使用了一个共享的线性转换方式,同时介绍了一个权重矩阵来参数化线性转换。对于节点中的每两个node间都有了相互关注机制(用来做加权平均,卷积时每个node的更新是其他的加权平均)。 计算节点与节点的相关性系数(注意力值): 先初步计算节点i与节点j的相关性:其中a是一个共享的权重系数,执行的是 计算节点i与节点j的相关性(归一化)$ \\alpha_{i, j} = softmax_j(e_{ij}) = \\frac {exp(e_{ij})} {\\sum_{k \\in N_i}exp(e_{ik})} $ 论文中采取取的计算attention coefficient的函数a是一个单层的前馈网络,经LeakyReLU处理得最终的: $\\alpha_{i, j} = \\frac {exp(LeakyReLU({\\vec a\^T}\[W\\vec{h_i} \|\| W \\vec{h_j}\]))} {\\sum_{k \\in N_i}exp(LeakyReLU(\\vec a\^T\[W \\vec{h_i} ,W \\vec{h_k}\])} $ 式中 \|\| 表示串联/连接,一旦获得,归一化的相互注意系数用来计算对应特征的线性组合,以用作每个节点的最终输出特征。 左图表示在模型中应用注意机制a(W \* h_i ,W \* h_j) 通过权重向量参数化,应用LeakyReLU 激活输出。 右图表示在邻域中具有多端连接,不同的箭头样式表示独立的注意力计算,通过直连concat或平均avg获取。 多头注意力机制分析 对于图中多头注意力情况,对应上图中右图情景,不只用一个函数进行attention coefficient的计算,而是设置K个函数,每一个函数都能计算出一组attention coefficient,并能计算出一组加权求和用的系数,每一个卷积层中,K个attention机制独立的工作,分别计算出自己的结果后连接在一起,得到卷积的结果。 我们知道对于单个注意力层输出计算如下: 对于有k个独立的相互注意机制同时计算,则集中其特征,可得到特征表示如下: 分别遍历1\~k个头,每一个上按照下述公式计算: 对于网络的最后一层卷积层,如果还是使用multi-head attention机制,那么就不采取连接的方式合并不同的attention机制的结果了,而是采用求平均的方式进行处理。 GAT网络用于Pubmed数据集分类实战 #导入torch相关库 import torch import torch.nn.functional as F 该实验需要跑在npu上,因此需要导入Npu相关库使得模型快速迁移到npu上运行 import torch_npu from torch_npu.contrib import transfer_to_npu /home/pengyongrong/miniconda3/envs/AscendCExperiments/lib/python3.9/site-packages/torch_npu/dynamo/__init__.py:18: UserWarning: Register eager implementation for the 'npu' backend of dynamo, as torch_npu was not compiled with torchair. warnings.warn( /home/pengyongrong/miniconda3/envs/AscendCExperiments/lib/python3.9/site-packages/torch_npu/contrib/transfer_to_npu.py:164: ImportWarning: ************************************************************************************************************* The torch.Tensor.cuda and torch.nn.Module.cuda are replaced with torch.Tensor.npu and torch.nn.Module.npu now.. The torch.cuda.DoubleTensor is replaced with torch.npu.FloatTensor cause the double type is not supported now.. The backend in torch.distributed.init_process_group set to hccl now.. The torch.cuda.* and torch.cuda.amp.* are replaced with torch.npu.* and torch.npu.amp.* now.. The device parameters have been replaced with npu in the function below: torch.logspace, torch.randint, torch.hann_window, torch.rand, torch.full_like, torch.ones_like, torch.rand_like, torch.randperm, torch.arange, torch.frombuffer, torch.normal, torch._empty_per_channel_affine_quantized, torch.empty_strided, torch.empty_like, torch.scalar_tensor, torch.tril_indices, torch.bartlett_window, torch.ones, torch.sparse_coo_tensor, torch.randn, torch.kaiser_window, torch.tensor, torch.triu_indices, torch.as_tensor, torch.zeros, torch.randint_like, torch.full, torch.eye, torch._sparse_csr_tensor_unsafe, torch.empty, torch._sparse_coo_tensor_unsafe, torch.blackman_window, torch.zeros_like, torch.range, torch.sparse_csr_tensor, torch.randn_like, torch.from_file, torch._cudnn_init_dropout_state, torch._empty_affine_quantized, torch.linspace, torch.hamming_window, torch.empty_quantized, torch._pin_memory, torch.Tensor.new_empty, torch.Tensor.new_empty_strided, torch.Tensor.new_full, torch.Tensor.new_ones, torch.Tensor.new_tensor, torch.Tensor.new_zeros, torch.Tensor.to, torch.nn.Module.to, torch.nn.Module.to_empty ************************************************************************************************************* warnings.warn(msg, ImportWarning) 由于torch_geometric中集成了单层的GATConv模块,这里直接进行导入,若有兴趣可以自行实现该类,注意输入与输出对齐即可。此外,数据集用的是Pubmed,该数据集也直接集成在Planetoid模块中,这里也需要将其import进来。 from torch_geometric.nn import GATConv from torch_geometric.datasets import Planetoid /home/pengyongrong/miniconda3/envs/AscendCExperiments/lib/python3.9/site-packages/torch_npu/contrib/transfer_to_npu.py:124: RuntimeWarning: torch.jit.script will be disabled by transfer_to_npu, which currently does not support it. warnings.warn(msg, RuntimeWarning) Pubmed数据集介绍 PubMed数据集是一个广泛用于图神经网络(GNN)研究的基准数据集,主要用于节点分类任务。其由生物医学文献组成,每篇文献被视为一个节点,引用关系被视为边。该数据集包含三类糖尿病相关的论文,每个节点都带有特征向量和标签。 数据集一共有19717个节点 ,每一个节点代表一篇生物医学文献,每个节点有一个500 维的特征向量,用来表示该医学文献的内容。总共含44338条边 ,每条边表示一篇文献对另一篇文献的引用关系,边与边之间是无向的,因此可以看做是对称的。总类别数包含Diabetes Mellitus Experiment、Diabetes Mellitus Type 1与Diabetes Mellitus Type2三类。 # 加载数据 print("===== begin Download Dadasat=====\n") dataset = Planetoid(root='/home/pengyongrong/workspace/data', name='PubMed') print("===== Download Dadasat finished=====\n") print("dataset num_features is: ", dataset.num_features) print("dataset.num_classes is: ", dataset.num_classes) print("dataset.edge_index is: ", dataset.edge_index) print("train data is: ", dataset.data) print("dataset0 is: ", dataset[0]) print("train data mask is: ", dataset.train_mask, "num train is: ", (dataset.train_mask ==True).sum().item()) print("val data mask is: ",dataset.val_mask, "num val is: ", (dataset.val_mask ==True).sum().item()) print("test data mask is: ",dataset.test_mask, "num test is: ", (dataset.test_mask ==True).sum().item()) ===== begin Download Dadasat===== ===== Download Dadasat finished===== dataset num_features is: 500 dataset.num_classes is: 3 dataset.edge_index is: tensor([[ 1378, 1544, 6092, ..., 12278, 4284, 16030], [ 0, 0, 0, ..., 19714, 19715, 19716]]) train data is: Data(x=[19717, 500], edge_index=[2, 88648], y=[19717], train_mask=[19717], val_mask=[19717], test_mask=[19717]) dataset0 is: Data(x=[19717, 500], edge_index=[2, 88648], y=[19717], train_mask=[19717], val_mask=[19717], test_mask=[19717]) train data mask is: tensor([ True, True, True, ..., False, False, False]) num train is: 60 val data mask is: tensor([False, False, False, ..., False, False, False]) num val is: 500 test data mask is: tensor([False, False, False, ..., True, True, True]) num test is: 1000 /home/pengyongrong/miniconda3/envs/AscendCExperiments/lib/python3.9/site-packages/torch_geometric/data/in_memory_dataset.py:300: UserWarning: It is not recommended to directly access the internal storage format `data` of an 'InMemoryDataset'. If you are absolutely certain what you are doing, access the internal storage via `InMemoryDataset._data` instead to suppress this warning. Alternatively, you can access stacked individual attributes of every graph via `dataset.{attr_name}`. warnings.warn(msg) 下载后的pubmed数据集总共包含8个文件,分别是ind.pubmed.x、ind.pubmed.tx、ind.pubmed.all、ind.pubmed.y、ind.pubmed.ty、ind.pubmed.ally、ind.pubmed.graph与ind.pubmed.test.index。每个文件的作用说明如下: ind.pubmed.x:训练集节点特征向量,大小(140,1433) ind.pubmed.tx:测试集节点特征向量,实际展开后大小为(1000,1433) ind.pubmed.allx:包含标签核无标签的训练节点特征向量(1708,1433) ind.pubmed.y:one-hot表示的训练节点的标签 ind.pubmed.ty:one-hot表示的测试节点的标签 ind.pubmed.ally:one-hot表示的ind.cora.allx对应的标签 ind.pubmed.graph:保存节点之间边的信息 ind.pubmed.test.index:保存测试集节点的索引,用于后面的归纳学习设置 从打印结果可以看出,数据集的特点与上述描述的相对应,GAT_NET网络定义了一个两层的GAT网络,heads的数量设置成4。 开启Pubmed数据训练过程 class GAT_NET(torch.nn.Module): def __init__(self, features, hidden, classes, heads=4): super(GAT_NET, self).__init__() # 定义GAT层,使用多头注意力机制 self.gat1 = GATConv(features, hidden, heads=4) # 因为多头注意力是将向量拼接,所以维度乘以头数。 self.gat2 = GATConv(hidden*heads, classes) def forward(self, data): # 从输入数据集中获取x与边集相关信息 x, edge_index = data.x, data.edge_index # 将输入传入GAT层中,获得第一层Gat层的输出 x = self.gat1(x, edge_index) # 经过非线性激活与dropout,减少过拟合现象,增加模型的泛化能力 x = F.relu(x) x = F.dropout(x, training=self.training) # 第二层GAT层,得到整个网络的输出送给分类器进行分类 x = self.gat2(x, edge_index) return F.log_softmax(x, dim=1) 定义设备跑在Npu上,这里如果需要替换成Gpu或Cpu,则替换成'cuda'或'cpu'即可。 device = 'npu' 定义GAT_NET网络,中间隐藏层节点个数定义为16,'dataset.num_classes'为先前数据集中总的类别数,这里是7类。'to()'的作用是将该加载到指定模型设备上。优化器用的是'optim'中的'Adam'。 model = GAT_NET(dataset.num_node_features, 16, dataset.num_classes).to(device) # 定义GraphSAGE data = dataset[0].to(device) optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4) 开始训练模型,指定训练次数200次,训练后采用极大似然用作损失函数计算损失,然后进行反向传播更新模型的参数,训练完成后,用验证集中的数据对模型效果进行验证,最后打印模型的准确率。 model.train() for epoch in range(200): optimizer.zero_grad() out = model(data) loss = F.nll_loss(out[data.train_mask], data.y[data.train_mask]) loss.backward() optimizer.step() # 模型验证过程,对训练得到的模型效果进行评估,并打印准确率。 model.eval() _, pred = model(data).max(dim=1) correct = int(pred[data.test_mask].eq(data.y[data.test_mask]).sum().item()) acc = correct / int(data.test_mask.sum()) print('GAT Accuracy: {:.4f}'.format(acc)) [W VariableFallbackKernel.cpp:51] Warning: CAUTION: The operator 'aten::scatter_reduce.two_out' is not currently supported on the NPU backend and will fall back to run on the CPU. This may have performance implications. (function npu_cpu_fallback) GAT Accuracy: 0.3660 内存使用情况: 整个训练过程的内存使用情况可以通过"npu-smi info"命令在终端查看,因此本文实验只用到了单个npu卡(也就是chip 0),内存占用约573M,对内存、精度或性能优化有兴趣的可以自行尝试进行优化。 Reference ========= \[1\] Velikovi, Petar , et al. "Graph Attention Networks." (2017).
2025年-4月-27日
11 阅读
0 评论
人工智能
2025-4-27
陶瓷绝缘子缺陷检测数据集VOC+YOLO格式2908张3类别
数据集中存在部分增强,具体看图片 数据集格式:Pascal VOC格式+YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):2908 标注数量(xml文件个数):2908 标注数量(txt文件个数):2908 标注类别数:3 标注类别名称(注意yolo格式类别顺序不和这个对应,而以labels文件夹classes.txt为准):["broken","flashover","insulator"] 每个类别标注的框数: broken 框数 = 3817 flashover 框数 = 782 insulator 框数 = 2557 总框数:7156 使用标注工具:labelImg 标注规则:对类别进行画矩形框 重要说明:暂无 特别声明:本数据集不对训练的模型或者权重文件精度作任何保证,数据集只提供准确且合理标注 图片预览: 标注例子:
2025年-4月-27日
7 阅读
0 评论
人工智能
2025-4-27
基于Pytorch 在昇腾上实现GCN图神经网络
本文主要介绍了如何在昇腾上,使用pytorch对经典的图神经网络GCN在论文引用Cora数据集上进行分类训练的实战讲解。内容包括GCN背景介绍、模型特点介绍、GCN网络架构剖析与GCN网络模型代码实战分析等等。 本文的目录结构安排如下所示: GCN网络背景介绍 模型特点介绍 GCN网络架构剖析 GCN网络用于Cora数据集分类实战 GCN网络背景介绍 多层感知机、卷积神经网络、循环神经网络和自编码器等深度学习模型通过对输入的数据进行逐层的特征提取和筛选,可以完成分类和预测等任务,在计算机视觉和语音识别等领域已被广泛应用。但上述模型只能处理具有固定排列规则和顺序的欧氏结构数据,对于一些非规则排布的非欧式数据显得有些则力不从心。随着非欧式数据结构被越来越多的实际问题应用所需要,针对处理非欧氏结构数据的深度学习模型图神经网络(Graph Neural Networks, GNN)应运而生。 图神经网络的本质就是:图中的任何一个节点,都受到和它相连的其他节点的影响,距离越近影响则越大。一个图中的所有节点间的互动关系和每个节点本身的信息,就构成了这整张图的全部信息。 由于CNN已经是个相当成熟的技术了,聚合"邻居"的信息并不是什么少见的思路。显然,从GNN出现开始,就必然会有人尝试在GNN上进行类似CNN的"聚合节点信息"操作。事实上在GCN之前,就已经有一些关于类似的研究了。但不外乎存在计算量大、聚合效果差、卷积核复杂的问题。 模型特点介绍 GCN是GNN的一个分支,全称为图卷积神经网络,顾名思义,GCN是在图上进行"卷积"操作的GNN,这里用引号是因为,GCN的操作并不是卷积神经网络里的那个卷积,这里的卷积,是因为GCN的运算是在聚合节点周围其他节点的信息,与卷积神经网络(CNN)的行为类似。不过话说回来,CNN里的"卷积",也并不是不是数学意义上的卷积。 GCN的创新之处在于,提出了一种简化到在计算量上可行且效果好的"卷积"计算方案。GCN利用拉普拉斯变换变化,利用邻接矩阵算出了这个滤波矩阵,然后利用这个滤波矩阵进行层间传播。 其迭代间节点核心更新计算公式如下: 其中表示邻接矩阵的度矩阵,表示整张图的邻接矩阵(含自回环,也就是加了单位矩阵),X表示节点在k-1层的特征向量,是k-1层的卷积参数。 GCN的上述公式表达的是从整个图的角度来考虑和描述的。从单个节点来说,每个节点的特征向量可以表示为的变换 (前向传播) 的向量形式可以表示为如下: 其中是权重矩阵 (即模型学习过程中要更新的参数),表示节点i在第k次迭代的特征向量,deg(i)表示节点i的度,N(i)表示节点i所有邻接节点的集合。 GCN网络架构剖析 GCN定义了一个两层的模型,中间隐藏的节点个数可以自设,后面输出层可以结合具体数据集类别设置使用,当然也可以跟训练类别设置不一致,只需要在后面接一个分类器即可(后再接一个全连接层)。 MessagePassing模块是图神经网络(Graph Neural Networks,GNNs)的一个基础组件,它被设计用来处理图形数据的问题。在图形数据中,数据点(节点)之间的关系(边)是非常重要的信息。MessagePassing通过在节点之间传递和聚合信息,使得每个节点都能获取其邻居节点的信息,从而更好地理解图形的结构和特性。里面'propagate'函数与'aggregate'函数用于实现节点之间的传播与聚合功能。 # 导入torch及相关库,便于后续搭建网络调用基础算子模块 import torch import torch.nn.functional as F from torch_geometric.nn import MessagePassing 在图神经网络(GNN)的实现中,对图结构的调整和优化是提升模型性能的关键手段之一。'add_self_loops'函数在PyTorch的图处理库中用于向图中添加自环(self-loops),即连接节点自身的边。'degree'用来计算一个无权图的入度矩阵。 from torch_geometric.utils import add\_self\_loops, degree GCN实现继承了'MessagePassing'类,线性变换功能在'init'函数中通过'self.lin'为线性变换函数定义,具体特征维度的逻辑在'forward()'中实现,'init'函数中入参'in_channel'是每个节点输入特征的维度,'out_channels'是每个节点输出特征的维度,这一部分对应上述公式中的X。输入的特征矩阵维度是(N, in_channels),输出的特征矩阵维度是(N, out_channels),其中 N 是节点个数。 在'forward()'函数中'edge_index, _ = add_self_loops(edge_index, num_nodes=x.size(0))'是给邻接矩阵加上self loops,也即构造出矩阵 ,在torch geometric中,无权图的邻接矩阵表示为2维数组(COO存储格式),第1行表示边的起始节点(source 节点),第2行表示边的目标节点(target节点)。 对于'message()'函数而言,函数入参'x_j' 的形状是\[E, out_channels\],其中E表示边的数量。由上面可知,特征矩阵经过线性变换后的输出形状是(N, out_channels),边的矩阵的形状为 \[2, E\]。'row, col = edge_index'表示取出所有边的起始节点和目标节点,row表示边的起始节点的结合,col表示边的目标节点的集合。在无向图中,这两者是等价的。以target节点作为索引,从线性变换后的特征矩阵中索引得到target节点的特征矩阵。 class GCNConv(MessagePassing): def __init__(self, in_channels, out_channels): # "Add" aggregation. super(GCNConv, self).__init__(aggr='add') self.lin = torch.nn.Linear(in\_channels, out\_channels) def forward(self, x, edge_index): # x has shape \[N, in_channels\] # edge_index has shape \[2, E\] # Step 1: Add self-loops to the adjacency matrix. edge_index, _ = add_self_loops(edge_index, num_nodes=x.size(0)) # Step 2: Linearly transform node feature matrix. x = self.lin(x) # Step 3-5: Start propagating messages. return self.propagate(edge_index, size=(x.size(0), x.size(0)), x=x) def message(self, x_j, edge_index, size): # x_j has shape [E, out_channels] # edge_index has shape [2, E] # Step 3: Normalize node features. row, col = edge_index # [N, ] deg = degree(row, size[0], dtype=x_j.dtype) # [N, ] deg_inv_sqrt = deg.pow(-0.5) norm = deg_inv_sqrt[row] * deg_inv_sqrt[col] return norm.view(-1, 1) * x_j def update(self, aggr_out): # aggr_out has shape [N, out_channels] # Step 5: Return new node embeddings. return aggr_out 上述类目前已经集成在torch_geometric.nn模块中,也可以使用下述一行代码替换 'from torch_geometric.nn import GCNConv' 导入GCN层替换GCNConv类定义。 Planetoid集成了论文引用中Cora,CiteSeer,PubMed三个数据集,由于本实验需要用到Cora数据集,因此此处需要导入该模块用于加载数据集。 from torch_geometric.datasets import Planetoid 定义GCN_NET图网络,中间构造一个隐藏层用来辅助实现线性转换过程。 class GCN_NET(torch.nn.Module): def __init__(self, features, hidden, classes): super(GCN_NET, self).__init__() # shape(输入的节点特征维度 * 中间隐藏层的维度) self.conv1 = GCNConv(features, hidden) # shaape(中间隐藏层的维度 * 节点类别) self.conv2 = GCNConv(hidden, classes) def forward(self, data): # 加载节点特征和邻接关系 x, edge_index = data.x, data.edge_index # 传入卷积层 x = self.conv1(x, edge_index) # 激活函数 x = F.relu(x) # dropout层,防止过拟合 x = F.dropout(x, training=self.training) # 第二层卷积层 x = self.conv2(x, edge_index) # 将经过两层卷积得到的特征输入log_softmax函数得到概率分布 return F.log_softmax(x, dim=1) GCN网络用于Cora数据集分类实战 本实验需要跑在npu上,因此需要导入Npu相关库,以便于模型能够跑在Npu上。 import torch_npu from torch_npu.contrib import transfer_to_npu /home/pengyongrong/miniconda3/envs/AscendCExperiments/lib/python3.9/site-packages/torch_npu/dynamo/init.py:18: UserWarning: Register eager implementation for the 'npu' backend of dynamo, as torch_npu was not compiled with torchair.warnings.warn(/home/pengyongrong/miniconda3/envs/AscendCExperiments/lib/python3.9/site-packages/torch_npu/contrib/transfer_to_npu.py:164: ImportWarning: The torch.Tensor.cuda and torch.nn.Module.cuda are replaced with torch.Tensor.npu and torch.nn.Module.npu now..The torch.cuda.DoubleTensor is replaced with torch.npu.FloatTensor cause the double type is not supported now..The backend in torch.distributed.init_process_group set to hccl now.. The torch.cuda.\* and torch.cuda.amp.\* are replaced with torch.npu.\* and torch.npu.amp.\* now.. The device parameters have been replaced with npu in the function below: torch.logspace, torch.randint, torch.hann_window, torch.rand, torch.full_like, torch.ones_like, torch.rand_like, torch.randperm, torch.arange, torch.frombuffer, torch.normal, torch._empty_per_channel_affine_quantized, torch.empty_strided, torch.empty_like, torch.scalar_tensor, torch.tril_indices, torch.bartlett_window, torch.ones, torch.sparse_coo_tensor, torch.randn, torch.kaiser_window, torch.tensor, torch.triu_indices, torch.as_tensor, torch.zeros, torch.randint_like, torch.full, torch.eye, torch._sparse_csr_tensor_unsafe, torch.empty, torch._sparse_coo_tensor_unsafe, torch.blackman_window, torch.zeros_like, torch.range, torch.sparse_csr_tensor, torch.randn_like, torch.from_file, torch._cudnn_init_dropout_state, torch._empty_affine_quantized, torch.linspace, torch.hamming_window, torch.empty_quantized, torch._pin_memory, torch.Tensor.new_empty, torch.Tensor.new_empty_strided, torch.Tensor.new_full, torch.Tensor.new_ones, torch.Tensor.new_tensor, torch.Tensor.new_zeros, torch.Tensor.to, torch.nn.Module.to, torch.nn.Module.to_empty\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*warnings.warn(msg, ImportWarning) /home/pengyongrong/miniconda3/envs/AscendCExperiments/lib/python3.9/site-packages/torch_npu/dynamo/init.py:18: UserWarning: Register eager implementation for the 'npu' backend of dynamo, as torch_npu was not compiled with torchair.warnings.warn(/home/pengyongrong/miniconda3/envs/AscendCExperiments/lib/python3.9/site-packages/torch_npu/contrib/transfer_to_npu.py:164: ImportWarning: The torch.Tensor.cuda and torch.nn.Module.cuda are replaced with torch.Tensor.npu and torch.nn.Module.npu now..The torch.cuda.DoubleTensor is replaced with torch.npu.FloatTensor cause the double type is not supported now..The backend in torch.distributed.init_process_group set to hccl now.. The torch.cuda.\* and torch.cuda.amp.\* are replaced with torch.npu.\* and torch.npu.amp.\* now.. The device parameters have been replaced with npu in the function below: torch.logspace, torch.randint, torch.hann_window, torch.rand, torch.full_like, torch.ones_like, torch.rand_like, torch.randperm, torch.arange, torch.frombuffer, torch.normal, torch._empty_per_channel_affine_quantized, torch.empty_strided, torch.empty_like, torch.scalar_tensor, torch.tril_indices, torch.bartlett_window, torch.ones, torch.sparse_coo_tensor, torch.randn, torch.kaiser_window, torch.tensor, torch.triu_indices, torch.as_tensor, torch.zeros, torch.randint_like, torch.full, torch.eye, torch._sparse_csr_tensor_unsafe, torch.empty, torch._sparse_coo_tensor_unsafe, torch.blackman_window, torch.zeros_like, torch.range, torch.sparse_csr_tensor, torch.randn_like, torch.from_file, torch._cudnn_init_dropout_state, torch._empty_affine_quantized, torch.linspace, torch.hamming_window, torch.empty_quantized, torch._pin_memory, torch.Tensor.new_empty, torch.Tensor.new_empty_strided, torch.Tensor.new_full, torch.Tensor.new_ones, torch.Tensor.new_tensor, torch.Tensor.new_zeros, torch.Tensor.to, torch.nn.Module.to, torch.nn.Module.to_empty warnings.warn(msg, ImportWarning) Cora数据集介绍与加载 Cora数据集包含2708篇科学出版物,10556条边,总共7种类别,数据集中的每个出版物都由一个 0/1 值的词向量描述,表示字典中相应词的缺失/存在。该词典由1433个独特的词组成,意思就是说每一个出版物都由1433个特征构成,每个特征仅由0/1表示。 如图,节点大小对应进出边的数量,节点越大表示进出边的数量越多,边的粗细反映对应两节点之间的相似或关联程度越高,也就是对彼此的影响力权重越大。 由于cora数据集处理的是无向图,所以'in degree count'与'out degree count'分布图一致,底部的'nodes for a given out-degree'与'node degree'图统计的是数据集中出边的分布情况,可以看到峰值点出现在\[2, 4\]范围内,说明大多数的节点之间之间与少量的边进行相连,相连节点最多的边是图中绿色节点,约有169个节点相连。 下载后的数据集总共包含8个文件分别是ind.cora.x、ind.cora.tx、ind.cora.all、ind.cora.y、ind.cora.ty、ind.cora.ally、ind.cora.graph与ind.cora.test.index。 其中: ind.cora.x:训练集节点特征向量,大小(140,1433) ind.cora.tx:测试集节点特征向量,实际展开后大小为(1000,1433) ind.cora.allx:包含标签核无标签的训练节点特征向量(1708,1433) ind.cora.y:one-hot表示的训练节点的标签 ind.cora.ty:one-hot表示的测试节点的标签 ind.cora.ally:one-hot表示的ind.cora.allx对应的标签 ind.cora.graph:保存节点之间边的信息 ind.cora.test.index:保存测试集节点的索引,用于后面的归纳学习设置 上述介绍完cora数据集的基本组成情况,接下来我们通过Planetoid集成库来下载cora数据集,下载好以后对数据集中一些基本的信息进行打印。 import numpy as np # 加载数据,出错可自行下载,解决方案见下文 print("===== begin Download Dadasat=====\\n") dataset = Planetoid(root='/home/pengyongrong/workspace/data', name='Cora') print("===== Download Dadasat finished=====\\n") print("dataset num_features is: ", dataset.num_features) print("dataset.num_classes is: ", dataset.num_classes) print("dataset.edge_index is: ", dataset.edge_index) print("train data is: ", dataset.data) print("dataset0 is: ", dataset\[0\]) print("train data mask is: ", dataset.train_mask, "num train is: ", (dataset.train_mask ==True).sum().item()) print("val data mask is: ",dataset.val_mask, "num val is: ", (dataset.val_mask ==True).sum().item()) print("test data mask is: ",dataset.test_mask, "num test is: ", (dataset.test_mask ==True).sum().item()) ===== begin Download Dadasat===== ===== Download Dadasat finished===== dataset num_features is: 1433 dataset.num_classes is: 7 dataset.edge_index is: tensor(\[\[ 633, 1862, 2582, ..., 598, 1473, 2706\], \[ 0, 0, 0, ..., 2707, 2707, 2707\]\]) train data is: Data(x=\[2708, 1433\], edge_index=\[2, 10556\], y=\[2708\], train_mask=\[2708\], val_mask=\[2708\], test_mask=\[2708\]) dataset0 is: Data(x=\[2708, 1433\], edge_index=\[2, 10556\], y=\[2708\], train_mask=\[2708\], val_mask=\[2708\], test_mask=\[2708\]) train data mask is: tensor(\[ True, True, True, ..., False, False, False\]) num train is: 140 val data mask is: tensor(\[False, False, False, ..., False, False, False\]) num val is: 500 test data mask is: tensor(\[False, False, False, ..., True, True, True\]) num test is: 1000 /home/pengyongrong/miniconda3/envs/AscendCExperiments/lib/python3.9/site-packages/torch_geometric/data/in_memory_dataset.py:300: UserWarning: It is not recommended to directly access the internal storage format \data\ of an 'InMemoryDataset'. If you are absolutely certain what you are doing, access the internal storage via \InMemoryDataset._data\ instead to suppress this warning. Alternatively, you can access stacked individual attributes of every graph via \dataset.{attr_name}\. warnings.warn(msg) 本文用到的实验数据集这里已经下载好并保存在"/home/pengyongrong/workspace/data"目录下,若没有下载好启动该命令会自动下载数据集,整个下载过程可能会比较慢,也可以在https://github.com/D61-IA/FisherGCN/tree/a58c1613f1aca7077ef90af6e51a8021548cdb4c/data 自行选择下载。 从打印的信息可以看出来,每一个节点的特征维度为1433,也就是'datasat.numfeatures'的取值是1433;总的类别数是7,对应'datasat.numclasses';'dataset.edge_index'表示所有边与边之间的互联关系,采用coo存储格式,因为这里是无权边,因此只需要二维数组即可完成对应功能。 上述信息介绍完后就剩下训练集、验证集与测试集相关的信息,dataset\[0\]包含了所有信息,包括输入x,边信息、标签y及'train_mask'、'val_mask'与'test_mask'分别表示2708篇刊物中哪些用于训练,哪些用于验证及哪些用于测试。 开启cora数据训练过程 接下来就是将cora数据集送入搭建好的GCN网络模型中进行训练,训练过程中设置设备在npu上运行,并定义训练的'epoch=200',迭代次数可以根据需要自行更改,训练完成后对模型的效果进行评估并打印预测的准确率约为0.8。 #设置成npu device = 'npu' print("device is: ", device) # 构建模型,设置中间隐藏层维度为16 model = GCN_NET(dataset.num_node_features, 16, dataset.num_classes).to(device) # 加载数据 data = dataset[0].to(device) # 定义优化函数 optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4) model.train() for epoch in range(200): # 梯度设为零 optimizer.zero_grad() # 模型输出 out = model(data) # 计算损失 loss = F.nll_loss(out[data.train_mask], data.y[data.train_mask]) # 反向传播计算梯度 loss.backward() # 一步优化 optimizer.step() # 评估模型 model.eval() # 得到模型输出的类别 _, pred = model(data).max(dim=1) # 计算正确的个数 correct = int(pred[data.test_mask].eq(data.y[data.test_mask]).sum().item()) # 得出准确率 acc = correct / int(data.test_mask.sum()) # 打印准确率及结果 print('GCN Accuracy: {:.4f}'.format(acc)) device is: npuGCN Accuracy: 0.8040 内存使用情况: 整个训练过程的内存使用情况可以通过"npu-smi info"命令在终端查看,因此本文实验只用到了单个npu卡(也就是chip 0),内存占用约167M,对内存、精度或性能优化有兴趣的可以自行尝试进行优化,这里运行过程中也有其他程序在运行,因此本实验用到的网络所需要的内存已单独框出来。 Reference========= \[1\] Heidari, Negar , L. Hedegaard , and A. Iosifidis . "Graph convolutional networks." Deep Learning for Robot Perception and Cognition (2022).
2025年-4月-27日
7 阅读
0 评论
人工智能
2025-4-27
绝缘子缺陷检测数据集VOC+YOLO格式795张4类别
数据集格式:Pascal VOC格式+YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):795 标注数量(xml文件个数):795 标注数量(txt文件个数):795 标注类别数:4 标注类别名称(注意yolo格式类别顺序不和这个对应,而以labels文件夹classes.txt为准):["breakage","insulator","insulator_string_broken","pollution_flashover"] 每个类别标注的框数: breakage 框数 = 512 insulator 框数 = 974 insulator_string_broken 框数 = 239 pollution_flashover 框数 = 847 总框数:2572 使用标注工具:labelImg 标注规则:对类别进行画矩形框 重要说明:暂无 特别声明:本数据集不对训练的模型或者权重文件精度作任何保证,数据集只提供准确且合理标注 图片预览: 标注例子:
2025年-4月-27日
8 阅读
0 评论
人工智能
2025-4-22
入选AAAI 2025,浙江大学提出多对一回归模型M2OST,利用数字病理图像精准预测基因表达
数字病理图像作为一种全切片病理图像 (WSIs),能够对组织切片的高分辨率数字化呈现,全面展示细胞形态、结构和空间分布特征。与传统玻璃切片相比,WSIs 不仅便于存储和分析,还能在多个尺度上提供更直观的组织视图,因而在病理诊断与生物医学研究中应用日益广泛。通过对这些图像的分析,科研人员可以探索细胞空间组织与基因表达之间的内在联系,从而揭示多细胞系统中复杂的转录调控机制。 近年来,空间转录组学 (Spatial Transcriptomics, ST) 作为单细胞 RNA 测序的空间延伸技术,已成为研究细胞亚型分布、互作关系和分子机制的重要工具。然而,受限于其高昂的设备和试剂成本,ST 技术在实际应用中仍面临普及难题。相较之下,WSIs 更具经济性和可及性,在临床应用上更为经济且易于获取。因此,如何借助深度学习手段,从 WSIs 中低成本重建 ST 图谱,成为一个备受关注的研究方向。 现有方法多将 ST 预测问题视为传统的回归问题,使用单级图像 - 标签对进行训练。这使得它们只能对最大放大倍数图像的基因表达关系进行建模,浪费了 WSIs 固有的多尺度信息。 基于这一问题,中国浙江大学的林兰芬教授研究团队联合浙江杭州之江实验室以及日本立命馆大学共同提出了 M2OST,这是一种多对一回归 Transformer 模型,旨在利用不同层次的病理图像共同预测基因表达。 通过整合 WSIs 中的采样点视觉信息和多尺度特征,该模型能够生成更准确的 ST 图谱。此外,研究团队还将多对一的多层特征提取过程解耦为层内特征提取和跨层特征提取,在不影响模型性能的情况下大大降低了计算成本,优化了计算效率。 相关成果以「M2OST: Many-to-one Regression for Predicting Spatial Transcriptomics from Digital Pathology Images」为题,入选 AAAI 2025。 研究亮点: 将 ST 预测问题概念化为多对一建模问题,利用分层结构 WSIs 中嵌入的多尺度信息和点间特征,联合预测 ST 图谱 提出基于多对一回归的 Transformer 模型 M2OST,对不同序列长度的输入集具有鲁棒性 将 M2OST 中的多尺度特征提取过程解耦为层内特征提取和跨层特征提取,在不影响模型性能的情况下显著提高了计算效率 对提出的 M2OST 方法进行了全面的实验,并在 3 个公开的 ST 数据集上证明了其有效性 论文地址:https://arxiv.org/abs/2409.15092 关注公众号,后台回复「M2OST」获取完整 PDF 开源项目「awesome-ai4s」汇集了 200 余篇 AI4S 论文解读,并提供海量数据集与工具: https://github.com/hyperai/awesome-ai4s 数据集:使用 3 个 ST 数据集证明其有效性 研究团队使用了 3 个公开的 ST 数据集来评估所提出的 M2OST 模型的性能: *人类乳腺癌数据集 (HBC): 包含 68 个 WSI 中的 30,612 个点位,每个点位至多有 26,949 个不同的基因。该数据集中的点直径为 100μm,以 200μm 的中心距排列成网格。 *人类阳性乳腺肿瘤数据集 (HER2): 由 36 个病理图像和 13,594 个点位组成,每个点位包含 15,045 个已记录的基因表达数据。该数据集中的 ST 数据每个捕获点之间的中心距为 200μm,每个点的直径为 100μm。 *人类皮肤鳞状细胞癌数据集 (cSCC): 包括 12 个 WSI 和 8,671 个点位。该数据集中的每个点位都对 16,959 个基因进行了分析。所有点的直径为 110μm,排列成中矩形点阵,中心距为 150μm。 M2OST 模型:多对一回归结构,多层次病理图像共同预测基因表达 近年来,从全切片病理图像 (WSIs) 中预测空间转录组 (ST) 图谱成为当前数字病理学领域中的研究热点。早期方法如 ST-Net 和 DeepSpaCE 基于卷积神经网络 (CNN) 进行图像块级别的 ST 预测。近期发布的双模态嵌入框架 BLEEP 引入对比学习策略,将 WSI 图像块特征与 ST 点嵌入对齐,并引入 K 近邻算法缓解推理阶段的批次效应问题。 随着基于 Transformer 的模型兴起,其性能已超越传统 CNN。深度学习模型 HisToGene 首次将 Transformer 引入基因表达预测,实现玻片级建模,提升了效率但仍受限于计算资源。Hist2ST 模型在此基础上融合 CNN、Transformer 与图神经网络,进一步捕捉长距离依赖,但其复杂的模型结构也导致过拟合风险上升。 与主流关注采样点间相关性的思路不同,基于分层图像特征提取的方法 iStar,强调采样点内的基因表达仅与其对应的图像块区域相关,采用预训练的 HIPT 进行特征提取,并通过 MLP 映射至表达值,性能优越,但由于特征不可学习,仍存在进一步优化空间。 研究团队受此启发,M2OST 同样采用了图像块级方案,一次预测一个采样点,确保每个预测的独立性与准确性。 研究团队还进一步拓展了 iStar 的思路,设计了一套可学习的多尺度特征提取与融合模块,通过对局部区域的精细建模和跨尺度信息整合,提升模型在复杂组织结构下的预测能力。 如下图所示,来自不同全切片病理图像 (WSIs) 层级的 3 个图像块序列被输入到模型中,以共同预测相应位点的基因表达。 在接收到来自 3 个不同层次的病理图像块后,首先,M2OST 会将它们送入可变形图像块嵌入层 (DPE), 以实现自适应 token 生成。DPE 不仅能从每张图像中提取基础病理图像块,还能在高层次的病理图像中引入更大尺寸的图像块,从而捕捉更广泛的上下文信息。 同时,DPE 通过生成细粒度的点内 token 和粗粒度的周围 token,以强化模型对采样点中心区域特征的关注,从而在多对一的建模过程中突出采样点间特征 (inter-spot features),为后续的表达预测提供更精细、结构化的特征表示。 ::: hljs-center M2OST 模型示意图 ::: ::: hljs-center 在 M2OST 中使用的 DPE ::: 而后,在每个序列中添加 cls token,并如图中 PE 所示,引入可学习的位置编码,M2OST 使用内层 token 混合模块 (ITMM) 对每个序列进行层内特征提取。 ITMM 基于 Vision Transformer 架构构建,并引入随机掩码自注意力机制 (Rand Mask Self-Attn),以增强模型在图像建模过程中的泛化能力。 ::: hljs-center ITMM 的网络结构 ::: 在层内特征提取完成后,M2OST 引入跨层 token 混合模块 (CTMM),用于促进多层序列之间的跨层信息交互。 由于多尺度输入序列的长度存在差异,CTMM 通过引入全连接跨层注意力机制以避免直接融合造成的信息失真,同时保持每个尺度分支参数的相对独立性。随后,为了增强通道级的跨尺度信息交换能力,M2OST 在 CTMM 之后引入了跨层通道混合模块 (CCMM)。 CCMM 采用对序列长度不敏感的结构设计,CTMM 根据不同层之间的注意力相似度和可学习权重,动态整合跨尺度的上下文信息,输出同形状的多层序列。 首先对每个层次的序列进行全局平均池化 (Global Avg Pooling),将其序列信息压缩为一个 token 表示,然后将不同层次的 token 组合在一起,并结合挤压激励机制 (Squeeze & Excitation) 计算跨层通道注意力分数。这些分数随后被映射回各自的输入序列,完成通道级的跨尺度信息交换。 ::: hljs-center (a) CTMM 的网络结构。(b) CCMM 的网络结构。 ::: 该多尺度特征建模过程整体构成 M2OST 的编码器模块,并在整个网络中迭代 N 次,以逐步丰富空间转录组预测所需的多层次、高表达力的图像表征。** 最后,将 3 个 cls token 连接起来,送入线性回归头部进行 ST 点预测。** 实验结果:多维度评估证明 M2OST 模型有效性 研究团队全面比较了 M2OST 与多种主流方法在多个数据集上的表现。实验结果如下表所示,** M2OST 在更少的参数量和更少的 FLOPs 下,实现了更为优越的性能。** 与 ST-Net 相比,M2OST 的参数量减少了 0.40M,FLOPs 降低了 0.63G,而 M2OST 在 HER2+ 和 cSCC 数据集上的皮尔逊相关系数 (PCC) 分别提升了 1.16% 和 1.13%。 ::: hljs-center M2OST 与其他方法的比较实验结果 ::: M2OST 与一对一多尺度方法的比较: 研究团队还将 M2OST 与普通的一对一多尺度方法进行了比较,如 CrossViT 和 HIPT/iStar。相较于标准 ViT,CrossViT 展现出更强的 ST 回归能力,证实了在该任务中整合多尺度信息具有显著优势。然而,CrossViT 在点内信息建模方面存在一定限制,其整体性能仍不及 M2OST。 此外,iStar 在 ST 预测准确性上表现出色,证明了 HIPT 架构在从 WSI 中提取多尺度特征方面的有效性。然而,为了节约计算成本,iStar 采用固定的 HIPT 权重来生成用于 ST 预测的 WSI 特征,限制了其特征提取能力。同时,在推理效率方面,iStar 的逐块、逐尺度的提取流程显著增加了处理时间。研究结果表明,当在相同的 GPU 内存限制下运行,M2OST 的推理速度比 iStar 快约 100 倍,且性能仍优于后者,充分展示了端到端训练在 ST 回归任务中的潜力和 M2OST 模型的有效性。 图像块级和玻片级 ST 方法的比较: 实验结果显示,玻片级方法在 3 个数据集上的表现普遍不及图像块级方法。尽管 Hist2ST 相较于 HisToGene 展现出更强性能,但其大量参数和高 FLOPs 使得这种性能的提升意义不大。与 ST-Net 等基线图像块级方法相比,Hist2ST 在 3 个数据集上的 PCC 分别降低 2.78%、2.99% 和 2.66%。这表明一个点的基因表达主要与其对应的组织区域相关,引入点间相关性并未显著提升预测准确性。尽管如此,玻片级方法在生成完整 ST 图谱方面仍具优有更高的效率,未来通过优化网络设计,仍有潜力实现具有竞争力的回归精度。 可视化分析: ::: hljs-center (a) 主成分分析 (PCA) 之后的空间转录组 (ST) 图谱的可视化结果。 (b) DDX5 基因空间分布的可视化结果。 ::: 研究团队对不同方法在 ST 图谱预测中的可视化结果进行了分析对比,结果显示玻片级方法(如 HisToGene 和 Hist2ST)通常能够生成更平滑的图谱,而图像块级方法则保留了更清晰的局部结构特征。 值得注意的是,M2OST 始终能够生成更准确的 ST 图谱,呈现出更高的预测精度。研究团队进一步对关键基因 DDX5 的表达进行了可视化,DDX5 通过激活 β - catenin 信号通路,在非小细胞癌细胞的增殖和肿瘤发生中起关键作用。结果表明 M2OST 在该基因的预测中表现最优,优于所有对比方法,验证了 M2OST 模型在单基因表达预测水平上的准确性。 空间转录组学的突破性进展与跨领域应用 空间转录组学作为连接细胞功能与组织结构的桥梁,能够解析单个细胞在时间和空间维度上的基因表达模式,并揭示细胞类群的空间位置及其生物学特征,正推动生物医学研究向更深层次发展。 在这一领域,2025 年 4 月, 日本东京大学医科学研究所的研究团队开发了基于图像辅助的图对比学习进行空间转录组学分析的深度学习框架 STAIG。 该框架能够整合基因表达、空间数据和组织学图像,且不需要对齐数据,从而克服了传统方法在消除批次效应和识别空间区域上的局限性。STAIG 通过自监督学习,从苏木精和伊红 (H&E) 染色图像中提取特征,无需依赖大规模数据集进行预训练。 在训练过程中,STAIG 动态调整图结构,并通过组织学图像选择性排除无关的负样本,减少了偏差。最终,STAIG 通过局部对比分析基因表达的共性,成功实现了批次整合,避免了手动坐标对齐的复杂性,显著减少了批次效应。研究表明,STAIG 在多个数据集上表现出色,特别是在空间区域识别方面,能够揭示肿瘤微环境中的详细基因和空间信息,展现出其解析空间生物学复杂性的重要潜力。 点击查看详细报道:无需预对齐即可消除批次效应,东京大学团队开发深度学习框架STAIG,揭示肿瘤微环境中的详细基因信息 与此同时,中国上海临港实验室魏武研究团队也在空间转录组学领域取得了显著进展。2024 年 11 月,团队在 Briefings in Bioinformatics 期刊上发表了题为「MCGAE: unraveling tumor invasion through integrated multimodal spatial transcriptomics」的研究论文。该研究开发了专为空间转录组数据分析设计的深度学习框架 MCGAE (Multi-View Contrastive Graph Autoencoder), 该框架通过结合基因表达、空间坐标和图像特征,创建多模态、多视图的生物表征,显著提升了空间域识别的准确性。 在肿瘤数据中展现了对肿瘤区域的精确识别与分子调控特征的深度解析,为复杂组织、疾病机制研究和药物靶点发现提供了强有力的工具。 论文原文:https://academic.oup.com/bib/article-pdf/26/1/bbae608/60786360/bbae608.pdf 此外,空间转录组学在农业领域的应用也展现出巨大潜力。2025 年 4 月,北京大学现代农业研究院的研究团队在 Genome Biology 上发表了一项题为「Spatiotemporal tranomics reveals key gene regulation for grain yield and quality in wheat」的重要研究, 利用空间转录组技术构建了小麦籽粒发育早期不同时间段的高分辨率基因表达图谱, 揭示了小麦籽粒发育过程中的基因表达特征。这一研究不仅为小麦的分子设计育种与产量提高提供了重要的理论支持,也为全球粮食安全提供了有力保障。 论文原文:https://www.biorxiv.org/content/biorxiv/early/2024/06/03/2024.06.02.596756.full.pdf 未来,随着空间转录组数据的不断积累和数字病理图像获取手段的持续优化,人工智能与组学技术的深度融合将推动深度学习模型在多种组织类型和疾病背景中的广泛应用,助力精准医疗的发展。M2OST 的提出为构建高效、低成本、高精度的空间基因表达预测框架奠定了坚实基础,预示着人工智能与多组学数据融合分析在生物医学领域的深远前景。
2025年-4月-22日
11 阅读
0 评论
人工智能