Cora数据集 :https://linqs.soe.ucsc.edu/data

  • 共2708个paper,7个类,一共有1433个关键词,关键词频次小于10会被删掉。

最开始为paper_id,后面为每一个单词是否出现,最后为类的标签。

第一列为paper ID,后面几列为每个单词出现与否,用0与1表示,最后一列为类别标签。

Cora数据集由机器学习论文组成,是近年来图深度学习很喜欢使用的数据集。在数据集中,论文分为以下七类之一:

  • 基于案例
  • 遗传算法
  • 神经网络
  • 概率方法
  • 强化学习
  • 规则学习
  • 理论

论文的选择方式是,在最终语料库中,每篇论文引用或被至少一篇其他论文引用。整个语料库中有2708篇论文。

在词干堵塞和去除词尾后,只剩下1433个独特的单词。文档频率小于10的所有单词都被删除。

数据集组成

  • Content文件:
    .content文件包含以下格式的论文描述:
    <paper_id> <word_attributes>+ <class_label>

    1. 每行的第一个条目包含纸张的唯一字符串标识,后跟二进制值,指示词汇中的每个单词在文章中是存在(由1表示)还是不存在(由0表示)。
    2. 最后,该行的最后一个条目包含纸张的类别标签。因此数据集的feature应该为**2709×1433**维度。第一行为idx,最后一行为label
  • Cites文件:
    那个.cites文件包含语料库的引用’图’。每行以以下格式描述一个链接:
    <被引论文编号> <引论文编号>
    每行包含两个纸质id。第一个条目是被引用论文的标识,第二个标识代表包含引用的论文。链接的方向是从右向左。
    如果一行由“论文1 论文2”表示,则链接是“论文2 - >论文1”。可以通过论文之间的索引关系建立邻接矩阵adj

python setuptools

  • python读取文件时,比如txt或xlxs,要加上文件后缀,否则会出现无法找到的情况。

GCN用自己的数据

pygcn源码阅读

你要用GCN,只需要输入的大图邻接矩阵、顶点nodes特征矩阵、每个顶点的类别one-hot向量矩阵。 它这个大图邻接矩阵一开始是用字典来存的,你只要将你的数据转换成”””将三元组数据,转换为graph,按字典存储:{0:[],1:[],2:[],…}
a dict in the format {index: [index_of_neighbor_nodes]}
“”” 比如,你的顶点node1,与他相关的顶点有node23/node33/node43,那么这个顶点按照字典的形式放入graph_dict中,当取值graph_dict[node1]时,它的值为:[node23,node33,node43]。 你仔细看看gcn的graph生成过程,模仿一下它的数据处理格式,就可以直接将你的数据直接套用GCN代码中了

  • scipy.sparse.csr.csr_matrix:ref1; ref2
    解释说明:
    indptr: 代表每行中有多少个不为0的值,其中第一项0是固定的,第2项与第一项的差值表示第0行有2-0个不为0的值,第3项与第2项的差3-2=1表示第1行有一个不为0的值,依次类推
    indices: indptr指明了每行有多少个非0项,indices则指定每行究竟是那几列不为0,例子中第0行有2个非0,则对应indices中前两项,即0,2两列不为0,第1行有1个非0,则对应indices中的2列不为0,依次类推
    data: 则代表这些不为0的值具体是什么值,例子中第0行的0,2两列不为0,即对应data中的1,2两个值,第1行的2列不为0,则对应data中的3这个值。

    1. >>> indptr = np.array([0, 2, 3, 6])
    2. >>> indices = np.array([0, 2, 2, 0, 1, 2])
    3. >>> data = np.array([1, 2, 3, 4, 5, 6])
    4. >>> csr_matrix((data, indices, indptr), shape=(3, 3)).toarray()
    5. array([[1, 0, 2],
    6. [0, 0, 3],
    7. [4, 5, 6]])
    8. # .toarray()将压缩后的数据又转成了array形式,其中压缩后的数据形式如下:
    9. feature = csr_matrix((data, indices, indptr), shape=(3, 3))
    10. print (feature)
    11. 输出为:
    12. (0, 0) 1
    13. (0, 2) 2
    14. (1, 2) 3
    15. (2, 0) 4
    16. (2, 1) 5
    17. (2, 2) 6
    18. 第一行(0, 0) 1表示第0行第0列值为1,其它同理
  • 当遇到稀疏矩阵时,数据量比较大,但是大部分都是0,此时可以记录非0值所在的列,以及每行非0值的个数或者非0值所在的行(前者占更少的存储空间),然后对其再进行压缩。

  • coo_matrix:coo_matrix是可以根据行和列索引进行data值的累加。
  • np.getfromtxt()

    1. import numpy as np
    2. data = np.genfromtxt('waveform.txt',delimiter=',',skip_header=18)
  • np.identity():只能创建方阵,返回的是nxn的主对角线为1,其余地方为0的数组

    1. np.identity(n,dtype=None)
  • np.eye():创建对角阵

    1. numpy.eye(N,M=None,k=0,dtype=<class 'float'>,order='C)
  • 也可以用来将数组转为one-hot形式。 ```python import numpy as np

labels=np.array([[1],[2],[0],[1]]) print(“labels的大小:”,labels.shape,”\n”)

因为我们的类别是从0-2,所以这里是3个类

a=np.eye(3)[1] print(“如果对应的类别号是1,那么转成one-hot的形式”,a,”\n”)

a=np.eye(3)[2] print(“如果对应的类别号是2,那么转成one-hot的形式”,a,”\n”)

a=np.eye(3)[1,0] print(“1转成one-hot的数组的第一个数字是:”,a,”\n”)

这里和上面的结果的区别,注意!!!

a=np.eye(3)[[1,2,0,1]] print(“如果对应的类别号是1,2,0,1,那么转成one-hot的形式\n”,a)

res=np.eye(3)[labels.reshape(-1)] print(“labels转成one-hot形式的结果:\n”,res,”\n”) print(“labels转化成one-hot后的大小:”,res.shape)

  1. - dict.get(key, default=None)
  2. - np.where(condition, x, y)<br />只有条件 (condition),没有xy,则输出满足条件 (即非0) 元素的坐标,这里的坐标以tuple的形式给出,通常原数组有多少维,输出的tuple中就包含几个数组。
  3. ```python
  4. >>> a = np.array([2,4,6,8,10])
  5. >>> np.where(a > 5) # 返回索引
  6. (array([2, 3, 4]),)
  7. >>> a[np.where(a > 5)] # 等价于 a[a>5]
  8. array([ 6, 8, 10])
  9. >>> np.where([[0, 1], [1, 0]])
  10. (array([0, 1]), array([1, 0]))
  • python,类中的__repr__方法:
    事实上,当我们输出某个实例化对象时,其调用的就是该对象的 __repr__() 方法,输出的是该方法的返回值。
  • pickle:python对象序列化.

    1. import pickle as pkl
    2. # dump保存对象
    3. dict1 = {'name': 'flyme', 'age': '22', 'hobby': 'sleep', 'kinsfole': ['father', 'mother']}
    4. with open('testfile', 'wb') as file:
    5. pickle.dump(dict1, file)
    6. # load读取对象
    7. with open('testfile', 'rb') as file:
    8. dict1 = pickle.load(file)
    9. print(dict1)
  • 注意output.max(1)[1]为表示最大值所在的indice。
    output为tensor,max函数返回的是个元组。

  • 【代码实现】GCN的Pytorch实现 - 图1自己的数据是什么?问师兄
    统计类别标签和属性的关系建立知识图谱
    步骤S1,对输入图片进行特征提取,获得特征图。 步骤S2,统计数据集中类别标签和属性的关联性来构建知识图谱; 步骤S3,利用GGNN网络对所构建的知识图谱进行特征表达,迭代地更新知识图谱得到 知识图谱的特征表示; 步骤S4,将步骤S1提取到的特征图与步骤S3通过GGNN网络得到的高级知识进行融合, 通过高级知识和特征图结合来引导网络分类。

要想每次跑出结果一样,可以用如下代码:

  1. np.random.seed(1234)
  2. torch.manual_seed(1234)
  3. torch.cuda.manual_seed(1234)

others(结合知识图谱)

如果节点的特征 input 不存在的话, 可以考虑将节点的 one-hot 表示作为特征输入到模型中.

file:///F:/一种细粒度图像分类的方法及系统.pdf

  1. 将数据 集中同类物体中对应属性的特征值相加,并进行归一化,得到一个C×A维度的矩阵S,根据 矩阵S构建邻接矩阵,进而利用所述邻接矩阵构建所述知识图谱。

C*A中C应该是类别数,A是属性数

步骤S1,对输入图片进行特征提取,获得特征图。

步骤S2,,统计数据集中类别标签和属性的关联性来构建知识图谱;

步骤S3,利用GGNN网络对所构建的知识图谱进行特征表达,迭代地更新知识图谱 得到知识图谱的特征表示

  1. 优选地,步骤S3进一步包括: 步骤S300,对给定图像进行分类; 步骤S301,定义GGNN网络结构,**_并用分类结果初始化类别节点特征和初始化属性节点特征_**,再将其输入GGNN网络,并迭代地更新每个节点的信息。
  2. 于步骤S301中,输入的是一个图 其中V是表示节点的集合,A 表示节点之间关系的邻接矩阵,对于每个节点vV ,在迭代次数t都有一个隐藏信息 t0时, 其中xv为初始的特征向量,迭代过程如下:

步骤S4,将步骤S1提取到的特征图与步骤S3通过GGNN网络得到的高级知识进行融 合,通过高级知识和特征图结合来引导网络分类。

  1. 所述GGNN网络结构通 过迭代更新节点特征来学习任意图结构数据的特征,然后构成一个知识图谱,包括类别标 签和属性的节点,以及节点间的相关性。
  2. 特征提取单元,用于对输入图片进行特征提取,获得特征图; 知识图谱构建单元,用于统计数据集中类别标签和属性的关联性来构建知识图谱; 知识表达学习单元,用于利用GGNN网络对所构建的知识图谱进行特征表达,迭代地更 新知识图谱得到知识图谱的特征表示; 知识嵌入分类单元,将所述特征提取单元提取到的特征图与所述知识表达学习单元通 GGNN网络得到的高级知识进行融合,通过高级知识和特征图结合来引导网络分类。
  • 具体实施:
    具体地说,对于细粒度分类任务,同一类别中仅有的几个个体拥有特殊的属性是。很常见的,就像有的个体有一种属性,而同一物种的另一个体没有这种属性一样。这样看 来,类别-属性之间的关系具有不确定性。因此,于步骤S2中,将数据集中同类物体中对应 属性的特征值相加,并进行归一化,得到一个C×A维度的矩阵S,其中C表示类别节点,A表示 属性节点。由于类别与类别之间没有关联,属性和属性之间也没有关联,所以构成一个邻接 矩阵为:
  • 与现有技术相比,本发明一种细粒度图像的分类方法及系统通过引入了高级知识 引导特征学习,并加入了一个引导机制将知识进行嵌入来进行细粒度分类,使网络关注到 图片中更具有判别性的区域,学习到更强的分类特征,从而提高网络分类准确率
  • 疑问:
    1、用分类结果初始化类别节点特征和属性节点特征
    2、如何结合图像特征与GGNN学习到的特征,(不是有维度差异吗)

毕设论文中介绍GCN,参考:

  1. GCN介绍:
  2. https://blog.csdn.net/weixin_40367126/article/details/90145257
  • 使用GCN+图谱的目的:
    方便gradcam识别判别性区域(属性)
    利用显式语义来辅助推理以及输出图谱可视化

原始GCN论文,数据即为节点(节点本身有特征),节点之间存在关系,利用图网络来判断节点种类。

直接借鉴到我们的方法中,就是将图片作为数据,然而图像间并无关系。因此要用词向量初始化,建立图谱为属性和类别间的关系。

  • 我们的项目是使用GCN引入知识图谱的先验关系,对分类准确率可能没有提升。但当知识图谱很大时,能够学习到类别相关的属性关系,并对知识图谱进行激活,从而提供一个可解释性的输出。
    知识与数据融合:因为属性数据比较少,因此加入先验知识(即属性和类别的对应关系,属性对类别的贡献可以加权),可以一定程度上弥补数据的缺陷。
    只进行了属性的标注,而没有边界框(bounding box),事实证明,grad-cam是能够显示判别性的区域的(属性),因为模型已经在inception上经过预训练,特征提取的能力较强。而损失函数会针对属性、类别标签计算损失(即属性标注也作为监督信息),因为模型经过在我们数据集上的微调(即迁移到我们数据集上),会具有更好的识别判别性区域的能力。

    CNN特征和GCN特征结合,经过属性监督信息的反向传播,会让CNN更注意判别力区域,从而输出判断的依据。

  • 答辩的时候也可以说数据已经标注了边界框(但好像要涉及到目标检测、Anchor相关,如果麻烦,也可不讲)

其实现在的做法是由于标注数据太少而做的折衷,原来的想法是:先训练出属性分类器,比如能识别颧骨突出、鼻梁凹陷等。这样即使对于没有见过的病症类别,我们只要知道类别和属性的对应关系,就可以得到类别分类器。但是现在只有二分类,因此这种做法不太可行。

对师兄的问题

  • 是否拿属性作为监督信息了?
  • 算法如何识别出判别性区域的,和图谱有关吗?图谱在里面又起什么作用呢?词向量作为语义信息有用吗?可以随机初始化而非词向量作为语义特征吗?
  • 训练GCN的监督信息又是什么呢?

目前想法

CNN+GCN提取的特征,然后送入多分支,分别识别出属性和类别标签。这样也同时利用了属性和类别标签作为监督信息。

是否可以说:知识图谱能够根据属性和类别的关系,促进分类。因为某几个属性经常出现在某个类别。

知识图谱提取出的特征的作用就是告诉我们,出现了某几个属性,大概率为哪个类别。这样知识图谱相当于先验知识和约束,(知识图谱包含了类别可能出现的所有属性,最后激活的可能只有部分)

另外,知识图谱也是作为对grad-cam的指导

知识图谱加grad-cam,可以实现热力图和知识图谱的激活。

TODO

  • 看师兄的代码逻辑
  • 代码的输入输出
  • 知识图谱对grad-cam的指导

论文摘要