note

  • ranking by discriminative power(input):sum-multiset > mean-distribution > max-set

  • 【基础部分】GIN图同构模型有效学习图中节点的特征表示,实现图的分类。其中有单射rejective函数(每个x对应一个不同的y)、多重集,是为后面介绍同构性做准备(对同构图处理后的图特征应该相同):

    • 若GNN能根据computation graph训练得到node emb,每个节点对应emb是单射函数,则GNN可认为强表达能力
    • 邻居聚合可看做一个input为multi-set的函数:
      • GCN(均值池化)无法区分各类占比相同的多重集

      • GraphSAGE(最大池化)无法区分具有相同的不同类的多重集(颜色占比相同)

      • GIN通过设计一个含有 Φ\PhiΦf\mathrm{f}f 的两个末知函数(根据universal approximation theorem知Φ\PhiΦf\mathrm{f}f可以通过MLP拟合得到),然后使用sum-pooling表示对应的单射函数。

  • 图同构网络(GIN)的图表征网络步骤:为了得到图表征首先需要做节点表征,然后做图读出。

    • GIN中节点表征的计算遵循WL Test算法中节点标签的更新方法,因此它的上界是WL Test算法。
    • 在图读出中,我们对所有的节点表征(加权,如果用Attention的话)求和,这会造成节点分布信息的丢失。

  • 图同构模型研究图神经网络的表达力问题,Weisfeiler-Lehman测试就是检测两个图是否在拓扑结构上图同构的近似方法;该测试最大的特点是:对每个节点的子树的聚合函数采用的是单射(Injective)的散列函数
    ——由该特点我们可以通过设计一个单射聚合聚合函数来设计与WL一样强大的图卷积网络(同时,图同构网络有强大的图区分能力,适合图分类任务)。

文章目录

  • note
  • 零、Recap部分
    • 0.1 message passing
    • 0.2 GNN的表达能力
    • 0.3 GraphSAGE的failure
    • 0.4 Injective Multi-set Function
  • 一、GIN图同构网络
    • 1.1 WL Graph Kernel -> GIN
    • 1.2 基于图同构网络(GIN)的图表征网络的实现
      • 图表征模块运行流程
    • 1.3 The power of pooling
    • 1.4 dgl中的GINConv层
  • 二、Expressive of Power GNNs
    • 1.Motivation
    • 2.大致内容
    • 3.背景:Weisfeiler-Lehman Test (WL Test)
      • (1)图同构性测试算法WL Test
        • 背景介绍
        • WL举例说明(以一维为栗子)
    • 第一步:聚合
    • 第二步:标签散列(哈希)
      • 注:怎样的聚合函数是一个单射函数?
    • 第三步:给节点重新打上标签。
    • 第四步:数标签
    • 第五步:判断同构性
      • (2)WL Subtree Kernel图相似性评估(定量化)
    • 4.小结
  • 三、General Tips
  • 附:时间安排
  • Reference

零、Recap部分

0.1 message passing

  • 每个节点基于邻居节点确定computation graph
  • message passing GNNs:
    • 每个节点计算对应message:mu(l)=MSG⁡(l)(hu(l−1)),u∈{N(v)∪v}\mathbf{m}_u^{(l)}=\operatorname{MSG}^{(l)}\left(\mathbf{h}_u^{(l-1)}\right), u \in\{N(v) \cup v\}mu(l)=MSG(l)(hu(l1)),u{N(v)v}
    • 聚合:hv(l)=AGG(l)({mu(l),u∈N(v)},mv(l))\mathbf{h}_v^{(l)}=\mathrm{AGG}^{(l)}\left(\left\{\mathbf{m}_u^{(l)}, u \in N(v)\right\}, \mathbf{m}_v^{(l)}\right)hv(l)=AGG(l)({mu(l),uN(v)},mv(l))
  • GCN(mean-pool,如下图)
  • GraphSAGE(max-pool):MLP + element-wise max-pooling
  • 仅仅考虑图中节点的degree无法区分图节点信息(有些节点的邻居节点还一毛一样)

0.2 GNN的表达能力

  • GNN的表达能力=区分计算图根节点embedding的能力。不同邻居有不同的计算图(如下图),即表达能力强的GNN应该将不同的子树,单射映射到节点embedding(且不同)。

  • 聚合:基于multi-set(可以有重复的元素出现)的函数,下图点颜色相同指对应特征相同。

0.3 GraphSAGE的failure

其聚合函数无法区分情况:颜色种类相同,但颜色个数不同;如下图中,上一层节点嵌入u经过一个单射的MLP后形成不同的one hot vector,经过element-wise max-pooling后的结果相同。

0.4 Injective Multi-set Function

从Xu et al. ICLR 2019知,all injective multi-set function can be expressed as:

【Universal Approximation Theorem】

  • 1-hidden-layer MLP with sufficiently-large hidden dimensionality and appropriate non-linearity function(such as Relu and sigmoid) can approximate any continous function.
  • In practice, MLP hidden dimensionality of 100 to 500 is sufficent.

一、GIN图同构网络

1.1 WL Graph Kernel -> GIN

  • 节点不同颜色体现节点的不同特征
  • 先给每个节点的赋初值。对节点颜色进行迭代更新:
    c(k+1)(v)=HASH⁡(c(k)(v),{c(k)(u)}u∈N(v))c^{(k+1)}(v)=\operatorname{HASH}\left(c^{(k)}(v),\left\{c^{(k)}(u)\right\}_{u \in N(v)}\right) c(k+1)(v)=HASH(c(k)(v),{c(k)(u)}uN(v))
  • GIN模型:MLP⁡Φ(∑x∈SMLP⁡f(x))\operatorname{MLP}_{\Phi}\left(\sum_{x \in S} \operatorname{MLP}_f(x)\right)MLPΦ(xSMLPf(x)),其聚合函数时单射的
  • GIN is a NN version of WL graph kernel
  • GIN使用NN建模单射的哈希函数, 建立在元组(根节点特征,邻居节点颜色)上:c(k)(v),{c(k)(u)}u∈N(v)c^{(k)}(v),\left\{c^{(k)}(u)\right\}_{u \in N(v)}c(k)(v),{c(k)(u)}uN(v),所以单射函数可以被建模如下(其中ϵ\epsilonϵ可以通过训练得到):MLP⁡Φ((1+ϵ)⋅MLP⁡f(c(k)(v)]+∑u∈N(v)MLP⁡f(c(k)(u)))\operatorname{MLP}_{\Phi}\left((1+\epsilon) \cdot \operatorname{MLP}_f\left(c^{(k)}(v)\right]+\sum_{u \in N(v)} \operatorname{MLP}_f\left(c^{(k)}(u)\right)\right) MLPΦ (1+ϵ)MLPf(c(k)(v)]+uN(v)MLPf(c(k)(u))


1.2 基于图同构网络(GIN)的图表征网络的实现

基于图同构网络的图表征学习主要包含以下两个过程

  1. 首先计算得到节点表征;
  2. 其次对图上各个节点的表征做图池化(Graph Pooling),或称为图读出(Graph Readout),得到图的表征(Graph Representation)。

自顶向下的学习顺序:GIN图表征—>节点表征

基于图同构网络的图表征模块(GINGraphRepr Module):

  • 能实现判断图同构性的图神经网络需要满足,只在两个节点自身标签一样且它们的邻接节点一样时,图神经网络将这两个节点映射到相同的表征,即映射是单射性的。
  • 可重复集合/多重集(Multisets):元素可重复的集合,元素在集合中没有顺序关系 。一个节点的所有邻接节点是一个可重复集合,一个节点可以有重复的邻接节点,邻接节点没有顺序关系。因此GIN模型中生成节点表征的方法遵循WL Test算法更新节点标签的过程。

在生成节点的表征后仍需要执行图池化(或称为图读出)操作得到图表征,最简单的图读出操作是做求和。由于每一层的节点表征都可能是重要的,因此在图同构网络中,不同层的节点表征在求和后被拼接,其数学定义如下,
hG=CONCAT(READOUT({hv(k)∣v∈G})∣k=0,1,⋯,K)h_{G} = \text{CONCAT}(\text{READOUT}\left(\{h_{v}^{(k)}|v\in G\}\right)|k=0,1,\cdots, K) hG=CONCAT(READOUT({hv(k)vG})k=0,1,,K)
采用拼接而不是相加的原因在于不同层节点的表征属于不同的特征空间。未做严格的证明,这样得到的图的表示与WL Subtree Kernel得到的图的表征是等价的。

图表征模块运行流程

(1)首先采用GINNodeEmbedding模块对图上每一个节点做节点嵌入(Node Embedding),得到节点表征;
(2)然后对节点表征做图池化得到图的表征;
(3)最后用一层线性变换对图表征转换为对图的预测。

1.3 The power of pooling

  • use element-wise sum pooling, instead of mean-/max-pooling

1.4 dgl中的GINConv层

dglGINConv层的公式:

hi(l+1)=fΘ((1+ϵ)hil+aggregate({hjl,j∈N(i)}))h_i^{(l+1)} = f_\Theta \left((1 + \epsilon) h_i^{l} + \mathrm{aggregate}\left(\left\{h_j^{l}, j\in\mathcal{N}(i) \right\}\right)\right)hi(l+1)=fΘ((1+ϵ)hil+aggregate({hjl,jN(i)}))
如果是异构图,边可以加上对应的weight tensor:hi(l+1)=fΘ((1+ϵ)hil+aggregate({ejihjl,j∈N(i)}))h_i^{(l+1)} = f_\Theta \left((1 + \epsilon) h_i^{l} + \mathrm{aggregate}\left(\left\{e_{ji} h_j^{l}, j\in\mathcal{N}(i) \right\}\right)\right)hi(l+1)=fΘ((1+ϵ)hil+aggregate({ejihjl,jN(i)}))
其中:

  • e_{ji} is the weight on the edge from nodej to node i.
  • 要确定ejie_{ji}eji is broadcastable with hjlh_j^{l}hjl.
  • dglGINConv层:
    • input:DGLGraph类的图对象、feat特征矩阵(如维度为(N,Din)(N, D_{in})(N,Din)的矩阵,N为节点个数,DinD_{in}Din为输入的特征个数)
    • output:(N,Dout)(N, D_{out})(N,Dout)维度的矩阵,N为节点个数, DoutD_{out}Doutapply_func函数(更新节点特征表示)结果的矩阵维度。
"""Torch Module for Graph Isomorphism Network layer"""
# pylint: disable= no-member, arguments-differ, invalid-name
import torch as th
from torch import nnfrom .... import function as fn
from ....utils import expand_as_pairclass GINConv(nn.Module):def __init__(self,apply_func,aggregator_type,init_eps=0,learn_eps=False):super(GINConv, self).__init__()self.apply_func = apply_funcself._aggregator_type = aggregator_typeif aggregator_type == 'sum':self._reducer = fn.sumelif aggregator_type == 'max':self._reducer = fn.maxelif aggregator_type == 'mean':self._reducer = fn.meanelse:raise KeyError('Aggregator type {} not recognized.'.format(aggregator_type))# to specify whether eps is trainable or not.if learn_eps:self.eps = th.nn.Parameter(th.FloatTensor([init_eps]))else:self.register_buffer('eps', th.FloatTensor([init_eps]))def forward(self, graph, feat, edge_weight=None):with graph.local_scope():aggregate_fn = fn.copy_src('h', 'm')if edge_weight is not None:assert edge_weight.shape[0] == graph.number_of_edges()graph.edata['_edge_weight'] = edge_weight# message functionaggregate_fn = fn.u_mul_e('h', '_edge_weight', 'm')feat_src, feat_dst = expand_as_pair(feat, graph)graph.srcdata['h'] = feat_src# aggregate function: neighbor info + self infograph.update_all(aggregate_fn, self._reducer('m', 'neigh'))# self inforst = (1 + self.eps) * feat_dst + graph.dstdata['neigh']if self.apply_func is not None:rst = self.apply_func(rst)return rst

二、Expressive of Power GNNs

提出图同构网络的论文:How Powerful are Graph Neural Networks?

1.Motivation

新的图神经网络的设计大多基于经验性的直觉、启发式的方法和实验性的试错。人们对图神经网络的特性和局限性了解甚少,对图神经网络的表征能力学习的正式分析也很有限。

2.大致内容

  1. (理论上)图神经网络在区分图结构方面最高能达到与WL Test一样的能力。
  2. 确定了邻接节点聚合方法和图池化方法应具备的条件,在这些条件下,所产生的图神经网络能达到与WL Test一样的能力。
  3. 分析过去流行的图神经网络变体(如GCN和GraphSAGE)无法区分一些结构的图。
  4. 开发了一个简单的图神经网络模型–图同构网络(Graph Isomorphism Network, GIN),并证明其分辨同构图的能力和表示图的能力与WL Test相当。

3.背景:Weisfeiler-Lehman Test (WL Test)

(1)图同构性测试算法WL Test

背景介绍

两个图是同构的,意思是两个图拥有一样的拓扑结构,也就是说,我们可以通过重新标记节点从一个图转换到另外一个图。Weisfeiler-Lehman 图的同构性测试算法,简称WL Test,是一种用于测试两个图是否同构的算法。

WL Test 的一维形式,类似于图神经网络中的邻接节点聚合。WL Test
1)迭代地聚合节点及其邻接节点的标签,然后 2)将聚合的标签散列(hash)成新标签,该过程形式化为下方的公式,
Luh←hash⁡(Luh−1+∑v∈N(U)Lvh−1)L^{h}_{u} \leftarrow \operatorname{hash}\left(L^{h-1}_{u} + \sum_{v \in \mathcal{N}(U)} L^{h-1}_{v}\right) Luhhash

Luh1+vN(U)Lvh1


符号:LuhL^{h}_{u}Luh表示节点uuu的第hhh次迭代的标签,第000次迭代的标签为节点原始标签。

在迭代过程中,发现两个图之间的节点的标签不同时,就可以确定这两个图是非同构的。需要注意的是节点标签可能的取值只能是有限个数。

WL举例说明(以一维为栗子)

给定两个图GGGG′G^{\prime}G,每个节点拥有标签(实际中,一些图没有节点标签,我们可以以节点的度作为标签)。

Weisfeiler-Leman Test 算法通过重复执行以下给节点打标签的过程来实现图是否同构的判断

第一步:聚合

聚合自身与邻接节点的标签得到一串字符串,自身标签与邻接节点的标签中间用,分隔,邻接节点的标签按升序排序。排序的原因在于要保证单射性,即保证输出的结果不因邻接节点的顺序改变而改变。

如下图就是,每个节点有个一个label(此处表示节点的度)。

如下图,做标签的扩展:做一阶BFS,即只遍历自己的邻居,比如在下图中G中原5号节点变成(5,234),这是因为原(5)节点的一阶邻居有2、3、4。

第二步:标签散列(哈希)

即标签压缩,将较长的字符串映射到一个简短的标签。
如下图,仅仅是把扩展标签映射成一个新标签,如5,234映射为13

注:怎样的聚合函数是一个单射函数?

什么是单射函数?

单射指不同的输入值一定会对应到不同的函数值。如果对于每一个y存在最多一个定义域内的x,有f(x)=y,则函数f被称为单射函数。

看一个栗子:

两个节点v1和v2,其中v1的邻接点是1个黄球和1个蓝球,v2的邻接点是2个邻接点是2个黄球和2个蓝球。最常用的聚合函数包含图卷积网络中所使用的均值聚合,以及GraphSAGE中常用的均值聚合或最大值聚合。

(1)如果使用均值聚合或者最大值聚合,聚合后v1的状态是(黄,蓝),而v2的状态也是(黄,蓝),显然它们把本应不同的2个节点映射到了同一个状态,这不满足单射的定义。
(2)如果使用求和函数,v1的状态是(黄,蓝),而v2的状态是(2×黄,2×蓝),也就分开了。

可以看出WL测试最大的特点是:对每个节点的子树的聚合函数采用的是单射(Injective)的散列函数。

第三步:给节点重新打上标签。

继续一开始的栗子,

第四步:数标签

如下图,在G网络中,含有1号标签2个,那么第一个数字就是1。这些标签的个数作为整个网络的新特征。

每重复一次以上的过程,就完成一次节点自身标签与邻接节点标签的聚合。

第五步:判断同构性

当出现两个图相同节点标签的出现次数不一致时,即可判断两个图不相似。如果上述的步骤重复一定的次数后,没有发现有相同节点标签的出现次数不一致的情况,那么我们无法判断两个图是否同构。

当两个节点的hhh层的标签一样时,表示分别以这两个节点为根节点的WL子树是一致的。WL子树与普通子树不同WL子树包含重复的节点。下图展示了一棵以1节点为根节点高为2的WL子树。

(2)WL Subtree Kernel图相似性评估(定量化)

此方法来自于Weisfeiler-Lehman Graph Kernels。

  • WL测试不能保证对所有图都有效,特别是对于具有高度对称性的图,如链式图、完全图、环图和星图,它会判断错误
  • WL测试只能判断两个图的相似性,无法衡量图之间的相似性。要衡量两个图的相似性,我们用WL Subtree Kernel方法

Weisfeiler-Lehman Graph Kernels 方法提出用WL子树核衡量图之间相似性。该方法使用WL Test不同迭代中的节点标签计数作为图的表征向量,它具有与WL Test相同的判别能力。在WL Test的第kkk次迭代中,一个节点的标签代表了以该节点为根的高度为kkk的子树结构

该方法的思想是用WL Test算法得到节点的多层的标签,然后我们可以分别统计图中各类标签出现的次数,存于一个向量,这个向量可以作为图的表征。两个图的表征向量的内积,即可作为这两个图的相似性估计,内积越大表示相似性越高

4.小结

大部分空域图神经网络的更新步骤,和WL测试非常类似。就像消息传递网络中归纳的框架,大部分基于空域的图神经网络都可以归结为2个步骤:聚合邻接点信息(aggregate),更新节点信息(combine)。avk=Aggregate⁡({huk−1:u∈N(v)}),hvk=Combine⁡(hvk−1,avk)a_{v}^{k}=\operatorname{Aggregate}\left(\left\{\boldsymbol{h}_{u}^{k-1}: u \in \mathcal{N}(v)\right\}\right), \boldsymbol{h}_{v}^{k}=\operatorname{Combine}\left(\boldsymbol{h}_{v}^{k-1}, \boldsymbol{a}_{v}^{k}\right)avk=Aggregate({huk1:uN(v)}),hvk=Combine(hvk1,avk)
与WL测试一样,在表达网络结果时,一个节点的表征会由该结点的父结点的子树信息聚合而成。

正如上面提到的栗子中(下图),均值聚合或者最大值聚合把栗子中的v1和v2两个节点映射到了同一个状态(错误),而如果使用求和函数则能正确分开两者状态。WL测试最大的特点是:对每个节点的子树的聚合函数采用的是单射(Injective)的散列函数
——由该特点我们可以通过设计一个单射聚合聚合函数来设计与WL一样强大的图卷积网络(同时,图同构网络有强大的图区分能力,适合图分类任务)。

三、General Tips

  • 数据预处理很重要:如如果数据波动很大,可以使用normalization标准化
  • optimizer: adam还是牛逼
  • activation function:relu,leakyRelu, PReLU等
  • embedding dimensions:32,64,128等
  • debug:loss/accuracy not converging(收敛)时,检查pipeline(如是否漏了zero_grad())、调整学习速率、检查参数初始化、损失函数、loss曲线变化等。

附:时间安排

任务 任务内容 截止时间 注意事项
2月11日开始
task1 图机器学习导论 2月14日周二 完成
task2 图的表示和特征工程 2月15、16日周四 完成
task3 NetworkX工具包实践 2月17、18日周六 完成
task4 图嵌入表示 2月19、20日周一 完成
task5 deepwalk、Node2vec论文精读 2月21、22、23、24日周五 完成
task6 PageRank 2月25、26日周日 完成
task7 标签传播与节点分类 2月27、28日周二 完成
task8 图神经网络基础 3月1、2日周四 完成
task9 图神经网络的表示能力 3月3日周五 完成
task10 图卷积神经网络GCN 3月4日周六 完成
task11 图神经网络GraphSAGE 3月5日周七
task12 图神经网络GAT 3月6日周一

Reference

[1] https://docs.dgl.ai/en/0.8.x/generated/dgl.nn.pytorch.conv.GINConv.html?highlight=ginconv#dgl.nn.pytorch.conv.GINConv
[2] CS224W官网:https://web.stanford.edu/class/cs224w/index.html
[3] https://github.com/TommyZihao/zihao_course/tree/main/CS224W
[4] cs224w(图机器学习)2021冬季课程学习笔记11 Theory of Graph Neural Networks
[5] 【图神经网络DGL】消息传递范式(消息+聚合+更新)
[6] 【GNN】task6-基于图神经网络的图表征学习方法

【CS224W】(task9)图神经网络的表示能力(GIN图同构模型)相关推荐

  1. 图神经网络的表达能力,究竟有多强大?

    来源:AI科技评论 作者 | Mr Bear 编辑 | 丛 末 近年来,随着图神经网络在各个领域的火热应用,越来越多的学者试图从图论的角度对图神经网络的表达能力进行理论分析,并基于这些理论分析开发出了 ...

  2. TPAMI 2022 | 利用子图同构计数提升图神经网络的表达能力

    ©作者 | 桑士龙 来源 | MIND Laboratory 论文标题: Improving Graph Neural Network Expressivity via Subgraph Isomor ...

  3. 【图神经网络】 - GNN的几个模型及论文解析(NN4G、GAT、GCN)

    文章目录 图神经网络 Neural Network for Graphs(NN4G) 论文信息 摘要 NN4G模型思想 Graph Attention Network(GAT) 论文信息 摘要 GAT ...

  4. 华为诺亚ViG架构媲美CNN、Transformer,图神经网络也能用作CV骨干模型

    华为诺亚实验室的研究员发现图神经网络(GNN)也能做视觉骨干网络.将图像表示为图结构,通过简洁高效的适配,提出一种新型视觉网络架构 ViG,表现优于传统的卷积网络和 Transformer.在 Ima ...

  5. 图神经网络也能用作CV骨干模型,华为诺亚ViG架构媲美CNN、Transformer

    来源丨机器之心 华为诺亚实验室的研究员发现图神经网络(GNN)也能做视觉骨干网络.将图像表示为图结构,通过简洁高效的适配,提出一种新型视觉网络架构 ViG,表现优于传统的卷积网络和 Transform ...

  6. 活动报名|ICLR 2023杰出论文奖一作张博航:从图双连通性的角度重新思考图神经网络的表达能力...

  7. ICLR 2020 开源论文 | 隐空间的图神经网络:Geom-GCN

    作者丨纪厚业 学校丨北京邮电大学博士生 研究方向丨异质图神经网络及其应用 引言 图神经网络(Graph Neural Network)已经成为深度学习领域最热⻔的方向之一.作为经典的 Message- ...

  8. Paper:《Graph Neural Networks: A Review of Methods and Applications—图神经网络:方法与应用综述》翻译与解读

    Paper:<Graph Neural Networks: A Review of Methods and Applications-图神经网络:方法与应用综述>翻译与解读 目录 < ...

  9. 图神经网络与图同构测试

    图神经网络在很多任务上取得了非凡的成功,如: (1) Node Classification (2) Link Prediction (3) Graph Classification 图神经网络的表示 ...

最新文章

  1. pytorch问题汇总
  2. 网站降权的原因以及恢复的方法 (二)
  3. AR头显要上天!欧洲太空总署或用HoloLens维修太空站
  4. 进程间基于共享存储区的通信_IPC(进程间通讯):inter process communication
  5. ux和ui_他们说,以UX / UI设计师的身份加入一家初创公司。 他们说,这会很有趣。
  6. ElementUI dialog嵌套蒙层遮挡问题
  7. 转帖:对linux中半增加半连接数量和防止服务器被dos***
  8. Leetcode算法题(C语言)17--验证回文字符串
  9. 详解static、volatile、const
  10. Linux安装Flash脚本,linux 下安装adobe flash的关键。
  11. R 回归 虚拟变量na_互助问答第30期:工具变量、GARCH模型操作和多项选择效信度...
  12. 小升初冲击SSF未遂,进入“帝都理工附中
  13. 这些两轮电动车的黑科技你知道吗?
  14. 基于JAVA江西婺源旅游文化推广系统计算机毕业设计源码+数据库+lw文档+系统+部署
  15. 记一个小工具——font-spider(字蛛-css压缩中文字体字体)
  16. cython(cython安装)
  17. 孤单是对你最好的惩罚
  18. VUE使用video-player在线播放视频
  19. abp+dapper+mysql_ABP架构学习系列四:集成Dapper
  20. 多益网络的四个笔试题(数学)

热门文章

  1. 将制表符变成4个字节c语言,天津市 高职升本 计算机2007真题 答案
  2. DGCF,Disentangled Graph Collaborative Filtering论文理解
  3. IEEE754标准中的4种舍入模式
  4. python整蛊代码
  5. 【java面向对象题型练习】——通过继承实现员工工资核算打印功能
  6. 天青色等烟雨,而我在等你
  7. 校办研修之计算机培训简报,校本培训简报_712041.doc
  8. 大学生找工作的个人简历模板(合集)
  9. python实现批量打开windows cmd
  10. thinkphp5 导入/导出 Csv文件