noch inator commited on
Commit
7b34311
·
verified ·
1 Parent(s): 9e6d62a

Update ThoughtVectors.py

Browse files

Added improvements, including more error handling, proper loss calculation/application, and more

Files changed (1) hide show
  1. ThoughtVectors.py +74 -68
ThoughtVectors.py CHANGED
@@ -1,4 +1,3 @@
1
- # thought_vectors.py
2
  import random
3
  import math
4
  import torch
@@ -6,7 +5,7 @@ import torch.nn as nn
6
  import torch.optim as optim
7
  import sentencepiece as spm
8
  from torch.utils.data import Dataset, DataLoader
9
- from torch.cuda.amp import autocast, GradScaler
10
  from typing import List, Union, Generator, Sequence, Optional
11
  import os
12
  import csv
@@ -48,8 +47,7 @@ class PositionalEncoding(nn.Module):
48
  (-math.log(10000.0) / d_model))
49
 
50
  pe[:, 0::2] = torch.sin(position * div_term)
51
- pe[:, 1::2] = torch.cos(position * div_term[:d_model // 2 + 1] if d_model % 2 else div_term)
52
-
53
  pe = pe.unsqueeze(0)
54
  self.register_buffer('pe', pe)
55
  else:
@@ -107,7 +105,8 @@ class ThoughtEncoder(nn.Module):
107
  nhead: int = 8, num_layers: int = 2, dropout: float = 0.1, pad_id: int = 0,
108
  termination_threshold: float = 0.75, max_len: int = 5000):
109
  super().__init__()
110
- assert nhead % 2 == 0, "nhead must be even for thought_attention"
 
111
  self.d_model = d_model
112
  self.max_thoughts = max_thoughts
113
  self.pad_id = pad_id
@@ -164,7 +163,7 @@ class ThoughtEncoder(nn.Module):
164
 
165
  thought_vectors_list.append(next_thought)
166
  finished = finished | (termination_score > self.termination_threshold)
167
- if finished.all():
168
  break
169
 
170
  return torch.stack(thought_vectors_list, dim=1)
@@ -202,6 +201,8 @@ class ThoughtDecoder(nn.Module):
202
  Returns:
203
  torch.Tensor: Mask tensor, shape (sz, sz).
204
  """
 
 
205
  mask = (torch.triu(torch.ones(sz, sz, device=device)) == 1).transpose(0, 1)
206
  mask = mask.float().masked_fill(mask == 0, float('-inf')).masked_fill(mask == 1, float(0.0))
207
  return mask
@@ -302,43 +303,40 @@ class LazyList(Sequence):
302
  else:
303
  self._length = 4
304
  return self._length
305
-
306
- def __getitem__(self, index: int) -> List[str]:
307
- """Return a single row with semi-random skipping; index is ignored.
308
-
309
- Args:
310
- index (int): Ignored parameter (kept for Sequence compatibility).
311
-
312
- Returns:
313
- List[str]: A row from the data, with ~25% chance of skipping each row.
314
- """
315
  if self.data_list is not None:
316
- # For in-memory list, pick a random row (faster than iterating)
317
  return random.choice(self.data_list)
318
-
319
  elif self.filepath and os.path.exists(self.filepath):
320
  self._open_file()
321
  try:
322
  while True:
323
  row = next(self._reader)
324
- if row and random.random() <= self.sample_prob: # 75% chance to return
325
  return row
326
  except StopIteration:
327
- # Reset file pointer to start if we reach the end
328
  self._file_handle.seek(0)
329
  self._reader = csv.reader(self._file_handle)
330
- row = next(self._reader) # Return first row if available
331
- if row:
332
- return row
333
-
334
- # Dummy data fallback
335
- dummy_data = [
 
 
336
  ["Hello world", "AI is cool"],
337
  ["This is a test", "Another sentence"],
338
  ["Python is fun", "Coding rocks"],
339
  ["Short sentence", "Quick test"],
340
  ]
341
- return random.choice(dummy_data)
342
 
343
  def __del__(self):
344
  """Close the file handle when the object is destroyed."""
@@ -441,6 +439,7 @@ class ThoughtVectors:
441
  test_lazy_data = LazyList(test_data) if test_data is not None else None
442
 
443
  if model and os.path.exists(model):
 
444
  checkpoint = torch.load(model, map_location=self.device)
445
  self.sp.Load(checkpoint['spm_model_path'])
446
  self.vocab_size = self.sp.GetPieceSize()
@@ -457,6 +456,7 @@ class ThoughtVectors:
457
  self.decoder.load_state_dict(checkpoint['decoder_state_dict'])
458
  print(f"Loaded pre-existing model from {model}")
459
  else:
 
460
  with tempfile.NamedTemporaryFile(mode="w", encoding="utf8", delete=False) as temp_file:
461
  for group in train_lazy_data:
462
  for sentence in group:
@@ -466,6 +466,8 @@ class ThoughtVectors:
466
  temp_dir = tempfile.mkdtemp()
467
  temp_spm_prefix = os.path.join(temp_dir, "spm")
468
  try:
 
 
469
  spm.SentencePieceTrainer.Train(
470
  input=temp_dataset_path,
471
  model_prefix=temp_spm_prefix,
@@ -499,56 +501,54 @@ class ThoughtVectors:
499
  lr=learning_rate, weight_decay=weight_decay)
500
  scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=num_epochs)
501
  criterion = nn.CrossEntropyLoss(ignore_index=self.sp.pad_id())
502
- scaler = GradScaler()
503
 
504
  best_val_loss = float('inf')
505
  patience_counter = 0
506
 
507
  print("Beginning training")
508
  for epoch in range(num_epochs):
509
- self.encoder.train()
510
- self.decoder.train()
511
  total_train_loss = 0.0
512
- optimizer.zero_grad()
513
 
514
- # Manual batching from train_lazy_data with tokenization
515
- train_data_list = list(train_lazy_data) # List[str]
516
- random.shuffle(train_data_list)
517
- num_train_batches = (len(train_data_list) + batch_size - 1) // batch_size
518
-
519
- for i in range(0, len(train_data_list), batch_size):
520
- raw_batch = train_data_list[i:i + batch_size]
521
- # Tokenize each group in the batch
522
  tokenized_batch = [
523
  [[self.sp.bos_id()] + self.sp.EncodeAsIds(s) + [self.sp.eos_id()] for s in group]
524
  for group in raw_batch
525
  ]
526
- group_batch = group_collate_fn(tokenized_batch) # Process into padded tensors
527
 
528
  batch_loss = 0.0
529
- with autocast():
530
  for group_tensor in group_batch:
531
  if group_tensor.shape[1] <= self.max_len and group_tensor.numel() > 0:
532
  group_tensor = group_tensor.to(self.device)
533
  force_single_vector = random.random() < single_vector_prob
534
  thought_vectors = self.encoder(group_tensor, force_single_vector)
535
  output_logits = self.decoder(thought_vectors, group_tensor[:, :-1])
 
 
 
536
  loss = criterion(output_logits.reshape(-1, self.vocab_size),
537
  group_tensor[:, 1:].reshape(-1))
 
538
  if not force_single_vector:
539
  loss += length_penalty * thought_vectors.shape[1]
540
  batch_loss += loss / accum_steps
541
 
542
  scaler.scale(batch_loss).backward()
 
543
  if (i // batch_size + 1) % accum_steps == 0:
544
  scaler.step(optimizer)
545
  scaler.update()
546
  optimizer.zero_grad()
547
  torch.cuda.empty_cache()
548
 
549
- total_train_loss += batch_loss.item() * accum_steps
550
- print(
551
- f"Batch {i // batch_size + 1}/{num_train_batches} - Train Loss: {batch_loss:.4f}")
 
552
 
553
  avg_train_loss = total_train_loss / num_train_batches if num_train_batches > 0 else float('inf')
554
 
@@ -557,13 +557,12 @@ class ThoughtVectors:
557
  self.encoder.eval()
558
  self.decoder.eval()
559
  total_val_loss = 0.0
560
- test_data_list = list(test_lazy_data)
561
- num_val_batches = (len(test_data_list) + batch_size - 1) // batch_size
562
 
563
  with torch.no_grad():
564
- for i in range(0, len(test_data_list), batch_size):
565
- raw_batch = test_data_list[i:i + batch_size]
566
- # Tokenize each group in the batch
567
  tokenized_batch = [
568
  [[self.sp.bos_id()] + self.sp.EncodeAsIds(s) + [self.sp.eos_id()] for s in group]
569
  for group in raw_batch
@@ -578,14 +577,17 @@ class ThoughtVectors:
578
  output_logits = self.decoder(thought_vectors, group_tensor[:, :-1])
579
  val_loss = criterion(output_logits.reshape(-1, self.vocab_size),
580
  group_tensor[:, 1:].reshape(-1))
 
581
  batch_val_loss += val_loss.item()
582
  total_val_loss += batch_val_loss
583
-
 
 
584
  avg_val_loss = total_val_loss / num_val_batches if num_val_batches > 0 else float('inf')
585
  else:
586
  avg_val_loss = avg_train_loss
587
 
588
- print(f"Epoch {epoch + 1}/{num_epochs} - Train Loss: {avg_train_loss:.4f} - Val Loss: {avg_val_loss:.4f}")
589
 
590
  if avg_val_loss < best_val_loss:
591
  best_val_loss = avg_val_loss
@@ -626,14 +628,14 @@ class ThoughtVectors:
626
 
627
  return self.encoder(input_tokens, force_single_vector)
628
 
629
- def decode(self, thought_vectors: torch.Tensor, max_length: int = 50, beam_width: Optional[int] = 5,
630
  temperature: float = 1.0) -> List[str]:
631
  """Decodes thought vectors into text sequences.
632
 
633
  Args:
634
  thought_vectors (torch.Tensor): Thought vectors, shape (batch_size, num_thoughts, d_model).
635
  max_length (int, optional): Maximum length of generated sequences. Defaults to 50.
636
- beam_width (Optional[int], optional): Beam width for beam search; if None, uses greedy
637
  decoding. Defaults to 5.
638
  temperature (float, optional): Temperature for softmax sampling in greedy decoding.
639
  Defaults to 1.0.
@@ -647,13 +649,14 @@ class ThoughtVectors:
647
  thought_vectors = thought_vectors.to(self.device)
648
  batch_size = thought_vectors.size(0)
649
 
650
- if beam_width is not None and beam_width > 1:
651
  return self._beam_search_decode(thought_vectors, max_length, beam_width)
652
 
653
  target_tokens = torch.full((batch_size, 1), self.sp.bos_id(), dtype=torch.long, device=self.device)
654
  for _ in range(max_length - 1):
655
  logits = self.decoder(thought_vectors, target_tokens)
656
  logits = logits[:, -1, :] / temperature
 
657
  next_token = logits.softmax(dim=-1).multinomial(1)
658
  target_tokens = torch.cat([target_tokens, next_token], dim=1)
659
  if (next_token == self.sp.eos_id()).all():
@@ -702,7 +705,8 @@ class ThoughtVectors:
702
  results = []
703
  for i in range(batch_size):
704
  combined = sorted(finished[i] + beams[i], key=lambda x: x[0])
705
- results.append(self.sp.DecodeIds(combined[0][1].squeeze(0).tolist()) if combined else "<empty>")
 
706
 
707
  return results
708
 
@@ -756,10 +760,11 @@ class ThoughtVectors:
756
  ThoughtVectors: Loaded model instance.
757
  """
758
  translator = cls()
 
759
  try:
760
  with tarfile.open(path, "r") as tar:
761
  tar.extractall()
762
- checkpoint = torch.load("model.pth")
763
  translator.sp = spm.SentencePieceProcessor()
764
  if not translator.sp.Load("spm.model"):
765
  raise RuntimeError("Failed to load SentencePiece model.")
@@ -778,6 +783,7 @@ class ThoughtVectors:
778
  translator.dropout = checkpoint['dropout']
779
  translator.max_len = checkpoint['max_len']
780
  translator.termination_threshold = checkpoint['termination_threshold']
 
781
 
782
  translator.encoder = ThoughtEncoder(
783
  vocab_size=translator.vocab_size, d_model=translator.d_model, max_thoughts=translator.max_thoughts,
@@ -796,16 +802,16 @@ class ThoughtVectors:
796
 
797
 
798
  if __name__ == "__main__":
799
- csv.field_size_limit(8 ** 8)
800
  tv = ThoughtVectors()
801
  tv.train(
802
- group_data="data.csv",
 
803
  num_epochs=1000,
804
- batch_size=64,
805
- accum_steps=4,
806
- learning_rate=1e-4,
807
  weight_decay=2e-5,
808
- length_penalty=0.01,
809
  single_vector_prob=0.1,
810
  save_path="thought_vectors_prototype.tar",
811
  spm_model_prefix="spm",
@@ -813,18 +819,18 @@ if __name__ == "__main__":
813
  d_model=512,
814
  encoder_nhead=8,
815
  decoder_nhead=8,
816
- encoder_layers=2,
817
- decoder_layers=2,
818
- max_thoughts=32,
819
  dropout=0.1,
820
- max_len=1024,
821
  termination_threshold=0.8,
822
  patience=5
823
  )
824
  loaded_tv = ThoughtVectors.load("thought_vectors_prototype.tar")
825
  thought_vectors = loaded_tv.encode("AI is smart")
826
- generated_text_greedy = loaded_tv.decode(thought_vectors, temperature=0.7)
827
- generated_text_beam = loaded_tv.decode(thought_vectors, beam_width=3)
828
  print(f"Greedy decoding: {generated_text_greedy}")
829
  print(f"Beam search decoding: {generated_text_beam}")
830
 
 
 
1
  import random
2
  import math
3
  import torch
 
5
  import torch.optim as optim
6
  import sentencepiece as spm
7
  from torch.utils.data import Dataset, DataLoader
8
+ from torch.amp import autocast, GradScaler
9
  from typing import List, Union, Generator, Sequence, Optional
10
  import os
11
  import csv
 
47
  (-math.log(10000.0) / d_model))
48
 
49
  pe[:, 0::2] = torch.sin(position * div_term)
50
+ pe[:, 1::2] = torch.cos(position * div_term[:self.d_model // 2 + (self.d_model % 2)])
 
51
  pe = pe.unsqueeze(0)
52
  self.register_buffer('pe', pe)
53
  else:
 
105
  nhead: int = 8, num_layers: int = 2, dropout: float = 0.1, pad_id: int = 0,
106
  termination_threshold: float = 0.75, max_len: int = 5000):
107
  super().__init__()
108
+ if nhead % 2 != 0:
109
+ raise ValueError(f"nhead must be even for thought_attention, got {nhead}")
110
  self.d_model = d_model
111
  self.max_thoughts = max_thoughts
112
  self.pad_id = pad_id
 
163
 
164
  thought_vectors_list.append(next_thought)
165
  finished = finished | (termination_score > self.termination_threshold)
166
+ if finished.all() and not force_single_vector:
167
  break
168
 
169
  return torch.stack(thought_vectors_list, dim=1)
 
201
  Returns:
202
  torch.Tensor: Mask tensor, shape (sz, sz).
203
  """
204
+ if self.positional_encoding.max_len > 0 and sz > self.positional_encoding.max_len:
205
+ raise ValueError(f"Sequence length {sz} exceeds max_len {self.positional_encoding.max_len}")
206
  mask = (torch.triu(torch.ones(sz, sz, device=device)) == 1).transpose(0, 1)
207
  mask = mask.float().masked_fill(mask == 0, float('-inf')).masked_fill(mask == 1, float(0.0))
208
  return mask
 
303
  else:
304
  self._length = 4
305
  return self._length
306
+
307
+ def __getitem__(self, index: Union[int, slice]) -> Union[List[str], List[List[str]]]:
308
+ if isinstance(index, slice):
309
+ start, stop, step = index.indices(len(self))
310
+ count = (stop - start) // (step or 1)
311
+ return [self._get_single_item() for _ in range(max(0, count))]
312
+ return self._get_single_item()
313
+
314
+ def _get_single_item(self) -> List[str]:
 
315
  if self.data_list is not None:
 
316
  return random.choice(self.data_list)
 
317
  elif self.filepath and os.path.exists(self.filepath):
318
  self._open_file()
319
  try:
320
  while True:
321
  row = next(self._reader)
322
+ if row and random.random() <= self.sample_prob:
323
  return row
324
  except StopIteration:
 
325
  self._file_handle.seek(0)
326
  self._reader = csv.reader(self._file_handle)
327
+ row = next(self._reader)
328
+ return row if row else random.choice(self._dummy_data())
329
+ print("WARN: file error, file may be empty, missing, or inaccessible. Dummy data returned") # change to raise in release
330
+ return random.choice(self._dummy_data()) # remove in release
331
+
332
+ # remove in release
333
+ def _dummy_data(self) -> List[List[str]]:
334
+ return [
335
  ["Hello world", "AI is cool"],
336
  ["This is a test", "Another sentence"],
337
  ["Python is fun", "Coding rocks"],
338
  ["Short sentence", "Quick test"],
339
  ]
 
340
 
341
  def __del__(self):
342
  """Close the file handle when the object is destroyed."""
 
439
  test_lazy_data = LazyList(test_data) if test_data is not None else None
440
 
441
  if model and os.path.exists(model):
442
+ print("loading model...")
443
  checkpoint = torch.load(model, map_location=self.device)
444
  self.sp.Load(checkpoint['spm_model_path'])
445
  self.vocab_size = self.sp.GetPieceSize()
 
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")
460
  with tempfile.NamedTemporaryFile(mode="w", encoding="utf8", delete=False) as temp_file:
461
  for group in train_lazy_data:
462
  for sentence in group:
 
466
  temp_dir = tempfile.mkdtemp()
467
  temp_spm_prefix = os.path.join(temp_dir, "spm")
468
  try:
469
+ print("training sentence piece (could take a while on massive datasets)")
470
+ print("Also you will get some log spamming from it cause it won't shut up")
471
  spm.SentencePieceTrainer.Train(
472
  input=temp_dataset_path,
473
  model_prefix=temp_spm_prefix,
 
501
  lr=learning_rate, weight_decay=weight_decay)
502
  scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=num_epochs)
503
  criterion = nn.CrossEntropyLoss(ignore_index=self.sp.pad_id())
504
+ scaler = GradScaler('cuda')
505
 
506
  best_val_loss = float('inf')
507
  patience_counter = 0
508
 
509
  print("Beginning training")
510
  for epoch in range(num_epochs):
 
 
511
  total_train_loss = 0.0
512
+ num_train_batches = (len(train_lazy_data) + batch_size - 1) // batch_size
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
 
 
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
  with torch.no_grad():
564
+ for i in range(0, len(test_lazy_data), batch_size):
565
+ raw_batch = test_lazy_data[i:i + batch_size]
 
566
  tokenized_batch = [
567
  [[self.sp.bos_id()] + self.sp.EncodeAsIds(s) + [self.sp.eos_id()] for s in group]
568
  for group in raw_batch
 
577
  output_logits = self.decoder(thought_vectors, group_tensor[:, :-1])
578
  val_loss = criterion(output_logits.reshape(-1, self.vocab_size),
579
  group_tensor[:, 1:].reshape(-1))
580
+ val_loss += length_penalty * thought_vectors.shape[1]
581
  batch_val_loss += val_loss.item()
582
  total_val_loss += batch_val_loss
583
+ print(f"VAL batch loss: {batch_val_loss:.4f}")
584
+ print(f" Input: {self.sp.DecodeIds(group_tensor[0].tolist())}")
585
+ print(f"Output: {self.sp.DecodeIds(output_logits.argmax(-1)[0].tolist())}\n\n")
586
  avg_val_loss = total_val_loss / num_val_batches if num_val_batches > 0 else float('inf')
587
  else:
588
  avg_val_loss = avg_train_loss
589
 
590
+ print(f"Epoch {epoch + 1}/{num_epochs} - Train Loss: {avg_train_loss:.4f} - Val Loss: {avg_val_loss:.4f}\n\n")
591
 
592
  if avg_val_loss < best_val_loss:
593
  best_val_loss = avg_val_loss
 
628
 
629
  return self.encoder(input_tokens, force_single_vector)
630
 
631
+ def decode(self, thought_vectors: torch.Tensor, max_length: int = 50, beam_width: int = 0,
632
  temperature: float = 1.0) -> List[str]:
633
  """Decodes thought vectors into text sequences.
634
 
635
  Args:
636
  thought_vectors (torch.Tensor): Thought vectors, shape (batch_size, num_thoughts, d_model).
637
  max_length (int, optional): Maximum length of generated sequences. Defaults to 50.
638
+ beam_width (Optional[int], optional): Beam width for beam search; if 0, uses greedy
639
  decoding. Defaults to 5.
640
  temperature (float, optional): Temperature for softmax sampling in greedy decoding.
641
  Defaults to 1.0.
 
649
  thought_vectors = thought_vectors.to(self.device)
650
  batch_size = thought_vectors.size(0)
651
 
652
+ if beam_width > 1:
653
  return self._beam_search_decode(thought_vectors, max_length, beam_width)
654
 
655
  target_tokens = torch.full((batch_size, 1), self.sp.bos_id(), dtype=torch.long, device=self.device)
656
  for _ in range(max_length - 1):
657
  logits = self.decoder(thought_vectors, target_tokens)
658
  logits = logits[:, -1, :] / temperature
659
+
660
  next_token = logits.softmax(dim=-1).multinomial(1)
661
  target_tokens = torch.cat([target_tokens, next_token], dim=1)
662
  if (next_token == self.sp.eos_id()).all():
 
705
  results = []
706
  for i in range(batch_size):
707
  combined = sorted(finished[i] + beams[i], key=lambda x: x[0])
708
+ results.append(self.sp.DecodeIds(combined[0][1].squeeze(0).tolist()) if combined else self.sp.DecodeIds(
709
+ beams[i][0][1].squeeze(0).tolist()))
710
 
711
  return results
712
 
 
760
  ThoughtVectors: Loaded model instance.
761
  """
762
  translator = cls()
763
+ translator.device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # load based on available device, not model train device
764
  try:
765
  with tarfile.open(path, "r") as tar:
766
  tar.extractall()
767
+ checkpoint = torch.load("model.pth", map_location=torch.device(translator.device))
768
  translator.sp = spm.SentencePieceProcessor()
769
  if not translator.sp.Load("spm.model"):
770
  raise RuntimeError("Failed to load SentencePiece model.")
 
783
  translator.dropout = checkpoint['dropout']
784
  translator.max_len = checkpoint['max_len']
785
  translator.termination_threshold = checkpoint['termination_threshold']
786
+
787
 
788
  translator.encoder = ThoughtEncoder(
789
  vocab_size=translator.vocab_size, d_model=translator.d_model, max_thoughts=translator.max_thoughts,
 
802
 
803
 
804
  if __name__ == "__main__":
 
805
  tv = ThoughtVectors()
806
  tv.train(
807
+ group_data="train.csv",
808
+ test_data="val.csv",
809
  num_epochs=1000,
810
+ batch_size=128,
811
+ accum_steps=1,
812
+ learning_rate=5e-4,
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",
 
819
  d_model=512,
820
  encoder_nhead=8,
821
  decoder_nhead=8,
822
+ encoder_layers=4,
823
+ decoder_layers=4,
824
+ max_thoughts=16,
825
  dropout=0.1,
826
+ max_len=256,
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)
834
  print(f"Greedy decoding: {generated_text_greedy}")
835
  print(f"Beam search decoding: {generated_text_beam}")
836