[Tensorflow] 3. Natural Language Processing in TensorFlow (4 week Sequence models and literature ) : Programming (1)

gunny·2024년 3월 22일
0

[Tensorflow] 3. Natural Language Processing in TensorFlow (4 week Sequence models and literature ) : Programming (1)


3코스 자연어처리(Natural Language Processing in TensorFlow)의 4주차 Sequence models and literature에서 수행되는 프로그래밍 노트북은 실습 2개와 시험 1개로 이뤄진다.

실습 1. 텍스트 생성

먼저 실습으로 제공되는 첫번째 노트북은 "텍스트 생성" 이다.
텍스트 생성을 위해 데이터를 불러오고 모델을 만들어서 텍스트를 생성하는 실습니다.

Ungraded Lab: Generating Text with Neural Networks

주어진 데이터는 아일랜드 노래 가사이다.
해당 데이터를 핸들링해서 새로운 노래를 만드는 것이 첫 번째 실습의 주된 내용이다.

(1) 필요한 라이브러리 import

import tensorflow as tf
import numpy as np 
from tensorflow.keras.layers import Embedding, LSTM, Dense, Bidirectional
from tensorflow.keras.models import Sequential
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
  • tensorflow와 numpy를 import 한다.
    numpy는 들어오는 텍스트를 시퀀스 데이터로 만든 후 패딩 작업을 거친 후에,
    모델에 넣어서 예측한 값 중 가장 높은 단어를 argmax로 찾아올 때 사용할 예정이다.
  • 원래 tensorflow 까지만 import 하고 .keras.layers 혹은 .keras.models. 로 직접 모델을 구현 할때 다 작성하기 싫다면 위와 같이 전체적인 모듈을 한번에 import 해서 모델을 쌓을 때 좀 더 코드적으로 깔끔하게 쌓을 수 있다.
  • 다음으로 Tokenizer, 시퀀스데이터 패딩을 위한 pad_sequences 이다.

(2) 데이터 load

이번에 사용할 데이터는 https://en.wikipedia.org/wiki/Lanigan%27s_Ball
한국말로 번역하면 래니건의 공이라는 아일랜드 민요이다.
래니건이 아버지로부터 땅을 물려 받은 후 열광적인 파티를 벌이고 있는 내용을 주로 담고 있다.

"""
data="In the town of Athy one Jeremy Lanigan \n Battered away til he hadnt a pound. \nHis father died and made him a man again \n Left him a farm and ten acres of ground. \nHe gave a grand party for friends and relations \nWho didnt forget him when come to the wall, \nAnd if youll but listen Ill make your eyes glisten \nOf the rows and the ructions of Lanigans Ball. \nMyself to be sure got free invitation, \nFor all the nice girls and boys I might ask, \nAnd just in a minute both friends and relations \nWere dancing round merry as bees round a cask. \nJudy ODaly, that nice little milliner, \nShe tipped me a wink for to give her a call, \nAnd I soon arrived with Peggy McGilligan \nJust in time for Lanigans Ball. \nThere were lashings of punch and wine for the ladies, \nPotatoes and cakes; there was bacon and tea, \nThere were the Nolans, Dolans, OGradys \nCourting the girls and dancing away. \nSongs they went round as plenty as water, \nThe harp that once sounded in Taras old hall,\nSweet Nelly Gray and The Rat Catchers Daughter,\nAll singing together at Lanigans Ball. \nThey were doing all kinds of nonsensical polkas \nAll round the room in a whirligig. \nJulia and I, we banished their nonsense \nAnd tipped them the twist of a reel and a jig. \nAch mavrone, how the girls got all mad at me \nDanced til youd think the ceiling would fall. \nFor I spent three weeks at Brooks Academy \nLearning new steps for Lanigans Ball. \nThree long weeks I spent up in Dublin, \nThree long weeks to learn nothing at all,\n Three long weeks I spent up in Dublin, \nLearning new steps for Lanigans Ball. \nShe stepped out and I stepped in again, \nI stepped out and she stepped in again, \nShe stepped out and I stepped in again, \nLearning new steps for Lanigans Ball. \nBoys were all merry and the girls they were hearty \nAnd danced all around in couples and groups, \nTil an accident happened, young Terrance McCarthy \nPut his right leg through miss Finnertys hoops. \nPoor creature fainted and cried Meelia murther, \nCalled for her brothers and gathered them all. \nCarmody swore that hed go no further \nTil he had satisfaction at Lanigans Ball. \nIn the midst of the row miss Kerrigan fainted, \nHer cheeks at the same time as red as a rose. \nSome of the lads declared she was painted, \nShe took a small drop too much, I suppose. \nHer sweetheart, Ned Morgan, so powerful and able, \nWhen he saw his fair colleen stretched out by the wall, \nTore the left leg from under the table \nAnd smashed all the Chaneys at Lanigans Ball. \nBoys, oh boys, twas then there were runctions. \nMyself got a lick from big Phelim McHugh. \nI soon replied to his introduction \nAnd kicked up a terrible hullabaloo. \nOld Casey, the piper, was near being strangled. \nThey squeezed up his pipes, bellows, chanters and all. \nThe girls, in their ribbons, they got all entangled \nAnd that put an end to Lanigans Ball."

"""

data="In the town of Athy one Jeremy Lanigan \n Battered away til he hadnt a pound. \nHis father died and made him a man again \n Left him a farm and ten acres of ground. \nHe gave a grand party for friends and relations \nWho didnt forget him when come to the wall, \nAnd if youll but listen Ill make your eyes glisten \nOf the rows and the ructions of Lanigans Ball. \nMyself to be sure got free invitation, \nFor all the nice girls and boys I might ask, \nAnd just in a minute both friends and relations \nWere dancing round merry as bees round a cask. \nJudy ODaly, that nice little milliner, \nShe tipped me a wink for to give her a call, \nAnd I soon arrived with Peggy McGilligan \nJust in time for Lanigans Ball. \nThere were lashings of punch and wine for the ladies, \nPotatoes and cakes; there was bacon and tea, \nThere were the Nolans, Dolans, OGradys \nCourting the girls and dancing away. \nSongs they went round as plenty as water, \nThe harp that once sounded in Taras old hall,\nSweet Nelly Gray and The Rat Catchers Daughter,\nAll singing together at Lanigans Ball. \nThey were doing all kinds of nonsensical polkas \nAll round the room in a whirligig. \nJulia and I, we banished their nonsense \nAnd tipped them the twist of a reel and a jig. \nAch mavrone, how the girls got all mad at me \nDanced til youd think the ceiling would fall. \nFor I spent three weeks at Brooks Academy \nLearning new steps for Lanigans Ball. \nThree long weeks I spent up in Dublin, \nThree long weeks to learn nothing at all,\n Three long weeks I spent up in Dublin, \nLearning new steps for Lanigans Ball. \nShe stepped out and I stepped in again, \nI stepped out and she stepped in again, \nShe stepped out and I stepped in again, \nLearning new steps for Lanigans Ball. \nBoys were all merry and the girls they were hearty \nAnd danced all around in couples and groups, \nTil an accident happened, young Terrance McCarthy \nPut his right leg through miss Finnertys hoops. \nPoor creature fainted and cried Meelia murther, \nCalled for her brothers and gathered them all. \nCarmody swore that hed go no further \nTil he had satisfaction at Lanigans Ball. \nIn the midst of the row miss Kerrigan fainted, \nHer cheeks at the same time as red as a rose. \nSome of the lads declared she was painted, \nShe took a small drop too much, I suppose. \nHer sweetheart, Ned Morgan, so powerful and able, \nWhen he saw his fair colleen stretched out by the wall, \nTore the left leg from under the table \nAnd smashed all the Chaneys at Lanigans Ball. \nBoys, oh boys, twas then there were runctions. \nMyself got a lick from big Phelim McHugh. \nI soon replied to his introduction \nAnd kicked up a terrible hullabaloo. \nOld Casey, the piper, was near being strangled. \nThey squeezed up his pipes, bellows, chanters and all. \nThe girls, in their ribbons, they got all entangled \nAnd that put an end to Lanigans Ball."

corpus = data.lower().split("\n")

print(corpus)

# ['in the town of athy one jeremy lanigan ', ' battered away til he hadnt a pound. ', 'his father died and made him a man again ', ' left him a farm and ten acres of ground. ', 'he gave a grand party for friends and relations ', 'who didnt forget him when come to the wall, ', 'and if youll but listen ill make your eyes glisten ', 'of the rows and the ructions of lanigans ball. ', 'myself to be sure got free invitation, ', 'for all the nice girls and boys i might ask, ', 'and just in a minute both friends and relations ', 'were dancing round merry as bees round a cask. ', 'judy odaly, that nice little milliner, ', 'she tipped me a wink for to give her a call, ', 'and i soon arrived with peggy mcgilligan ', 'just in time for lanigans ball. ', 'there were lashings of punch and wine for the ladies, ', 'potatoes and cakes; there was bacon and tea, ', 'there were the nolans, dolans, ogradys ', 'courting the girls and dancing away. ', 'songs they went round as plenty as water, ', 'the harp that once sounded in taras old hall,', 'sweet nelly gray and the rat catchers daughter,', 'all singing together at lanigans ball. ', 'they were doing all kinds of nonsensical polkas ', 'all round the room in a whirligig. ', 'julia and i, we banished their nonsense ', 'and tipped them the twist of a reel and a jig. ', 'ach mavrone, how the girls got all mad at me ', 'danced til youd think the ceiling would fall. ', 'for i spent three weeks at brooks academy ', 'learning new steps for lanigans ball. ', 'three long weeks i spent up in dublin, ', 'three long weeks to learn nothing at all,', ' three long weeks i spent up in dublin, ', 'learning new steps for lanigans ball. ', 'she stepped out and i stepped in again, ', 'i stepped out and she stepped in again, ', 'she stepped out and i stepped in again, ', 'learning new steps for lanigans ball. ', 'boys were all merry and the girls they were hearty ', 'and danced all around in couples and groups, ', 'til an accident happened, young terrance mccarthy ', 'put his right leg through miss finnertys hoops. ', 'poor creature fainted and cried meelia murther, ', 'called for her brothers and gathered them all. ', 'carmody swore that hed go no further ', 'til he had satisfaction at lanigans ball. ', 'in the midst of the row miss kerrigan fainted, ', 'her cheeks at the same time as red as a rose. ', 'some of the lads declared she was painted, ', 'she took a small drop too much, i suppose. ', 'her sweetheart, ned morgan, so powerful and able, ', 'when he saw his fair colleen stretched out by the wall, ', 'tore the left leg from under the table ', 'and smashed all the chaneys at lanigans ball. ', 'boys, oh boys, twas then there were runctions. ', 'myself got a lick from big phelim mchugh. ', 'i soon replied to his introduction ', 'and kicked up a terrible hullabaloo. ', 'old casey, the piper, was near being strangled. ', 'they squeezed up his pipes, bellows, chanters and all. ', 'the girls, in their ribbons, they got all entangled ', 'and that put an end to lanigans ball.']
  • 하나의 긴 string으로 되어 있는 data 에 할당된 텍스트를 구분자를 '\n' 개행을 기준으로 끊어서 텍스트 배열로 만들어 corpus에 할당한다.
  • 위에 print 해서 출력한 corpus는 ['in the town of athy one jeremy lanigan ', ' battered away til he hadnt a pound. ', ... ] 과 같은 형태가 된다.
print(len(corpus))

# 64
  • 해당 텍스트를 개행을 기준으로 split 했을 때의 총 코퍼스의 길이는 64이다.

(3) 단어 사전 만들기

# 토크나이저 초기화
tokenizer = Tokenizer()

# 위에 생성한 corpus를 tokenizer에 학습
tokenizer.fit_on_texts(corpus)

# 텍스트에 있는 총 단어의 수 (+1을 해주어 padding token 또한 고려함)
total_words = len(tokenizer.word_index) + 1

print(f'word index dictionary: {tokenizer.word_index}')
print(f'total words: {total_words}')

# word index dictionary: {'and': 1, 'the': 2, 'a': 3, 'in': 4, 'all': 5, 'i': 6, 'for': 7, 'of': 8, 'lanigans': 9, 'ball': 10, 'were': 11, 'at': 12, 'to': 13, 'she': 14, 'stepped': 15, 'his': 16, 'girls': 17, 'as': 18, 'they': 19, 'til': 20, 'he': 21, 'again': 22, 'got': 23, 'boys': 24, 'round': 25, 'that': 26, 'her': 27, 'there': 28, 'three': 29, 'weeks': 30, 'up': 31, 'out': 32, 'him': 33, 'was': 34, 'spent': 35, 'learning': 36, 'new': 37, 'steps': 38, 'long': 39, 'away': 40, 'left': 41, 'friends': 42, 'relations': 43, 'when': 44, 'wall': 45, 'myself': 46, 'nice': 47, 'just': 48, 'dancing': 49, 'merry': 50, 'tipped': 51, 'me': 52, 'soon': 53, 'time': 54, 'old': 55, 'their': 56, 'them': 57, 'danced': 58, 'dublin': 59, 'an': 60, 'put': 61, 'leg': 62, 'miss': 63, 'fainted': 64, 'from': 65, 'town': 66, 'athy': 67, 'one': 68, 'jeremy': 69, 'lanigan': 70, 'battered': 71, 'hadnt': 72, 'pound': 73, 'father': 74, 'died': 75, 'made': 76, 'man': 77, 'farm': 78, 'ten': 79, 'acres': 80, 'ground': 81, 'gave': 82, 'grand': 83, 'party': 84, 'who': 85, 'didnt': 86, 'forget': 87, 'come': 88, 'if': 89, 'youll': 90, 'but': 91, 'listen': 92, 'ill': 93, 'make': 94, 'your': 95, 'eyes': 96, 'glisten': 97, 'rows': 98, 'ructions': 99, 'be': 100, 'sure': 101, 'free': 102, 'invitation': 103, 'might': 104, 'ask': 105, 'minute': 106, 'both': 107, 'bees': 108, 'cask': 109, 'judy': 110, 'odaly': 111, 'little': 112, 'milliner': 113, 'wink': 114, 'give': 115, 'call': 116, 'arrived': 117, 'with': 118, 'peggy': 119, 'mcgilligan': 120, 'lashings': 121, 'punch': 122, 'wine': 123, 'ladies': 124, 'potatoes': 125, 'cakes': 126, 'bacon': 127, 'tea': 128, 'nolans': 129, 'dolans': 130, 'ogradys': 131, 'courting': 132, 'songs': 133, 'went': 134, 'plenty': 135, 'water': 136, 'harp': 137, 'once': 138, 'sounded': 139, 'taras': 140, 'hall': 141, 'sweet': 142, 'nelly': 143, 'gray': 144, 'rat': 145, 'catchers': 146, 'daughter': 147, 'singing': 148, 'together': 149, 'doing': 150, 'kinds': 151, 'nonsensical': 152, 'polkas': 153, 'room': 154, 'whirligig': 155, 'julia': 156, 'we': 157, 'banished': 158, 'nonsense': 159, 'twist': 160, 'reel': 161, 'jig': 162, 'ach': 163, 'mavrone': 164, 'how': 165, 'mad': 166, 'youd': 167, 'think': 168, 'ceiling': 169, 'would': 170, 'fall': 171, 'brooks': 172, 'academy': 173, 'learn': 174, 'nothing': 175, 'hearty': 176, 'around': 177, 'couples': 178, 'groups': 179, 'accident': 180, 'happened': 181, 'young': 182, 'terrance': 183, 'mccarthy': 184, 'right': 185, 'through': 186, 'finnertys': 187, 'hoops': 188, 'poor': 189, 'creature': 190, 'cried': 191, 'meelia': 192, 'murther': 193, 'called': 194, 'brothers': 195, 'gathered': 196, 'carmody': 197, 'swore': 198, 'hed': 199, 'go': 200, 'no': 201, 'further': 202, 'had': 203, 'satisfaction': 204, 'midst': 205, 'row': 206, 'kerrigan': 207, 'cheeks': 208, 'same': 209, 'red': 210, 'rose': 211, 'some': 212, 'lads': 213, 'declared': 214, 'painted': 215, 'took': 216, 'small': 217, 'drop': 218, 'too': 219, 'much': 220, 'suppose': 221, 'sweetheart': 222, 'ned': 223, 'morgan': 224, 'so': 225, 'powerful': 226, 'able': 227, 'saw': 228, 'fair': 229, 'colleen': 230, 'stretched': 231, 'by': 232, 'tore': 233, 'under': 234, 'table': 235, 'smashed': 236, 'chaneys': 237, 'oh': 238, 'twas': 239, 'then': 240, 'runctions': 241, 'lick': 242, 'big': 243, 'phelim': 244, 'mchugh': 245, 'replied': 246, 'introduction': 247, 'kicked': 248, 'terrible': 249, 'hullabaloo': 250, 'casey': 251, 'piper': 252, 'near': 253, 'being': 254, 'strangled': 255, 'squeezed': 256, 'pipes': 257, 'bellows': 258, 'chanters': 259, 'ribbons': 260, 'entangled': 261, 'end': 262}
# total words: 263
  • tensorflow의 Tokenizer를 초기화한 후에, 해당 Tokenizer에
    위에서 문자열을 원소로 구성한 배열 corpus로 학습시킨다.
    fit_on_text 를 사용하여 corpus에 있는 텍스트 데이터를 기반으로 토크나이저를 학습한다.

  • 여기서의 fit_on_text 메소드는
    (1) Tokenization(토큰화) : 입력된 텍스트를 단어, 형태소 혹은 다른 기준에 따라 분할하여 토큰을 만든다. 이 때 특수 문자나 구두점을 기준으로 나눌 수 있다.
    (2) Word Indexing(단어 인덱싱) : 각 토큰에 고유한 인덱스를 할당한다.
    이 인덱스는 해당 토큰을 나타내는 정수값이다.
    (3) Frequency Calculation(빈도 계산) : 각 토큰(단어)의 빈도를 계산한다. 토크나이저가 토큰화를 수행할 때 각 토큰이 나타나는 횟수를 타나낸다.
    (4) Option 으로 특수 토큰 추가 : 특정 목적을 위해서 사용되는 특수 토큰인 패딩 토큰이나 OOV(Out-Of-Vocabulary) 토큰을 필요에 따라 추가한다.

    즉, fit_on_text는 텍스트 데이터에서 고유한 토큰을 추출하고, 이를 인덱스로 매핑해서 모델이 텍스트 데이터를 이해하고 처리할 수 있도록 한다.

  • 학습한 Tokenizer의 .word_index를 통해서 토크나이저로 학습한 각 단어를 고유한 정수 인덱스로 매핑한 딕셔너리를 가져온다.
    위에서 출력한 word index dictionary: {'and': 1, 'the': 2, ' ... 'ribbons': 260, 'entangled': 261, 'end': 262} 까지 총 262개의 토큰에 해당하는 정수 인덱싱이 되어 있는 것을 확인할 수 있다.

  • 해당 .word_index를 통해서 텍스트 데이터를 인덱스화하여 모델에 입력할 수 있다.
    이를 통해서 텍스트 데이터를 신경망 모델에 입력할 수 있게 된다.

  • 위에 서보면 total_Words로 현재 있는 토큰 단어에 +1 을 해주는데, 해당 이유는 패딩 토큰을 추가해주기 위해서이다.
    일반적으로 자연어 처리에서 시퀀스 데이터를 모델에 입력할 때, 시퀀스의 길이를 일정하게 맞추기 위해 패딩(padding)을 추가하게 되는데, 패딩을 보통 "0"으로 설정하고 이를 토크나이저의 단어 집합(Vocabulary)에 포함시켜야 한다.
    따라서 총 단어수에 패딩 토큰을 취가하기 위해 +1을 더해준 것이고,
    total words는 모델의 입력으로 사용되는 단어의 총 개수이다.

(4) 데이터 전처리

데이터를 생성하기 위해서 훈련 시퀀스와 해당 레이블을 생성하는 단계를 거친다.
노래의 각 라인을 가져와 입력과 레이블을 생성한다.
예를 들어, "I am using Tensorflow"라는 문장이 하나만 있는 경우 모델이 이 문장의 하위 문구가 주어지면 다음 단어를 학습하기를 희망할 수 있다.

INPUT ->LABEL

I ---> am
I am ---> using
I am using ---> Tensorflow

아래의 코드는 위의 훈련 시퀀스와 해당 레이블을 생성하는 과정이다.
결과는 패딩된 시퀀스의 입력이고 원-핫 인코딩된 배열의 레이블로 나타난다.

# 시퀀스 리스트를 초기화
input_sequences = []

# 위 데이터를 개행한 문장들의 loop
for line in corpus:

	# 현재 문장에 대한 토크나이저
	token_list = tokenizer.texts_to_sequences([line])[0]

	# 하위 문구를 생성하기 위해 문장 반복
	for i in range(1, len(token_list)):
		
		# 하위 문구 생성
		n_gram_sequence = token_list[:i+1]

		# 해당 시퀀스를 시퀀스 리스트에 추가
		input_sequences.append(n_gram_sequence)

# 가장 긴 시퀀스 길이 확인
max_sequence_len = max([len(x) for x in input_sequences])

# 모든 시퀀스 데이터들을 패딩 작업
input_sequences = np.array(pad_sequences(input_sequences, maxlen=max_sequence_len, padding='pre'))

# 하위 문구의 마지막 토큰을 분할하여 입력 및 레이블을 생성함
xs, labels = input_sequences[:,:-1],input_sequences[:,-1]

# 레이블을 원-핫 배열로 변환
ys = tf.keras.utils.to_categorical(labels, num_classes=total_words)
  • tokenizer.texts_to_sequences는 주어진 텍스트를 정수 시퀀스로 변환하는데 사용된다. 토큰화된 텍스트를 기반으로 각 단어를 해당하는 정수 인덱스로 변환한다.
    주어진 텍스트를 토큰화 하고, 각 단어를 word_index에 따라 정수로 변환해서 시퀀스로 구성한다. 이 메소드는 여러 개의 텍스트를 한 번에 처리하고 각 텍스트에 대한 정수 시퀀스를 반환한다.

corpus에 있던 하나의 문장 'in the town of athy one jeremy lanigan' 은 위의 과정에 따라서 토큰별로 정수 시퀀스로 반환된다.

sentence = corpus[0].split()
print(f'sample sentence: {sentence}')
# ['in', 'the', 'town', 'of', 'athy', 'one', 'jeremy', 'lanigan']
 
token_list = []
for word in sentence: 
  token_list.append(tokenizer.word_index[word])
print(token_list)
# [4, 2, 66, 8, 67, 68, 69, 70]
print(tokenizer.texts_to_sequences([corpus[0]]))
# [[4, 2, 66, 8, 67, 68, 69, 70]]
  • 여기서 texts_to_sequences 내에는 "[]" 배열 타입으로 넣어주어야 하고 해당 정수 인코딩으로 된 배열 안에 배열로 반환된다. 그렇기 때문에 배열에 0번째 인덱스로 가져온다.
  • 그 뒤에 n_gram_sequence = token_list[:i+1] 로 주어진 토큰 리스트에서 인덱스 0부터 i까지의 부분 시퀀스를 추출하는 작업을 수행한다.
    n-gram 텍스트 생성 과정인데, 위에서 'in the town of athy one jeremy lanigan'을

input -> label 로 했을 때
input : in the / output : town
intput : in the town / output : of
input : in the town of / output: athy ...

등으로 하는 작업이다.

max_sequence_len = max([len(x) for x in input_sequences])
input_sequences = np.array(pad_sequences(input_sequences, maxlen=max_sequence_len, padding='pre'))
xs, labels = input_sequences[:,:-1],input_sequences[:,-1]
ys = tf.keras.utils.to_categorical(labels, num_classes=total_words)
  • 해당 작업으로 만든 시퀀스 배열에서 가장 긴 배열의 길이를 구한 뒤에,
    가장 긴 배열의 길이를 기준으로 padding을 수행하고 여기서 패딩 옵션은 'pre'로 지정한다.
  • 텍스트를 생성할 때 시작 부분에 주요 정보가 위치해 있기 때문에, 시작 부분에 더 중요한 정보를 유실하지 않기 위해 padding시에 'pre'로 지정한다.
  • 학습을 위해서 xs, label을 input_sequences에서
    input_sequences[:,:-1]로 input_sequences에서 모든 행(row)과 마지막 열(column)을 제외한 부분을 추출한다. 즉, 각 행의 마지막 요소를 제외한 모든 요소를 포함하는 부분 시퀀스를 추출해서 이것은 입력 시퀀스에서 마지막 토큰을 제외한 부분을 학습 데이터로 할당한다.
    input_sequences[:,-1]:로 input_sequences에서 모든 행(row)의 마지막 열(column)을 추출한다. 즉, 각 행의 마지막 요소만을 포함하는 부분 시퀀스를 추출해서 입력 시퀀스의 마지막 토큰(혹은 단어)를 label로 할당한다.
elem_number = 6

print(f'token list: {xs[elem_number]}')
print(f'decoded to text: {tokenizer.sequences_to_texts([xs[elem_number]])}')

# token list: [ 0  0  0  4  2 66  8 67 68 69]
# decoded to text: ['in the town of athy one jeremy']

print(f'one-hot label: {ys[elem_number]}')
print(f'index of label: {np.argmax(ys[elem_number])}')

# output
one-hot label: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0.
 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
index of label: 70

  • 하나의 ele_number를 랜덤으로 6을 지정하고,
    학습 데이터에서 6번째를 출력해보고,
    해당 정수 인코딩된 시퀀스 데이터를 tokenizer.sequences_to_texts를 이용해 다시 텍스트로 변환하면 ['in the town of athy one jeremy'] 가 나온다.
  • 해당하는 label을 출력하면 원핫 인코딩 된 라벨이 나오고, argmax로 해당하는 인덱스 라벨인 '70'을 알아낼수 있고 해당 단어사전과 매핑해보면 'lanigan'이 등장한다.
print(tokenizer.index_word[70])

# lanigan

(5) 모델 빌드

# 모델 
model = Sequential([
          Embedding(total_words, 64, input_length=max_sequence_len-1),
          Bidirectional(LSTM(20)),
          Dense(total_words, activation='softmax')
])

# 모델 컴파일
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

# 모델 요약 
model.summary()
  • 텍스트 생성을 위해서 신경망을 구축하는데, Keras의 Sequential 모델을 사용해서 모델을 정의해서 Embedding, 양방향 LSTM, Dense층을 구성한다.

  • Embedding :
    단어 임베딩을 학습할 때 사용한다.
    입력 시퀀스의 각 단어를 고정된 크기의 밀집 벡터로 변환한다.
    입력으로 들어오는 단어들은 해당하는 인덱스의 임베딩 벡터로 매핑된다.
    total_words로 단어의 총 개수로, 토크나이저를 통해 만들어진 단어 집합의 크기이고 현재 임베딩 차원은 64로 고정했다. 각 단어가 64 차원의 벡터로 임베딩되는 것을 의미한다.
    input_length는 입력 시퀀스의 길이로, max_sequence_len-1 로 설정되어 있는데, 입력 시퀀스의 마지막 토큰을 제외한 길이를 나타내는 것이다.

  • Bidirectional LSTM :
    양방향 LSTM으로 시계열 데이터나 텔스트 데이터와 같은 순차적 데이터를 처리하는데 사용한다. 양방향 LSTM은 입력 시퀀스를 순방향과 역방향으로 모두 처리해서 더 많은 정보를 추출한다
    현재 20으로 LSTM의 unit의 개수를 나타내는데, LSTM이 내부적으로 가지는 뉴런의 수이다.

  • Dense :
    Dense 층은 전체 단어 집합에 대한 다중 분류를 수행하고, 모델이 다음에 등장할 단어를 예측하기 위해 softmax 활성화 함수를 사용한다.
    출력 뉴런의 개수는 total_words로 설정되어 있고, 단어 집합의 크기이다.

  • 모델을 컴파일 하기 위해서 현재 categorical_crossentory를 사용하고 있고, 다중 분류 문제를 다룰 때 사용되는 손실함수이다. 옵티마이저는 adam을 사용하고, 메트릭으로는 accuracy를 측정한다.

해당 모델에 대한 요약을 출력해서, 각 층에 대한 정보인 층 이름, 출력 크기, 파라미터 수 등을 확인한다.

Embedding 층 (Embedding):

Embedding 층은 입력으로 들어오는 텍스트 시퀀스를 임베딩합니다. 이 층은 단어를 고정된 크기의 밀집 벡터로 변환하여 신경망에 입력될 수 있도록 합니다.
출력 모양(Output Shape)은 (None, 10, 64)으로, 입력 시퀀스의 길이가 10이며, 각 단어가 64차원의 임베딩 벡터로 표현됩니다.
총 16,832개의 학습 가능한 파라미터가 있습니다.
Bidirectional LSTM 층 (Bidirectional):

Bidirectional LSTM은 양방향으로 시퀀스를 처리하여 순방향과 역방향의 정보를 결합하여 더 풍부한 표현을 만듭니다.
출력 모양은 (None, 40)으로, 40개의 LSTM 유닛이 있는 양방향 LSTM 층의 출력을 나타냅니다.
총 13,600개의 학습 가능한 파라미터가 있습니다.
Dense 층 (Dense):

Dense 층은 다음에 등장할 단어를 예측하기 위해 모델의 출력을 다중 분류하는 역할을 합니다.
출력 모양은 (None, 263)으로, 다음 단어를 나타내는 가능한 모든 단어의 확률 분포를 출력합니다.
총 10,783개의 학습 가능한 파라미터가 있습니다.
모델 요약 출력:

총 파라미터 수는 41,215개이며, 학습 가능한 파라미터와 비학습 가능한 파라미터로 나뉩니다.
학습 가능한 파라미터는 모델이 학습하는 동안 업데이트되는 파라미터를 나타냅니다.
비학습 가능한 파라미터는 Embedding 층의 경우에는 입력된 텍스트에 따라서만 변화되지만, 모델 학습 과정에서 업데이트되지 않는 파라미터를 나타냅니다.

위에 필요한 사전 지식들은 ML part에 정리할 예정이다.

(6) 모델 학습

history = model.fit(xs, ys, epochs=500)

model을 epochs 500 으로 학습한다.

  • "epochs = 500"은 모델을 학습할 때 전체 데이터셋을 총 500번 반복하여 학습한다는 의미이다. 에포크(epoch)란 모델이 전체 훈련 데이터셋을 한 번씩 학습하는 과정이다.

  • 에포크는 모델이 훈련 데이터를 학습하는 주기이고 한 번의 에포크가 끝날 때마다 모든 훈련 데이터가 모델에 한 번씩 전달되어 가중치(파라미터)가 업데이된다.
    따라서 에포크가 높을수록 모델은 더 많은 훈련 데이터를 보고 더 많이 학습하게 됩니다.

(7) 모델 평가

import matplotlib.pyplot as plt

def plot_graphs(history, string):
  plt.plot(history.history[string])
  plt.xlabel("Epochs")
  plt.ylabel(string)
  plt.show()

# 정확도 시각화
plot_graphs(history, 'accuracy')
  • plot_graphs 함수를 통해서 matplotlib 으로 epoch 당 정확도를 확인한다.

(8) 텍스트 생성 확인(예측)

학습한 모델을 사용하여 이제 자체 노래를 생성한다.
프로세스는
[1] 시드 텍스트를 입력
[2] 모델은 가장 가능성이 높은 다음 단어의 인덱스를 예측
[3] 역 단어 색인 사전에서 색인을 찾기
[4] 시드 텍스트에 다음 단어를 추가하기
[5] 결과를 모델에 다시 공급
[6] 원하는 노래 길이에 도달할 때까지 2~5단계가 반복됨

# 시드 텍스트 설정
seed_text = "Laurence went to Dublin"

# 예측하고자 하는 단어의 수
next_words = 100

# 예측할 단어의 수에 도달할때 까지 loop 
for _ in range(next_words):

	# 시드 텍스트를 토큰화를 통해서 텍스트를 정수화된 시퀀스 데이터로 변환 	token_list = tokenizer.texts_to_sequences([seed_text])[0]

	# 시퀀스 데이터 패딩 작업
	token_list = pad_sequences([token_list], maxlen=max_sequence_len-1, padding='pre')
	
	# 모델에게 시퀀스 데이터를 제공하여 다음 단어가 가장 높을 확률 예측
	probabilities = model.predict(token_list)

	# 가장 높은 확률을 예측한 단어 인덱스 가져오기
	predicted = np.argmax(probabilities, axis=-1)[0]

	# 패딩인 0이 아닌 경우에만 생성한 테스트를 뒤에 붙임
	if predicted != 0:
		output_word = tokenizer.index_word[predicted]
		seed_text += " " + output_word

# 결과 출력
print(seed_text)

위의 'Laurence went to Dublin'에 해당하는 텍스트로 생성한 텍스트는 아래와 같다.

Laurence went to Dublin up bees as dublin suppose suppose he hoops pound pound free hall hall invitation hall father gray hearty til gray and hearty the rat catchers daughter daughter father gray hearty and glisten glisten hearty suppose a man again suppose he rose fair rose rose relations forget invitation father gray hearty hearty were hearty the rat catchers daughter daughter father gray til gave hearty stepped til again again again again a youll call rose rose call father strangled harp hearty hearty suppose suppose suppose suppose suppose suppose stepped til suppose suppose suppose suppose suppose suppose suppose suppose suppose might ask forget

이러한 과정으로 DeepLearning.AI-TensorFlow-Developer-Specialization의 3코스 Natural Language Processing in TensorFlow의 4주차 Sequence models and literature 프로그래밍 실습인 lab 1 주차를 수행할 수 있다.

관련 git : https://github.com/heyggun/DeepLearning.AI-TensorFlow-Developer-Specialization/blob/main/Natural%20Language%20Processing%20in%20TensorFlow/W4/ungraded_labs/C3_W4_Lab_1.ipynb

profile
꿈꾸는 것도 개발처럼 깊게

0개의 댓글

관련 채용 정보