zeguru commited on
Commit
972b71a
·
verified ·
1 Parent(s): 137f7ef

Upload folder using huggingface_hub

Browse files
app.py CHANGED
@@ -12,7 +12,7 @@ from src.task.inference.classify import TextClassifier
12
 
13
  # Paths
14
  # DATA_PATH = Path("data/tiny_shakespear.txt")
15
- GENERATOR_MODEL_PATH = Path("checkpoints/mh_tiny_text_generator.pt")
16
 
17
  CLASSIFIER_MODEL_PATH = Path(
18
  "checkpoints/mh_tiny_text_classifier.pt"
@@ -22,31 +22,22 @@ CLASSIFIER_TOKENIZER_PATH = Path(
22
  "checkpoints/ag_news_tokenizer.json"
23
  )
24
 
25
- # Model config
26
- config = ModelConfig()
27
- config.number_of_heads = 2
28
-
29
- # Tokenizer: in future use a reusable vocab instead of loading the entire corpus
30
- # text = DATA_PATH.read_text(encoding="utf-8",)
31
- # tokenizer = CharacterTokenizer(text)
32
 
33
  TEXT_TOKENIZER_PATH = Path("checkpoints/shakespeare_tokenizer.json")
34
  tokenizer = CharacterTokenizer.load(TEXT_TOKENIZER_PATH)
35
 
36
- # Recreate the generator model
37
- config.number_of_heads = 2
38
  model = load_model(
39
  checkpoint_path=GENERATOR_MODEL_PATH,
40
- config=config,
41
  vocab_size=tokenizer.vocab_size,
42
  )
43
 
44
-
45
- # A. Generator
46
  text_generator = TextGenerator(
47
  model=model,
48
  tokenizer=tokenizer,
49
- context_length=config.context_length,
50
  )
51
 
52
  # Text Generation
@@ -68,18 +59,18 @@ def generate_text(
68
  # B. Classifier
69
  classifier_tokenizer = CharacterTokenizer.load(CLASSIFIER_TOKENIZER_PATH)
70
 
71
- config.context_length = 384
72
- config.number_of_heads = 2
73
  classifier_model = load_classifier_model(
74
  checkpoint_path=CLASSIFIER_MODEL_PATH,
75
- config=config,
76
  vocab_size=classifier_tokenizer.vocab_size,
77
  )
78
 
79
  text_classifier = TextClassifier(
80
  model=classifier_model,
81
  tokenizer=classifier_tokenizer,
82
- context_length=config.context_length,
83
  )
84
 
85
  CLASS_NAMES = [
 
12
 
13
  # Paths
14
  # DATA_PATH = Path("data/tiny_shakespear.txt")
15
+ GENERATOR_MODEL_PATH = Path("checkpoints/tiny_poet.pt")
16
 
17
  CLASSIFIER_MODEL_PATH = Path(
18
  "checkpoints/mh_tiny_text_classifier.pt"
 
22
  "checkpoints/ag_news_tokenizer.json"
23
  )
24
 
 
 
 
 
 
 
 
25
 
26
  TEXT_TOKENIZER_PATH = Path("checkpoints/shakespeare_tokenizer.json")
27
  tokenizer = CharacterTokenizer.load(TEXT_TOKENIZER_PATH)
28
 
29
+ generator_config = ModelConfig(context_length=128, d_model=128, d_ff=512, num_layers=4, number_of_heads=4)
30
+
31
  model = load_model(
32
  checkpoint_path=GENERATOR_MODEL_PATH,
33
+ config=generator_config,
34
  vocab_size=tokenizer.vocab_size,
35
  )
36
 
 
 
37
  text_generator = TextGenerator(
38
  model=model,
39
  tokenizer=tokenizer,
40
+ context_length=generator_config.context_length,
41
  )
42
 
43
  # Text Generation
 
59
  # B. Classifier
60
  classifier_tokenizer = CharacterTokenizer.load(CLASSIFIER_TOKENIZER_PATH)
61
 
62
+ classifier_config = ModelConfig(context_length=384, d_model=64, d_ff=256, num_layers=2)
63
+
64
  classifier_model = load_classifier_model(
65
  checkpoint_path=CLASSIFIER_MODEL_PATH,
66
+ config=classifier_config,
67
  vocab_size=classifier_tokenizer.vocab_size,
68
  )
69
 
70
  text_classifier = TextClassifier(
71
  model=classifier_model,
72
  tokenizer=classifier_tokenizer,
73
+ context_length=classifier_config.context_length,
74
  )
75
 
76
  CLASS_NAMES = [
checkpoints/tiny_poet.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ae86a4a481806e36be89c8fb79ec7d879a822673f07926eb6f80cf40b211b597
3
+ size 3389619
data/tinystories_300k.txt ADDED
The diff for this file is too large to render. See raw diff
 
notebooks/.ipynb_checkpoints/Untitled-checkpoint.ipynb ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [],
3
+ "metadata": {},
4
+ "nbformat": 4,
5
+ "nbformat_minor": 5
6
+ }
notebooks/.ipynb_checkpoints/attention-visualizer-checkpoint.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
notebooks/.ipynb_checkpoints/training-text-generator-checkpoint.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
notebooks/attention-visualizer.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
notebooks/checkpoints/poet_take1.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a46f5ae3aa75742aa57608d71df5756e9b129d2940e650c45092f1447df5fd7a
3
+ size 470389
notebooks/training-text-generator.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
pyproject.toml CHANGED
@@ -3,8 +3,16 @@ name = "tiny-text-transformer"
3
  version = "0.1.0"
4
  requires-python = ">=3.14"
5
  dependencies = [
 
6
  "gradio>=6.26.0",
 
7
  "numpy>=2.5.2",
8
  "spaces>=0.51.2",
9
  "torch>=2.13.0",
10
  ]
 
 
 
 
 
 
 
3
  version = "0.1.0"
4
  requires-python = ">=3.14"
5
  dependencies = [
6
+ "datasets>=5.0.1",
7
  "gradio>=6.26.0",
8
+ "matplotlib>=3.11.2",
9
  "numpy>=2.5.2",
10
  "spaces>=0.51.2",
11
  "torch>=2.13.0",
12
  ]
13
+
14
+ [dependency-groups]
15
+ dev = [
16
+ "ipykernel>=7.3.0",
17
+ "jupyterlab>=4.6.3",
18
+ ]
scripts/.ipynb_checkpoints/train_classifier-checkpoint.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+
3
+ import torch
4
+
5
+ from src.infra.dataset.classification import TextClassificationDataset
6
+ from src.infra.dataset.util import split_tokens, get_batch, build_label, build_text
7
+ from src.infra.tokenizer import CharacterTokenizer
8
+ from src.infra.dataset.autoregressive import AutoRegressiveDataset
9
+
10
+ from src.task.config import ModelConfig,TrainingConfig
11
+
12
+ from src.task.model import TinyTransformerLM, TinyClassifier
13
+ from src.task.training.classification import train
14
+ import pandas as pd
15
+ import numpy as np
16
+ from src.task.training.util import TrainingLogger, count_parameters, separator
17
+
18
+
19
+
20
+ # Custom Logger
21
+ logger = TrainingLogger(
22
+ "logs/text_classifier.log"
23
+ )
24
+
25
+
26
+ # Configs
27
+ separator("Configuration")
28
+
29
+ torch.manual_seed(42)
30
+ # Configs
31
+ model_config = ModelConfig()
32
+ training_config = TrainingConfig()
33
+
34
+ # Overrides
35
+ model_config.context_length = 384
36
+ model_config.number_of_heads = 2
37
+
38
+ training_config.num_steps = 10
39
+ training_config.eval_interval = 1
40
+ training_config.num_train_samples = None
41
+
42
+ logger.log(model_config)
43
+ logger.log(training_config)
44
+
45
+ # Load the corpus
46
+ separator("Corpus")
47
+
48
+ TRAIN_PATH = Path("data/ag-news/train.csv")
49
+ TEST_PATH = Path("data/ag-news/test.csv")
50
+ checkpoint = "mh_tiny_text_classifier.pt"
51
+
52
+ if not TRAIN_PATH.exists():
53
+ raise FileNotFoundError(f"Training file not found: {TRAIN_PATH}")
54
+
55
+ if not TEST_PATH.exists():
56
+ raise FileNotFoundError(f"Test file not found: {TEST_PATH}")
57
+
58
+ separator("Load corpus")
59
+
60
+ train_corpus = pd.read_csv(TRAIN_PATH)
61
+ if training_config.num_train_samples is not None:
62
+ train_corpus = train_corpus.head(training_config.num_train_samples)
63
+
64
+ test_corpus = pd.read_csv(TEST_PATH)
65
+
66
+ train_text = build_text(train_corpus)
67
+ test_text = build_text(test_corpus)
68
+
69
+ train_labels = build_label(train_corpus)
70
+ test_labels = build_label(test_corpus)
71
+
72
+
73
+ # Tokens
74
+ separator("Tokenization")
75
+
76
+ tokenizer = CharacterTokenizer("".join(train_text))
77
+
78
+ CLASS_TOKENIZER_PATH = Path("checkpoints/ag_news_tokenizer.json")
79
+ tokenizer.save(CLASS_TOKENIZER_PATH)
80
+
81
+ vocab_size = tokenizer.vocab_size
82
+ print(f"Vocab size: {vocab_size}")
83
+
84
+ # Datasets
85
+ separator("Datasets")
86
+
87
+ train_dataset = TextClassificationDataset(
88
+ texts=train_text,
89
+ labels=train_labels,
90
+ tokenizer=tokenizer,
91
+ max_length=model_config.context_length
92
+ )
93
+
94
+ val_dataset = TextClassificationDataset(
95
+ texts=test_text,
96
+ labels=test_labels,
97
+ tokenizer=tokenizer,
98
+ max_length=model_config.context_length
99
+ )
100
+
101
+ print(f"Train examples: {len(train_dataset):,}")
102
+
103
+ # Models
104
+ separator("Transformer")
105
+
106
+ model = TinyClassifier(
107
+ config=model_config,
108
+ vocab_size=tokenizer.vocab_size,
109
+ num_classes=4,
110
+ )
111
+
112
+ print(model)
113
+
114
+
115
+ # Train........
116
+ separator("Training")
117
+
118
+ train(
119
+ model=model,
120
+ train_dataset=train_dataset,
121
+ val_dataset=val_dataset,
122
+ training_config=training_config,
123
+ )
124
+
125
+
126
+ separator("Saving")
127
+
128
+ checkpoint_dir = Path("checkpoints")
129
+ checkpoint_dir.mkdir(parents=True, exist_ok=True)
130
+
131
+ checkpoint_path = (
132
+ checkpoint_dir / checkpoint
133
+ )
134
+
135
+ torch.save(
136
+ model.state_dict(),
137
+ checkpoint_path,
138
+ )
139
+
140
+ print(f"Checkpoint saved to: {checkpoint_path}")
scripts/generate_text.py CHANGED
@@ -8,7 +8,7 @@ from src.task.inference.inference import TextGenerator
8
 
9
  # Runtime configs
10
 
11
- checkpoint = "checkpoints/mh_tiny_text_generator.pt"
12
 
13
  TEXT_TOKENIZER_PATH = Path("checkpoints/shakespeare_tokenizer.json")
14
  tokenizer = CharacterTokenizer.load(
@@ -17,14 +17,13 @@ tokenizer = CharacterTokenizer.load(
17
 
18
  # Conf
19
 
20
- config = ModelConfig()
21
- config.number_of_heads = 2
22
 
23
 
24
  # Load model/checkpoint from file
25
  model = load_model(
26
  checkpoint_path=checkpoint,
27
- config=config,
28
  vocab_size=tokenizer.vocab_size,
29
  )
30
 
@@ -33,7 +32,7 @@ model = load_model(
33
  text_generator = TextGenerator(
34
  model=model,
35
  tokenizer=tokenizer,
36
- context_length=config.context_length,
37
  )
38
 
39
 
 
8
 
9
  # Runtime configs
10
 
11
+ checkpoint = "checkpoints/tiny_poet.pt"
12
 
13
  TEXT_TOKENIZER_PATH = Path("checkpoints/shakespeare_tokenizer.json")
14
  tokenizer = CharacterTokenizer.load(
 
17
 
18
  # Conf
19
 
20
+ generator_config = ModelConfig(context_length=128, d_model=128, d_ff=512, num_layers=4, number_of_heads=4)
 
21
 
22
 
23
  # Load model/checkpoint from file
24
  model = load_model(
25
  checkpoint_path=checkpoint,
26
+ config=generator_config,
27
  vocab_size=tokenizer.vocab_size,
28
  )
29
 
 
32
  text_generator = TextGenerator(
33
  model=model,
34
  tokenizer=tokenizer,
35
+ context_length=generator_config.context_length,
36
  )
37
 
38
 
scripts/train_generator.py CHANGED
@@ -29,10 +29,10 @@ separator("Configuration")
29
  torch.manual_seed(42)
30
 
31
  # Configs
32
- model_config = ModelConfig()
 
33
  training_config = TrainingConfig()
34
  # Overrides
35
- model_config.number_of_heads = 2
36
  training_config.num_steps = 10000
37
  training_config.eval_interval = 1000
38
 
@@ -119,14 +119,20 @@ logger.log(model)
119
  # Train........
120
  separator("Training")
121
 
122
- train(
 
 
 
 
 
 
 
123
  model=model,
124
  train_dataset=train_dataset,
125
  val_dataset=val_dataset,
126
  training_config=training_config,
127
  )
128
 
129
-
130
  # Final test evaluation
131
  separator("Test Evaluation")
132
 
 
29
  torch.manual_seed(42)
30
 
31
  # Configs
32
+ model_config = ModelConfig(context_length=128, d_model=128, d_ff=512, num_layers=4, number_of_heads=4)
33
+
34
  training_config = TrainingConfig()
35
  # Overrides
 
36
  training_config.num_steps = 10000
37
  training_config.eval_interval = 1000
38
 
 
119
  # Train........
120
  separator("Training")
121
 
122
+ # train(
123
+ # model=model,
124
+ # train_dataset=train_dataset,
125
+ # val_dataset=val_dataset,
126
+ # training_config=training_config,
127
+ # )
128
+
129
+ model, steps, train_history, val_history = train(
130
  model=model,
131
  train_dataset=train_dataset,
132
  val_dataset=val_dataset,
133
  training_config=training_config,
134
  )
135
 
 
136
  # Final test evaluation
137
  separator("Test Evaluation")
138
 
src/infra/dataset/util.py CHANGED
@@ -10,7 +10,7 @@ def split_tokens(
10
  tokens: torch.Tensor,
11
  train_ratio: float = 0.90,
12
  val_ratio: float = 0.05,
13
- ) -> tuple[
14
  torch.Tensor,
15
  torch.Tensor,
16
  torch.Tensor,
 
10
  tokens: torch.Tensor,
11
  train_ratio: float = 0.90,
12
  val_ratio: float = 0.05,
13
+ ) -> tuple[
14
  torch.Tensor,
15
  torch.Tensor,
16
  torch.Tensor,
src/infra/tokenizer.py CHANGED
@@ -50,7 +50,15 @@ class CharacterTokenizer:
50
  for token_id in token_ids
51
  if token_id != self.pad_token_id
52
  )
53
-
 
 
 
 
 
 
 
 
54
  def pad(
55
  self,
56
  sequences,
 
50
  for token_id in token_ids
51
  if token_id != self.pad_token_id
52
  )
53
+
54
+ #do not assume tokenids are python integerser
55
+ # def decode(self, token_ids):
56
+ # return "".join(
57
+ # self.itos[int(token_id)]
58
+ # for token_id in token_ids
59
+ # if int(token_id) != self.pad_token_id
60
+ # )
61
+
62
  def pad(
63
  self,
64
  sequences,
src/task/config.py CHANGED
@@ -8,7 +8,7 @@ class ModelConfig:
8
  d_model: int = 64 #model dim
9
  d_ff: int = 256 #feed forward dim
10
  num_layers: int = 2 #transformer blocks
11
- number_of_heads: int = 1
12
  dropout: float = 0.1 #percent. avoid overfitting, break emerging biases
13
 
14
 
 
8
  d_model: int = 64 #model dim
9
  d_ff: int = 256 #feed forward dim
10
  num_layers: int = 2 #transformer blocks
11
+ number_of_heads: int = 2
12
  dropout: float = 0.1 #percent. avoid overfitting, break emerging biases
13
 
14
 
src/task/training/autoregressive.py CHANGED
@@ -21,6 +21,10 @@ def train(
21
  lr=training_config.learning_rate,
22
  )
23
 
 
 
 
 
24
  model.train()
25
 
26
  for step in range(training_config.num_steps):
@@ -39,6 +43,10 @@ def train(
39
  training_config=training_config,
40
  )
41
 
 
 
 
 
42
  print(
43
  f"step {step:4d} | "
44
  f"train {train_loss:.4f} | "
@@ -61,7 +69,8 @@ def train(
61
  loss.backward()
62
  optimizer.step()
63
 
64
- return model
 
65
 
66
 
67
  @torch.no_grad() #do not calculate gradients
 
21
  lr=training_config.learning_rate,
22
  )
23
 
24
+ train_history = []
25
+ val_history = []
26
+ steps = []
27
+
28
  model.train()
29
 
30
  for step in range(training_config.num_steps):
 
43
  training_config=training_config,
44
  )
45
 
46
+ steps.append(step)
47
+ train_history.append(train_loss)
48
+ val_history.append(val_loss)
49
+
50
  print(
51
  f"step {step:4d} | "
52
  f"train {train_loss:.4f} | "
 
69
  loss.backward()
70
  optimizer.step()
71
 
72
+ #return model
73
+ return model, steps, train_history, val_history
74
 
75
 
76
  @torch.no_grad() #do not calculate gradients
uv.lock CHANGED
The diff for this file is too large to render. See raw diff