| name | x-algo-ml |
| description | Explain the Phoenix ML model architecture for X recommendations. Use when users ask about embeddings, transformers, how predictions work, or ML model details. |
X Algorithm ML Architecture
The X recommendation system uses Phoenix, a transformer-based ML system for predicting user engagement. It operates in two stages: retrieval and ranking.
Two-Stage Pipeline
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ RECOMMENDATION PIPELINE โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ โ โ โ โ โ
โ โ User โโโโโโถโ STAGE 1: โโโโโโถโ STAGE 2: โโโโโโถ Feedโ
โ โ Request โ โ RETRIEVAL โ โ RANKING โ โ
โ โ โ โ (Two-Tower) โ โ (Transformer) โ โ
โ โโโโโโโโโโโโ โ โ โ โ โ
โ โ Millions โ 1000s โ โ 1000s โ Ranked โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Stage 1: Retrieval (Two-Tower Model)
Efficiently narrows millions of candidates to thousands using approximate nearest neighbor search.
Architecture
- User Tower: Encodes user features + engagement history โ normalized embedding
[B, D]
- Candidate Tower: Pre-computed embeddings for all posts in corpus โ
[N, D]
- Similarity: Dot product between user embedding and candidate embeddings
User Tower Candidate Tower
โ โ
โผ โผ
[B, D] user emb [N, D] all posts
โ โ
โโโโโโ dot product โโโโ
โ
โผ
Top-K by similarity
Stage 2: Ranking (Transformer with Candidate Isolation)
Scores the retrieved candidates using a transformer that predicts multiple engagement actions.
Model Configuration
@dataclass
class PhoenixModelConfig:
model: TransformerConfig
emb_size: int
num_actions: int
history_seq_len: int = 128
candidate_seq_len: int = 32
product_surface_vocab_size: int = 16
hash_config: HashConfig
Input Structure
class RecsysBatch(NamedTuple):
user_hashes: ArrayLike
history_post_hashes: ArrayLike
history_author_hashes: ArrayLike
history_actions: ArrayLike
history_product_surface: ArrayLike
candidate_post_hashes: ArrayLike
candidate_author_hashes: ArrayLike
candidate_product_surface: ArrayLike
Hash-Based Embeddings
Multiple hash functions map IDs to embedding tables:
@dataclass
class HashConfig:
num_user_hashes: int = 2
num_item_hashes: int = 2
num_author_hashes: int = 2
Why hashes?
- Fixed memory: No need for individual embeddings per user/post
- Handles new entities: Any ID maps to some embedding
- Collision averaging: Multiple hashes reduce collision impact
Embedding Combination
Each entity type has a "reduce" function that combines hash embeddings:
def block_user_reduce(...):
user_embedding = user_embeddings.reshape((B, 1, num_user_hashes * D))
user_embedding = jnp.dot(user_embedding, proj_mat_1)
return user_embedding, user_padding_mask
def block_history_reduce(...):
post_author_embedding = jnp.concatenate([
history_post_embeddings_reshaped,
history_author_embeddings_reshaped,
history_actions_embeddings,
history_product_surface_embeddings,
], axis=-1)
history_embedding = jnp.dot(post_author_embedding, proj_mat_3)
return history_embedding, history_padding_mask
Transformer Input
Final input is concatenation of:
[User (1)] + [History (S)] + [Candidates (C)]
โ โ โ
โผ โผ โผ
[B, 1, D] [B, S, D] [B, C, D]
โฒ โ โฑ
โฒ โ โฑ
[B, 1+S+C, D]
Attention Masking: Candidate Isolation
Critical design: Candidates cannot attend to each other, only to user + history.
ATTENTION MASK
Keys (what we attend TO)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโถ
โ User โ History (S) โ Candidates (C) โ
โโโโโโผโโโโโโโผโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโค
Q โ U โ โ โ โ โ โ โ โ โ โ โ โ โ
u โโโโโโผโโโโโโโผโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโค
e โ H โ โ โ โ โ โ โ โ โ โ โ โ โ
r โ i โ โ โ โ โ โ โ โ โ โ โ โ โ
i โ s โ โ โ โ โ โ โ โ โ โ โ โ โ
e โ t โ โ โ โ โ โ โ โ โ โ โ โ โ
s โโโโโโผโโโโโโโผโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโค
โ C โ โ โ โ โ โ โ โ โ โ โ โ โ
โ โ a โ โ โ โ โ โ โ โ โ โ โ โ โ
โ โ n โ โ โ โ โ โ โ โ โ โ โ โ โ
โผ โ d โ โ โ โ โ โ โ โ โ โ โ โ โ
โโโโโโดโโโโโโโดโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโ
โ = Can attend โ = Cannot attend (diagonal only for candidates)
Why candidate isolation?
- Score for post A shouldn't depend on whether post B is in the batch
- Ensures consistent scoring regardless of batch composition
- Enables parallel scoring of candidates
Transformer Forward Pass
def __call__(self, batch, recsys_embeddings) -> RecsysModelOutput:
embeddings, padding_mask, candidate_start = self.build_inputs(batch, recsys_embeddings)
model_output = self.model(
embeddings,
padding_mask,
candidate_start_offset=candidate_start,
)
out_embeddings = layer_norm(model_output.embeddings)
candidate_embeddings = out_embeddings[:, candidate_start:, :]
logits = jnp.dot(candidate_embeddings, unembeddings)
return RecsysModelOutput(logits=logits)
Output: Multi-Action Prediction
Output Shape: [B, num_candidates, num_actions]
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Like โ Reply โ Retweet โ Quote โ ... (18) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Each output is a log-probability. Convert to probability:
probability = exp(log_prob)
Action Embeddings
History actions are encoded as signed vectors:
def _get_action_embeddings(self, actions):
actions_signed = (2 * actions - 1)
action_emb = jnp.dot(actions_signed, action_projection)
return action_emb
This encodes "did action" (+1) vs "didn't do action" (-1) for each action type.
Product Surface Embeddings
Where the user engaged (home feed, search, notifications, etc.):
def _single_hot_to_embeddings(self, input, vocab_size, emb_size, name):
embedding_table = hk.get_parameter(name, [vocab_size, emb_size])
input_one_hot = jax.nn.one_hot(input, vocab_size)
return jnp.dot(input_one_hot, embedding_table)
Model Heritage
The sample transformer implementation is ported from the Grok-1 open source release by xAI. The core transformer architecture comes from Grok-1, adapted for recommendation system use cases with custom input embeddings and attention masking for candidate isolation.
Related Skills
/x-algo-engagement - The 18 action types the model predicts
/x-algo-scoring - How predictions become weighted scores
/x-algo-pipeline - Where ML fits in the full system