Code Review) DyRep : Learning Representations over Dynamic Graphs

25678 단어 DyrepDyrep

Paper Review :

https://velog.io/@rlawlsgus117/Paper-Review-DyRep-Learning-Representations-over-Dynamic-Graphs

Original Source Code (not official)

https://github.com/code-ball/dynamic-embedding

Modified Source Code (for me)

https://github.com/KimJinHyeon0/dynamic-embedding

소스코드가 Official이 아니여서 애초에 코드가 돌지 않았고, 포함되어있던 Dataset도 불러오지 못 해서 전체적인 코드 검증이 필요했다.

Code

1. data_processing.py

기존 dataset인 Calls.csv / Proximity.csv / RElationshipsFromSurveys.csv / SMS.csv 대신에
web-Google Dataset을 수정해서 사용하기로 했다.

Google Web Graph Source:
https://www.kaggle.com/pappukrjha/google-web-graph

작업 내용

  1. Edge random shuffle
  2. 메인 코드에서 필요한 k(1) 추가 (전부 Communication으로 가정)
  3. Train : Test = 8 : 2
  4. 메인 코드에서 train data와 test data를 다른 파일로 불러오기 때문에 train / test 개별 저장
import numpy as np
import random

data_path = './data/web-Google.txt'
with open(data_path, 'r') as f:
    data = f.read().replace("\n", ",").split(",")
    del data[:5]

# add random k (0,1)
for i in range(len(data)):
    # random_k = random.randint(0, 1)
    # data[i] += '\t'+str(random_k)
    data[i] += '\t1'

#split into train/test
dataset = np.array(data)
dataset = np.random.permutation(dataset)
test_size = int(len(data)*0.2)
train_size = test_size * 4
test_data = dataset[:test_size]
train_data = dataset[test_size:]

#save files
f = open('./data/web-Google_dyrep_train.txt', 'w')
f.write('\n'.join(train_data))
f.close()
f = open('./data/web-Google_dyrep_test.txt', 'w')
f.write('\n'.join(test_data))
f.close()

2. data_loader.py 데이터 읽기 오류

1번에서 수정한 dataset을 읽는것도 중간에서 오류 발생했다.

400만개 정도 되는 Edge들 중에서 몇 개가 읽히지 않았다.
-> 일일히 범위 좁혀가면서 찾음

3471570번 데이터에 FromNode랑 ToNode가 없었다.
-> raw data는 빵꾸 없는데 왜 생긴지 모름 (?)

data_loader에서 3471570번 데이터만 삭제
(수정) data_processing 다시 돌리니 문제 해결 (일시적 오류였던 것 같다.)

3. torch.narrow

torch.narrow 언제 쓰는지 정확히 몰랐는데 짤짤이 털 때(?) 쓰는 듯하다.

...

    train_data = [[float(i) for i in train_data[p].split("\t")] for p in range(len(train_data)-1)]
    train_data = torch.from_numpy(np.array(train_data, dtype=float))
    print('original train_data : ', train_data.shape)
    train_batch_num = train_data.size(0) // batch
    train_data = train_data.narrow(0, 0, train_batch_num * batch) #짤 털기
    print('\nnarrowed train_data : ', train_data.shape)
    
...

그림으로 보면 이해가 빠르다 (짤짤이 30 삭제)

4. .cuda() 추가

cuda 설정이 안 되어있어서 .cuda() 추가

cuda = torch.device('cuda')

5. model.py - AttributeError: 'int' object has no attribute 'data'

111~112행에서 latest_embeddings.data를 int의 data로 불러오고 있었다. (수정)

v1.data -> v1
v2.data -> v2

6. main.py - IndexError: index 361554 is out of bounds for dimension 0 with size 100

web-Google.txt 문제인데 얘네는 node가 510000개면서 nodeid는 910000번대까지 있다.
그래서 IndexError 터진 듯.
-> opt.nodes (number of nodes in graph, default=100)를 여유있게 100만으로 줬다.

...

dynemb = dynemb(1000000, opt.emsize, opt.ndyn, opt.eval_batch_size)

...

7. main.py - TypeError: 'builtin_function_or_method' object is not subscriptable

batch마다 잘 돌길래 됐나보다 했더니 100 batch마다 돌아가는 구문에서 오류가 나왔다.

original code:

        if i % opt.log_interval == 0 and i > 0:
            cur_loss = total_loss.item[0] / opt.log_interval
            epoch_loss += cur_loss
            elapsed = time.time() - start_time
            print('| Epoch {:3d} | {:3d}/{:3d} batches | lr {:2.4f} | Training Time {:5.2f} s/batch | '
                    'Current Training Loss {:5.2f}'.format(
                epoch + 1, i, batch_num, lr,
                elapsed / opt.log_interval, cur_loss))
            total_loss = 0
            start_time = time.time()

main.py의 88행, 위 코드의 2행에서 오류가 떴다.
출력해보니 total_loss가 죄다 nan이였다.

거슬러 올라가보니 model.py에서 임베딩 칠 때가 문제였다.

8. model.py

    def forward(self, input, node_list, N, eval_phase=0):
        outputv1_intent = []
        outputv1_surv = []

        for i in range(input.size(0)):
            inp_tuple = input[i]

            v1 = int(inp_tuple.data[0])
            v2 = int(inp_tuple.data[1])
            l = int(inp_tuple.data[3])
            k = int(inp_tuple.data[4])

            if self.embed_available.data[int(inp_tuple.data[0])]:
                v1_emb = self.latest_embeddings[int(inp_tuple.data[0])].view(1, 1, self.em_size)
            else:
                emb_inp = Variable(torch.LongTensor([[int(inp_tuple.data[0])]]))
                v1_emb = self.initial_embeddings(emb_inp)
                self.embed_available.data[int(inp_tuple.data[0])] = 1

            if self.embed_available.data[int(inp_tuple.data[1])]:
                v2_emb = self.latest_embeddings[int(inp_tuple.data[1])].view(1, 1, self.em_size)
            else:
                emb_inp = Variable(torch.LongTensor([[int(inp_tuple.data[1])]]))
                v2_emb = self.initial_embeddings(emb_inp)
                self.embed_available.data[int(inp_tuple.data[1])] = 1

model.py의 82~83행과 89~90행, 위 코드의 11~12행과 18~19행 if문이 문제였다.

latest_embeddings 통과하고 나온 임베딩 값이 안 예쁘게(?) 나왔다.

latest_embeddings :

self.latest_embeddings = Variable(torch.zeros(nsize, em_size)).cuda()

(수정)
계속 보다보니 lastest_embeddings 자체는 문제가 없는 것으로 결론내렸다.

오히려 임베딩 거치고 나온 데이터들이 서로 같은 값인 것에 의문을 가지다가
문제 5번에서 v1.data -> v1로 고친 것이 잘못 되었음을 깨달았다.

원본 코드에서는 v1.data였는데, v1으로 고치는 것이 아닌, v1_emb로 고쳐야했다.

self.latest_embeddings.data[int(inp_tuple.data[0])] = v1_emb.data # origin = v1.data
self.latest_embeddings.data[int(inp_tuple.data[1])] = v2_emb.data # origin = v2.data

9. 시간 문제

연구실 서버가 있긴 하지만 지금 쓸 수 있는 상황이 아니라서 우선 급한대로 노트북으로 코드를 돌리고 있다.

배치 당 대략 4초 정도 걸리는데, 1 epoch당 13613 배치가 있으니 단순 계산만 잡아도
13613batch * 4sec = 54,452sec. 약 15시간이 걸린다. 1 에폭당 15시간인데 3에폭을 줬으니 45시간이 걸릴텐데 우선 두고봐야겠다.

10. IndexError

11. 새로운 데이터셋에서 작업 시작.

좋은 웹페이지 즐겨찾기