-- ๋ณธ ํฌ์คํ
์ ํ์ดํ ์น๋ก ๋ฐฐ์ฐ๋ ์์ฐ์ด ์ฒ๋ฆฌ (ํ๋น๋ฏธ๋์ด) ์ฑ
์ ์ฐธ๊ณ ํด์ ์์ฑ๋ ๊ธ์
๋๋ค.
-- ์์ค์ฝ๋๋ ์ฌ๊ธฐ
1. CBOW ๋
- Word2Vec CBOW ๋ชจ๋ธ
- ๋ค์ค ๋ถ๋ฅ ์์
- ๋จ์ด๋ฅผ ์ค์บํ์ฌ ๋จ์ด์ ๋ฌธ๋งฅ Window๋ฅผ ๋ง๋ ํ ๋ฌธ๋งฅ Window์์ ์ค์์ ๋จ์ด๋ฅผ ์ ๊ฑฐํ๊ณ ๋ฌธ๋งฅ WIndow๋ฅผ ํ์ฉํ์ฌ ๋๋ฝ ๋จ์ด๋ฅผ ์์ธกํ๋ ๋ชจ๋ธ
- ๋จ์ด๊ฐ ๋๋ฝ๋ ๋ฌธ์ฅ์์ ๋๋ฝ ๋จ์ด๊ฐ ๋ฌด์์ธ์ง ํ์ ํ๋ ์ญํ ์ ์ํ
2. ํ์ฉ ๋ฐ์ดํฐ
- http://bit.ly/2T5iU8J ์์ ๋ฉ๋ฆฌ ์ ธ๋ฆฌ์ ์์ค [ํ๋์ผ์ํ์ธ]์ ๋์งํธ ๋ฒ์ ์ ๋ฐ์ ๊ตฌ์ถํ ํ ์คํธ ๋ฐ์ดํฐ์ ํ์ฉ
- ํ์ดํ ์น์ Dataset ํด๋์ค๋ฅผ ๋ง๋ค๊ณ ๋ง์ง๋ง์ ๋ฐ์ดํฐ๋ฅผ ํ๋ จ, ๊ฒ์ฆ, ํ ์คํธ ์ธํธ๋ก ๋ถํ ํ์ฌ ์ฌ์ฉ
3. ๋ฐ์ดํฐ ์ ์ฒ๋ฆฌ
3.1 ํ ์คํธ๋ฅผ ๊ฐ๋ณ ๋ฌธ์ฅ์ผ๋ก ๋ถํ
# Split the raw text book into sentences
tokenizer = nltk.data.load('tokenizers/punkt/english.pickle')
with open(args.raw_dataset_txt) as fp:
book = fp.read()
sentences = tokenizer.tokenize(book)
print (len(sentences), "sentences")
print ("Sample:", sentences[100])
3.2 ๋ค์ ๊ฐ ๋ฌธ์ฅ์ ์๋ฌธ์๋ก ๋ณํํ๊ณ ๊ตฌ๋์ ์ ์์ ํ ์ ๊ฑฐ
- ์ ๊ท์์ ํ์ฉํ์ฌ ์ ๊ฑฐํด์ฃผ๊ณ , ๊ณต๋ฐฑ์ผ๋ก ๋ฌธ์์ด์๋ถํ ํ์ฌ ํ ํฐ ๋ฆฌ์คํธ๋ฅผ ์ถ์ถ
# Clean sentences
def preprocess_text(text):
text = ' '.join(word.lower() for word in text.split(" "))
text = re.sub(r"([.,!?])", r" \1 ", text)
text = re.sub(r"[^a-zA-Z.,!?]+", r" ", text)
return text
cleaned_sentences = [preprocess_text(sentence) for sentence in sentences]
3.3 ๋ฐ์ดํฐ๋ฅผ ์๋์ฐ ์ํ์ค๋ก ํํ
- CBOW๋ชจ๋ธ์ ์ต์ ํ ํ ์ ์๋๋ก ๋ฐ์ดํฐ์ ์ window์ ์ํ์ค๋ก ํํ
'''
# ์ด์ ์ ์ค์ ํด๋ ํ๋ผ๋ฏธํฐ ํ์ธํ๊ธฐ
args = Namespace(
raw_dataset_txt="data/books/frankenstein.txt",
window_size=5,
train_proportion=0.7,
val_proportion=0.15,
test_proportion=0.15,
output_munged_csv="data/books/frankenstein_with_splits.csv",
seed=1337
)
'''
# Global vars
MASK_TOKEN = "<MASK>"
# ์๋์ฐ๋ก ๋ง๋ค์ด์ฃผ๊ธฐ (window size = 5)
# ๊ฐ ๋ฌธ์ฅ์ ํ ํฐ ๋ฆฌ์คํธ๋ฅผ ์ํํ๋ฉด์ ์ง์ ๋ ํฌ๊ธฐ์ window๋ก ๋ฌถ์ด์ฃผ๊ธฐ
flatten = lambda outer_list: [item for inner_list in outer_list for item in inner_list]
windows = flatten([list(nltk.ngrams([MASK_TOKEN] * args.window_size + sentence.split(' ') + \
[MASK_TOKEN] * args.window_size, args.window_size * 2 + 1)) \
for sentence in tqdm_notebook(cleaned_sentences)])
# CBOW ๋ฐ์ดํฐ๋ก ๋ง๋ค์ด์ฃผ๊ธฐ
data = []
for window in tqdm_notebook(windows):
target_token = window[args.window_size]
context = []
for i, token in enumerate(window):
if token == MASK_TOKEN or i == args.window_size:
continue
else:
context.append(token)
data.append([' '.join(token for token in context), target_token])
# DataFrame์ ํํ๋ก ๋ณํ
cbow_data = pd.DataFrame(data, columns=["context", "target"])
โถ ์ง์ ๋ ํฌ๊ธฐ์ Window๋ก ๋ฌถ์ด์ค๋ค๋ ๋ง์ ๊ทธ๋ฆผ์ผ๋ก ํํํ๋ฉด ์๋์ ๊ฐ๋ค.
- CBOW ์์ ์ ์ ๊ทธ๋ฆผ๊ณผ ๊ฐ๋ค.
- ์ผ์ชฝ๋ฌธ๋งฅ๊ณผ ์ค๋ฅธ์ชฝ ๋ฌธ๋งฅ์ ์ฌ์ฉํ์ฌ (๋นจ๊ฐ๋จ์ด)๋ฅผ ์์ธกํ๋ค.
- ๋ฌธ๋งฅ์ ์๋์ฐ ๊ธธ์ด๋ ์์ชฝ์ผ๋ก 2์์ ๋ณผ ์ ์๋ค.
- ํ ์คํธ ์๋ฅผ ์ฌ๋ผ์ด๋ฉํ๋ ์๋์ฐ๊ฐ ์ง๋ํ์ต ์ํ์ ์์ฑํ๋ค.
- ๊ฐ ์ํ์ ํ๊น์ (๋นจ๊ฐ๋จ์ด) ์ด๊ณ , ์ํ์ ์๋์ฐ์ ์๋ ๋๋จธ์ง ๋จ์ด์ด๋ค.
- ๊ธธ์ด๊ฐ 2๊ฐ์๋๋ window๋ ์ ์ ํ๊ฒ ํจ๋ฉ๋๋ค.
3.4 ๋ฐ์ดํฐ ๋ถํ
- ๋ฐ์ดํฐ๋ฅผ train 70%, validation 15%, test 15%๋ก ๋ถํ ํ ๊ฒ์ด๋ค. (์ด์ ์ args์์ ์ง์ )
- ํ๋ จtrain ์ธํธ๋ ํ๋ผ๋ฏธํฐ๋ฅผ ์ ๋ฐ์ดํธํ๋๋ฐ ์ฌ์ฉํ๊ณ
- ๊ฒ์ฆval ์ธํธ๋ ๋ชจ๋ธ์ ์ฑ๋ฅ์ ์ธก์ ํ๋๋ฐ ์ฌ์ฉ๋๋ค.
- ํ ์คํธtest ์ธํธ๋ ๋ง์ง๋ง์ ๊ฐ์ฅ ์ข์ ๋ชจ๋ธ์ ๋ฑ ํ๋ฒ๋ง ์ฌ์ฉ๋๋ค.
# Create split data
n = len(cbow_data)
def get_split(row_num):
if row_num <= n*args.train_proportion:
return 'train'
elif (row_num > n*args.train_proportion) and (row_num <= n*args.train_proportion + n*args.val_proportion):
return 'val'
else:
return 'test'
cbow_data['split']= cbow_data.apply(lambda row: get_split(row.name), axis=1)
cbow_data.head()
2. Dataset class
์ ์ฒด์ฝ๋ ๋๋ณด๊ธฐ ํด๋ฆญ
class CBOWDataset(Dataset):
# CBOWDataset์ ์์ฑ์ ๋ฉ์๋
# CBOWDataset์ ๊ฒฐ๊ตญ cbow๋ฐ์ดํฐ์
๊ณผ vectorizer๋ฅผ ์์ฑํ๋ค!
def __init__(self, cbow_df, vectorizer):
"""
๋งค๊ฐ๋ณ์:
cbow_df (pandas.DataFrame): ๋ฐ์ดํฐ์
vectorizer (CBOWVectorizer): ๋ฐ์ดํฐ์
์์ ๋ง๋ CBOWVectorizer ๊ฐ์ฒด
"""
self.cbow_df = cbow_df
self._vectorizer = vectorizer
measure_len = lambda context: len(context.split(" "))
# cbow df ๋ฐ์ดํฐ์ค ๊ฐ์ฅ ๊ธด ๊ฒ์ ์ํ์ค์ ๊ธธ์ด๋ก ์ค์ ํ๋ค
self._max_seq_length = max(map(measure_len, cbow_df.context))
self.train_df = self.cbow_df[self.cbow_df.split=='train']
self.train_size = len(self.train_df)
self.val_df = self.cbow_df[self.cbow_df.split=='val']
self.validation_size = len(self.val_df)
self.test_df = self.cbow_df[self.cbow_df.split=='test']
self.test_size = len(self.test_df)
self._lookup_dict = {'train': (self.train_df, self.train_size),
'val': (self.val_df, self.validation_size),
'test': (self.test_df, self.test_size)}
self.set_split('train')
@classmethod
def load_dataset_and_make_vectorizer(cls, cbow_csv):
"""๋ฐ์ดํฐ์
์ ๋ก๋ํ๊ณ ์ฒ์๋ถํฐ ์๋ก์ด Vectorizer ๋ง๋ค๊ธฐ
๋งค๊ฐ๋ณ์:
cbow_csv (str): ๋ฐ์ดํฐ์
์ ์์น
๋ฐํ๊ฐ:
CBOWDataset์ ์ธ์คํด์ค
"""
cbow_df = pd.read_csv(cbow_csv)
train_cbow_df = cbow_df[cbow_df.split=='train']
# from_dataframe : vocabulary ํด๋์ค๋ก๋ถํฐ vocab์ ๋ฐ์์ค๊ณ , ํด๋น vocab์ ์ฌ์ฉํด์ ๋จ์ด์ ์ ์๋ฅผ ๋งคํํด์ค๋ค.
# : ๋ฐํ๊ฐ์ ๋จ์ด์ ์ ์๊ฐ ๋งคํ๋ cbow_vocab ์ด๋ค.
# --> ์ฆ ์ด๊ฒ์ด vectorizer์ด๊ณ cls์ ๋งค๊ฐ๋ณ์๋ก ๋ค์ด๊ฐ๊ฒ ๋๋ค.
return cls(cbow_df, CBOWVectorizer.from_dataframe(train_cbow_df))
@classmethod
def load_dataset_and_load_vectorizer(cls, cbow_csv, vectorizer_filepath):
""" ๋ฐ์ดํฐ์
์ ๋ก๋ํ๊ณ ์๋ก์ด CBOWVectorizer ๊ฐ์ฒด๋ฅผ ๋ง๋ญ๋๋ค.
์บ์๋ CBOWVectorizer ๊ฐ์ฒด๋ฅผ ์ฌ์ฌ์ฉํ ๋ ์ฌ์ฉํฉ๋๋ค.
๋งค๊ฐ๋ณ์:
cbow_csv (str): ๋ฐ์ดํฐ์
์ ์์น
vectorizer_filepath (str): CBOWVectorizer ๊ฐ์ฒด์ ์ ์ฅ ์์น
๋ฐํ๊ฐ:
CBOWVectorizer์ ์ธ์คํด์ค
"""
cbow_df = pd.read_csv(cbow_csv)
# load_vectorizer_only : vectorizer์ ํ์ผ์ ๋ฐ์์์ cbow_vocab (์ ์๊ฐ ๋งคํ๋ ๋จ์ด)๋ฅผ ๋ฐํํ๋ค.
# --> ์ฆ ์ด๊ฒ์ด vectorizer์ด๊ณ cls์ ๋งค๊ฐ๋ณ์๋ก ๋ค์ด๊ฐ๊ฒ ๋๋ค.
vectorizer = cls.load_vectorizer_only(vectorizer_filepath)
return cls(cbow_df, vectorizer)
@staticmethod
def load_vectorizer_only(vectorizer_filepath):
"""ํ์ผ์์ CBOWVectorizer ๊ฐ์ฒด๋ฅผ ๋ก๋ํ๋ ์ ์ ๋ฉ์๋
๋งค๊ฐ๋ณ์:
vectorizer_filepath (str): ์ง๋ ฌํ๋ CBOWVectorizer ๊ฐ์ฒด์ ์์น
๋ฐํ๊ฐ:
CBOWVectorizer์ ์ธ์คํด์ค
"""
with open(vectorizer_filepath) as fp:
# from_serializable() : vocab์ ๋ฐ์์์ ์ ์๊ฐ ๋งคํ๋ vocab์ ์ป๋๋ค.
# ---> ์ฆ, ์ด๊ฒ vectorizer
return CBOWVectorizer.from_serializable(json.load(fp))
def save_vectorizer(self, vectorizer_filepath):
"""CBOWVectorizer ๊ฐ์ฒด๋ฅผ json ํํ๋ก ๋์คํฌ์ ์ ์ฅํฉ๋๋ค
๋งค๊ฐ๋ณ์:
vectorizer_filepath (str): CBOWVectorizer ๊ฐ์ฒด์ ์ ์ฅ ์์น
"""
with open(vectorizer_filepath, "w") as fp:
json.dump(self._vectorizer.to_serializable(), fp)
def get_vectorizer(self):
""" ๋ฒกํฐ ๋ณํ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค """
return self._vectorizer
def set_split(self, split="train"):
""" ๋ฐ์ดํฐํ๋ ์์ ์๋ ์ด์ ์ฌ์ฉํด ๋ถํ ์ธํธ๋ฅผ ์ ํํฉ๋๋ค """
self._target_split = split
self._target_df, self._target_size = self._lookup_dict[split]
def __len__(self):
return self._target_size
def __getitem__(self, index):
"""ํ์ดํ ์น ๋ฐ์ดํฐ์
์ ์ฃผ์ ์ง์
๋ฉ์๋
๋งค๊ฐ๋ณ์:
index (int): ๋ฐ์ดํฐ ํฌ์ธํธ์ ์ธ๋ฑ์ค
๋ฐํ๊ฐ:
๋ฐ์ดํฐ ํฌ์ธํธ์ ํน์ฑ(x_data)๊ณผ ๋ ์ด๋ธ(y_target)๋ก ์ด๋ฃจ์ด์ง ๋์
๋๋ฆฌ
"""
row = self._target_df.iloc[index]
context_vector = \
self._vectorizer.vectorize(row.context, self._max_seq_length)
target_index = self._vectorizer.cbow_vocab.lookup_token(row.target)
return {'x_data': context_vector,
'y_target': target_index}
def get_num_batches(self, batch_size):
"""๋ฐฐ์น ํฌ๊ธฐ๊ฐ ์ฃผ์ด์ง๋ฉด ๋ฐ์ดํฐ์
์ผ๋ก ๋ง๋ค ์ ์๋ ๋ฐฐ์น ๊ฐ์๋ฅผ ๋ฐํํฉ๋๋ค
๋งค๊ฐ๋ณ์:
batch_size (int)
๋ฐํ๊ฐ:
๋ฐฐ์น ๊ฐ์
"""
return len(self) // batch_size
def generate_batches(dataset, batch_size, shuffle=True,
drop_last=True, device="cpu"):
"""
ํ์ดํ ์น DataLoader๋ฅผ ๊ฐ์ธ๊ณ ์๋ ์ ๋๋ ์ดํฐ ํจ์.
๊ฑฑ ํ
์๋ฅผ ์ง์ ๋ ์ฅ์น๋ก ์ด๋ํฉ๋๋ค.
"""
dataloader = DataLoader(dataset=dataset, batch_size=batch_size,
shuffle=shuffle, drop_last=drop_last)
for data_dict in dataloader:
out_data_dict = {}
for name, tensor in data_dict.items():
out_data_dict[name] = data_dict[name].to(device)
yield out_data_dict
๋ง๋ค์ด์ง ๋ฐ์ดํฐ์ ๊ณผ ํ๊ฒ์ pandas dataframe ํํ๋ก ๋ก๋๋๊ณ , CBOWDatasetํด๋์ค์์ ์ธ๋ฑ์ฑ ๋๋ค.
2.1 Dataset ํด๋์ค ๋ด๋ถ ๋ฉ์๋ ์ดํด๋ณด๊ธฐ
โถ ์์ฑ์ ๋ฉ์๋ __init__(self, cbow_df, vectorizer)
- cbow ๋ฐ์ดํฐ์ (train, val, test df)๊ณผ ๋ฐ์ดํฐ์ ์์ ๋ง๋ vectorizer ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค.
# CBOWDataset์ ์์ฑ์ ๋ฉ์๋
# CBOWDataset์ ๊ฒฐ๊ตญ cbow๋ฐ์ดํฐ์
๊ณผ vectorizer๋ฅผ ์์ฑํ๋ค!
def __init__(self, cbow_df, vectorizer):
"""
๋งค๊ฐ๋ณ์:
cbow_df (pandas.DataFrame): ๋ฐ์ดํฐ์
vectorizer (CBOWVectorizer): ๋ฐ์ดํฐ์
์์ ๋ง๋ CBOWVectorizer ๊ฐ์ฒด
"""
self.cbow_df = cbow_df
self._vectorizer = vectorizer
measure_len = lambda context: len(context.split(" "))
# cbow df ๋ฐ์ดํฐ์ค ๊ฐ์ฅ ๊ธด ๊ฒ์ ์ํ์ค์ ๊ธธ์ด๋ก ์ค์ ํ๋ค
self._max_seq_length = max(map(measure_len, cbow_df.context))
self.train_df = self.cbow_df[self.cbow_df.split=='train']
self.train_size = len(self.train_df)
self.val_df = self.cbow_df[self.cbow_df.split=='val']
self.validation_size = len(self.val_df)
self.test_df = self.cbow_df[self.cbow_df.split=='test']
self.test_size = len(self.test_df)
self._lookup_dict = {'train': (self.train_df, self.train_size),
'val': (self.val_df, self.validation_size),
'test': (self.test_df, self.test_size)}
self.set_split('train')
โถ load_dataset_and_make_vectorizer(cls, cbow_csv)
โถ load_dataset_and_load_vectorizer(cls, cbow_csv, vectorizer_filepath)
- make
- vectorizer๊ฐ ์กด์ฌํ์ง ์์ ๋ ํด๋น ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ค.
- cbow csv ํ์ผ์ ๋ฐ์์์ vectorizer ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ฃผ๋ ๋ฉ์๋
- return ๊ฐ์ ๋ณด๋ฉด, vetorizer ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ ๋ค์ clsํจ์์ ๋ฃ์ด์ฃผ๊ธฐ ๋๋ฌธ์ ๊ฒฐ๊ตญ Dataset์ ์ธ์คํด์ค๊ฐ ๋ฐํ๊ฐ์ด๋ผ๊ณ ํ ์ ์๋ค.
- cbow_csv ๋งค๊ฐ๋ณ์์๋ ํ์ผ์ ์์น๋ฅผ ๋ฐ๋๋ค.
- dataset = CBOWDataset.load_dataset_and_make_vectorizer(args.cbow_csv) ์ด๋ ๊ฒ ๋ฐ์ดํฐ์ ์ ์์ฑํ๊ฒ ๋๋ค.
- load
- ์ด๋ฏธ vectorizer ๊ฐ์ฒด๊ฐ ์กด์ฌํ๋ค๋ฉด ํด๋น ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ค.
- cbow csv ํ์ผ๊ณผ vectorizer ํ์ผ์ ๋ฐ์์์ ์ฌ์ฉํ๋๋ก ๋์ด์๋ค.
- make์ ๋ง์ฐฌ๊ฐ์ง๋ก ๊ฒฐ๊ตญ cls๋ก ๋ค์ด๊ฐ๊ธฐ ๋๋ฌธ์ dataset์ ์ธ์คํด์ค๋ก ๋ฐํ๋๋ค๊ณ ์๊ฐํ๋ฉด ๋๋ค.
- dataset = CBOWDataset.load_dataset_and_load_vectorizer(args.cbow_csv) ์ด๋ ๊ฒ ๋๊ฐ์ ํ์ผ์ ๋ก๋ํ๊ฒ ๋๋ค.
@classmethod
def load_dataset_and_make_vectorizer(cls, cbow_csv):
"""๋ฐ์ดํฐ์
์ ๋ก๋ํ๊ณ ์ฒ์๋ถํฐ ์๋ก์ด Vectorizer ๋ง๋ค๊ธฐ
๋งค๊ฐ๋ณ์:
cbow_csv (str): ๋ฐ์ดํฐ์
์ ์์น
๋ฐํ๊ฐ:
CBOWDataset์ ์ธ์คํด์ค
"""
cbow_df = pd.read_csv(cbow_csv)
train_cbow_df = cbow_df[cbow_df.split=='train']
# from_dataframe : vocabulary ํด๋์ค๋ก๋ถํฐ vocab์ ๋ฐ์์ค๊ณ , ํด๋น vocab์ ์ฌ์ฉํด์ ๋จ์ด์ ์ ์๋ฅผ ๋งคํํด์ค๋ค.
# : ๋ฐํ๊ฐ์ ๋จ์ด์ ์ ์๊ฐ ๋งคํ๋ cbow_vocab ์ด๋ค.
# --> ์ฆ ์ด๊ฒ์ด vectorizer์ด๊ณ cls์ ๋งค๊ฐ๋ณ์๋ก ๋ค์ด๊ฐ๊ฒ ๋๋ค.
return cls(cbow_df, CBOWVectorizer.from_dataframe(train_cbow_df))
@classmethod
def load_dataset_and_load_vectorizer(cls, cbow_csv, vectorizer_filepath):
""" ๋ฐ์ดํฐ์
์ ๋ก๋ํ๊ณ ์๋ก์ด CBOWVectorizer ๊ฐ์ฒด๋ฅผ ๋ง๋ญ๋๋ค.
์บ์๋ CBOWVectorizer ๊ฐ์ฒด๋ฅผ ์ฌ์ฌ์ฉํ ๋ ์ฌ์ฉํฉ๋๋ค.
๋งค๊ฐ๋ณ์:
cbow_csv (str): ๋ฐ์ดํฐ์
์ ์์น
vectorizer_filepath (str): CBOWVectorizer ๊ฐ์ฒด์ ์ ์ฅ ์์น
๋ฐํ๊ฐ:
CBOWVectorizer์ ์ธ์คํด์ค
"""
cbow_df = pd.read_csv(cbow_csv)
# load_vectorizer_only : vectorizer์ ํ์ผ์ ๋ฐ์์์ cbow_vocab (์ ์๊ฐ ๋งคํ๋ ๋จ์ด)๋ฅผ ๋ฐํํ๋ค.
# --> ์ฆ ์ด๊ฒ์ด vectorizer์ด๊ณ cls์ ๋งค๊ฐ๋ณ์๋ก ๋ค์ด๊ฐ๊ฒ ๋๋ค.
vectorizer = cls.load_vectorizer_only(vectorizer_filepath)
return cls(cbow_df, vectorizer)
โถ load_vectorizer_only(vectorizer_filepath)
โถ save_vectorizer(self, vectorier_filepath)
โถ get_vectorizer(self)
โถ set_split(self, split='train')
โถ get_num_batches(self, batch_size)
@staticmethod
def load_vectorizer_only(vectorizer_filepath):
"""ํ์ผ์์ CBOWVectorizer ๊ฐ์ฒด๋ฅผ ๋ก๋ํ๋ ์ ์ ๋ฉ์๋
๋งค๊ฐ๋ณ์:
vectorizer_filepath (str): ์ง๋ ฌํ๋ CBOWVectorizer ๊ฐ์ฒด์ ์์น
๋ฐํ๊ฐ:
CBOWVectorizer์ ์ธ์คํด์ค
"""
with open(vectorizer_filepath) as fp:
# from_serializable() : vocab์ ๋ฐ์์์ ์ ์๊ฐ ๋งคํ๋ vocab์ ์ป๋๋ค.
# ---> ์ฆ, ์ด๊ฒ vectorizer
return CBOWVectorizer.from_serializable(json.load(fp))
def save_vectorizer(self, vectorizer_filepath):
"""CBOWVectorizer ๊ฐ์ฒด๋ฅผ json ํํ๋ก ๋์คํฌ์ ์ ์ฅํฉ๋๋ค
๋งค๊ฐ๋ณ์:
vectorizer_filepath (str): CBOWVectorizer ๊ฐ์ฒด์ ์ ์ฅ ์์น
"""
with open(vectorizer_filepath, "w") as fp:
json.dump(self._vectorizer.to_serializable(), fp)
def get_vectorizer(self):
""" ๋ฒกํฐ ๋ณํ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค """
return self._vectorizer
def set_split(self, split="train"):
""" ๋ฐ์ดํฐํ๋ ์์ ์๋ ์ด์ ์ฌ์ฉํด ๋ถํ ์ธํธ๋ฅผ ์ ํํฉ๋๋ค """
self._target_split = split
self._target_df, self._target_size = self._lookup_dict[split]
def get_num_batches(self, batch_size):
"""๋ฐฐ์น ํฌ๊ธฐ๊ฐ ์ฃผ์ด์ง๋ฉด ๋ฐ์ดํฐ์
์ผ๋ก ๋ง๋ค ์ ์๋ ๋ฐฐ์น ๊ฐ์๋ฅผ ๋ฐํํฉ๋๋ค
๋งค๊ฐ๋ณ์:
batch_size (int)
๋ฐํ๊ฐ:
๋ฐฐ์น ๊ฐ์
"""
return len(self) // batch_size
โถ __len__ / __getitem__ ๋ฉ์๋
def __len__(self):
return self._target_size
def __getitem__(self, index):
"""ํ์ดํ ์น ๋ฐ์ดํฐ์
์ ์ฃผ์ ์ง์
๋ฉ์๋
๋งค๊ฐ๋ณ์:
index (int): ๋ฐ์ดํฐ ํฌ์ธํธ์ ์ธ๋ฑ์ค
๋ฐํ๊ฐ:
๋ฐ์ดํฐ ํฌ์ธํธ์ ํน์ฑ(x_data)๊ณผ ๋ ์ด๋ธ(y_target)๋ก ์ด๋ฃจ์ด์ง ๋์
๋๋ฆฌ
"""
row = self._target_df.iloc[index]
context_vector = \
self._vectorizer.vectorize(row.context, self._max_seq_length)
target_index = self._vectorizer.cbow_vocab.lookup_token(row.target)
return {'x_data': context_vector,
'y_target': target_index}
2.2 ๋ณธ ์ฝ๋์๋ DataLoader๋ฅผ ๊ฐ์ธ๊ณ ์๋ ์ ๋๋ ์ดํฐ ํจ์๊ฐ ์ถ๊ฐ๋์ด์๋ค.
def generate_batches(dataset, batch_size, shuffle=True,
drop_last=True, device="cpu"):
"""
ํ์ดํ ์น DataLoader๋ฅผ ๊ฐ์ธ๊ณ ์๋ ์ ๋๋ ์ดํฐ ํจ์.
๊ฑฑ ํ
์๋ฅผ ์ง์ ๋ ์ฅ์น๋ก ์ด๋ํฉ๋๋ค.
"""
dataloader = DataLoader(dataset=dataset, batch_size=batch_size,
shuffle=shuffle, drop_last=drop_last)
for data_dict in dataloader:
out_data_dict = {}
for name, tensor in data_dict.items():
out_data_dict[name] = data_dict[name].to(device)
yield out_data_dict
3. Vectorizer class
- ์ดํ ์ฌ์ ์ ์์ฑํ๊ณ ๊ด๋ฆฌํ๋ ํด๋์ค
- ๋ฌธ๋งฅ์ ์ธ๋ฑ์ค๋ฅผ ๋ํ๋ด๋ ์ ์ ๋ฒกํฐ๋ฅผ๋ง๋ค์ด์ ๋ฐํํ๋ค.
- ๋ฌธ๋งฅ์ ํ ํฐ ์๊ฐ ์ต๋ ๊ธธ์ด๋ณด๋ค ์์ผ๋ฉด 0์ผ๋ก ์ฑ์์ง๋ ์ ๋กํจ๋ฉ์ ์ํนํ๋ค.
vectorizer ์ ์ฒด์ฝ๋๋ ๋๋ณด๊ธฐ ํด๋ฆญ
class CBOWVectorizer(object):
""" ์ดํ ์ฌ์ ์ ์์ฑํ๊ณ ๊ด๋ฆฌํฉ๋๋ค """
def __init__(self, cbow_vocab):
"""
๋งค๊ฐ๋ณ์:
cbow_vocab (Vocabulary): ๋จ์ด๋ฅผ ์ ์์ ๋งคํํฉ๋๋ค
"""
self.cbow_vocab = cbow_vocab
def vectorize(self, context, vector_length=-1):
"""
๋งค๊ฐ๋ณ์:
context (str): ๊ณต๋ฐฑ์ผ๋ก ๋๋์ด์ง ๋จ์ด ๋ฌธ์์ด
vector_length (int): ์ธ๋ฑ์ค ๋ฒกํฐ์ ๊ธธ์ด ๋งค๊ฐ๋ณ์
"""
indices = [self.cbow_vocab.lookup_token(token) for token in context.split(' ')]
if vector_length < 0:
vector_length = len(indices)
out_vector = np.zeros(vector_length, dtype=np.int64)
out_vector[:len(indices)] = indices
out_vector[len(indices):] = self.cbow_vocab.mask_index
return out_vector
@classmethod
def from_dataframe(cls, cbow_df):
"""๋ฐ์ดํฐ์
๋ฐ์ดํฐํ๋ ์์์ Vectorizer ๊ฐ์ฒด๋ฅผ ๋ง๋ญ๋๋ค
๋งค๊ฐ๋ณ์::
cbow_df (pandas.DataFrame): ํ๊น ๋ฐ์ดํฐ์
๋ฐํ๊ฐ:
CBOWVectorizer ๊ฐ์ฒด
"""
cbow_vocab = Vocabulary()
for index, row in cbow_df.iterrows():
for token in row.context.split(' '):
cbow_vocab.add_token(token)
cbow_vocab.add_token(row.target)
return cls(cbow_vocab)
@classmethod
def from_serializable(cls, contents):
cbow_vocab = \
Vocabulary.from_serializable(contents['cbow_vocab'])
return cls(cbow_vocab=cbow_vocab)
def to_serializable(self):
return {'cbow_vocab': self.cbow_vocab.to_serializable()}
3.1 Vectorizer ๋ด๋ถ ๋ฉ์๋ ์ดํด๋ณด๊ธฐ
โถ Vectorizer ์์ฑ์ ๋ฉ์๋ __init__(self, cbow_vocab)
- ๋จ์ด๋ฅผ ์ ์์ ๋งคํํ cbow vocab์ ๋ฐํํ๋ค.
def __init__(self, cbow_vocab):
"""
๋งค๊ฐ๋ณ์:
cbow_vocab (Vocabulary): ๋จ์ด๋ฅผ ์ ์์ ๋งคํํฉ๋๋ค
"""
self.cbow_vocab = cbow_vocab
โถ vectorizer(self, context, vector_length = 1)
- ๋ฌธ์์ด๊ณผ ์ธ๋ฑ์ค ๋ฒกํฐ์ ๊ธธ์ด๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ๋๋ค
def vectorize(self, context, vector_length=-1):
"""
๋งค๊ฐ๋ณ์:
context (str): ๊ณต๋ฐฑ์ผ๋ก ๋๋์ด์ง ๋จ์ด ๋ฌธ์์ด
vector_length (int): ์ธ๋ฑ์ค ๋ฒกํฐ์ ๊ธธ์ด ๋งค๊ฐ๋ณ์
"""
indices = [self.cbow_vocab.lookup_token(token) for token in context.split(' ')]
if vector_length < 0:
vector_length = len(indices)
# ์ผ๋จ ๋ฒกํฐ ๊ธธ์ด๋งํผ์ zero ๋ฆฌ์คํธ๋ฅผ ์์ฑํด์ค๋ค. (์ ๋กํจ๋ฉ)
out_vector = np.zeros(vector_length, dtype=np.int64)
out_vector[:len(indices)] = indices
out_vector[len(indices):] = self.cbow_vocab.mask_index
return out_vector
โถ from_dataframe(cls, cbow_df)
- ๋ฐ์ดํฐํ๋ ์์ ํํ๋ก ๋์ด์๋ cbow df๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์์จ๋ค.
- vocab์ด๋ผ๋ vocabulary ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ , ํด๋น vocab์ผ๋ก ์ ์๋ฅผ ๋งคํ
@classmethod
def from_dataframe(cls, cbow_df):
"""๋ฐ์ดํฐ์
๋ฐ์ดํฐํ๋ ์์์ Vectorizer ๊ฐ์ฒด๋ฅผ ๋ง๋ญ๋๋ค
๋งค๊ฐ๋ณ์::
cbow_df (pandas.DataFrame): ํ๊น ๋ฐ์ดํฐ์
๋ฐํ๊ฐ:
CBOWVectorizer ๊ฐ์ฒด
"""
cbow_vocab = Vocabulary()
for index, row in cbow_df.iterrows():
for token in row.context.split(' '):
# add_tocken(aa) : aa์ ์์ํ๋ ์ธ๋ฑ์ค๋ฅผ ๋ฐํํด์ค๋ค.
cbow_vocab.add_token(token)
cbow_vocab.add_token(row.target)
# ์
return cls(cbow_vocab)
โถ from_serializable(cls, contents)
โถ to_serializable(self)
- from
- vocab์ ๋ฐ์์์ ์ ์๊ฐ ๋งคํ๋ vocab์ ์ป๋๋ค.
- ๋ฐํ๊ฐ์ cls์ด๋ฏ๋ก ๊ฒฐ๊ตญ vectorizer์ ๊ฐ์ฒด
- to
- ์ง๋ ฌํ๋ vocab์ผ๋ก ๋ง๋ค์ด์ฃผ๋ ์ญํ
@classmethod
def from_serializable(cls, contents):
cbow_vocab = \
Vocabulary.from_serializable(contents['cbow_vocab'])
return cls(cbow_vocab=cbow_vocab)
def to_serializable(self):
return {'cbow_vocab': self.cbow_vocab.to_serializable()}
4. Vocabulary class
๋งคํ์ ์ํด ํ ์คํธ๋ฅผ ์ฒ๋ฆฌํ๊ณ ์ดํ ์ฌ์ ์ ๋ง๋๋ ํด๋์ค์ด๋ค. ์ด์ ํฌ์คํ ์ vocabulary class์ ๊ตฌ์ฑ๊ณผ ํจ์๊ฐ ๋์ผํ๋ค. ๋ฐ๋ผ์ (๋๋ณด๊ธฐํด๋ฆญ) ์ ์ฒด์ฝ๋๋ง ์ฒจ๋ถํ๊ณ ๊ฐ๋จํ ์ค๋ช ๋ง ๋ง๋ถ์ด๊ฒ ๋ค.
class Vocabulary(object):
""" ๋งคํ์ ์ํด ํ
์คํธ๋ฅผ ์ฒ๋ฆฌํ๊ณ ์ดํ ์ฌ์ ์ ๋ง๋๋ ํด๋์ค """
def __init__(self, token_to_idx=None, mask_token="<MASK>", add_unk=True, unk_token="<UNK>"):
"""
๋งค๊ฐ๋ณ์:
token_to_idx (dict): ๊ธฐ์กด ํ ํฐ-์ธ๋ฑ์ค ๋งคํ ๋์
๋๋ฆฌ
mask_token (str): Vocabulary์ ์ถ๊ฐํ MASK ํ ํฐ.
๋ชจ๋ธ ํ๋ผ๋ฏธํฐ๋ฅผ ์
๋ฐ์ดํธํ๋๋ฐ ์ฌ์ฉํ์ง ์๋ ์์น๋ฅผ ๋ํ๋
๋๋ค.
add_unk (bool): UNK ํ ํฐ์ ์ถ๊ฐํ ์ง ์ง์ ํ๋ ํ๋๊ทธ
unk_token (str): Vocabulary์ ์ถ๊ฐํ UNK ํ ํฐ
"""
if token_to_idx is None:
token_to_idx = {}
self._token_to_idx = token_to_idx
self._idx_to_token = {idx: token
for token, idx in self._token_to_idx.items()}
self._add_unk = add_unk
self._unk_token = unk_token
self._mask_token = mask_token
self.mask_index = self.add_token(self._mask_token)
self.unk_index = -1
if add_unk:
self.unk_index = self.add_token(unk_token)
def to_serializable(self):
""" ์ง๋ ฌํํ ์ ์๋ ๋์
๋๋ฆฌ๋ฅผ ๋ฐํํฉ๋๋ค """
return {'token_to_idx': self._token_to_idx,
'add_unk': self._add_unk,
'unk_token': self._unk_token,
'mask_token': self._mask_token}
@classmethod
def from_serializable(cls, contents):
""" ์ง๋ ฌํ๋ ๋์
๋๋ฆฌ์์ Vocabulary ๊ฐ์ฒด๋ฅผ ๋ง๋ญ๋๋ค """
return cls(**contents)
def add_token(self, token):
""" ํ ํฐ์ ๊ธฐ๋ฐ์ผ๋ก ๋งคํ ๋์
๋๋ฆฌ๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค
๋งค๊ฐ๋ณ์:
token (str): Vocabulary์ ์ถ๊ฐํ ํ ํฐ
๋ฐํ๊ฐ:
index (int): ํ ํฐ์ ์์ํ๋ ์ ์
"""
if token in self._token_to_idx:
index = self._token_to_idx[token]
else:
index = len(self._token_to_idx)
self._token_to_idx[token] = index
self._idx_to_token[index] = token
return index
def add_many(self, tokens):
""" ํ ํฐ ๋ฆฌ์คํธ๋ฅผ Vocabulary์ ์ถ๊ฐํฉ๋๋ค.
๋งค๊ฐ๋ณ์:
tokens (list): ๋ฌธ์์ด ํ ํฐ ๋ฆฌ์คํธ
๋ฐํ๊ฐ:
indices (list): ํ ํฐ ๋ฆฌ์คํธ์ ์์๋๋ ์ธ๋ฑ์ค ๋ฆฌ์คํธ
"""
return [self.add_token(token) for token in tokens]
def lookup_token(self, token):
""" ํ ํฐ์ ๋์ํ๋ ์ธ๋ฑ์ค๋ฅผ ์ถ์ถํฉ๋๋ค.
ํ ํฐ์ด ์์ผ๋ฉด UNK ์ธ๋ฑ์ค๋ฅผ ๋ฐํํฉ๋๋ค.
๋งค๊ฐ๋ณ์:
token (str): ์ฐพ์ ํ ํฐ
๋ฐํ๊ฐ:
index (int): ํ ํฐ์ ํด๋นํ๋ ์ธ๋ฑ์ค
๋
ธํธ:
UNK ํ ํฐ์ ์ฌ์ฉํ๋ ค๋ฉด (Vocabulary์ ์ถ๊ฐํ๊ธฐ ์ํด)
`unk_index`๊ฐ 0๋ณด๋ค ์ปค์ผ ํฉ๋๋ค.
"""
if self.unk_index >= 0:
return self._token_to_idx.get(token, self.unk_index)
else:
return self._token_to_idx[token]
def lookup_index(self, index):
""" ์ธ๋ฑ์ค์ ํด๋นํ๋ ํ ํฐ์ ๋ฐํํฉ๋๋ค.
๋งค๊ฐ๋ณ์:
index (int): ์ฐพ์ ์ธ๋ฑ์ค
๋ฐํ๊ฐ:
token (str): ์ธํ
์ค์ ํด๋นํ๋ ํ ํฐ
์๋ฌ:
KeyError: ์ธ๋ฑ์ค๊ฐ Vocabulary์ ์์ ๋ ๋ฐ์ํฉ๋๋ค.
"""
if index not in self._idx_to_token:
raise KeyError("the index (%d) is not in the Vocabulary" % index)
return self._idx_to_token[index]
def __str__(self):
return "<Vocabulary(size=%d)>" % len(self)
def __len__(self):
return len(self._token_to_idx)
โท Vocabulary ํด๋์ค์ ๋ฑ์ฅํ๋ ํจ์ ์ ๋ฆฌ
- __init__(self, token_to_idx=None, add_unk=True, unk_token="<UNK>"
- ๋งค๊ฐ๋ณ์ ์ค๋ช
- token_to_idx (dict) : ๊ธฐ์กด ํ ํฐ-์ธ๋ฑ์ค ๋งคํ ๋์
๋๋ฆฌ
- mask_token(str) : vocabulary์ ์ถ๊ฐํ MASKํ ํฐ (๋ชจ๋ธ ํ๋ผ๋ฏธํฐ๋ฅผ ์ ๋ฐ์ดํธ ํ๋๋ฐ ์ฌ์ฉํ์ง ์๋ ์์น๋ฅผ ๋ํ๋ธ๋ค.)
- add_unk (bool) : UNK ํ ํฐ์ ์ถ๊ฐํ ์ง ์ง์ ํ๋ ํ๋๊ทธ
- unk_token (str) : Vocabulary์ ์ถ๊ฐํ UNK ํ ํฐ
- token_to_idx (dict) : ๊ธฐ์กด ํ ํฐ-์ธ๋ฑ์ค ๋งคํ ๋์
๋๋ฆฌ
- ๋งค๊ฐ๋ณ์ ์ค๋ช
- to_serializable(self)
- ์ง๋ ฌํ ํ ์ ์๋ ๋์
๋๋ฆฌ๋ฅผ ๋ฐํ
- {'token_to_idx': self._token_to_idx, 'add_unk': self._add_unk, 'unk_token': self._unk_token, 'mask_token': self._mask_token} ํํ
- ์ง๋ ฌํ ํ ์ ์๋ ๋์
๋๋ฆฌ๋ฅผ ๋ฐํ
- @classmethod from_serializable(cls, contents)
- ์ง๋ ฌํ๋ ๋์ ๋๋ฆฌ์์ vocabulary ๊ฐ์ฒด๋ฅผ ์์ฑ
- add_token(self, token)
- ์๋ก์ด ํ ํฐ์ ์ถ๊ฐํ๊ธฐ ์ํ ํจ์
- ํ ํฐ์ ๊ธฐ๋ฐ์ผ๋ก ๋งคํ ๋์ ๋๋ฆฌ๋ฅผ ์ ๋ฐ์ดํธํด์ค๋ค
- ๋งค๊ฐ๋ณ์ token ์ด Vocabulary์ ์ถ๊ฐํ ํ ํฐ์ด ๋๋ค.
- return index : ํ ํฐ์ ์์ํ๋ ์ธ๋ฑ์ค๊ฐ ๋ฐํ๊ฐ์ผ๋ก ์ถ๋ ฅ
- add_many(self, tokens)
- ํ ํฐ ๋ฆฌ์คํธ๋ฅผ vocabulary์ ์ถ๊ฐ
- tokens ๋ ๋ฌธ์์ด list
- ๋ฐํ๊ฐ๋ tokens ์ ์์ํ๋ ์ธ๋ฑ์ค๊ฐ
- lookup_token(self, token)
- ํ ํฐ์ ๋์ํ๋ ์ธ๋ฑ์ค๋ฅผ ์ถ์ถํ๋ ๋ฉ์๋
- ๋งค๊ฐ๋ณ์ token ์ด ์ฐพ์ ํ ํฐ์ด๊ณ
- ๋ฐํ๊ฐ์ token์ด ๊ฐ๋ ์ธ๋ฑ์ค๊ฐ
- lookup_index(self, index)
- ์ธ๋ฑ์ค์ ๋์ํ๋ ํ ํฐ์ ์ฐพ๋ ๋ฉ์๋
- ๋งค๊ฐ๋ณ์ index๊ฐ ์ฐพ์ ์ธ๋ฑ์ค
- ๋ฐํ๊ฐ์ index ์ ํด๋นํ๋ ํ ํฐ
<NEXT> ๋ค์ ๊ธ์์๋ ํด๋น class๋ฅผ ํ์ฉํ์ฌ ๋ชจ๋ธ์ ์์ฑํ๊ณ , ํ๋ จํ๋ ๊ณผ์ ์ ๋ํด์ ํฌ์คํ ํ๊ฒ ๋ค.
https://didu-story.tistory.com/102