Task04:數(shù)據(jù)完整存儲與內(nèi)存的數(shù)據(jù)集類+節(jié)點預(yù)測與邊預(yù)測任務(wù)實踐

Datawhale提供的課程鏈接:https://github.com/datawhalechina/team-learning-nlp/blob/master/GNN

一、數(shù)據(jù)完全存于內(nèi)存的數(shù)據(jù)集類

對于占用內(nèi)存有限的數(shù)據(jù)集,我們可以將整個數(shù)據(jù)集的數(shù)據(jù)都存儲到內(nèi)存里。PyG為我們提供了方便的方式來構(gòu)造數(shù)據(jù)完全存于內(nèi)存的數(shù)據(jù)集類(簡稱為InMemory數(shù)據(jù)集類)。在此小節(jié)我們就將學(xué)習(xí)構(gòu)造InMemory數(shù)據(jù)集類的方式。

內(nèi)容安排如下:

首先,我們將學(xué)習(xí)PyG規(guī)定的使用數(shù)據(jù)的一般過程;

其次,我們將學(xué)習(xí)InMemoryDataset基類;

接著,我們將學(xué)習(xí)一個簡化的InMemory數(shù)據(jù)集類;

最后,我們將學(xué)習(xí)一個InMemory數(shù)據(jù)集類實例,以及使用該數(shù)據(jù)集類時會發(fā)生的一些過程。

PyG定義了使用數(shù)據(jù)的一般過程

1.從網(wǎng)絡(luò)上下載數(shù)據(jù)原始文件;

2.對數(shù)據(jù)原始文件做處理,為每一個圖樣本生成一個**Data對象**;

3.對每一個Data對象執(zhí)行數(shù)據(jù)處理,使其轉(zhuǎn)換成新的Data對象;

4.過濾Data對象;

5.保存Data對象到文件;

6.獲取Data對象,在每一次獲取Data對象時,都先對Data對象做數(shù)據(jù)變換(于是獲取到的是數(shù)據(jù)變換后的Data對象)。

實際中并非需要嚴格執(zhí)行每一個步驟。

1.InMemoryDataset基類簡介

在PyG中,我們通過繼承InMemoryDataset類來自定義一個數(shù)據(jù)可全部存儲到內(nèi)存的數(shù)據(jù)集類。

圖1.InMemoryDataset類

InMemoryDataset類初始化方法的參數(shù)說明:

root:字符串類型,存儲數(shù)據(jù)集的文件夾路徑。包含兩個文件夾,raw_dir和processed_dir。raw_dir用來存儲未處理的文件,即從網(wǎng)絡(luò)上下載的數(shù)據(jù)集原始文件會保存在里面。processed_dir保存處理后的數(shù)據(jù)。

transform:函數(shù)類型,一個數(shù)據(jù)轉(zhuǎn)換函數(shù),它接收一個Data對象并返回一個轉(zhuǎn)換后的Data對象。此函數(shù)在每一次數(shù)據(jù)獲取過程中都會被執(zhí)行。獲取數(shù)據(jù)的函數(shù)首先使用此函數(shù)對Data對象做轉(zhuǎn)換,然后才返回數(shù)據(jù)。此函數(shù)應(yīng)該用于數(shù)據(jù)增廣(Data Augmentation)。該參數(shù)默認值為None,表示不對數(shù)據(jù)做轉(zhuǎn)換。

pre_transform:函數(shù)類型,一個數(shù)據(jù)轉(zhuǎn)換函數(shù),它接收一個Data對象并返回一個轉(zhuǎn)換后的Data對象。此函數(shù)在Data對象被保存到文件前調(diào)用。因此它應(yīng)該用于只執(zhí)行一次的數(shù)據(jù)預(yù)處理。該參數(shù)默認值為None,表示不做數(shù)據(jù)預(yù)處理。

pre_filter:函數(shù)類型,一個檢查數(shù)據(jù)是否要保留的函數(shù),它接收一個Data對象,返回此Data對象是否應(yīng)該被包含在最終的數(shù)據(jù)集中。此函數(shù)也在Data對象被保存到文件前調(diào)用。該參數(shù)默認值為None,表示不做數(shù)據(jù)檢查,保留所有的數(shù)據(jù)。

通過繼承InMemoryDataset類來構(gòu)造一個我們自己的數(shù)據(jù)集類,我們需要實現(xiàn)四個基本方法:

圖2.構(gòu)造的數(shù)據(jù)集類包含的基本方法

2.一個簡化的InMemory數(shù)據(jù)基類

圖3. 一個簡化的 InMemory數(shù)據(jù)基類

其中,class中的@property的使用方法可以參考博客https://blog.csdn.net/weixin_44232308/article/details/104897924,@property是一個裝飾器,作用是把類中的方法變成屬性來調(diào)用。

raw_file_names屬性方法中,寫上數(shù)據(jù)集原始文件有哪些,再此例子中有some_file_1,some_file_2等。

processed_file_names屬性方法里,表示處理過的數(shù)據(jù)要保存在哪些文件中,這里的例子只有“data.pt”

download方法里,我們實現(xiàn)下載數(shù)據(jù)到self.raw_dir文件夾的邏輯。

process方法里,我們實現(xiàn)數(shù)據(jù)處理的邏輯:

1.首先,我們從數(shù)據(jù)集原始文件中讀取樣本并生成Data對象,所有樣本的Data對象保存在列表data_list中。

2.其次,如果要對數(shù)據(jù)做過濾的話,我們執(zhí)行數(shù)據(jù)過濾的過程。

3.接著,如果要對數(shù)據(jù)做處理的話,我們執(zhí)行數(shù)據(jù)處理的過程。

4.最后,我們保存處理好的數(shù)據(jù)到文件。但由于python保存一個巨大的列表是相當(dāng)慢的,我們需要先將所有Data對象合并成一個巨大的Data對象再保存。collate()函數(shù)接收一個列表的Data對象,返回合并后的Data對象以及用于從合并后的Data對象重構(gòu)各個原始Data對象的切片字典slices。最后我們將這個巨大的Data對象和切片字典slices保存到文件。

3.InMemoryDataset數(shù)據(jù)集類實例

我們以公開數(shù)據(jù)集PubMed為例子,進行InMemoryDataset數(shù)據(jù)集實例分析。PubMed?數(shù)據(jù)集存儲的是文章引用網(wǎng)絡(luò),文章對應(yīng)圖的結(jié)點,如果兩篇文章存在引用關(guān)系(無論引用與被引用),則這兩篇文章對應(yīng)的結(jié)點之間存在邊。該數(shù)據(jù)集來源于論文Revisiting Semi-Supervised Learning with Graph Embeddings。PyG中的Planetoid數(shù)據(jù)集類包含了數(shù)據(jù)集PubMed的使用,因此我們直接基于Planetoid類進行修改,得到PlanetoidPubMed數(shù)據(jù)集類。

圖4. PlanetoidPubMed數(shù)據(jù)集類的構(gòu)造
圖5. PlanetoidPubMed數(shù)據(jù)集類的使用

二、節(jié)點預(yù)測和邊預(yù)測任務(wù)實踐

1.節(jié)點預(yù)測任務(wù)

圖6.導(dǎo)入庫
圖7.定自己的PlanetoidPubMed數(shù)據(jù)集類
圖8.定義數(shù)據(jù)集并把數(shù)據(jù)集放到GPU上
圖9.定義模型、模型訓(xùn)練函數(shù)、模型測試函數(shù)

這里我們模型選用GAT圖神經(jīng)網(wǎng)絡(luò),使其能夠通過參數(shù)來定義GATConv的層數(shù),以及每一層GATConv的out_channels。

圖10.調(diào)用定義好的模型
圖11.定義損失函數(shù)和優(yōu)化器
圖12.運行結(jié)果

2.邊預(yù)測任務(wù)

邊預(yù)測任務(wù)的目標時預(yù)測兩個節(jié)點之間是否存在邊。拿到一個圖數(shù)據(jù),我們有節(jié)點屬性x,邊端點edge_index.edge_index存儲的是正樣本。為了構(gòu)建邊預(yù)測任務(wù),我們需要生成一些負樣本,即采樣一些不存在邊的節(jié)點對作為負樣本邊,正負樣本數(shù)量應(yīng)平衡。此外要將樣本分為訓(xùn)練集、驗證集和測試集三個集合。

圖13.PyG采樣負樣本方法

2.1 獲取數(shù)據(jù)集并分析

圖14.獲取數(shù)據(jù)集并分析

我們觀察到:

263 + 527 + 8976 = 9766 != 10556

263 + 527 + 8976/2 = 5278 = 10556/2

數(shù)據(jù)集中訓(xùn)練集、驗證集和測試集中正樣本邊的數(shù)量之和不等于原始邊的數(shù)量。這是因為現(xiàn)在所用的Cora圖是無向圖,在統(tǒng)計原始邊數(shù)量時,每一條邊的正向與反向各統(tǒng)計了一次,訓(xùn)練集也包含邊的正向與反向,但驗證集與測試集都只包含邊的一個方向。

為什么訓(xùn)練集要包含邊的正向和反向,而驗證集與測試集都只包含了邊的一個方向?這是因為,訓(xùn)練集用于訓(xùn)練,訓(xùn)練時一條邊的兩個端點要互傳消息,只考慮一個方向的話,只能由一個端點傳信息給另一個端點,而驗證集與測試集的邊用于衡量檢驗邊預(yù)測的準確性,只需考慮一個方向的邊即可。

2.2 圖神經(jīng)網(wǎng)絡(luò)的構(gòu)造

圖15.圖神經(jīng)網(wǎng)絡(luò)的構(gòu)造

2.3 圖神經(jīng)網(wǎng)絡(luò)的訓(xùn)練

圖16.單個epoch訓(xùn)練過程
圖17.單個epoch驗證和訓(xùn)練過程
圖18.運行完整的訓(xùn)練、驗證和測試

三、作業(yè)

圖19.作業(yè)

思考問題:

圖20.思考問題

實踐問題一就在節(jié)點分類任務(wù)的代碼中,導(dǎo)入GCNConv的庫,然后更改模型代碼里的GATConv為GCNConv即可。

實踐問題二待解決??!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容