-- ๋ณธ ํฌ์คํ
์ ํ์ดํ ์น๋ก ๋ฐฐ์ฐ๋ ์์ฐ์ด ์ฒ๋ฆฌ (ํ๋น๋ฏธ๋์ด) ์ฑ
์ ์ฐธ๊ณ ํด์ ์์ฑ๋ ๊ธ์
๋๋ค.
-- ์์ค์ฝ๋๋ ์ฌ๊ธฐ
1. ๋ชจ๋ธ ์์ฑ
- embedding์ธต์ ์ฌ์ฉํ์ฌ ๋ฌธ๋งฅ์ ๋จ์ด๋ฅผ ๋ํ๋ด๋ ์ธ๋ฑ์ค๋ฅผ ๊ฐ ๋จ์ด์ ๋ํ ๋ฒกํฐ๋ก ๋ง๋ ๋ค.
- ์ ๋ฐ์ ์ธ ๋ฌธ๋งฅ์ ๊ฐ์งํ๋๋ก ๋ฒกํฐ๋ฅผ ๊ฒฐํฉํ๋ค.
- Linear ์ธต์์ ๋ฌธ๋งฅ ๋ฒกํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์์ธก ๋ฒกํฐ๋ฅผ ๊ณ์ฐํ๋ค.
- ์ด ์์ธก๋ฒกํฐ๋ ์ ์ฒด ์ดํ ์ฌ์ ์ ๋ํ ํ๋ฅ ๋ถํฌ์ด๋ค.
- ์์ธก๋ฒกํฐ์์ ๊ฐ์ฅ ํฐ ๊ฐ์ด ํ๊ฒ ๋จ์ด์ ๋ํ ์์ธก์ ๋ํ๋ธ๋ค.
class CBOWClassifier(nn.Module): # Simplified cbow Model
def __init__(self, vocabulary_size, embedding_size, padding_idx=0):
"""
๋งค๊ฐ๋ณ์3๊ฐ๋ก ์ ์ด๋๋ค:
vocabulary_size (int): ์ดํ ์ฌ์ ํฌ๊ธฐ, ์๋ฒ ๋ฉ ๊ฐ์์ ์์ธก ๋ฒกํฐ ํฌ๊ธฐ๋ฅผ ๊ฒฐ์ ํฉ๋๋ค
embedding_size (int): ์๋ฒ ๋ฉ ํฌ๊ธฐ
padding_idx (int): ๊ธฐ๋ณธ๊ฐ 0; ์๋ฒ ๋ฉ์ ์ด ์ธ๋ฑ์ค๋ฅผ ์ฌ์ฉํ์ง ์์ต๋๋ค
"""
super(CBOWClassifier, self).__init__()
# padding idx๋ ๊ธฐ๋ณธ๊ฐ์ด 0 ์ด์ง๋ง, ๋ฐ์ดํฐ ํฌ์ธํธ์ ๊ธธ์ด๊ฐ ๋ชจ๋ ๊ฐ์ง ์์ ๋
# embedding์ธต์ ํจ๋ฉํ๋๋ฐ ์ฌ์ฉ๋๋ ๋งค๊ฐ๋ณ์์ด๋ค.
self.embedding = nn.Embedding(num_embeddings=vocabulary_size,
embedding_dim=embedding_size,
padding_idx=padding_idx)
# linear์ธต์์ ๋ฌธ๋งฅ๋ฒกํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์์ธก๋ฒกํฐ๋ฅผ ๊ณ์ฐํ๋ค
# ์์ธก๋ฒกํฐ๋ ์ดํ์ฌ์ ์ ๋ํ ํ๋ฅ ๋ถํฌ
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 = F.dropout(self.embedding(x_in).sum(dim=1), 0.3)
y_out = self.fc1(x_embedded_sum)
## ์ถ๋ ฅ: ์ํํธ๋งฅ์คํจ์๋ ์ ํ์ ์ผ๋ก ๊ณ์ฐํ ์์ / ์์น์ ๊ณ์ฐ ๋ญ๋น ๋ฐ์, ๋ถ์์ ๋ฐ์
if apply_softmax:
y_out = F.softmax(y_out, dim=1)
return y_out
2. ๋ชจ๋ธ ํ๋ จ
2.1 ํฌํผํจ์ ์ ์
- make_train_state : ํ์ฌ ํ๋ จ ์ ๋๋ฅผ ๋ํ๋ผ ์ ์๋ ํจ์์ด๋ค. ๋ค์์ ํ๋ จํ๋ ๊ณผ์ ์ ๋ณด๋ฉด state์ ๊ณ์ ํ๋ จ ์ํ๋ฅผ ์ ๋ฐ์ดํธ ํด์ฃผ๊ณ , ๋ชจ๋ธ์ ํ๋ จ์์ผ์ฃผ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
- update_train_state : ์ต์ ์ ๋ชจ๋ธ์ ์ฐพ๊ธฐ ์ํด์ ํด๋น ํจ์๊ฐ ์ฌ์ฉ๋๋ค. ๋ชจ๋ธ์ด ํ๋ฒ์ฉ ๋์๊ฐ๋๋ง๋ค ์ํ๊ฐ ์ ๋ฐ์ดํธ ๋๊ณ , ์ ๋ฐ์ดํธ๋ ๊ฐ์ ํตํด์ ๋ชจ๋ธ์ ์ ์ฅํด์ค๋ค. ์์ค์ ์ข๊ฒ ๋ง๋ค์ด์ฃผ๊ณ ์ต์์ ๋ชจ๋ธ์ ์ฐพ์ ๋ ์ฌ์ฉ๋๋ค.
- compute_accuracy : ์ ํ๋๋ฅผ ๊ณ์ฐํ ๋ ์ฌ์ฉ๋๋ ํฌํผํจ์์ด๋ค.
# ํ์ฌ ํธ๋ ์ธ ์ํ๋ฅผ ๋ํ๋ผ ์ ์๋ ํจ์
# ๋ค์ ๊ฐ๋ฉด ๋ชจ๋ธ์ ํ๋ จ ๋์ค ์
๋ฐ์ดํธ ํ๊ณ ์ต์์ ๋ชจ๋ธ์ ์ฐพ์๋ด๋๋ฐ ์ฌ์ฉ๋๋ค.
# ์์ค ์ ์ฅ, ์ํฌํฌ ์ ์ฅ ๋ฑ๋ฑ
def make_train_state(args):
return {'stop_early': False,
'early_stopping_step': 0,
'early_stopping_best_val': 1e8,
'learning_rate': args.learning_rate,
'epoch_index': 0,
'train_loss': [],
'train_acc': [],
'val_loss': [],
'val_acc': [],
'test_loss': -1,
'test_acc': -1,
'model_filename': args.model_state_file}
# ๋ค์ ๊ฐ๋ฉด ์์ค์ด ์ ๊ฒ๋์ค๋ ์ต์ ์ ๋ชจ๋ธ์ ์ฐพ์ ๊ฑด๋ฐ ํด๋น ๋ชจ๋ธ์ ์ฐพ๊ธฐ์ํด
# ์ง์์ ์ผ๋ก ์ํ๋ฅผ ์
๋ฐ์ดํธ ํด์ฃผ๊ธฐ ์ํด ์ด ํจ์ ์ฌ์ฉ
# ๋ชจ๋ธ์ด ํ๋ฒ ๋์๊ฐ๋ฉด, ์
๋ฐ์ดํธ ํด์ฃผ๋ ์์
์ ํ ๊ฑด๋ฐ, ๊ทธ๋
# ์ด์ ์ ์ ์ฅ๋์ด ์๋ train state์ ์ฑ๋ฅ์ ๋น๊ตํ์ฌ ์ต์ ์ ๋ชจ๋ธ์ ์ฐพ์ ๊ฒ
def update_train_state(args, model, train_state):
""" ํ๋ จ ์ํ๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค.
Components:
- ์กฐ๊ธฐ ์ข
๋ฃ: ๊ณผ๋ ์ ํฉ ๋ฐฉ์ง
- ๋ชจ๋ธ ์ฒดํฌํฌ์ธํธ: ๋ ๋์ ๋ชจ๋ธ์ ์ ์ฅํฉ๋๋ค
:param args: ๋ฉ์ธ ๋งค๊ฐ๋ณ์
:param model: ํ๋ จํ ๋ชจ๋ธ
:param train_state: ํ๋ จ ์ํ๋ฅผ ๋ด์ ๋์
๋๋ฆฌ
:returns:
์๋ก์ด ํ๋ จ ์ํ
"""
# ์ ์ด๋ ํ ๋ฒ ๋ชจ๋ธ์ ์ ์ฅํฉ๋๋ค
if train_state['epoch_index'] == 0:
torch.save(model.state_dict(), train_state['model_filename'])
train_state['stop_early'] = False
# ์ฑ๋ฅ์ด ํฅ์๋๋ฉด ๋ชจ๋ธ์ ์ ์ฅํฉ๋๋ค
elif train_state['epoch_index'] >= 1:
loss_tm1, loss_t = train_state['val_loss'][-2:]
# ์์ค์ด ๋๋น ์ง๋ฉด
if loss_t >= train_state['early_stopping_best_val']:
# ์กฐ๊ธฐ ์ข
๋ฃ ๋จ๊ณ ์
๋ฐ์ดํธ
train_state['early_stopping_step'] += 1
# ์์ค์ด ๊ฐ์ํ๋ฉด
else:
# ์ต์์ ๋ชจ๋ธ ์ ์ฅ
if loss_t < train_state['early_stopping_best_val']:
torch.save(model.state_dict(), train_state['model_filename'])
# ์กฐ๊ธฐ ์ข
๋ฃ ๋จ๊ณ ์ฌ์ค์
train_state['early_stopping_step'] = 0
# ์กฐ๊ธฐ ์ข
๋ฃ ์ฌ๋ถ ํ์ธ
train_state['stop_early'] = \
train_state['early_stopping_step'] >= args.early_stopping_criteria
return train_state
# ์ ํ๋๋ฅผ ๊ณ์ฐํด์ฃผ๋ ํจ์๋ฅผ ์ ์ํ๋ค.
def compute_accuracy(y_pred, y_target):
_, y_pred_indices = y_pred.max(dim=1)
n_correct = torch.eq(y_pred_indices, y_target).sum().item()
return n_correct / len(y_pred_indices) * 100
2.2 ์ผ๋ฐ ์ ํธ๋ฆฌํฐ ํจ์ ์ ์
#์ถํ ์ฌํ์ฑ์ ์ํด์ ๋๋ค์๋๋ฅผ ๋ค์ ์ค์ ํด์ค ๊ฒ์ธ๋ฐ ๊ทธ๋ ์ฌ์ฉํ๋ ํจ์
# ์ด๋ค ์ฐ๊ตฌ๋ฅผ ๋๊ฐ์ด ๋ค์ ๋ฐ๋ณตํจ์ผ๋ก์จ ๊ธฐ์กด ์๋ณธ์์ ๋ณด๊ณ ๋์๋ ๊ฒฐ๊ณผ๊ฐ (๊ฑฐ์) ๋๊ฐ์ด ๋ค์ ๋ํ๋๋์ง๋ฅผ ๊ด์ฐฐํ๋ ๊ฒ.
def set_seed_everywhere(seed, cuda):
np.random.seed(seed)
torch.manual_seed(seed)
if cuda:
torch.cuda.manual_seed_all(seed)
# ๋๋ ํ ๋ฆฌ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํ ํจ์
def handle_dirs(dirpath):
if not os.path.exists(dirpath):
os.makedirs(dirpath)
2.3 ์ค์ ๊ณผ ์ ์ฒ๋ฆฌ ์์ (ํ๊ฒฝ์ค์ )
args = Namespace(
# ๋ ์ง์ ๊ฒฝ๋ก ์ ๋ณด
cbow_csv="data/books/frankenstein_with_splits.csv",
vectorizer_file="vectorizer.json",
model_state_file="model.pth",
save_dir="model_storage/ch5/cbow",
# ๋ชจ๋ธ ํ์ดํผํ๋ผ๋ฏธํฐ
embedding_size=50,
# ํ๋ จ ํ์ดํผํ๋ผ๋ฏธํฐ
seed=1337,
num_epochs=100,
learning_rate=0.0001,
batch_size=32,
early_stopping_criteria=5,
# ์คํ ์ต์
cuda=True,
catch_keyboard_interrupt=True,
reload_from_files=False,
expand_filepaths_to_save_dir=True
)
if args.expand_filepaths_to_save_dir:
args.vectorizer_file = os.path.join(args.save_dir,
args.vectorizer_file)
args.model_state_file = os.path.join(args.save_dir,
args.model_state_file)
print("ํ์ผ ๊ฒฝ๋ก: ")
print("\t{}".format(args.vectorizer_file))
print("\t{}".format(args.model_state_file))
# CUDA ์ฒดํฌ
if not torch.cuda.is_available():
args.cuda = False
args.device = torch.device("cuda" if args.cuda else "cpu")
print("CUDA ์ฌ์ฉ์ฌ๋ถ: {}".format(args.cuda))
# ์ฌํ์ฑ์ ์ํด ์๋ ์ค์
set_seed_everywhere(args.seed, args.cuda)
# ๋๋ ํ ๋ฆฌ ์ฒ๋ฆฌ
handle_dirs(args.save_dir)
2.4 ๋ฐ์ดํฐ ์ด๊ธฐํ
- ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค ๊ฒ์ด๋ค.
- ์ด๋ฏธ ์ ์ฒ๋ฆฌ๋ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ค.
- ์ด ์ฑ ์์ ๋ผ์ดํธ ๋ฒ์ ์ ์ ์ฒ๋ฆฌ๋, ํฌ๊ธฐ๋ฅผ ์ข ์ค์ฌ์ ์ ์ฒ๋ฆฌ๋์ด์ง ๋ฐ์ดํฐ์ ์ ์๋ฏธํ๋ค.
# ๋ง์ฝ ์ฝ๋ฉ์์ ์คํํ๋ ๊ฒฝ์ฐ ์๋ ์ฝ๋๋ฅผ ์คํํ์ฌ ์ ์ฒ๋ฆฌ๋ ๋ผ์ดํธ ๋ฒ์ ์ ๋ฐ์ดํฐ๋ฅผ ๋ค์ด๋ก๋ํ์ธ์.
!mkdir data
!wget https://git.io/JtX5A -O data/download.py
!wget https://git.io/JtX5F -O data/get-all-data.sh
!chmod 755 data/get-all-data.sh
%cd data
!./get-all-data.sh
%cd ..
2.5 ๋ฐ์ดํฐ์ , vectorizer ์์ฑ
args์ ์ ์ฅ๋ ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก ๋ฐ์ดํฐ์ ๊ณผ vectorizer๋ฅผ ๋ง๋ค์ด์ค๋ค. ์ฐ๋ฆฌ๋ ์ด๋ฏธ ์ฌ์ ์ ์์ฑ๋ vectorizer ๊ฐ์ฒด๊ฐ ์๊ธฐ ๋๋ฌธ์ else๋ฌธ์ด ์คํ๋๋ค.
# ์ด๋ฏธ ์์ฑ๋์ด์๋ ๋ฐ์ดํฐ์
๊ณผ vectorizer๊ฐ์ฒด๊ฐ ์กด์ฌํ๋ค๋ฉด ๊ทธ ๋ถ๋ถ์์ ๋ฐ์ดํฐ์
์ ๋ฐ์์์ ๋ค์ ํ๋ จ ์์
# args.reload_from_files = False ๋ก ์ง์ ํ์
# ์๋๋ฉด ๋ฐ์ดํฐ์
๊ณผ ๋ฒกํ ๋ผ์ด์ ๋ง๋ค๊ธฐ
''' args ์ค์ ์ดํด๋ณด๊ธฐ!!
# ๋ชจ๋ธ ํ์ดํผํ๋ผ๋ฏธํฐ
embedding_size=50,
# ํ๋ จ ํ์ดํผํ๋ผ๋ฏธํฐ
seed=1337,
num_epochs=100,
learning_rate=0.0001,
batch_size=32,
early_stopping_criteria=5,
'''
if args.reload_from_files:
print("๋ฐ์ดํฐ์
๊ณผ Vectorizer๋ฅผ ๋ก๋ํฉ๋๋ค")
dataset = CBOWDataset.load_dataset_and_load_vectorizer(args.cbow_csv,
args.vectorizer_file)
else:
print("๋ฐ์ดํฐ์
์ ๋ก๋ํ๊ณ Vectorizer๋ฅผ ๋ง๋ญ๋๋ค")
dataset = CBOWDataset.load_dataset_and_make_vectorizer(args.cbow_csv)
#save vectorizer = ๋ฒกํฐ๋ฅผ ๋์คํฌ์ json ํํ๋ก ์ ์ฅํด์ฃผ๋ ๋ฉ์๋
dataset.save_vectorizer(args.vectorizer_file)
# get vectoirzer = ๋ณํ ๋ฒกํฐ ๊ฐ์ฒด๋ฅผ ๋ฐํํด์ฃผ๋ ๋ฉ์๋
vectorizer = dataset.get_vectorizer()
# ๋ชจ๋ธ ์ค์ (embedingsize = 50)
classifier = CBOWClassifier(vocabulary_size=len(vectorizer.cbow_vocab),
embedding_size=args.embedding_size)
2.6 ํ๋ จ ์ํ๋ฅผ ์ ๋ฐ์ดํธ ํ๋ฉด์ ํ๋ จ ๋ฐ๋ณต
classifier = classifier.to(args.device)
# ๋ค์คํด๋์ค๋ถ๋ฅ์ ์์๋๋CrossEntropyLoss ์ฌ์ฉ
# ์ตํฐ๋ง์ด์ adam
loss_func = nn.CrossEntropyLoss()
optimizer = optim.Adam(classifier.parameters(), lr=args.learning_rate)
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer=optimizer,
mode='min', factor=0.5,
# ํธ๋ ์ธ์ํ ๋ง๋ค๊ธฐ (ํฌํผํจ์) patience=1)
train_state = make_train_state(args)
# ์ํฌํฌ๋ 100
epoch_bar = tqdm.notebook.tqdm(desc='training routine',
total=args.num_epochs,
position=0)
#set_split ๋ฉ์๋ : ๋ฐ์ดํฐํ๋ ์์ ์๋ ์ด์ ์ฌ์ฉํด ๋ถํ ์ธํธ๋ฅผ ์ ํ
dataset.set_split('train')
# get_num_batches ๋ฉ์๋ : ๋ฐฐ์น ํฌ๊ธฐ๊ฐ ์ฃผ์ด์ง๋ฉด ๋ฐ์ดํฐ์
์ผ๋ก ๋ง๋ค ์ ์๋ ๋ฐฐ์น ๊ฐ์๋ฅผ ๋ฐํํด์ฃผ๋ ๋ฉ์๋
train_bar = tqdm.notebook.tqdm(desc='split=train',
total=dataset.get_num_batches(args.batch_size),
position=1,
leave=True)
dataset.set_split('val')
val_bar = tqdm.notebook.tqdm(desc='split=val',
total=dataset.get_num_batches(args.batch_size),
position=1,
leave=True)
#์ธ๋ถ for๋ฌธ : ์ํฌํฌ ํ์๋งํผ ๋์๊ฐ. (์ํฌํฌ๋ 100์)
#๋ด๋ถ for๋ฌธ : ๋ฐฐ์น๋จ์๋ฅผ ๋๋ฆฌ๋ ๋ฐ๋ณต๋ฌธ
try:
for epoch_index in range(args.num_epochs):
train_state['epoch_index'] = epoch_index
# ํ๋ จ ์ธํธ์ ๋ํ ์ํ
# ํ๋ จ ์ธํธ์ ๋ฐฐ์น ์ ๋๋ ์ดํฐ ์ค๋น, ์์ค๊ณผ ์ ํ๋๋ฅผ 0์ผ๋ก ์ค์
dataset.set_split('train')
batch_generator = generate_batches(dataset,
batch_size=args.batch_size,
device=args.device)
running_loss = 0.0
running_acc = 0.0
classifier.train()
for batch_index, batch_dict in enumerate(batch_generator):
# ํ๋ จ ๊ณผ์ ์ 5๋จ๊ณ๋ก ์ด๋ฃจ์ด์ง๋๋ค
# --------------------------------------
# ๋จ๊ณ 1. ๊ทธ๋ ์ด๋์ธํธ๋ฅผ 0์ผ๋ก ์ด๊ธฐํํฉ๋๋ค
optimizer.zero_grad()
# ๋จ๊ณ 2. ์ถ๋ ฅ์ ๊ณ์ฐํฉ๋๋ค
y_pred = classifier(x_in=batch_dict['x_data'])
# ๋จ๊ณ 3. ์์ค์ ๊ณ์ฐํฉ๋๋ค
loss = loss_func(y_pred, batch_dict['y_target'])
loss_t = loss.item()
running_loss += (loss_t - running_loss) / (batch_index + 1)
# ๋จ๊ณ 4. ์์ค์ ์ฌ์ฉํด ๊ทธ๋ ์ด๋์ธํธ๋ฅผ ๊ณ์ฐํฉ๋๋ค
loss.backward()
# ๋จ๊ณ 5. ์ตํฐ๋ง์ด์ ๋ก ๊ฐ์ค์น๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค
optimizer.step()
# -----------------------------------------
# ์ ํ๋๋ฅผ ๊ณ์ฐํฉ๋๋ค
acc_t = compute_accuracy(y_pred, batch_dict['y_target'])
running_acc += (acc_t - running_acc) / (batch_index + 1)
# ์งํ ๋ฐ ์
๋ฐ์ดํธ
train_bar.set_postfix(loss=running_loss, acc=running_acc,
epoch=epoch_index)
train_bar.update()
train_state['train_loss'].append(running_loss)
train_state['train_acc'].append(running_acc)
# ๊ฒ์ฆ ์ธํธ์ ๋ํ ์ํ
# ๊ฒ์ฆ ์ธํธ์ ๋ฐฐ์น ์ ๋๋ ์ดํฐ ์ค๋น, ์์ค๊ณผ ์ ํ๋๋ฅผ 0์ผ๋ก ์ค์
dataset.set_split('val')
batch_generator = generate_batches(dataset,
batch_size=args.batch_size,
device=args.device)
running_loss = 0.
running_acc = 0.
classifier.eval()
for batch_index, batch_dict in enumerate(batch_generator):
# ๋จ๊ณ 1. ์ถ๋ ฅ์ ๊ณ์ฐํฉ๋๋ค
y_pred = classifier(x_in=batch_dict['x_data'])
# ๋จ๊ณ 2. ์์ค์ ๊ณ์ฐํฉ๋๋ค
loss = loss_func(y_pred, batch_dict['y_target'])
loss_t = loss.item()
running_loss += (loss_t - running_loss) / (batch_index + 1)
# ๋จ๊ณ 3. ์ ํ๋๋ฅผ ๊ณ์ฐํฉ๋๋ค
acc_t = compute_accuracy(y_pred, batch_dict['y_target'])
running_acc += (acc_t - running_acc) / (batch_index + 1)
val_bar.set_postfix(loss=running_loss, acc=running_acc,
epoch=epoch_index)
val_bar.update()
train_state['val_loss'].append(running_loss)
train_state['val_acc'].append(running_acc)
train_state = update_train_state(args=args, model=classifier,
train_state=train_state)
scheduler.step(train_state['val_loss'][-1])
if train_state['stop_early']:
break
train_bar.n = 0
val_bar.n = 0
epoch_bar.update()
except KeyboardInterrupt:
print("Exiting loop")
2.7 ๊ฐ์ฅ ์ข์ ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ์ ํ๋ ๊ณ์ฐ
- test ๋ฐ์ดํฐ์ ์ ํ์ฉํด์ ์ ํ๋๋ฅผ ๊ณ์ฐํ๋ค.
# ๊ฐ์ฅ ์ข์ ๋ชจ๋ธ์ ์ฌ์ฉํด ํ
์คํธ ์ธํธ์ ์์ค๊ณผ ์ ํ๋๋ฅผ ๊ณ์ฐํฉ๋๋ค
# train_state model filename์ ๊ฐ์ฅ ์ข์ ๋ชจ๋ธ์ด ์ ์ฅ๋์ด ์๋ค.
classifier.load_state_dict(torch.load(train_state['model_filename']))
classifier = classifier.to(args.device)
loss_func = nn.CrossEntropyLoss()
# test ๋ฐ์ดํฐ์
์ ์ ํ
dataset.set_split('test')
batch_generator = generate_batches(dataset,
batch_size=args.batch_size,
device=args.device)
running_loss = 0.
running_acc = 0.
classifier.eval()
for batch_index, batch_dict in enumerate(batch_generator):
# ์ถ๋ ฅ์ ๊ณ์ฐํฉ๋๋ค
y_pred = classifier(x_in=batch_dict['x_data'])
# ์์ค์ ๊ณ์ฐํฉ๋๋ค
loss = loss_func(y_pred, batch_dict['y_target'])
loss_t = loss.item()
running_loss += (loss_t - running_loss) / (batch_index + 1)
# ์ ํ๋๋ฅผ ๊ณ์ฐํฉ๋๋ค
acc_t = compute_accuracy(y_pred, batch_dict['y_target'])
running_acc += (acc_t - running_acc) / (batch_index + 1)
train_state['test_loss'] = running_loss
train_state['test_acc'] = running_acc
print("ํ
์คํธ ์์ค: {};".format(train_state['test_loss']))
print("ํ
์คํธ ์ ํ๋: {}".format(train_state['test_acc']))
(์ด๊ฒ ๋ง์ด ๋๋ ์ ํ๋์ธ๊ฐ..?!)
- ๊ฒฐ๊ณผ๊ฐ์ด ๋์ง ์์ ์ด์
- ์ด ์์ ์์๋ ๋ฒ์ฉ์ ์ธ ์๋ฒ ๋ฉ์ ๊ตฌ์ฑํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํ๊ธฐ ํธํ๋๋ก ์ฌ๋ฌ๊ฐ์ง ๊ธฐ๋ฅ์ ์๋ตํ์ฌ CBOW ์ค์ต์ ์งํํ๋ค. (์ฑ๋ฅ ์ต์ ํ์ ํ์์ ์ธ ์ฌ๋ฌ๊ฐ์ง ๊ธฐ๋ฅ์ ์๋ตํ๊ณ ๋จ์ ๊ตฌํํ ๊ฒ์ด๋ค.)
- ์ฌ๊ธฐ์ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ์ ์ ํฌ๊ธฐ๊ฐ ์์ฃผ ์๋ค. (๋จ์ด์ ์๋ ์ฝ 70000๊ฐ ๋ฟ์ด๋ผ์, zero base์์ ๊ท์น์ฑ์ ๊ฐ์งํ๊ธฐ์ ์ถฉ๋ถํ์ง ๋ชปํ๋ค.
3. ์๋ฒ ๋ฉ ๊ฒฐ๊ณผ ์ถ๋ ฅํด๋ณด๊ธฐ
์๋ฒ ๋ฉ ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅํ๊ธฐ ์ํ ํฌํผ ํจ์๋ฅผ ์์ฑํ๋ค. ๋จ์ง ์ด์๊ฒ ์๋ฒ ๋ฉ๋ ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅํ๊ธฐ ์ํจ์ด๋ค.
๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐํ์ฌ ์
๋ ฅ๋ ๋จ์ด์ ๊ฐ์ฅ ๊ฐ๊น์ด ์กด์ฌํ๋๋จ์ด๋ค์ ์ถ๋ ฅํ ๊ฒ์ด๋ค.
def pretty_print(results):
"""
์๋ฒ ๋ฉ ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅํฉ๋๋ค
"""
for item in results:
print ("...[%.2f] - %s"%(item[1], item[0]))
# n์ ์ถ๋ ฅ์์ํ๋ ๊ฐ์ ์
๋ ฅ
def get_closest(target_word, word_to_idx, embeddings, n=5):
"""
n๊ฐ์ ์ต๊ทผ์ ๋จ์ด๋ฅผ ์ฐพ์ต๋๋ค.
"""
# ๋ค๋ฅธ ๋ชจ๋ ๋จ์ด๊น์ง ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐํฉ๋๋ค
word_embedding = embeddings[word_to_idx[target_word.lower()]]
distances = []
for word, index in word_to_idx.items():
if word == "<MASK>" or word == target_word:
continue
distances.append((word, torch.dist(word_embedding, embeddings[index])))
results = sorted(distances, key=lambda x: x[1])[1:n+2]
return results
word = input('๋จ์ด๋ฅผ ์
๋ ฅํด ์ฃผ์ธ์: ')
embeddings = classifier.embedding.weight.data
word_to_idx = vectorizer.cbow_vocab._token_to_idx
pretty_print(get_closest(word, word_to_idx, embeddings, n=5))
target_words = ['frankenstein', 'monster', 'science', 'sickness', 'lonely', 'happy']
embeddings = classifier.embedding.weight.data
word_to_idx = vectorizer.cbow_vocab._token_to_idx
for target_word in target_words:
print(f"======={target_word}=======")
if target_word not in word_to_idx:
print("Not in vocabulary")
continue
pretty_print(get_closest(target_word, word_to_idx, embeddings, n=5))
์ด๋ฒ ์์ ์์๋ nn.Embedding ์ธต์ ์ฌ์ฉํ์ฌ CBOW ๋ถ๋ฅ ์ง๋ํ์ต ์์ ์ผ๋ก ๋ฐ๋ฐ๋ฅ๋ถํฐ ์๋ฒ ๋ฉ์ ํ๋ จ์์ผ ๋ณด์๋ค. ์์ ๋ณด์๋ฏ์ด ๋ฐ๋ฐ๋ฅ๋ถํฐ ํ๋ จ์ํค๊ธฐ์ ์ถฉ๋ถํ์ง ๋ชปํ ๋ฐ์ดํฐ์ ํฌ๊ธฐ๋ฅผ ๊ฐ์ง๊ณ ์์ด์ ์ ํ๋๊ฐ 15%๋ก ๋งค์ฐ ๋ฎ๋ค. ๋ค์ ๊ณต๋ถ์์๋ ๋ง๋ญ์น์ ์ฃผ์ด์ง '์ฌ์ ํ๋ จ๋ ์๋ฒ ๋ฉ'์ ๋ฏธ์ธ ์กฐ์ ํด์ ์ฌ์ฉํ๋ '์ ์ดํ์ต'๋ฐฉ๋ฒ์ ์ดํด๋ณผ ๊ฒ์ด๋ค. ๋ฐ๋ฐ๋ฅ ๋ถํฐ ํ๋ จ์ํค๋ ๊ฒ์ ๋งค์ฐ ๋ง์ ๋ฐ์ดํฐ์ ์ด ํ์ํ๊ธฐ์ ์์ฆ์๋ '์ ์ดํ์ต'๊ณผ ๊ฐ์ด ํ๋ จ๋ ๋ชจ๋ธ์ ๋ค๋ฅธ ์์ ์ ์ด๊ธฐ ๋ชจ๋ธ๋ก ์ฌ์ฉํ๋ ๋ฐฉ์์ด ๋ง์ด ์ฌ์ฉ๋๋ค.