์ด๋ฒ์๋ ๋ฒ์ฉ ๋จ์ด ์๋ฒ ๋ฉ ๋ฐ์ดํฐ์
์ ๊ตฌ์ฑํ๊ณ ํ์ตํ๋ ๋ชจ๋ธ์ธ Word2Vec CBOW(Continuous Bag-of-Words) ๋ชจ๋ธ์ ๋ง๋ค์ด๋ณด๋ ค๊ณ ํฉ๋๋ค. CBOW๋ ๋จ์ํ๊ฒ ๋น์นธ ์ฑ์ฐ๊ธฐํ๋ ๊ฒ์ ๋น์ ํด ๋ณผ ์ ์์ ๊ฒ ๊ฐ์ต๋๋ค. ์ ์ฒด์ ์ธ ๊ณผ์ ์ ์ค๋ช
๋๋ฆฌ์๋ฉด ๋ฌธ์ฅ ์ โ๋ฌธ๋งฅ ์๋โ๋ฅผ ๋ง๋ค์ด ๋ฌธ๋งฅ ์๋์ ์ค์ ๋จ์ด๋ฅผ ์ ๊ฑฐํ ํ ๋ค์ ๊ทธ ์ ๊ฑฐ๋ ๋จ์ด๋ฅผ ์์ธกํ๋ฉฐ ํ์ต์ ํ๋ โ๋ค์ค ๋ถ๋ฅ ์์
โ์
๋๋ค. ๋๋ฝ๋ ๋จ์ด๊ฐ ๋ฌด์์ธ์ง ์ผ๋ง๋ ์ ํ์
ํด๋ด๋์ง๊ฐ CBOW ๋ชจ๋ธ์ ์ฑ๋ฅ์ ๊ฒฐ์ ์ง๊ฒ ์ฃ .
ย
ํ๋์ผ์ํ์ธ ๋ฐ์ดํฐ์ ์ ์ด์ฉํ ์ ์ฒ๋ฆฌ ๊ณผ์
์ ์ฒ๋ฆฌ ๊ณผ์ ์์๋ ์ฌ์ฉํ ํ
์คํธ ๋ฐ์ดํฐ์
์ ๊ตฌ์ถํ๊ณ ๊ทธ ๋ฐ์ดํฐ์
์ ๋ด์ ํ์ดํ ์น ๋ฐ์ดํฐ์
ํด๋์ค๋ฅผ ๋ง๋ค๊ณ ๋ง์ง๋ง์ผ๋ก ๋ฐ์ดํฐ์
์ ํ๋ จ, ๊ฒ์ฆ, ํ
์คํธ ์ธํธ๋ก ๋ถํ ํด์ฃผ๋ ๋จ๊ณ๋ฅผ ๊ฑฐ์นฉ๋๋ค.
ย
๋ฐ์ดํฐ์ ๊ตฌ์ถํ๊ธฐ
์์ ์ ์ฌ์ฉ๋ ๋ฐ์ดํฐ์
์ ํ๋ก์ ํธ ๊ตฌํ
๋ฒ ๋ฅดํฌ(Project Gutenberg)์์ ๋ฐฐํฌํ๋ ๋ฉ๋ฆฌ ์
ธ๋ฆฌ์ ์์ค ใํ๋์ผ์ํ์ธใ์ ๋์งํธ ๋ฒ์ ์
๋๋ค. NLTK์ Punkt ํ ํฐ ๋ถํ ๊ธฐ๋ฅผ ์ฌ์ฉํ์ฌ ํ
์คํธ๋ฅผ ๊ฐ๋ณ ๋ฌธ์ฅ์ผ๋ก ๋ถํ ํ๊ณ ๋๋ฌธ์๋ ์๋ฌธ์๋ก ๋ณํํ๊ณ ๊ตฌ๋์ ์ ์์ ํ ์ ๊ฑฐํด์ค๋๋ค. ์ฌ๊ธฐ์ ์๋ฌธ์๋ก ๋ณํํ๋ ์ด์ ๋ NLTK๊ฐ case sensitive, ์ฆ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ๊ธฐ ๋๋ฌธ์ ๊ฐ์ ์คํ ๋ง์ ๋จ์ด๋ผ๋ ๋๋ฌธ์๋ก ์์ํ๋ ๊ฒ๊ณผ ์๋ฌธ์๋ก ์์ํ๋ ๊ฒ์ ๋ค๋ฅด๊ฒ ์ธ์ํ๊ธฐ ๋๋ฌธ์
๋๋ค. ์ด ๊ณผ์ ์ ๊ฑฐ์น ํ, ์ด์ ๊ณต๋ฐฑ์ผ๋ก ๋ฌธ์์ด์ ๋ถํ ํ์ฌ ํ ํฐ ๋ฆฌ์คํธ๋ฅผ ์ถ์ถํด์ผํฉ๋๋ค.
ย
ย
ย
CBOW ๋ชจ๋ธ์ ๋ฐ์ดํฐ์
์ ์ฐ์๋ ์๋(Window)๋ค๋ก ํํํฉ๋๋ค. ์์ ๋ชจ์ด๋ ๊ฒ์ ์ฌ๊ฐํ๋ค์ด ๊ฐ๊ฐ์ ์ฐ์๋ ์๋์ด๊ณ ๋นจ๊ฐ ์ฌ๊ฐํ๋ค์ ๊ฐ ์๋์ ์ค์ ๋จ์ด์
๋๋ค! ๋ชจ๋ธ์ ๋ฌธ์ฅ์ ํ ํฐ ๋ฆฌ์คํธ๋ฅผ ์ฌ์
์ง๋๊ฐ๋ฉด์ ์ง์ ๋ ํฌ๊ธฐ์ ์๋๋ก ๋จ์ด๋ค์ ๋ฌถ์ต๋๋ค. ์ ์์์์ ๋ณด์ด๋ ๋ฌธ๋งฅ ์๋๋ ๊ธธ์ด๊ฐ ์์ชฝ์ผ๋ก 2(์ฝ๊ฒ ๋งํด์ ๋จ์ด 2๊ฐ)์ธ ๋ฌธ๋งฅ ์๋์ฃ . ์ด ์๋๊ฐ ํ
์คํธ ์๋ฅผ ์ฌ๋ผ์ด๋ฉํ๋ฉฐ ํ์ต ์ํ์ ์์ฑํ์ฌ CBOW ๋ชจ๋ธ์ด ์ผ์ชฝ ๋ฌธ๋งฅ๊ณผ ์ค๋ฅธ์ชฝ ๋ฌธ๋งฅ์ ํตํด ํ๊น ๋จ์ด, ์ฆ ์ค์์ ๋จ์ด๋ฅผ ์์ธกํ ์ ์๋๋ก ํด์ฃผ๋ ๊ฒ๋๋ค.
ย
ํ์ดํ ์น ๋ฐ์ดํฐ์ ํด๋์ค ๋ง๋ค๊ธฐ
์ด๋ ๊ฒ ๋ง๋ค์ด์ง ์๋ ๋ฐ์ดํฐ์
๊ณผ ํ๊น ๋จ์ด๋ฅผ ํ๋ค์ค ๋ฐ์ดํฐํ๋ ์์ผ๋ก ๊ฐ์ ธ์์ฃผ๊ณ CBOWDataset ํด๋์ค๋ฅผ ํตํด ์ธ๋ฑ์ฑํด์ค๋๋ค.
class CBOWDataset(Dataset): @classmethod def load_dataset_and_make_vetorizer(cls, cbow_csv) '''๋ฐ์ดํฐ์ ์ ๊ฐ์ ธ์ค๊ณ Vectorizer ๋ง๋ค๊ธฐ ๋งค๊ฐ๋ณ์: cbow_csv(str) ๋ฐ์ดํฐ์ ์ ์์น ๋ฐํ๊ฐ: CBOWDataset์ instance''' cbow_df = pd.read_csv(cbow_csv) train_cbow_df = cbow_df[cbow_df.split == 'train'] return cls(cbow_df, CBOWVectorizer.from_dataframe(train_cbow_df)) 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}
์ฌ๊ธฐ์ ์ฌ์ฉ๋ __ getitem__() ๋ฉ์๋๋ Vectorizer๋ฅผ ์ฌ์ฉํ์ฌ ์๋์ ์ผ์ชฝ ๋ฌธ๋งฅ๊ณผ ์ค๋ฅธ์ชฝ ๋ฌธ๋งฅ์ ๋ฒกํฐ๋ก ๋ณํํด์ค๋๋ค. ํ๊น ๋จ์ด, ์ฆ ์ค์ ๋จ์ด๋ Vocabulary๋ฅผ ์ฌ์ฉํ์ฌ ์ ์๋ก ๋ณํ๋ฉ๋๋ค.
๋ฐ์ดํฐ์ ์ train set, validation set, test set์ผ๋ก ๋๋์ด์ฃผ๊ธฐ
๊ตฌ์ฑ๋ ๋ฐ์ดํฐ์
์ ๋ชจ๋ ํ์ต์ ์ฌ์ฉํ๋ ๊ฒ์ ์๋๊ณ , ๋ถ๋ถ ๋ถ๋ถ ๋๋์ด์ ํ๋ จํ๋ ๋ฐ ์ฌ์ฉํ ๋ฐ์ดํฐ์
, ๊ฒ์ฆํ๋ ๋ฐ ์ฌ์ฉํ ๋ฐ์ดํฐ์
, ํ
์คํธํ ๋ ์ฌ์ฉํ ๋ฐ์ดํฐ์
์ ๋ง๋ จํด์ค๋๋ค.
Train set(ํ๋ จ ์ธํธ)๋ ์ฑ๋ฅ์ ์ต์ ํํ๊ธฐ ์ํ ํ๋ผ๋ฏธํฐ ์
๋ฐ์ดํธ์ ์ฌ์ฉํ๊ณ validation set(๊ฒ์ฆ ์ธํธ)๋ ํ์ตํ ๊ฒ์ ํ ๋๋ก ์ ํ๋ จ๋์๋ ๋ชจ๋ธ์ ์ฑ๋ฅ์ ์ธก์ ํ๊ณ ๊ฐ๋ ํ๊ธฐ ์ํด ์ฌ์ฉํฉ๋๋ค. ์ด ๋ ์ธํธ๋ ๋ชจ๋ธ ํ๋ จ ์ค์ ์ฌ์ฉ๋๋ ๊ฒ์ด๋ฉฐ, test set(ํ
์คํธ ์ธํธ)๊ฐ ์ค์ ์ธ ๊ฒ์ด๋ผ ๊ฒ์ฆ ์ธํธ์ ํ
์คํธ ์ธํธ๋ฅผ ํท๊ฐ๋ ค ํ์๋ฉด ์ ๋ฉ๋๋ค~
์ด ๊ธ์ ์์ ์์๋ ๊ตฌ์ฑํ ๋ฐ์ดํฐ์
์ 70%๋ฅผ ํ๋ จ ์ธํธ, 15%๋ฅผ ๊ฒ์ฆ ์ธํธ, ๋๋จธ์ง 15%๋ฅผ ํ
์คํธ ์ธํธ๋ก ๋๋๋๋ค.
ย
Vocabulary, Vectorizer, DataLoader
์ด์ ํ
์คํธ๋ฅผ ๋ฒกํฐ์ ๋ฏธ๋๋ฐฐ์น๋ก ๋ณํํด์ผํ๋๋ฐ, ์ด๋ Vocabulary ํจ์, Vectorizer ํจ์, DataLoaderํจ์๊ฐ ์ฌ์ฉ๋ฉ๋๋ค. CBOW ๋ชจ๋ธ์ ์กฐ๊ธ ํน๋ณํ Vocabulary ํจ์๊ฐ ์-ํซ ๋ฒกํฐ๋ฅผ ๋ง๋ค์ง ์๊ณ ๋์ ๋ฌธ๋งฅ์ ์ธ๋ฑ์ค๋ฅผ ๋ํ๋ด๋ ์ ์ ๋ฒกํฐ๋ฅผ ๋ง๋ค์ด ๋ฐํํ๋ ์์
์ ํฉ๋๋ค. ๋ฐ์ ์ฝ๋๋ฅผ ํตํด Vectorizerํจ์๋ฅผ ๊ตฌํํด๋ด
๋๋ค.
class CBOWVectorizer(object): '''์ดํ ์ฌ์ ์ ์์ฑํ๊ณ ๊ด๋ฆฌํจ''' 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
ย
์ด๋ ๋ฌธ๋งฅ์ ํ ํฐ ์๊ฐ ์ต๋ ๊ธธ์ด๋ณด๋ค ์ ์ผ๋ฉด, ๋จ์ ํญ๋ชฉ๋ค์ 0์ผ๋ก ์ฑ์์ง๋๋ฐ, ์ด ํ์์ 0์ผ๋ก โํจ๋ฉโ๋์๋ค๊ณ ํํํฉ๋๋ค.
ย
CBOWClassifier ๋ชจ๋ธ
class CBOWClassifier(nn.Module): def __init__(self, vocabulary_size, embedding_size, padding_idx = 0): '''๋งค๊ฐ๋ณ์: vocabulary_size(int) ์ดํ ์ฌ์ ์ ํฌ๊ธฐ, ์๋ฒ ๋ฉ ๊ฐ์์ ์์ธก ๋ฒกํฐ ํฌ๊ธฐ๋ฅผ ๊ฒฐ์ ํจ embedding_size(int) ์๋ฒ ๋ฉ ํฌ๊ธฐ padding_idx(int) ๊ธฐ๋ณธ๊ฐ 0 (์๋ฒ ๋ฉ์ด ์ฌ์ฉํ์ง ์๋ ์ธ๋ฑ์ค)''' super(CBOWClassifier, self).__init__() self.embedding = nn.embedding(num_embeddings = vocabulary_size, embedding_dim = embedding_size, padding_idx = padding_idx) self.fc1 = nn.Linear(in_features = embedding_size, out_features = vocabulary_size) def forward(self, x_in, apply_softmax = False): '''๋ถ๋ฅ๊ธฐ์ ์ ๋ฐฉํฅ ๊ณ์ฐ ๋งค๊ฐ๋ณ์: x_in (torch.Tensor) ์ ๋ ฅ ๋ฐ์ดํฐ ํ ์ x_in.shape๋ (batch, input_dim)์ apply_softmax (bool) ์ํํธ๋งฅ์ค ํ์ฑํ ํจ์๋ฅผ ์ํ ํ๋๊ทธ ํฌ๋ก์ค ์ํธ๋กํผ ์์ค์ ์ฌ์ฉํ๋ ค๋ฉด False๋ก ์ ์ฅ ๋ฐํ๊ฐ: ๊ฒฐ๊ณผ ํ ์ tensor.shape๋ (batch, output_dim)์''' x_embedded_sum = self.embedding(x_in).sum(dim = 1) y_out = self.fc1(x_embedded_sum) if apply_softmax: y_out = F.softmax(y_out, dim = 1) return y_out
ย
ย
์ด์ ๊ธ ์ฝ๊ธฐ
๋ค์ ๊ธ ์ฝ๊ธฐ
ย