2018년 9월 3일 월요일

Deep Learning with Sequence Data and text (순차적 데이터와 텍스트의 딥러닝 PyTorch) (3)

시작하기 전에


여기 글의 예제는 PyTorch 로 되어 있습니다.
본문의 내용은 Deep Learning with PyTorch (Vishnu Subramanian) 책 내용으로 구성 되어있으며, 해당 내용은 Chapter 6 의 내용으로 구성되어 있습니다.

Word embedding

워드 임베딩이 딥러닝에서 텍스트 데이터를 나타내는 굉장히 대중적으로 사용되는 방법입니다. 벡터의 차원이 사전 크기에 따라서 다른데 가장 일반적인 차원의 크기는 50,100,256,300 그리고 때때로 1000이 되기도 합니다. 차원크기가 커지면 아무래도 훈련이나 자원을 더 많이 소모 하게 됩니다.
만약 사전 크기가 20000이라면 one-hot 표현에서는 20000*20000 크기의 숫자가 되고 대부분이 0으로 차 있습니다. 동일한 사전에서 word embedding 표현에서는 20000*dimension 크기가 됩니다. 그 크기는 10,50,300... 등이 되고요. 또한 내부에 들어있는는 값은 one-hot값과 다르게 float(부동소스점) 값을 지닙니다.
word embedding 을 생성하는 한가지 방법은 해당 밀도 벡터의 각각의 토큰에 랜덤 숫자를 가지고 시작하는것입니다. 그리고 문서 분류기나 의미 분석기 같은 훈련 모델을 통해서 훈련하는것입니다. 토큰을 표현하는 부동 소수점 숫자들은 의미적으로 비슷한 단어들로 조정이 될것입니다.
이게 어떤 뜻이냐면 예를 들어 영화를 의미 분류기에 넣었을때 Superman, Batman, Thor는 비슷한 영화이니까 vector상의 거리가 가깝게 표시가 된다는 의미입니다.
그리고 Notebook과 Titanic같은 로맨틱 영화는 액션 영화와 떨어져서 있게 될것입니다.
아래는 2차원일때 가정해서 word embedding 벡터값이 아래와 같이 되어 의미가 비슷하게 된다는 것입니다. (예제의 수치는 임의의 값입니다.)
Superman = [ 10.3, 4 ]
Batman = [ 10.9, 4.5 ]
Thor = [ 9.5 , 5.5 ]
Notebook = [ 2.2 , 6.3 ]
Titanic= [ 3.4 , 7.1 ]
결론은 위 값을 어떻게 만드냐? 그것은 train이 필요합니다.

Training word embedding by building a sentiment classifier

(의미 분류 생성에 의한 워드 임베딩 훈련)
IMDB라고 불리는 데이터 셋을 다운로드 할겁니다. 이것은 리뷰를 포함하고 있고 의미가 분류되어 있으며, 리뷰의 문장이 긍정적인지 부정적인지 또는 모르겠는지 분류 되어 있습니다. 만드는 과정에 있어서 IMBD데이터셋에 있는 단어에 대해서 우리는 word embedding을train을 할 것입니다. 이때 torchtext라는 라이브러리를 사용할건데, 해당 라이브러리는 다운로딩(IMDB다운로드), 텍스트 벡터화, 일괄 작업을 좀 더 쉽게 할 수 있습니다. 의미 분류기를 train하는것은 다음과 같은 절차로 이루어 질것입니다.

1. IMDB 데이터의 다운로드와 text 토큰화 수행
2. 사전 생성
3. 벡터의 일괄 작업 생성
3. embedding을 가지고 네트워크 모델 생성
5. 모델 training(훈련)


IMDB 데이터의 다운로드와 text 토큰화 수행

PyTorch에서 text를 처리하는 라이브러리가 torchtext라고 불립니다.  PyTorch에서 포함이 안되어 있어서 직접 설치해야합니다.
pip install torchtext
한번 설치되면 그것을 계속 이용할 수 있습니다. torchtext는 torchtex.data와 torchtext.datasets라는 두개의 중요한 모듈을 제공합니다.

torchtext.data

torchtext.datas인스턴스는 클래스를 정의합니다. Field 는 어떻게 데이터가 읽혀져야 하는지와 토큰되어야 하는지 정의 하는것을 돕습니다. IMDB데이터 셋을 준비 하는 다음 예제를 살표봅시다.
from torchtext import data
TEXT = data.Field(lower=True, batch_first=True, fix_length=20) 
LABEL = data.Field(sequential=False) 
위 코드에서 두개의 Field 오브젝트를 정의 했습니다. 실제 text를 위한 것 하나와 label데이터를 위한것입니다. 실제 text에 대해서 우리는 모든 데이터가 소문자로 예상(lower=True)되고 최대 길이 20(fix_length=20)으로 예상합니다. 실제 환경이라면 20보다 매우큰 수를 사용해야합니다. Field생성자는 도한 다른 인자로 tokenize를 입력 받습니다. 여기에서는 깁손값으로 str.split함수를 사용합니다.

torchtext.datasets

torchtext.datasets인스턴스는 IMDB, TREC와 같은 사용 데이터 셋 래퍼를 제공해줍니다. IMDB데이터셋을 다운로드하고 그것을 (split 단어와 단어를)자르고 train하고 test 하기 위해 torch.datasets를 사용할겁니다. 다음 코드는 처음 실행시키면 실행하는데 몇 분 정도 절릴겁니다. IMDB데이터셋을 인터넷으로 다운로드 하는데 시간이 걸리기 때문입니다. 아래코드에서 datasets.IMDB.splits(TEXT, LABEL) 부분입니다.
from torchtext import data,datasets

TEXT = data.Field(lower=True, batch_first=True, fix_length=20) 
LABEL = data.Field(sequential=False) 

train, test = datasets.IMDB.splits(TEXT, LABEL)
type(train)

그리고 상황에 따라 아래와 같은 오류가 발생합니다.
(base) E:\>python test.py

downloading aclImdb_v1.tar.gz

Traceback (most recent call last):

  File "test.py", line 8, in <module>

    train, test = datasets.IMDB.splits(TEXT,LABEL)

  File "E:\ProgramData\Anaconda3\lib\site-packages\torchtext\datasets\imdb.py", line 54, in splits

    train=train, validation=None, test=test, **kwargs)

  File "E:\ProgramData\Anaconda3\lib\site-packages\torchtext\data\dataset.py", line 74, in splits

    path = cls.download(root)

  File "E:\ProgramData\Anaconda3\lib\site-packages\torchtext\data\dataset.py", line 175, in download

    download_from_url(url, zpath)

  File "E:\ProgramData\Anaconda3\lib\site-packages\torchtext\utils.py", line 33, in download_from_url

    return urllib.request.urlretrieve(url, path)

  File "E:\ProgramData\Anaconda3\lib\urllib\request.py", line 289, in urlretrieve

    % (read, size), result)

urllib.error.ContentTooShortError: <urlopen error retrieval incomplete: got only 83886080 out of 84125825 bytes>

확인해보니 aclImdb_v1.tar.gz파일을 가져오는데 다운받다가 작은 크기가 받아지는 문제가 있습니다. python 문제인지 어디문제인지 모르겠지만, 수동으로 다운로드 하여 적당한 위치에 넣어주면 해결됩니다.
다운로드 하는 파일 정보는 아래 위치에 있으며,
E:\ProgramData\Anaconda3\Lib\site-packages\torchtext\datasets\imdb.py
실제 파일 url 정보는 아래와 같습니다.
urls = ['http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz']
해당 파일을 수동으로 다운로드 하여,
aclImdb_v1.tar.gz
아래 위치에 복사해서 넣습니다.

dataset.IMDB class는 모든 복잡한 다운로딩, 토큰화, splitting 모든 처리를 포함하고 있습니다.
train, test = datasets.IMDB.splits(TEXT, LABEL)
위에서 train.fields 는 TEXT키이고 value가 LABEL인 사전이 들어있습니다.
아래 출력을 더 넣은 예제입니다.
from torchtext import data,dataset

TEXT = data.Field(lower=True, batch_first=True, fix_length=20) 
LABEL = data.Field(sequential=False) 

print(TEXT)
print(LABEL)
train, test = datasets.IMDB.splits(TEXT, LABEL)
type(train)

print('train.fields', train.fields)
print('len(train)', len(train))
print('vars(train[0])', vars(train[0]))
print('vars(test[0])', vars(test[0]))
실행 결과
(base) E:\>python test.py
<torchtext.data.field.Field object at 0x000001FFC685A668>
<torchtext.data.field.Field object at 0x000001FFC685A6A0>
train.fields {'text': <torchtext.data.field.Field object at 0x000001FFC685A668>, 'label': <torchtext.data.field.Field object at 0x000001FFC685A6A0>}
len(train) 25000
vars(train[0]) {'text': ['bromwell', 'high', 'is', 'a', 'cartoon', 'comedy.', 'it', 'ran', 'at', 'the', 'same', 'time', 'as', 'some', 'other', 'programs', 'about', 'school', 'life,', 'such', 'as', '"teachers".', 'my', '35', 'years', 'in', 'the', 'teaching', 'profession', 'lead', 'me', 'to', 'believe', 'that', 'bromwell', "high's", 'satire', 'is', 'much', 'closer', 'to', 'reality', 'than', 'is', '"teachers".', 'the', 'scramble', 'to', 'survive', 'financially,', 'the', 'insightful', 'students', 'who', 'can', 'see', 'right', 'through', 'their', 'pathetic', "teachers'", 'pomp,', 'the', 'pettiness', 'of', 'the', 'whole', 'situation,', 'all', 'remind', 'me', 'of', 'the', 'schools', 'i', 'knew', 'and', 'their', 'students.', 'when', 'i', 'saw', 'the', 'episode', 'in', 'which', 'a', 'student', 'repeatedly', 'tried', 'to', 'burn', 'down', 'the', 'school,', 'i', 'immediately', 'recalled', '.........', 'at', '..........', 'high.', 'a', 'classic', 'line:', 'inspector:', "i'm", 'here', 'to', 'sack', 'one', 'of', 'your', 'teachers.', 'student:', 'welcome', 'to', 'bromwell', 'high.', 'i', 'expect', 'that', 'many', 'adults', 'of', 'my', 'age', 'think', 'that', 'bromwell', 'high', 'is', 'far', 'fetched.', 'what', 'a', 'pity', 'that', 'it', "isn't!"], 'label': 'pos'}
vars(test[0]) {'text': ['i', 'went', 'and', 'saw', 'this', 'movie', 'last', 'night', 'after', 'being', 'coaxed', 'to', 'by', 'a', 'few', 'friends', 'of', 'mine.', "i'll", 'admit', 'that', 'i', 'was', 'reluctant', 'to', 'see', 'it', 'because', 'from', 'what', 'i', 'knew', 'of', 'ashton', 'kutcher', 'he', 'was', 'only', 'able', 'to', 'do', 'comedy.', 'i', 'was', 'wrong.', 'kutcher', 'played', 'the', 'character', 'of', 'jake', 'fischer', 'very', 'well,', 'and', 'kevin', 'costner', 'played', 'ben', 'randall', 'with', 'such', 'professionalism.', 'the', 'sign', 'of', 'a', 'good', 'movie', 'is', 'that', 'it', 'can', 'toy', 'with', 'our', 'emotions.', 'this', 'one', 'did', 'exactly', 'that.', 'the', 'entire', 'theater', '(which', 'was', 'sold', 'out)', 'was', 'overcome', 'by', 'laughter', 'during', 'the', 'first', 'half', 'of', 'the', 'movie,', 'and', 'were', 'moved', 'to', 'tears', 'during', 'the', 'second', 'half.', 'while', 'exiting', 'the', 'theater', 'i', 'not', 'only', 'saw', 'many', 'women', 'in', 'tears,', 'but', 'many', 'full', 'grown', 'men', 'as', 'well,', 'trying', 'desperately', 'not', 'to', 'let', 'anyone', 'see', 'them', 'crying.', 'this', 'movie', 'was', 'great,', 'and', 'i', 'suggest', 'that', 'you', 'go', 'see', 'it', 'before', 'you', 'judge.'], 'label': 'pos'}

위 결과를 살펴보면 train으로 입력되는 자료의 수가 2500이고 train[0]은 첫번째 자료가 됩니다. 이때 text ,  label 이 있는데요. text는 입력 자료의 순수 text인데 이것이 단어 단위로 split되어 있습니다. label은 학습에 있어서 결과를 의미합니다. 여기에선 pos 즉 긍정적 이라는 뜻이 됩니다. (앞에서 IMDB의 데이터는 긍정적 부정적 알수없는 3가지로 되어 있다고 언급했습니다. 이 데이터는 영화의 리뷰에대한 평가입니다.), train과 test 자료가 있는데 train은 훈련을 하기 위한 데이터이고 test는 훈련후 훈련이 제대로 되었는지 확인하는 용도의 자료입니다.
다운로드 받은 위치의 .data\imdb\aclImdb 폴더를 열어보면 데이터가 어떻게 로딩되는지 참고해볼 수 있습니다.






댓글 없음:

댓글 쓰기