예은이의 이것저것

(GPT-3 key를 늦게 받아서 쓰는) GPT-2 사용기와 text to image 모듈 사용기 본문

나는 컴공이다/기술블로그

(GPT-3 key를 늦게 받아서 쓰는) GPT-2 사용기와 text to image 모듈 사용기

김짱짱 2021. 5. 28. 04:09

드디어 한 학기가 마무리되어간다. 졸업 프로젝트 스타트 학기가 마무리되어간다는 말이다. 처음에는 이걸 어떻게 해야 하나 했는데 어느새 뭔가를 하고 있긴 하다.

 

우리 팀은 GPT-3을 활용한 동화 창작 어플리케이션을 만들려고 하고 있다.

 

먼저 GPT-3에 대해 간략하게 소개하자면 GPT-3는 Generative Pre-trained Transformer 3의 약자로 openAI에서 발표한 딥 러닝을 사용하여 인간과 유사한 텍스트를 생성하는 자기 회귀 언어 모델이다. 여기서 자동 회귀란 이전의 출력이 이후의 입력이 되는 그런 형식을 말한다.

 

GPT-3는 이전의 GPT-1과 GPT-2에 비해 상당히 많은 수인 1750억 개의 매개변수를 가지고 있어 보다 더 정교한 text를 생성해낸다. 때문에 가짜 뉴스 등에 악용될 가능성이 있어 GPT-3가 상용화되었음에도 이를 사용할 수 있는 키를 받는 것은 쉽지 않다. 실제로 우리 팀은 4월 초에 openAI의 waitlist에 이름을 올렸지만 아직도 연락이 없다. 

더보기

여기까지 썼을 때는 키가 안 왔지만 27일인 오늘 새벽 4시 19분 경에 답변이 왔다!!!! 아직 계정을 만들어보지는 않았지만 이번 학기가 끝나면 테스트해볼 수 있을 것 같다.

 

 

그래서 일단은 GPT-2를 통해 우리의 프로젝트를 위한 기술을 검증해보기로 했다.


이 포스팅에서 다룰 내용은 크게 다음의 세 가지로 나눌 수 있다.

 

1. GPT-2 설치 - 언어 모델 설치

2. GPT-2 fine tuning: 해리포터 데이터 + 동화 데이터 - 모델 학습시키기

3. text to image 모듈 사용해보기 - 동화에 들어갈 삽화가 어떻게 나올지 테스트해보기

 

그럼 시작~

 


GPT-2 설치

 

1. GPT-2 repository(https://github.com/openai/gpt-2.git)를 내 로컬 저장소에 clone

git clone https://github.com/openai/gpt-2.git

2. GPT-2를 사용할 때 필요한 모듈 설치하기

pip install --upgrade -r requirements.txt

3. 사용할 모델 다운받기

 - 뒤의 숫자는 모델의 parameter의 수를 의미, parameter의 수가 클수록 다운받는 시간이 오래 걸린다.

 - 124M(124million), 355M(355million), 774M(774million), 1.5B(1.5billion) 모델 총 4가지 모델이 있다.

python download_model.py 774M

4. GPT2 repository 내 src 폴더의 interactive_contiditional_samples.py 파일의 model_name 부분을 내가 사용할 모델의 parameter로 바꿔준다.

5. src 폴더의 interactive_conditional_samples.py 파일을 실행시킨다.

python src/interactive_conditional_samples.py --model_name='774M' --nsamples=2 --temperature=.80
더보기

model_name: 사용할 모델의 이름을 입력한다.

nsamples: 생성할 문단의 수를 정한다.

temperature: 생성되는 문장과 이전 문장의 자유도를 정한다. 높을수록 자유도가 높은 것이다. (수가 너무 높으면 이전 문장과 매끄럽지 않게 연결될 가능성이 높다.)

이런 화면이 뜨면 성공이다.

Model prompt>>> 뒤에 시작하는 문장을 넣어주면 그와 이어지는 글을 작성해준다.

 

동화라면 역시 '옛날 옛적에...'로 시작하고 공주와 성이 나오는 것이 가장 익숙하므로 'Once upon a time, a princess lived in a castle' 을 넣어봤다.

뭔가 동화같지는 않지만 어느 정도 이야기 같은 결과가 나왔다.

 

 * 시작 문장을 넣지 않고 랜덤한 결과를 얻고 싶다면 generate_unconditional_samples.py 파일을 실행시키면 된다.

 


GPT-2 학습: fine tuning

 

GPT-2를 통해서 좀 더 원하는 결과를 내기 위해서는 fine tuning 과정이 필요하다.

fine tuning이란 사전에 학습된 모델을 더 학습시키는 것을 말한다.

우리는 소설 해리포터 데이터와 우리가 수집한 동화 데이터를 통해 학습시켰다. 로컬에서 학습시켰는데 노트북 사양이 별로 좋지 않아서 상당히 오랜 시간이 걸렸다. epoch 두 번 도는데 12시간 정도 걸린 것 같다.

소설 해리포터 데이터를 학습시킨 이유는 우리가 참고한 곳에서 해리포터를 사용했기 때문이다.

(이 부분은 멘토님이 도움을 많이 주셨다. 감사합니다, 멘토님!!😍😍)

 

1. 소스코드 다운받기 - fine tuning 참고 자료 다운(https://github.com/priya-dwivedi/Deep-Learning/tree/master/GPT2-HarryPotter-Training)

이 repository의 모든 코드를 다운받고 GPT2-HarryPotter-Training 폴더만 사용한다.

 

2. transformers 모듈 설치하기

GPT-2를 fine tuning 하기 위해서는 transformers라는 모듈이 필요하기 때문에 설치해줘야 한다.

pip install transformers

3. 위의 다운받은 예제가 있는 위치로 이동한다.

cd 다운받은_예제_있는_경로

4. fine tuning 코드 실행하기

- 아직은 공부를 충분히 하지 못해서 다른 사람이 만든 코드를 활용했지만 우리 동화 데이터에 맞게  run_lm_finetuning.py 파일을 수정해야할 것 같다.

python run_lm_finetuning.py --output_dir=output --model_type=gpt2 --model_name_or_path=gpt2-medium --do_train --train_data_file=./input_data/train_harry.txt --do_eval --eval_data_file=./input_data/val_harry.txt --overwrite_output_dir --block_size=200 --per_gpu_train_batch_size=1 --save_steps 5000 --num_train_epochs=2

4번까지 완료한 뒤에는 다시 위의 GPT2 설치기의 5번을 다시 수행하여 테스트해볼 수 있다.

Harry Potter loves Hogwarts. 라는 문장을 시작 문장으로 넣어봤다.

sample1

 He was the first named student, and he chose it for a reason—not because he wanted to attend, but because he knew that the School would be the best place for him.

Harry Potter didn't see Sirius as a magical outsider. When he met him, he saw Sirius like the rest of his classmates: a caring, erudite man, who enjoyed his life, a man afraid of nothing, and more than anything, a person who believed in the power of the good things in life.

And he loved him for it.

Harry knew that he had a great role in his future.

Harry Potter did not want to become a knight.

He wished to live a quiet life, to study and learn magic, and to be close to the animals he knew so well.

He wished to live a simple life.

Unfortunately, that dream was not going to happen, not with Sirius.

"Why is Harry so scared of Sirius?" Draco asked, turning around to face his brother. "When did you see him as a threat?"

"It was because he had a stubborn streak," Harry said.

"Liar!" Draco scoffed. "My brother's the most loyal, reliable person I know!"

"No, he's not." Harry said. "He knows what he's doing, but it's not for everyone. I had no idea what to expect, when I got here."

Draco frowned. "Who told you that? Why did you hesitate, for a second?"

"Because...I wanted to be the first to find out," Harry said.

Draco shrugged, and looked at him suspiciously. "Then what? Why flaunt it so much?"

"It took a lot of persuading," Harry said. "Why did I feel that I needed to convince you? Because you are the most influential person in my life. It wasn't about showing that I was right, or that I had information, or anything like that. It was about showing that I was loyal, that I believed in the right things."

"WHAT?" Draco asked.

"I wanted to do the right thing. It was a selfish thing. But I needed to do it. Because I knew that if you knew, you would help me make a better life for myself, for Sirius, for everyone else. I'd be on your side, and if I could find out who was

무슨 내용인지는 잘 모르겠지만 드레이코와 시리우스라는 등장인물이 나오는 것으로 보아 학습이 잘 된 것 같다.

 


그 뒤에는 우리가 수집한 동화데이터로 fine_tuning 해봤다. 해리포터를 학습시킬 때도 시간이 굉장히 오래 걸렸는데 우리가 수집한 동화 데이터는 그의 두 배 정도 돼서 학습 시간도 두 배 정도 걸렸다. (25일 새벽 4시에 시작해서 26일 같은 시각에 끝났다)

 progress bar를 통해 어느 정도 진행되었는지 볼 수 있다.
26일 오전 4시에 fine tuning 완료

이번에는 처음에 GPT2 설치했을 때와 같이 옛날 옛적에 공주가 성에 살고 있었습니다(Once upon a time, a princess lived in a castle.)를 넣어봤다.

Once upon a time, a princess lived in a castle.

 According to legend, a young man visited the castle one day, asking to see her. Upon arriving, he was told that her father was a treacherous and vicious tyrant. Complaining, he hurried out of the village for the night, only to return the next morning to find a group of armed bandits waiting for him. He fled to the castle grounds, but was captured by one of the men, and then tied to a chair. The bandits, seeing that his strength was sorely lacking, decided to strip off his clothes and bound him. Determined to fight back, the young man fought off the men until they realized that he was a princess. They dragged him away in shame and humiliation.

This story is not entirely true, however. There was a young man known as the "Pride of the Land." He was a brave young man who tirelessly chased the bandits until he had them on the run. Eventually, he was captured by a group of peasants, and taken to a castle where he was tortured and chained to a throne where he awaited the execution of his captors. They placed him in a deep bowl of gall, which was then poured over a young girl in his stead to remind him of his life before the bandits came to his village. The girl then became the Pride of the Land's confidante and when the bandits finally captured her he did not manage to escape from their grasp. In the end, he was sacrificed on the altar of the village gods.

On the other side of the world, the King Arcadia is ruled by either a woman, a man, or a deer. All three power the realm, and all three are known to have married each other. All three of these women are known to have had a daughter, though no clues have been discovered concerning their relationship to their daughter.

The Queen Arcadia is the least powerful of the three, though she is powerful enough to fight off her husband's bandits, and she is also quick to act whenever she spots danger on the horizon. She cannot speak much, but she did grow up to be a very strong leader of people. She would eventually be crowned Queen of the Land, and her presence was felt on the continent.

The Hero Arcadia is mostly unknown. His existence has not been confirmed, however, he is known to have a sister, whom he has never met. He was also born to a bear and a woman, known to have an affinity towards the water element. He was always told that the greatest threat.

 When she died, a group of young men came to claim her ghost to become kings. The ghost replied, "Yes, yes, you should be kings. You are the right ones. I am the queen."

She then vanished. The ghost who was the queen had a fairy-tale story; she said, "There was a boy who was hungry and he said to the king, 'I have a candle and I want to light it.' The king said, 'This is not the time to hear about candles.' So he brought a sword, and the boy's name was Peepcake. His sword was named Peepface."

Peepface became king, and he was excited and excited. Someone said, "Peepface's name sounds like Peep, so what's wrong with going with the flow?" So Peepface said to Peepface. "Peepface's name is Peep."

"Peepface. Peepface," said Peepface. "Peeping Peculiar."

Peepface asked, "You're not my Peepface. What's your name? Peepface?"

Peepface's name is Peepface, and he has a fairy-tale story; he said, "There was a boy who was hungry and he said to the king, 'I have a candle and I want to light it.' The king said, 'This is not the time to hear about candles.' So he brought a sword, and the boy's name was Peepface. His sword was named Peepface."

Peepface became king, and he was excited and excited. He went to his father and said, "Daddy, Daddy! I've found the little fairy. Her name is Peepface, and she has a fairy-tale story! Poopstick, have you seen this fairy fairy?"

His father answered, "No."

Peepface asked, "Can you tell me what she's called?"

His father said, "There's a girl named Lyra, and she's called Peepface."

Peepface's name is Peepface, and he has a fairy-tale story; he said, "There was a boy who was hungry and he said to the king, 'I have a candle and I want to light it.' The king said, 'This is not the time to hear about candles.' So he brought a sword,

학습시키기 전에 비해 좀 더 매끄러운 내용이 생성되는 것을 확인할 수 있었다. 하지만 우리가 수집한 동화 데이터가 옛날 동화이다 보니 내용적인 면에서 잔혹한 이야기가 많아 아이들의 눈높이에 맞는 내용이 될지는 알 수 없다. 그래서 좀 더 단순한 동화 데이터를 수집해야겠다는 생각이 든다.


Text to Image 모듈 사용해보기

아이들이 보는 동화에 그림이 빠질 수 없다. 그래서 동화를 생성해내는 모듈도 사용하기로 했다. 우리가 찾은 이미지 생성 모듈은 Big sleep, Deep-daze 이렇게 두 가지이다. 

GPT2는 로컬에서 실행했지만 아래의 모듈들은 상당히 무거워서 구글 코랩을 통해 실행하였다.

 

하나씩 사용기를 적어보도록 하겠다.

 

1. Big-sleep

먼저 Big-sleep 모듈을 설치한다.

pip install big-sleep --upgrade

그 뒤 아래의 코드를 실행시키면 된다.

TEXT = '이 공간에 원하는 내용을 입력'

(learning rate와 epoch 등 다른 parameter도 조절할 수 있다.)

from tqdm.notebook import trange
from IPython.display import Image, display

from big_sleep import Imagine

TEXT = 'an apple next to a fireplace' #@param {type:"string"} #생성하고 싶은 이미지의 내용 입력하기
SAVE_EVERY = 100 #@param {type:"number"}
SAVE_PROGRESS = True #@param {type:"boolean"}
LEARNING_RATE = 5e-2 #@param {type:"number"}
ITERATIONS = 1050 #@param {type:"number"}
SEED = 0 #@param {type: "number"}

model = Imagine(
    text = TEXT,
    save_every = SAVE_EVERY,
    lr = LEARNING_RATE,
    iterations = ITERATIONS,
    save_progress = SAVE_PROGRESS,
    seed = SEED
)

for epoch in trange(20, desc = 'epochs'):
    for i in trange(1000, desc = 'iteration'):
        model.train_step(epoch, i)

        if i == 0 or i % model.save_every != 0:
            continue

        filename = TEXT.replace(' ', '_')
        image = Image(f'./{filename}.png')
        display(image)

입력으로 an apple next to fireplace를 넣어봤다.

첫번째로 생성된 이미지

가장 처음에 나온 이미지는 어떤 그림인지 의미를 파악하기가 힘들다.

초반에 생성된 이미지

fireplace...는 잘 모르겠지만 apple은 어느 정도 사과같아졌다.

런타임이 끊겼을 때 마지막으로 생성된 이미지

구글코랩에서 돌려놓고 잤는데 새벽에 런타임이 끊겼다. 런타임이 끊기고 마지막으로 생성된 이미지는 위와 같은데 크게 발전된 부분은 없었다.

 

2. Deep-daze

사용 방법은 위의 big-sleep과 거의 같다.

먼저 Deep-daze 모듈을 설치한다.

pip install deep-daze --upgrade

그 뒤 아래의 코드를 실행시키면 된다.

TEXT = '이 공간에 원하는 내용을 입력'

 

from tqdm.notebook import trange
from IPython.display import Image, display

from deep_daze import Imagine

TEXT = 'an apple next to fireplace' #@param {type:"string"} #생성하고 싶은 이미지의 내용 입력하기
NUM_LAYERS = 32 #@param {type:"number"}
SAVE_EVERY =  20#@param {type:"number"}
IMAGE_WIDTH = 512 #@param {type:"number"}
SAVE_PROGRESS = True #@param {type:"boolean"}
LEARNING_RATE = 1e-5 #@param {type:"number"}
ITERATIONS = 1050 #@param {type:"number"}

model = Imagine(
    text = TEXT,
    num_layers = NUM_LAYERS,
    save_every = SAVE_EVERY,
    image_width = IMAGE_WIDTH,
    lr = LEARNING_RATE,
    iterations = ITERATIONS,
    save_progress = SAVE_PROGRESS
)

for epoch in trange(3, desc = 'epochs'):
    for i in trange(ITERATIONS, desc = 'iteration'):
        model.train_step(epoch, i)

        if i % model.save_every != 0:
            continue

        filename = TEXT.replace(' ', '_')
        image = Image(f'./{filename}.jpg')
        display(image)

이번에도 입력은 an apple next to fireplace를 넣어봤다.

deep-daze는 big-sleep과 다르게 첫 이미지는 거의 아무것도 없는 회색의 무언가다.

 

 

an apple next to fireplace

왼쪽에 비해 오른쪽의 이미지가 선명한 게 확연하게 느껴진다. 가운데의 빨간 물체도 좀 더 사과같아졌다.

 

그 다음으로는 좀 더 동화스러운 a princess living in a castle(성에 살고 있는 공주...)를 넣어봤다.

 

초반 그림

상당히 초반에 생성된 이미지인데 숲 속의 성 같은 것과 공주 같은 것이 있는 것을 볼 수 있었다.

 

 

마지막 그림

원래 더 많고 정교한 그림이 나와야 하는데 구글 코랩 런타임이 끊겨서 여기까지만 볼 수 있었다.

공주와 성이 곳곳에 생겼다. 이런 부분은 좀 더 공부해서 조절해야할 것 같다.


Deep-daze와 Big-sleep을 비교했을 때 Deep-daze가 비교적 일러스트스러운 이미지를 생성해내는 것을 확인할 수 있었다. Deep-daze와 Big-sleep 중에서는 Deep-daze를 사용하는 것이 적절할 것 같다.


 

후기

처음에는 팀원들이랑 완성할 수 있을까, 뭘 어떻게 해야하나, 아는 것도 없는데 뭘 할 수는 있나 이런 생각밖에 없었는데 점점 뭐라도 하는 우리를 보면서 올해 안에는 뭐라도 결과가 나오긴 하겠구나... 하는 생각이 들었다. 한 학기동안 같이 열심히 했는데 여름방학이랑 다음 학기에 더 열심히해서 부끄럽진 않은 결과가 나왓으면 좋겠다. GPT-3 key도 받았으니 앞으로 더 좋은 결과가 나올 것 같다. 앞으로 화이팅!~!!~!!