zyoralabs commited on
Commit
4e45e39
·
verified ·
1 Parent(s): 70fb07f

Upload folder using huggingface_hub

Browse files
README.md ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ language:
4
+ - en
5
+ - ta
6
+ - hi
7
+ pipeline_tag: text-generation
8
+ tags:
9
+ - education
10
+ - academic
11
+ - concept-first
12
+ - india
13
+ - from-scratch
14
+ ---
15
+
16
+ # AQ-1B — Academic Quotient v1 (Base)
17
+
18
+ **AQ (Academic Quotient) — India's Concept-First Academic AI.**
19
+ *Raising the Academic Quotient of every student.*
20
+
21
+ AQ-1B is a **1.26B-parameter foundation model built completely from scratch** by Zyora Labs — proprietary architecture, own training code (pure PyTorch), own tokenizer, own data pipeline. No fine-tune of any existing model.
22
+
23
+ It is trained **concept-first**: the model learns the *concepts* of mathematics, physics, chemistry, biology, engineering, history, geography, civics and economics — from foundations to advanced — rather than curriculum checklists.
24
+
25
+ ## Highlights
26
+
27
+ - **From scratch, end to end** — architecture, tokenizer (32k byte-level BPE), training loop, and data pipeline all built in-house
28
+ - **20B tokens** of knowledge-dense pretraining: encyclopedic text, real textbooks and course notes, scientific papers, and mathematical reasoning corpora
29
+ - **Final quality anneal** — the last 1.5B tokens use only the highest-quality sources (textbooks, course material, scientific papers, encyclopedic facts) with learning rate annealed to zero
30
+ - **Tamil + Hindi inclusive** — trained with native Tamil and Hindi text alongside English
31
+ - **Progressive growth training** — grown and continually trained through 75M → 300M → 1.26B parameter stages, each stage inheriting the previous stage's knowledge
32
+
33
+ ## Architecture (proprietary, from scratch)
34
+
35
+ | | |
36
+ |---|---|
37
+ | Parameters | 1.26B |
38
+ | Layers | 48 |
39
+ | Hidden size | 1536 |
40
+ | Attention heads | 24 (grouped-query, 8 KV heads) |
41
+ | Feed-forward | SwiGLU, 4096 |
42
+ | Positional encoding | Rotary (RoPE) |
43
+ | Normalization | RMSNorm |
44
+ | Context length | 2048 |
45
+ | Vocabulary | 32,000 (byte-level BPE, English + Tamil + Hindi) |
46
+ | Embeddings | Tied |
47
+
48
+ ## Usage
49
+
50
+ ```python
51
+ from transformers import AutoModelForCausalLM, AutoTokenizer
52
+
53
+ tok = AutoTokenizer.from_pretrained("zyoralabs/AQ-academic-ai")
54
+ model = AutoModelForCausalLM.from_pretrained("zyoralabs/AQ-academic-ai", trust_remote_code=True)
55
+
56
+ ids = tok("Photosynthesis is the process", return_tensors="pt").input_ids
57
+ out = model.generate(ids, max_new_tokens=60)
58
+ print(tok.decode(out[0]))
59
+ ```
60
+
61
+ ## Intended use
62
+
63
+ AQ-1B is a **base (pretrained) model** — the foundation of the AQ educator stack (instruct tuning, retrieval grounding, and the AQ Playground sit on top of it). As a raw base model it predicts text continuations; it is not yet instruction-tuned.
64
+
65
+ ## Team
66
+
67
+ | Name | Role | Affiliation |
68
+ |---|---|---|
69
+ | **Vasanth** | Chief AI Researcher | Zyora Labs |
70
+ | **Adithi Sreedhar** | Jr AI Engineer | AI & DS, Arunachala College of Engineering for Women |
71
+
72
+ ## About
73
+
74
+ Built in India by [Zyora Labs](https://zyora.in). AQ v1 is the first release of the Academic Quotient model family.
config.json ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "AQForCausalLM"
4
+ ],
5
+ "auto_map": {
6
+ "AutoConfig": "configuration_aq.AQConfig",
7
+ "AutoModelForCausalLM": "modeling_aq.AQForCausalLM"
8
+ },
9
+ "bos_token_id": 0,
10
+ "eos_token_id": 0,
11
+ "head_dim": 64,
12
+ "hidden_size": 1536,
13
+ "intermediate_size": 4096,
14
+ "max_position_embeddings": 2048,
15
+ "model_type": "aq",
16
+ "num_attention_heads": 24,
17
+ "num_hidden_layers": 48,
18
+ "num_key_value_heads": 8,
19
+ "pad_token_id": 0,
20
+ "rms_norm_eps": 1e-05,
21
+ "rope_theta": 10000.0,
22
+ "torch_dtype": "bfloat16",
23
+ "transformers_version": "4.53.0",
24
+ "vocab_size": 32000
25
+ }
configuration_aq.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """AQ model configuration.
2
+
3
+ AQ (Academic Quotient) — Zyora Labs' proprietary, from-scratch decoder
4
+ architecture: RMSNorm, rotary position embeddings, grouped-query attention,
5
+ SwiGLU feed-forward, tied embeddings.
6
+ """
7
+
8
+ from transformers import PretrainedConfig
9
+
10
+
11
+ class AQConfig(PretrainedConfig):
12
+ model_type = "aq"
13
+
14
+ def __init__(
15
+ self,
16
+ vocab_size: int = 32000,
17
+ hidden_size: int = 1536,
18
+ intermediate_size: int = 4096,
19
+ num_hidden_layers: int = 48,
20
+ num_attention_heads: int = 24,
21
+ num_key_value_heads: int = 8,
22
+ head_dim: int = 64,
23
+ max_position_embeddings: int = 2048,
24
+ rope_theta: float = 10000.0,
25
+ rms_norm_eps: float = 1e-5,
26
+ tie_word_embeddings: bool = True,
27
+ bos_token_id: int = 0,
28
+ eos_token_id: int = 0,
29
+ pad_token_id: int = 0,
30
+ **kwargs,
31
+ ):
32
+ self.vocab_size = vocab_size
33
+ self.hidden_size = hidden_size
34
+ self.intermediate_size = intermediate_size
35
+ self.num_hidden_layers = num_hidden_layers
36
+ self.num_attention_heads = num_attention_heads
37
+ self.num_key_value_heads = num_key_value_heads
38
+ self.head_dim = head_dim
39
+ self.max_position_embeddings = max_position_embeddings
40
+ self.rope_theta = rope_theta
41
+ self.rms_norm_eps = rms_norm_eps
42
+ super().__init__(
43
+ tie_word_embeddings=tie_word_embeddings,
44
+ bos_token_id=bos_token_id,
45
+ eos_token_id=eos_token_id,
46
+ pad_token_id=pad_token_id,
47
+ **kwargs,
48
+ )
generation_config.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 0,
4
+ "eos_token_id": 0,
5
+ "pad_token_id": 0,
6
+ "transformers_version": "4.53.0"
7
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cfb954c76b28c488b9ac8980f0f9e06edd99ae5536cb727ea2ec87cb4e03e436
3
+ size 2514566480
modeling_aq.py ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """AQ modeling code — Zyora Labs' proprietary, from-scratch decoder architecture.
2
+
3
+ AQ (Academic Quotient) is a concept-first academic language model built from
4
+ scratch in pure PyTorch. Architecture: RMSNorm, rotary position embeddings
5
+ (RoPE), grouped-query attention (GQA), SwiGLU feed-forward, tied embeddings.
6
+
7
+ Module names intentionally mirror the original AQ training code, so trained
8
+ checkpoints load 1:1 with no key remapping.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from typing import Optional
14
+
15
+ import torch
16
+ import torch.nn as nn
17
+ import torch.nn.functional as F
18
+ from transformers import PreTrainedModel
19
+ from transformers.generation import GenerationMixin
20
+ from transformers.modeling_outputs import CausalLMOutput
21
+
22
+ from configuration_aq import AQConfig
23
+
24
+
25
+ class AQRMSNorm(nn.Module):
26
+ def __init__(self, dim: int, eps: float = 1e-5):
27
+ super().__init__()
28
+ self.eps = eps
29
+ self.weight = nn.Parameter(torch.ones(dim))
30
+
31
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
32
+ dtype = x.dtype
33
+ x = x.float()
34
+ x = x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)
35
+ return (x.to(dtype)) * self.weight
36
+
37
+
38
+ def build_rope_cache(seq_len: int, head_dim: int, theta: float, device):
39
+ inv_freq = 1.0 / (theta ** (torch.arange(0, head_dim, 2, device=device).float() / head_dim))
40
+ t = torch.arange(seq_len, device=device).float()
41
+ freqs = torch.outer(t, inv_freq)
42
+ emb = torch.cat((freqs, freqs), dim=-1)
43
+ return emb.cos(), emb.sin()
44
+
45
+
46
+ def rotate_half(x: torch.Tensor) -> torch.Tensor:
47
+ x1, x2 = x.chunk(2, dim=-1)
48
+ return torch.cat((-x2, x1), dim=-1)
49
+
50
+
51
+ def apply_rope(q, k, cos, sin):
52
+ cos = cos.unsqueeze(0).unsqueeze(0)
53
+ sin = sin.unsqueeze(0).unsqueeze(0)
54
+ q = (q * cos) + (rotate_half(q) * sin)
55
+ k = (k * cos) + (rotate_half(k) * sin)
56
+ return q, k
57
+
58
+
59
+ class AQAttention(nn.Module):
60
+ def __init__(self, cfg: AQConfig):
61
+ super().__init__()
62
+ self.n_heads = cfg.num_attention_heads
63
+ self.n_kv = cfg.num_key_value_heads
64
+ self.head_dim = cfg.head_dim
65
+ self.n_rep = self.n_heads // self.n_kv
66
+
67
+ self.q_proj = nn.Linear(cfg.hidden_size, self.n_heads * self.head_dim, bias=False)
68
+ self.k_proj = nn.Linear(cfg.hidden_size, self.n_kv * self.head_dim, bias=False)
69
+ self.v_proj = nn.Linear(cfg.hidden_size, self.n_kv * self.head_dim, bias=False)
70
+ self.o_proj = nn.Linear(self.n_heads * self.head_dim, cfg.hidden_size, bias=False)
71
+
72
+ def forward(self, x, cos, sin, attn_mask: Optional[torch.Tensor] = None):
73
+ B, T, _ = x.shape
74
+ q = self.q_proj(x).view(B, T, self.n_heads, self.head_dim).transpose(1, 2)
75
+ k = self.k_proj(x).view(B, T, self.n_kv, self.head_dim).transpose(1, 2)
76
+ v = self.v_proj(x).view(B, T, self.n_kv, self.head_dim).transpose(1, 2)
77
+
78
+ q, k = apply_rope(q, k, cos, sin)
79
+
80
+ k = k.repeat_interleave(self.n_rep, dim=1)
81
+ v = v.repeat_interleave(self.n_rep, dim=1)
82
+
83
+ if attn_mask is not None:
84
+ out = F.scaled_dot_product_attention(q, k, v, attn_mask=attn_mask)
85
+ else:
86
+ out = F.scaled_dot_product_attention(q, k, v, is_causal=True)
87
+ out = out.transpose(1, 2).contiguous().view(B, T, -1)
88
+ return self.o_proj(out)
89
+
90
+
91
+ class AQSwiGLU(nn.Module):
92
+ def __init__(self, cfg: AQConfig):
93
+ super().__init__()
94
+ self.gate_proj = nn.Linear(cfg.hidden_size, cfg.intermediate_size, bias=False)
95
+ self.up_proj = nn.Linear(cfg.hidden_size, cfg.intermediate_size, bias=False)
96
+ self.down_proj = nn.Linear(cfg.intermediate_size, cfg.hidden_size, bias=False)
97
+
98
+ def forward(self, x):
99
+ return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))
100
+
101
+
102
+ class AQBlock(nn.Module):
103
+ def __init__(self, cfg: AQConfig):
104
+ super().__init__()
105
+ self.attn_norm = AQRMSNorm(cfg.hidden_size, cfg.rms_norm_eps)
106
+ self.attn = AQAttention(cfg)
107
+ self.mlp_norm = AQRMSNorm(cfg.hidden_size, cfg.rms_norm_eps)
108
+ self.mlp = AQSwiGLU(cfg)
109
+
110
+ def forward(self, x, cos, sin, attn_mask=None):
111
+ x = x + self.attn(self.attn_norm(x), cos, sin, attn_mask)
112
+ x = x + self.mlp(self.mlp_norm(x))
113
+ return x
114
+
115
+
116
+ class AQPreTrainedModel(PreTrainedModel):
117
+ config_class = AQConfig
118
+ base_model_prefix = "aq"
119
+ supports_gradient_checkpointing = False
120
+ _no_split_modules = ["AQBlock"]
121
+
122
+ def _init_weights(self, module):
123
+ if isinstance(module, nn.Linear):
124
+ nn.init.normal_(module.weight, mean=0.0, std=0.02)
125
+ elif isinstance(module, nn.Embedding):
126
+ nn.init.normal_(module.weight, mean=0.0, std=0.02)
127
+
128
+
129
+ class AQForCausalLM(AQPreTrainedModel, GenerationMixin):
130
+ """AQ decoder language model with a causal LM head (tied embeddings)."""
131
+
132
+ _tied_weights_keys = ["lm_head.weight"]
133
+
134
+ def __init__(self, config: AQConfig):
135
+ super().__init__(config)
136
+ self.embed = nn.Embedding(config.vocab_size, config.hidden_size)
137
+ self.layers = nn.ModuleList([AQBlock(config) for _ in range(config.num_hidden_layers)])
138
+ self.norm = AQRMSNorm(config.hidden_size, config.rms_norm_eps)
139
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
140
+
141
+ cos, sin = build_rope_cache(
142
+ config.max_position_embeddings, config.head_dim, config.rope_theta, "cpu")
143
+ self.register_buffer("rope_cos", cos, persistent=False)
144
+ self.register_buffer("rope_sin", sin, persistent=False)
145
+
146
+ self.post_init() # weight init + embedding tying (config.tie_word_embeddings)
147
+
148
+ def get_input_embeddings(self):
149
+ return self.embed
150
+
151
+ def set_input_embeddings(self, value):
152
+ self.embed = value
153
+
154
+ def get_output_embeddings(self):
155
+ return self.lm_head
156
+
157
+ def set_output_embeddings(self, new_embeddings):
158
+ self.lm_head = new_embeddings
159
+
160
+ def forward(
161
+ self,
162
+ input_ids: torch.LongTensor,
163
+ attention_mask: Optional[torch.Tensor] = None,
164
+ labels: Optional[torch.LongTensor] = None,
165
+ **kwargs,
166
+ ) -> CausalLMOutput:
167
+ B, T = input_ids.shape
168
+ cos = self.rope_cos[:T].to(input_ids.device)
169
+ sin = self.rope_sin[:T].to(input_ids.device)
170
+
171
+ # Combined causal + padding mask (only when padding is actually present).
172
+ attn_mask = None
173
+ if attention_mask is not None and not bool(attention_mask.all()):
174
+ causal = torch.tril(torch.ones(T, T, dtype=torch.bool, device=input_ids.device))
175
+ pad = attention_mask[:, None, None, :].to(torch.bool) # (B,1,1,T)
176
+ attn_mask = causal[None, None, :, :] & pad
177
+
178
+ x = self.embed(input_ids)
179
+ for layer in self.layers:
180
+ x = layer(x, cos, sin, attn_mask)
181
+ x = self.norm(x)
182
+ logits = self.lm_head(x)
183
+
184
+ loss = None
185
+ if labels is not None:
186
+ shift_logits = logits[:, :-1, :].contiguous()
187
+ shift_labels = labels[:, 1:].contiguous()
188
+ loss = F.cross_entropy(
189
+ shift_logits.view(-1, shift_logits.size(-1)),
190
+ shift_labels.view(-1),
191
+ ignore_index=-100,
192
+ )
193
+ return CausalLMOutput(loss=loss, logits=logits)
special_tokens_map.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "bos_token": "<|endoftext|>",
3
+ "eos_token": "<|endoftext|>",
4
+ "pad_token": "<|endoftext|>"
5
+ }
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "added_tokens_decoder": {
3
+ "0": {
4
+ "content": "<|endoftext|>",
5
+ "lstrip": false,
6
+ "normalized": false,
7
+ "rstrip": false,
8
+ "single_word": false,
9
+ "special": true
10
+ }
11
+ },
12
+ "bos_token": "<|endoftext|>",
13
+ "clean_up_tokenization_spaces": false,
14
+ "eos_token": "<|endoftext|>",
15
+ "extra_special_tokens": {},
16
+ "model_max_length": 2048,
17
+ "pad_token": "<|endoftext|>",
18
+ "tokenizer_class": "PreTrainedTokenizerFast"
19
+ }