Aether / model /aether.py
yadavkapil7155's picture
Publish AETHER-100M model release
2353ae6 verified
Raw History Blame Contribute Delete
6.53 kB
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.checkpoint import checkpoint
from .attention import GQAAttention
from .rmsnorm import RMSNorm
from .rope import rope_cache
from .swiglu import SwiGLU
class AETHERConfig:
vocab_size = 32000
hidden_size = 768
num_hidden_layers = 12
num_attention_heads = 12
num_key_value_heads = 4
head_dim = 64
intermediate_size = 2048
max_position_embeddings = 2048
rope_theta = 10000.0
rms_norm_eps = 1e-6
tie_word_embeddings = True
bias = False
gradient_checkpointing = True
dropout = 0.0
class AETHERBlock(nn.Module):
def __init__(self, config):
super().__init__()
self.input_layernorm = RMSNorm(
config.hidden_size,
config.rms_norm_eps,
)
self.self_attn = GQAAttention(
hidden_size=config.hidden_size,
num_attention_heads=config.num_attention_heads,
num_key_value_heads=config.num_key_value_heads,
head_dim=config.head_dim,
bias=config.bias,
)
self.post_attention_layernorm = RMSNorm(
config.hidden_size,
config.rms_norm_eps,
)
self.mlp = SwiGLU(
hidden_size=config.hidden_size,
intermediate_size=config.intermediate_size,
bias=config.bias,
)
def forward(self, x, cos, sin):
x = x + self.self_attn(
self.input_layernorm(x),
cos,
sin,
)
x = x + self.mlp(
self.post_attention_layernorm(x)
)
return x
class AETHER100M(nn.Module):
def __init__(self, config=None):
super().__init__()
if config is None:
config = AETHERConfig()
self.config = config
self.embed = nn.Embedding(
config.vocab_size,
config.hidden_size,
)
self.layers = nn.ModuleList(
[
AETHERBlock(config)
for _ in range(config.num_hidden_layers)
]
)
self.norm = RMSNorm(
config.hidden_size,
config.rms_norm_eps,
)
self.lm_head = nn.Linear(
config.hidden_size,
config.vocab_size,
bias=False,
)
if config.tie_word_embeddings:
self.lm_head.weight = self.embed.weight
self._init_weights()
def _init_weights(self):
std = 0.02
nn.init.normal_(
self.embed.weight,
mean=0.0,
std=std,
)
for module in self.modules():
if isinstance(module, nn.Linear):
if module.weight is self.embed.weight:
continue
nn.init.normal_(
module.weight,
mean=0.0,
std=std,
)
if module.bias is not None:
nn.init.zeros_(module.bias)
residual_scale = 1.0 / math.sqrt(
2 * self.config.num_hidden_layers
)
for layer in self.layers:
layer.self_attn.o_proj.weight.data.mul_(
residual_scale
)
layer.mlp.down_proj.weight.data.mul_(
residual_scale
)
def forward(
self,
input_ids,
labels=None,
):
B, T = input_ids.shape
if T > self.config.max_position_embeddings:
raise ValueError(
f"Sequence length {T} exceeds "
f"maximum {self.config.max_position_embeddings}"
)
x = self.embed(input_ids)
cos, sin = rope_cache(
seq_len=T,
head_dim=self.config.head_dim,
theta=self.config.rope_theta,
device=input_ids.device,
)
for layer in self.layers:
if (
self.config.gradient_checkpointing
and self.training
):
x = checkpoint(
layer,
x,
cos,
sin,
use_reentrant=False,
)
else:
x = layer(
x,
cos,
sin,
)
x = self.norm(x)
loss = None
logits = None
if labels is not None:
shift_x = x[:, :-1, :].contiguous()
shift_labels = labels[:, 1:].contiguous()
B, T, H = shift_x.shape
# Avoid creating the enormous
# [B, T, vocab_size] tensor at once.
chunk_tokens = 64
total_loss = torch.zeros(
(),
device=x.device,
dtype=torch.float32,
)
total_tokens = 0
flat_x = shift_x.view(
-1,
H,
)
flat_labels = shift_labels.view(
-1,
)
for start in range(
0,
B * T,
chunk_tokens,
):
end = min(
start + chunk_tokens,
B * T,
)
hidden_chunk = flat_x[
start:end
]
label_chunk = flat_labels[
start:end
]
logits_chunk = self.lm_head(
hidden_chunk
)
chunk_loss = F.cross_entropy(
logits_chunk,
label_chunk,
reduction="sum",
)
total_loss += chunk_loss.float()
total_tokens += label_chunk.numel()
loss = (
total_loss /
total_tokens
)
else:
logits = self.lm_head(x)
return {
"logits": logits,
"loss": loss,
}
def count_parameters(model):
return sum(
p.numel()
for p in model.parameters()
)