天天看點

1運作GCN和DeepWalk目錄第一課:圖學習初印象習題

百度飛漿PGL圖神經網絡學習心得-1

  • 目錄
    • Paddlepaddle
    • PGL本地運作出現的問題
  • 第一課:圖學習初印象習題
    • 1. 環境搭建
    • 2. 下載下傳PGL代碼庫
    • 3. 運作示例
      • 3.1 GCN
      • 3.2 DeepWalk
    • 4 PGL相關資訊
    • 5. 代碼架構梳理
      • 5.1 參數設定
      • 5.2 資料預處理
      • 5.3 模型建構
      • 5.4 模型訓練和測試

目錄

這是我第一次在CSDN上發文章,之前寫代碼參考了無數篇CSDN上面的文章和code,也曾經想過自己寫一寫平常遇到的技術和代碼難點,但總是因為懶是以一直擱置(咕咕咕)。有這個想法不是說想給别人有多大啟發與借鑒,主要是為了記錄自己的學習心得。

這次參與了百度飛漿PGL圖神經網絡訓練營,其中一個結營作業就是寫一篇結營感想,既然總要寫,那不如順便就開始在CSDN上寫啦!這篇文章是圖神經網絡學習感想及課後作業的第一篇,以後有時間應該會繼續更下去(要是有時間的話!!!)。

Paddlepaddle

深度學習的架構很多,tensorflow、pytorch等很受關注。國内的開源深度學習架構我目前在學習使用的就是百度飛漿paddlepaddle。(PS:英文不好,用飛漿的話,遇到問題可以在中文讨論區裡面找答案,而且配備了非常完善的各種視訊教程,對剛接觸這個架構的人很友好)

安裝推薦使用annaconda,可以省很多事(加一下國内的清華源)

飛槳安裝文檔:https://paddlepaddle.org.cn/install/quick

圖檔:

1運作GCN和DeepWalk目錄第一課:圖學習初印象習題

提示:使用 python 進入python解釋器,輸入import paddle.fluid ,再輸入 paddle.fluid.install_check.run_check()。

如果出現 Your Paddle Fluid is installed successfully!,說明您已成功安裝。

顯示如下就算成功了:

1運作GCN和DeepWalk目錄第一課:圖學習初印象習題

本地安裝PaddlePaddle的常見錯誤:https://aistudio.baidu.com/aistudio/projectdetail/697227

手把手教你 win10 安裝Paddlepaddle-GPU:https://aistudio.baidu.com/aistudio/projectdetail/696822

PGL本地運作出現的問題

第一天的作業還是比較簡單的,運作GCN和deepwalk模型就好。

但我使用pycharm進行本地運作時,一直存在dll not load找不到指定子產品的問題:

1運作GCN和DeepWalk目錄第一課:圖學習初印象習題

在這裡非常感謝訓練營裡面的老師,很耐心細緻的幫我解決了問題,可參考如下連結裡的方法,pycharm配置一下conda 虛拟環境環境路徑:

1運作GCN和DeepWalk目錄第一課:圖學習初印象習題

第一課:圖學習初印象習題

搭建環境,運作GCN和DeepWalk。

1. 環境搭建

# !pip install paddlepaddle==1.8.5 # 安裝PaddlePaddle
!pip install pgl # 安裝PGL
           

2. 下載下傳PGL代碼庫

# 由于 AIStudio 上通路 github速度比較慢,是以我們提供已經下載下傳好了的 PGL 代碼庫
# !git clone --depth=1 https://github.com/PaddlePaddle/PGL
!ls PGL # 檢視PGL庫根目錄
           

3. 運作示例

3.1 GCN

GCN層的具體實作見 PGL/pgl/layers/conv.py

NOTE:

  1. 在GCN模型中,對于圖中的某個節點N,相鄰節點會将學到的資訊發送給它。節點N根據節點的度數給收到的資訊加上權重,組合起來作為它新的表示向量。
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/sklearn/externals/joblib/externals/cloudpickle/cloudpickle.py:47: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
  import imp
[INFO] 2020-11-24 14:35:23,012 [    train.py:  153]:	Namespace(dataset='cora', epochs=100, use_cuda=False)
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/numpy/core/fromnumeric.py:3118: RuntimeWarning: Mean of empty slice.
  out=out, **kwargs)
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/numpy/core/_methods.py:85: RuntimeWarning: invalid value encountered in double_scalars
  ret = ret.dtype.type(ret / rcount)
[INFO] 2020-11-24 14:35:24,072 [    train.py:  135]:	Epoch 0 (nan sec) Train Loss: 1.946185 Train Acc: 0.142857 Val Loss: 1.937398 Val Acc: 0.350000 
[INFO] 2020-11-24 14:35:24,115 [    train.py:  135]:	Epoch 1 (nan sec) Train Loss: 1.935671 Train Acc: 0.342857 Val Loss: 1.927820 Val Acc: 0.523333 
[INFO] .......此處太多,故省略
[INFO] 2020-11-24 14:35:28,392 [    train.py:  135]:	Epoch 99 (0.02773 sec) Train Loss: 0.696660 Train Acc: 0.864286 Val Loss: 0.935254 Val Acc: 0.793333 
[INFO] 2020-11-24 14:35:28,408 [    train.py:  143]:	Accuracy: 0.759000
           

3.2 DeepWalk

模型代碼詳見 PGL/examples/deepwalk/deepwalk.py

NOTE:

  1. DeepWalk的主要原理是通過随機遊走生成節點路徑,然後将其作為詞向量模型SkipGram的輸入來學習節點表示。
  2. DeepWalk 模型會在第二節課詳細介紹。

Step1 學習節點表示

檢視deepwalk.py中的parser(239行起),修改不同參數的值,觀察其對訓練結果的影響,比如遊走路徑長度walk_len,SkipGram視窗大小win_size等

Tips

  1. 如果出現記憶體不足的問題,可以調小batch_size參數
  2. 以下設定的參數為了讓同學們可以快速跑出結果,設定的 epoch、walk_len、hidden_size 均比較小,可以自行嘗試調大這些值。
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/sklearn/externals/joblib/externals/cloudpickle/cloudpickle.py:47: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
  import imp
[INFO] 2020-11-24 14:36:01,632 [ deepwalk.py:  258]:	Namespace(batch_size=256, dataset='ArXiv', epoch=2, hidden_size=10, neg_num=20, offline_learning=True, processes=1, save_path='./tmp/deepwalk_ArXiv', use_cuda=False, walk_len=10, win_size=10)
[INFO] 2020-11-24 14:36:02,430 [ deepwalk.py:  172]:	Start random walk on disk...
[INFO] 2020-11-24 14:36:03,184 [ deepwalk.py:  182]:	Random walk on disk Done.
[INFO] .......此處太多,故省略
[INFO] 2020-11-24 14:36:03,601 [ deepwalk.py:  228]:	Step 0 Deepwalk Loss: 0.724576  0.372420 s/step.
[INFO] 2020-11-24 14:39:34,124 [ deepwalk.py:  228]:	Step 1450 Deepwalk Loss: 0.538972  0.078368 s/step.
           

Step2 連結預測任務上的測試

這裡選用的資料集是ArXiv,它包含了天體實體學類的論文作者間的合作關系圖,得到的節點表示存儲在 ./tmp/deepwalk_Arxiv

/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/sklearn/externals/joblib/externals/cloudpickle/cloudpickle.py:47: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
  import imp
[INFO] 2020-11-24 14:40:44,192 [link_predict.py:  233]:	Namespace(batch_size=None, ckpt_path='./tmp/deepwalk_Arxiv/paddle_model', dataset='ArXiv', epoch=50, hidden_size=128, use_cuda=False)
2020-11-24 14:40:44,980-WARNING: paddle.fluid.layers.py_reader() may be deprecated in the near future. Please use paddle.fluid.io.DataLoader.from_generator() instead.
2020-11-24 14:40:44,999-WARNING: paddle.fluid.layers.py_reader() may be deprecated in the near future. Please use paddle.fluid.io.DataLoader.from_generator() instead.
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/executor.py:1093: UserWarning: There are no operators in the program to be executed. If you pass Program manually, please use fluid.program_guard to ensure the current Program is being used.
  warnings.warn(error_info)
[INFO] 2020-11-24 14:40:45,836 [link_predict.py:  215]:		Step 1 Test Loss: 0.693220 Test AUC: 0.503291 
[INFO] 2020-11-24 14:40:46,125 [link_predict.py:  215]:		Step 2 Test Loss: 0.693154 Test AUC: 0.504987 
[INFO] .......此處太多,故省略
[INFO] 2020-11-24 14:40:59,882 [link_predict.py:  192]:	Step 50 Train Loss: 0.693121 Train AUC: 0.528213 
[INFO] 2020-11-24 14:41:00,010 [link_predict.py:  215]:		Step 50 Test Loss: 0.693128 Test AUC: 0.520660 
           

4 PGL相關資訊

pip install pgl # 安裝PGL

git clone --depth=1 https://github.com/PaddlePaddle/PGL #下載下傳PGL代碼庫(或者直接把左邊檔案中的下載下傳到本地)
	
# 運作示例-GCN
cd PGL/examples/gcn; python train.py --epochs 100 # 切換到gcn的目錄,運作train.py在cora資料集上訓練  
           

5. 代碼架構梳理

本小節以GCN的 PGL/examples/gcn/train.py 為例,簡單介紹一下圖模型的訓練架構。

5.1 參數設定

可修改parser的參數來使用不同的資料集進行訓練

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='GCN')
    # 設定資料集,預設選擇cora資料集
    parser.add_argument(
        "--dataset", type=str, default="cora", help="dataset (cora, pubmed)")
    # 設定是否使用GPU
    parser.add_argument("--use_cuda", action='store_true', help="use_cuda")
    args = parser.parse_args()
    log.info(args)
    main(args)
           

5.2 資料預處理

讀取資料後,需要進行一些預處理,例如GCN中對圖中節點度數進行了标準化

dataset = load(args.dataset)

indegree = dataset.graph.indegree()
norm = np.zeros_like(indegree, dtype="float32")
norm[indegree > 0] = np.power(indegree[indegree > 0], -0.5)
dataset.graph.node_feat["norm"] = np.expand_dims(norm, -1)
           

5.3 模型建構

Step1 執行個體化GraphWrapper和Program

  • 定義train_program、startup_program和test_program等程式
place = fluid.CUDAPlace(0) if args.use_cuda else fluid.CPUPlace()
  train_program = fluid.Program()
  startup_program = fluid.Program()
  test_program = fluid.Program()
           
  • 執行個體化GraphWrapper,它提供了圖的基本資訊,以及GNN算法message passing機制中的send和receive兩個接口。
with fluid.program_guard(train_program, startup_program): 
    gw = pgl.graph_wrapper.GraphWrapper(
        name="graph",
        place=place,
        node_feat=dataset.graph.node_feat_info())
           

Step2 模型定義

在train_program中定義要使用的模型結構,這裡是雙層的GCN模型

output = pgl.layers.gcn(gw,
                            gw.node_feat["words"],
                            hidden_size,
                            activation="relu",
                            norm=gw.node_feat['norm'],
                            name="gcn_layer_1")
    output = fluid.layers.dropout(
        output, 0.5, dropout_implementation='upscale_in_train')
    output = pgl.layers.gcn(gw,
                            output,
                            dataset.num_classes,
                            activation=None,
                            norm=gw.node_feat['norm'],
                            name="gcn_layer_2")
           

Step3 損失函數計算

  • node_index和node_label定義了有标簽樣本的資料下标和标簽資料
node_index = fluid.layers.data(
        "node_index",
        shape=[None, 1],
        dtype="int64",
        append_batch_size=False)
    node_label = fluid.layers.data(
        "node_label",
        shape=[None, 1],
        dtype="int64",
        append_batch_size=False)
           
  • 使用gather函數找出output中有标簽樣本的預測結果後,計算得到交叉熵損失函數值以及準确度
pred = fluid.layers.gather(output, node_index)
    loss, pred = fluid.layers.softmax_with_cross_entropy(
        logits=pred, label=node_label, return_softmax=True)
    acc = fluid.layers.accuracy(input=pred, label=node_label, k=1)
    loss = fluid.layers.mean(loss)
           

Step4 構造測試程式

複制構造test_program的靜态圖。到此為止,train_program和test_program的靜态圖結構完全相同,差別在于test_program不需要梯度計算和反向傳播過程。

Step5 定義優化器

為了實作train_program上的參數更新,需要定義優化器和優化目标,這裡是用Adam最小化loss

with fluid.program_guard(train_program, startup_program):
    adam = fluid.optimizer.Adam(
        learning_rate=1e-2,
        regularization=fluid.regularizer.L2DecayRegularizer(
            regularization_coeff=0.0005))
    adam.minimize(loss)
           

5.4 模型訓練和測試

模型建構完成後,就可以定義一個Executor來執行program了

Step1 初始化

執行startup_program進行初始化

Step2 資料準備

将預處理階段讀取到的資料集填充到GraphWrapper中,同時準備好訓練、驗證和測試階段用到的樣本下标和标簽資料

feed_dict = gw.to_feed(dataset.graph)

train_index = dataset.train_index
train_label = np.expand_dims(dataset.y[train_index], -1)
train_index = np.expand_dims(train_index, -1)

val_index = dataset.val_index
val_label = np.expand_dims(dataset.y[val_index], -1)
val_index = np.expand_dims(val_index, -1)

test_index = dataset.test_index
test_label = np.expand_dims(dataset.y[test_index], -1)
test_index = np.expand_dims(test_index, -1)
           

Step3 訓練和測試

給Executor分别傳入不同的program來執行訓練和測試過程

  • feed以字典形式給定了輸入資料 {變量名:numpy資料}
  • fetch_list給定了模型中需要取出結果的變量名,可以根據需要自行修改
dur = []
for epoch in range(200):
    if epoch >= 3:
        t0 = time.time()
    feed_dict["node_index"] = np.array(train_index, dtype="int64")
    feed_dict["node_label"] = np.array(train_label, dtype="int64")
    train_loss, train_acc = exe.run(train_program,
                                        feed=feed_dict,
                                        fetch_list=[loss, acc],
                                        return_numpy=True)

	# 3個epoch後,統計每輪訓練執行的時間然後求均值。
    if epoch >= 3:
        time_per_epoch = 1.0 * (time.time() - t0)
        dur.append(time_per_epoch)
    feed_dict["node_index"] = np.array(val_index, dtype="int64")
    feed_dict["node_label"] = np.array(val_label, dtype="int64")
    val_loss, val_acc = exe.run(test_program,
                                    feed=feed_dict,
                                    fetch_list=[loss, acc],
                                    return_numpy=True)

    log.info("Epoch %d " % epoch + "(%.5lf sec) " % np.mean(dur) +
                 "Train Loss: %f " % train_loss + "Train Acc: %f " % train_acc
                 + "Val Loss: %f " % val_loss + "Val Acc: %f " % val_acc)

feed_dict["node_index"] = np.array(test_index, dtype="int64")
feed_dict["node_label"] = np.array(test_label, dtype="int64")
test_loss, test_acc = exe.run(test_program,
                                  feed=feed_dict,
                                  fetch_list=[loss, acc],
                                  return_numpy=True)
log.info("Accuracy: %f" % test_acc)
           

圖模型訓練的基本架構大概就是這樣啦,下次再見咯~

繼續閱讀