noch inator commited on
Fixed some model loading errors in train function
Browse files- ThoughtVectors.py +140 -106
ThoughtVectors.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
|
|
| 1 |
import random
|
| 2 |
import math
|
| 3 |
import torch
|
|
@@ -440,20 +441,8 @@ class ThoughtVectors:
|
|
| 440 |
|
| 441 |
if model and os.path.exists(model):
|
| 442 |
print("loading model...")
|
| 443 |
-
|
| 444 |
-
self.
|
| 445 |
-
self.vocab_size = self.sp.GetPieceSize()
|
| 446 |
-
self.encoder = ThoughtEncoder(
|
| 447 |
-
vocab_size=self.vocab_size, d_model=d_model, max_thoughts=max_thoughts,
|
| 448 |
-
nhead=encoder_nhead, num_layers=encoder_layers, dropout=dropout,
|
| 449 |
-
termination_threshold=termination_threshold, max_len=self.max_len
|
| 450 |
-
).to(self.device)
|
| 451 |
-
self.decoder = ThoughtDecoder(
|
| 452 |
-
vocab_size=self.vocab_size, d_model=d_model, num_layers=decoder_layers,
|
| 453 |
-
nhead=decoder_nhead, dropout=dropout, max_len=self.max_len
|
| 454 |
-
).to(self.device)
|
| 455 |
-
self.encoder.load_state_dict(checkpoint['encoder_state_dict'])
|
| 456 |
-
self.decoder.load_state_dict(checkpoint['decoder_state_dict'])
|
| 457 |
print(f"Loaded pre-existing model from {model}")
|
| 458 |
else:
|
| 459 |
print("building models")
|
|
@@ -507,100 +496,122 @@ class ThoughtVectors:
|
|
| 507 |
patience_counter = 0
|
| 508 |
|
| 509 |
print("Beginning training")
|
| 510 |
-
|
| 511 |
-
|
| 512 |
-
|
| 513 |
-
|
| 514 |
-
for i in range(0, len(train_lazy_data), batch_size):
|
| 515 |
-
raw_batch = train_lazy_data[i:i + batch_size]
|
| 516 |
-
tokenized_batch = [
|
| 517 |
-
[[self.sp.bos_id()] + self.sp.EncodeAsIds(s) + [self.sp.eos_id()] for s in group]
|
| 518 |
-
for group in raw_batch
|
| 519 |
-
]
|
| 520 |
-
group_batch = group_collate_fn(tokenized_batch)
|
| 521 |
-
|
| 522 |
-
batch_loss = 0.0
|
| 523 |
-
with autocast('cuda'):
|
| 524 |
-
for group_tensor in group_batch:
|
| 525 |
-
if group_tensor.shape[1] <= self.max_len and group_tensor.numel() > 0:
|
| 526 |
-
group_tensor = group_tensor.to(self.device)
|
| 527 |
-
force_single_vector = random.random() < single_vector_prob
|
| 528 |
-
thought_vectors = self.encoder(group_tensor, force_single_vector)
|
| 529 |
-
output_logits = self.decoder(thought_vectors, group_tensor[:, :-1])
|
| 530 |
-
|
| 531 |
-
# Masked loss
|
| 532 |
-
mask = (group_tensor[:, 1:] != self.sp.pad_id()).float()
|
| 533 |
-
loss = criterion(output_logits.reshape(-1, self.vocab_size),
|
| 534 |
-
group_tensor[:, 1:].reshape(-1))
|
| 535 |
-
loss = (loss * mask.reshape(-1)).sum() / mask.sum().clamp(min=1.0)
|
| 536 |
-
if not force_single_vector:
|
| 537 |
-
loss += length_penalty * thought_vectors.shape[1]
|
| 538 |
-
batch_loss += loss / accum_steps
|
| 539 |
-
|
| 540 |
-
scaler.scale(batch_loss).backward()
|
| 541 |
-
total_train_loss += batch_loss.item() * accum_steps
|
| 542 |
-
if (i // batch_size + 1) % accum_steps == 0:
|
| 543 |
-
scaler.step(optimizer)
|
| 544 |
-
scaler.update()
|
| 545 |
-
optimizer.zero_grad()
|
| 546 |
-
torch.cuda.empty_cache()
|
| 547 |
-
|
| 548 |
-
print(f"Batch {i // batch_size + 1}/{num_train_batches} - Loss: {batch_loss.item():.4f}")
|
| 549 |
-
# Debugging
|
| 550 |
-
print(f" Input: {self.sp.DecodeIds(group_tensor[0].tolist())}")
|
| 551 |
-
print(f"Output: {self.sp.DecodeIds(output_logits.argmax(-1)[0].tolist())}\n\n")
|
| 552 |
-
|
| 553 |
-
avg_train_loss = total_train_loss / num_train_batches if num_train_batches > 0 else float('inf')
|
| 554 |
-
|
| 555 |
-
# Validation with test_lazy_data
|
| 556 |
-
if test_lazy_data is not None:
|
| 557 |
-
self.encoder.eval()
|
| 558 |
-
self.decoder.eval()
|
| 559 |
-
total_val_loss = 0.0
|
| 560 |
-
num_val_batches = (len(test_lazy_data) + batch_size - 1) // batch_size
|
| 561 |
-
print(f"Starting validation with {num_val_batches} batches")
|
| 562 |
|
| 563 |
-
|
| 564 |
-
|
| 565 |
-
|
| 566 |
-
|
| 567 |
-
|
| 568 |
-
|
| 569 |
-
|
| 570 |
-
|
| 571 |
-
|
| 572 |
-
|
|
|
|
| 573 |
for group_tensor in group_batch:
|
| 574 |
if group_tensor.shape[1] <= self.max_len and group_tensor.numel() > 0:
|
| 575 |
group_tensor = group_tensor.to(self.device)
|
| 576 |
-
|
|
|
|
| 577 |
output_logits = self.decoder(thought_vectors, group_tensor[:, :-1])
|
| 578 |
-
|
| 579 |
-
|
| 580 |
-
|
| 581 |
-
|
| 582 |
-
|
| 583 |
-
|
| 584 |
-
|
| 585 |
-
|
| 586 |
-
|
| 587 |
-
|
| 588 |
-
|
| 589 |
-
|
| 590 |
-
|
| 591 |
-
|
| 592 |
-
|
| 593 |
-
|
| 594 |
-
|
| 595 |
-
|
| 596 |
-
|
| 597 |
-
|
| 598 |
-
|
| 599 |
-
print(f"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 600 |
break
|
| 601 |
-
|
| 602 |
-
|
| 603 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 604 |
print(f"Best model saved to {save_path}")
|
| 605 |
|
| 606 |
def encode(self, text: Union[str, List[str]], force_single_vector: bool = False) -> torch.Tensor:
|
|
@@ -802,10 +813,33 @@ class ThoughtVectors:
|
|
| 802 |
|
| 803 |
|
| 804 |
if __name__ == "__main__":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 805 |
tv = ThoughtVectors()
|
| 806 |
tv.train(
|
| 807 |
-
group_data=
|
| 808 |
-
test_data=
|
|
|
|
| 809 |
num_epochs=1000,
|
| 810 |
batch_size=128,
|
| 811 |
accum_steps=1,
|
|
@@ -813,7 +847,7 @@ if __name__ == "__main__":
|
|
| 813 |
weight_decay=2e-5,
|
| 814 |
length_penalty=0.001,
|
| 815 |
single_vector_prob=0.1,
|
| 816 |
-
save_path="thought_vectors_prototype.tar",
|
| 817 |
spm_model_prefix="spm",
|
| 818 |
vocab_size=8192,
|
| 819 |
d_model=512,
|
|
@@ -827,7 +861,7 @@ if __name__ == "__main__":
|
|
| 827 |
termination_threshold=0.8,
|
| 828 |
patience=5
|
| 829 |
)
|
| 830 |
-
loaded_tv = ThoughtVectors.load("thought_vectors_prototype.tar")
|
| 831 |
thought_vectors = loaded_tv.encode("AI is smart")
|
| 832 |
generated_text_greedy = loaded_tv.decode(thought_vectors, temperature=0.7, beam_width=0)
|
| 833 |
generated_text_beam = loaded_tv.decode(thought_vectors, beam_width=5)
|
|
|
|
| 1 |
+
# thought_vectors.py
|
| 2 |
import random
|
| 3 |
import math
|
| 4 |
import torch
|
|
|
|
| 441 |
|
| 442 |
if model and os.path.exists(model):
|
| 443 |
print("loading model...")
|
| 444 |
+
loaded_instance = self.load(model)
|
| 445 |
+
self.__dict__.update(loaded_instance.__dict__) # actually update self
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 446 |
print(f"Loaded pre-existing model from {model}")
|
| 447 |
else:
|
| 448 |
print("building models")
|
|
|
|
| 496 |
patience_counter = 0
|
| 497 |
|
| 498 |
print("Beginning training")
|
| 499 |
+
try:
|
| 500 |
+
for epoch in range(num_epochs):
|
| 501 |
+
total_train_loss = 0.0
|
| 502 |
+
num_train_batches = (len(train_lazy_data) + batch_size - 1) // batch_size
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 503 |
|
| 504 |
+
# training
|
| 505 |
+
for i in range(0, len(train_lazy_data), batch_size):
|
| 506 |
+
raw_batch = train_lazy_data[i:i + batch_size]
|
| 507 |
+
tokenized_batch = [
|
| 508 |
+
[[self.sp.bos_id()] + self.sp.EncodeAsIds(s) + [self.sp.eos_id()] for s in group]
|
| 509 |
+
for group in raw_batch
|
| 510 |
+
]
|
| 511 |
+
group_batch = group_collate_fn(tokenized_batch)
|
| 512 |
+
|
| 513 |
+
batch_loss = 0.0
|
| 514 |
+
with autocast('cuda'):
|
| 515 |
for group_tensor in group_batch:
|
| 516 |
if group_tensor.shape[1] <= self.max_len and group_tensor.numel() > 0:
|
| 517 |
group_tensor = group_tensor.to(self.device)
|
| 518 |
+
force_single_vector = random.random() < single_vector_prob
|
| 519 |
+
thought_vectors = self.encoder(group_tensor, force_single_vector)
|
| 520 |
output_logits = self.decoder(thought_vectors, group_tensor[:, :-1])
|
| 521 |
+
|
| 522 |
+
# Masked loss
|
| 523 |
+
mask = (group_tensor[:, 1:] != self.sp.pad_id()).float()
|
| 524 |
+
loss = criterion(output_logits.reshape(-1, self.vocab_size),
|
| 525 |
+
group_tensor[:, 1:].reshape(-1))
|
| 526 |
+
loss = (loss * mask.reshape(-1)).sum() / mask.sum().clamp(min=1.0)
|
| 527 |
+
if not force_single_vector:
|
| 528 |
+
loss += length_penalty * thought_vectors.shape[1]
|
| 529 |
+
batch_loss += loss / accum_steps
|
| 530 |
+
|
| 531 |
+
scaler.scale(batch_loss).backward()
|
| 532 |
+
total_train_loss += batch_loss.item() * accum_steps
|
| 533 |
+
if (i // batch_size + 1) % accum_steps == 0:
|
| 534 |
+
scaler.step(optimizer)
|
| 535 |
+
scaler.update()
|
| 536 |
+
optimizer.zero_grad()
|
| 537 |
+
torch.cuda.empty_cache()
|
| 538 |
+
|
| 539 |
+
print(f"Batch {i // batch_size + 1}/{num_train_batches} - Loss: {batch_loss.item():.4f}")
|
| 540 |
+
# Debugging
|
| 541 |
+
print(f" Input: {self.sp.DecodeIds(group_tensor[0].tolist())}")
|
| 542 |
+
print(f"Output: {self.sp.DecodeIds(output_logits.argmax(-1)[0].tolist())}\n\n")
|
| 543 |
+
|
| 544 |
+
avg_train_loss = total_train_loss / num_train_batches if num_train_batches > 0 else float('inf')
|
| 545 |
+
|
| 546 |
+
# Validation
|
| 547 |
+
if test_lazy_data is not None:
|
| 548 |
+
self.encoder.eval()
|
| 549 |
+
self.decoder.eval()
|
| 550 |
+
total_val_loss = 0.0
|
| 551 |
+
num_val_batches = (len(test_lazy_data) + batch_size - 1) // batch_size
|
| 552 |
+
print(f"Starting validation with {num_val_batches} batches")
|
| 553 |
+
|
| 554 |
+
with torch.no_grad():
|
| 555 |
+
for i in range(0, len(test_lazy_data), batch_size):
|
| 556 |
+
raw_batch = test_lazy_data[i:i + batch_size]
|
| 557 |
+
tokenized_batch = [
|
| 558 |
+
[[self.sp.bos_id()] + self.sp.EncodeAsIds(s) + [self.sp.eos_id()] for s in group]
|
| 559 |
+
for group in raw_batch
|
| 560 |
+
]
|
| 561 |
+
group_batch = group_collate_fn(tokenized_batch)
|
| 562 |
+
|
| 563 |
+
batch_val_loss = 0.0
|
| 564 |
+
for group_tensor in group_batch:
|
| 565 |
+
if group_tensor.shape[1] <= self.max_len and group_tensor.numel() > 0:
|
| 566 |
+
group_tensor = group_tensor.to(self.device)
|
| 567 |
+
thought_vectors = self.encoder(group_tensor)
|
| 568 |
+
output_logits = self.decoder(thought_vectors, group_tensor[:, :-1])
|
| 569 |
+
val_loss = criterion(output_logits.reshape(-1, self.vocab_size),
|
| 570 |
+
group_tensor[:, 1:].reshape(-1))
|
| 571 |
+
val_loss += length_penalty * thought_vectors.shape[1]
|
| 572 |
+
batch_val_loss += val_loss.item()
|
| 573 |
+
total_val_loss += batch_val_loss
|
| 574 |
+
print(f"VAL batch loss: {batch_val_loss:.4f}")
|
| 575 |
+
print(f" Input: {self.sp.DecodeIds(group_tensor[0].tolist())}")
|
| 576 |
+
print(f"Output: {self.sp.DecodeIds(output_logits.argmax(-1)[0].tolist())}\n\n")
|
| 577 |
+
avg_val_loss = total_val_loss / num_val_batches if num_val_batches > 0 else float('inf')
|
| 578 |
+
else:
|
| 579 |
+
avg_val_loss = avg_train_loss
|
| 580 |
+
|
| 581 |
+
print(f"Epoch {epoch + 1}/{num_epochs} - Train Loss: {avg_train_loss:.4f} - Val Loss: {avg_val_loss:.4f}\n\n")
|
| 582 |
+
|
| 583 |
+
if avg_val_loss < best_val_loss:
|
| 584 |
+
best_val_loss = avg_val_loss
|
| 585 |
+
patience_counter = 0
|
| 586 |
+
self.save(save_path, spm_model_prefix, clean=False)
|
| 587 |
+
else:
|
| 588 |
+
self.load(save_path)
|
| 589 |
+
self.save(save_path, spm_model_prefix, clean=True)
|
| 590 |
+
patience_counter += 1
|
| 591 |
+
if patience_counter >= patience:
|
| 592 |
+
print(f"Early stopping triggered after {epoch + 1} epochs.")
|
| 593 |
+
break
|
| 594 |
+
|
| 595 |
+
scheduler.step()
|
| 596 |
+
# Allow saving model on keyboard interrupt
|
| 597 |
+
except KeyboardInterrupt:
|
| 598 |
+
while True:
|
| 599 |
+
saving = input("Would you like to save the best (b), current (c), or no (n) model?")
|
| 600 |
+
saving = saving.strip().lower
|
| 601 |
+
if saving == "best" or saving == "b":
|
| 602 |
+
self.load(save_path)
|
| 603 |
+
self.save(save_path, spm_model_prefix, clean=True)
|
| 604 |
break
|
| 605 |
+
elif saving == "current" or saving == "c" or saving == "curr":
|
| 606 |
+
self.save(save_path, spm_model_prefix, clean=True)
|
| 607 |
+
break
|
| 608 |
+
elif saving == "n" or saving == "no" or saving == "":
|
| 609 |
+
self.save(save_path, spm_model_prefix, clean=True)
|
| 610 |
+
os.remove(save_path)
|
| 611 |
+
break
|
| 612 |
+
else:
|
| 613 |
+
print("invalid input, type 'b' 'c' or 'n'")
|
| 614 |
+
|
| 615 |
print(f"Best model saved to {save_path}")
|
| 616 |
|
| 617 |
def encode(self, text: Union[str, List[str]], force_single_vector: bool = False) -> torch.Tensor:
|
|
|
|
| 813 |
|
| 814 |
|
| 815 |
if __name__ == "__main__":
|
| 816 |
+
def process_train(input_file):
|
| 817 |
+
data = []
|
| 818 |
+
with open(input_file, 'r', encoding='utf-8') as f_in:
|
| 819 |
+
reader = csv.reader(f_in)
|
| 820 |
+
for row in reader:
|
| 821 |
+
sentence1 = row[0].strip()
|
| 822 |
+
data.append([sentence1])
|
| 823 |
+
|
| 824 |
+
return data
|
| 825 |
+
|
| 826 |
+
def process_test(input_file):
|
| 827 |
+
data = []
|
| 828 |
+
with open(input_file, 'r', encoding='utf-8') as f_in:
|
| 829 |
+
reader = csv.reader(f_in)
|
| 830 |
+
for row in reader:
|
| 831 |
+
sentence1 = row[0].strip()
|
| 832 |
+
data.append([sentence1])
|
| 833 |
+
return data
|
| 834 |
+
|
| 835 |
+
data = process_train("SNLItrain.csv")
|
| 836 |
+
val = process_test("SNLIval.csv")
|
| 837 |
+
|
| 838 |
tv = ThoughtVectors()
|
| 839 |
tv.train(
|
| 840 |
+
group_data=data,
|
| 841 |
+
test_data=val,
|
| 842 |
+
model="thought_vectors_prototype-0.1.tar",
|
| 843 |
num_epochs=1000,
|
| 844 |
batch_size=128,
|
| 845 |
accum_steps=1,
|
|
|
|
| 847 |
weight_decay=2e-5,
|
| 848 |
length_penalty=0.001,
|
| 849 |
single_vector_prob=0.1,
|
| 850 |
+
save_path="thought_vectors_prototype-0.2.tar",
|
| 851 |
spm_model_prefix="spm",
|
| 852 |
vocab_size=8192,
|
| 853 |
d_model=512,
|
|
|
|
| 861 |
termination_threshold=0.8,
|
| 862 |
patience=5
|
| 863 |
)
|
| 864 |
+
loaded_tv = ThoughtVectors.load("thought_vectors_prototype-0.2.tar")
|
| 865 |
thought_vectors = loaded_tv.encode("AI is smart")
|
| 866 |
generated_text_greedy = loaded_tv.decode(thought_vectors, temperature=0.7, beam_width=0)
|
| 867 |
generated_text_beam = loaded_tv.decode(thought_vectors, beam_width=5)
|