학습일지/AI

성균관대 "AI로 글쓰기" 해커톤 - OpenAI GPT-2 한글 transfer learning 작업기 (2)

inspirit941 2020. 1. 21. 12:11
반응형

19.11.23 ~ 24일. 성균관대에서 진행한 딥러닝으로 글쓰기 해커톤 대회 참여 및 작업기.

 

 

교내 학부생 및 대학원생을 대상으로 처음 진행한 '딥러닝으로 글쓰기' 교내 해커톤이며.

마인즈랩 (https://mindslab.ai/kr) 에서 제공한 OpenAI GPT-2의 한글 pretrained 모델을 참여 팀에게 제공하고

교내 Tesla V100 GPU 1대씩 지원했다.

정원은 총 10팀이었으나 참여자가 많다는 이유로 추가 5팀을 받고, 5팀은 네이버 클라우드 쪽 회사의 서버를 이용할 수 있게 해 줬다.

 

본 행사를 시작하기 약 1주일 전부터 서버와 글 형식 (수필)을 공지했고,

일주일의 training 기간을 거쳐 행사 당일에 주제를 발표하는 방식이었다.

분량은 10,000자 이내. 주제는 '만약 (if)' 두 글자였다.

 

 

행사 시작 후 안내받기로는 마인즈랩에서 서비스하고 있는 '문장 생성' 서비스에서 사용하는 모델이라고 했다. 
54개의 뉴스 카테고리, 총 1,000만 개의 뉴스 데이터로 GPT-2 모델을 학습시켰다고 하며, 해당 모델을 학생들에게 제공했다.

 

 

https://maum.ai/login/loginForm?lang=ko

 

maum.ai platform

Voice 앨범 We call it LOVE! 소중한 사람의 목소리를 언제 어디서든 들을 수 있는 AI 감성 서비스! 자세히보기

maum.ai

 

작업했던 내용들은

https://github.com/inspirit941/gpt_hackathon

 

inspirit941/gpt_hackathon

Contribute to inspirit941/gpt_hackathon development by creating an account on GitHub.

github.com

에서 확인할 수 있다. 단, 재연은 불가능하다. GPT-2 모델 업로드는 하지 않았기 때문.

 


3. 텍스트 데이터 수집하기

 

19. 11. 13일에 GPT-2 알고리즘과 작성해야 할 글 형식을 안내받았는데, '수필'이라는 형식이 참 난감했다.

주제도 따로 없고, 형식도 상대적으로 자유로운 게 수필이니까.

 

심지어 수필 형식도 1990년대나 2000년대 초에는 소설처럼 긴 글과 긴 호흡을 가져가는 방식이었다면,

요즘 수필은 '언어의 온도'같은 책으로 대표할 만한 '아름답고 있어 보이며 힐링할 수 있는' 짧은 글 형식을 띠고 있다.

'수필'이라기보다는 '에세이'에 가깝다고 할까.

사실 수필과 에세이는 같은 단어이지만, 요즘 수필은 짧은 글토막을 모아 '에세이'라는 이름으로 팔리고 있다.

 


 

내가 속한 팀은 나를 제외한 나머지 전부 다 소프트웨어학과 사람들이었는데,

 

1) 지금까지 주어진 정보는 "주제도 모르고 형식도 미정"이다.

2) GPT-2 알고리즘으로 '10,000자'가 넘는 수준의 긴 글을 일관성 있게 작성하는 건 불가능하다.

3) 그러면, 요즘 수필이나 에세이처럼 '짧은 토막글'의 모음 형태를 만들어보자.

 

세 가지 의견에 합의했다.

 

그러면 '짧은 에세이 형태의 글'이 필요한데,

나는 여기서 브런치 에세이 / 수필 데이터를 가져오기로 했다.

 

 


브런치 웹페이지의 구조를 뜯어보니 크게 세 번의 requests로 데이터를 가져올 수 있어 보였다.

 

1. 브런치는 'keyword' 쿼리를 입력받아, 해당 키워드가 잘 어울리는 작가를 추천해준다.

스크롤 다운 형식의 웹페이지로, 하나의 키워드당 대략 500명 정도의 브런치 작가가 API 형태로 전달된다.

-> 이 브런치 API에서, 브런치 작가의 ID (@ID 형태) 데이터와 그 사람이 쓴 가장 최근의 Post ID를 전부 가져온다.

brunch.co.kr/keyword/profile/에세이 url의 화면. 여기 등장하는 작가들의 @ID값을 전부 받아온다

"에세이스트, 에세이, 수필, 문학, 출간작가, 칼럼니스트" 등 총 12개의 키워드를 선정했다.

주제가 무엇일지도 모르고 형식도 모르니, '문법적인 비문이 적으면서도 문학성이 있는 글'을 최대한 모아야 했다.

 

2. 수집한 ID별로, 그 사람이 쓴 모든 글을 스크래핑한다.

예컨대 이 분, 이 분의 브런치 ID는  @binkond다. brunch.co.kr/@binkond를 url에 입력하면 얻을 수 있다.

브런치는 브런치url/@작가ID/포스트ID 형태로 클라이언트가 get 요청을 보내면 텍스트 데이터를 돌려준다.

그리고, 글을 썼다 지워도 포스트ID는 줄어들지 않는다.

3번 글을 썼다 지우면 3번 post id로 get 요청을 했을 때 '존재하지 않는 페이지입니다'를 반환하는 식이다.

 

그러면, 해당 ID에서 가장 최근에 쓴 포스트 ID를 가져오고, 이 값을 1까지 내리면서 request를 반복하면

모든 글을 가져올 수 있다.

 

3. 약간의 전처리

 

브런치 글들을 보면, 머릿말에 '누구누구의 명언'을 모든 포스트에 동일하게 적어 두거나 꼬릿말에 '한줄 자기소개' 같은 표현이 나온다.

즉, 모든 텍스트에서 동일한 패턴이 반복되는 글이 존재한다.

 

GPT-2 알고리즘은 '학습한 데이터를 토대로 나타나는, 특정 단어 다음에 가장 attention이 높게 나타나는 단어'를 학습하기 때문에,

이렇게 동일한 패턴이 반복되는 텍스트는 피해야 한다.

 

 

결국 웹 스크래핑 과정에서 각 텍스트 자체는 html 문서로 주어지고, 본문은 Line by Line으로 읽어들이기 때문에

각 Line을 python set에 저장하고,

해당 Line이 이미 python set에 들어 있으면 그 문장은 학습 데이터셋에서 제외하는 식으로 중복을 제거했다.

 

크롤링 코드는 저장을 따로 안 하다보니, 발표에 쓰려고 스크린샷을 찍어뒀던 것밖에 남은 게 없네... 아깝다.

위에서 설명한 논리 그대로다.

 

a = set()으로 중복문장을 저장할 자료구조를 설정해두고,

1부터 해당 @ID의 마지막 포스트까지 for문을 반복한다.

본문을 의미하는 html <p>를 parser.select()로 가져온 뒤, get_text()로 텍스트를 가져왔을 때 a 안에 이미 있으면 저장하지 않는다.

 

저 때는 제대로 가져오는지 확인하려고 모든 포스트를 .txt 파일에 저장했지만,

제대로 작동하는 것을 확인한 후에는 pandas DataFrame으로 한 번에 csv 파일로 저장했다.

 

except를 사용한 이유는, request를 반복해서 보내다 보면 서버 측에서 operation time out Exception을 반환했기 때문이다.

데이터가 없는 게 아니라 request를 보내다 보니 생긴 오류라서, 해당 포스트 id만 err에 따로 저장해두고

err 리스트 안에 있는 ID만 한 번 더 for loop을 돌았다.

그러면 오류 없이 모든 포스트를 가져올 수 있다.

 


이렇게 가져온 총 데이터는

약 36만 개 게시글, hdf5 파일로 변환했을 시 약 1.75GB 분량이었다.

이 작업을 완료했을 때가 행사 시작 3일 전이었다.

 

이렇게 만들어낸 텍스트 파일을 tokenization.py를 써서 변환하고,

hdf5 파일로 변환한 다음 모델 학습을 시작했다.

변환 코드는 github의 data/data_preprocess/make_hdf5.ipynb에서 확인할 수 있다.

 

19.11.21 오후 4시까지의 학습 경과.

다량의 데이터를 학습시키는 과정이었지만, 만 하루 정도 모델을 돌렸을 때 (batch size 6, iteration 14만 번)

loss는 3.4 -> 1.7까지 감소하는 걸 확인했고,

학습 모델이 만들어낸 test 문장은 아직 문법적으로 완전하진 않지만 꽤 흥미로운 결과들을 담아냈다.


소프트웨어학과 3명 + 유사 소프트웨어학과 1명이 머리 맞대도 써내지 못할 문장들

 

'그저 손을 뻗으면 쉽게 녹는 종이봉투에 서로에게 사랑을 담아 말을 건네 보려 한다',

"나"를 만나면 그 사람은 그저 '나' 였던 것 같고, "너"를 만나면 나는 완전히 다른 사람이 되었다 라고 얘기하고 싶었다.

 

"택배 상자를 손에 쥔 손끝에 온기가 퍼져나간다. 그리고 그 온기가 다시 나를 따뜻하게 데우는 데까지 한다."

"나의 작은 행동들은 결국 그때 내가 느꼈던 따뜻함이라는 것과 꼭 닮아서 누군가에게 사랑받는 그런 삶이 되어가고 있다"

 

딥러닝이 쓰는 언어유희

"나의 아이디어가 사장되는 상황에서 사장이 되면 어떻게 될까?"

명사 '사장'과 동사 '사장'을 한 문장에 표현하면서도, 문법적으로 틀리거나 의미가 없는 문장은 아니다.

딥러닝의 '뇌피셜'.

뇌피셜에 따르면, 인간은 본질을 볼 수 없다 (by AI).

학습 데이터가 뭐였는지는 몰라도, AI가 뇌피셜이라는 단어를 언급했다는 게 재미있었다.

심지어 '인간은 본질을 볼 수 없다'고 AI가 뇌피셜로 선언해버린다.


 

학습이 잘 되고 있는 걸 확인하고, 행사 당일까지 중간중간 학습 경과만 확인하면 되겠다 싶었다.

행사 당일인 23일 오전 10시에, 내가 받은 네이버 클라우드 서버 측 담당자가 실수로 서버를 초기화하기 전까지는

 

5팀을 추가모집하면서, 신청 순서가 가장 빨랐던 5팀에게는 네이버 클라우드 서버를 제공했다고 하는데

그 서버가 터져버렸다. 주최인 성균관대 측 문제도 아니고 서버 관리자의 실수로.

만 3일간 학습한 모델 전체가 그대로 사라졌고, 복구는 불가능하다는 답변을 받았다.

 

뭐 어쩌겠는가. 서버 터지는 거 예측 못하고 백업 안해둔 내 잘못이지.

성균관대 측에서도 따로 조치해 줄 수 있는 건 없었고, 우리 팀은 입상하지 못했다.

 

 

 

 

이 포스트도 사실 행사 끝나고 가능하면 빨리 정리하고 싶었는데,

입상은 해볼 만하다 생각했던 행사에서 워낙 어이없이, 무기력하게 털려버리니 다시 생각하고 싶지가 않더라.

오랜만에 웹 스크래핑도 해보고, GPT-2 한글 모델도 학습해봤다는 점에서는 흥미로운 경험이었지만,

서버 믿지 말고 반드시 백업본을 만들어둬야 한다는 깊은 깨달음을 얻은 행사였다.

 

반응형