PRISM: Personalized Item Representations in User History

Renzhi Wu, Zikun Cui, Junjie Yang, Li Sheng, Yongjun Xie, Jerry Fu, Nipun Mathur, Sri Reddy, Hong Li
30 minread4.00scoreNo. 111-02 Personalization issue
Contents · 9 sections1What problem does it solve?2How does it differ from existing approaches?3Pipeline: export while ranking, read in time order4Why take every layer, not just the last?5How does the downstream model use the codes?6Results7Limitations8Trying it in your own setting9Verdict
Rel 4Nov 4Prac 4Evid 4Time 4

The same cooking video is a pastime for a casual viewer and source material for a food creator. Yet a recommender gives it the same starting embedding in both users' history sequences. PRISM (the method this Meta paper proposes) replaces each history event with a new vector. That vector expresses how this user related to this item at that moment. It reuses the intermediate states of every layer that the upstream ranking model already computed while scoring, concatenates them, and feeds them to an autoencoder that compresses them into one embedding per scored user–item pair. These are stored, and later sequence models read them in time order. On a billion-user recommendation surface at Meta, downstream NE drops by 0.15% on average. At a similar history length, VISTA, an approach that compresses the user history into cached summary tokens, drops by only 0.07%. The gain also grows with longer histories. The input to a history sequence can itself be personalized, and the compute can ride on ranking work that already happens.

This paper is worth a close read because it changes what goes into a history sequence: instead of an item ID, it stores what the upstream model understood about that scoring event at the time, something that is computed every day and normally thrown away. The evidence so far is offline NE only, with no online experiment and no breakdown of which states matter most, so it is best treated as a cheap direction to try rather than a proven result.

What problem does it solve?

Mainstream sequential recommendation writes the user history as a list of item IDs. Each ID looks up a shared embedding table, and a sequence model such as a Transformer reads the result. The problem is that the table is shared by everyone.

The same history record (illustration)What an ID sequence feeds inWhat it actually meant
User A watched cooking video Vthe embedding of Vscrolling after work, then moving on
Food creator B watched cooking video Vthe same embedding of Vrewatching knife work to film her own

A sequence model can learn to separate these meanings in later layers, but that costs capacity and data. PRISM's view is that when the upstream ranker scored V, it had already combined A's or B's features and the other candidates in the same request to work out this relationship. Keep those intermediate results, and every history entry starts out carrying "how this person saw this item back then."

How does it differ from existing approaches?

The most direct option is to train a separate user–item model and recompute a relationship vector for every history event of every user. History volume is enormous, so that compute does not scale. The paper notes that many recommenders already have an upstream ranker that supplies user embedding features and teacher labels to downstream models. While scoring, it reads the user history and combines user, item, and context, so its hidden states already hold information about each encounter. PRISM keeps that computation so it does not have to be done twice.

The two approaches the paper names as closest reuse at different granularity:

ApproachWhat is storedWhat downstream can access
VISTAa few summary tokens compressed from the whole user historya summary of the whole history
OneTransKV cache reused across requestsintermediate results from an earlier request
PRISMone short code per scored user–item pairsingle history events, each with the user and context of that moment

So PRISM's difference is storing per event: downstream can choose which events to read and how many, and each one keeps the user state and the other candidates from that time.

Pipeline: export while ranking, read in time order

PRISM architecture: every layer's states from the user tower, the user–item tower, and session mixing are detached from gradients, normalized separately, and concatenated into one long vector; the encoder compresses it into an event code stored in the event store, the decoder is used only in training for reconstruction, and later requests read these codes in time order.
PRISM architecture: every layer's states from the user tower, the user–item tower, and session mixing are detached from gradients, normalized separately, and concatenated into one long vector; the encoder compresses it into an event code stored in the event store, the decoder is used only in training for reconstruction, and later requests read these codes in time order.

The system has two halves: the upstream model that produces codes, and storage plus downstream reading.

StageInputWhat it doesOutput
User toweruser history and user featurescomputes the user's state over several layersuser state at each layer
User–item towercandidate features, context, final user statemodels the relationship between this user and this candidate, with multitask headsuser–item state at each layer
Session mixingfinal states of all candidates in the same ranking requestcandidates exchange information (one realization in the paper is a Transformer-style module); each layer pools all valid candidates' states into a request summary; item-level and request-level headsper-candidate state at each layer plus a request summary
Compressionall layer states from the three sourcesconcatenates them and shortens them with an encoderone code p_e per scored user–item pair
Downstream readingup to L codes from before the current requestadds time information and other available information about the event, then runs a sequence modelextra features for the downstream predictor

Here "session" does not mean the user's past browsing session. It means the batch of candidates scored together in one ranking request. Session mixing receives detached candidate states, so its loss never changes the user–item tower.

Why take every layer, not just the last?

The last layer mainly serves the upstream prediction heads and leans toward "will this be clicked now." Middle layers keep broader information, such as different sides of the user's interests and comparisons between candidates. PRISM takes every layer from all three sources, rescales each part by its own root mean square so no part dominates just because its numbers are larger, and concatenates them into a long vector v_e. Its length does not depend on how many candidates a request has, because the session part keeps only the current candidate's own states and one request summary, which pools the states of all valid candidates into a fixed-length vector.

Storing the long vector directly is too expensive. So an autoencoder follows: the encoder is a stack of gated residual blocks, and a softsign at the end bounds every dimension to (−1, 1), giving a short code p_e. The decoder is used only in training and must rebuild v_e from p_e; the smaller the reconstruction error, the less information compression lost. The key point is that the reconstruction loss updates only the encoder and decoder, not the three sources. The upstream model trains on its own recommendation goals as usual, and the compressor just takes notes alongside. The total loss is the sum of three terms: the user–item prediction loss, the session-mixing prediction loss, and the reconstruction loss.

In the experiments each code has 128 dimensions stored as INT8, so each code takes about 128 bytes.

These codes are exported while PRISM trains online: the upstream model already runs a forward pass for training, and export just compresses that pass's intermediate states and writes them to the event store. All history the downstream model reads in the experiments comes from these 14 days of export. Each record corresponds to one scoring, identified as (user, item, scoring time, request), and the code uses only information available at that moment: the user history before it, the user features at the time, the candidate features, and the request context. The paper does not say where the full candidate set of the same request comes from at export time, nor whether candidates never shown to the user take part in session mixing or are written to the event store. That step decides which candidates the request summary actually contains, so a reproduction has to choose its own rule. At read time, a retention rule (in the experiments, the latest 400 events within 30 days) picks the history from the event store.

How does the downstream model use the codes?

For a concrete example, go back to creator B. She opens the app today, and the downstream model must score a batch of new videos. The reader looks up her records with three rules: the scoring happened before now, the code has already been written and can be read, and the current request itself is excluded. It keeps the most recent L records.

Each code p_e goes through three steps before entering the downstream model. It is multiplied by a projection matrix specific to the upstream model version, because different upstream versions produce slightly different code spaces. A time encoding for how long ago it happened is added, and so is an encoding of other available information about the event, which the paper only calls eligible metadata without listing fields. A sequence model then processes them, and a reader conditioned on the current candidate weights them by relevance. The result joins the ordinary features in the predictor.

Stored codes are fixed and downstream training never changes them. The downstream reader and version-specific projections, along with the ordinary-feature network and the final predictor, are updated by downstream training, so upstream and downstream can iterate on their own schedules. Users with no history get an availability flag and go through the ordinary feature path. If video V appears twice in B's history, it gets two different codes, because her state and the other candidates differed each time. For example (illustration), at the first scoring she had mostly been watching comedy, and V came in a batch with a few comedy clips. At the second scoring she had spent the past week watching knife-skill tutorials, and V came in a batch with tutorials. The difference between the two codes comes from the user state and the other candidates known at scoring time; whether she later finished or saved the video is not written into that code. In an ID sequence these two entries look identical. In a PRISM sequence each carries its own context, making it easier for the downstream model to see her interest in cooking becoming professional.

Results

Experiments run on a billion-user recommendation surface inside Meta (called Surface 1 in the paper). PRISM first trains online for 14 days and exports codes as it goes, so downstream has enough history to read. The downstream model then trains from scratch on the 3 days of production data after those 14 days and is evaluated on held-out data from the day right after, so evaluation data comes strictly after training data. Neither the baseline nor the PRISM arm uses a warm start, so the difference comes only from the added history branch.

History keeps the most recent 400 events within 30 days, and 98% of users have records, so coverage is not a problem. Lower NE is better, and the paper treats improvements above 0.03% as significant.

Task groupVISTAPRISM
Positive actions (8 tasks)−0.05%−0.17%
Negative actions (5 tasks)−0.09%−0.11%
All (13 tasks)−0.07%−0.15%

Both methods use the same ranking baseline, data, ordinary features, and evaluation protocol, with similar history lengths. Among positive actions the larger gains are like −0.22%, comment −0.20%, and share −0.17%; on the negative side, dislike is −0.09%. This shows PRISM's advantage is mainly on positive engagement. On negative actions the gap between the two is only 0.02 percentage points, below the significance line.

As downstream history length grows from 26 to 240 events, the NE gain rises from 0.06% to 0.17%, and the four points fall on a power-law curve.
As downstream history length grows from 26 to 240 events, the NE gain rises from 0.06% to 0.17%, and the four points fall on a power-law curve.

The paper also varies how much history the downstream model reads. From 26 to 240 events, the NE gain rises from 0.06% to 0.17%. The fitted power-law exponent is 0.468, which means each doubling of length multiplies the gain by about 1.38. This shows the benefit grows with longer history and has not saturated within 240 events.

Limitations

First, the evidence is offline NE only. An average of −0.15% over 13 tasks is not small at this scale, but every evaluation is offline, so how much of it turns into online metrics is unknown.

Second, there are no ablations. The experiments only compare full PRISM against VISTA, so how much the three sources, the use of all layers, or the autoencoder each contribute is unknown. Readers cannot tell whether the last few layers of the user–item tower alone would be enough, which is exactly what decides the cost of reproducing it.

Third, there are no cost numbers. The paper stresses reuse of upstream compute, but export and storage are not free: at 128 bytes per event and up to 400 events per user, the event store grows linearly with scoring volume, while the experiments describe only the training hardware, with no numbers for storage size, write latency, or downstream read time. The power-law fit also rests on only 4 points between 26 and 240 events and cannot be extrapolated to longer histories.

Trying it in your own setting

If you already run an online ranking model, a low-cost test has three steps:

  1. Export only the last one or two layers of the user–item tower, compress them to 64 or 128 dimensions with a small encoder, and log them per scoring record.
  2. Keep the existing ID sequence downstream and add a separate sequence branch that reads these codes. Compare NE at the same length and see which tasks gain.
  3. If it helps, add more layers and request-level states step by step, and record the storage added by each part to judge cost against benefit.

One more point: the paper's PRISM is an upstream ranker designed specifically to produce these codes, with session mixing and an autoencoder, not an off-the-shelf model used as is. Exporting states from an existing model may work less well, and the comparison in step 1 answers exactly that.

Watch for compatibility of old codes after the upstream model changes version. The paper handles this with version-specific projection matrices, which a trial should keep.

Verdict

DimensionAssessment
NoveltyUsing upstream ranking states as personalized input to the history sequence is a clear idea
EvidenceOffline NE −0.15% over 13 tasks, about twice VISTA; no online test, no ablations
CostReuses existing compute, but storage and read costs are not reported
Worth trying?Teams with a mature upstream ranker and long histories should run a small offline check

How did this read for you?

One tap, no sign-in; tap again to undo. Only anonymous counts are kept, never who you are.

Discussion

Add experiment details, reproduction notes or a different take. Requires a GitHub sign-in.

Loading the discussion…