# Copyright (c) Meta Platforms, Inc. and affiliates. # # This software may be used and distributed in accordance with # the terms of the DINOv3 License Agreement. from typing import Callable, Optional, Tuple import torch import torch.nn as nn from dinov3.layers import CausalSelfAttentionBlock class TextTransformer(nn.Module): def __init__( self, context_length: int, vocab_size: int, dim: int, num_heads: int, num_layers: int, ffn_ratio: float, is_causal: bool, ls_init_value: Optional[float] = None, act_layer: Callable = nn.GELU, norm_layer: Callable = nn.LayerNorm, dropout_prob: float = 0.0, ): super().__init__() self.vocab_size = vocab_size self.embed_dim = dim self.num_heads = num_heads self.token_embedding = nn.Embedding(vocab_size, dim) self.positional_embedding = nn.Parameter(torch.empty(context_length, dim)) self.dropout = nn.Dropout(dropout_prob) self.num_layers = num_layers block_list = [ CausalSelfAttentionBlock( dim=dim, num_heads=num_heads, ffn_ratio=ffn_ratio, ls_init_value=ls_init_value, is_causal=is_causal, act_layer=act_layer, norm_layer=norm_layer, dropout_prob=dropout_prob, ) for _ in range(num_layers) ] self.blocks = nn.ModuleList(block_list) self.ln_final = norm_layer(dim) def init_weights(self): nn.init.normal_(self.token_embedding.weight, std=0.02) nn.init.normal_(self.positional_embedding, std=0.01) init_attn_std = self.embed_dim**-0.5 init_proj_std = (self.embed_dim**-0.5) * ((2 * self.num_layers) ** -0.5) init_fc_std = (2 * self.embed_dim) ** -0.5 for block in self.blocks: block.init_weights(init_attn_std, init_proj_std, init_fc_std) self.ln_final.reset_parameters() def forward(self, token_indices: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]: _, N = token_indices.size() x = self.token_embedding(token_indices) + self.positional_embedding[:N] x = self.dropout(x) for block in self.blocks: x = block(x) x = self.ln_final(x) return x