-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
419 lines (221 loc) · 263 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>吃了睡的程序猪</title>
<link href="https://over-shine.github.io/atom.xml" rel="self"/>
<link href="https://over-shine.github.io/"/>
<updated>2021-11-06T06:40:03.775Z</updated>
<id>https://over-shine.github.io/</id>
<author>
<name>程序猪-渔枫</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>Dropout</title>
<link href="https://over-shine.github.io/2021/11/06/Dropout/"/>
<id>https://over-shine.github.io/2021/11/06/Dropout/</id>
<published>2021-11-06T06:18:58.000Z</published>
<updated>2021-11-06T06:40:03.775Z</updated>
<content type="html"><![CDATA[<h1 id="Dropout解析"><a href="#Dropout解析" class="headerlink" title="Dropout解析"></a>Dropout解析</h1><a id="more"></a><p>Dropout的一般形式如下所示:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Dropout(p)</span><br></pre></td></tr></table></figure><p>其中p是一个0-1的小数,表示在训练时,使用伯努利分布的样本,以概率 $p$ 随机置零输入张量的一些元素。每个信道在每次前向调用时都将被独立地置零。</p><p>此外,对于那些没有被置0的参数,同时乘以 $\frac{1}{1-p}$ 进行放大。</p><p><strong>注意:</strong> 只有在model.train()模式下,Dropout才会起作用, 而在model.eval()模式下,Dropout不进行处理。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">In [5]: x=torch.rand(2,5)</span><br><span class="line">In [6]: x</span><br><span class="line">Out[6]:</span><br><span class="line">tensor([[0.9188, 0.6057, 0.4477, 0.6748, 0.0624],</span><br><span class="line"> [0.7781, 0.7598, 0.8580, 0.5582, 0.8246]])</span><br><span class="line">In [7]: model = nn.Dropout(0.5)</span><br><span class="line">In [8]: model.train()</span><br><span class="line">Out[8]: Dropout(p=0.5, inplace=False)</span><br><span class="line">In [9]: model(x)</span><br><span class="line">Out[9]:</span><br><span class="line">tensor([[0.0000, 0.0000, 0.8953, 1.3497, 0.0000],</span><br><span class="line"> [0.0000, 1.5197, 0.0000, 1.1163, 1.6493]])</span><br><span class="line">In [10]: model.eval()</span><br><span class="line">Out[10]: Dropout(p=0.5, inplace=False)</span><br><span class="line">In [11]: model(x)</span><br><span class="line">Out[11]:</span><br><span class="line">tensor([[0.9188, 0.6057, 0.4477, 0.6748, 0.0624],</span><br><span class="line"> [0.7781, 0.7598, 0.8580, 0.5582, 0.8246]])</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1 id="Dropout解析"><a href="#Dropout解析" class="headerlink" title="Dropout解析"></a>Dropout解析</h1></summary>
<category term="Pytorch" scheme="https://over-shine.github.io/categories/Pytorch/"/>
<category term="Tensorflow" scheme="https://over-shine.github.io/categories/Pytorch/Tensorflow/"/>
<category term="pytorch" scheme="https://over-shine.github.io/tags/pytorch/"/>
<category term="tensorflow" scheme="https://over-shine.github.io/tags/tensorflow/"/>
</entry>
<entry>
<title>vcpkg安装tensorflow采坑经验</title>
<link href="https://over-shine.github.io/2021/10/31/vcpkg%E5%AE%89%E8%A3%85tensorflow%E9%87%87%E5%9D%91%E7%BB%8F%E9%AA%8C/"/>
<id>https://over-shine.github.io/2021/10/31/vcpkg%E5%AE%89%E8%A3%85tensorflow%E9%87%87%E5%9D%91%E7%BB%8F%E9%AA%8C/</id>
<published>2021-10-31T14:50:11.000Z</published>
<updated>2021-11-06T06:40:39.225Z</updated>
<content type="html"><![CDATA[<h1 id="vcpkg-安装-tensorflow-cc-采坑记录"><a href="#vcpkg-安装-tensorflow-cc-采坑记录" class="headerlink" title="vcpkg 安装 tensorflow-cc 采坑记录"></a>vcpkg 安装 tensorflow-cc 采坑记录</h1><a id="more"></a><p>注意:安装tensorflow-cc需要保证磁盘最少有150G左右的空闲空间</p><h2 id="设置HTTP-S-PROXY"><a href="#设置HTTP-S-PROXY" class="headerlink" title="设置HTTP(S)_PROXY"></a>设置HTTP(S)_PROXY</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">vcpkg env</span><br><span class="line">set HTTPS_PROXY=http://127.0.0.1:10809/</span><br><span class="line">set HTTP_PROXY=http://127.0.0.1:10809/</span><br></pre></td></tr></table></figure><p>这里的端口号在自己电脑网络中查看代理</p><h2 id="设置git的https-proxy"><a href="#设置git的https-proxy" class="headerlink" title="设置git的https_proxy"></a>设置git的https_proxy</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git config --global https.proxy https://127.0.0.1:1080</span><br></pre></td></tr></table></figure><p>通过如下命令可以查看是否设置成功</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git config --global --list</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1 id="vcpkg-安装-tensorflow-cc-采坑记录"><a href="#vcpkg-安装-tensorflow-cc-采坑记录" class="headerlink" title="vcpkg 安装 tensorflow-cc 采坑记录"></a>vcpkg 安装 tensorflow-cc 采坑记录</h1></summary>
<category term="tensorflow" scheme="https://over-shine.github.io/tags/tensorflow/"/>
<category term="Error" scheme="https://over-shine.github.io/tags/Error/"/>
<category term="c++" scheme="https://over-shine.github.io/tags/c/"/>
</entry>
<entry>
<title>论文贡献记录</title>
<link href="https://over-shine.github.io/2021/05/17/%E8%AE%BA%E6%96%87%E8%B4%A1%E7%8C%AE%E8%AE%B0%E5%BD%95/"/>
<id>https://over-shine.github.io/2021/05/17/%E8%AE%BA%E6%96%87%E8%B4%A1%E7%8C%AE%E8%AE%B0%E5%BD%95/</id>
<published>2021-05-17T03:49:37.000Z</published>
<updated>2021-11-06T06:53:42.073Z</updated>
<content type="html"><![CDATA[<h1 id="论文贡献记录"><a href="#论文贡献记录" class="headerlink" title="论文贡献记录"></a>论文贡献记录</h1><a id="more"></a><h2 id="Extracting-multiple-relations-in-one-pass-with-pre-trained-transformers论文"><a href="#Extracting-multiple-relations-in-one-pass-with-pre-trained-transformers论文" class="headerlink" title="Extracting multiple-relations in one-pass with pre-trained transformers论文"></a>Extracting multiple-relations in one-pass with pre-trained transformers<a href="https://arxiv.org/pdf/1905.08284.pdf%22">论文</a></h2><h3 id="贡献"><a href="#贡献" class="headerlink" title="贡献"></a>贡献</h3><h2 id="A-Novel-Document-Level-Relation-Extraction-Method-Based-on-BERT-and-Entity-Information论文"><a href="#A-Novel-Document-Level-Relation-Extraction-Method-Based-on-BERT-and-Entity-Information论文" class="headerlink" title="A Novel Document-Level Relation Extraction Method Based on BERT and Entity Information论文"></a>A Novel Document-Level Relation Extraction Method Based on BERT and Entity Information<a href="https://ieeexplore.ieee.org/iel7/6287639/8948470/09098945.pdf">论文</a></h2><h3 id="贡献-1"><a href="#贡献-1" class="headerlink" title="贡献"></a>贡献</h3><ol><li>首先,我们提出了一种实体掩码方法(将每个不同实体用不同的special token替代),可以将实体的身份和类型信息引入模型.<img src="img1.png" alt="">。</li><li>提出了一个基于BERT的“one-pass”模型,该模型通过使用所提出的实体掩码方法来引入实体信息,并且所提出的模型在DocRed数据集上实现了最先进的性能。</li></ol><h2 id="DocRED-A-Large-Scale-Document-Level-Relation-Extraction-Dataset论文"><a href="#DocRED-A-Large-Scale-Document-Level-Relation-Extraction-Dataset论文" class="headerlink" title="DocRED: A Large-Scale Document-Level Relation Extraction Dataset论文"></a>DocRED: A Large-Scale Document-Level Relation Extraction Dataset<a href="https://arxiv.org/pdf/1906.06127">论文</a></h2><h3 id="DocRED数据集特点"><a href="#DocRED数据集特点" class="headerlink" title="DocRED数据集特点"></a>DocRED数据集特点</h3><ol><li>DocRED包含5053个Wikipedia文档中注释的132375个实体和56354个关系事实,使其成为最大的带有人类注释的文档级RE数据集。</li><li>由于DocRED中至少40.7%的关系事实只能从多个句子中提取,因此DocRED要求阅读文档中的多个句子以识别实体并通过综合文档的所有信息来推断它们之间的关系。 这将DocRED与那些句子级RE数据集区分开来。</li><li>我们还提供了大规模的远程监督数据,以支持弱监督的RE研究。</li></ol><h3 id="人工注释数据收集步骤"><a href="#人工注释数据收集步骤" class="headerlink" title="人工注释数据收集步骤"></a>人工注释数据收集步骤</h3><ol><li>为Wikipedia文档生成远程监督的注释。</li><li>注释文档中的所有命名实体和共指信息。</li><li>将命名实体链接到Wikidata项目。</li><li>标注关系和相应的支持证据。</li></ol><p>步骤2和4需要按照下面的步骤迭代处理3次:</p><ol><li>使用命名实体识别(NER)模型来生成命名实体,或使用远程监督和RE模型推荐关系。</li><li>来生成命名实体。</li><li>查看并进一步修改第二遍的注释结果,以获得更好的准确性和一致性。</li></ol><p>为了确保注释器训练有素,采用了有原则的训练程序,并且注释器必须在对数据集进行注释之前通过测试任务。 并且只有经过精心选择的有经验的注释器才有资格进行第三遍注释。</p>]]></content>
<summary type="html"><h1 id="论文贡献记录"><a href="#论文贡献记录" class="headerlink" title="论文贡献记录"></a>论文贡献记录</h1></summary>
<category term="论文" scheme="https://over-shine.github.io/categories/%E8%AE%BA%E6%96%87/"/>
<category term="NLP" scheme="https://over-shine.github.io/tags/NLP/"/>
</entry>
<entry>
<title>Attention Summary in NLP</title>
<link href="https://over-shine.github.io/2021/03/12/Attention-Summary-in-NLP/"/>
<id>https://over-shine.github.io/2021/03/12/Attention-Summary-in-NLP/</id>
<published>2021-03-12T09:15:05.000Z</published>
<updated>2021-11-06T06:54:45.362Z</updated>
<content type="html"><![CDATA[<h1 id="Attention-summary-in-NLP"><a href="#Attention-summary-in-NLP" class="headerlink" title="Attention summary in NLP"></a>Attention summary in NLP</h1><a id="more"></a>]]></content>
<summary type="html"><h1 id="Attention-summary-in-NLP"><a href="#Attention-summary-in-NLP" class="headerlink" title="Attention summary in NLP"></a>Attention summary in NLP</h1></summary>
<category term="随笔" scheme="https://over-shine.github.io/categories/%E9%9A%8F%E7%AC%94/"/>
<category term="Attention" scheme="https://over-shine.github.io/tags/Attention/"/>
<category term="NLP" scheme="https://over-shine.github.io/tags/NLP/"/>
</entry>
<entry>
<title>Matching the Blanks: Distributional Similarity for Relation Learning</title>
<link href="https://over-shine.github.io/2020/11/02/Matching-the-Blanks-Distributional-Similarity-for-Relation-Learning/"/>
<id>https://over-shine.github.io/2020/11/02/Matching-the-Blanks-Distributional-Similarity-for-Relation-Learning/</id>
<published>2020-11-02T02:22:30.000Z</published>
<updated>2021-11-06T06:56:51.502Z</updated>
<content type="html"><![CDATA[<h1 id="Matching-the-Blanks-Distributional-Similarity-for-Relation-Learning"><a href="#Matching-the-Blanks-Distributional-Similarity-for-Relation-Learning" class="headerlink" title="Matching the Blanks: Distributional Similarity for Relation Learning"></a>Matching the Blanks: Distributional Similarity for Relation Learning</h1><a id="more"></a><p>可以对任意关系建模的通用关系提取器是信息提取中的核心期望。之前提出的构建通用关系抽取器的方法,如用表面形式(Surface Form)来表示关系,或者联合嵌入关系的表面形式和现存知识图谱中的关系的方法,都不能够很好地泛化。在本文中,我们基于 Harris 的分布假设对关系的扩展以及在学习文本表示形式(特别是BERT)方面的最新进展,以完全从实体链接的文本构建与任务无关的关系表示形式。我们证明,即使不使用任何任务的训练数据,这些表示也大大优于以前基于示例的关系提取(FewRel)的工作。我们还显示,使用任务无关的表示形式初始化的模型,然后在受监督的关系提取数据集上进行了调整,大大优于 SemEval 2010 Task 8,KBP37 和 TACRED 上的先前方法。</p><h2 id="1-简介"><a href="#1-简介" class="headerlink" title="1. 简介"></a>1. 简介</h2><p>读取文本来识别和提取实体间的关系一直是 NLP 中的一个长期目标。通常在关系提取中的研究方向可以分为三组。第一个方向是监督或远程监督的关系提取器在有限的模式下学习一个从文本到关系的映射;第二个方向是,开放信息提取通过使用它们的表面形式表示关系来解决预定义模式的局限性,这扩大了范围,但由于许多表面形式可以表达相同的关系,因此也导致缺乏通用性。最后,通用模式既包含文本的多样性,又包含示意关系的简洁性,可以构建一种扩展到任意文本输入和任意实体对的联合表示形式。但是,就像远程监督的关系提取器一样,通用模式依赖于可以与文本对齐的大型知识图。</p><p>在 Lin 和 Pantel 将 Harris 的分布假设扩展到关系的基础上,以及从上下文中学习单词表示的最新进展,我们提出了一种直接从文本中学习关系表示的新方法。首先,我们研究了 Transformer 神经网络架构对实体对之间的关系进行编码的能力,并确定了一种在监督关系提取中表现优于先前工作的表示方法。 然后,我们提出一种通过匹配空白而无需知识图或人工注释者任何监督的情况下训练这种关系表示的方法。</p><p>继 Riedel,我们假设访问了一个语料库,其中实体已链接到唯一标识符,并且我们定义了一个关系语句为包含两个标记实体的文本块。据此,我们创建了包含关联语句的训练数据,其中实体已被特殊的[BLANK]符号替换,如图1所示。我们的训练过程采用成对的包含空白[BLANK]的关联语句,其目标是如果关系表示在同一对实体上,则鼓励它们相似。</p><div align=center><img src="1.png"/></div><p>经过训练后,我们将学习到的关系表示形式用于最近发布的FewRel 任务,其中特定的关系(例如“original language of work”)用一些示例表示,例如The Crowd(Italian:La Folla)是1951年的意大利电影。Han 将 FewRel 展示为监督数据集,旨在评估模型在测试时适应新领域关系的能力。我们证明,通过匹配空白的训练而不要任何 FewRel 训练数据,我们可以胜过 Han 在 FewRel 上的最高表现。我们还显示,通过匹配空白进行预训练并在 FewRel 上进行调整的模型在 FewRel 评估中的性能优于人类。同样,通过匹配空白训练然后再标注数据上微调,我们极大地提高了在 SemEval 2010 Task 8、KBP-37 和 TACRED 等关系提取基准模型上的性能。</p><h2 id="2-综述"><a href="#2-综述" class="headerlink" title="2. 综述"></a>2. 综述</h2><h3 id="2-1-任务定义"><a href="#2-1-任务定义" class="headerlink" title="2.1 任务定义"></a>2.1 任务定义</h3><p>在这篇论文中,我们关注于学习从关系语句到关系表示的映射。通常,令 $\mathbf{x}=[x_0 \ldots x_n]$ 表示一个 token 序列,其中,$x_0=[CLS], x_n=[SEP]$ 是序列的开始和结束标记,令 $\mathbf{s}_1=(i,j), \mathbf{s}_2=(k, l)$ 表示像 $0<i<j-1,j<k,k\le l-1, l\le n$ 的整数对。一个关系句子是一个三元组 $\mathbf{r}=(\mathbf{x}, \mathbf{s}_1, \mathbf{s}_2)$,其中 $\mathbf{s}_1$ 和 $\mathbf{s}_2$ 的索引表示界定了 $\mathbf{x}$ 中的实体:序列 $[x_i\ldots x_{j-1}]$ 是一个实体,$[x_k\ldots x_{l-1}]$ 也是一个实体。我们的目标是是学习一个函数 $\mathbf{h}_r=f_\theta(\mathbf{r})$ 将关系句子映射成一个定长的 $\mathbf{h}_r\in\mathcal{R}^d$ 向量,它表示在序列 $\mathbf{x}$ 中被 $\mathbf{s}_1$ 和 $\mathbf{s}_2$ 标记的实体间的关系。</p><h3 id="2-2-贡献"><a href="#2-2-贡献" class="headerlink" title="2.2 贡献"></a>2.2 贡献</h3><p>这篇论文包含两个贡献:</p><ol><li>首先对关系编码器 $f_\theta$ 引入了不同的框架,所有编码器都是使用最广的 Transformer 序列模型上。我们通过在有监督的训练下将它们应用到一组关系提取基准中,来评估每种体系结构。</li><li>最重要的贡献是 $f_\theta$ 可以通过实体链接文本的形式从广泛使用的远程监控中学到。</li></ol><h2 id="3-关系学习框架"><a href="#3-关系学习框架" class="headerlink" title="3 关系学习框架"></a>3 关系学习框架</h2><p>这项工作的主要目标是开发直接从文本产生关系表示的模型。鉴于最近在各种语言建模上训练的深度 Transformer 表现的强大性能,我们采用了Devlin等人的BERT模型作为我们工作的基础。在本节中,我们探索使用Transformer模型表示关系的不同方法。</p><h3 id="3-1-关系分类和提取任务"><a href="#3-1-关系分类和提取任务" class="headerlink" title="3.1 关系分类和提取任务"></a>3.1 关系分类和提取任务</h3><p>我们在一套有监督的关系提取基准上评估了不同的表示方法。我们使用的关系提取任务可以大致分为两种类型:完全监督的关系提取和少量关联匹配。</p><p>对于监督任务,目标是对于给定的关系句子 $\mathbf{r}$,预测关系类型 $t\in\mathcal{T}$,其中, $\mathcal{T}$ 是一个固定的关系类型字典,并且 $t=0$ 通常代表在关系句子中,实体间缺少关系。对于这种类型的任务,我们在 SemEval 2010 Task 8、KBP-37 和 TACRED 上进行了评估。</p><p>在少量关系匹配的情况下,根据查询关系语句对一组候选关系语句进行排序和匹配。在此任务中,测试和开发集中的示例通常包含训练集中不存在的关系类型。对于这种类型的任务,我们在 FewRel 数据集上进行了评估。对于给定的 $K$ 个带 $N$ 个标签关系语句集合 $\mathcal{S}_k=\{(\mathbf{r}_0, t_0)\ldots (\mathbf{r}_N, t_N)\}$,其中,$t_i\in\{1\ldots K\}$ 是相关的关系类型。对于一个查询关系语句,目标是预测 $t_q\in\{1\ldots K\}$</p><h3 id="3-2-深度-Transformer-模型的关系表示"><a href="#3-2-深度-Transformer-模型的关系表示" class="headerlink" title="3.2 深度 Transformer 模型的关系表示"></a>3.2 深度 Transformer 模型的关系表示</h3><p>这一节的所有实验中,我们从 Devlin 提供的 BERT-Large 模型开始并针对特定任务开始训练。因为 BERT 还没有被用到关系表示的问题上,我们旨在回答两个主要的建模问题:</p><ul><li>(1)如何在 BERT 的输入中表示感兴趣的实体</li><li>(2)如何从 BERT 的输出中提取一个关系的定长表示。</li></ul><p>我们为输入编码和输出关系表示提供了三个选项。下图说明了这些的六个组合。</p><div align=center><img src="3.png"/></div><p>回顾第2节,关系语句 $\mathbf{r} =(\mathbf{x}, \mathbf{s}_1, \mathbf{s}_2)$ 包含标记序列 $\mathbf{x}$ 和实体跨度标识符 $\mathbf{s}_1$ 和 $\mathbf{s}_2$。 我们提供了三种不同的选项,用于将有关聚焦范围 $\mathbf{s}_1$ 和 $\mathbf{s}_2$ 的信息获取到BERT编码器中。</p><h4 id="3-2-1-标准输入"><a href="#3-2-1-标准输入" class="headerlink" title="3.2.1 标准输入"></a>3.2.1 标准输入</h4><p>首先,我们尝试使用无法访问实体范围 $\mathbf{s}_1$ 和 $\mathbf{s}_2$ 的任何显式标识的BERT模型。我们将此选择称为“标准”输入。这是一个重要的参考点,因为我们相信 BERT 可以识别 $\mathbf{x}$ 中的实体,但是使用标准输入,当 $\mathbf{x}$ 包含两个以上提及的实体时,无法知道哪个两个实体处于焦点。</p><h4 id="3-2-2-位置嵌入"><a href="#3-2-2-位置嵌入" class="headerlink" title="3.2.2 位置嵌入"></a>3.2.2 位置嵌入</h4><p>对于输入的每个 token,BERT 也会添加一个段嵌入,主要是用于添加句子信息到模型。为了解决标准表示形式缺乏明确的实体标识的问题,我们引入了两个新的分段嵌入,一个嵌入到跨度 $\mathbf{s}_1$ 中的所有标记中,另一个添加到跨度 $\mathbf{s}_2$ 中的所有标记中。这种方法类似于以前的工作,在该工作中,将位置嵌入应用于关系提取.</p><h4 id="3-2-3-实体标记-token"><a href="#3-2-3-实体标记-token" class="headerlink" title="3.2.3 实体标记 token"></a>3.2.3 实体标记 token</h4><p>最后,我们用四个保留词来扩展 $\mathbf{x}$,以在关系语句中标记每个实体提及的开始和结束。我们引入 $[E1_{start}], [E1_{end}], [E2_{start}], [E2_{end}]$,并且修改 $\mathbf{x}$ 为:</p><script type="math/tex; mode=display">\tilde{\mathbf{x}}=[x_0\ldots[E1_{start}]x_i\ldots x_{j-1}[E1_{end}]\ldots[E2_{start}]x_k\ldots x_{l-1}[E2_{end}]\ldots x_n]</script><p>并且将 $\tilde{\mathbf{x}}$ 代替 $\mathbf{x}$ 作为 BERT 的输入,同样更新实体索引 $\tilde{\mathbf{s}}_1=(i+1,j+1), \tilde{\mathbf{s}}_2=(K+3,l+3)$,我们将此输入的表示形式称为ENTITY MARKERS。</p><h3 id="3-3-定长的关系表示"><a href="#3-3-定长的关系表示" class="headerlink" title="3.3 定长的关系表示"></a>3.3 定长的关系表示</h3><p>现在,我们介绍三种从BERT编码器提取固定长度关系表示 $\mathbf{h}_r$ 的单独方法。这三个变体依赖于提取 Transformer 网络的最后一个隐藏层,我们将其定义为 $H = [\mathbf{h}_0,\ldots, \mathbf{h}_n]$ 表示 $n=|\mathbf{x}|$(如果使用实体标记 token,则为 $|\tilde{\mathbf{x}}|$)。</p><h4 id="3-3-1-CLS-token"><a href="#3-3-1-CLS-token" class="headerlink" title="3.3.1 [CLS] token"></a>3.3.1 [CLS] token</h4><p>回顾第二节,每个 $\mathbf{x}$ 以一个保留词 [CLS] 开始,BERT 的输出状态和 [CLS] 对应的向量作为句子 $\mathbf{x}$ 的表示。</p><h4 id="3-3-2-Entity-mention-pooling"><a href="#3-3-2-Entity-mention-pooling" class="headerlink" title="3.3.2 Entity mention pooling"></a>3.3.2 Entity mention pooling</h4><p>我们通过对 BERT 的最后一层输出中每个实体对应的 token 做最大池化操作得到两个向量 $\mathbf{h}_{e1}=\mathbf{MAXPOOL}([h_i\ldots h_{j-1}]), \mathbf{h}_{e2}=\mathbf{MAXPOOL}([h_k\ldots h_{l-1}])$ 表示两个提及的实体,我们将这两个向量拼接得到一个单独的表示 $\mathbf{h}_r=<\mathbf{h}_{e1}|\mathbf{h}_{e2}>$,我们称这个框架为 MENTION POOLING。</p><h4 id="3-3-3-Entity-start-state"><a href="#3-3-3-Entity-start-state" class="headerlink" title="3.3.3 Entity start state"></a>3.3.3 Entity start state</h4><p>最后,当使用 ENTITY MARKERS 时,我们建议使用它们各自的起始标记的最终隐藏状态的级联来简单地表示两个实体之间的关系。回顾 ENTITY MARKERS 在 $\mathbf{x}$ 中插入的 token,并在 $\mathbf{s}_1$ 和 $\mathbf{s}_2$ 中创建偏移量,我们对该关系的表示是 $\mathbf{r}_h=<\mathbf{h}_i|\mathbf{h}_{j+2}>$</p><p>图3显示了我们在这一节评估的一些变体。除了定义了模型的输入和输出框架,确定了用于训练模型的损失函数,如图2所示。在所有的模型中,来自 Transformer 网络的输出表示作为包含线性激活函数或者执行正则化的全连接层的输入。我们将选后 Transfomer 层的选择视为超参数,并对每个任务使用性能最佳的层类型。</p><p>对于监督任务,我们引入一个新的分类层 $\mathcal{W}\in\mathcal{R}^{K\times H}$,其中,$H$ 是关系表示的大小,$K$ 是关系的类别数量,分类损失是 $\mathbf{h}_rW^T$ 的 $softmax$ 相对于真实关系类型的标准交叉熵。</p><p>对于 few-shot 任务,我们使用查询语句与每个候选语句之间的关系表示之间的点积作为相似性得分。 在这种情况下,我们还对真实类别应用了相似评分的softmax的交叉熵损失。</p><p>对于所有变体,我们使用以下超参数集对 BERT 模型执行特定于任务的微调:</p><ul><li>Transformer 结构:24 layers,1024 hidden size,16 heades</li><li>权重初始化:BERT-Large</li><li>Post Transformer Layer:线性激活的全连接层(KBP-37 and TACRED),或正则化层(SemEval 2010 and FewRel)</li><li>训练次数:1-10</li><li>学习率(监督):Adam 3e-5</li><li>批次大小(监督):64</li><li>学习率(few-shot):SGD 1e-4</li><li>批次大小(few-shot):256</li></ul><p>表1显示了三个监督关系提取任务上的模型变体的结果,以及 few-shot关系提取任务的 5-way-1-shot 变体的结果。对于4个任务,模型使用 ENTUTY MARKERS 输入表示和 ENTITY START 输出表示取得最好效果。</p><div align=center><img src="4.png"/></div><p>从结果中可以看出在输入中添加位置信息对于模型学习有用的关系表示是非常重要的。与先前从位置嵌入中受益的工作不同,深层的 Transformer 受益于看到新的实体边界词块 $[E_{start}], E_{end}$(ENTITY MARKERS)。还值得注意的是,在所有四个任务上,最佳变体的性能均优于先前发布的模型。在本文的其余部分,我们将在进一步训练和评估模型时使用此框架。</p><h2 id="4-Learning-by-Matching-the-Blanks"><a href="#4-Learning-by-Matching-the-Blanks" class="headerlink" title="4. Learning by Matching the Blanks"></a>4. Learning by Matching the Blanks</h2><p>到目前为止,我们使用了人工标注数据去训练我们的关系句子编码器 $f_\theta$。受开放信息提取启发,直接从标记文本中获取关系的方法,我们现在介绍一种无需预定义本体或关系标签训练数据的新训练方法。相反,我们声明对于任何一对关系语句 $\mathbf{r}$ 和 $\mathbf{r}^\prime$,如果两个关系语句 $\mathbf{r}$ 和 $\mathbf{r}^\prime$ 表示语义上相似的关系,则内积 $f_\theta(\mathbf{r})>f_\theta(\mathbf{r}^\prime)$ 应该较高。并且,如果两个关系语句在语义上表达不同的关系,则该内积应较低。与远程监督中有关信息提取的相关工作不同,我们在训练时不使用关系标签。取而代之的是,我们观察到 Web 文本中存在高度冗余,并且任意一对实体之间的每个关系都可能被多次声明。随后,如果 $\mathbf{s}_1$ 和 $\mathbf{s}_1^\prime$ 指代相同的实体,并且 $\mathbf{s}_2$ 和 $\mathbf{s}_2^\prime$ 指代相同的实体,那么 $\mathbf{r}=(\mathbf{x}, \mathbf{s}_1, \mathbf{s}_2)$ 更可能和 $\mathbf{r}^\prime=(\mathbf{x}^\prime, \mathbf{s}_1^\prime, \mathbf{s}_2^\prime)$ 编码相同的语义信息。从观察开始,我们介绍了一种从实体链接文本中学习 $f_\theta$ 的新方法。我们通过匹配空白(MTB)来介绍这种学习方法。在第5节中,我们展示了MTB学习的关系表示形式,无需对关系提取进行任何进一步的调整就可以使用它们,甚至可以击败以前在人工标记数据上进行训练的模型。</p><h3 id="4-1-学习设置"><a href="#4-1-学习设置" class="headerlink" title="4.1 学习设置"></a>4.1 学习设置</h3><p>令 $\mathcal{E}$ 表示预定义的实体集合,并且 $\mathcal{D}=[(\mathbf{r}^0, e_1^0, e_2^0)\ldots(\mathbf{r}^N, e_1^N, e_2^N)]$ 是一个有被两个实体标注 $e_1^i, e_2^i\in\mathcal{E}$ 的关系句子的语料库。$\mathbf{r}^i=(\mathbf{x}^i, \mathbf{s}_1^i, \mathbf{s}_2^i)$,其中,$\mathbf{s}_1^i$ 和 $\mathbf{s}_2^i$ 界定 $\mathbf{x}^i$ 中的实体。通过将关系语句 $\mathbf{r}^i$ 分别与对应于跨度 $\mathbf{s}_1^i$ 和 $\mathbf{s}_2^i$ 的两个实体 $e_1^i$ 和 $e_2^i$ 配对来创建 $\mathcal{D}$ 中的每个项。</p><p>我们旨在学习一个关系语句编码器 $f_\theta$,我们可以用它来确定两个关系语句是否编码相同的关系。为了实现这个目标,我们定义了如下的二分类器为 $\mathbf{r}$ 和 $\mathbf{r}^\prime$ 编码相同关系 $(l=1)$ 或不编码 $(l=0)$ 的情况指定一个概率。</p><script type="math/tex; mode=display">p\left(l=1 \mid \mathbf{r}, \mathbf{r}^{\prime}\right)=\frac{1}{1+\exp f_{\theta}(\mathbf{r})^{\top} f_{\theta}\left(\mathbf{r}^{\prime}\right)}</script><p>我们之后通过最小化下面的损失学习 $f_\theta$ 的参数</p><script type="math/tex; mode=display">\begin{aligned}\mathcal{L}(\mathcal{D})=-& \frac{1}{|\mathcal{D}|^{2}} \sum_{\left(\mathrm{r}, e_{1}, e_{2}\right) \in \mathcal{D}}\sum_{\left(\mathrm{r}^{\prime}, e_{1}^{\prime}, e_{2}^{\prime}\right) \in \mathcal{D}} \\& \delta_{e_{1}, e_{1}^{\prime}} \delta_{e_{2}, e_{2}^{\prime}} \cdot \log p\left(l=1 \mid \mathrm{r}, \mathrm{r}^{\prime}\right)+\\&\left(1-\delta_{e_{1}, e_{1}^{\prime}} \delta_{e_{2}, e_{2}^{\prime}}\right) \cdot \log \left(1-p\left(l=1 \mid \mathrm{r}, \mathrm{r}^{\prime}\right)\right)\end{aligned}</script><p>其中,$\delta_{e,e^\prime}$ 是 Kronecker 增量,如果 $e=e^\prime$,它取值为1,否则取值为0。</p><h3 id="4-2-Introducing-Blanks"><a href="#4-2-Introducing-Blanks" class="headerlink" title="4.2 Introducing Blanks"></a>4.2 Introducing Blanks</h3><p>读者可能注意到上述的损失可以通过用于创建 $\mathcal{D}$ 的实体链接系统将其最小化。并且,由于该链接系统没有任何关系的概念,因此假设 $f_\theta$ 将以某种方式神奇地构建有意义的关系表示形式是不合理的。为了避免简单地重新学习实体链接系统,我们引入了一个经过修改的语料库</p><script type="math/tex; mode=display">\tilde{\mathcal{D}}=\left[\left(\tilde{\mathbf{r}}^{0}, e_{1}^{0}, e_{2}^{0}\right) \ldots\left(\tilde{\mathbf{r}}^{N}, e_{1}^{N}, e_{2}^{N}\right)\right]</script><p>其中,每个 $\tilde{\mathbf{r}}^i=(\tilde{\mathbf{x}}^i, \mathbf{s}_1^i, \mathbf{s}_2^i)$ 包含一个关系句,其中一个或两个实体可能已被特殊的 [BLANK] 符号代替。具体来说,$\tilde{\mathbf{x}}$ 包含 $\mathbf{s}_1$ 定义的跨度,其概率为 $\alpha$。否则,跨度已被单个 [BLANK] 符号代替。$\mathbf{s}_2$ 同样如此。$\tilde{\mathcal{D}}$ 中只有$\alpha^2$ 的概率,两个关系语句显式命名参与关系的两个实体。结果,最小化 $\mathcal{L}(\tilde{\mathcal{D}})$ 需要 $f_\theta$ 做更多的工作,而不是简单地标识 $\mathbf{r}$ 中的命名实体。我们假设在 $\tilde{\mathcal{D}}$ 上进行训练将导致 $f_\theta$ 编码两个可能消失的实体跨度之间的语义关系。</p><h3 id="4-3-Matching-the-Blanks-Training"><a href="#4-3-Matching-the-Blanks-Training" class="headerlink" title="4.3 Matching the Blanks Training"></a>4.3 Matching the Blanks Training</h3><p>为了使用 match the blanks 任务训练模型,我们构建了一个和 BERT 相似的训练设置,同时使用两个损失:MLM 损失和 MTB 损失。为了生成训练语料库,我们使用英语 Wikipedia 并从 HTML 中的段落块提取文本信息,忽略列表和表格。我们使用现成的实体链接系统来注释具有唯一知识库标识符的文本跨度。 跨度注释不仅包括专有名称,还包括其他指称实体,例如普通名词和代词。从带注释的语料库中,我们提取关系语句,其中每个语句在固定大小的 token 窗口中至少包含两个真实的实体。为了避免偏向流行实体的关系语句,我们通过随机采样一定数量的包含任何给定实体的关系语句来限制包含相同实体的关系语句的数量。</p><p>我们使用这些语句训练模型的参数来最小化损失函数 $\mathcal{L}(\tilde{\mathcal{D}})$。在实际中,不可能和每个关系句对进行比较,如上面的损失函数,所以我们使用噪声对比估计。在此估算中,我们考虑了包含同一实体的所有对关系语句的正对,因此损失函数中的第一项贡献不变,其中 $\delta_{e_1,e_1^\prime}\delta_{e_2,e_2^\prime}=1$。但是,近似值确实会改变第二项的贡献。我们不对所有不包含同一对实体的关系语句对进行求和,而是对一组负样本进行采样,这些负例要么从所有关系语句对的集合中统一随机抽样,要么从一组共享一个实体的关系句中抽样。我们包括第二组“硬”否定词,以说明以下事实:大多数随机采样的关系语句对极不可能在局部上具有远距离相关性,并且我们要确保训练过程能够看到引用相似的关系语句对,但关系不同。最后,如第3.2节所述,我们以 $\alpha=0.7$ 的概率用[BLANK] 符号替换提及的每个实体,以确保模型不会因评估任务中没有 [BLANK] 符号而感到困惑。总共,我们从英语维基百科中生成了6亿个关联声明对,大致分为50%的正例和50%的强烈的负例。</p><h2 id="5-试验评估"><a href="#5-试验评估" class="headerlink" title="5. 试验评估"></a>5. 试验评估</h2><p>在本节中,我们通过匹配空白来评估训练的影响。我们从第3.3节中基于 BERT 的最佳模型开始,我们将其称为 $BERT_{EM}$,并将其与经过匹配空白任务训练的变量($BERT_{EM} + MTB$)进行比较。 我们通过将 Transformer 权重初始化为 $BERT_{LARGE}$ 的权重来训练 $BERT_{EM} + MTB$ 模型,并使用以下参数:</p><ul><li>学习率: Adam 3e-5</li><li>批次大小:2048</li><li>训练步数:1百万</li><li>关系表示:ENTITY MARKER</li></ul><p>我们使用 $BERT_{EM}$ 和 $BERT_{EM} + MTB$ 相同的针对特定任务的训练方法,报告了第3.1节中所有任务的结果。</p><h3 id="5-1-Few-shot-Relation-Matching"><a href="#5-1-Few-shot-Relation-Matching" class="headerlink" title="5.1 Few-shot Relation Matching"></a>5.1 Few-shot Relation Matching</h3><p>首先,我们研究了 $BERT_{EM} + MTB$ 在没有任何特定于任务的训练数据的情况下解决 FewRel 任务的能力。由于 FewRel 是基于示例的方法,因此我们可以根据每个候选关系语句的表示形式与示例表示形式的内积对其进行排名。</p><p>图4显示,与任务无关的 $BERT_{EM}$ 和 $BERT_{EM} + MTB$ 模型甚至比以前发布的有关 FewRel 任务的最新技术要好,即使他们没有看到任何 FewRel 训练数据也是如此。对于 $BERT_{EM} + MTB$ 而言,在 5-way-1-shot 任务和 10-way-1-shot 任务中,Han 的监督方法所占的比例显着提高了8.8%。在这种不受监督的设置中,$BERT_{EM} + MTB$ 的性能也大大优于 $BERT_{EM}$,这是可以预期的,因为在 $BERT_{EM}$ 的训练过程中没有因关系而造成的损失。</p><p>为了调查监督对 $BERT_{EM}$ 和 $BERT_{EM} + MTB$ 的影响,我们引入了越来越多的 FewRel 培训数据。图4显示了性能的提高,因为我们要么增加每种关系类型的训练示例数量,要么增加训练数据中的关系类型数量。在获得所有培训数据的访问权限后,$BERT_{EM}$ 就会达到 $BERT_{EM} + MTB$ 的性能。但是,当我们在训练期间保留所有关系类型并更改每个示例的类型数量时,$BERT_{EM} + MTB$ 只需要6%的训练数据即可匹配在所有训练数据上训练的 $BERT_{EM}$ 模型的性能。 我们观察到,保持关系类型的多样性并减少每种类型的示例数量,是减少此任务注释工作的最有效方法。 图4中的结果表明,可以使用 $MTB$ 训练显着减少实施基于示例的关系提取系统的工作量。</p><p>最后,我们在表3中报告 $BERT_{EM} + MTB$ 在 FewRel 的所有受完全监督的任务上的性能。 我们看到它的性能优于 Han 等人报道的人类上限,它的表现明显好于 FewRel 排行榜上所有其他已发布或未发布的内容。</p><h3 id="5-2-监督关系提取"><a href="#5-2-监督关系提取" class="headerlink" title="5.2 监督关系提取"></a>5.2 监督关系提取</h3><p>表4包含根据监督关系提取数据调整的分类器结果。 、正如在3.2节中所确定的那样,我们基于 $BERT_{EM}$ 的分类器在这三个任务上的性能优于先前发布的结果。 额外的基于 $MTB$ 的培训进一步提高了所有任务的 F1 分数。</p><p>我们还分析了两个模型的性能,同时减少了受监督的任务特定调整数据的数量。表5中显示的结果显示了在调整任务特定训练数据的随机子集时的开发集性能。对于所有任务,我们看到基于MTB的培训对于资源匮乏的案例甚至更为有效,因为在这些案例中,我们的 $BERT_{EM}$ 和基于 $BERT_{EM} + MTB$ 的分类器之间的性能差距更大。这进一步支持了我们的论点,即通过匹配空格进行培训可以显着减少创建关系提取器并填充知识库所需的人工输入量。</p><p>在本文中,我们研究直接从文本产生有用的关系表示的问题。我们描述了一种新颖的训练设置,我们称之为匹配空白,它完全依赖于实体分辨率注释。结合用于微调 BERT 中关系表示的新体系结构,我们的模型可在三个关系提取任务上实现最新的结果,并且在几次匹配关系匹配方面的表现均优于人工精度。此外,我们展示了新模型在资源短缺的情况下如何特别有效,并且我们认为它可以大大减少创建关系提取器所需的人力。</p><p>在将来的工作中,我们计划根据 $BERT_{EM} + MTB$ 对具有相似表示形式的关系语句进行聚类,以进行关系发现。这将使我们朝着实现真正通用关系识别和提取目标的方向走一些路。我们还将研究可用于在分布式知识库中存储关系三元组的关系和实体的表示形式。这是受到知识库嵌入方面最新工作的启。</p>]]></content>
<summary type="html"><h1 id="Matching-the-Blanks-Distributional-Similarity-for-Relation-Learning"><a href="#Matching-the-Blanks-Distributional-Similarity-for-Relation-Learning" class="headerlink" title="Matching the Blanks: Distributional Similarity for Relation Learning"></a>Matching the Blanks: Distributional Similarity for Relation Learning</h1></summary>
<category term="论文" scheme="https://over-shine.github.io/categories/%E8%AE%BA%E6%96%87/"/>
<category term="NLP" scheme="https://over-shine.github.io/tags/NLP/"/>
<category term="RE" scheme="https://over-shine.github.io/tags/RE/"/>
</entry>
<entry>
<title>GPT-GNN: Generative Pre-Training of Graph Neural Networks</title>
<link href="https://over-shine.github.io/2020/08/29/GPT-GNN-Generative-Pre-Training-of-Graph-Neural-Networks/"/>
<id>https://over-shine.github.io/2020/08/29/GPT-GNN-Generative-Pre-Training-of-Graph-Neural-Networks/</id>
<published>2020-08-29T08:35:06.000Z</published>
<updated>2021-11-06T06:56:23.161Z</updated>
<content type="html"><![CDATA[<h1 id="GPT-GNN-Generative-Pre-Training-of-Graph-Neural-Networks"><a href="#GPT-GNN-Generative-Pre-Training-of-Graph-Neural-Networks" class="headerlink" title="GPT-GNN: Generative Pre-Training of Graph Neural Networks"></a>GPT-GNN: Generative Pre-Training of Graph Neural Networks</h1><a id="more"></a><h2 id="摘要"><a href="#摘要" class="headerlink" title="摘要"></a>摘要</h2><p>预训练模型在CV和NLP中已经得到了广泛的应用,这篇文章提出了在GNN使用自监督的方法预训练GNN的方法。训练GNN需要任务大量的标注数据,这是一个及其费力的事情。减少标注工作量的一种有效方法是使用自监督方法对未标注数据预先训练表达性的GNN模型,然后将学习到的模型转移到仅带有少量标记的下游任务。本文GPT-GNN 框架,通过生成式预训练来初始化GNN。GPT-GNN引入了自监督的图属性生成任务来预训练GNN,以便它可以捕获图的结构和语义属性。它将图生成的可能性分解为两个部分:节点属性生成和边属性生成。</p><!-- more --><p>通过对两个组件进行建模,GPT-GNN可以在生成过程中捕获节点属性和图结构之间的固有依赖性。对数十亿规模的Open Academic Graph和Amazon推荐数据进行的综合实验表明,GPT-GNN在不进行各种下游任务的预训练的情况下,显着优于最先进的GNN模型。</p><h2 id="1-简介"><a href="#1-简介" class="headerlink" title="1. 简介"></a>1. 简介</h2><p>图神经网络(GNN)的突破已经彻底改变了图挖掘从结构特征工程到表示学习。最近 GNN 已经被证明了有利于各种图应用和网络任务,如半监督的节点分类、推荐系统和知识推理等。</p><p>通常,GNN将具有属性的图作为输入,并应用卷积过滤器逐层生成节点的表示。通常,针对输入图上的一项任务,以端到端的方式用监督信息训练GNN模型。也就是说,对于同一张图上的不同任务,需要具有足够多且不同的标记数据集,以训练对应于每个任务的专用GNN。通常,对于特定任务、特别是对于大规模图来说,很难找到合适的标注数据。例如,对于学术作者消歧任务来说,它仍然面临一个巨大的挑战。</p><p>在 NLP 中也遇到了类似的问题。NLP的最新进展通过训练来自未标注的大型语料库的模型,并将学习的模型转移到仅带有少量标签的下游任务(即预训练的思想)来解决这些问题。预训练的目的是使 GNN 能够捕获输入图的结构和语义特性,以便可以通过在同一领域内对图进行一些微调的步骤轻松地将其推广到任何下游任务。为了实现此目标,我们提出<strong>通过学习重构输入属性图来对图分布建模</strong>。</p><p>基于预训练 GNN 的一个直接选择是直接采用神经网络生成技术。但是,它们不适合通过设计预训练GNN。一个原因是它们大多数只专注于生成没有属性的图构,这不能捕获节点属性和图结构(GNN中卷积聚合的核心)之间的基础模式。其次,迄今为止它们被设计来处理小图,从而限制了它们在大规模图上进行预训练的潜力。</p><h3 id="1-1-本文主要贡献"><a href="#1-1-本文主要贡献" class="headerlink" title="1.1 本文主要贡献"></a>1.1 本文主要贡献</h3><p>本文设计了一种用于 GNN 预训练的自监督属性图生成任务,通过该任务对图的结构和属性进行建模。基于此任务,我们提出了用于图神经网络的生成式预训练 GPT-GNN框架(参见图1)。输入图经过预训练的 GNN 可以用作同一类型图上,不同下游任务的模型的初始化。具体来说,我们的贡献如下所示:</p><ol><li>设计了<strong>属性图生成任务</strong>对节点属性和图结构建模。本文把图生成目标分解成两部分:属性生成和边生成,它们的联合优化等价于最大化整个属性图的可能性。通过这样做,预训练的模型可以捕获节点属性和图结构之间的固有依赖性。</li><li>本文提出了一个有效的框架 GPT-GNN 来进行上述任务的生成式预训练。GPT-GNN 可以同时计算每个节点的属性和边生成损失,因此对于该图只需要运行一次GNN。此外,GPT-GNN可以处理带有子图采样的大型图,并通过自适应嵌入队列缓解负采样带来的不准确损失。</li><li>GPT-GNN 在两个大型图,1.79亿个节点和20亿条边的开放学术图(OAG)和1.13亿个节点的Amazon建议数据上对 GNN 进行了预训练。大量实验表明,GPT-GNN预训练框架可以显著是各种下游任务受益。例如,通过在 OAG 上应用预训练模型,与没有进行预训练的最新 GNN 模型相比,节点分类和链接预测性能平均提高了9.1%。此外,我们证明了 GPT-GNN 可以在各种设置下持续改善不同基础GNN的性能。</li></ol><h2 id="2-相关工作"><a href="#2-相关工作" class="headerlink" title="2. 相关工作"></a>2. 相关工作</h2><p>预训练的目标是使得一个模型的权重可以使用预训练的权重来初始化。GNN可以被视作使用输入图结构作为计算图进行信息传递,在这个过程中领域信息被聚合获得更多的语境表示。本文中,用 $H_t^{(l)}$ 表示节点 $t$ 在第 $l$ 层的节点表示,从第 $(l-1)$ 层到第 $(l)$ 层的更新过程如下:</p><script type="math/tex; mode=display">H_t^{l}\leftarrow\mathbf{Aggregate}_{\forall s\in N(t), \forall e\in E(s,t)}\big(\{\mathbf{Extract}(H_s^{(l-1)};H_t^{(l-1)};e)\}\big)\tag{1}</script><p>其中,$N_(t)$ 表示节点 $t$ 的所有源节点,$E(s,t)$ 表示节点 $s$ 到节点 $t$ 的边;$\mathbf{Extract}(\cdot)$ 表示领域信息提取操作,它使用目标节点 $t$ 的表示和两节点间的边作为 $query$,并从源节点 $H_s^{(l-1)}$ 提取有用的信息;$\mathbf{Aggregate}(\cdot)$ 作为领域信息的聚合函数,它的常见基本操作是取均值、取和、取最大值,也可以设计池化、正则化等聚合函数。</p><p>基于注意力模型完成 $\mathbf{Extract}(\cdot)$ 通过评估每个源节点重要性,基于此,加权的聚合操作被提出。如 GAT 采用自适应的机制计算注意力并使用相同的权重计算信息;HGT对不同的关系类型使用多头注意力得到类型独立的注意力。GPT-GNN 可以所有的这些模型当中。</p><h3 id="2-1-图的预训练"><a href="#2-1-图的预训练" class="headerlink" title="2.1 图的预训练"></a>2.1 图的预训练</h3><p>曾经的研究利用预训练学习节点表示,大致分为两类。</p><ol><li>网络/图嵌入:直接参数化节点嵌入向量并通过保留一些相似性度量来优化它们,例如网络接近度或从随机游走得出的统计数据。然而,它的缺点就是通过这种方式学习的嵌入不能用于初始化其他任务以微调其他任务。</li><li>预训练:通过迁移学习在一个大的数据集上训练一个通用的模型,可以用于初始化下有任务模型以微调训练模型。</li></ol><p>随着对 GNN 关注的增多,研究人员已经探索 GNN 在无标签数据上的预训练。Kipf 等人提出 Variational Graph Auto-Encoders 去重构图结构;Hamilton 等人提出 GraphSAGE 通过使用基于随机游动的相似性度量,可以通过无监督的损失进行优化。Velickovic 等人提出 Graph Infomax,它最大化来自于 GNNs 和一个池化的图表示的节点表示之间的交互信息。尽管这些方法显示了对纯监督学习的增强,但通过迫使附近的节点具有相似的嵌入来实现学习任务,会忽略图丰富语义和高阶结构。 GPT-GNN 通过排列的生成目标对GNN进行预训练,这是一项更困难的图任务,因此可以指导模型学习输入图的更复杂的语义和结构。</p><p>另外,尝试对 GNN 进行预训练以提取图级表示。Sun 等人提出的 InfoGraph 最大化来自于图表示和子结构表示之间的交互信息。Hu 等人引入不同的策略在节点和图两个级别上预训练 GPT-GNN,并表明将它们组合在一起可以提高图分类任务的性能。与它们不同的是,GPT-GNN 的目标是在一个大规模图上预训练 GNN 并进行节点级别的迁移。</p><h2 id="3-通用-GNN-预训练"><a href="#3-通用-GNN-预训练" class="headerlink" title="3. 通用 GNN 预训练"></a>3. 通用 GNN 预训练</h2><h3 id="3-1-GNN-预训练问题"><a href="#3-1-GNN-预训练问题" class="headerlink" title="3.1 GNN 预训练问题"></a>3.1 GNN 预训练问题</h3><p>GNN 的输入通常是一个属性图 $G=(\mathcal{V}, \mathcal{E}, \mathcal{X})$,其中 $\mathcal{V}$ 和 $\mathcal{E}$ 代表图的节点集合边集,$\mathcal{X}$ 代表节点的特征矩阵。</p><p>GNN 模型在一个下游任务(如节点分类)的监督下学习输出节点的表示。有时在一个图上存在多个任务,并且大部分 GNN 对每一个下游任务要求足够的标注数据。然而,这是这是一个很大的阻碍。因此期望得到一个仅使用较少的标注数据就可以泛化的预训练模型,从理论上讲,这个模型应该可以捕获图潜在的结构和属性模式,并且在这张图上,可以使得各种下游任务受益。</p><p>本文 GNN 预训练目标涉及仅基于单个(大型)图 $G =(\mathcal{V}, \mathcal{E}, \mathcal{X})$ 而不具有标注数据的通用 GNN 模型 $f_\theta$ 的学习,因此 $f_\theta$ 是在相同领域图或相同图上各种下游任务的一个好的初始权重。为了在图上训练一个不带标签的数据的通用 GNN 模型,提出了一个首要问题:<strong>如何在图上设计一个无监督学习任务来预训练 GNN 模型?</strong></p><h3 id="3-2-通用预训练框架"><a href="#3-2-通用预训练框架" class="headerlink" title="3.2 通用预训练框架"></a>3.2 通用预训练框架</h3><p>受 NLP 和 CV 使用自监督方法预训练模型的启发,本文提出 GPT-GNN 模型,它通过重构/生成输入图的框架和属性来预训练 GNN 模型。</p><p>形式上,给定一个输入图 $G =(\mathcal{V}, \mathcal{E}, \mathcal{X})$ 和一个 GNN 模型 $f_\theta$,我们将 GNN 在该图上的似然建模为 $p(G;θ)$,表示图 $G$ 中的节点如何分配和连接。 GPT-GNN 旨在通过最大化图的似然(即 $\theta^*=\max_\theta p(G;\theta)$)来预训练GNN 模型。</p><p>然后,首要问题就变成了:<strong>如何正确建模$p(G;\theta)$ ?</strong></p><p>目前,大多数现有的图生成方法都遵循以自回归的方式来分解概率目标,即图中的节点按顺序排列,并通过将每个新出现的节点链接到现有的边来生成边。类似,本文以一个排列向量 $\pi$ 来确定节点的顺序,其中 $i^\pi$ 表示排列向量 $\pi$ 中的第 $i$ 个位置的节点 $id$。因此,图分布 $p(G;\theta)$ 等价于所有可能排列的期望概率,即</p><script type="math/tex; mode=display">p(G;\theta)=\mathbb{E}_\pi\big[p_\theta(X^\pi, E^\pi)\big]</script><p>其中,$X^\pi\in\mathbb{R}^{|\mathcal{V}|\times d}$ 表示排列的节点属性,$E$ 表示边集,$E_i^\pi$ 表示连接节点 $i^\pi$ 的所有边的集合。为简单起见,我们假定观察任意节点的顺序 $\pi$ 的概率均等,并且在以下各节中说明一个排列的生成过程时,也省略了下标 $\pi$。 给定一个排列顺序,我们可以自回归分解对数似然(每次迭代生成一个节点),如下所示:</p><script type="math/tex; mode=display">\log p_\theta(X,E)=\sum_{i=1}^{|\mathcal{V}|}\log p_\theta(X_i,E_i|X_{<i}, E_{<i})\tag{2}</script><p>在每次迭代步骤 $i$,使用在之前迭代步骤生成的所有节点,它们的属性 $X_{<i}$,这些节点之间的结构(边)$E_{<i}$ 来生成新节点,包括节点属性 $X_i$ 和新节点与已存在节点之间的边集 $E_i$。本质上,在公式(2)中,的目标描述了一个属性图的自回归生成过程。问题变成了:<strong>怎样对条件概率 $p_\theta(X_i,E_i|X_{<i},E_{<i})$ 建模?</strong></p><h3 id="3-3-分解属性图"><a href="#3-3-分解属性图" class="headerlink" title="3.3 分解属性图"></a>3.3 分解属性图</h3><p>为了计算条件概率 $p_\theta(X_i,E_i|X_{<i},E_{<i})$,一个简单方法是假设 $X_i$ 和 $E_i$ 是独立的,</p><script type="math/tex; mode=display">p_\theta(X_i,E_i|X_{<i},E_{<i})=p_\theta(X_i|X_{<i},E_{<i})\cdot p_\theta(E_i|X_{<i},E_{<i})</script><p>这样分解,对于每个节点,它的属性和连接是完全忽略的,然而,忽略的这种依赖关系是属性图的核心属性,并且也是 GNN 中卷积聚合的基础。因此,这样简单的分解不能为预训练 GNN 提供信息指导。</p><p>为了解决这个问题,为属性图生成过程提出了<strong>依赖感知的因式分解机制</strong>。具体来说,在估算新节点的属性时,我们会得到其结构信息,反之亦然。 在此过程中,已经观察到(或生成了)部分边缘。 然后可以将生成分解为两个耦合部分:</p><ol><li>给定观察的边,生成节点属性;</li><li>给定观察的边和生成的节点属性,生成剩余的边</li></ol><p>用这种方式,模型可以捕获每个节点属性和结构之间的依赖关系。</p><p>形式上,定义一个变量 $o$ 表示边集 $E_i$ 内所有观察到的边的索引向量。因此,$E_{i,o}$ 表示观察到的边。类似地,$\lnot o$ 表示所有遮盖边索引,它们将要生被生成。这样,我们可以将条件概率作为所有观察到的边上的期望似然:</p><script type="math/tex; mode=display">p_{\theta}\left(X_{i}, E_{i} \mid X_{<i}, E_{<i}\right) =\sum_{o} p_{\theta}\left(X_{i}, E_{i, \neg o} \mid E_{i, o}, X_{<i}, E_{<i}\right) \cdot p_{\theta}\left(E_{i, o} \mid X_{<i}, E_{<i}\right) \\=\mathbb{E}_{o}\left[p_{\theta}\left(X_{i}, E_{i, \neg o} \mid E_{i, o}, X_{<i}, E_{<i}\right)\right] \\=\mathbb{E}_{o}[\underbrace{p_{\theta}\left(X_{i} \mid E_{i, o}, X_{<i}, E_{<i}\right)}_{1) \text { generate attributes }} \cdot \underbrace{p_{\theta}\left(E_{i, \neg o} \mid E_{i, o}, X_{\leq i}, E_{<i}\right)}_{2) \text { generate edges }}]\tag{3}</script><p>这个分解设计可以对节点 $i$ 的属性 $X_i$ 和它的边 $E_i$ 之间的依赖建模。第一项 $p_{\theta}\left(X_{i} \mid E_{i, o}, X_{<i}, E_{<i}\right)$ 表示节点 $i$ 的属性生成过程。基于观察到的边 $E_{i,o}$,聚合目标节点 $i$ 的邻域信息来生成它的属性 $X_i$。第二项 $p_{\theta}\left(E_{i, \neg o} \mid E_{i, o}, X_{\leq i}, E_{<i}\right)$ 表示遮盖边的生成过程,基于观察到的边 $E_{i,o}$ 和生成的节点属性 $X_i$,生成目标节点的表示,并预测 $E_{i,\lnot o}$ 中的边是否存在。</p><p><strong>图生成例子:</strong> 对于一个学术图,如果我们想生成一个论文节点,它的标题被考虑作为它的属性,同时这个论文节点和它的作者、期刊和引文相连。基于一些论文节点和它的作者相连的观察到的边,生成程序首先生成它的标题。然后基于观察到的边和生成的标题,预测剩下的作者、出版期刊和引文。用这种方式,这个过程对论文属性(标题)和结构(观察到的和剩下的边)之间的交互进行建模来完成生成任务,为学术图上的 GNN 训练提供信息信号。</p><p>到目前为止,我们将属性图的生成过程分解为节点属性生成步骤和边生成步骤。 我们需要在这里回答的问题是:<strong>如何通过同时优化属性和边缘生成任务来有效地预训练 GNN ?</strong></p><h3 id="3-4-高效的属性和边生成"><a href="#3-4-高效的属性和边生成" class="headerlink" title="3.4 高效的属性和边生成"></a>3.4 高效的属性和边生成</h3><p>为了提高效率,希望通过仅对输入图运行 GNN 一次来计算属性和边生成的损失。另外,希望同时进行属性生成和边生成。但是,边生成需要将节点属性作为输入,这可能会泄露给属性生成。 为了避免信息泄漏,我们设计将每个节点分为两种类型:</p><ol><li>属性生成节点:通过用虚拟令牌替换它们的属性来掩盖这些节点的属性,并学习一个共享向量 $X^{init}$ 来表示它。这等效于在屏蔽语言模型(MLM)中使用[Mask]令牌的技巧。</li><li>边生成节点:对于这些节点,保持它们的属性并且把它们作为 GNN 的输入。</li></ol><p>把修正过的图输入到 GNN 模型并生成输出表示,用 $h^{Attr}$ 和 $h^{Edge}$ 表示属性生成和变生成节点的输出嵌入。由于属性生成节点的属性被屏蔽掉,因此 $h^{Attr}$ 通常包含的信息少于 $h^{Edge}$。 因此,在进行 GNN 消息传递时,我们仅将边生成节点的输出 $h^{Edge}$ 用作向外消息。然后使用两组节点的表示来生成具有不同解码器的属性和边。</p><p><strong>对于属性生成:</strong> 用 $Dec^{Attr}(\cdot)$ 代表它的编码器,它使用 $h^{Attr}$ 作为输入并且生成被 mask 的属性。建模选择取决于属性的类型。例如,如果节点的输入属性是文本,则可以使用文本生成器模型(例如LSTM)来生成它。 如果输入属性是标准向量,则可以应用多层感知器来生成它。 另外,我们定义了距离函数作为生成的属性和真实属性之间的度量,例如文本的困惑或向量的L2距离。 因此,我们通过以下方式计算属性生成损失:</p><script type="math/tex; mode=display">\mathcal{L}_i^{Attr}=Distance(Dec^{Attr}(h_i^{Attr}),X_i)\tag{4}</script><p>通过最小化生成属性和遮盖属性之间的距离,就等价于最大化观察每个节点属性的似然(即 $p_\theta(X_i|E_{i,o},X_{<i},E_{<i})$),因此这个与训练模型可以捕获图的语义。</p><p><strong>对于边生成:</strong> 每条边的生成是相互独立的,因此可以分解似然如下:</p><script type="math/tex; mode=display">p_\theta(E_{i,\lnot o}|E_{i,o},X_{\leq i},E_{<i})=\prod_{j^+\in E_{i,\lnot o}}p_\theta(j^+|E_{i,o},X_{\leq i}, E_{<i})\tag{5}</script><p>之后,在得到边生成节点表示 $h^{Edge}$ 后,通过 $Dec^{Edge}(h_i^{Edge}, h_j^{Edge})$ 对节点 $i$ 与节点 $j$ 的连接可能性进行建模,其中 $Dec^{Edge}$ 是一个成对的得分函数。最后,采用负对比估计来计算每个连接节点 $j^+$ 的可能性。我们将所有未连接的节点设为 $S_i^-$ 并通过如下公式计算对比损失:</p><script type="math/tex; mode=display">\mathcal{L}_{i}^{E d g e}=-\sum_{j^{+} \in E_{i, \neg o}} \log \frac{\exp \left(\operatorname{Dec}^{E d g e}\left(h_{i}^{E d g e}, h_{j^{+}}^{E d g e}\right)\right)}{\sum_{j \in S_{i}^{-} \cup\left\{j^{+}\right\}} \exp \left(\operatorname{Dec}^{E d g e}\left(h_{i}^{E d g e}, h_{j}^{E d g e}\right)\right)}\tag{6}</script><p>通过优化 $\mathcal{L}_i^{Edge}$,等价于最大化生成所有边的可能性,因此这个预训练模型可以捕获图的内在可够。</p><div align=center><img src="1.png"/></div><p>上图展示了属性图的生成过程:</p><ol><li>a) 确定输入图的节点排列顺序 $\pi$;</li><li>b) 随机选择部分节点的边作为观测边 $E_{i,o}$,剩下的边作为遮盖边 $E_{i,\lnot o}$ (带叉的灰色虚线),在图中,删除被遮盖的边;</li><li>c) 把每个节点分成属性生成和边生成节点来避免信息的泄露;</li><li>d) 预处理后,使用修正的邻接矩阵去计算节点3、4、5的表示,包括它们的属性和边生成节点。</li></ol><p>最后,如上图(d)-(e)展示,通过对每个节点的属性预测和遮盖边的预测任务来并行训练 GNN 模型。GPT-GNN的总体流程在如下所示:</p><div align=center><img src="2.png"/></div><h3 id="3-5-适用于异构图和大型图的-GPT-GNN"><a href="#3-5-适用于异构图和大型图的-GPT-GNN" class="headerlink" title="3.5 适用于异构图和大型图的 GPT-GNN"></a>3.5 适用于异构图和大型图的 GPT-GNN</h3><p>在本节中,讨论如何将 GPT-GNN 应用于大规模图和异构图的预训练,这对于模拟现实世界中的复杂系统,例如学术图,产品图, 物联网网络和知识图。</p><p><strong>异构图:</strong> 许多现实世界的图是异构的,这意味着它们包含不同类型的节点和边。 对于异构图,提出的 GPT-GNN 框架可以直接应用于预训练的异构 GNNs。 唯一的区别是,每种类型的节点和边缘都可以具有自己的解码器,该解码器由异构 GNN(而不是预训练框架)指定。所有其他组件保持完全相同。</p><p><strong>大规模图:</strong> 为了在太大而无法容纳在硬件的图上对 GNN 进行预训练,我们对子图进行采样以进行训练。特别是,我们建议分别使用 LADIES 算法和其异构版本 HGSampling 从同构图和异构图采样密集子图。从理论上讲,这两种方法都保证了采样节点之间的高度互连,并最大程度地保留了结构信息。</p><p>为了公式 (6) 中的对比损失,需要遍历输入图的所有节点。但是,我们只能访问子图中的采样节点以估计此损失,从而使(自)监督仅关注局部信号。为了缓解此问题,我们提出了“自适应队列”,它在先前采样的子图中将节点表示形式存储为负样本。每次处理新的子图时,我们都会通过添加最新的节点表示并删除最旧的节点表示来逐步更新此队列。由于不会严格更新模型参数,因此队列中存储的负样本是一致且准确的。自适应队列使我们能够使用更大的负样本池 $S_i^-$。此外,跨不同采样子图的节点可以引入用于对比学习的全局结构指导。</p><h2 id="4-评估"><a href="#4-评估" class="headerlink" title="4. 评估"></a>4. 评估</h2><p>为了评估 GPT-GNN 的性能,我们在 Open Academic Graph(OAG)和 亚马逊推荐数据集。为了评估 GPT-GNN 的泛化能力,我们考虑了不同的迁移方案:time transfer 和 filed transfer(具有实际意义)</p><h3 id="4-1-实验设置"><a href="#4-1-实验设置" class="headerlink" title="4.1 实验设置"></a>4.1 实验设置</h3><p><strong>数据集和任务:</strong> 我们在同构图和异构图上都进行了试验。对于<strong>异构图</strong>,使用了 OAG 和亚马逊评论推荐数据。对于<strong>同构图</strong>,使用了 Reddit 数据集和从 OAG 抽取的论文引用网络。</p><p><strong>开源学术图(OAG)</strong>:包含超过1.78亿个节点和22.36亿条边。它是迄今为止最大的公开可用的异构学术数据集。每篇论文都带有一组研究主题/领域(例如,物理和医学)的标签,其发表日期为1900年至2019年。我们考虑对Paper-Field,Paper-Venue和Author Name Disambiguation的预测(作者ND) 作为三个下游任务。性能由MRR(一种广泛采用的排名指标)进行评估。</p><p><strong>亚马逊推荐数据集:</strong> 包含8280万条评论,2090万用户和930万种产品。该评论发布于1996年至2018年。每条评论都包含一个从1到5的离散评分,以及一个特定领域,包括书籍,时装等。对于下游任务,我们在时尚,美容和奢侈品领域将评分分为五类分类任务。我们使用micro-F1得分作为评估指标。</p><p><strong>基本 GNN 模型:</strong> 在 OAG 和 Amazon 数据集上,我们使用最新的异构 GNN-Heterogeneous Transformer(HGT)作为 GPT-GNN 的基础模型。此外,我们还使用其他(异构)GNN作为基础模型来测试我们的生成式预训练框架。</p><p><strong>完成细节:</strong> 对于所有的基础模型,设置隐藏维度为400,8个注意力头,GNN 的层数为3,它们所有的都使用 Pytorch-Geometric 这个库实现。</p><p>我们通过带有余弦退火学习速率调度器的 AdamW 优化器优化模型,并选择验证损失最低的模型作为预训练模型。我们将自适应队列大小设置为256。</p><p>在下游任务评估期间,我们使用与预训练相同的优化设置对模型进行微调。 我们对下游任务进行了5次训练,并报告了测试性能的平均值和标准偏差。</p><p><strong>预训练基准:</strong> 有几项工作提出了关于图的无监督目标,可以潜在地用于预训练GNN。因此,我们将提出的的 GPT-GNN 框架与这些基准进行了比较:</p><ul><li><strong>GAE:</strong> 表示图形自动编码器,它专注于传统的链接预测任务。它随机掩盖固定比例的边,并要求模型重建这些掩盖的边。</li><li><strong>GraphSAGE:</strong> 强制连接的节点具有相似的输出节点嵌入。它与 GAE 的主要区别在于,它在预训练过程中不会掩盖边缘。</li><li><strong>Graph Infomax:</strong> 尝试使用全局图总的嵌入最大化局部节点嵌入。在为大型图设置按照它的参数设置之后,对于每个采样的子图,我们将图进行混洗以构造负样本。</li></ul><p>此外,我们还单独使用 GPT-GNN 中的两个预训练任务,即属性生成 GPT-GNN 和边生成 GPT-GNN 来评估它们。</p><h3 id="4-2-预训练和微调设置"><a href="#4-2-预训练和微调设置" class="headerlink" title="4.2 预训练和微调设置"></a>4.2 预训练和微调设置</h3><p>预训练的目标是将从一个大型图的大量无标签节点中学到的知识迁移到带有少量标签的下游任务。具体来说,我们首先预训练 GNN,然后使用预训练的模型权重来初始化下游任务的模型。然后,我们使用训练(微调)集上的下游任务特定解码器对模型进行微调,并评估测试集的性能。</p><p>大致而言,有两种不同的设置。第一个是在完全相同的图形上进行预训练和微调。第二种相对更实用,它是在一张图上进行预训练,并在与预训练图相同类型的没见过的的图上进行微调。具体来说,我们考虑在预训练和微调阶段之间进行以下三个图的迁移设置:</p><ul><li><strong>时间迁移(Time Transfer):</strong> 对于预训练和微调,使用不同时间跨度的数据。对于 OAG 和亚马逊,使用2014年之前的数据用于预训练,2014年及之后的数据用于微调。</li><li><strong>领域迁移(Field Transfer):</strong> 使用来自不同领域的数据用于预训练和微调。在 OAG,使用计算机科学领域的论文用于下游任务微调,剩下所有领域的数据用于预训练。在亚马逊,我们对艺术、手工艺和缝纫产品用于预训练,并对时尚、美容和奢侈品产品进行微调。</li><li><strong>时间+领域迁移(Time+Field Transfer):</strong> 使用2014年之前特定领域的图进行预训练,并且使用2014年之后其它领域的数据进行微调。直观地讲,这种组合的迁移设置比单独的时间或领域迁移更具挑战性。例如,我们在2014年之前除 CS 领域之外的 OAG 图上进行预训练,并在2014年之后的 CS 图中进行微调。</li></ul><p>在微调期间,对于这两个数据集,我们从2014年到2016年选择节点进行训练,从2017年选择节点进行验证,从2018年开始选择节点进行测试。 为了满足通常缺乏训练数据的假设,默认情况下,我们仅提供10%的训练标签用于训练(微调),同时还对不同数据百分比进行了消融研究。在预训练期间,随机选择数据的一个自己作为验证集。</p><h3 id="4-3-实验结果"><a href="#4-3-实验结果" class="headerlink" title="4.3 实验结果"></a>4.3 实验结果</h3><p>我们在表1中总结了在OAG和Amazon上使用不同的预训练方法的下游任务的性能。如上所述,我们在预训练和微调阶段之间设置了三种不同的传输设置:领域传输、时间迁移和领域迁移+时间迁移,按表中三个不同的块组织所示。</p><div align=center><img src="3.png"></div><p>总体而言,提出的的 GPT-GNN 框架显著提高了两个数据集上所有下游任务的性能。平均而言,在不经过 OAG 和 Amazon 预先训练的情况下, GPT-GNN 相对于基本模型的相对性能提升分别为13.3%和5.7%。此外,对于两个数据集上的所有三个迁移设置,它在不同的下游任务上始终优于其他预训练框架,例如 Graph Infomax。</p><p><strong>不同的迁移设置:</strong> 从表1可以看出,在领域迁移训练中通过预训练提升的性能增益要比在时间迁移下要高,并且时间+领域组合迁移是最具挑战性的设置,这明显体现在预训练带来的最低性能增益上 。尽管如此,在合并迁移的情况下,GPT-GNN 仍分别在两个数据集上实现了11.7%和4.6%的性能提升。总之,结果表明,所提出的生成式预训练策略可以使 GNN 模型能够捕获输入图的一般结构和语义知识,可用于微调图数据的看不见的部分。</p><p><strong>预训练任务中的 Ablation Study</strong>:Abaltion Study 是指去除掉模型或算法中的一些特征,一次来观察这部分去掉的特征对模型性能的影响。通过检查 GPT-GNN 中的两个预训练任务(属性生成和边生成)的有效性,我们检查了其中哪一个对预训练框架以及扩展到下游任务更有利。在表1中,我们仅通过属性生成和边生成即 GPT-GNN(Attr)和 GPT-GNN(Edge)报告了GPT-GNN的性能。在OAG上,GPT-GNN(Attr)和GPT-GNN(Edge)的平均性能提升分别为7.4%和10.3%,这表明与 GPTGNN 中的属性生成相比,边生成是更具信息量的预训练任务。但是,对于 Amazon 我们却有相反的看法,在此方面,属性生成带来的性能提升为5.2%,而边生成带来的性能提升为4.1%。这表明 GPT-GNN 框架的收益与不同数据集上的属性和边生成不同。但是,将两个预训练任务结合在一起可以在两种情况下获得最佳性能。</p><p>在表1中,我们进一步将边生成任务与其他基于边的预训练方法(GAE和GraphSage(未分解))进行了比较。在OAG上,由 GPT-GNN 的边生成,GAE和GraphSage在不进行预训练的情况下所带来的性能改进分别为10.3%,7.4%和4.0%。在Amazon上,收益分别为5.2%,3.1%和1.3%。从比较中,我们有以下观察。首先,在两个数据集上,GAE和GPT-GNN的边生成都比GraphSage提供更好的结果,这表明在边上进行遮盖是用于自我监督的图表示学习的有效策略。如果没有边遮盖,该模型将为连接的节点保留类似的嵌入,因为我们希望预测的标签(是否链接了两个节点)已经在输入图结构中进行了编码。这样的信息泄漏会将边预测任务降级为一个小问题。其次,提出的的边生成任务始终胜过GAE。GPT-GNN边生成的主要优势在于,它学会自动生成缺失的边,从而可以捕获被掩盖的边之间的依赖关系,这些依赖关系已被GAE丢弃。总之,结果表明,提出的图生成任务可以为 GNN 预训练提供丰富信息的自我监督。</p><p><strong>在基础GNN上的 Ablation Study:</strong> 我们调查其他GNN架构是否可以从建议的预训练框架中受益。 因此,除了HGT,我们还尝试使用GCN,GAT ,RGCN 和 HAN 作为基础模型。具体来说,我们在OAG上对它们进行预训练,然后在组合迁移设置下使用论文-领域预测任务,其中10%训练数据以进行微调和测试。与模型无关的超参数(如隐藏的尺寸大小和优化)设置为相同。结果记录在表2中。我们可以观察到:</p><ul><li>1)HGT在所有非预训练的GNN模型中均达到最佳性能;</li><li>2)带有HGT的GPT-GNN对于相关下游任务产生了最有希望的结果;</li><li>3)<strong>更重要的是,提出的GPT-GNN预训练框架可以增强所有GNN体系结构的下游性能</strong>。</li></ul><div align=center><img src="4.png"></div><p><strong>在节点分割和自适应队列的 Ablation Study:</strong> 最后,我们检查了GPT-GNN的两种设计选择(即节点分离和自适应队列)的有效性。节点分离旨在减轻属性生成任务的信息泄漏问题。没有此组件,属性将出现在输入中,因此预训练方法将仅需要维护输入特征以进行输出。换句话说,它无法学习输入图的任何知识,这些知识可能会转移到下游任务,从而对结果产生负面影响。从表1中可以看出,基于属性生成的预训练模型遭受了节点分离成分(无节点分离)的困扰,并且在许多情况下,其性能甚至比未进行预训练的性能更差。这证明了这种节点分离设计在避免属性信息泄漏方面的重要性。</p><p>自适应队列旨在减轻采样图和完整图之间的差距。同样,我们通过从基于边生成的预训练模型中删除消融研究来进行消融研究,并且从表1中,我们看到了所有任务(GPT-GNN(Edge)与(不包括自适应队列))的性能持续下降。 这表明通过使用自适应队列添加更多否定样本确实有助于预训练框架。</p><p><strong>训练数据大小:</strong> 在图3中,我们检查了提出的GPT-GNN方法是否可以在微调期间(即从10%到100%)使用不同的训练数据大小很好地泛化。首先,我们可以观察到GPT-GNN和其他预训练框架通过标记更多的训练数据不断提高了下游任务的绩效。其次,很明显,GPT-GNN在所有预训练任务/框架中表现最好。最后,我们可以看到,使用预先训练的模型,仅对10%到20%的数据(最左边的两个蓝色圆圈)进行微调,就可以与所有100%的训练数据(最右边的紫色菱形)的有监督学习相比 ),证明了GNN预训练的优越性,尤其是在标签稀缺的情况下。</p><div align=center><img src="5.png"></div><p><strong>同构图的结果:</strong> 除了异构图之外,我们还测试了GPT-GNN预训练框架是否可以使同构图上的下游任务受益。具体来说,我们在两个同构图上进行预训练和微调:</p><ul><li>1)从OAG的CS领域中提取的论文引文网络,对每个论文的主题进行预测;</li><li>2)由Reddit帖子组成的Reddit网络,从中可以推断每个帖子的社区。</li></ul><p>由于在同构图中只有一种类型的节点和边,因此我们需要一组边和属性解码器进行预训练。 HGT通过忽略其异质成分而用作基本的预训练模型。 表3中列出了带有10%标记数据的优化结果。我们可以观察到,两个同构图上的下游任务都可以从所有预训练框架中受益,其中建议的GPT-GNN提供最大的性能提升。</p><div align=center><img src="6.png"></div><h2 id="5-总结"><a href="#5-总结" class="headerlink" title="5. 总结"></a>5. 总结</h2><p>在这项工作中,我们研究了图神经网络的预训练问题。我们介绍GPT-GNN-一种生成的GNN预训练框架。在GPT-GNN中,我们设计图生成因子分解,以指导基本的GNN模型自回归地重构输入图的属性和结构。此外,我们建议将属性和边生成节点分开,以避免信息泄漏。此外,我们引入了自适应节点表示队列,以减轻采样图和完整图之间的似然度之间的差距。对少量标记数据进行微调的预训练GNN可以在跨不同数据集的各种下游任务上实现显着的性能提升。同样,GPT-GNN对于预训练和微调之间的不同传输设置也很强大。最后,我们发现使用10%至20%的标记数据对生成的预训练GNN模型进行微调可以为下游任务与100%训练数据的监督GNN模型提供可比的性能。</p>]]></content>
<summary type="html"><h1 id="GPT-GNN-Generative-Pre-Training-of-Graph-Neural-Networks"><a href="#GPT-GNN-Generative-Pre-Training-of-Graph-Neural-Networks" class="headerlink" title="GPT-GNN: Generative Pre-Training of Graph Neural Networks"></a>GPT-GNN: Generative Pre-Training of Graph Neural Networks</h1></summary>
<category term="论文" scheme="https://over-shine.github.io/categories/%E8%AE%BA%E6%96%87/"/>
<category term="GNN" scheme="https://over-shine.github.io/tags/GNN/"/>
</entry>
<entry>
<title>node2vec</title>
<link href="https://over-shine.github.io/2020/08/24/node2vec/"/>
<id>https://over-shine.github.io/2020/08/24/node2vec/</id>
<published>2020-08-24T08:00:00.000Z</published>
<updated>2021-11-06T06:57:07.776Z</updated>
<content type="html"><![CDATA[<h1 id="node2vec:-Scalable-Feature-Learning-for-Networks"><a href="#node2vec:-Scalable-Feature-Learning-for-Networks" class="headerlink" title="node2vec: Scalable Feature Learning for Networks"></a>node2vec: Scalable Feature Learning for Networks</h1><a id="more"></a><h2 id="1-node2vec介绍"><a href="#1-node2vec介绍" class="headerlink" title="1. node2vec介绍"></a>1. node2vec介绍</h2><p>node2vec是一种用于学习网络中节点连续特征表示的算法框架,是一种在玩网络中可扩展的半监督特征学习学习算法,学习了节点特征的低维空间的映射,该映射最大程度地保留了节点的网络邻域,定义了网络邻域的灵活概念,并设计了一种有偏的随机游走程序,该程序可以有效地探索各种邻域。</p><!-- more --><p>node2vec学习节点的特征表示遵循<strong>两个原则</strong>:</p><ol><li>来自相同网络社区的节点的特征应该相似</li><li>在网络中扮演相似角色的节点的特征应该相似</li></ol><h2 id="2-相关工作"><a href="#2-相关工作" class="headerlink" title="2. 相关工作"></a>2. 相关工作</h2><h3 id="2-1-特征学习框架"><a href="#2-1-特征学习框架" class="headerlink" title="2.1 特征学习框架"></a>2.1 特征学习框架</h3><p>网络中的特征学习可以看做是一个最大可能性优化问题。</p><p>给定一个图 $G=(V,E)$,$f: V\rightarrow\mathbb{R}^d$ 是从节点到特征表示的映射函数,它是通过下游的预测任务来学习的一个 $|V|\times d$ 的矩阵。对于每个源节点 $u\in V$,$N_S(u)\subset V$ 是源节点通过邻域策略 $S$ 采样的得到的邻域节点。</p><p>我们寻求优化以下目标函数,该函数最大化源节点 $u$ 特征表示 $f(u)$ 的网络邻域 $N_S(u)$ 的对数概率:</p><script type="math/tex; mode=display">\max_f\sum_{u\in V}\log Pr(N_S(u)|f(u))\tag{1}</script><p>为了便于处理,做出如下两个假设:</p><ol><li>条件独立性:假设观察到邻域节点的可能性独立于观察任何其他邻域节点:</li></ol><script type="math/tex; mode=display">N_S(u)|f(u))=\prod_{n_i\in N_S(u)}Pr(n_i|f(u))</script><ol><li>特征空间对称:源节点和邻域节点在特征空间中彼此对称。因此,我们将每个源-邻节点对的条件似然概率建模为由其特征的点乘参数化的softmax单元:</li></ol><script type="math/tex; mode=display">n_i|f(u))=\frac{\exp(f(n_i)\cdot f(u))}{\sum_{v\in V}\exp(f(v)\cdot f(u))}</script><p>根据上面两个假设,公式 (1) 可以简化为:</p><script type="math/tex; mode=display">\max_f\sum_{u\in v}\bigg [-\log Z_u+\sum_{n_i\in N_S(u)}f(n_i)\cdot f(u)\bigg]\tag{2}</script><p>其中,$Z_u=\sum_{v\in V}\exp(f(u)\cdot f(v))$,由于该公式对于大规模的网络运算量太大,因此采用负采样来逼近它。</p><h2 id="2-2-经典的搜索策略"><a href="#2-2-经典的搜索策略" class="headerlink" title="2.2 经典的搜索策略"></a>2.2 经典的搜索策略</h2><p>我们将对源节点的邻域进行采样的问题视为局部搜索的一种形式。下图展示了一个简单图,其中给定一个源节点 $u$,目的是采样出它的邻域节点 $N_S(u)$,为了公平比较不同的采样策略,将 $N_S(u)$ 的采样大小设为 $k$。</p><div align=center><img src="g1.png"/></div><h3 id="2-2-1-广度优先采样策略(BFS)"><a href="#2-2-1-广度优先采样策略(BFS)" class="headerlink" title="2.2.1 广度优先采样策略(BFS)"></a>2.2.1 广度优先采样策略(BFS)</h3><p>BFS采样的邻域节点 $N_S(u)$ 是节点 $u$ 的直接邻居,如 $k=3$ 时,BFS采样节点 $s_1, s_2, s_3$。它可以准确地刻画局部邻域,仅通过观察每个节点的邻近区域就可以推断出基于网络角色的结构等效性。在BFS中,采样邻域中的节点往往会重复很多次,它减少了表征1-hop节点相对于源节点的分布时的差异。<strong>但是,对于任何给定的k,都只探究该图的很小一部分</strong>。</p><h3 id="2-2-2-深度优先采样策略(DFS)"><a href="#2-2-2-深度优先采样策略(DFS)" class="headerlink" title="2.2.2 深度优先采样策略(DFS)"></a>2.2.2 深度优先采样策略(DFS)</h3><p>邻域 $N_S(u)$ 由在距源节点越来越远的节点顺序采样组成。 如上图,DFS采样 $s_4,s_5,s_6$。在DFS中,采样的节点可以更准确地反映邻域的宏观视图,这对于基于同构性推断社区至关重要。 但是,DFS的问题在于,不仅要推断网络中存在哪些节点到节点依赖关系,而且要表征这些依赖关系的确切性质,这一点很重要。 鉴于我们在样本数量上有一个限制,并且要探索的邻域很大,所以很难做到这一点。 其次,移动到更大的深度会导致复杂的依赖性,因为采样的节点可能离源头很远,并且<strong>代表性可能降低</strong>。</p><h2 id="2-3-偏随机游走(BRW)"><a href="#2-3-偏随机游走(BRW)" class="headerlink" title="2.3 偏随机游走(BRW)"></a>2.3 偏随机游走(BRW)</h2><p>基于以上观察,我们设计了一种灵活的邻域采样策略,该策略使我们能够在BFS和DFS之间进行平衡。</p><h4 id="2-2-3-1-随机游走(Random-Walk)"><a href="#2-2-3-1-随机游走(Random-Walk)" class="headerlink" title="2.2.3.1 随机游走(Random Walk)"></a>2.2.3.1 随机游走(Random Walk)</h4><p>对于给定的源节点 $u$,模拟一个长度为 $l$ 的随机游走。让 $c_i$ 代表随机游走的的第 $i$ 个节点,$c_0=u$,节点 $c_i$ 有以下公式生成:</p><script type="math/tex; mode=display">P(c_i=x|c_{i-1}=v)=\begin{cases} \frac{\pi_{vx}}{Z}, & \mathbf{if}(v,x)\in E\\ 0, &\mathbf{otherwise}\end{cases}</script><p>其中,$\pi_{vx}$ 是节点 $v$ 和节点 $u$ 之间未归一化的转移概率,$Z$ 是归一化的常数。</p><h4 id="2-2-3-2-搜索偏差-alpha"><a href="#2-2-3-2-搜索偏差-alpha" class="headerlink" title="2.2.3.2 搜索偏差 $\alpha$"></a>2.2.3.2 搜索偏差 $\alpha$</h4><p>偏随机游走的最简单方法是基于静态边缘权重 $w_{vx}$ 采样下一个节点,即 $\pi_{vx} = w_{vx}$。(如果未加权图 $w_{vx} =1$)。但是,这不允许我们考虑网络结构并指导我们探索不同类型的网络邻域。此外,与BFS和DFS分别是分别适合结构对等和同构的极端采样范式不同,偏随机游走结合了这两种极端的采样方式,并且这也满足现实世界的情况。</p><div align=center><img src="g2.png"></div><p>本文定义了带参数 $p$ 和 $q$ 的二阶随机游走来知道采样。假设当前节点 $u$ 刚经过边 $(t, v)$,并且现在需要根据边 $(v, x)$ 的转移概率 $\pi_{vx}$ 来决定下一步往哪走。令未归一化的转移概率为 $\pi_{vx}=\alpha_{pq}(t,x)\cdot w_{vx}$,</p><script type="math/tex; mode=display">\alpha_{pq}(t,x)=\begin{cases} \frac{1}{p},& \mathbf{if}\ d_{tx}=0\\ 1, &\mathbf{if}\ d_{tx}=1\\ \frac{1}{q},&\mathbf{if}\ d_{tx}=2\end{cases}</script><p>其中,$d_{tx}$ 代表节点 $t$ 和 $x$ 之间的最短路径,$d_{tx}$ 必须在 $\{0,1,2\}$ 中,两个参数就足够进行采样了。参数 $p$ 和 $q$ 控制探索和离开邻域的速度。</p><p>参数 $p$ 控制访问已访问过的直接邻居的可能性,当 $p>\max(q,1)$ 设为较大的值时,保证在接下来的两步中只有很小的可能访问已访问过的节点(除了节点没有其它邻居)。这种策略鼓励在采样时,适当探索并且避免2-hop冗余。如果 $p<\min(q, 1)$ 很小,那么将会在源节点 $u$ 的局部游走。</p><p>参数 $q$ 允许搜索向内和向外的不同节点。如果 $q>1$,那么随机游走会偏向节点 $t$。在我们的样本包含一个小的局部性内的节点的意义上,这样的行走可获取相对于行走中的起始节点的基础图的局部视图,并近似 BFS 行为。如果 $q<1$,则步行更倾向于访问距离节点 $t$ 更远的节点。 这种行为反映了DFS,DFS鼓励向外探索。</p><h2 id="2-4-node2vec算法"><a href="#2-4-node2vec算法" class="headerlink" title="2.4 node2vec算法"></a>2.4 node2vec算法</h2><div align=center><img src="node2vec.png"/></div><p>在每一步的随机游走过程中,由于初始节点 $u$ 的选择,都存在一个隐式偏差。由于学习所有节点的表示,因此通过模拟从节点 $u$ 开始的固定长度为 $l$ 的 $r$ 个随机游走来抵消此偏差。在每一步,都是基于转移概率 $\pi_{vx}$ 采样。可以预先计算二阶马尔可夫链的转移概率 $\pi_{vx}$,因此可以使用<strong>别名采样</strong>在O(1)时间内高效地完成节点的采样,同时模拟随机游走。 依次执行node2vec的三个阶段,即计算转移概率的预处理,随机游走模拟和使用SGD的优化。 每个阶段均可并行化并异步执行,从而有助于node2vec的总体可伸缩性。</p>]]></content>
<summary type="html"><h1 id="node2vec:-Scalable-Feature-Learning-for-Networks"><a href="#node2vec:-Scalable-Feature-Learning-for-Networks" class="headerlink" title="node2vec: Scalable Feature Learning for Networks"></a>node2vec: Scalable Feature Learning for Networks</h1></summary>
<category term="论文" scheme="https://over-shine.github.io/categories/%E8%AE%BA%E6%96%87/"/>
<category term="GNN" scheme="https://over-shine.github.io/tags/GNN/"/>
</entry>
<entry>
<title>OMP: Error #15: Initializing libiomp5md.dll</title>
<link href="https://over-shine.github.io/2020/08/22/OMP-Error-15-Initializing-libiomp5md-dll/"/>
<id>https://over-shine.github.io/2020/08/22/OMP-Error-15-Initializing-libiomp5md-dll/</id>
<published>2020-08-22T10:40:14.000Z</published>
<updated>2021-11-06T06:57:22.689Z</updated>
<content type="html"><![CDATA[<h1 id="OMP-Error-15-Initializing-libiomp5md-dll"><a href="#OMP-Error-15-Initializing-libiomp5md-dll" class="headerlink" title="OMP: Error #15: Initializing libiomp5md.dll"></a>OMP: Error #15: Initializing libiomp5md.dll</h1><a id="more"></a><p>报错信息如下:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">OMP: Error <span class="comment">#15: Initializing libiomp5md.dll, but found libiomp5md.dll already initialized.</span></span><br><span class="line">OMP: Hint This means that multiple copies of the OpenMP runtime have been linked into the program. That <span class="keyword">is</span> dangerous, since it can degrade performance <span class="keyword">or</span> cause incorrect results. The best thing to do <span class="keyword">is</span> to ensure that only a single OpenMP runtime <span class="keyword">is</span> linked into the process, e.g. by avoiding static linking of the OpenMP runtime <span class="keyword">in</span> any library. As an unsafe, unsupported, undocumented workaround you can set the environment variable KMP_DUPLICATE_LIB_OK=TRUE to allow the program to <span class="keyword">continue</span> to execute, but that may cause crashes <span class="keyword">or</span> silently produce incorrect results. For more information, please see http://www.intel.com/software/products/support/.</span><br></pre></td></tr></table></figure><!-- more --><p><strong>解决方法:</strong> 在文件中添加下面代码</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line">os.environ[<span class="string">'KMP_DUPLICATE_LIB_OK'</span>] = <span class="string">'True'</span></span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1 id="OMP-Error-15-Initializing-libiomp5md-dll"><a href="#OMP-Error-15-Initializing-libiomp5md-dll" class="headerlink" title="OMP: Error #15: Initializing libiomp5md.dll"></a>OMP: Error #15: Initializing libiomp5md.dll</h1></summary>
<category term="Error" scheme="https://over-shine.github.io/tags/Error/"/>
<category term="Python" scheme="https://over-shine.github.io/tags/Python/"/>
</entry>
<entry>
<title>hexo搭配mathjax注意事项</title>
<link href="https://over-shine.github.io/2020/08/22/hexo%E6%90%AD%E9%85%8Dmathjax%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9/"/>
<id>https://over-shine.github.io/2020/08/22/hexo%E6%90%AD%E9%85%8Dmathjax%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9/</id>
<published>2020-08-22T06:56:56.000Z</published>
<updated>2021-11-06T06:56:35.754Z</updated>
<content type="html"><![CDATA[<h1 id="hexo-yilia-plus-mathjax-显示数学公式"><a href="#hexo-yilia-plus-mathjax-显示数学公式" class="headerlink" title="hexo + yilia-plus + mathjax 显示数学公式"></a>hexo + yilia-plus + mathjax 显示数学公式</h1><a id="more"></a><h2 id="1-使用-Kramed-代替-hexo-自带的-Marked"><a href="#1-使用-Kramed-代替-hexo-自带的-Marked" class="headerlink" title="1. 使用 Kramed 代替 hexo 自带的 Marked"></a>1. 使用 Kramed 代替 hexo 自带的 Marked</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm uninstall hexo-renderer-marked --save</span><br><span class="line">npm install hexo-renderer-kramed --save</span><br></pre></td></tr></table></figure><p>更改/node_modules/hexo-renderer-kramed/lib/renderer.js</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">formatText</span>(<span class="params">text</span>) </span>{</span><br><span class="line"> <span class="comment">// Fit kramed's rule: $$ + \1 + $$</span></span><br><span class="line"> <span class="keyword">return</span> text.replace(<span class="regexp">/`\$(.*?)\$`/g</span>, <span class="string">'$$$$$1$$$$'</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>为</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">formatText</span>(<span class="params">text</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> text;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="2-停止使用-hexo-math-并安装-mathjax"><a href="#2-停止使用-hexo-math-并安装-mathjax" class="headerlink" title="2. 停止使用 hexo-math 并安装 mathjax"></a>2. 停止使用 hexo-math 并安装 mathjax</h2><p>如果你已经安装 hexo-math, 请卸载它,然后安装 hexo-renderer-mathjax 包</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm uninstall hexo-math --save</span><br><span class="line">npm install hexo-renderer-mathjax --save</span><br></pre></td></tr></table></figure><p><strong>注意:</strong> 由于一些原因,当使用yilia-plus主题时,使用mathjax会报错,如果仍要使用mathjax,根据 yilia-plus作者 <a href="https://github.com/JoeyBling">JoeyBling</a>提供的解决方案,需要进入 node_modules/hexo-renderer-mathjax文件夹执行如下代码:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">npm uninstall ejs -S</span><br><span class="line"><span class="comment"># 安装最新版ejs</span></span><br><span class="line">npm i ejs@latest -S</span><br></pre></td></tr></table></figure><h2 id="3-更改默认转义规则"><a href="#3-更改默认转义规则" class="headerlink" title="3. 更改默认转义规则"></a>3. 更改默认转义规则</h2><p>因为 hexo 默认的转义规则会将一些字符进行转义,所以我们需要对默认的规则进行修改.<br>对文件 node_modules/kramed/lib/rules/inline.js 参考<a href="https://blog.csdn.net/frone/article/details/81170627">半路出家的coder</a>进行如下更改:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">escape</span>: <span class="regexp">/^\\([\\`*{}\[\]()#$+\-.!_>])/</span>,</span><br><span class="line"><span class="comment">//修改为</span></span><br><span class="line"><span class="built_in">escape</span>: <span class="regexp">/^\\([`*\[\]()# +\-.!_>])/</span>,</span><br><span class="line"></span><br><span class="line">em: <span class="regexp">/^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/</span>,</span><br><span class="line"><span class="comment">//修改为</span></span><br><span class="line">em: <span class="regexp">/^\*((?:\*\*|[\s\S])+?)\*(?!\*)/</span>,</span><br></pre></td></tr></table></figure><p>我只是修改了上面的 <strong>em</strong> 项,这一项好像对应的是行内公式转义问题,我没有更改 <strong>escape</strong> 项,可以正常显示。</p><h2 id="4-配置-Mathjax"><a href="#4-配置-Mathjax" class="headerlink" title="4. 配置 Mathjax"></a>4. 配置 Mathjax</h2><p>在文件 node_modules\hexo-renderer-mathjax\mathjax.html 中添加如下一行代码:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><script id=<span class="string">"MathJax-script"</span> <span class="keyword">async</span> src=<span class="string">"https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"</span>></script></span><br></pre></td></tr></table></figure><p>注意,我之前查了很多网上的 hexo 配置 Mathjax 的文章,它们在该文件中加入的代码通常是</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><script type=<span class="string">"text/javascript"</span> <span class="keyword">async</span> src=<span class="string">"cdn.mathjax.org/mathjax/latest/MathJax.js"</span>></script></span><br></pre></td></tr></table></figure><p>但是这行代码仅在本地(即执行hexo s时)可以渲染 tex 数学公式,但是部署到 github 后就不能渲染 tex 数学公式了,所以强烈推荐使用第一种代码,这是<a href="https://github.com/mathjax/MathJax-src">Mathjax官网给出的url</a>。</p><p>最后在你使用的主题中添加</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">mathjax:</span> </span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment"># 是不是没页都使用mathjax</span></span><br><span class="line"> <span class="attr">perpage:</span> <span class="literal">false</span></span><br></pre></td></tr></table></figure><p>最后执行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">hexo clean</span><br><span class="line">hexo g</span><br><span class="line">hexo d</span><br></pre></td></tr></table></figure><p>这时打开博客就能看到渲染效果了,渲染很快哦。</p>]]></content>
<summary type="html"><h1 id="hexo-yilia-plus-mathjax-显示数学公式"><a href="#hexo-yilia-plus-mathjax-显示数学公式" class="headerlink" title="hexo + yilia-plus + mathjax 显示数学公式"></a>hexo + yilia-plus + mathjax 显示数学公式</h1></summary>
<category term="Error" scheme="https://over-shine.github.io/tags/Error/"/>
<category term="hexo" scheme="https://over-shine.github.io/tags/hexo/"/>
</entry>
<entry>
<title>ERROR Deployer not found: git</title>
<link href="https://over-shine.github.io/2020/08/21/ERROR-Deployer-not-found-git/"/>
<id>https://over-shine.github.io/2020/08/21/ERROR-Deployer-not-found-git/</id>
<published>2020-08-21T14:29:16.000Z</published>
<updated>2021-11-06T06:55:44.902Z</updated>
<content type="html"><![CDATA[<h1 id="ERROR-Deployer-not-found-git"><a href="#ERROR-Deployer-not-found-git" class="headerlink" title="ERROR Deployer not found: git"></a>ERROR Deployer not found: git</h1><a id="more"></a><p>报错信息如下</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">hexo d</span><br><span class="line">ERROR Deployer not found: git</span><br></pre></td></tr></table></figure><!-- more --><p><strong>解决方法:</strong> 在根目录执行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install --save hexo-deployer-git</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1 id="ERROR-Deployer-not-found-git"><a href="#ERROR-Deployer-not-found-git" class="headerlink" title="ERROR Deployer not found: git"></a>ERROR Deployer not found: git</h1></summary>
<category term="Error" scheme="https://over-shine.github.io/tags/Error/"/>
<category term="hexo" scheme="https://over-shine.github.io/tags/hexo/"/>
</entry>
<entry>
<title>GNN基础</title>
<link href="https://over-shine.github.io/2020/08/21/GNN%E5%9F%BA%E7%A1%80/"/>
<id>https://over-shine.github.io/2020/08/21/GNN%E5%9F%BA%E7%A1%80/</id>
<published>2020-08-21T14:20:55.000Z</published>
<updated>2021-11-06T06:56:01.941Z</updated>
<content type="html"><![CDATA[<h1 id="GNN基础"><a href="#GNN基础" class="headerlink" title="GNN基础"></a>GNN基础</h1><a id="more"></a><h2 id="图的属性"><a href="#图的属性" class="headerlink" title="图的属性"></a>图的属性</h2><ol><li><strong>节点的度分布 $P(k)$</strong><br>随机选择的节点度为 $k$ 的概率<br>归一化:$P(k)=\frac{N_k}{N}$,$N_k$ 是度为 $k$ 的节点的数量,$N$ 是总的节点数</li></ol><!-- more --><ol><li><strong>路径长度 $h$**</strong>距离(无向图)<strong>:一对节点之间的距离定义为沿着连接这些节点的最短路径的边数</strong>直径<strong>:图中任意节点对之间的最大距离</strong>平均路径长度(连接图或强连接有向图)**:$\bar{h}=\frac{\sum_{i,j\neq i}h_{ij}}{2E_{max}}$,$h_{ij}$ 是节点 $v_i$ 到节点 $v_j$ 的距离,$E_{max}=\frac{n(n-1)}{2}$ 是最大边数(全连接图的边数)</li><li><strong>聚类系数(无向图)</strong>:领居之间的联系如何?$C_i=\frac{2e_i}{K_i(K_i-1)}$,$e_i$ 是节点 $v_i$ 邻居之间的边数,$K_i$ 是节点 $v_i$ 的度数,$K_i(K_i-1)$ 是节点 $v_i$ 邻居之间的最大边数<br><strong>平均聚类系数</strong>:$C=\frac{\sum_i^NC_i}{N}$</li></ol><h2 id="G-np-的属性"><a href="#G-np-的属性" class="headerlink" title="$G_{np}$ 的属性"></a>$G_{np}$ 的属性</h2><p>包含 $n$ 个节点的无向图中,每个边以概率 $p$ 出现,$n$ 和 $p$ 不能唯一确定图!该图是随机过程的结果。给定相同的n和p,我们可以有许多不同的实现。</p><ol><li><strong>$G_{np}$的度分布(一个二项式)</strong>:$P(k)=C_{n-1}^kp^k(1-p)^{n-1-k}$<br>二项式分布的<strong>均值和方差</strong>:$\bar{k}=p(n-1),\sigma^2=p(1-p)(n-1)$<br>根据大数定律,随着网络规模的增加,分布变得越来越狭窄-我们越来越有信心节点的度数在k附近:$\frac{\sigma}{\bar{k}}=[\frac{1-p}{p}\frac{1}{n-1}]^{\frac{1}{2}}\approx\frac{1}{(n-1)^{\frac{1}{2}}}$</li><li><strong>聚类系数</strong>:$E(e_i)=p\frac{k_i(k_i-1)}{2},E(C_i)=\frac{pk_i(k_i-1)}{k_i(k_i-1)}=p=\frac{\bar{k}}{n-1}\approx \frac{\bar{k}}{n}$</li><li><strong>路径长度</strong>:对于图 $G(V,E)$,对于任意离开节点子集 $S$ 的边 $E_{leave}\geq\alpha\cdot\min(|S|,|V/S|)$,即 $\alpha=\min_{S\subseteq V}\frac{E_{leave}}{\min(|S|,|V/S|)}$<br>在n个具有扩展α的节点上的图中,对于所有成对的节点,路径的长度为:$O((\log n)/α)$<br>对于 $G_{np}$:$\log n>np>c, diam(G_{np})=O(\log n/\log (np))$<br><strong>随机图具有良好的扩展性,因此BFS访问所有节点都需要对数步</strong></li></ol>]]></content>
<summary type="html"><h1 id="GNN基础"><a href="#GNN基础" class="headerlink" title="GNN基础"></a>GNN基础</h1></summary>
<category term="随笔" scheme="https://over-shine.github.io/categories/%E9%9A%8F%E7%AC%94/"/>
<category term="GNN" scheme="https://over-shine.github.io/tags/GNN/"/>
</entry>
<entry>
<title>tf.keras.Model子类注意项</title>
<link href="https://over-shine.github.io/2020/08/21/tf-keras-Model%E5%AD%90%E7%B1%BB%E6%B3%A8%E6%84%8F%E9%A1%B9/"/>
<id>https://over-shine.github.io/2020/08/21/tf-keras-Model%E5%AD%90%E7%B1%BB%E6%B3%A8%E6%84%8F%E9%A1%B9/</id>
<published>2020-08-21T14:18:25.000Z</published>
<updated>2021-11-06T06:58:38.117Z</updated>
<content type="html"><![CDATA[<h1 id="tf-keras-Model子类的注意项"><a href="#tf-keras-Model子类的注意项" class="headerlink" title="tf.keras.Model子类的注意项"></a>tf.keras.Model子类的注意项</h1><a id="more"></a><h2 id="自定义网络层"><a href="#自定义网络层" class="headerlink" title="自定义网络层"></a>自定义网络层</h2><p>自定义网络层需要继承 tf.keras.layers.Layer,自定义的层的 trainable 参数默认为 True,即默认可以训练, 如以下定义了两个层:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MaskMean</span>(<span class="params">tf.keras.layers.Layer</span>):</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span>(<span class="params">self</span>):</span></span><br><span class="line"> super(MaskMean, self).__init__()</span><br><span class="line"> self.dropout = tf.keras.layers.Dropout(<span class="number">0.1</span>)</span><br><span class="line"> <span class="comment"># self.trainable_variables.append(self.dropout)</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">call</span>(<span class="params">self, inputs, **kwargs</span>):</span></span><br><span class="line"> print(type(inputs), len(inputs))</span><br><span class="line"> dropout = self.dropout(inputs[<span class="number">0</span>])</span><br><span class="line"> mean = self.batch_boolean_mask_and_mean(dropout, inputs[<span class="number">1</span>])</span><br><span class="line"> <span class="keyword">return</span> mean</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">batch_boolean_mask_and_mean</span>(<span class="params">self, tensor, mask</span>):</span></span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> mask with batch</span></span><br><span class="line"><span class="string"> :param tensor: needed to be masked</span></span><br><span class="line"><span class="string"> :param mask: masker</span></span><br><span class="line"><span class="string"> :return: [batch_size, embedding_size]</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> <span class="keyword">assert</span> tensor.shape[<span class="number">0</span>] == mask.shape[<span class="number">0</span>]</span><br><span class="line"> <span class="comment"># [batch_size, embedding_size]</span></span><br><span class="line"> mean_embeddings = np.zeros([tensor.shape[<span class="number">0</span>], tensor.shape[<span class="number">2</span>]])</span><br><span class="line"> <span class="comment"># example[max_seq_len, embedding_size], masker[max_seq_len,]</span></span><br><span class="line"> <span class="keyword">for</span> i, (example, masker) <span class="keyword">in</span> enumerate(zip(tensor, mask)):</span><br><span class="line"> masked = tf.boolean_mask(example, masker)</span><br><span class="line"> mean_embeddings[i] = tf.reduce_mean(masked, axis=<span class="number">0</span>).numpy()</span><br><span class="line"> <span class="keyword">return</span> mean_embeddings</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Predict</span>(<span class="params">tf.keras.layers.Layer</span>):</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span>(<span class="params">self</span>):</span></span><br><span class="line"> super(Predict, self).__init__()</span><br><span class="line"> self.dense_layer = tf.keras.layers.Dense(<span class="number">512</span>, activation=<span class="string">'relu'</span>, name=<span class="string">"full connection"</span>, dtype=tf.float64)</span><br><span class="line"> self.predict = tf.keras.layers.Dense(<span class="number">1</span>, name=<span class="string">"prediction"</span>, dtype=tf.float64)</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">call</span>(<span class="params">self, inputs, **kwargs</span>):</span></span><br><span class="line"> print(type(inputs), len(inputs))</span><br><span class="line"> middle = self.dense_layer(inputs[<span class="number">0</span>] - inputs[<span class="number">1</span>])</span><br><span class="line"> prediction = self.predict(middle)</span><br><span class="line"> <span class="keyword">return</span> tf.abs(prediction)</span><br></pre></td></tr></table></figure><p>上面定义的两个层,第一个层是作为 Batch MaskMean 层,Predict层是回归模型的输出层</p><p><strong>这里注意:</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mask_mean_layer = MaskMean()</span><br><span class="line">output_layer = Predict()</span><br></pre></td></tr></table></figure><p>这里实例化了两个层的对象,但是此时 mask_mean_layer.trainable_variables 和 output_layer.trainable_variables 为空,这是 tf.keras 的一个特点,因为此时不知道 input_shape, 所以此时还没有分配层的变量,只有当输入一次数据后才会产生变量,当输入一次数据后, trainable_variables 参数就已经产生了。</p><h2 id="自定义模型"><a href="#自定义模型" class="headerlink" title="自定义模型"></a>自定义模型</h2><p><strong>另外的注意点:</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Regulation</span>(<span class="params">tf.keras.Model</span>):</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span>(<span class="params">self</span>):</span></span><br><span class="line"> super(Regulation, self).__init__()</span><br><span class="line"> self.predict = Predict()</span><br><span class="line"> self.mask_mean_layer = MaskMean()</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">call</span>(<span class="params">self, inputs, sentence_pair=False, **kwargs</span>):</span></span><br><span class="line"> <span class="keyword">if</span> sentence_pair:</span><br><span class="line"> prediction = self.sentence_pair(inputs, **kwargs)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> prediction = self.sentence(inputs, **kwargs)</span><br><span class="line"> <span class="keyword">return</span> prediction</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">sentence</span>(<span class="params">self, inputs, **kwargs</span>):</span></span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> the input of model is one sentence and this function is</span></span><br><span class="line"><span class="string"> to split the data into input_ids, input_mask, segment_ids</span></span><br><span class="line"><span class="string"> :param inputs: dataset</span></span><br><span class="line"><span class="string"> :param kwargs: config of input, {sentence_pair:bool, training:bool}</span></span><br><span class="line"><span class="string"> :return: input_ids, input_mask, segment_ids</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> input_ids = inputs[<span class="number">0</span>]</span><br><span class="line"> <span class="keyword">if</span> len(inputs) >= <span class="number">2</span>:</span><br><span class="line"> input_mask = inputs[<span class="number">1</span>]</span><br><span class="line"> <span class="keyword">if</span> len(inputs) >= <span class="number">3</span>:</span><br><span class="line"> segment_ids = inputs[<span class="number">2</span>]</span><br><span class="line"> <span class="comment"># [batch_size, max_seq_len, embedding_size]</span></span><br><span class="line"> embeddings = self.embedding((input_ids, input_mask, segment_ids), **kwargs)[<span class="number">0</span>]</span><br><span class="line"> <span class="comment"># Dropout keep shape</span></span><br><span class="line"> dropout = self.dropout(inputs=embeddings)</span><br><span class="line"> <span class="comment"># [batch_size, max_seq_len, embedding_size] -> [batch_size, seq_len, embedding_size]</span></span><br><span class="line"> <span class="comment"># seq_a_len may be not equal to seq_b_len</span></span><br><span class="line"> mask = tf.boolean_mask(dropout, input_mask, axis=<span class="number">1</span>)</span><br><span class="line"> <span class="comment"># [batch_size, seq_len, embedding_size] -> [batch_size, embedding_size]</span></span><br><span class="line"> <span class="comment"># let all token embeddings' mean as the sentence embedding</span></span><br><span class="line"> mean = tf.reduce_mean(mask, <span class="number">1</span>)</span><br><span class="line"> <span class="comment"># [batch_size, embedding_size] -> [batch_size*embedding_size,]</span></span><br><span class="line"> flatten = tf.reshape(mean, (<span class="number">-1</span>,))</span><br><span class="line"> middle = self.inmediate(flatten)</span><br><span class="line"> prediction = tf.reshape(self.predict(middle), [<span class="number">-1</span>, ])</span><br><span class="line"> <span class="keyword">return</span> tf.abs(prediction)</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">sentence_pair</span>(<span class="params">self, inputs, **kwargs</span>):</span></span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> the input of model is sentence pairs and this function is</span></span><br><span class="line"><span class="string"> to split the data into input_ids, input_mask, segment_ids</span></span><br><span class="line"><span class="string"> :param inputs: dataset</span></span><br><span class="line"><span class="string"> :param kwargs: config of input, {'sentence_pair:bool, training:bool}</span></span><br><span class="line"><span class="string"> :return: input_ids:(sentence_a, sentence_b), input_mask:(input_mask_a, input_mask_b), segment_ids:(segment_ids_a, segment_ids_b)</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> <span class="comment"># input_ids = inputs[0]</span></span><br><span class="line"> embeddings = inputs[<span class="number">0</span>]</span><br><span class="line"> <span class="keyword">if</span> len(inputs) >= <span class="number">2</span>:</span><br><span class="line"> input_mask = inputs[<span class="number">1</span>]</span><br><span class="line"> <span class="keyword">if</span> len(inputs) >= <span class="number">3</span>:</span><br><span class="line"> segment_ids = inputs[<span class="number">2</span>]</span><br><span class="line"> mean_a, mean_b = self.mask_mean_layer((embeddings[<span class="number">0</span>], input_mask[<span class="number">0</span>]), **kwargs), self.mask_mean_layer(</span><br><span class="line"> (embeddings[<span class="number">1</span>], input_mask[<span class="number">1</span>]), **kwargs)</span><br><span class="line"> prediction = self.predict((mean_a, mean_b), **kwargs)</span><br><span class="line"> <span class="keyword">return</span> prediction</span><br><span class="line"></span><br><span class="line">model = Regulation()</span><br></pre></td></tr></table></figure><p>这里定义了一个 tf.keras.Model 的一个子类,包含两个自定义层。这时查看 model.layers 可以发现只有一个层, 而且即使输入一次数据,它的 trainable_variables 仍为空,后来发现 transformers 库里的每个 Model 都只包含一个层,所以经过尝试,重新定义如下:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Regulation</span>(<span class="params">tf.keras.layers.Layer</span>):</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span>(<span class="params">self</span>):</span></span><br><span class="line"> super(Regulation, self).__init__()</span><br><span class="line"> self.predict = Predict()</span><br><span class="line"> self.mask_mean_layer = MaskMean()</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">call</span>(<span class="params">self, inputs, sentence_pair=False, **kwargs</span>):</span></span><br><span class="line"> <span class="keyword">if</span> sentence_pair:</span><br><span class="line"> prediction = self.sentence_pair(inputs, **kwargs)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> prediction = self.sentence(inputs, **kwargs)</span><br><span class="line"> <span class="keyword">return</span> prediction</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">sentence</span>(<span class="params">self, inputs, **kwargs</span>):</span></span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> the input of model is one sentence and this function is</span></span><br><span class="line"><span class="string"> to split the data into input_ids, input_mask, segment_ids</span></span><br><span class="line"><span class="string"> :param inputs: dataset</span></span><br><span class="line"><span class="string"> :param kwargs: config of input, {sentence_pair:bool, training:bool}</span></span><br><span class="line"><span class="string"> :return: input_ids, input_mask, segment_ids</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> input_ids = inputs[<span class="number">0</span>]</span><br><span class="line"> <span class="keyword">if</span> len(inputs) >= <span class="number">2</span>:</span><br><span class="line"> input_mask = inputs[<span class="number">1</span>]</span><br><span class="line"> <span class="keyword">if</span> len(inputs) >= <span class="number">3</span>:</span><br><span class="line"> segment_ids = inputs[<span class="number">2</span>]</span><br><span class="line"> <span class="comment"># [batch_size, max_seq_len, embedding_size]</span></span><br><span class="line"> embeddings = self.embedding((input_ids, input_mask, segment_ids), **kwargs)[<span class="number">0</span>]</span><br><span class="line"> <span class="comment"># Dropout keep shape</span></span><br><span class="line"> dropout = self.dropout(inputs=embeddings)</span><br><span class="line"> <span class="comment"># [batch_size, max_seq_len, embedding_size] -> [batch_size, seq_len, embedding_size]</span></span><br><span class="line"> <span class="comment"># seq_a_len may be not equal to seq_b_len</span></span><br><span class="line"> mask = tf.boolean_mask(dropout, input_mask, axis=<span class="number">1</span>)</span><br><span class="line"> <span class="comment"># [batch_size, seq_len, embedding_size] -> [batch_size, embedding_size]</span></span><br><span class="line"> <span class="comment"># let all token embeddings' mean as the sentence embedding</span></span><br><span class="line"> mean = tf.reduce_mean(mask, <span class="number">1</span>)</span><br><span class="line"> <span class="comment"># [batch_size, embedding_size] -> [batch_size*embedding_size,]</span></span><br><span class="line"> flatten = tf.reshape(mean, (<span class="number">-1</span>,))</span><br><span class="line"> middle = self.inmediate(flatten)</span><br><span class="line"> prediction = tf.reshape(self.predict(middle), [<span class="number">-1</span>, ])</span><br><span class="line"> <span class="keyword">return</span> tf.abs(prediction)</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">sentence_pair</span>(<span class="params">self, inputs, **kwargs</span>):</span></span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> the input of model is sentence pairs and this function is</span></span><br><span class="line"><span class="string"> to split the data into input_ids, input_mask, segment_ids</span></span><br><span class="line"><span class="string"> :param inputs: dataset</span></span><br><span class="line"><span class="string"> :param kwargs: config of input, {'sentence_pair:bool, training:bool}</span></span><br><span class="line"><span class="string"> :return: input_ids:(sentence_a, sentence_b), input_mask:(input_mask_a, input_mask_b), segment_ids:(segment_ids_a, segment_ids_b)</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> embeddings = inputs[<span class="number">0</span>]</span><br><span class="line"> <span class="keyword">if</span> len(inputs) >= <span class="number">2</span>:</span><br><span class="line"> input_mask = inputs[<span class="number">1</span>]</span><br><span class="line"> <span class="keyword">if</span> len(inputs) >= <span class="number">3</span>:</span><br><span class="line"> segment_ids = inputs[<span class="number">2</span>]</span><br><span class="line"> mean_a, mean_b = self.mask_mean_layer((embeddings[<span class="number">0</span>], input_mask[<span class="number">0</span>]), **kwargs), self.mask_mean_layer(</span><br><span class="line"> (embeddings[<span class="number">1</span>], input_mask[<span class="number">1</span>]), **kwargs)</span><br><span class="line"> prediction = self.predict((mean_a, mean_b), **kwargs)</span><br><span class="line"> <span class="keyword">return</span> prediction</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">RegulateModel</span>(<span class="params">tf.keras.Model</span>):</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span>(<span class="params">self</span>):</span></span><br><span class="line"> super(RegulateModel, self).__init__()</span><br><span class="line"> self.regulation_layer = Regulation()</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">call</span>(<span class="params">self, inputs, sentence_pair=True, **kwargs</span>):</span></span><br><span class="line"> <span class="keyword">return</span> self.regulation_layer(inputs, sentence_pair=sentence_pair)</span><br><span class="line"></span><br><span class="line">model = RegulateModel()</span><br></pre></td></tr></table></figure><p>这时可以发现 model.layers 包含一个层, 而且model.layers[0]._layers 包含两个自定义层,此时输入一次数据并输出后,发现 model.trainable_variable 已经分配变量了。</p><p><strong>结论:</strong> 通过这次试验发现,tf.keras.Model 的子类只能包含一个层,而且只有自定义的层可以包含多个网络层,而且只有在输入一次数据后才会分配变量。</p>]]></content>
<summary type="html"><h1 id="tf-keras-Model子类的注意项"><a href="#tf-keras-Model子类的注意项" class="headerlink" title="tf.keras.Model子类的注意项"></a>tf.keras.Model子类的注意项</h1></summary>
<category term="Tensorflow" scheme="https://over-shine.github.io/categories/Tensorflow/"/>
<category term="DL" scheme="https://over-shine.github.io/tags/DL/"/>
<category term="Tensorflow" scheme="https://over-shine.github.io/tags/Tensorflow/"/>
</entry>
<entry>
<title>word2vec</title>
<link href="https://over-shine.github.io/2020/08/21/word2vec/"/>
<id>https://over-shine.github.io/2020/08/21/word2vec/</id>
<published>2020-08-21T14:15:45.000Z</published>
<updated>2021-11-06T06:58:49.988Z</updated>
<content type="html"><![CDATA[<h1 id="From-Count-Vectors-to-Word2Vec"><a href="#From-Count-Vectors-to-Word2Vec" class="headerlink" title="From Count Vectors to Word2Vec"></a>From Count Vectors to Word2Vec</h1><a id="more"></a><p>Word Embeddings可以广义的分为以下两种:</p><ol><li>Frequency based Embedding.</li><li>Prediction based Embedding.</li></ol><!-- more --><h2 id="1-Frequency-based-Embedding"><a href="#1-Frequency-based-Embedding" class="headerlink" title="1. Frequency based Embedding"></a>1. Frequency based Embedding</h2><p>给予频率的Word Embedding可以分为以下三种:</p><ol><li>Count Vector.</li><li>TF-IDF Vector.</li><li>Co-Occurrence Vector.</li></ol><h3 id="1-1-Count-Vector"><a href="#1-1-Count-Vector" class="headerlink" title="1.1 Count Vector"></a>1.1 Count Vector</h3><p>Count Vector工作原理:Count Vector是将一个语料库中的每个文档中每个word出现的次数分别统计起来,这样一个语料库就形成了一个words-documents矩阵,words是整个语料库出现的所有单词,而documents是语料库中的所有文档,最终形成的W-D Matrix如下:</p><div align=center><img src="count-vector.png"/></div><h3 id="1-2-TF-IDF-vectorization"><a href="#1-2-TF-IDF-vectorization" class="headerlink" title="1.2 TF-IDF vectorization"></a>1.2 TF-IDF vectorization</h3><p>这是另一种基于频率方法的方法,但与Count Vector不同的是,它不仅考虑单个文档中单词的出现,还考虑整个语料库中的单词。理想情况下,我们希望<strong>减少在几乎所有文档中出现的常用单词,并更加重视出现在文档子集中的单词。</strong></p><p>TF-IDF工作原理:通过给这些常用词分配较低的权重来对其进行惩罚,同时在特定文档中重视特别出现的词。</p><div align=center><img src="Tf-IDF.png"/></div><p>下面是一些与TF-IDF相关的术语:</p><script type="math/tex; mode=display">TF=\frac{单词\ t\ 在某个文档出现的次数}{该文档中的单词总数}</script><p>如$ TF(This,document1)=\frac{1}{8}$,它表示单词对文档的贡献,即与文档相关的单词应经常出现。</p><script type="math/tex; mode=display">IDF=\log(\frac{语料库中的文档数N}{语料库中出现单词\ t\ 的文档数n})</script><p>如$ IDF(This)=\log(\frac{2}{2})=0$,$IDF(Messi)=\log(\frac{2}{1})=0.301$</p><p>理想情况下,如果一个单词出现在所有文档中,则该单词可能与特定文档无关。但是,如果它出现在一部分文档中,则该单词可能与其所在的文档有些相关。</p><script type="math/tex; mode=display">TF-IDF(This,document1)=\frac{1}{8}*0=0</script><script type="math/tex; mode=display">TF-IDF(This,Document2)=\frac{1}{5}*0=0</script><script type="math/tex; mode=display">TF-IDF(Messi,Document1)=\frac{4}{8}*0.301=0.15</script><p>如上所见,对于Document1,TF-IDF方法严重惩罚了单词’This’,但为’Messi’分配了更大的权重。因此,从整个语料库的上下文来看,“Messi”对于Document1来说是一个重要的词。</p><h3 id="1-3-Co-Occurrence-Matrix-with-a-fixed-context-window"><a href="#1-3-Co-Occurrence-Matrix-with-a-fixed-context-window" class="headerlink" title="1.3 Co-Occurrence Matrix with a fixed context window"></a>1.3 Co-Occurrence Matrix with a fixed context window</h3><p>伟大的想法 -相似的词往往会在一起出现,并且具有类似的上下文-例如,苹果是一种水果。芒果是一种水果。苹果和芒果倾向于具有相似的背景,即水果。</p><p>一对单词w1和w2的共现是它们在上下文窗口中一起出现的次数。</p><p>对于如下上下文窗口为2(实际整个窗口大小为2*2+1=5)的共现矩阵:</p><div align=center><img src="comatrix.png" /></div><p>红色框-这是上下文窗口2中出现“他”和“是”的次数,可以看出计数结果为4。</p><div align=center><img src="comatrix1.png" /></div><h4 id="1-3-1-Variations-of-Co-occurrence-Matrix"><a href="#1-3-1-Variations-of-Co-occurrence-Matrix" class="headerlink" title="1.3.1 Variations of Co-occurrence Matrix"></a>1.3.1 Variations of Co-occurrence Matrix</h4><p>我们可以对共现矩阵做处理:</p><ol><li>最初的贡献矩阵是一个$V\times V$的方阵,当语料库很大时,维度非常高,我们可以通过删除不想关的词来降低一下维度获得$V\times N$的矩阵;</li><li>对于上面的$V\times N$的共现矩阵,维度仍然很高。我们可以通过对共现矩阵$V\times V$做PCA降维处理获得一个$V\times K$的共现矩阵;</li><li>接下来要做的就是对共现矩阵$V\times K$做奇异值分解(SVD),获得三个分接矩阵$U,S和V$,其中$U和V$都是正交矩阵。其中$U和S$的点乘是单词的向量表示,$V$是单词的上下文表示。</li></ol><h4 id="1-3-2-共现矩阵的优点"><a href="#1-3-2-共现矩阵的优点" class="headerlink" title="1.3.2 共现矩阵的优点"></a>1.3.2 共现矩阵的优点</h4><ol><li>它保留了单词之间的语义关系。即男人和女人往往比男人和苹果更接近。</li><li>它以SVD为核心,比现有方法产生更准确的单词向量表示。</li><li>它使用因式分解,这是一个明确定义的问题,可以有效解决。</li><li>它必须计算一次,并且可以在计算后随时使用。从这个意义上讲,它比其他方法更快。</li></ol><h4 id="1-3-3-共现矩阵的缺点"><a href="#1-3-3-共现矩阵的缺点" class="headerlink" title="1.3.3 共现矩阵的缺点"></a>1.3.3 共现矩阵的缺点</h4><ol><li>它需要大量内存来存储共现矩阵。但是,可以通过将矩阵分解到系统外(例如在Hadoop集群等中)来解决此问题,并可以将其保存下来。</li></ol><h2 id="2-Word2vec(Prediction-based-Vector)"><a href="#2-Word2vec(Prediction-based-Vector)" class="headerlink" title="2. Word2vec(Prediction based Vector)"></a>2. Word2vec(Prediction based Vector)</h2><h3 id="2-1-N-Gram统计语言模型"><a href="#2-1-N-Gram统计语言模型" class="headerlink" title="2.1 N-Gram统计语言模型"></a>2.1 N-Gram统计语言模型</h3><script type="math/tex; mode=display">\begin{aligned} S1&="The\ cat\ jumped\ over\ the \ puddle."\\ S2&="stock \ boil\ fish\ is \ toy"\end{aligned}</script><h4 id="2-1-1-Unigram-Model-1-gram"><a href="#2-1-1-Unigram-Model-1-gram" class="headerlink" title="2.1.1 Unigram Model(1-gram)"></a>2.1.1 Unigram Model(1-gram)</h4><p>这里,我们可以在给定的包含n个单词的序列得出一个如下的概率:</p><script type="math/tex; mode=display">P(S)=P(w_1,w_2,\ldots,w_n)</script><p>我们可以通过假设序列中每个单词出现是完全独立的,并采用一元语言模型来计算这个概率:</p><script type="math/tex; mode=display">P(S)=P(w_1,w_2,\ldots,w_n)=\prod_{i=1}^nP(w_i)</script><p>因此,对于上面两个句子$S1$和$S2$,$P(S1)$应该是一个高概率($S1$是一个有效的句子),$P(S2)$应该是一个低概率($S2$是一个无效的句子)</p><h4 id="2-1-2-Bigram-Model-2-gram"><a href="#2-1-2-Bigram-Model-2-gram" class="headerlink" title="2.1.2 Bigram Model(2-gram)"></a>2.1.2 Bigram Model(2-gram)</h4><p>在现实中,一个单词出现在一个句子中是高度依赖于前面的单词序列的,所以Unigram Model太武断了,并不能很好的计算句子有效的概率,所以提出了Bigram Model。Bigram Model假设一个单词的出现高度依赖于它前面的那个单词,概率的计算公式如下:</p><script type="math/tex; mode=display">P(S)=P(w_1,w_2,\ldots,w_n)=\prod_{i=2}^nP(w_i|w_{i-1})</script><p>Bigram Model也有缺陷,因为它只是关注了与单词紧邻的那个单词,并没有考虑到整个句子,但这种计算概率的方法使我们走的更远。</p><p>Word2vec不是单个算法,而是两种技术的组合-CBOW(连续词袋)和Skip-gram模型。这两个都是浅层神经网络,它们将单词映射到目标变量,目标变量也是单词。这两种技术都学习用作词向量表示的权重。让我们分别讨论这两种方法,并直观地了解它们的工作原理。</p><h3 id="2-2-CBOW(连续词袋)模型"><a href="#2-2-CBOW(连续词袋)模型" class="headerlink" title="2.2 CBOW(连续词袋)模型"></a>2.2 CBOW(连续词袋)模型</h3><p>CBOW的工作方式是在给定上下文的情况下倾向于预测单词的概率。上下文可以是单个单词或一组单词。但为简单起见,我将使用单个上下文词并尝试预测单个目标词。</p><p>假设我们有一个语料库C =“Hey, this is sample corpus using only one context word.”并且我们定义了一个上下文窗口1。可以将该语料库转换为CBOW模型的训练集,如下所示。输入如下所示。下图右侧的矩阵包含左侧输入的one-hot编码。</p><div align=center><img src="cbow1.png" /></div><p>上表一行代表一个样本。</p><p><strong>CBOW模型如下:</strong></p><div align=center><img src="CBOW.png"/></div><p>该网络具有三层:输入层,隐藏层和输出层。输出层是softmax层,用于将在输出层中获得的概率求和为1。现在让我们看一下正向传播如何计算隐藏层激活。</p><p>下面是单个样本数据作为CBOW模型输入的流程:</p><div align=center><img src="cbow2.png"/></div><ol><li>输入层和目标都进行了一次one-hot编码,大小为[1 XV]。在上面的示例中,V = 10;</li><li>有两组权重。一个在输入层与隐藏层之间,第二个在隐藏层与输出层之间。输入隐藏层矩阵大小$U=[V\times N]$,隐藏输出层矩阵大小$V= [N\times V]$:其中N是我们选择用来表示单词的维数。它是神经网络的任意参数和超参数。同样,N是隐藏层中神经元的数量。在此,N = 4;</li><li>任何层之间都没有激活功能;</li><li>输入乘以输入隐藏权重$U$,称为隐藏激活。它只是复制的输入隐藏矩阵中的相应行;</li><li>计算隐藏层的输入和隐藏权重$V$;</li><li>计算输出和目标之间的误差,并传播回去以重新调整权重;</li><li>隐藏层和输出层之间的权重被用作单词的单词向量表示。</li></ol><p>下图使用了三个上下文词作为输入,CBOW模型计算如下:</p><div align=center><img src="cbow3.png"/></div><p>输入层在输入中将具有3 [1 XV]个向量,在输出层中将具有1 [1 XV]个向量。</p><p>步骤保持不变,只是隐藏激活的计算发生了变化。不仅将输入隐藏的权重矩阵的对应行复制到隐藏层,还对矩阵的所有对应行取平均值。通过上图我们可以理解这一点。计算出的平均向量成为隐藏的激活。因此,如果我们针对单个目标词具有三个上下文词,则我们将具有三个初始隐藏激活,然后将其按元素进行平均以获得最终激活。</p><h4 id="2-2-1-CBOW的训练过程"><a href="#2-2-1-CBOW的训练过程" class="headerlink" title="2.2.1 CBOW的训练过程"></a>2.2.1 CBOW的训练过程</h4><p><strong>CBOW模型一些参数:</strong></p><p><strong>$ x^{(c)} $:</strong> 输入上下文的one-hot编码向量;<br><strong>$ y^{(c)} $:</strong> 预测单词的one-hot编码向量;<br><strong>$ \mathcal{V}\in R^{n\times |V|} $:</strong> 输入层-隐藏层权重矩阵;<br><strong>$ \mathcal{U}\in R^{|V|\times n} $:</strong> 隐藏层-输出层权重矩阵;<br><strong>$ w_i $:</strong> 词典的地$i$个单词;<br><strong>$ \mathcal{v}_i $:</strong> 输入层-隐含层权重矩阵的第$i$列,代表词典中第$i$个单词的word embedding;<br><strong>$ \mathcal{u}_i $:</strong> 隐藏层-输出层权重矩阵的第$i$行,表示词典中第$i$个单词的向量表示。</p><div align=center><img src="CBOWS.png"></div><p><strong>我们把计算步骤细化为如下步骤:</strong></p><ol><li>生成上下文窗口为m的one-hot编码词向量,$x^{(c-j)}$是维度为$V$的one-hot编码向量:<script type="math/tex; mode=display">(x^{(c-m)}, \cdots,x^{(c-1)},x^{(c+1)},\cdots,x^{(c+m)}\in R^{|V|})</script></li><li>取得上下文单词的word embeddings:<script type="math/tex; mode=display">(v_{c-m}=\mathcal{V} x^{(c-m)},v_{c-m+1}=\mathcal{V} x^{(c-m+1)},\cdots,v_{c+m}=\mathcal{V} x^{(c+m)})</script></li><li>对word embeddings取均值 $ \hat{v}=\frac{\sum_{j=-m}^{j=m}v_{c+j}}{2m}\in R^n$;</li><li>生成分数向量 $z=\mathcal{U}\hat\in R^{|V|}$ 。相似单词点乘越高,它将会促进相似单词更加接近以获得更高分数;</li><li>将分数转成概率 $\hat{y}=softmax(z)\in R^{|V|}$;</li><li>我们希望生成的概率,$\hat{y}\in R^{|V|}$ , t去匹配真实概率, $y\in R^{|V|}$。</li></ol><p><strong>怎么获得 $\mathcal{V}$ 和 $\mathcal{U}$ 这两个矩阵?</strong></p><p>我们使用交叉熵 $H(\hat{y},y)$作为代价函数:</p><script type="math/tex; mode=display">H(\hat{y},y)=-\sum_{j=1}^{|V|}y_i\log(\hat{y_i})</script><p>让我们关注当前的情况,即$y$是一个one-hot向量。 因此,我们知道上述损失简化为:</p><script type="math/tex; mode=display">H(\hat{y},y)=-y_i\log(\hat{y_i})</script><p>我们生成了优化的目标函数:</p><script type="math/tex; mode=display">\begin{aligned} minimize \ J&=-\log P(w_c|w_{c-m},\cdots,w_{c-1},w_{c+1},\cdots,w_{c+m})\\ & =-\log P(\mathcal{u}_c|\hat{\mathcal{v}})\\ &=-\log\frac{exp^{(\mathcal{u}_c^T\hat{\mathcal{v}})}}{\sum_{j=1}^{|V|}exp^(\mathcal{u}_j^T\hat{\mathcal{v}})}\\ &=-\mathcal{u}_c^T\hat{\mathcal{v}}+log\sum_{j=1}^{|V|}exp^{(\mathcal{u}_j^T\hat{\mathcal{v}})}\end{aligned}</script><h4 id="2-2-2-CBOW优点"><a href="#2-2-2-CBOW优点" class="headerlink" title="2.2.2 CBOW优点"></a>2.2.2 CBOW优点</h4><ol><li>概率是自然,它应该表现出比确定性方法更好的(通常)。</li><li>内存不足。它不需要像共现矩阵那样需要巨大的RAM需求,因为它需要存储三个巨大的矩阵。</li></ol><h4 id="2-2-3-CBOW缺点"><a href="#2-2-3-CBOW缺点" class="headerlink" title="2.2.3 CBOW缺点"></a>2.2.3 CBOW缺点</h4><ol><li>CBOW取一个单词上下文的平均值(如上图所示,用于计算隐藏激活)。例如,苹果既可以是水果,也可以是公司,但CBOW会同时获取两种情况的平均值,并将其置于水果和公司的集群之间。</li><li>如果未进行适当的优化,从头开始培训CBOW可能会花费很多时间。</li></ol><h3 id="2-3-Skip-Gram模型"><a href="#2-3-Skip-Gram模型" class="headerlink" title="2.3 Skip-Gram模型"></a>2.3 Skip-Gram模型</h3><p>Skip-Gram的工作方式是根据给定的单词预测该单词的上下文。</p><div align=center><img src="skip.png"/></div>输入层大小向量$ [1 \times V]$,输入层-隐藏层权重矩阵大小$ [V\times N]$,隐藏层中的神经元数量为N,隐藏层-输出层权重矩阵大小$ [N\times V]$,输出层大小$C [1\times V]$,其中C是上下文单词的数量。下面是一次上下文输入的skip-gram计算流程:1. 红色的行是对应于输入的one-hot向量的隐藏激活。它基本上是复制的输入隐藏矩阵的相应行;2. 黄色矩阵是隐藏层和输出层之间的权重;3. 通过隐藏层激活和隐藏层-输出层权重的矩阵乘法获得蓝色矩阵,产生两个上下文向量(根据上下文窗口大小而定);4. 蓝色矩阵的每一行分别转换为其softmax概率,如绿色框所示;5. 灰度矩阵包含两个上下文词(目标)的一个one-hot向量(目标单词的one-hot向量);6. 通过从元素矩阵的绿色矩阵(输出)的第一行减去灰色矩阵(目标)的第一行来计算误差。对于下一行重复此过程。因此,对于n个 目标上下文词,我们将具有n个误差向量;7. 对所有误差向量取逐个元素的和,以获得最终误差向量;8. 该误差向量被传播回以更新权重。#### 2.3.1 Skip-Gram训练过程<div align=center><img src="SG.png"/></div><p><strong>我们把Skip-Gram模型训练过程分为如下步骤:</strong></p><ol><li>生成中心词的one-hot输入向量 $x\in R^{|V|}$ ;</li><li>通过点乘获取中心词的word embedding $ v_c = \mathcal{V} x\in R^n$;</li><li>计算分数向量 $ z = \mathcal{U} v_c $;</li><li>将分数向量转换成概率, $\hat{y}=\operatorname{softmax}(z)$ . 注意 $\hat{y}_{c-m}, \ldots, \hat{y}_{c-1}, \hat{y}_{c+1}, \ldots, \hat{y}_{c+m}$ 是每个关注的上下文单词的概率;</li><li>我们希望生成的上下文单词概率能够匹配真实上下文单词的概率 $y^{(c-m)}, \ldots, y^{(c-1)}, y^{(c+1)}, \ldots, y^{(c+m)}$;</li></ol><p>像CBOW模型一样,Skip-Gram模型也需要一个目标函数来评估该模型。和CBOW模型评估函数的主要区别在于,Skip-Gram调用了朴素贝叶斯假设来得出概率 。如果您以前没有看过,那么简单地说,这是一个强有力的(本机)条件独立假设。 换句话说,给定中心词,所有输出词都是完全独立的。</p><script type="math/tex; mode=display">\begin{aligned} \operatorname{minimize} J &=-\log P\left(w_{c-m}, \ldots, w_{c-1}, w_{c+1}, \ldots, w_{c+m} | w_{c}\right) \\ &=-\log \prod_{j=0, j \neq m}^{2 m} P\left(w_{c-m+j} | w_{c}\right) \\ &=-\log \prod_{j=0, j \neq m}^{2 m} P\left(u_{c-m+j} | v_{c}\right) \\ &=-\log \prod_{j=0, j \neq m}^{2 m} \frac{\exp \left(u_{c-m+j}^{T} v_{c}\right)}{\sum_{k=1}^{|V|} \exp \left(u_{k}^{T} v_{c}\right)} \\ &=-\sum_{i=0}^{2 m} u_{c-m+j}^{T} v_{c}+2 m \log \sum_{i=1}^{|V|} \exp \left(u_{k}^{T} v_{c}\right) \end{aligned}</script><script type="math/tex; mode=display">\begin{aligned} J &=-\sum_{j=0, j \neq m}^{2 m} \log P\left(u_{c-m+j} | v_{c}\right) \\ &=\sum_{j=0, j \neq m}^{2 m} H\left(\hat{y}, y_{c-m+j}\right) \end{aligned}</script><p>$H\left(\hat{y}, y_{c-m+j}\right)$ 是概率向量 $\hat{y}$ 和one-hot向量 $y_{c-m+j}$的交叉熵损失函数。</p><h4 id="2-3-2-Skip-Gram模型的优点"><a href="#2-3-2-Skip-Gram模型的优点" class="headerlink" title="2.3.2 Skip-Gram模型的优点"></a>2.3.2 Skip-Gram模型的优点</h4><ol><li>Skip-Gram模型可以捕获单个单词的两种语义。即它将具有Apple的两个矢量表示。一个用于公司,另一个用于水果。</li><li>带有负采样的Skip-Gram模型通常胜过其他所有方法。</li></ol>]]></content>
<summary type="html"><h1 id="From-Count-Vectors-to-Word2Vec"><a href="#From-Count-Vectors-to-Word2Vec" class="headerlink" title="From Count Vectors to Word2Vec"></a>From Count Vectors to Word2Vec</h1></summary>
<category term="随笔" scheme="https://over-shine.github.io/categories/%E9%9A%8F%E7%AC%94/"/>
<category term="NLP" scheme="https://over-shine.github.io/tags/NLP/"/>
<category term="word2vec" scheme="https://over-shine.github.io/tags/word2vec/"/>
</entry>
<entry>
<title>Deep Learning on Graph: A Survey</title>
<link href="https://over-shine.github.io/2020/08/21/Deep-Learning-on-Graph-A-Survey/"/>
<id>https://over-shine.github.io/2020/08/21/Deep-Learning-on-Graph-A-Survey/</id>
<published>2020-08-21T14:11:17.000Z</published>
<updated>2021-11-06T06:55:07.620Z</updated>
<content type="html"><![CDATA[<h1 id="Deep-Learning-on-Graph-A-Survey"><a href="#Deep-Learning-on-Graph-A-Survey" class="headerlink" title="Deep Learning on Graph: A Survey"></a>Deep Learning on Graph: A Survey</h1><a id="more"></a><p>基于现有模型的模型架构和训练策略,我们将其分为五类:<strong>图递归神经网络</strong>,<strong>图卷积网络</strong>,<strong>图自动编码器</strong>,<strong>图强化学习</strong>和<strong>图对抗方法</strong></p><!-- more --><h2 id="1-Introduction"><a href="#1-Introduction" class="headerlink" title="1. Introduction"></a>1. Introduction</h2><p>在近些年,怎样利用深度学习分析图数据吸引了大量研究人员的注意,但是在应用深度学习框架到图上仍然存在一些挑战,如下:</p><ul><li><strong>图的不规则框架</strong>:图具有不规则结构,因此很难将一些基本的数学运算概括为图</li><li><strong>图的异构性和多样性</strong>:图可能非常复杂,包含各种各样的类型和属性,如图可以是异构的或同构的,加权的或未加权的,有符号的或无符号的。此外,图任务也比较广,关注节点的问题,如节点分类、连接预测,到关注图的问题,如图分类和生成图</li><li><strong>大规模图</strong>:在大数据时代,现实中的图包含百万上亿的节点和边,如社交网络和电子商务网络。因此,如何设计可扩展模型,最好是相对于图形大小具有线性时间复杂度的模型,是一个关键问题。</li><li><strong>整合跨学科知识</strong>:图通常与其他学科联系在一起,例如生物学,化学和社会科学。 这种跨学科的性质既带来了机遇,也带来了挑战:可以利用领域知识来解决特定问题,但是集成领域知识可以使模型设计复杂化。 例如,当生成分子图时,目标函数和化学约束通常是不可微的。 因此,基于梯度的训练方法不容易应用。</li></ul><p>为了解决这些问题,研究人员付出了很大的努力,发表了很多相关文章和方法。GNN所采用的体系结构和深度学习训练策略也大相径庭,从监督到无监督,从卷积到递归。</p><div align=center><img src="GNN1.PNG"></div><p>我们根据现有方法的模型架构和训练策略将其分为五类:</p><ul><li><strong>图递归神经网络(Graph RNN)</strong>:图RNN通过在节点级别或图级别对状态进行建模来捕获图的递归和顺序模式。</li><li><strong>图卷积网络(GCN)</strong>:GCN 在不规则图结构上定义卷积和读出操作,以捕获常见的局部和全局结构模式。</li><li><strong>图自动编码器(GAEs)</strong>:GAEs 采取低等级的图结构,并采用无监督的方法进行节点表示学习。</li><li><strong>图强化学习(Graph RL)</strong>:Graph RL 定义了基于图形的动作和奖励,以在遵循约束的同时获得图形任务的反馈。</li><li><strong>图对抗方法</strong>:图对抗方法采用对抗训练技术来增强基于图的模型的泛化能力,并通过对抗攻击来测试其健壮性。</li></ul><p>基于以下高级区别,我们在表1中总结了这些类别的一些主要特征。</p><div align=center><img src="GNN2.PNG"></div><h2 id="2-Notations-And-Preliminaries"><a href="#2-Notations-And-Preliminaries" class="headerlink" title="2. Notations And Preliminaries"></a>2. Notations And Preliminaries</h2><ul><li>图:$G=(V,E), V=\{v_1,v_2,\ldots,v_N\},N=|V|,E\subseteq V\times V,M=|E|$,$N$代表节点数,$M$代表边数</li><li>邻接矩阵:$A\in \mathbb{R}^{N\times N}$,在这篇论文中主要考虑无符号图,因此 $A(i,j)\ge 0$</li><li>边特征和节点特征:$F^E,F^V$</li><li>在本文中,大写字母代表矩阵,小写字母代表向量,卷曲字母代表函数如 $\mathcal{F}(\cdot)$</li><li>一个无向图的拉普拉斯矩阵:$L=D-A$,$D$ 是一个对角矩阵,代表每个节点的度,$A$ 是邻接矩阵;拉普拉斯矩阵的特征分解表示为 $L=Q\Lambda Q^T,\Lambda \in\mathbb{R}^{N\times N}$</li><li>转移矩阵:$P=D^{-1}A$,$P(i,j)$ 代表从节点 $v_i$ 随机游走到节点 $v_j$ 的概率</li><li>节点的K步邻居:$\mathcal{N}_k=\{j|\mathcal{D}(i,j)\leq k\}$,其中 $\mathcal{D}(i,j)$ 是节点 $v_i$ 到节点 $v_j$ 的最短距离,即 $\mathcal{N}_k$ 是从节点 $v_i$ 可以在 k 步内到达节点 $v_j$ 的节点集合。</li><li>深度学习模型:$H^l$ 代表层,$f_l$ 代表 $l$ 层的维度, $\sigma(x)$ 代表激活函数,一般的元素非线性激活函数表示为 $\rho(\cdot)$,$\Theta$ 代表模型的参数,$s$ 代表采样大小。</li></ul><p>在图上深度学习模型的任务可以大致分为两类:</p><ul><li><strong>关注节点的任务</strong>:如节点分类、连接预测和节点推荐</li><li><strong>关注图的任务</strong>:如图分类、图形分类,估计各种图形属性并生成图形</li></ul><h2 id="3-Graph-RNN"><a href="#3-Graph-RNN" class="headerlink" title="3. Graph RNN"></a>3. Graph RNN</h2><p>Graph RNN 可以被分为两类:<strong>node-level RNN</strong> 和 <strong>graph-level RNN</strong></p><p>主要区别在于模式是位于节点级别并由节点状态建模,还是在图级别并由公共图状态建模。 表3总结了所调查方法的主要特征。</p><div align=center><img src="GNN3.PNG"></div><h3 id="3-1-Nodel-level-RNN"><a href="#3-1-Nodel-level-RNN" class="headerlink" title="3.1 Nodel-level RNN"></a>3.1 Nodel-level RNN</h3><p><strong>node-level RNN</strong> 也称为GNN。它的思想很简单:为了编码图结构信息,每个节点 $v_i$ 都由一个低维状态向量 $s_i$ 表示,受RNN启发,Graph RNN定义如下:</p><script type="math/tex; mode=display">s_i=\sum_{j\in\mathcal{N}(i)}\mathcal{F}(s_i,s_j,F_i^V,F_j^V,F_{i,j}^E)\tag{1}</script><p>其中,$\mathcal{F}(\cdot)$ 是一个可学习的参数方程。当得到 $s_i$ 后经过下面函数得到最终的输出:</p><script type="math/tex; mode=display">\hat{y}_i=\mathcal{O}(s_i, F_i^V)\tag{2}</script><p>对于以图为中心的任务,【“The graph neural network model”】的作者建议添加一个具有唯一属性的特殊节点来表示整个图。 为了学习模型参数,采用下面的半监督方法:迭代求解方程(1),使用Jacobi方法到稳定点,使用Almeida-Pineda算法执行一个梯度下降步骤,以最小化特定于任务的目标函数,例如, 回归任务的预测值和真实性;然后,重复此过程,直到收敛为止。</p><p>在等式中使用两个简单方程式(1)和(2),GNN扮演着两个重要角色。回想起来,GNN统一了一些用于处理图数据的早期方法,例如<strong>递归神经网络和马尔可夫链</strong>。展望未来,GNN的基本概念具有深远的启发:正如后面将要展示的,<strong>许多效果最好的的GCNs实际上具有类似于公式(1)的公式,并遵循在直接节点邻域内交换信息的相同框架。 实际上,GNNs和GCNs可以统一为一些通用框架,一个GNN等同于使用相同层来达到稳定状态的GCN</strong>。第4节将提供更多讨论。</p><p>尽管从概念上讲它们很重要,但是GNNs仍然有一些缺点。首先,<strong>要确保公式(1)具有唯一解,$\mathcal{F}(\cdot)$ 必须满足压缩映射</strong> ,即 $\exist\mu, 0<\mu<1$这样</p><script type="math/tex; mode=display">\forall x,y ,||\mathcal{F}(x)-\mathcal{y}||\leq\mu||x-y||\tag{3}</script><p>直观地,<strong>“压缩映射”要求任意两点之间的距离只能在 $\mathcal{F}(\cdot)$ 操作之后“压缩”,这严重限制了建模能力</strong>。其次,由于需要<strong>多次迭代才能在梯度下降步骤之间达到稳定状态,因此GNN的计算量很大</strong>。由于这些缺点以及可能缺乏计算能力(例如,图形处理单元GPU在当时未被广泛用于深度学习)和缺乏研究兴趣,因此GNN并没有成为一般研究的重点。</p><p>GNNs的显著改进是带有以下修改的<strong>门控图序列神经网络(GGS-NNs)</strong>【“Gated graph sequence neural networks”】。最重要的是,作者使用GRU替换了公式中的递归定义,从而消除了“压缩映射”要求并支持现代优化技术。 具体来说,等式(1)修改如下:</p><script type="math/tex; mode=display">s_i^{(t)}=(1-z_i^{(t)})\odot s_i^{(t-1)}+z_i^{(t)}\odot\tilde{s_i}^{(t)}\tag{4}</script><p>其中,$z$ 通过更新门计算,$\tilde{s}$ 是待更新的候选者,$t$ 是伪时间, 其次,作者提议使用在序列上运行几个这样的网络来产生序列输出,并表明它们的方法可以应用于基于序列的任务,例如程序验证。</p><p><strong>SSE</strong>【“Learning steadystates of iterative algorithms over graphs”】采用了与公式(4)相似的方法,在计算时没有使用 GRU ,而是采用随机定点梯度下降法来加快训练过程。该方案基本上是在使用局部邻域计算稳态节点状态与优化模型参数之间进行交替,两种计算都是在随机小批次中进行的。</p><h3 id="3-2-Graph-level-RNN"><a href="#3-2-Graph-level-RNN" class="headerlink" title="3.2 Graph-level RNN"></a>3.2 Graph-level RNN</h3><p>在本小节中,我们回顾了如何应用RNN捕获图级别的模式,例如动态图的时间模式或图粒度不同级别的顺序模式。在图级别的RNN中,对整个图使用RNN来对图的状态编码,而不是对每个节点使用RNN学习节点状态。</p><p><strong>“Graph Rnn:Generating realistic graphs with deep auto-regressive models”</strong> 将Graph RNN应用到图生成问题,这篇文章采用了两个RNN,一个用于生成节点,另外一个用于以自回归的方式生成新加入节点的边。结果发现,这种分层RNN框架相对于传统基于规则的的图生成模型来说从输入图学习效率更高,同时具有合理的时间复杂度。</p><p>为了捕获动态图的时序信息,<strong>动态图神经网络(DGNN)</strong> 被提出,<strong>它使用时间感知的LSTM来学习节点的表示,当建立新的边时,DGNN使用LSTM更新两个交互节点及其直接邻居的表示,即考虑单步传播效应</strong>。 作者表明,具有时间感知能力的LSTM可以很好地模拟边形成的建立顺序和时间间隔,从而有利于一系列图形应用。</p><div align=center><img src="GNN4.PNG"></div><p>Graph RNN也可以和其它框架结合,如<strong>GCNs</strong>或<strong>GAEs</strong>。例如,为了解决图稀疏性问题,<strong>RMGCNN</strong>将LSTM应用于GCN的结果以逐步重建图,如图2所示。通过<strong>使用LSTM,来自图的不同部分的信息可以扩散到图的很大区域,而且不用很多GCN层</strong>。在动态网络中,<strong>Dynamic GCN</strong> 【“Dynamic graph convolutional networks”】应用LSTM来收集不同时间片的GCN结果,以捕获时空图信息。</p><h2 id="4-Graph-Convolutional-Networks"><a href="#4-Graph-Convolutional-Networks" class="headerlink" title="4. Graph Convolutional Networks"></a>4. Graph Convolutional Networks</h2><p>图卷积神经网络(GCNs)在基于图的深度学习来说是最热的一个话题。模仿CNN,现代GCN通过设计的卷积和读出功能来学习图的常见局部和全局结构模式。由于大多数GCN都可以通过反向传播进行特定于任务的损失训练(少数例外),所以我们关注才用的体系结构。我们首先讨论卷积运算,然后转向读取运算和其他一些改进。我们首先讨论卷积运算,然后转向读取运算和其他一些改进。表四总结了GCN的主要特点。</p><div align=center><img src="GNN5.PNG"></div><h3 id="4-1-Convolution-Operations"><a href="#4-1-Convolution-Operations" class="headerlink" title="4.1 Convolution Operations"></a>4.1 Convolution Operations</h3><p>图卷积操作可以被分为两组:<strong>谱域卷积,它通过使用图傅里叶变换将节点的表示转换到谱域执行卷积操作</strong>;和<strong>空域卷积,它通过节点邻域执行卷积操作。注意,这两种可能重合,例如当使用多项式谱核时</strong>。</p><h4 id="4-1-1-Spectral-Methods"><a href="#4-1-1-Spectral-Methods" class="headerlink" title="4.1.1 Spectral Methods"></a>4.1.1 Spectral Methods</h4><p>在卷积神经网络中,卷积操作是最基本的操作。然而,<strong>使用在图像或文本中的标准卷积操作不能被直接应用到图上,因为图缺少网格框架</strong>。“Spectral networks and locally connected networks on graphs”<strong>首先使用拉普拉斯矩阵从谱域对图数据引入了卷积操作,它和在信号处理中的傅里叶变换扮演着相似的角色</strong>。图卷积操作,$*G$,如下定义:</p><script type="math/tex; mode=display">\mathbf{u}_1*G\;\mathbf{u}_2=Q((Q^T \mathbf{u}_1)\odot (Q^T\mathbf{u}_2)\tag{5})</script><p>其中,$\mathbf{u}_1,\mathbf{u}_2$表示定义在节点上的两个信号,$Q$ 是拉普拉斯矩阵的特征向量。简而言之,<strong>$Q^T$ 乘以图信号 $\mathbf{u}_1,\mathbf{u}_2$ 进入光谱域(即图傅立叶变换),同时乘以 $Q$ 进行逆变换</strong>。 此定义的有效性基于卷积定理,即卷积运算的傅立叶变换是其傅立叶变换的逐元素乘积。 然后,信号 $\mathbf{u}$ 可以通过如下公式过滤:</p><script type="math/tex; mode=display">\mathbf{u}^{\prime}=Q\Theta Q^T\mathbf{u}\tag{6}</script><p>其中 $\mathbf{u}^{\prime}$ 是输出信号,$\Theta=\Theta(\Lambda) \in \mathbb{R}^{N \times N}$ 是一个可学习的对角矩阵滤波器, $\Lambda$ 是拉普拉斯矩阵 $L$ 的特征向量,通过将不同的滤波器应用于不同的输入-输出信号对来定义卷积层,如下所示:</p><script type="math/tex; mode=display">\mathbf{u}_j^{l+1}=\rho(\sum_{i=1}^{f_l}Q\Theta_{i,j}^lQ^T\mathbf{u}_i^l)\;j=1,\cdots,f_{l+1}\tag{7}</script><p>其中 $l$ 代表层,$\mathbf{u}_j^l\in\mathbb{R}^N$ 代表在第 $l$ 层的节点的第 $j$ 个隐藏表示,$\Theta_{i,j}^l$ 是可学习的滤波器,公式(7)的思想和传统卷积相似:它使输入信号通过一组可学习的滤波器,以汇总信息,然后进行一些非线性转换。Graph CNN和CNN框架基本相似,使用节点特征 $F^V$ 作为输入层,然后堆叠多个卷积层。理论分析表明,图卷积运算的这种定义可以模仿CNN的某些几何特性,我们请读者参考“Geometric deep learning: going beyond euclidean data”进行全面的调查。</p><p>然而,直接使用公式(7)要求学习 $O(N)$ 的参数,这在实践中可能不可行。此外,光谱域中的滤波器可能不会位于空间域中,此外,频谱域中的滤波器可能不位于空间域中,即,每个节点可能会受到所有其他节点的影响,而不是仅受较小区域中的节点的影响。为了减轻这个问题,“Spectral networks and locally connected networks on graphs”建议使用下面的平滑滤波器:</p><script type="math/tex; mode=display">diag(\Theta_{i,j}^l)=\mathcal{K}\;\alpha_{l.i.j}\tag{8}</script><p>其中 $\mathcal{K}$ 是固定插值内核,$\alpha_{l,i,j}$ 是可学习的插值系数。作者还把这种想法推广到没有给出图而是使用有监督或无监督方法从原始特征构造图形的情况“Deep convolutional networks on graph-structured data”。</p><p>然而,有两个基本问题没有解决。首先,由于每次计算都需要拉普拉斯矩阵的完整特征向量,因此每次向前和向后传播的时间复杂度至少为 $O(N^2)$,更不用说计算特征分解所需的 $O(N^3)$复杂度,这意味着 这种方法无法扩展到大型图形。其次,由于过滤器取决于图的本征基 $Q$,因此无法在具有不同大小和结构的多个图之间共享参数。接下来,我们回顾两个尝试解决这些局限性的工作,然后使用一些通用框架将它们统一起来。</p><h4 id="4-1-2-效率方面"><a href="#4-1-2-效率方面" class="headerlink" title="4.1.2 效率方面"></a>4.1.2 效率方面</h4><p>为了解决效率问题,ChebNet提出使用如下多项式滤波器:</p><script type="math/tex; mode=display">\Theta(\Lambda)=\sum_{k=0}^K\theta_k\Lambda^k\tag{9}</script><p>其中,$\theta_0,\cdots,\theta_K$ 是可学习的参数,$K$ 是多项式阶数,作者使用切比雪夫展开重写了公式(9)代替执行特征分解:</p><script type="math/tex; mode=display">\Theta(\Lambda)=\sum_{k=0}^K\theta_k\mathcal{T}_k(\hat{\Lambda})\tag{10}</script><p>其中,$\hat{\Lambda}=2\Lambda/\lambda_{max}-\mathbf{I}$ 是重新缩放的特征值,$\lambda_{max}$ 是最大特征值,$\mathbf{I}\in\mathbb{R}^{N\times N}$ 单位矩阵,$\mathcal{T}_k(x)$ 是 $k$ 阶的切比雪夫多项式,由于Chebyshev多项式的正交基础,因此重新缩放是必要的。利用拉普拉斯矩阵的多项式作为其特征值的多项式(即$L_k = Q\Lambda^kQ^T$)的事实,在公式(6)中的滤波操作可以被重写为以下公式:</p><script type="math/tex; mode=display">\mathbf{u}^{\prime}=Q\Theta(\Lambda)Q^T\mathbf{u}=\sum_{k=0}^K\theta_kQ\mathcal{T}_k(\tilde{\Lambda})Q^T\mathbf{u}\\=\sum_{k=0}^K\theta_k\mathcal{T}_k(\tilde{L})\mathbf{u}=\sum_{k=0}^K\theta_k\bar{\mathbf{u}}_k\tag{11}</script><p>其中,$\bar{\mathbf{u}}_k=\mathcal{T}_k(\tilde{L})\mathbf{u},\;\tilde{L}=2L/\lambda_{max}-\mathbf{I}$,使用切比雪夫多项式的递推关系 $\mathcal{T}_k(x)=2x\mathcal{T}_{k-1}(x)-\mathcal{T}_{k-2}$ 和 $\mathcal{T}_0(x)=1,\;\mathcal{T}_1(x)=x$,$\bar{\mathbf{u}}_k$ 也可以递归计算:</p><script type="math/tex; mode=display">\bar{\mathbf{u}}_k=2\tilde{L}\bar{\mathbf{u}}_{k-1}-\bar{\mathbf{u}}_{k-2}\tag{12}</script><p>其中,$\bar{\mathbf{u}}_0=\mathbf{u},\;\bar{\mathbf{u}}_1=\tilde{L}\mathbf{u}$。现在,因为仅需要计算稀疏矩阵 $\tilde{L}$ 的矩阵乘法和一些矢量,所以当使用稀疏矩阵乘法时,时间复杂度变为 $O(KM)$,其中 $M,K$ 分别是边的数量和多项式的阶数,即时间复杂度相对于边数是线性的。可以看出,这样的多项式滤波器是严格 $K$ 局部化的:在一次卷积之后,节点 $v_i$ 的表示将仅受其 $K$ 阶领域 $\mathcal{N}_K(i)$。有趣的是,该思想在网络嵌入中被独立使用以保持高阶邻近度。为了简洁,我们省略了细节。</p><p>“Semi-supervised classification with graph convolutional networks”仅使用一阶邻居进一步简化了滤波器:</p><script type="math/tex; mode=display">h_i^{l+1}=\rho\left(\sum_{j\in\tilde{\mathcal{N}}_i}\frac{h_j^l\Theta^l}{\sqrt{\tilde{\mathbf{D}}(i,i)\tilde{\mathbf{D}}(j,j)}}\right)\tag{13}</script><p>其中,$h_i^l\in\mathbb{R}^{f_l}$ 是节点 $v_i$ 在第 $l$ 层的隐藏表示,$\tilde{\mathbf{D}}=\mathbf{D}+\mathbf{I},\;\tilde{\mathcal{N}}(i)=\mathcal{N}(i)\cup\{i\}$,这可以等效地以矩阵形式重写为以下公式:</p><script type="math/tex; mode=display">\mathbf{H}^{l+1}=\rho\left(\tilde{\mathbf{D}}^{-\frac{1}{2}}\tilde{\mathbf{A}}\tilde{\mathbf{D}}^{-\frac{1}{2}}\mathbf{H}^l\Theta^l\right)\tag{14}</script><p>其中,$\tilde{\mathbf{A}}=\mathbf{A}+\mathbf{I}$,即添加自连接,作者通过设置 $K=1$ 这一个细小的改变表明公式(14)是公式(9)的一种特殊形式。然后,作者认为,如图3所示,堆叠足够数量的层具有类似于ChebNet的建模能力,但会带来更好的结果。</p><div align=center><img src="GNN6.PNG"></div><p>ChebNet及其扩展的重要见解是它们将频谱图卷积与空间体系结构联系在一起。具体而言,他们表明,当谱卷积函数是多项式或一阶时,谱图卷积等效于空间卷积。 另外,公式(13)中的卷积与公式(1)中GNN中的状态定义高度相似。只是用卷积定义代替了递归定义。 从这个方面来说,GNN可以看作是具有大量相同层以达到稳定状态的GCN,即GNN使用具有固定参数的固定函数来迭代更新节点的隐藏状态,直到达到平衡为止; 而GCN具有预设的层数,并且每个层包含不同的参数。</p><p>目前已经提出了一些谱方法解决效率问题。例如,不像等式(10)中那样使用切比雪夫展开,CayleyNet [44]采用Cayley多项式定义图卷积:</p><script type="math/tex; mode=display">\Theta(\Lambda)=\theta_{0}+2 R e\left\{\sum_{k=1}^{K} \theta_{k}\left(\theta_{h} \Lambda-i \mathbf{I}\right)^{k}\left(\theta_{h} \Lambda+i \mathbf{I}\right)^{k}\right\}\tag{15}</script><p>其中,$i=\sqrt{-1}$ 表示虚数单位,$\theta$ 是另一个光谱缩放参数。除了证明CayleyNet的效率与ChebNet一样,作者还证明了Cayley多项式可以检测“重要的窄频带”以获得更好的结果。图小波神经网络(GWNN)[45]被进一步提出,通过重写等式,用图小波变换代替频谱滤波器中的傅立叶变换。重写公式(5)如下:</p><script type="math/tex; mode=display">\mathbf{u}_{1} *_{G} \mathbf{u}_{2}=\psi\left(\left(\psi^{-1} \mathbf{u}_{1}\right) \odot\left(\psi^{-1} \mathbf{u}_{2}\right)\right)\tag{16}</script><p>其中 $\psi$ 表示图小波基。 通过使用快速逼近算法进行计算 $\psi$ 和 $\psi^{-1}$加1,<strong>GWNN</strong>的计算复杂度也为 $O(KM)$,即,相对于边数而言是线性的。</p><h4 id="4-1-3-多图方面"><a href="#4-1-3-多图方面" class="headerlink" title="4.1.3 多图方面"></a>4.1.3 多图方面</h4><p>一系列并行的工作着重于将图卷积泛化为任意大小的多个图。 Neural FPs 【“Convolutional networks on graphs for learning molecular fingerprints”】提出了一种也使用一阶邻居的空间方法:</p><script type="math/tex; mode=display">\mathbf{h}_{i}^{l+1}=\sigma\left(\sum_{j \in \hat{\mathcal{N}}(i)} \mathbf{h}_{j}^{l} \Theta^{l}\right)\tag{17}</script><p>因为参数 $\Theta$ 可以在不同的图形之间共享并且与图形大小无关,所以Neural FP可以处理任意大小的多个图形。注意,公式(17)和公式(13)非常相似。Neural FPs 通过对不同度的节点学习不同的参数,而不是通过添加归一化项来考虑节点度的影响。<strong>该策略对于较小的图,例如分子图(即原子作为节点,键作为边)表现良好,但可能无法扩展到更大的图。</strong></p><p>PATCHY-SAN 【“Learning convolutional neural networks for graphs”】 采用了新的想法。它使用诸如Weisfeiler-Lehman内核【“Weisfeiler-lehman graph kernels”】之类的图形标注过程分配了唯一的节点顺序,然后使用此预定义的顺序将节点邻居布置在一条直线上。此外,PATCHY-SAN 还通过从对每个节点的 $K$ 步邻居 $\mathcal{N}_k(i)$ 中选择固定数量的节点来定义了一个接收域。然后采用具有适当归一化的标准一维CNN。使用这种方法,不同图中的节点都具有固定大小和顺序的“接收域”。 因此,PATCHY-SAN可以从多个图形中学习,就像正常的CNN从多个图像中学习一样。缺点是卷积在很大程度上取决于图形标注过程,而图形标注过程是一个尚未学习的预处理步骤。LGCN 【“Large-scale learnable graph convolutional networks”】进一步建议通过按字典顺序简化排序过程(即根据邻居在最后一层 $\mathbf{H}^L$ 中的隐藏表示对邻居进行排序)。作者没有使用一个单一的顺序,而是分别对 $\mathbf{H}^L$ 的不同通道进行了排序。SortPooling 【“An end-to-end deep learning architecture for graph classification”】采取了类似的方法,但作者没有对每个节点的邻居进行排序,而是提议对所有节点进行排序(即,对所有邻域使用单一顺序)。 尽管这些方法之间存在差异,但对于图形来说,强制执行一维节点顺序可能不是自然选择。</p><p>DCNN 【“Diffusion-convolutional neural networks”】采用了另一种方法,即用扩散基础代替了图卷积的本征基础,即节点的邻域由节点之间的扩散转移概率确定。 具体来说,卷积定义如下:</p><script type="math/tex; mode=display">\mathbf{H}^{l+1}=\rho\left(\mathbf{P}^{K} \mathbf{H}^{l} \mathbf{\Theta}^{l}\right)\tag{18}</script><p>其中,$\mathbf{P}^K=(\mathbf{P})^K$ 是长为 $K$ 的扩散过程(即随机游走)的转移概率,$K$ 是预设的扩散长度,$\Theta^l$ 是可学习参数。因为只有 $\mathbf{P}^K$ 依赖于图结构,参数 $\theta^l$ 可以在任意大小的图之间共享,然而计算 $\mathbf{P}^K$ 的时间复杂度是 $O(N^2K)$;因此该方法无法扩展到大图。</p><p>DGCN 【“Dual graph convolutional networks for graphbased semi-supervised classification”】进一步提出了使用对偶图卷积网络联合采用扩散和邻接基础。 具体地说,DGCN使用了两个卷积:一个是等式(14),另一个用转移概率的正点想互信息(PPMI)矩阵【“Neural word embedding as implicit matrix factorization,”】替换了邻接矩阵,如下所示:</p><script type="math/tex; mode=display">\mathbf{Z}^{l+1}=\rho\left(\mathbf{D}_{P}^{-\frac{1}{2}} \mathbf{X}_{P} \mathbf{D}_{P}^{-\frac{1}{2}} \mathbf{Z}^{l} \mathbf{\Theta}^{l}\right)\tag{19}</script><p>其中,$\mathbf{X}_P$ 是正点互信息(PPMI)矩阵,按如下公式计算:</p><script type="math/tex; mode=display">\mathbf{X}_{P}(i, j)=\max \left(\log \left(\frac{\mathbf{P}(i, j) \sum_{i; j} \mathbf{P}(i, j)}{\sum_{i} \mathbf{P}(i, j) \sum_{j} \mathbf{P}(i, j)}\right), 0\right)\tag{20}</script><p>其中,$\mathbf{D}_P(i,j)=\sum_j\mathbf{X}_P(i,j)$ 是 $\mathbf{X}_P$ 的对角度矩阵。然后,通过最小化 $\mathbf{H}$ 和 $\mathbf{Z}$ 之间的均方差来合并这两个卷积。DGCN采用随机游走采样技术来加快转移概率的计算。 实验表明,这种双重卷积甚至对于单图问题也是有效的。</p><h4 id="4-1-4-框架"><a href="#4-1-4-框架" class="headerlink" title="4.1.4 框架"></a>4.1.4 框架</h4><p>基于以上两点工作,提出了MPNN 【“Neural message passing for quantum chemistry”】作为使用消息传递函数的空间域图卷积操作的统一框架:</p><script type="math/tex; mode=display">\begin{array}{c}\mathbf{m}_{i}^{l+1}=\sum_{j \in \mathcal{N}(i)} \mathcal{F}^{l}\left(\mathbf{h}_{i}^{l}, \mathbf{h}_{j}^{l}, \mathbf{F}_{i, j}^{E}\right) \\\mathbf{h}_{i}^{l+1}=\mathcal{G}^{l}\left(\mathbf{h}_{i}^{l}, \mathbf{m}_{i}^{l+1}\right)\end{array}\tag{21}</script><p>其中,$\mathcal{F}^l(\cdot),\;\mathcal{G}^l(\cdot)$ 分别表示要学习的消息函数和节点更新函数,$\mathbf{m}^l$ 代表两个节点间传递的信息。从概念上讲,MPNNs是一个框架,在该框架中,每个节点都根据其状态发送消息,并根据从直接邻居收到的消息来更新其状态。 作者表明,上述框架已经包括了许多现有方法,例如GGSNNs 【“Gated graph sequence neural networks”】,Bruna等 【““Spectral networks and locally connected networks on graphs”】,Henaff等 【“Deep convolutional networks on graph-structured data”】,Neural FPs 【“Convolutional networks on graphs for learning molecular fingerprints”】,Kipf和Welling 【“Semi-supervised classification with graph convolutional networks”】和Kearnes等 【“Molecular graph convolutions: moving beyond fingerprints”】作为特殊情况。 此外,作者建议添加一个“主”节点,该节点连接到所有节点以加速长距离消息传递,并且他们将隐藏的表示形式拆分为不同的“塔”以提高泛化能力。 作者表明,MPNNs的特定变体可以在预测分子特性方面达到最先进的性能。</p><p>同时,GraphSAGE 【“Inductive representation learning on large graphs”】提出了与公式(21)类似的想法,使用多个聚合函数,如下所示:</p><script type="math/tex; mode=display">\begin{array}{c}\mathbf{m}_{i}^{l+1}= \text { AGGREGATE }^{l}\left(\left\{\mathbf{h}_{j}^{l}, \forall j \in \mathcal{N}(i)\right\}\right)\\\mathbf{h}_{i}^{l+1}=\rho\left(\mathbf{\Theta}^{l}\left[\mathbf{h}_{i}^{l}, \mathbf{m}_{i}^{l+1}\right]\right)\end{array}\tag{22}</script><p>其中,$[\cdot,\cdot]$ 表示级联操作,$\text{AGGREGATE}(\cdot)$ 表示聚合函数。作者推荐了三个聚合函数:按元素的均值,LSTM和最大池化如下:</p><script type="math/tex; mode=display">\text { AGGREGATE }^{l}=\max \left\{\rho\left(\Theta_{\text {pool }} \mathbf{h}_{j}^{l}+\mathbf{b}_{\text {pool }}\right), \forall j \in \mathcal{N}(i)\right\}\tag{23}</script><p>其中,$\Theta_{pool},\;\mathbf{b}_{pool}$ 是要学习的参数,$\max\{\cdot\}$ 是逐元素取最大值。对于 LSTM 聚合函数,因为需要对邻居排序,作者才用了随机排序。</p><p>混合模型网络(MoNet)【“Geometric deep learning on graphs and manifolds using mixture model cnns”】还尝试使用“模板匹配”将现有的GCN模型以及用于歧管的CNN统一到一个通用框架中:</p><script type="math/tex; mode=display">h_{i k}^{l+1}=\sum_{j \in \mathcal{N}(i)} \mathcal{F}_{k}^{l}(\mathbf{u}(i, j)) \mathbf{h}_{j}^{l}, k=1, \ldots, f_{l+1}\tag{24}</script><p>其中,$\mathbf{u}(i,j)$ 是节点对 $(v_i,v_j)$ 的伪坐标,$\mathcal{F}_k^l(\mathbf{u})$ 是要学习的参数函数,$h_{ik}^l$ 是 $h_i^l$ 的第 $k$ 维,换句话说,$\mathcal{F}_k^l(\mathbf{u})$ 用作组合领域的加权内核。然后,MoNet采用了以下高斯内核:</p><script type="math/tex; mode=display">\mathcal{F}_{k}^{l}(\mathbf{u})=\exp \left(-\frac{1}{2}\left(\mathbf{u}-\boldsymbol{\mu}_{k}^{l}\right)^{T}\left(\boldsymbol{\Sigma}_{k}^{l}\right)^{-1}\left(\mathbf{u}-\boldsymbol{\mu}_{k}^{l}\right)\right)\tag{25}</script><p>其中,$\mu_k^l,\;\sum_k^l$ 分别是均值向量和对角协方差矩阵。伪坐标是度数,如Kipf和Welling 【“Semi-supervised classification with graph convolutional networks”】,即</p><script type="math/tex; mode=display">\mathbf{u}(i, j)=\left(\frac{1}{\sqrt{\mathbf{D}(i, i)}}, \frac{1}{\sqrt{\mathbf{D}(j, j)}}\right)\tag{26}</script><p>图网络(GNs)【“Relational inductive biases, deep learning, and graph networks”】为GCN和GNN提出了一个更通用的框架,该框架学习了三组表示:$\mathbf{h}_i^l,\mathbf{e}_{ij}^l,\mathbf{z}^l$ 分别表示节点,边和整个图。 这些表示是使用三个聚合函数和三个更新函数来学习的:</p><script type="math/tex; mode=display">\begin{array}{c}\mathbf{m}_{i}^{l}=\mathcal{G}^{E \rightarrow V}\left(\left\{\mathbf{e}_{i j}^{l}, \forall j \in \mathcal{N}(i)\right\}\right), \mathbf{m}_{V}^{l}=\mathcal{G}^{V \rightarrow G}\left(\left\{\mathbf{h}_{i}^{l}, \forall v_{i} \in V\right\}\right) \\\mathbf{m}_{E}^{l}=\mathcal{G}^{E \rightarrow G}\left(\left\{\mathbf{e}_{i j}^{l}, \forall\left(v_{i}, v_{j}\right) \in E\right\}\right), \mathbf{h}_{i}^{l+1}=\mathcal{F}^{V}\left(\mathbf{m}_{i}^{l}, \mathbf{h}_{i}^{l}, \mathbf{z}^{l}\right) \\\mathbf{e}_{i j}^{l+1}=\mathcal{F}^{E}\left(\mathbf{e}_{i j}^{l}, \mathbf{h}_{i}^{l}, \mathbf{h}_{j}^{l}, \mathbf{z}^{l}\right), \mathbf{z}^{l+1}=\mathcal{F}^{G}\left(\mathbf{m}_{E}^{l}, \mathbf{m}_{V}^{l}, \mathbf{z}^{l}\right)\end{array}\tag{27}</script><p>其中,$\mathcal{F}^V(\cdot),\mathcal{F}^E(\cdot),\mathcal{F}^G(\cdot)$ 是节点、边和整个图的更新函数,$\mathcal{G}(\cdot)$ 表示消息传递函数,它的上标代表消息传递方向。注意,消息传递函数都以集合作为输入,因此它们的参数的长度是可变的,因此这些函数对于输入排列应该是不变的。一些示例包括按元素求和,均值和最大值。与MPNNs相比,GNs引入了边表示和整个图形的表示,从而使框架更加通用。</p><p>总而言之,卷积运算已从频谱域发展到空间域,并从多步邻居发展到直接邻居。目前,正在从直接邻居那里收集信息(如等式(14))并遵循等式(21)(22)(27)的框架,是图卷积运算的最常见选择。</p><h3 id="4-2-Readout-OPeration"><a href="#4-2-Readout-OPeration" class="headerlink" title="4.2 Readout OPeration"></a>4.2 Readout OPeration</h3><p>使用图卷积运算,可以学习有用的节点特征来解决许多以节点为中心的任务。但是,为了处理以图形为中心的任务,需要将节点信息进行汇总以形成图形级别的表示。 在文献中,这种程序通常称为<strong>读出操作</strong>。基于常规和本地邻域,标准CNN会进行多次跨步卷积或池化以逐渐降低分辨率。 由于图形缺乏网格结构,因此这些现有方法无法直接使用。</p><p><strong>阶数不变</strong>:图读取操作的关键要求是该操作应不依赖于节点顺序,即,如果我们使用两个节点集之间的双射函数来更改节点和边的索引,则整个图的表示不应更改。 例如,一种药物是否可以治疗某些疾病取决于其固有结构。 因此,如果我们使用不同的节点索引表示药物,我们应该得到相同的结果。 注意,因为这个问题与图同构问题有关,其中最著名的算法是拟多项式判【“Graph isomorphism in quasipolynomial time”】,所以我们只能找到在多项式时间内阶不变的函数,反之亦然,即两个结构不同的函数 图可能具有相同的表示形式。</p><h4 id="4-2-1-统计"><a href="#4-2-1-统计" class="headerlink" title="4.2.1 统计"></a>4.2.1 统计</h4><p>最基本的阶数不变运算涉及简单的统计信息,例如求和,求平均值或最大池化【“Convolutional networks on graphs for learning molecular fingerprints”】,【“Diffusion-convolutional neural networks”】,即</p><script type="math/tex; mode=display">\mathbf{h}_{G}=\sum_{i=1}^{N} \mathbf{h}_{i}^{L} \text { or } \mathbf{h}_{G}=\frac{1}{N} \sum_{i=1}^{N} \mathbf{h}_{i}^{L} \text { or } \mathbf{h}_{G}=\max \left\{\mathbf{h}_{i}^{L}, \forall i\right\}\tag{28}</script><p>其中,$\mathbf{h}_{G}$ 是图 $G$ 的表示,$h_i^L$ 表示节点 $v_i$ 在最后一层 $L$ 的表示.但是,这样的第一刻统计数据可能不足以代表不同的图。</p><p>【“Molecular graph convolutions: moving beyond fingerprints”】建议使用模糊直方图考虑节点表示的分布【“Fuzzy sets and fuzzy logic”】。 模糊直方图背后的基本思想是构造几个“直方图箱”,然后计算 $h_i^L$ 到这些箱子的隶属度,即通过将节点表示视为样本并将它们与一些预定义的模板进行匹配,最后返回最终直方图的级联。 以这种方式,可以区分具有相同的总和/平均/最大但具有不同分布的节点。</p><p>聚合节点表示的另一种常用方法是添加一个完全连接的(FC)层作为最终层【“Spectral networks and locally connected networks on graphs,”】,即</p><script type="math/tex; mode=display">\mathbf{h}_{G}=\rho\left(\left[\mathbf{H}^{L}\right] \boldsymbol{\Theta}_{F C}\right)\tag{29}</script><p>其中,$[\mathbf{H}^L]\in\mathbb{R}^{Nf_l}$ 是最终节点表示 $\mathbf{H}^L$ 的级联,$\Theta_{FC}\in\mathbb{R}^{Nf_l\times f_{output}}$ 是参数,且 $f_{output}$ 是输出的维度,公式(29)可以看做节点级特征的加权和。一个优点就是可以对不同的节点学习不同的权重值;但是,此功能是以无法保证阶数不变为代价的。</p><h4 id="4-2-2-层次聚类"><a href="#4-2-2-层次聚类" class="headerlink" title="4.2.2 层次聚类"></a>4.2.2 层次聚类</h4><p>众所周知,图显示出丰富的层次结构,而不是节点和图的层次结构之间的二分法【“Hierarchical taxonomy aware network embedding”】,可以通过图4所示的层次聚类方法进行探索。</p><div align=center><img src=".\Deep-Learning-on-Graphs-A-Survey\GNN7.png"></div><br>例如,在Bruna等人【“Spectral networks and locally connected networks on graphs”】中使用了基于密度的聚集聚类【“The elements of statistical learning: Data mining, inference, and prediction”】和在Henaff等【“Deep convolutional networks on graph-structured data”】中使用的多分辨率光谱聚类【“A tutorial on spectral clustering”】。ChebNet 【“Convolutional neural networks on graphs with fast localized spectral filtering”】和MoNet 【“Geometric deep learning on graphs and manifolds using mixture model cnns”】采用了另一种贪婪的层次聚类算法Graclus 【“Weighted graph cuts without eigenvectors a multilevel approach”】来一次合并两个节点,并采用快速池化方法将节点重新排列为平衡的二叉树。ECC 【“Dynamic edgeconditioned filters in convolutional neural networks on graphs”】通过执行特征分解【““A multiscale pyramid transform for graph signals”】采用了另一种层次聚类方法。 但是,这些分层聚类方法都与图卷积无关(即,它们可以作为预处理步骤执行,并且不能以端到端的方式进行训练)。为了解决这个问题,DiffPool 【“Hierarchical graph representation learning with differentiable pooling”】提出了一种与图卷积联合训练的可微层次聚类算法。 具体来说,作者建议使用如下公式在每一层中学习软聚类分配矩阵隐藏表示法在,如下所示:$$\mathbf{S}^{l}=\mathcal{F}\left(\mathbf{A}^{l}, \mathbf{H}^{l}\right)\tag{30}$$其中,$\mathbf{S}^l\in\mathbb{R}^{N_l\times N_{l+1}}$ 是聚类分配矩阵,$N_l$ 是 $l$ 层的簇数,$\mathcal{F}(\cdot)$ 是要学习的函数。然后,可以通过根据 $S^1$ 取平均值来获得此“粗化”图的节点表示和新的邻接矩阵:$$\mathbf{H}^{l+1}=\left(\mathbf{S}^{l}\right)^{T} \hat{\mathbf{H}}^{l+1}, \mathbf{A}^{l+1}=\left(\mathbf{S}^{l}\right)^{T} \mathbf{A}^{l} \mathbf{S}^{l}\tag{31}$$其中,$\hat{\mathbf{H}}^{l+1}$ 是通过 $\mathbf{H}^l$ 经过一次图卷积后得到的,即,在卷积操作之后,将图从每层中的 $N^1$ 个节点粗化到 $N^{1 + 1}$ 个节点。 节点的初始数量为 $N_0 = N$,最后一层为 $N_L = 1$,即代表整个图的单个节点。 因为聚类分配操作很软,所以集群之间的连接并不稀疏。#### 4.2.3 Imposing Orders and Others如第4.1.3节所述,PATCHY-SAN 【“Learning convolutional neural networks for graphs”】和SortPooling 【““An end-to-end deep learning architecture for graph classification”】提出了施加节点顺序的想法,然后像CNN一样诉诸于标准1-D池化。 这些方法是否可以保留顺序不变性取决于顺序的施加方式,这是我们向读者推荐的另一研究领域【“Practical graph isomorphism”】。 但是,是否强加节点顺序是图形的自然选择,如果这样,那么构成最佳节点顺序的问题仍在进行中。除上述方法外,还有一些启发式方法。 在GNN中【“The graph neural network model”】,作者建议添加一个连接到所有节点的特殊节点以表示整个图。 同样,GNs 【“Relational inductive biases, deep learning, and graph networks”】提出通过从所有节点和边接收消息来直接学习整个图的表示。MPNNs采用set2set 【“Order matters: Sequence to sequence for sets”】,这是对seq2seq模型的修改。 具体而言,set2set使用“读取-处理-写入”模型,该模型同时接收所有输入,使用注意机制和LSTM计算内部存储器,然后写入输出。 与seq2seq是顺序敏感的不同,set2set对于输入顺序是不变的。#### 4.2.4 Summary简而言之,诸如平均或求和之类的统计信息是最简单的读出操作,而通过图卷积联合训练的层次聚类算法更先进,但也更加复杂。 还研究了其他方法,例如添加伪节点或强加节点顺序。### 4.3 Improvements and Discussions已经引入了许多技术来进一步改善GCN。 请注意,其中一些方法是通用的,也可以应用于图上的其他深度学习模型。#### 4.3.1 Attention Mechanism在上述GCN中,节点邻域以相等或预定义的权重进行聚合。 但是,邻居的影响可能相差很大。 因此,应该在训练过程中学习它们,而不是预先确定。 受注意力机制【“Attention is all you need”】的启发,图注意力网络(GAT)【“Graph attention networks”】通过修改公式(13)中的卷积运算将注意力机制引入了GCN如下:$$\mathbf{h}_{i}^{l+1}=\rho\left(\sum_{j \in \hat{\mathcal{N}}(i)} \alpha_{i j}^{l} \mathbf{h}_{j}^{l} \mathbf{\Theta}^{l}\right)\tag{32}$$其中,$\alpha_{i,j}^l$ 是在第 $l$ 层节点 $v_i$ 到节点 $v_j$ 的注意力:$$\alpha_{i j}^{l}=\frac{\exp \left(\text { LeakyReLU }\left(\mathcal{F}\left(\mathbf{h}_{i}^{l} \mathbf{\Theta}^{l}, \mathbf{h}_{j}^{l} \Theta^{l}\right)\right)\right)}{\sum_{k \in \mathcal{N}(i)} \exp \left(\text { LeakyReLU }\left(\mathcal{F}\left(\mathbf{h}_{i}^{l} \mathbf{\Theta}^{l}, \mathbf{h}_{k}^{l} \Theta^{l}\right)\right)\right)}\tag{33}$$其中,$\mathcal{F}(\cdot)$ 是一个像多层感知机那样要学习的函数。为了提高模型的容量和稳定性,作者还建议使用多个独立注意力并将其结果进行合并,即,如图5所示的多头注意力机制【“Attention is all you need”】。GaAN【“Gaan: Gated attention networks for learning on large and spatiotemporal graphs”】进一步建议针对不同的头和头学习不同的权重。 将这种方法应用于交通预测问题。<div align=center><img src="GNN8.png"/></div><p>HAN 【“Heterogeneous graph attention network”】提出了一种针对异构图的两级关注机制,即节点级和语义级的关注机制。 具体来说,节点级别的关注机制与GAT类似,但也考虑了节点类型。 因此,它可以分配不同的权重来聚合基于元路径的邻居。 然后,语义层面的注意了解了不同元路径的重要性,并输出了最终结果。</p><h4 id="4-3-2-Residual-and-Jumping-Connections"><a href="#4-3-2-Residual-and-Jumping-Connections" class="headerlink" title="4.3.2 Residual and Jumping Connections"></a>4.3.2 Residual and Jumping Connections</h4><p>许多研究已经观察到,现有GCN的最合适深度通常非常有限,例如2或3层。 这个问题可能是由于训练深层GCN时遇到的实际困难或过度平滑的问题所致,即,深层中的所有节点都具有相同的表示形式【“Representation learning on graphs with jumping knowledge networks”】,【“Deeper insights into graph convolutional networks for semi-supervised learning”】。 为了解决这个问题,可以将类似于ResNet 【“Deep residual learning for image recognition”】的剩余连接添加到GCN。 例如,Kipf和Welling 【“Semi-supervised classification with graph convolutional networks”】在公式(14)中增加了剩余的连接如下:</p><script type="math/tex; mode=display">\mathbf{H}^{l+1}=\rho\left(\tilde{\mathbf{D}}^{-\frac{1}{2}} \tilde{\mathbf{A}} \tilde{\mathbf{D}}^{-\frac{1}{2}} \mathbf{H}^{l} \mathbf{\Theta}^{l}\right)+\mathbf{H}^{l}\tag{34}</script><p>他们通过实验表明,添加此类残差连接可以使网络深度增加,这与ResNet的结果类似。</p><p>列网络(CLN)【““Column networks for collective classification”】通过使用以下具有可学习权重的残差连接采用了类似的思想:</p><script type="math/tex; mode=display">\mathbf{h}_{i}^{l+1}=\boldsymbol{\alpha}_{i}^{l} \odot \widetilde{\mathbf{h}}_{i}^{l+1}+\left(1-\boldsymbol{\alpha}_{i}^{l}\right) \odot \mathbf{h}_{i}^{l}\tag{35}</script><script type="math/tex; mode=display">\alpha_i^l=\rho\left(\mathbf{b}_{\alpha}^l+\Theta_{\alpha}^lh_i^l+\Theta_{\alpha}^{\prime l}\sum_{j\in\mathcal{N}(i)}\mathbf{h}_j^l\right)\tag{36}</script><p>其中,$\mathbf{b}_{\alpha}^l,\Theta_{\alpha}^l,\Theta_{\alpha}^{\prime l}$ 是参数。注意,公式(34)和在GGS-NNs中的GRU相似。不同之处在于,CLN中的上标代表层数,并且不同的层包含不同的参数;而GGS-NNs中的上标代表伪时间和在时间步中使用的一个参数集合。</p><p>受到个性化PageRank的启发,PPNP 【“Predict then propagate: Graph neural networks meet personalized pagerank”】定义了通过隐形传送到初始层的图卷积:</p><script type="math/tex; mode=display">\mathbf{H}^{l+1}=(1-\alpha) \tilde{\mathbf{D}}^{-\frac{1}{2}} \tilde{\mathbf{A}} \tilde{\mathbf{D}}^{-\frac{1}{2}} \mathbf{H}^{l}+\alpha \mathbf{H}^{0}\tag{37}</script><p>其中,$\mathbf{H}_0=\mathcal{F}(\mathbf{F}^V),\alpha$ 是超参数。注意,所有参数在 $\mathcal{F}_{\theta}(\cdot)$,而不是在图卷积中。</p><div align=center><img src="GNN9.png"/></div><p>跳跃式知识网络(JK-Nets)[62]提出了另一种体系结构,以将网络的最后一层与所有较低的隐藏层相连,即,通过将所有表示“跳跃”到最终输出,如图6所示。 这样,模型可以学习选择性地利用来自不同层的信息。 JK-Nets的正式表述如下:</p><script type="math/tex; mode=display">\mathbf{h}_{i}^{\text {final }}=\operatorname{AGGREGATE}\left(\mathbf{h}_{i}^{0}, \mathbf{h}_{i}^{1}, \ldots, \mathbf{h}_{i}^{L}\right)</script><p>其中,$\mathbf{h}_{i}^{\text {final }}$ 是节点 $v_i$ 的最终表示,$\operatorname{AGGREGATE}(\cdot)$ 是聚合函数,$L$ 是隐藏层的层数。JK-Nets使用了三个类似于GraphSAGE 【“Inductive representation learning on large graphs”】的聚合函数:级联,最大池化和LSTM注意。 实验结果表明,添加跳转连接可以提高多个GCN的性能。</p><h4 id="4-3-3-Edge-Features"><a href="#4-3-3-Edge-Features" class="headerlink" title="4.3.3 Edge Features"></a>4.3.3 Edge Features</h4><p>前面提到的GCN大多集中在利用节点特征和图结构上。 在本小节中,我们简要讨论如何使用另一个重要的信息源:边特征。</p><p>对于具有离散值(例如边类型)的简单边特征,一种直接的方法是为不同的边类型训练不同的参数并汇总结果。 例如,Neural FPs 【“Convolutional networks on graphs for learning molecular fingerprints”】为不同度的节点训练了不同的参数,这对应于分子图中键类型的隐式边特征,然后对结果求和。 CLN 【“Column networks for collective classification”】在异构图中为不同的边类型训练了不同的参数,并对结果取平均值。 边条件卷积(ECC)【“Dynamic edgeconditioned filters in convolutional neural networks on graphs”】还基于边类型训练了不同的参数,并将其应用于图形分类。 关系GCN(R-GCN)【“Modeling relational data with graph convolutional networks”】通过为不同的关系类型训练不同的权重,对知识图采用了类似的想法。 但是,这些方法仅适用于有限数量的离散边特征。</p><p>DCNN 【“Diffusion-convolutional neural networks”】提出了另一种将每个边转换为连接到该边的头尾节点的节点的方法。进行此转换后,可以将边要素视为节点要素。</p><p>LGCN 【“Supervised community detection with line graph neural networks”】构造了一个折线图 $\mathbf{B}\in\mathbb{R}^{2M\times 2M}$,以合并边特征,如下所示:</p><script type="math/tex; mode=display">\mathbf{B}_{i \rightarrow j, i^{\prime} \rightarrow j^{\prime}}=\left\{\begin{array}{ll}1 & \text { if } j=i^{\prime} \text { and } j^{\prime} \neq i \\0 & \text { otherwise }\end{array}\right.\tag{39}</script><p>换句话说,折线图中的节点是原始图中的有向边,如果信息可以流过折线图中的相应边,则折线图中的两个节点是连接的。 然后,LGCN采用了两个GCN:一个位于原始图上,另一个位于线图上。</p><p>Kearnes等【“Molecular graph convolutions: moving beyond fingerprints”】提出了一种使用“编织模块”的架构。 具体来说,他们学习了节点和边的表示形式,并使用四个不同的功能在每个编织模块中交换了它们之间的信息:节点到节点(NN),节点到边(NE),边到边(EE)和边到节点(EN):</p><script type="math/tex; mode=display">\begin{array}{l}\mathbf{h}_{i}^{l^{\prime}}=\mathcal{F}_{N N}\left(\mathbf{h}_{i}^{0}, \mathbf{h}_{i}^{1}, \ldots, \mathbf{h}_{i}^{l}\right), \mathbf{h}_{i}^{l^{\prime \prime}}=\mathcal{F}_{E N}\left(\left\{\mathbf{e}_{i j}^{l} | j \in \mathcal{N}(i)\right\}\right) \\\mathbf{e}_{i j}^{l^{\prime}}=\mathcal{F}_{E E}\left(\mathbf{e}_{i j}^{0}, \mathbf{e}_{i j}^{1}, \ldots, \mathbf{e}_{i j}^{l}\right), \mathbf{e}_{i j}^{l^{\prime \prime}}=\mathcal{F}_{N E}\left(\mathbf{h}_{i}^{l}, \mathbf{h}_{j}^{l}\right) \\\mathbf{h}_{i}^{l+1}=\mathcal{F}_{N N}\left(\mathbf{h}_{i}^{l^{\prime}}, \mathbf{h}_{i}^{l^{\prime \prime}}\right), \mathbf{e}_{i j}^{l+1}=\mathcal{F}_{E E}\left(\mathbf{e}_{i j}^{l^{\prime}}, \mathbf{e}_{i j}^{l^{\prime \prime}}\right)\end{array}\tag{40}</script><p>其中,$e_{ij}^l$ 是第 $l$ 层边 $(v_i,v_j)$ 的表示,$\mathcal{F}(\cdot)$ 是可学习的函数,它的下标表示信息传递方向。通过堆叠多个这样的模块,信息可以通过在节点和边表示之间交替传递来传递。注意,在节点到节点和边到边函数中,隐式添加了与JK-Nets 【“Representation learning on graphs with jumping knowledge networks”】中相似的跳转连接。GNs 【“Relational inductive biases, deep learning, and graph networks”】还提出了学习边表示并使用消息传递功能更新节点和边表示的方法,如公式(27)所示。在这方面,“编织模块”是GNs的特殊情况,并不代表整个图。</p><h4 id="4-3-4-Sampling-Methods"><a href="#4-3-4-Sampling-Methods" class="headerlink" title="4.3.4 Sampling Methods"></a>4.3.4 Sampling Methods</h4><p>为大型图训练GCN时,关键的瓶颈之一是效率。 如第4.1.4节所示,许多GCN遵循邻域聚合方案。 但是,由于许多实图遵循幂律分布【““Emergence of scaling in random networks”】(即,几个节点的度数非常大),因此邻居数可以非常快速地扩展。 为了解决这个问题,已经提出了两种类型的采样方法:邻域采样和逐层采样,如图7所示。</p><div align=center><img src="GNN10.png"/></div><p>在邻域采样中,在计算期间对每个节点执行采样。 GraphSAGE 【“Inductive representation learning on large graphs”】在训练期间为每个节点统一采样了固定数量的邻居。 PinSage 【“Graph convolutional neural networks for web-scale recommender systems”】提出了在图形上使用随机游走对邻居进行采样以及一些实现方面的改进,包括CPU和GPU之间的协调,map reduce,pipline等。 PinSage被证明能够处理真实的十亿比例的图形。 StochasticGCN 【“Stochastic training of graph convolutional networks with variance reduction”】进一步建议通过使用最后一批的历史激活作为控制变量来减少采样方差,从而在理论上保证任意小样本量。</p><p>FastGCN 【“Fastgcn: fast learning with graph convolutional networks via importance sampling”】没有对节点的邻居进行采样,而是采用了不同的策略:它通过将节点解释为i.i.d.来在每个卷积层中对节点进行采样(即逐层采样)。样本和图卷积作为概率测度下的积分变换。FastGCN还显示,通过节点的归一化程度可以减少方差并提高性能。 使【“Adaptive sampling towards fast graph representation learning”】进一步建议的采样节点位于以顶层为条件的较低层; 这种方法更具适应性,适用于显着减少方差。</p><h4 id="4-3-5-Inductive-Setting"><a href="#4-3-5-Inductive-Setting" class="headerlink" title="4.3.5 Inductive Setting"></a>4.3.5 Inductive Setting</h4><p>GCN的另一个重要方面是它们是否可以应用于归纳设置,即在一组节点或图上进行训练,并在另一组没见过的节点或图上进行测试。 原则上,此目标是通过在不依赖于图的基础上学习给定特征的映射函数来实现的,并且可以跨节点或图进行传递。 归纳设置在GraphSAGE 【“Inductive representation learning on large graphs”】,GAT 【“Graph attention networks”】,GaAN 【“Gaan: Gated attention networks for learning on large and spatiotemporal graphs”】和FastGCN 【“Fastgcn: fast learning with graph convolutional networks via importance sampling”】中得到了验证。 但是,现有的归纳GCN仅适用于具有显式特征的图。 如何对没有显着特征的图进行归纳学习,通常被称为样本外问题【“Depthlgp: Learning embeddings of out-ofsample nodes in dynamic networks”】,在文献中仍处于很大程度上开放的状态。</p><h4 id="4-3-6-Theoretical-Analysis"><a href="#4-3-6-Theoretical-Analysis" class="headerlink" title="4.3.6 Theoretical Analysis"></a>4.3.6 Theoretical Analysis</h4><p>为了了解GCN的有效性,已提出了一些理论分析,这些理论分析可分为三类:以节点为中心的任务,以图为中心的任务和常规分析。</p><p>对于以节点为中心的任务,Li等人【“Deeper insights into graph convolutional networks for semi-supervised learning”】首先通过使用一种特殊的拉普拉斯平滑法来分析GCN的性能,这使得同一簇中节点的特征相似。 原始拉普拉斯平滑操作的公式如下:</p><script type="math/tex; mode=display">\mathbf{h}_{i}^{\prime}=(1-\gamma) \mathbf{h}_{i}+\gamma \sum_{j \in \mathcal{N}(i)} \frac{1}{d_{i}} \mathbf{h}_{j}\tag{41}</script><p>其中,$\mathbf{h}_i,\mathbf{h}_i^{\prime}$ 是节点 $v_i$ 的原始特征和平滑特征。我们可以看到公式(41)和图卷积公式(13)非常相似。基于这种见解,Li等还提出了GCN的共同训练和自我训练方法。</p><p>最近,Wu等【“Simplifying graph convolutional networks”】从信号处理的角度分析了GCN。通过将节点特征视为图形信号,他们表明等式(13)基本上是一个固定的低通滤波器。利用这一见解,他们通过消除所有非线性并将学习参数折叠为一个矩阵,提出了一种极为简化的图卷积(SGC)架构:</p><script type="math/tex; mode=display">\mathbf{H}^{L}=\left(\tilde{\mathbf{D}}^{-\frac{1}{2}} \tilde{\mathbf{A}} \tilde{\mathbf{D}}^{-\frac{1}{2}}\right)^{L} \mathbf{F}_{V} \mathbf{\Theta}\tag{42}</script><p>作者表明,这种“非深度学习” GCN变体在许多任务上都可以与现有GCN媲美。 Maehara 【“Revisiting graph neural networks”】通过显示低通滤波操作并没有为GCN配备非线性流形学习能力来增强此结果,并进一步提出了GFNN模型来解决此问题,方法是在图卷积层之后添加MLP。</p><p>对于以图形为中心的任务,Kipf和Welling【“Semi-supervised classification with graph convolutional networks”】以及SortPooling【“An end-to-end deep learning architecture for graph classification,”】的作者都考虑了GCN与图形内核(例如Weisfeiler-Lehman(WL)内核【“Weisfeiler-lehman graph kernels”】)之间的关系,该关系已广泛用于图形同构测试中。他们表明,GCN从概念上讲是WL内核的概括,因为这两种方法都会迭代地聚合来自节点邻居的信息。 Xu等【“How powerful are graph neural networks?”】通过证明WL内核在区分图结构方面为GCN提供了上限,从而使这一思想形式化。基于此分析,他们提出了图形同构网络(GIN),并表明使用求和和MLP的读出操作可以实现可证明的最大判别力,即在图形分类任务中具有最高的训练精度。</p><p>对于一般分析,Scarselli等【“The vapnik– chervonenkis dimension of graph and recursive neural networks”】表明,具有不同激活函数的GCN的Vapnik-Chervonenkis维度(VC-dim)具有与现有RNN相同的规模。 Chen等【“Supervised community detection with line graph neural networks”】分析了线性GCN的优化情况,并表明在某些简化下,任何局部最小值都相对接近于全局最小值。 Verma和Zhang【“Stability and generalization of graph convolutional neural networks”】分析了GCN的算法稳定性和泛化边界。 他们表明,如果图卷积滤波器的最大绝对特征值与图大小无关,则单层GCN会满足强烈的均匀稳定性概念。</p><h2 id="5-Graph-Autoencoder"><a href="#5-Graph-Autoencoder" class="headerlink" title="5. Graph Autoencoder"></a>5. Graph Autoencoder</h2><p><strong>自动编码机(AE)和它的变体已经被广泛应用于无监督学习任务,并且适合学习图节点的表示</strong>。隐含的假设是,图具有固有的,潜在的非线性低秩结构。在本节中,我们首先详细介绍图自动编码机,然后介绍图形变分自动编码机和其他改进。 表5总结了GAEs的主要特征。</p><div align=center><img src="GNN11.png"/></div><h3 id="5-1-Autoencoders"><a href="#5-1-Autoencoders" class="headerlink" title="5.1 Autoencoders"></a>5.1 Autoencoders</h3><p>图AE的使用源自稀疏自动编码器(SAE)。 基本思想是,通过将邻接矩阵或其变体视为节点的原始特征,可以利用AE作为降维技术来学习低维节点表示。 具体来说,SAE采用了以下L2重建损失:</p><script type="math/tex; mode=display">\begin{array}{c}\min _{\Theta} \mathcal{L}_{2}=\sum_{i=1}^{N}\|\mathbf{P}(i,:)-\hat{\mathbf{P}}(i,:)\|_{2} \\\hat{\mathbf{P}}(i,:)=\mathcal{G}\left(\mathbf{h}_{i}\right), \mathbf{h}_{i}=\mathcal{F}(\mathbf{P}(i,:))\end{array}\tag{43}</script><p>其中,$\mathbf{P}$ 是转移矩阵,$\hat{\mathbf{P}}$ 是重构矩阵,$\mathbf{h}_i\in\mathbb{R}^d$ 是节点 $v_i$ 的低维表示,$\mathcal{F}(\cdot)$ 是编码器,$\mathcal{G}(\cdot)$ 是解码器,$d\ll N$ 是维度,$\Theta$ 是参数,编码器和解码器都是包含多个隐含层的多层感知机。换句话说,SAE将 $P(i; :)$ 的信息压缩为低维向量hi,然后从该向量重构原始特征。 还添加了另一个稀疏正则化术语。 <strong>在获得低维表示 $h_i$ 之后,将 $k-means$用于节点聚类任务。</strong> 实验证明,SAE优于非深度学习基准。<strong>但是,SAE是基于不正确的理论分析得出的。其有效性的潜在机制仍无法解释。</strong></p><p>通过显示公式(43)中的L2重构损失,结构深层网络嵌入(SDNE)【“Structural deep network embedding”】填补了难题。实际上对应于节点之间的二阶接近度,即,如果两个节点具有相似的邻域,它们将共享相似的潜在的表示,这是网络科学中经过充分研究的概念,称为协作过滤或三角形闭合【“The emerging field of signal processing on graphs: Extending high-dimensional data analysis to networks and other irregular domains”】。 由于网络嵌入方法表明一阶邻近度也很重要【“Line: Large-scale information network embedding”】,因此SDNE通过添加另一个Laplacian特征图项【“Laplacian eigenmaps and spectral techniques for embedding and clustering”】修改了目标函数:</p><script type="math/tex; mode=display">\min _{\Theta} \mathcal{L}_{2}+\alpha \sum_{i, j=1}^{N} \mathbf{A}(i, j)\left\|\mathbf{h}_{i}-\mathbf{h}_{j}\right\|_{2}\tag{44}</script><p>即,如果两个节点直接连接,它们也共享相似的潜在表示。 作者还通过使用邻接矩阵并为零元素和非零元素分配了不同的权重来修改L2重构损失:</p><script type="math/tex; mode=display">\mathcal{L}_{2}=\sum_{i=1}^{N}\left\|\left(\mathbf{A}(i,:)-\mathcal{G}\left(\mathbf{h}_{i}\right)\right) \odot \mathbf{b}_{i}\right\|_{2}\tag{45}</script><p>其中,$\mathbf{h}_i=\mathcal{F}(\mathbf{A}(i,:)),b_{ij}=1\;if\; \mathbf{A}(i,j)=0\; else\;b_{ij}=\beta> 1$,$\beta$ 是另外的超参数。SDNE的总体架构如图8所示。</p><div align=center><img src="GNN12.png"/></div><p>受另一类研究的启发,当代著作DNGR【“Deep neural networks for learning graph representations”】用公式(20)中定义的正点向互信息(PPMI)【“Neural word embedding as implicit matrix factorization”】矩阵取代了公式(43)中的转移矩阵 $\mathbf{P}$ 与。这样,原始特征可以与图的某些随机游走概率相关联【“Random walks on graphs: A survey”】。 但是,构造输入矩阵的时间复杂度为 $O(N^2)$,无法扩展到大型图。</p><p>GC-MC【“Graph convolutional matrix completion”】通过使用Kipf和Welling【“Semi-supervised classification with graph convolutional networks”】提出的GCN作为编码器采用了不同的方法:</p><script type="math/tex; mode=display">\mathbf{H}=GCN(\mathbf{F}^V,\mathbf{A})\tag{46}</script><p>并使用简单的双线性函数作为解码器:</p><script type="math/tex; mode=display">\hat{\mathbf{A}}(i, j)=\mathbf{H}(i,:) \boldsymbol{\Theta}_{d e} \mathbf{H}(j,:)^{T}\tag{47}</script><p>其中,$\Theta_{de}$ 是解码器参数。使用这种方法,自然可以合并节点功能。对于没有节点特征的图,使用节点ID的one-hot编码。作者证明了GC-MC在二部图推荐问题上的有效性。</p><p>代替重构邻接矩阵或其变体,DRNE【“Deep recursive network embedding with regular equivalence”】提出了另一种修改,该修改通过使用LSTM聚合邻域信息来直接重构低维节点向量。 具体而言,DRNE采用了以下目标函数:</p><script type="math/tex; mode=display">\mathcal{L}=\sum_{i=1}^{N}\left\|\mathbf{h}_{i}-\mathrm{L} \operatorname{STM}\left(\left\{\mathbf{h}_{j} | j \in \mathcal{N}(i)\right\}\right)\right\|\tag{48}</script><p>由于LSTM要求其输入必须为序列,因此作者建议根据节点邻域的程度对其进行排序。他们还对具有较大程度的节点采用了邻域采样技术,以防止内存过长。作者证明,这种方法可以保留规则的等价性以及节点的许多中心性度量,例如PageRank。</p><p>与上述将节点映射到低维向量的工作不同,Graph2Gauss(G2G)【“Deep gaussian embedding of graphs: Unsupervised inductive learning via ranking”】建议将每个节点编码为高斯分布 $h_i = N(M(i; :); diag((i; :)))$ 捕获节点的不确定性。 具体来说,作者使用从节点属性到高斯分布的均值和方差的深度映射作为编码器:</p><script type="math/tex; mode=display">\mathbf{M}(i,:)=\mathcal{F}_{\mathbf{M}}\left(\mathbf{F}^{V}(i,:)\right), \mathbf{\Sigma}(i,:)=\mathcal{F}_{\Sigma}\left(\mathbf{F}^{V}(i,:)\right)\tag{49}</script><p>其中,$\mathcal{F}_M(\cdot),\mathcal{F}_{\sum}(\cdot)$ 是要学习的参数函数。然后,他们使用成对约束来学习模型,而不是使用显式解码器函数:</p><script type="math/tex; mode=display">\begin{array}{c}\mathrm{KL}\left(\mathrm{h}_{j} \| \mathrm{h}_{i}\right)<\mathrm{KL}\left(\mathrm{h}_{j^{\prime}} \| \mathrm{h}_{i}\right) \\\forall i, \forall j, \forall j^{\prime} \text { s.t. } d(i, j)<d\left(i, j^{\prime}\right)\end{array}\tag{50}</script><p>其中,$d(i,j)$ 是节点 $v_i$ 到节点 $v_j$ 的最短距离,$\mathbf{KL}(q(\cdot)|p(\cdot))$ 是 $q(\cdot)$ 和 $p(\cdot)$ 之间的Kullback-Leibler(KL)散度【“On information and sufficiency”】。换句话说,约束条件确保节点表示之间的KL散度具有与图距离相同的相对顺序。 但是,因为公式(50)难以优化,因此采用了基于能量的损失【“A tutorial on energy-based learning”】:</p><script type="math/tex; mode=display">\mathcal{L}=\sum_{\left(i, j, j^{\prime}\right) \in \mathcal{D}}\left(E_{i j}^{2}+\exp ^{-E_{i j^{\prime}}}\right)\tag{51}</script><p>其中,$\mathcal{D}=\{(i,j,j^{\prime})|d(i,j)<d(i,j^{\prime})\},E_{ij}=\mathbf{KL}(\mathbf{h}_j|\mathbf{h}_i)$。作者进一步提出了一种无偏的采样策略,以加快训练过程。</p><h3 id="5-2-Variational-Autoencoders"><a href="#5-2-Variational-Autoencoders" class="headerlink" title="5.2 Variational Autoencoders"></a>5.2 Variational Autoencoders</h3><p>与上述自动编码器不同,变异自动编码器(VAE)是将降维与生成模型结合在一起的另一种深度学习方法。 它的潜在好处包括容忍噪声和学习平滑表示【“Auto-encoding variational bayes”】。 VAE首先被引入VGAEs【“Variational graph auto-encoders”】中的图形数据,其中解码器是一个简单的线性乘积:</p><script type="math/tex; mode=display">p(\mathbf{A} | \mathbf{H})=\prod_{i, j=1}^{N} \sigma\left(\mathbf{h}_{i} \mathbf{h}_{j}^{T}\right)\tag{52}</script><p>其中假定节点表示遵循高斯分布 $q(\mathbf{h}_i|\mathbf{M},\sum)= \mathcal{N}(\mathbf{h}_i|\mathbf{M}(i; :), diag(\sum(i; :)))$。 对于均值和方差矩阵的编码器,作者还采用了Kipf和Welling提出的GCN【“Semi-supervised classification with graph convolutional networks”】:</p><script type="math/tex; mode=display">\mathbf{M}=G C N_{\mathrm{M}}\left(\mathbf{F}^{V}, \mathbf{A}\right), \log \mathbf{\Sigma}=G C N_{\Sigma}\left(\mathbf{F}^{V}, \mathbf{A}\right)\tag{53}</script><p>然后,通过最小化变分下界来学习模型参数【“Auto-encoding variational bayes”】:</p><script type="math/tex; mode=display">\mathcal{L}=\mathbb{E}_{q\left(\mathbf{H} | \mathbf{F}^{V}, \mathbf{A}\right)}[\log p(\mathbf{A} | \mathbf{H})]-\operatorname{KL}\left(q\left(\mathbf{H} | \mathbf{F}^{V}, \mathbf{A}\right) \| p(\mathbf{H})\right)\tag{54}</script><p>但这个方法要求重构整个图,所以复杂度为 $O(N^2)$。</p><p>受SDNE和G2G的推动,DVNE [103]为图数据提出了另一个VAE,该图也将每个节点都表示为高斯分布。 与现有的采用KLdivergence作为度量的工作不同,DVNE使用Wasserstein距离[114]来保留节点相似性的传递性。 与SDNE和G2G相似,DVNE在其目标函数中还保留了一阶和二阶接近度:</p><script type="math/tex; mode=display">\min _{\Theta} \sum_{\left(i, j, j^{\prime}\right) \in \mathcal{D}}\left(E_{i j}^{2}+\exp ^{-E_{i j^{\prime}}}\right)+\alpha \mathcal{L}_{2}\tag{55}</script><p>其中,$E_{ij}=W_2(\mathbf{h}_j|\mathbf{h}_i)$ 是两个高斯分布 $\mathbf{h}_i,\mathbf{h}_j$之间的第二个Wasserstein距离。$D = \{(i, j, j^{\prime})|j\in\mathcal{N}(i), j^{\prime}\notin \mathcal{N}(i)\}$是一组对应于一阶接近度的秩损失的三元组。 构损失定义如下:</p><script type="math/tex; mode=display">\mathcal{L}_{2}=\inf _{q(\mathbf{Z} | \mathbf{P})} \mathbb{E}_{p(\mathbf{P})} \mathbb{E}_{q(\mathbf{Z} | \mathbf{P})}\|\mathbf{P} \odot(\mathbf{P}-\mathcal{G}(\mathbf{Z}))\|_{2}^{2}\tag{56}</script><p>其中,$\mathbf{P}$ 是转移矩阵,$\mathbf{Z}$ 代表对 $\mathbf{H}$ 的采样。框架如图9所示。使用这种方法,可以将目标函数最小化,就像在常规VAE中重新参数化技巧一样【“Auto-encoding variational bayes”】。</p><div align=center><img src="GNN13.png"></div><h3 id="5-3-Improvements-and-Discussions"><a href="#5-3-Improvements-and-Discussions" class="headerlink" title="5.3 Improvements and Discussions"></a>5.3 Improvements and Discussions</h3><p>针对GAME提出了一些改进。</p><h4 id="5-3-1-Adversarial-Training"><a href="#5-3-1-Adversarial-Training" class="headerlink" title="5.3.1 Adversarial Training"></a>5.3.1 Adversarial Training</h4><div align=center><img src="GNN14.png"></div><p>对抗训练计划9被纳入GAEs,作为ARGA中的附加正则化项【“Adversarially regularized graph autoencoder for graph embedding”】。 总体架构如图10所示。具体地说,GAEs的编码器用作生成器,而判别器旨在区分潜在表示是来自生成器还是来自先验分布。 以这种方式,自动编码器被迫匹配先前的分布作为正则化。 目标函数是:</p><script type="math/tex; mode=display">\min _{\Theta} \mathcal{L}_{2}+\alpha \mathcal{L}_{G A N}\tag{57}</script><p>其中,$\mathcal{L}_2$ 在GAEss中是重构损失,$\mathcal{L}_{GAN}$ 是:</p><script type="math/tex; mode=display">\min _{\mathcal{G}} \max _{\mathcal{D}} \mathbb{E}_{\mathbf{h} \sim p_{\mathbf{h}}}[\log \mathcal{D}(\mathbf{h})]+\mathbb{E}_{\mathbf{z} \sim \mathcal{G}\left(\mathbf{F}^{V}, \mathbf{A}\right)}[\log (1-\mathcal{D}(\mathbf{z}))]\tag{58}</script><p>其中,$\mathcal{G}(\mathbf{F}^V,\mathbf{A})$是使用公式(53)中的图卷积编码器的生成器,$D(\cdot)$ 是基于交叉熵损失的判别器,$p_h$ 是先验分布。该研究采用了简单的高斯先验,实验结果证明了对抗训练方案的有效性。</p><p>同时,NetRA【“Learning deep network representations with adversarially regularized autoencoders,”】还提出使用生成对抗网络(GAN)【“Generative adversarial nets”】来增强图自动编码器的泛化能力。 具体来说,作者使用了以下目标函数:</p><script type="math/tex; mode=display">\min _{\Theta} \mathcal{L}_{2}+\alpha_{1} \mathcal{L}_{L E}+\alpha_{2} \mathcal{L}_{G A N}\tag{59}</script><p>其中,$L_{LE}$ 是公式(44)中所示的拉普拉斯特征图目标函数。另外,作者采用LSTM作为编码器,以汇总来自类似于公式(48)的邻域的信息。与其像DRNE【“Deep recursive network embedding with regular equivalence”】中那样仅对直接邻居采样并使用度对节点进行排序,作者还使用了随机游走来生成输入序列。与ARGA相比,NetRA认为GAEs中的表示形式是真实的,并采用了随机的高斯噪声,然后是MLP作为生成器。</p><h4 id="5-3-2-Inductive-Learning"><a href="#5-3-2-Inductive-Learning" class="headerlink" title="5.3.2 Inductive Learning"></a>5.3.2 Inductive Learning</h4><p>与GCN相似,如果将节点属性合并到编码器中,则GAE可以应用于归纳学习设置。 这可以通过使用GCN作为编码器来实现,例如在GC-MC【“Graph convolutional matrix completion”】,VGAE【“Variational graph auto-encoders”】和VGAE【“Adversarially regularized graph autoencoder for graph embedding”】中,或者通过像G2G【“Deep gaussian embedding of graphs: Unsupervised inductive learning via ranking”】中那样直接从节点特征中学习映射函数来实现。 由于仅在学习参数时才使用边缘信息,因此该模型也可以应用于训练期间未看到的节点。 这些工作还表明,尽管GCN和GAE基于不同的体系结构,但可以将它们组合使用,我们认为这是一个有希望的未来方向。</p><h4 id="5-3-3-Similarity-Measures"><a href="#5-3-3-Similarity-Measures" class="headerlink" title="5.3.3 Similarity Measures"></a>5.3.3 Similarity Measures</h4><p>在GAE中,已采用了许多相似性度量,例如L2重建损失,Laplacian特征图和图AE的秩损失,以及图VAE的KL散度和Wasserstein距离。 尽管这些相似性度量基于不同的动机,但是如何为给定的任务和模型体系结构选择合适的相似性度量仍未研究。 需要更多的研究来了解这些指标之间的根本差异。</p><h2 id="6-Graph-Reinforcement-Learning"><a href="#6-Graph-Reinforcement-Learning" class="headerlink" title="6. Graph Reinforcement Learning"></a>6. Graph Reinforcement Learning</h2><p>深度学习的一个方面尚未讨论,即强化学习(RL),它已被证明在诸如玩游戏之类的AI任务中是有效的。众所周知,RL善于从反馈中学习,尤其是在处理可微分的目标和约束时。在本节中,我们回顾了Graph RL方法。表6总结了它们的主要特性。</p><div align=center><img src="GNN15.png"/></div><p>GCPN【“Graph convolutional policy network for goal-directed molecular graph generation”】利用RL生成目标导向的分子图,同时考虑了非微分的目标和约束。具体而言,将图生成建模为添加节点和边的马尔可夫决策过程,并将生成模型视为在图生成环境中运行的RL代理。通过将代理人行为视为链接预测,使用特定领域以及对抗性奖励,并使用GCN来学习节点表示,可以使用策略梯度以端到端的方式训练GCPN【“Policy gradient methods for reinforcement learning with function approximation,”】。</p><p>一项并行的工作,MolGAN【“MolGAN: An implicit generative model for small molecular graphs”】,采用了类似的想法,即使用RL生成分子图。但是,MolGAN建议不要通过一系列动作来生成图,而是直接生成完整图。这种方法对小分子特别有效。</p><p>GTPN【“Graph transformation policy network for chemical reaction prediction”】采用RL预测化学反应产物。具体来说,该代理负责选择分子图中的节点对并预测它们的新键合类型,并根据预测是否正确对它们进行即时和最终奖励。GTPN使用GCN来学习节点表示,并使用RNN来存储预测序列。</p><p>GAM【“Graph classification using structural attention”】通过使用随机游走将RL应用于图分类。 作者将随机游走的产生建模为部分可观察到的马尔可夫决策过程(POMDP)。该代理执行了两项操作:首先,它预测了图的标签,然后,它选择了随机游走中的下一个节点。奖励的确定仅取决于代理人是否对图表进行了正确分类,即</p><script type="math/tex; mode=display">\mathcal{J}(\theta)=\mathbb{E}_{P\left(S_{1: T} ; \theta\right)} \sum_{t=1}^{T} r_{t}\tag{60}</script><p>其中,$r_t=1$ 表示一个正确的预测,$r_t=-1$ 表示错误的预测。$T$ 是总时间步长,$S_t$ 是环境。</p><p>DeepPath【“Deeppath: A reinforcement learning method for knowledge graph reasoning”】和MINERVA【“Go for a walk and arrive at the answer: Reasoning over paths in knowledge bases using reinforcement learning”】都采用RL进行知识图(KG)推理。 具体来说,DeepPath的目标是寻路,即在两个目标节点之间找到最有信息的路径,而MINERVA则负责解决问答任务,即在给定问题节点和关系的情况下找到正确的答案节点。 在这两种方法中,RL代理都需要在每个步骤中预测路径中的下一个节点,并在KG中输出推理路径。 如果路径到达正确的目的地,座席将获得奖励。 DeepPath还添加了一个正则化术语来鼓励路径的多样性。</p><h2 id="7-GRAPH-ADVERSARIAL-METHODS"><a href="#7-GRAPH-ADVERSARIAL-METHODS" class="headerlink" title="7. GRAPH ADVERSARIAL METHODS"></a>7. GRAPH ADVERSARIAL METHODS</h2><p>近年来,诸如GAN等对抗方法和对抗攻击在机器学习社区中引起了越来越多的关注。在本节中,我们将介绍如何将对抗方法应用于图形。表7总结了图对抗方法的主要特征。</p><div align=center><img src="GNN16.png"/></div><h3 id="7-1-Adversarial-Training"><a href="#7-1-Adversarial-Training" class="headerlink" title="7.1 Adversarial Training"></a>7.1 Adversarial Training</h3><p>GAN的基本思想是建立两个链接的模型:判别器和生成器。生成器的目标是通过生成假数据来“欺骗”判别器,而判别器的目的是区分样本是来自真实数据还是由生成器生成。随后,两个模型通过使用minimax游戏进行联合训练而彼此受益。对抗训练已被证明在生成模型中有效,并增强了判别模型的泛化能力。在第5.3.1节和第6节中,我们回顾了如何分别在GAE和Graph RL中使用对抗训练方案。在这里,我们详细回顾了图上的其他几种对抗训练方法。</p><p>GraphGAN [124]提出使用GAN来增强图嵌入方法[17],其目标函数如下:</p><script type="math/tex; mode=display">\begin{array}{c}\min _{\mathcal{G}} \max _{\mathcal{D}} \sum_{i=1}^{N}\left(\mathbb{E}_{v \sim p_{g r a p h}\left(\cdot | v_{i}\right)}\left[\log \mathcal{D}\left(v, v_{i}\right)\right]\right.\\+\left.\mathbb{E}_{v \sim \mathcal{G}\left(\cdot | v_{i}\right)}\left[\log \left(1-\mathcal{D}\left(v, v_{i}\right)\right)\right]\right)\end{array}\tag{61}</script><p>其中,判别器 $\mathcal{D}(\cdot)$ 和生成器 $\mathcal{G}(\cdot)$ 如下:</p><script type="math/tex; mode=display">\mathcal{D}(v,v_i)=\sigma(\mathbf{d}_v\mathbf{d}_{v_i}^T),\mathcal{G}(v|v_i)=\frac{\exp(\mathbf{g}_v\mathbf{g}_{v_i}^T)}{\sum_{v^{\prime}\neq v_i}\exp(\mathbf{g}_{v^{\prime}}\mathbf{g}_{v_i}^T)}\tag{62}</script><p>其中,$\mathbf{d}_v$ 和 $\mathbf{g}_v$ 分别是判别器和生成器中节点 $v$ 的低维嵌入向量。结合以上等式,判别器实际上具有两个目标:原始图中的节点对应具有较大的相似性,而生成器生成的节点对应具有较小的相似性。该架构与网络嵌入方法(如LINE [108])相似,除了负节点对由生成器 $\mathcal{G}(\cdot)} 而不是由随机采样生成。作者表明,该方法增强了节点嵌入向量的推断能力。</p><p>对抗网络嵌入(ANE)[125]也采用对抗训练方案来改进网络嵌入方法。类似于ARGA [104],ANE通过将先验分布作为真实数据并将嵌入矢量视为生成的样本,将GAN用作现有网络嵌入方法(如DeepWalk [131])的附加正则项。</p><p>GraphSGAN [126]使用GAN来增强图的半监督学习。特别是,作者观察到,应该在子图之间的密度间隙中生成伪节点,以削弱现有模型不同簇之间的传播效果。为了实现该目标,作者设计了一种新颖的优化目标,该目标具有精心设计的损失项,以确保生成器在平衡时的密度间隙中生成样本。</p><p>NetGAN [127]为图生成任务采用了GAN。具体来说,作者将图生成作为学习有偏随机游走分布的一项任务,并采用GAN框架使用LSTM生成和区分随机游走。实验表明,使用随机游走还可以学习全局网络模式。</p><h3 id="7-2-Adversarial-Attacks"><a href="#7-2-Adversarial-Attacks" class="headerlink" title="7.2 Adversarial Attacks"></a>7.2 Adversarial Attacks</h3><p>对抗攻击是另一类对抗方法,旨在通过向数据添加较小的扰动来故意“欺骗”目标方法。 研究对抗性攻击可以加深我们对现有模型的理解,并激发出更强大的体系结构。 我们在下面回顾基于图的对抗攻击。</p><p>Nettack [128]首先提出了通过修改图结构和节点属性来攻击节点分类模型(例如GCN)的方法。 表示目标节点为 $v_0$,其真实类为 $c_{true}$,目标模型为 $\mathcal{F}(\mathbf{A}; \mathbf{F}^V)$,其损失函数为 $\mathcal{L}_F(\mathbf{A}; \mathbf{F}^V)$,该模型采用以下目标函数:</p><script type="math/tex; mode=display">\begin{array}{c} \argmax_{(\mathbf{A}^{\prime},\mathbf{F}^{V\prime})\in\mathcal{P}}\max_{c\neq c_{true}}\log\mathbf{Z}_{v_0,c}^*-\log\mathbf{Z}_{v_0,c_{true}}^*\\ s.t.\;\mathbf{Z}^*=\mathcal{F}_{\theta^*}(\mathbf{A}^{\prime},\mathbf{F}^{V\prime}), \theta^*=\argmin_{\theta}\mathcal{L}_{\mathcal{F}}(\mathbf{A}^{\prime},\mathbf{F}^{V\prime})\end{array}\tag{63}</script><p>其中,$\mathbf{A}^{\prime},\mathbf{F}^{V\prime}$ 是修改的邻接矩阵和节点特征矩阵, $\mathbf{Z}$ 表示由 $\mathcal{F}(\cdot)$ 预测的分类概率,$\mathbf{P}$ 表示由攻击约束条件确定的空间。 简单来说,优化的目的是找到图结构和节点属性中的最佳合法更改,以使 $v_0$ 被错误分类。$\theta^*$ 表示攻击是起因的,即攻击发生在训练目标模型之前。 作者提出了一些针对攻击的约束条件。最重要的约束条件是,攻击应该是“不明显的”,即应该只进行很小的更改。具体来说,作者提议保留数据特征,例如节点度分布和特征共现。作者还提出了两种攻击方案:直接攻击(直接攻击 $v_0$)和影响攻击(仅攻击其他节点),并提出了几种放宽措施以使优化易于处理。</p><p>同时,Dai等[129]研究了目标函数与公式(63)类似的图的对抗攻击;但是,他们只关注只更改图结构的情况。作者没有假设攻击者拥有所有信息,而是考虑了几种设置,其中提供了不同数量的信息。最有效的策略是RL-S2V,它采用structure2vec [132]来学习节点和图形表示,并使用强化学习来解决优化问题。实验结果表明,这些攻击对于节点和图分类任务均有效。</p><p>前面提到的两种攻击是针对性的,即,它们旨在引起某些目标节点 $v_0$ 的错误分类。Zugner和Gunnemann [130]率先研究了非目标攻击,这些攻击旨在降低整体模型性能。他们将图结构视为要优化的超参数,并在优化过程中采用了元梯度,同时还采用了几种近似元梯度的技术。</p><h2 id="8-DISCUSSIONS-AND-CONCLUSION"><a href="#8-DISCUSSIONS-AND-CONCLUSION" class="headerlink" title="8. DISCUSSIONS AND CONCLUSION"></a>8. DISCUSSIONS AND CONCLUSION</h2><p>到目前为止,我们已经回顾了不同的基于图的深度学习架构以及它们的异同。 接下来,在总结本文之前,我们简要讨论它们的应用,实现和将来的方向。</p><h3 id="8-1-Applications"><a href="#8-1-Applications" class="headerlink" title="8.1 Applications"></a>8.1 Applications</h3><p>除了诸如节点或图形分类之类的标准图形推理任务外,基于图形的深度学习方法也已应用于多种学科,包括建模社会影响力[133],推荐[28],[66],[99],[134],化学和生物学[46],[52],[55],[116],[117],物理学[135],[136],疾病和药物预测[137]-[139], 基因表达[140],自然语言处理(NLP)[141],[142],计算机视觉[143]-[147],流量预测[148],[149],程序归纳[150],基于图的求解 NP问题[151],[152]和多主体AI系统[153]-[155]。</p><p>由于这些应用程序的多样性,因此对这些方法进行彻底的审查超出了本文的范围。但是,我们列出了一些关键灵感。首先,在构造图形或选择架构时,将领域知识纳入模型很重要。例如,基于相对距离构建图形可能适用于交通预测问题,但可能不适用于地理位置也很重要的天气预报问题。其次,基于图的模型通常可以在其他体系结构之上构建,而不是作为独立模型构建。例如,计算机视觉社区通常采用CNN来检测对象,然后将基于图的深度学习用作推理模块[156]。对于NLP问题,可以将GCN用作语法约束[141]。结果,关键的关键挑战是如何集成不同的模型。这些应用程序还表明,基于图的深度学习不仅能够挖掘现有图数据背后的丰富价值,而且还有助于将关系数据自然地建模为图,从而极大地扩展了基于图的深度学习模型的适用性。</p><h3 id="8-2-Implementations"><a href="#8-2-Implementations" class="headerlink" title="8.2 Implementations"></a>8.2 Implementations</h3><p>最近,已经提供了几个开放库,用于在图上开发深度学习模型。 这些库在表8中列出。我们还收集了一份源代码列表(大部分来自其原始作者),用于本文中讨论的研究。 该存储库包含在附录A中。这些开放的实现使您可以轻松学习,比较和改进不同的方法。 一些实现也解决了分布式计算的问题,我们不在本文中讨论。</p><div><img src="GNN17.png"></div><h3 id="8-3-Future-Directions"><a href="#8-3-Future-Directions" class="headerlink" title="8.3 Future Directions"></a>8.3 Future Directions</h3><p>有几个正在进行的或将来的研究方向也值得讨论:</p><ul><li><strong>未研究图结构的新模型</strong>:由于图数据的结构极为不同,因此现有方法并不适合所有方法。 例如,大多数方法集中于同构图,而很少研究异类图,尤其是那些包含不同模态的图,例如[157]中的图。 签名网络中的负边缘代表节点之间的冲突,它们也具有独特的结构,并且对现有方法提出了额外的挑战[158]。 表示两个以上对象之间复杂关系的超图[159]也未得到充分研究。 因此,重要的下一步是设计特定的深度学习模型来处理这些类型的图。</li><li><strong>现有模型的组成</strong>:如本文多次所示,可以集成许多现有架构:例如,将GCN用作GAE或Graph RL中的一个层。 除了设计新的构建块之外,如何系统地组合这些体系结构也是一个有趣的未来方向。 在这个过程中,如何以有原则的方式而不是个案的方式整合跨学科知识也是一个悬而未决的问题。 图网络[9]是最近的一项工作,迈出了第一步,并着重于将GNN和GCN的通用框架用于关系推理问题。 通过减少组装不同组件并选择超参数的人工负担,AutoML也可能会有所帮助[160]。</li><li><strong>动态图</strong>:现有的大多数方法都集中在静态图上。 但是,许多真实的图本质上是动态的:它们的节点,边线和特征会随着时间变化。 例如,在社交网络中,人们可能建立新的社交关系,删除旧的关系,并且他们的特征(例如兴趣爱好和职业)会随着时间而改变。 新用户可以加入网络,而现有用户可以离开。 如何对动态图的不断发展的特征进行建模以及如何支持对模型参数的增量更新仍未解决。 通过使用图RNN [27],[29],一些前期工作已获得令人鼓舞的结果。</li><li><strong>可解释性和鲁棒性</strong>:由于图通常与其他风险敏感的场景相关,因此解释图上深度学习模型的结果的能力对于决策问题至关重要。例如,在医学或与疾病相关的问题中,可解释性对于将计算机实验转化为临床应用至关重要。但是,基于图的深度学习的可解释性甚至比其他黑盒模型更具挑战性,因为图的节点和边缘通常紧密相连。另外,由于第7.2节中所示,许多现有的图上深度学习模型对对抗攻击都很敏感,因此增强现有方法的鲁棒性是另一个重要问题。关于可解释性和鲁棒性的一些开创性著作可以分别在[161]和[162],[163]中找到。</li></ul><h3 id="8-4-Summary"><a href="#8-4-Summary" class="headerlink" title="8.4 Summary"></a>8.4 Summary</h3><p>以上调查表明,在图上进行深度学习是一个有前途且发展迅速的研究领域,既提供了令人兴奋的机会,也提出了许多挑战。 研究图上的深度学习是对关系数据进行建模的关键组成部分,这是通过更好的机器学习和人工智能技术迈向未来的重要一步。</p>]]></content>
<summary type="html"><h1 id="Deep-Learning-on-Graph-A-Survey"><a href="#Deep-Learning-on-Graph-A-Survey" class="headerlink" title="Deep Learning on Graph: A Survey"></a>Deep Learning on Graph: A Survey</h1></summary>
<category term="论文" scheme="https://over-shine.github.io/categories/%E8%AE%BA%E6%96%87/"/>
<category term="GNN" scheme="https://over-shine.github.io/tags/GNN/"/>
<category term="DL" scheme="https://over-shine.github.io/tags/DL/"/>
</entry>
<entry>
<title>Attention Module is Not Only a Weight: Analyzing Transformers with Vector Norms</title>
<link href="https://over-shine.github.io/2020/08/21/Attention-Module-is-Not-Only-a-Weight-Analyzing-Transformers-with-Vector-Norms/"/>
<id>https://over-shine.github.io/2020/08/21/Attention-Module-is-Not-Only-a-Weight-Analyzing-Transformers-with-Vector-Norms/</id>
<published>2020-08-21T14:08:06.000Z</published>
<updated>2021-11-06T06:54:05.420Z</updated>
<content type="html"><![CDATA[<h1 id="Attention-Module-is-Not-Only-a-Weight-Analyzing-Transformers-with-Vector-Norms"><a href="#Attention-Module-is-Not-Only-a-Weight-Analyzing-Transformers-with-Vector-Norms" class="headerlink" title="Attention Module is Not Only a Weight: Analyzing Transformers with Vector Norms"></a>Attention Module is Not Only a Weight: Analyzing Transformers with Vector Norms</h1><a id="more"></a><h2 id="lt-center-gt-摘要-lt-center-gt"><a href="#lt-center-gt-摘要-lt-center-gt" class="headerlink" title="<center>摘要</center>"></a><code><center></code>摘要<code></center></code></h2><p><strong>目的:</strong> 注意力模块为何成功以及它们捕获了什么样的语言信息。</p><p><strong>本文和已有研究的不同之处:</strong></p><ol><li>以前的研究主要分析注意力权重,以查看注意力模块从每个输入中收集多少信息以产生输出;</li><li>在本文中,我们指出注意力权重只是决定自我注意力模块输出的两个因素之一,并且将转换后的输入向量纳入分析;</li></ol><p><strong>工作:</strong> 测量加权向量的范数作为每个输入对输出的贡献。</p><!-- more --><p><strong>结论:</strong> 对BERT和基于Transformer的神经机器翻译系统中的自我注意模块的分析表明,注意模块的行为非常直观,这与以前的发现相反。</p><ol><li>BERT的注意力模块并没有把大量注意力放到特殊token,如[CLS],[SEP]等;</li><li>Transformer的注意力模块擅长捕捉词对齐。</li></ol><h2 id="一、介绍"><a href="#一、介绍" class="headerlink" title="一、介绍"></a>一、介绍</h2><p>当前基于Transformer的模型在NLP的各种任务都取得了最好的效果。但这些模型的成功并没有得到很好的解释,因此大量的研究都集中在它们的语言能力上。由于注意力模块是Transformer的核心组成部分,因此研究的一项突出重点是注意力权重和各种语言现象的相关性。但是,目前社区尚未就注意力模块如何以及为什么运行良好达成共识。</p><p>为了在这一项研究中更进一步,本文提出了一种新颖的方法来分析注意力模块的行为。曾经跟踪注意力权重的方法是基于 <strong>“如果一个输入向量比其它输入向量获得了更大的注意力权重,则该输入向量对输出的贡献更大”</strong> 的假设。相比之下,本文首先提出的见解是,<strong>注意力模块的输出的计算可以分解为变换后的输入向量的加权和,并指出仅分析注意力权重不足以调查整个注意力模块的行为</strong>。然后,本文提出一种使用加权向量范数(长度)的分析方法,该方法也考虑了先前忽略的因子,即转换后的向量,以估计每个输入向量在输出向量计算中的贡献。</p><p>在本文实验中,首先分析了BERT中的自注意力模块。本文凭经验表明,输入token对其输出隐藏向量的贡献与以前的工作有很大不同。特别是,以前的一些报告显示了一些非直观的观察结果。 例如,逗号,句点和特殊token(例如分隔符 [SEP])之类的特殊token往往会获得显著的注意力权重。本文的实验表明,与以前的注意力权重跟踪方法不同,本文基于范数的方法产生了更直观的观察结果。</p><p>最后,本文在基于Transformer的神经机器翻译(NMT)系统中分析了源—目标注意力模块。使用基于范数的方法观察到NMT系统的属性与以前的结果明显不同,与注意力权重分析中的先前发现相反,它们的注意力模块隐式学习了单词对齐。</p><p><strong>本文贡献如下:</strong></p><ol><li>提出了一种基于向量范数的注意力模块分析方法,该方法考虑了先前被忽略的因素(转换后的输入向量)以及注意力权重;</li><li>我们使用基于范数的方法对BERT中的自注意力模块进行了分析,发现:<br>(1) 先前被忽略的向量(转换后的输入向量)的范数的分散很大;<br>(2) 注意力模块对特殊token的关注度不大;<br>(3) 注意力模块倾向于减少常用词。</li><li>对基于Transformer的NMT系统中分析了源—目标注意力模块,发现与先前的发现相反,该注意力模块隐式地执行了单词对齐。</li></ol><h2 id="二、背景"><a href="#二、背景" class="headerlink" title="二、背景"></a>二、背景</h2><h3 id="1-注意力模块"><a href="#1-注意力模块" class="headerlink" title="1. 注意力模块"></a>1. 注意力模块</h3><div align=center><img src="attention.png" /></div><p>注意模块的概述如图1所示。在注意模块中,使用输入矢量,权重和偏差的加权和来计算输出矢量。 直观地,当分配给某个矢量的权重较大时(图1中的蓝色圆圈),模块将注意力集中在输入矢量上,而权重较小的矢量则受到较少的关注。</p><p>$x_i$ 代表原始向量,输出向量 $y_i$ 的计算过程如图一所示</p><script type="math/tex; mode=display">y_i=(\sum_{j=1}^n\alpha_{i,j}v(x_j))W^O+b^O\in\mathbb{R}^d\tag{1}</script><script type="math/tex; mode=display">\alpha_{i,j}:={softmax}_{x_j\in\mathcal{X}}(\frac{q(\tilde{y}_i)k(x_j)^T}{\sqrt{d^{\prime}}})\in\mathbb{R}\tag{2}</script><p>其中</p><script type="math/tex; mode=display">q(\tilde{y}_i):=\tilde{y}_iW^Q+b^Q\qquad(W^Q\in\mathbb{R}^{d\times d^{\prime}},b^Q\in\mathbb{R}^{d^{\prime}})</script><script type="math/tex; mode=display">k(x_j):=x_jW^K+b^K\qquad(W^K\in\mathbb{R}^{d\times d^{\prime}},b^K\in\mathbb{R}^{d^{\prime}})</script><script type="math/tex; mode=display">v(x_j):=x_jW^V+b^V\qquad(W^V\in\mathbb{R}^{d\times d^{\prime}},b^V\in\mathbb{R}^{d^{\prime}})</script><p>即,首先计算注意力权重 $\alpha_{i,j}$ ,然后对值向量 $v(x_j)$ 进行 $\alpha_{i,j}$ 加权,对加权后的值向量求和,最后通过 $W^O\in\mathbb{R}^{d^{\prime}\times d},b^O\in\mathbb{R}^d$ 进行仿射变换。</p><p>如果 $\tilde{y}_i\in\mathcal{X}$ ,这个模块称为自注意力模块,它在BERT中被实现。在 Transformer 这个 Sequence2Sequence 模型的编码器和解码器之间的注意力模块中, $\mathcal{X}$ 编码器的堆栈表示,向量 $\tilde{y}_i$ 和 $y_i$ 对应于解码器的第 $i$ 个 token</p><h3 id="2-加权向量和注意力模块"><a href="#2-加权向量和注意力模块" class="headerlink" title="2. 加权向量和注意力模块"></a>2. 加权向量和注意力模块</h3><div align=center><img src="attention1.PNG"></div><p>通过简单的重构,我们可以看到注意力模块计算了输入向量的加权和。 利用矩阵乘积的线性特点,我们可以将等式重写为:</p><script type="math/tex; mode=display">y_i=\sum_{j=1}^{n}\alpha_{i,j}f(x_j)+b^O\tag{3}</script><script type="math/tex; mode=display">f(x):=(xW^V+b^V)W^O\tag{4}</script><p>公式3显示注意力模块首先对每个输入向量 $x$ 进行变换以生成 $f(x)$ 并计算注意力权重,然后将 $f(x)$ 的总和与偏置 $b^O$ 相加。</p><h3 id="3-注意力权重分析的问题"><a href="#3-注意力权重分析的问题" class="headerlink" title="3. 注意力权重分析的问题"></a>3. 注意力权重分析的问题</h3><p>注意力模块通过聚合句子的相关信息来更新表示,因此,在先前的研究中,已经通过分析注意力权重的大小来研究从每个输入中获取多少信息来产生输出。</p><p>但这部分的分析是基于一个假设:如果一个输入向量赋予了一个比其它输入向量大的注意力权重,那么这个输入向量比其它输入向量对输出向量的贡献更大。但是,该假设无视要加权的向量的大小。 直观地,在注意力权重相等的情况下,较大的向量将比较小的向量对输出向量的贡献更大。</p><p>忽略 $f(x_j)$ 的影响在图二进行了说明。这里假定输入向量 $x_1$ 的变换向量 $f(x_j)$ 非常小 ($||f(x_j)||\approx 0$) ,同时他获得了比其它输入更大的注意力权重 $\alpha_{i,1}$。在这种情况下,即使输入 $x_1$ 对输出向量的贡献,例如 $y_i$ 很小,仅关注注意力权重也可能导致错误的观察,即该输入向量 $x_1$ 对输出 $y_i$ 的贡献最大。在过去的研究中,或许正是因为这个原因,基于注意力权重的分析已经产生了不直观的观察。<em>What Does BERT Look At An Analysis of BERT’s Attention</em> 这篇论文指出,特殊 token 如逗号、句号,分隔符等的输入向量趋向于获得非常大的注意力权重,然而,直观上讲它们对于训练任务(MLM和NSP)相较于丰富内容的 token 应该受到限制。</p><h2 id="三、-建议:范数作为关注度"><a href="#三、-建议:范数作为关注度" class="headerlink" title="三、 建议:范数作为关注度"></a>三、 建议:范数作为关注度</h2><p>正如上一节提到的,在过去的工作中,在公式(3)中仅仅考虑了$\alpha_{i,j}$,但是$f(x_j)$却被忽略了。在这篇论文中,我们的主要建议是通过使用$\alpha_{i,j}f(x_j)$评估输入向量 $x_j$ 到输出向量$y_i$的贡献。正如我们将显示的,这种差异在探索注意模块的行为方面确实很重要。</p><p>为了解决上述问题,我们建议使用 $||\alpha f(x)||$(这是等式(3)中加权的转换向量的标准欧几里得范数(长度))作为一种分析注意力模块行为的新颖方法。 与之前仅观察到注意力权重的研究不同,我们分析 $||\alpha f(x)||$ 和 $||f(x)||$ 的行为,并获得对注意力模块工作原理的更深入了解。 与以前的基于权重的分析相比,我们将这种建议的分析注意力模块的方式称为基于范数的分析。</p><p>在实验部分(第4和第5节)中,我们经验表明,通过使用基于范数的分析而不是基于权重的分析,可以对注意力模块的行为获得更直观和有意义的观察结果。 值得注意的是,我们的基于规范的分析可以自然地扩展到Transformer,BERT等中实现的多头注意模块,因为多头注意模块是注意模块的自然扩展,并且它是线性的可分解的,即,注意头(注意模块)平行布置,并且多头注意力模块的输出是所有注意力头的输出矢量的总和。</p><h2 id="四、试验1:BERT"><a href="#四、试验1:BERT" class="headerlink" title="四、试验1:BERT"></a>四、试验1:BERT</h2><p>首先,我们初步展示了先前忽略的影响因子,即转换后的向量的范数,它可能影响BERT中注意力模块分析的结果。然后,我们使用基于范数的分析方法重新测试了曾经在BERT中使用基于权重的分析方法的结果。最终,我们引入了曾经BERT被忽略的属性。</p><p><strong>通用设置:</strong> 效仿之前的研究,我们分析了预训练的拥有12层神经网络和12个注意力头的bert-base-uncased模型的注意力模块。我们使用了论文<a href="https://www.aclweb.org/anthology/W19-4828/">"What Does BERT Look At? An Analysis of BERT’s Attention"</a>提供的数据。这个数据包含了从 Wikipedia 提取的992条句子,每个句子以 [CLS] paragraph1 [SEP] paragraph2 [SEP] 的形式包含两个连续的段落。每个句子包含最多128个token,平均每个句子包含122个token。</p><h3 id="4-1-f-x-是否有影响?"><a href="#4-1-f-x-是否有影响?" class="headerlink" title="4.1 $f(x)$ 是否有影响?"></a>4.1 $f(x)$ 是否有影响?</h3><p>$|\alpha f(x)|$ 和 $\alpha$ 有什么不同作为一个初步的证明,我们分析了 $|f(x)|$ 变量的系数。基于公式 (3),如果 $|f(x)|$ 是一个定值,权重 $\alpha$ 可能是 $|\alpha f(x)|$ 的一个好的近似逼近。也就是说,如果 $|f(x)|$ 是一个常量,那么我们基于范数的分析是不值得应用的。</p><p>所有数据首先输入到模型,然后计算 $|f(x)|$ 变量的系数。表1显示变量系数的平均值时0.22,$|f(x)|$ 的值通常在平均值的 0.78 倍和 1.22 倍之间变化。因此,$\alpha$ 和 $|\alpha f(x)|$ 之间的不同可以归咎到 $|f(x)|$ 的散度上,它促使我们在分析注意力模块时将 $|f(x)|$ 考虑进去。附件 A 显示了 $|x|$ 和仿射变换 $f$ 的影响。</p><h3 id="4-2-重新检测先前关注的现象"><a href="#4-2-重新检测先前关注的现象" class="headerlink" title="4.2 重新检测先前关注的现象"></a>4.2 重新检测先前关注的现象</h3><p>在这一部分,通过使用我们基于范数的分析方法,我们重新调查了曾经基于权重的报告的BERT的关注情况。</p><p><strong>设置:</strong> 首先,把数据输入BERT,然后获取每个注意力头的 $\alpha$ 和 $|\alpha f(x)|$,按照<a href="https://www.aclweb.org/anthology/W19-4828/">"What Does BERT Look At? An Analysis of BERT’s Attention"</a>,我们报告了下面的类型: [CLS] 、[SEP]、句号、逗号和其它token。</p><p><strong>结果:</strong> 图三展示了 $\alpha$ 和 $|\alpha f(x)|$ 完全不同的趋势,图3(a) 显示特殊token([SEP]、[CLS]和标点)的词向量获得非常大的注意力权重。然而,这样的观察是不直观的,因为这些标记按期望不具有如此的语言信息并且对于预训练任务(即,MLM和NSP)没有太大用处。但是,这种趋势确实与基于权重的分析报告一致。相反,我们基于范数的方法引入了一个直观的观察,那些特殊 token 的词向量的贡献通常很小(图3(b))。</p><p><a href="https://www.aclweb.org/anthology/W19-4828/">"What Does BERT Look At? An Analysis of BERT’s Attention"</a> 假设:如果在输入向量中没有必要的信息,则 BERT 为保证出现在任何输入序列中的[SEP]令牌分配较大的权重,而不通过注意模块合并任何其他信息。请注意,注意力模块的约束条件是注意力权重之和为1.0(请参见公式2)。<a href="https://www.aclweb.org/anthology/W19-4828/">"What Does BERT Look At? An Analysis of BERT’s Attention"</a> 称这个操作为“<strong>no-op</strong>”(无操作)。这个假设令人信服,但是,仍然不清楚分配给此类特殊 token 的强大关注权重如何收集任何东西。我们基于范数的分析表明,该数量实际上很小(图3b),这支持了BERT进行“no-op”的解释。</p><p><strong>分析 $\alpha$ 和 $|f(x)|$ 之间的关系:</strong></p>]]></content>
<summary type="html"><h1 id="Attention-Module-is-Not-Only-a-Weight-Analyzing-Transformers-with-Vector-Norms"><a href="#Attention-Module-is-Not-Only-a-Weight-Analyzing-Transformers-with-Vector-Norms" class="headerlink" title="Attention Module is Not Only a Weight: Analyzing Transformers with Vector Norms"></a>Attention Module is Not Only a Weight: Analyzing Transformers with Vector Norms</h1></summary>
<category term="论文" scheme="https://over-shine.github.io/categories/%E8%AE%BA%E6%96%87/"/>
<category term="Attention" scheme="https://over-shine.github.io/tags/Attention/"/>
<category term="NLP" scheme="https://over-shine.github.io/tags/NLP/"/>
</entry>
<entry>
<title>Recurrent Neural Network</title>
<link href="https://over-shine.github.io/2020/08/21/Recurrent-Neural-Network/"/>
<id>https://over-shine.github.io/2020/08/21/Recurrent-Neural-Network/</id>
<published>2020-08-21T14:03:07.000Z</published>
<updated>2021-11-06T06:58:16.419Z</updated>
<content type="html"><![CDATA[<h1 id="Recurrent-Neural-Network"><a href="#Recurrent-Neural-Network" class="headerlink" title="Recurrent Neural Network"></a>Recurrent Neural Network</h1><a id="more"></a><h2 id="RNN神经网络结构"><a href="#RNN神经网络结构" class="headerlink" title="RNN神经网络结构"></a>RNN神经网络结构</h2><div align=center><img src="RNN.png"/></div><p>由上图可以看出:一个典型的RNN网络包含一个输入x,一个输出h和一个神经网络单元A。和普通的神经网络不同的是,RNN网络的神经网络单元A与自身也存在一个回路。这种网络结构就揭示RNN的实质:上一个时刻的网络状态信息将会作用于下一个时刻的网络状态。RNN网络以时间序列展开成如下形式:</p><div align=center><img src="RNNs.png"/></div><p>如上图所示:{T0,T1,…,Tt}代表时间序列,{X0,X1,…,Xn}代表每个时间点输入的数据,{h0,h1,…,h(t-1)}代表时间点为(t-1)的状态。</p><p><strong>下面是在一个循环神经元中的步骤:</strong></p><ol><li>在一个时间点输入数据$X_t$;</li><li><p>根据上一个时间点状态$h_{(t-1)}$和当前输入数据$X_t$计算$h_{(t)}=f(h_{(t-1),X_t})$,详细计算公式如下:</p><script type="math/tex; mode=display">h_{(t)}=W_{(h)}h_{(t-1)}+W_{(x)}X_t</script><script type="math/tex; mode=display">\begin{aligned} &W_{(h)}: 上一个时间点状态和当前时间点的权重参数\\ &W_x: 当前时间点输入权重\end{aligned}</script></li><li>当前时间点的输出状态$h_{(t)}$作为(t+1)时刻的一个输入;</li><li>对于一个问题,我们可以通过许多时间步来将前面的状态信息联系起来;</li><li>所有的时间步走完后,我们用最终的输出状态来计算输出$y_t=W_{(o)}h_{(t)}$;</li><li>对神经元输出和真实值做差值,通过反向传播算法训练权重参数$W_{(h)}$和$W_{(x)}$</li></ol>]]></content>
<summary type="html"><h1 id="Recurrent-Neural-Network"><a href="#Recurrent-Neural-Network" class="headerlink" title="Recurrent Neural Network"></a>Recurrent Neural Network</h1></summary>
<category term="随笔" scheme="https://over-shine.github.io/categories/%E9%9A%8F%E7%AC%94/"/>
<category term="DL" scheme="https://over-shine.github.io/tags/DL/"/>
<category term="RNN" scheme="https://over-shine.github.io/tags/RNN/"/>
</entry>
<entry>
<title>Pytorch Geometric</title>
<link href="https://over-shine.github.io/2020/08/21/Pytorch-Geometric/"/>
<id>https://over-shine.github.io/2020/08/21/Pytorch-Geometric/</id>
<published>2020-08-21T13:58:05.000Z</published>
<updated>2021-11-06T06:40:26.942Z</updated>
<content type="html"><![CDATA[<h1 id="Pytorch-Geometric"><a href="#Pytorch-Geometric" class="headerlink" title="Pytorch Geometric"></a>Pytorch Geometric</h1><a id="more"></a><h2 id="图的数据处理"><a href="#图的数据处理" class="headerlink" title="图的数据处理"></a>图的数据处理</h2><p>图用于建模对象(节点)之间的成对关系(边)。Pytorch Geometric 中的单个图形由<code><code style="color:red;"></code>torch_geometric.data.Data<code></code></code> 的实例描述,该实例默认情况下具有以下属性:</p><!-- more --><ul><li><code><code style="color:red;"></code>data.x<code></code></code>: <code><code style="color:red;"></code>[num_nodes, num_node_features<code></code></code>,节点特征矩阵</li><li><code><code style="color:red;"></code>data.edge_index<code></code></code>: <code><code style="color:red;"></code>[2, num_edges]<code></code></code>,表示节点间的连接关系(边),<code><code style="color:red;"></code>edge_index[0]<code></code></code> 是源节点,<code><code style="color:red;"></code>edge_index[1]<code></code></code> 是目标节点</li><li><code><code style="color:red;"></code>data.edge_attr<code></code></code>: <code><code style="color:red;"></code>[num_edges, num_edge_features]<code></code></code>,边的特征矩阵</li><li><code><code style="color:red;"></code>data.y<code></code></code>: 节点级别的<code><code style="color:red;"></code>label,[num_nodes, <em>]<code></code></code>,或图级别的<code><code style="color:red;"></code>label,[1, </em>]<code></code></code></li><li><code><code style="color:red;"></code>data.pos<code></code></code>: <code><code style="color:red;"></code>[num_nodes, num_dimensions]<code></code></code>,节点位置矩阵</li></ul><p>这些属性都不是必需的。实际上,<code><code style="color:red;"></code>Data<code></code></code>对象甚至不限于这些属性。例如,我们可以通过data.face对其进行扩展,以将3D网格中的三角形的连通性保存在形状为<code><code style="color:red;"></code>[3,num_faces]<code></code></code>的张量中,并键入<code><code style="color:red;"></code>torch.long<code></code></code>。</p>]]></content>
<summary type="html"><h1 id="Pytorch-Geometric"><a href="#Pytorch-Geometric" class="headerlink" title="Pytorch Geometric"></a>Pytorch Geometric</h1></summary>
<category term="Pytorch" scheme="https://over-shine.github.io/categories/Pytorch/"/>
<category term="GNN" scheme="https://over-shine.github.io/tags/GNN/"/>
<category term="Pytorch" scheme="https://over-shine.github.io/tags/Pytorch/"/>
</entry>
<entry>
<title>N元语法</title>
<link href="https://over-shine.github.io/2020/08/21/N%E5%85%83%E8%AF%AD%E6%B3%95/"/>
<id>https://over-shine.github.io/2020/08/21/N%E5%85%83%E8%AF%AD%E6%B3%95/</id>
<published>2020-08-21T13:16:26.000Z</published>
<updated>2021-11-06T06:39:56.904Z</updated>
<content type="html"><![CDATA[<h1 id="N-元语法"><a href="#N-元语法" class="headerlink" title="$N$元语法"></a>$N$元语法</h1><a id="more"></a><p>给定一个单词序列“Please turn your homework…”,我们把猜测下一个单词的问题采用 <strong>N元语法模型(N-gram model)</strong> 这样的概率模型来形式化描述。$N$元语法法模型是根据前面出现的$N-1$个单词猜测下面一个单词。一个$N$元语法是包含$N$个单词的序列:1 元语法(一般称为unigram)是包含 1 个单词的序列,2 元语法(一般称为bigram)是包含 2 个单词的序列,3 元语法(一般称为trigram)是包含 3 个单词的序列。一个$N$元语法模型是根据前面出现的单词计算后一个单词的模型,这种单词序列的概率模型又称为语言模型(LM)。</p><p><strong>$N$元语法用处:</strong></p><ol><li>在噪声或者歧义的输入中辨认出单词;</li><li>机器翻译中,可以用于选择最通顺的译文;</li><li>在拼写中,可以用于发现并改正偶然的错误拼写;</li><li>词类标注、自然语言生成、单词相似度计算、匿名作者辨认、情感抽取,手机的预测式文本输入。</li></ol><h2 id="1-简单的(非平滑的)-N-元语法"><a href="#1-简单的(非平滑的)-N-元语法" class="headerlink" title="1. 简单的(非平滑的)$N$元语法"></a>1. 简单的(非平滑的)$N$元语法</h2><p>$N$元语法的目的是在给定了某个单词$w$的历史$h$的条件下,计算单词$w$的概率$P(w|h)$。假定历史$h$是“its water is so transparent that”,我们想知道这个历史$h$后面单词 the 的概率是多少:</p><script type="math/tex; mode=display">P(w=the|h=its\ water\ is \ so\ transparent\ that)</script><p>怎样计算这个概率?有以下两种方法,一种是基于相对频率计算;另一种是基于单词序列的联合概率计算。</p><h3 id="1-1-基于相对频率"><a href="#1-1-基于相对频率" class="headerlink" title="1.1 基于相对频率"></a>1.1 基于相对频率</h3><p>我们通过它们在语料库出现的次数来计算,公式如下:</p><script type="math/tex; mode=display">h+w=its\ water\ is\ so\ transparent\ that\ the</script><script type="math/tex; mode=display">P(w\ |\ h)=\frac{(h+w)在语料库中出现的次数}{h在语料库中出现的次数}</script><h3 id="1-2-给予单词序列的联合概率"><a href="#1-2-给予单词序列的联合概率" class="headerlink" title="1.2 给予单词序列的联合概率"></a>1.2 给予单词序列的联合概率</h3><p>我们用$ P(S)=P(w_1,w_2,\ldots,w_n) $来描述单词序列$S=(w_1,w_2,\ldots,w_n)$的概率:</p><script type="math/tex; mode=display">\begin{aligned} P(w_1,w_2,\ldots,w_n)&=P(w_1)P(w_2|w_1)P(w_3|w_1,w_2)\ldots P(w_n|w_1,w_2,\ldots,w_{n-1})\\ &=\prod_{i=1}^nP(w_i|w_1,w_2,\ldots,w_{i-1})\end{aligned}</script><p>当单词序列很长时,很难计算。所以,在计算某个单词的概率时,不是考虑他前面的全部历史,而是考虑最接近该单词的若干个单词,从而<strong>近似逼近</strong>该单词的历史。这就是$N$元语法模型的直觉解释。例如,我们只通过前面一个单词的条件概率$P(w_n|w_{n-1})$来逼近前面给定的所有单词的概率$P(w_n|w_1,w_2,\ldots,w_{n-1})$,这就是<strong>二元语法模型(bigram model)</strong>,如下公式</p><script type="math/tex; mode=display">P(w=the|h=its\ water\ is \ so\ transparent\ that)\approx P(w=the|h=that)</script><p>一个单词的概率只依赖于它前面单词的概率这种假设称为<strong>马尔可夫假设(Markov assumption)</strong></p><p>推广到 <strong>$N$元语法模型</strong>(看过去的$N-1$个单词),这样一来,在一个序列中,$N$元语法对于下一个单词的条件概率逼近的通用公式是:</p><script type="math/tex; mode=display">P(w_n|w_1,w_2,\ldots,w_{n-1})\approx P(w_n|w_{n-N+1},w_{n-N+2},\ldots,w_{n-1})</script><p>对于二元语法,只考虑前面一个单词的概率,则整个单词序列的概率是:</p><script type="math/tex; mode=display">P(w_1,w2,\ldots,w_n)\approx \prod_{i=1}^nP(w_i|w_{i-1})</script><p><strong>计算二元或$N$元语法的概率:</strong><br>估计这种概率最简单和最直观的方法是最大似然估计(Maximum Likelihood Estimation,MLE),可以把从语料库得到的计数<strong>归一化</strong>,从而得到$N$元语法模型参数的MLE估计,进行归一化后,概率都处于0和1之间。</p><hr><p>为了计算前面单词是$x$的条件下,单词$y$的二元语法概率,我们就要取第一个单词为$x$的所有二元语法$C(xy)$的计数(count,即出现次数),然后用第一个单词为$x$的所有二元语法的总数(即$x$出现的次数)作为除数来除这个计数,从而进行归一化:</p><script type="math/tex; mode=display">P(w_n|w_{n-1})=\frac{C(w_{n-1}w_n)}{\sum_wC(w_{n-1}w)}=\frac{C(w_{n-1}w_n)}{C(w_{n-1})}</script><p><strong>注意:</strong> 对于句子开头和结尾,如果采用$N$元语法,那么需要在句子开头添加$N-1$个特殊符号(如\<s>和\</s>),使得句子开头和结尾的单词具有$N$元语法的上下文。</p><p>如以下语料库:</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><s> I am Sam </s></span><br><span class="line"><s> Sam I am </s></span><br><span class="line"><s> I do not like green eggs and ham </s></span><br></pre></td></tr></table></figure><p>根据这个语料库,可以得到如下二元语法概率计算的一些结果:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">P(I|<s>)=\frac{2}{3}=0.67</span><br><span class="line">P(Sam|<s>)=\frac{1}{3}=0.33 </span><br><span class="line">P(am|I)=\frac{2}{3}=0.67</span><br><span class="line">P(</s>|Sam)=\frac{1}{2}=0.5</span><br><span class="line">P(Sam|am)=\frac{1}{2}=0.5</span><br><span class="line">P(do|I)=\frac{1}{3}=0.33</span><br></pre></td></tr></table></figure><p>推广到$N$元语法,MLE参数估计公式如下:</p><script type="math/tex; mode=display">P(w_n|w_{n-N+1},w_{n-N+2},\ldots,w_{n-1})==\frac{C(w_{n-N+1}\cdots w_{n-1}w_n)}{C(w_{n-N+1}\cdots w_{n-1})}</script>]]></content>
<summary type="html"><h1 id="N-元语法"><a href="#N-元语法" class="headerlink" title="$N$元语法"></a>$N$元语法</h1></summary>
<category term="随笔" scheme="https://over-shine.github.io/categories/%E9%9A%8F%E7%AC%94/"/>
<category term="NLP" scheme="https://over-shine.github.io/tags/NLP/"/>
</entry>
</feed>