文章目录

  • 1 相关介绍
    • GCN的局限性
    • 本文贡献(创新点)
    • attention 引入目的
    • 相关工作
      • 谱方法 spectral approaches
      • 非谱方法 non-spectral approaches (基于空间的方法)
      • 注意力机制 self-attention
  • 2 GAT
    • 2.1 Graph Attentional Layer
      • 计算注意力系数(attention coefficient)
      • 加权求和(aggregate)
        • multi-head attention机制
    • 2.2 和当前工作的对比
  • 3 实验和评价
    • 数据集
    • 半监督学习transductive learning
    • 归纳学习inductive learning
  • 4 总结
    • GAT模型的特点
    • GAT模型的局限及未来的研究方向
    • GAT核心公式
    • GAT的DGL实现
    • 参考

论文题目:Graph Attention Network (GAT)

时间:2018

来源:ICLR

论文链接:https://arxiv.org/abs/1710.10903

Github链接:https://github.com/Diego999/pyGAT

1 相关介绍

graph上的deep learning方法无外乎就是希望学习节点特征以及节点在图中的结构特征。

GCN的局限性

  • 无法完成inductive任务,即处理动态图问题。inductive任务是指:训练阶段与测试阶段需要处理的graph不同。通常是训练阶段只是在子图(subgraph)上进行,测试阶段需要处理未知的顶点。(unseen node)
  • 处理有向图的瓶颈,不容易实现分配不同的学习权重给不同的neighbor
  • 对于一个图结构训练好的模型,不能运用于另一个图结构(所以此文称自己为半监督的方法)

本文贡献(创新点)

  • 引入masked self-attentional layers 来改进前面图卷积的缺点
  • 对不同的相邻节点分配相应的权重,既不需要矩阵运算,也不需要事先知道图结构
  • 四个数据集上达到state-of-the-art的准确率Cora、Citeseer、Pubmed、protein interaction

attention 引入目的

  • 为每个节点分配不同权重
  • 关注那些作用比较大的节点,而忽视一些作用较小的节点
  • 在处理局部信息的时候同时能够关注整体的信息,不是用来给参与计算的各个节点进行加权的,而是表示一个全局的信息并参与计算

相关工作

对待图结构的数据有两种方法,谱方法和非谱方法

谱方法 spectral approaches

例如:GCN
Semi-Supervised Classification with Graph Convolutional Networks,ICLR 2017这篇文章中的方法

解析 :Semi-Supervised Classification with Graph Convolutional Networks用图卷积进行半监督分类

非谱方法 non-spectral approaches (基于空间的方法)

例如:GraphSAGE
William L Hamilton, Rex Ying, and Jure Leskovec. Inductive representation learning on largegraphs. Neural Information Processing Systems (NIPS), 2017.

解析:GraphSAGE:Inductive Representation Learning on Large Graphs

这种方法是将相邻节点设置为固定的长度,然后进行specific aggregator,这种方法在几个大的benchmarks上取得了非常好的效果。

注意力机制 self-attention

优点:可以处理任意大小输入的问题,并且关注最具有影响能力的输入。

注意力机制再RNN与CNN之中,都取得了不错的效果,并且可以达到state-of-the-art的性能。

attention来源于自然语言处理领域的这篇很著名的文章:
Attention is all you need

2 GAT

2.1 Graph Attentional Layer

和所有的attention mechanism一样,GAT的计算也分为两步:计算注意力系数(attention coefficient)和加权求和(aggregate)

input
单个 graph attentional layer的输入是一个节点特征向量集合

h={h1⃗,h2⃗,…,hN⃗},hi⃗∈RFh=\lbrace \vec{h_1},\vec{h_2},\dots,\vec{h_N} \rbrace,\; \vec{h_i}\in R^F h={h1

,h2

,,hN

},hi

RF

其中

  • NNN表示节点的数目
  • FFF表示每个节点的特征的数目

output
并生成一个新的节点特征集合

h′={h1′⃗,h2′⃗,…,hN′⃗},hi′⃗∈RF′h^{'}=\lbrace \vec{h_1^{'}},\vec{h_2^{'}},\dots,\vec{h_N^{'}} \rbrace,\; \vec{h_i^{'}}\in R^{F^{'}} h={h1

,h2

,,hN

},hi

RF
其中FFFF′F'F具有不同的维度。

为了得到相应的输入与输出的转换,需要根据输入的feature至少一次线性变换得到输出的feature,所以我们需要对所有节点训练一个权值矩阵:W∈RF′×FW\in R^{F^{'}\times F}WRF×F,这个权值矩阵就是输入与输出的F个feature与输出的F’个feature之间的关系:

hi′⃗=Whi⃗\vec{h_i^{'}}=\mathbf{W}\vec{h_i} hi

=Whi

为了获得足够的表达能力以将输入特征变换为更高级别的特征,需要至少一个可学习的线性变换。为此,作为初始步骤,一个共享的线性变换参数矩阵W∈RF′×F\mathbf{W}\in R^{F^{'}\times F}WRF×F被应用于每一个节点。

计算注意力系数(attention coefficient)

论文里说,self-attention是一种Global graph attention,会将注意力分配到图中所有的节点上,这种做法显然会丢失结构信息。通过self-attention注意力机制可以计算任意两个样本的关系,使一个样本用其他所有样本来表示,但是第一,基于空间相似假设,一个样本与一定范围内的样本关系较密切,第二,样本较多的时候,计算量非常大。为了解决这一问题,作者使用了一种 masked attention 的方法,对于一个样本来说只利用邻域内的样本计算注意力系数和新的表示,即仅将注意力分配到节点的一阶邻居节点集上

针对每个节点执行 self-attention机制,机制aaa

a:RF′×RF′→Ra:R^{F^{'}}\times R^{F^{'}}\to R a:RF×RFR

计算注意力互相关系数attention coefficients:

eij=a(Whi⃗,Whj⃗)(1)\tag{1} e_{ij}=a(\mathbf{W}\vec{h_i}, \mathbf{W}\vec{h_j}) eij=a(Whi

,Whj

)(1)
其中

  • 注意力系数eije_{ij}eij表示的节点jjj对于节点iii的重要性
  • 向量h⃗\vec{h}h 就是 feature向量
  • aaa是一个RF′×RF′→RR^{F^{'}}\times R^{F^{'}}\to RRF×RFR的映射
  • W∈RF′×F\mathbf{W}\in R^{F^{'}\times F}WRF×F,使用W\mathbf{W}W将每个特征转换为可用的表达性更强的特征

为了使得注意力系数更容易计算和便于比较,引入了softmax对所有的iii的相邻节点jjj进行正则化:

αij=softmaxj(eij)=exp⁡(eij)∑k∈Niexp⁡(eik)(2)\tag{2} \alpha_{ij} = \mathrm{softmax}_j (e_{ij}) = \frac{\exp(e_{ij})}{\sum_{k \in \mathcal{N}_i} \exp(e_{ik})} αij=softmaxj(eij)=kNiexp(eik)exp(eij)(2)
其中

  • Ni\mathcal{N_i}Ni表示节点iii的邻居节点集合
  • 这个系数α\alphaα就是每次卷积时,用来进行加权求和的系数

实验中,注意力机制aaa是一个单层的前馈神经网络,通过权值向量来确定a⃗∈R2F′\vec{\text{a}} \in \mathbb{R}^{2F'}a

R2F,并且加入了 LeakyRelu的非线性激活,这里小于零斜率为0.2。(回顾下几种Relu函数,relu:小于0就是0,大于零斜率为1;LRelu:小于零斜率固定一个值,大于零斜率为1;PRelu:小于零斜率可变,大于零斜率为1;还有CRelu,Elu,SELU)。

αij=exp⁡(LeakyReLU(a⃗T[Wh⃗i∥Wh⃗j]))∑k∈Niexp⁡(LeakyReLU(a⃗T[Wh⃗i∥Wh⃗k]))(3)\tag{3} \alpha_{ij} = \frac{ \exp{ ( \mathrm{LeakyReLU} ( \vec{\text{a}}^T [\mathbf{W} \vec{h}_i \Vert \mathbf{W} \vec{h}_j ] ))}}{\sum_{k \in \mathcal{N_i}} \exp{(\mathrm{LeakyReLU}(\vec{\text{a}}^T [\mathbf{W} \vec{h}_i \Vert \mathbf{W} \vec{h}_k]))}} αij=kNiexp(LeakyReLU(a

T[Wh

i
Wh

k
]))exp(LeakyReLU(a

T
[Wh

i
Wh

j
]))
(3)
其中

  • ||表示concatenation操作(串联)

下图就是表示Wh⃗i\mathbf{W} \vec{h}_iWh

iWh⃗j\mathbf{W} \vec{h}_jWh

j
经过串联以后,再和权值向量a⃗∈R2F′\vec{\text{a}} \in \mathbb{R}^{2F'}a

R2F
相乘后,最后进行一个softmax归一化处理后的示意图。

这部分代码为

def forward(self, x):# [B_batch,N_nodes,C_channels]B, N, C = x.size()# h = torch.bmm(x, self.W.expand(B, self.in_features, self.out_features))  # [B,N,C]h = torch.matmul(x, self.W)  # [B,N,C]a_input = torch.cat([h.repeat(1, 1, N).view(B, N * N, C), h.repeat(1, N, 1)], dim=2).view(B, N, N,2 * self.out_features)  # [B,N,N,2C]# temp = self.a.expand(B, self.out_features * 2, 1)# temp2 = torch.matmul(a_input, self.a)attention = self.leakyrelu(torch.matmul(a_input, self.a).squeeze(3))  # [B,N,N]attention = F.softmax(attention, dim=2)  # [B,N,N]attention = F.dropout(attention, self.dropout, training=self.training)h_prime = torch.bmm(attention, h)  # [B,N,N]*[B,N,C]-> [B,N,C]out = F.elu(h_prime + self.beta * h)return out

加权求和(aggregate)

得到归一化的注意力系数后,使用归一化的值计算对应特征的线性组合,作为每个顶点最后的输出特征(最后可以加一个非线性层,σ\sigmaσ):

h⃗i′=σ(∑j∈NiαijWh⃗j)(4)\tag{4} \vec{h}'_i = \sigma(\sum_{j \in \mathcal{N}_i} \alpha_{ij} \mathbf{W} \vec{h}_j) h

i=σ(jNiαijWh

j
)
(4)
h⃗i′\vec{h}'_ih

i
就是GAT输出的节点iii 融合了邻域信息的新特征

multi-head attention机制

为了使self-attention 的学习过程更稳定,发现使用 multi-head attention来扩展注意力机制是很有效的。

使用K个独立的 attention 机制执行公式式4这样的变换,然后他们的特征连(concatednated)在一起,就可以得到如下的输出:

h⃗i′=∥k=1Kσ(∑j∈NiαijkWkh⃗j)(5)\tag{5} \vec{h}'_i = \Vert^{K}_{k=1} \sigma(\sum_{j \in \mathcal{N}_i} \alpha^k_{ij} \mathbf{W}^k \vec{h}_j) h

i=k=1Kσ(jNiαijkWkh

j
)
(5)
其中

  • 最后的返回输出h′h'h,每个顶点都会有KF′KF'KF维的特征(不是F′F'F

下图表示K=3K=3K=3时的multi-head attention机制示意图。例如此图,节点1在邻域中具有多端注意机制,不同的箭头样式表示独立的注意力计算,通过连接或平均每个head获取h⃗1\vec{h}_1h

1

对于最后一个卷积层,如果还是使用multi-head attention机制,那么就不采取连接的方式合并不同的attention机制的结果了,而是采用求平均的方式进行处理,即

h⃗i′=σ(1K∑k=1K∑j∈NiαijkWkh⃗j)(6)\tag{6} \vec{h}'_i = \sigma(\frac{1}{K} \sum^K_{k=1} \sum_{j \in \mathcal{N}_i} \alpha^k_{ij} \mathbf{W}^k \vec{h}_j) h

i=σ(K1k=1KjNiαijkWkh

j
)
(6)

2.2 和当前工作的对比

  • 计算高效self-attention层的操作可以在所有的边上并行,输出特征的计算可以在所有顶点上并行。没有耗时的特征值分解。单个的GAT计算F′F'F个特征的时间复杂度可以压缩至O(∣V∣FF′+∣E∣F′)O(|V|FF'+|E|F')O(VFF+EF),F是输入的特征数,|V|和|E|是图中顶点数和边数。复杂度与Kipf & Welling, 2017的GCN差不多。
    尽管 multi-head 注意力将存储和参数个数变为了K倍,但是单个head的计算完全独立且可以并行化。
  • 鲁棒性更强:和GCN不同,本文的模型可以对同一个 neighborhood的node分配不同的重要性,使得模型的capacity大增。
  • 注意力机制以一种共享的策略应用在图的所有的边上,因此它并不需要在之前就需要得到整个图结构或是所有的顶点的特征(很多之前的方法的缺陷)。因此GAT 也是一种局部模型。也就是说,在使用 GAT 时,无需访问整个图,而只需要访问所关注节点的邻节点即可,解决了之前提出的基于谱的方法的问题。因此这个方法有几个影响:
    • 图不需要是无向的,可以处理有向图(若j→ij\to iji不存在,仅需忽略αij\alpha_{ij}αij即可)
    • 可以直接应用到 inductive learning:包括在训练过程中在完全未见过的图上评估模型的任务上。
  • 2017年Hamilton提出的归纳学习方法(GraphSAGE)为每一个node都抽取一个固定尺寸的neighborhood,为了计算的时候footprint是一致的(指的应该是计算的时候处理neighborhood的模式是固定的,不好改变,因此每次都抽样出固定数量的neighbor参与计算),这样,在计算的时候就不是所有的neighbor都能参与其中。此外,Hamilton的这个模型在使用一些基于LSTM的方法的时候能得到最好的结果,这样就是假设了每个node的neighborhood的node一直存在着一个顺序,使得这些node成为一个序列。但是本文提出的方法就没有这个问题,每次都可以将neighborhood所有的node都考虑进来,而且不需要事先假定一个neighborhood的顺序
    解析:GraphSAGE:Inductive Representation Learning on Large Graphs
  • 和MoNet(Monti et al., 2016)相比,GAT模型使用顶点特征计算相似性,而不是顶点的结构特征

3 实验和评价

实验分成两部分,transductive learning(半监督学习)和inductive learning(归纳学习)。

数据集

图结构的数据集,以及数据集之中的信息如下:

半监督学习transductive learning

  • 两层 GAT
  • 在Cora 数据集上优化网络结构的超参数,应用到Citeseer数据集
  • 第一层 8 head, F’=8 , ELU 作为非线性函数
  • 第二层为分类层,一个 attention head 特征数C,后跟 softmax 函数,为了应对小训练集,正则化(L2)
  • 两层都采用 0.6 的dropout,相当于计算每个node位置的卷积时都是随机的选取了一部分近邻节点参与卷积
  • 用Glorot初始化初始的,并且是用Adam SGD来最小化交叉熵进行优化

归纳学习inductive learning

  • 三层GAT 模型
  • 前两层 K=4, F’=256 ,ELU作为非线性函数
  • 最后一层用来分类 K=6, F`=121 , 激活函数为sigmoid
  • 该任务中,训练集足够大不需要使用 正则化 和 dropout
  • 用Glorot初始化初始的,并且是用Adam SGD来最小化交叉熵进行优化

最后,使用t-SNE(Maaten & Hinton, 2008)在Cora数据集上进行一层GAT模型的输出变换图如下所示

4 总结

GAT模型的特点

  • 计算高效self-attention层的操作可以在所有的边上并行,输出特征的计算可以在所有顶点上并行。没有耗时的特征值分解。单个的GAT计算F′F'F个特征的时间复杂度可以压缩至O(∣V∣FF′+∣E∣F′)O(|V|FF'+|E|F')O(VFF+EF),F是输入的特征数,|V|和|E|是图中顶点数和边数。复杂度与Kipf & Welling, 2017的GCN差不多。
    尽管 multi-head 注意力将存储和参数个数变为了K倍,但是单个head的计算完全独立且可以并行化。
  • 鲁棒性更强:和GCN不同,本文的模型可以对同一个 neighborhood的node分配不同的重要性,使得模型的capacity大增。
  • 注意力机制以一种共享的策略应用在图的所有的边上,因此它并不需要在之前就需要得到整个图结构或是所有的顶点的特征(很多之前的方法的缺陷)。因此GAT 也是一种局部模型。也就是说,在使用 GAT 时,无需访问整个图,而只需要访问所关注节点的邻节点即可,解决了之前提出的基于谱的方法的问题。因此这个方法有几个影响:
    • 图不需要是无向的,可以处理有向图(若j→ij\to iji不存在,仅需忽略αij\alpha_{ij}αij即可)
    • 可以直接应用到 inductive learning:包括在训练过程中在完全未见过的图上评估模型的任务上。

GAT模型的局限及未来的研究方向

  • 使用稀疏矩阵操作的GAT层,可以将空间复杂度降低到顶点和边数的线性级别,使得GAT模型可以在更大的图数据集上运行。然而,文中使用的tensor操作框架只支持二阶tensor的稀疏矩阵乘法,限制了当前实现的版本的模型能力(尤其在有多个图的数据集上)。解决这个问题是未来的一个重要研究方向。在这些使用稀疏矩阵的场景下,在某些图结构下GPU的运算并不能比CPU快多少。
  • 另一个需要注意的地方是GAT模型的感受野的大小的上界取决于网络的深度(与GCN和其他模型相似)。像skip connections(He et al., 2016)这样的技术可以来近似的扩展模型的深度。
  • 在所有边上的并行计算,尤其是分布式的计算可以设计很多冗余的计算,因为图中的邻居往往高度重叠。
  • 扩展GAT模型从顶点分类到图分类也是一个更具应用性的方向
  • 扩展GAT模型到整合边的信息(可能表示节点之间的关系)可以处理更多的问题

GAT核心公式

图注意力模型GAT用注意力机制替代了图卷积中固定的标准化操作。下图和公式定义了如何对第lll层节点特征做更新得到第l+1l+1l+1层节点特征:

zi(l)=W(l)hi(l)(1)\tag{1} z_{i}^{(l)}=\mathbf{W}^{(l)} h_{i}^{(l)} zi(l)=W(l)hi(l)(1)

eij(l)=LeakyReLU( a⃗(l)T(zi(l)∥zj(l)))(2)\tag{2} \left.e_{i j}^{(l)}=\text { LeakyReLU( } \vec{a}^{(l)^{T}}\left(z_{i}^{(l)} \| z_{j}^{(l)}\right)\right) eij(l)=LeakyReLU(a

(l)T(zi(l)zj(l)))(2)

αij(l)=exp⁡(eij(l))∑k∈N(i)exp⁡(eik(l))(3)\tag{3} \alpha_{i j}^{(l)}=\frac{\exp \left(e_{i j}^{(l)}\right)}{\sum_{k \in \mathcal{N}(i)} \exp \left(e_{i k}^{(l)}\right)} αij(l)=kN(i)exp(eik(l))exp(eij(l))(3)

hi(l+1)=σ(∑j∈N(i)αij(l)zj(l))(4)\tag{4} h_{i}^{(l+1)}=\sigma\left(\sum_{j \in \mathcal{N}(i)} \alpha_{i j}^{(l)} z_{j}^{(l)}\right) hi(l+1)=σjN(i)αij(l)zj(l)(4)
multi-head attention机制
神似卷积神经网络里的多通道,GAT 引入了多头注意力来丰富模型的能力和稳定训练的过程。每一个注意力的头都有它自己的参数。如何整合多个注意力机制的输出结果一般有两种方式:

  • 拼接
    hi(l+1)=∥k=1,...,Kσ(∑j∈N(i)αijkWkhj(l))(5)\tag{5} h_{i}^{(l+1)}=\|_{k=1, ..., K} \sigma\left(\sum_{j \in N(i)} \alpha_{i j}^{k} W^{k} h_{j}^{(l)}\right) hi(l+1)=k=1,...,KσjN(i)αijkWkhj(l)(5)
  • 平均

hi(l+1)=σ(1k∑k=1K∑j∈N(i)αijkWkhj(l))(6)\tag{6} h_{i}^{(l+1)}=\sigma\left(\frac{1}{k} \sum_{k=1}^{K} \sum_{j \in N(i)} \alpha_{i j}^{k} W^{k} h_{j}^{(l)}\right) hi(l+1)=σk1k=1KjN(i)αijkWkhj(l)(6)

对于上述公式的一些解释:

  • 公式(1)对lll层节点的embeddinghi(l)h_{i}^{(l)}hi(l)做了一个线性变换,W(l)\mathbf{W}^{(l)}W(l)是一个该变换的一个可训练的参数
  • 公式(2)计算了成对节点间的原始注意力分数。它首先拼接了两个节点的embeddingzzz,注意∥\|在这里表示拼接;随后对拼接好的embedding以及一个可学习的权重向量a⃗(l)\vec{a}^{(l)}a (l)做点积;最后应用了一个LeakyReLU激活函数。这一形式的注意力机制通常被称为加性注意力,区别于Transformer(Attention Is All You Need)里的点积注意力
  • 公式(3)对于一个节点所有入边得到的原始注意力分数应用了一个softmax操作,得到了注意力权重
  • 公式(4),形似GCN的节点特征更新规则,对所有邻节点的特征做了基于注意力的加权求和
  • 公式(5)、(6)作者建议对中间层使用拼接对最后一层使用求平均

GAT的DGL实现

参考:https://github.com/dmlc/dgl/tree/master/examples/pytorch/gat

有错误的地方还望不吝指出,欢迎进群交流GNNs&GCNs(入群备注信息!!!,格式:姓名 -(学校或其他机构信息)- 研究方向)。

参考

Graph Attention Network (GAT)
DGL博客 | 深入理解图注意力机制

GAT - Graph Attention Network 图注意力网络 ICLR 2018相关推荐

  1. Graph Convolution Network图卷积网络(二)数据加载与网络结构定义

    背景 : 弄懂Graph Convolution Network的pytorch代码如何加载数据并且如何定义网络结构的. 代码地址:https://github.com/tkipf/pygcn 论文地 ...

  2. 【GAT】如何理解Graph Attention Network(注意力机制)?

    论文链接:Graph Attention Networks Github链接:https://github.com/PetarV-/GAT 1 GAT的背景 2 GAT的主要结构 3 GAT的创新点是 ...

  3. GCN (Graph Convolutional Network) 图卷积网络

    这几个同时看一下,感觉能理解不少: B站视频:https://www.bilibili.com/video/BV1ta4y1t7EK GCN论文原文和代码:https://github.com/tki ...

  4. 【GNN】图注意力网络GAT(含代码讲解)

    CSDN页面公式加载有问题,如果影响观看请戳本文的知乎版本:https://zhuanlan.zhihu.com/p/112938037 毫无疑问,图神经网络(Graph Neural Network ...

  5. 图注意力网络(Graph Attention Network, GAT) 模型解读与代码实现(tensorflow2.0)

    前面的文章,我们讲解了图神经网络三剑客GCN.GraphSAGE.GAT中的两个: 图卷积神经网络(GCN)理解与tensorflow2.0代码实现 GraphSAGE 模型解读与tensorflow ...

  6. 【图结构】之图注意力网络GAT详解

    作者:張張張張 github地址:https://github.com/zhanghekai [转载请注明出处,谢谢!] GATGATGAT源代码地址:https://github.com/Petar ...

  7. Relational Graph Attention Network for Aspect-based Sentiment Analysis

    1.Introducton 本篇文章是2020年发表于ACL的一篇文章,不同于其他人直接编码现成的依赖树,这篇文章中作者通过重塑与修剪普通的依赖树从而将方面词作为依赖树的根节点.此外作者还提出一个Re ...

  8. 知识图注意力网络 KGAT

    自经典的GAT之后,各种花式图注意力网络层出不穷. 例如, 动态图注意力网络,异质图注意力网络, 知识图注意力网络. 本文介绍了用于推荐的知识图注意力网络KGAT,发表在KDD2019. 作者: 黄海 ...

  9. DeepLearning | 图注意力网络Graph Attention Network(GAT)论文、模型、代码解析

    本篇博客是对论文 Velikovi, Petar, Cucurull, Guillem, Casanova, Arantxa,et al. Graph Attention Networks, 2018 ...

最新文章

  1. 安装python3.6.1_CentOS 7 安装Python3.6.1 多版本共存
  2. 使用Flex Bison 和LLVM编写自己的编译器[zz]
  3. mysql打开sql语句日志
  4. 牛客网_PAT乙级_10234有理数四则运算(20)【通过5/7:格式错误】
  5. eclipse中显示jquery或extjs自动提示
  6. Python操作MySQL的封装类
  7. [Robot Framework] User Guide : 如何自己创建library
  8. Linux学习笔记:rpm程序包管理
  9. 0基础python入门书籍 excel_零基础学Python3(23):Excel 基础操作(上)
  10. java-Aspose.Words的使用(Office文档转为PDF)
  11. Linux下常用组的权限特点,Linux中的用户与用户组
  12. php 去除空余字符,PHP 删除字符串末端的空白字符(或者其他字符)
  13. MIME,拓展名需要相应的软件打开
  14. Git 生成SSH Key 之使用PuTTYgen工具
  15. python 背单词_背单词方法大全
  16. 主流智能汽车电子架构
  17. 机器学习模型评估——混淆矩阵
  18. VxWorks6.7新建bootrom工程
  19. 迷宫问题超详解(栈实现)
  20. Ubuntu18.04编译Openwrt 15.05.1 Chaos Calmer版本固件遇到的问题汇总

热门文章

  1. 【网络】PFC背景和原理 (DCB=PFC + ETS)
  2. js图片转base64
  3. PLC模拟量输出 模拟量输出FB(FX3U连接FX2N-2DA)
  4. 几个优质的涵盖了各种语言的项目,快来看看吧
  5. 利用 clip-path 绘制不规则的图形
  6. 调试绝对值编码器测试角速度值
  7. 可视化神器Plotly玩转桑基图
  8. Tetgen软件学习和使用
  9. 徐小明:探寻股市下跌的真正原因
  10. 自定义Unity在iOS平台上的虚拟键盘