-
graph2vec은 기존의 유명한 word2vec과 doc2vec의 방법을 착안해 Graph에서 subgraph를 추출하고 해당 subgraph를 임베딩 시켜 비슷한 그래프들은 비슷한 곳에 벡터화 될 것이라는 내용이다.
아래 블로거분이 너무 자세하게 설명해주셔서 이해가 쉬웠다. (사랑해요 😘 )
처음에 구현을 할려고했는데, 다행이 이미 나와있다. (사랑해요 😍)
나는 운이 좋은 사람이다. 이렇게 다 나와있다니 .. 훌쩍.. 😢
위 깃헙 코드는를 이용해 graph2vec을 사용해보고자 한다.
requirements는 다음과 같다.
jsonschema 2.6.0 tqdm 4.28.1 numpy 1.15.4 pandas 0.23.4 texttable 1.5.0 gensim 3.6.0 networkx 2.4 joblib 0.13.0 logging 0.4.9.6
- jsonschema: 위 코드는 데이터를 다룰때 json을 사용함.
- tqdm: 파이썬 코드 진행 과정을 알려준다. 얼마전에 처음알았는데, 너무 좋다 😄
- numpy, pandas는 워낙 유명하기때문에 pass, numpy는 수치 데이터 다룰때 좋고, pandas는 데이터 분석 시 유용하다.
- testtable: creating simple ASCII tables
- gensim: 최신 통계 기계 학습을 사용하여 비지도 및 자연어 처리 오픈소스 라이브러리
- networkx: 그래프 생성할 때 유용한 라이브러리다.
- joblib: 병렬 프로그래밍, 학습모델 저장, 디스크 캐싱
- logging: 응용 프로그램과 라이브러리를 위한 유연한 이벤트 로깅 시스템을 구현하는 함수와 클래스를 정의
위 깃헙 코드를 사용할 때 , 에러가 발생했다. 이는 파이썬 3.8이 기본으로 깔려있던 맥때문이였는데, 이때문에 파이썬 버전을 다운그레이하려고 노력했고, 그 결과 conda를 이용한 가상환경 설정으로 해결했다.
아래와같이 간단하게 돌려본 결과 아주 잘된다 ^>^ 아헤헤 기분좋당
위에서 사용된 데이터 파일을 열어보면 아래와 같다. 굉장히 간단하다.
노드와 엣지를 담은 json파일이다.
{"edges": [[11, 0], [11, 8], [10, 1], [10, 8], [10, 6], [13, 6], [13, 12], [13, 16], [12, 5], [12, 15], [15, 18], [14, 9], [14, 19], [14, 2], [17, 18], [17, 7], [17, 16], [3, 7], [5, 8], [4, 7], [9, 8]], "features": {"0": "14", "1": "1", "2": "1", "3": "1", "4": "1", "5": "2", "6": "2", "7": "2", "8": "3", "9": "3", "10": "3", "11": "3", "12": "3", "13": "3", "14": "3", "15": "3", "16": "3", "17": "3", "18": "3", "19": "3"}} 코드는 약 130줄로 굉장히 짧다. 라이브러리 import 한 것 줄바꿈 등등 .. 빼고 하면 거의 한 100줄..
흐름대로 코드를 분석해보자. 워낙 주석을 잘 달아놨고, 직관적으로 코드를 이쁘게 작성을 잘한탓에 바보라도 이해할 수 있을 정도이다...
존경,,, 코드 작성 방법도 많이 배울 수 있을 것 같아 분석해본다.
1. main ()
일단 가장 먼저 기본적으로 파라미터로 들어온 값들은 파서를 이용해서 나누어 전달한다.
document_collections = Parallel(n_jobs=args.workers)(delayed(feature_extractor)(g, args.wl_iterations) for g in tqdm(graphs))
위 코드를 뜯어보면 graph를 벡터화해 Doc2vec에 사용하기 위함이다.
Parallel은 joblibd에서 병렬처리를 가능케 해주는 함수이다. 이를 이용하여 workers 수대로 병렬처리를 하게 한다.
이 때, 병렬작업은 graph 마다 feature를 추출하고 가공한다.
함수 호출방법이 좀 특이한 것 같다. (feature_extractor)(g, args.wl_iterations) 이는 아래 함수를 호출한다.
2. def feature_extractor(path, rounds)
2-1.def dataset_reader(path)
말 그대로 json 파일을 읽어오고 읽어온 파일로부터 networkx를 이용해 graph를 생성한다. 본 코드를 보니 feature가 필수는 아닌 듯하다. 이를 이용하면 단순 패턴 비교로는 좋을 듯하다.
2-2. weisfeilerLehmanMachine(graph, features, rounds)
호출하면 바로 메서드인 do_recursion을 실행하고 반복횟수만큼 do_a_recursion을 실행한다. 아, 이렇게 필수 실행 함수는 바로 실행되도록 하는 방법 좋은 것 같다.
2-2-1. do_a_recursion
1) graph에 있는 노드를 하나씩 보면서 아래 코드를 실행한다.
#노드의 이웃을 nebs에 저장하고 nebs = self.graph.neighbors(node) #이웃노드를 받고 degs = [self.features[neb] for neb in nebs] #임베딩 features = [str(self.features[node])]\ +sorted([str(deg) for deg in degs]) features = "_".join(features) #hashlib를 이용하여 MD5( 128비트의 해시 값 )을 생성한다.(line 17까지) #str에 encode()함수를 사용하면, unicode hash_object = hashlib.md5(features.encode()) hashing = hash_object.hexdigest() new_features[node] = hashing # https://chioni.github.io/posts/gtv/ 위에 링크한 블로그분의 설명인데, 이 분은 tf를 이용해 구현한 코드를 분석하셨다. 아래와 알고리즘은 동일하다. get_int_node_label을 통해 이전 hob에서 취합한 sub graph 구조를 정수로 치환한다. ‘3+1’ (3노드 1노드) -> 31로 치환됨 ‘4+3’ (4노드 3노드) -> 43로 치환됨 새로운 라벨을 얻는 과정을 기준 노드 뿐 아니라 기준 노드의 이웃들에게도 수행한다. 새로 얻어진 라벨들을 다시 ‘+’ 로 묶어준다. (‘31+42’가 새로운 기준 노드의 라벨이 된다) 결론은 노드값을 str로 변환하고 이웃노드 값들을 모두 합친 뒤 해시값으로 그래프를 벡터화 시킨 것
* python encode 함수 사용해보기
그리고 바로 Doc2Vec() 함수를 이용하여 시작한다. Doc2vec은 gensim()에서 제공한다.
마지막으로 임베딩결과를 파일로 저장한다.(아래와 같이)
doc2vec 모델의 파라미터는 아래에서 확인할 수 있다.
radimrehurek.com/gensim/models/doc2vec.html
min_count (int, optional) – Ignores all words with total frequency lower than this.
sample (float, optional) – The threshold for configuring which higher-frequency words are randomly downsampled, useful range is (0, 1e-5).
alpha (float, optional) – The initial learning rate.
'2020년 > Development' 카테고리의 다른 글
Data munging (0) 2020.12.28 그래프 데이터에 대한 고찰 (0) 2020.12.18 딥러닝 공부 #3 (0) 2020.12.13 캐글을 써보자 (0) 2020.12.08 딥러닝 공부 #2 (0) 2020.12.07