import {useEffect,useRef,useState} from 'react'; import {Typewriter} from './Typewriter'; import type {Example} from './types'; type Mode='joint'|'t2p'|'p2t'; const details={ joint:{title:'Two directions. A shared learning process.',body:'Each protein–text pair supervises both directions in the same training step. Shared self-attention parameters link the encoder and decoder within each modality, coupling the two tasks.',tag:'JOINT TRAINING',loss:'L = ½ L(text → protein) + ½ L(protein → text)'}, t2p:{title:'Start with a function. Generate a sequence.',body:'The text encoder reads a functional description. A cross-modal projection conditions the protein decoder, which generates amino acids one token at a time.',tag:'TEXT → PROTEIN',loss:'Functional description → protein sequence'}, p2t:{title:'Start with a sequence. Describe its function.',body:'The protein encoder reads an amino-acid sequence. The reverse projection conditions the text decoder, which generates a functional description.',tag:'PROTEIN → TEXT',loss:'Protein sequence → functional description'}, }; export function DualLearning({example}:{example:Example}){ const [mode,setMode]=useState('joint'); const [technical,setTechnical]=useState(false),[playing,setPlaying]=useState(()=>!window.matchMedia('(prefers-reduced-motion: reduce)').matches); const section=useRef(null); useEffect(()=>{ if(!playing)return; let visible=true;const io=new IntersectionObserver(entries=>{visible=entries[0].isIntersecting;});if(section.current)io.observe(section.current); const timer=setInterval(()=>{if(visible&&!document.hidden)setMode(current=>current==='joint'?'t2p':current==='t2p'?'p2t':'joint');},4500); return()=>{clearInterval(timer);io.disconnect();}; },[playing]); const item=details[mode]; const direction=mode==='p2t'?'p2t':'t2p'; return

01 THE CORE IDEA

Read. Write.
Learn together.

One protein–text pair.
Two prediction tasks.
Connected through shared parameters.

ONE FRAMEWORK · TWO GENERATION TASKS
{([['joint','Joint learning'],['t2p','Text → Protein'],['p2t','Protein → Text']] as [Mode,string][]).map(([v,l])=>)}
FUNCTIONAL LANGUAGE{direction==='t2p'?'INPUT':'MODEL OUTPUT'}
{direction==='t2p'?

{example.text}

:}
{direction==='t2p'?'DESIGN':'DESCRIBE'}
{' '}TOKEN BY TOKEN
PROTEIN SEQUENCE{direction==='t2p'?'MODEL OUTPUT':'INPUT'}
{direction==='t2p'?:
{example.protein}
}
RECORDED DEMOlarge-v5 · {example.name} · {example.id}. Each direction starts from its reference input; this is not a round trip.Source ↗
Aa
MODALITY 01

Functional language

01
READText encoder
•••
Shared self-attention
04
WRITEText decoder
•••
DESIGNCross-modal projection
DESCRIBECross-modal projection
⌁
MODALITY 02

Protein sequence

02
WRITEProtein decoder
•••
Shared self-attention
03
READProtein encoder
•••
{item.tag}

{item.title}

{item.body}

{mode==='joint'?'ONE JOINT OBJECTIVE':'INFERENCE PATH'}{item.loss} Parameter-coupled bidirectional generation
01

The same paired dataEach sequence and description supports learning in both directions.

02

Two supervised predictionsGenerate a sequence from text, and text from a sequence.

03

Parameters connect the tasksShared weights receive learning signals from the joint objective.

{technical&&

The animation replays two archived model outputs from a held-out HSP20 reference example. Each direction uses the corresponding reference input, not the output of the other direction. Playback timing illustrates autoregressive decoding and is not measured inference speed. The live playground generates new outputs on demand.

The original large-v5 model jointly optimizes two autoregressive, teacher-forced cross-entropy losses. Corresponding encoder/decoder self-attention weights are shared within the text stack and within the protein stack. The projections are initialized as transposes but optimized independently.

Running a generated sequence back through the annotation model is an optional inference experiment. The training objective does not include a separate cycle-reconstruction loss. Model size: 1,226,512,384 independent parameters.

}
; }