SimpleDesign 1.0 fails if you don't align latent spaces properly
Jointly optimizing protein sequences and 3D structures is a nightmare because you're essentially trying to map a 1D string of amino acids to a 3D coordinate map in a single pass. I've been testing SimpleDesign 1.0 to see if it actually beats the old multi-stage autoencoder approach, and while the "joint model" claim sounds great on paper, the latent space alignment is where everything breaks. If the sequence encoder and structure encoder aren't perfectly synced, the model generates "hallucinated" proteins that look okay in a viewer but are physically impossible.
Why the joint approach is actually risky
Most of us are used to the two-stage pipeline: train a VAE or an autoencoder to tokenize the protein into a latent vector, then train a generative model (like a Transformer) on those tokens. SimpleDesign tries to skip the middleman by training everything together. In theory, this prevents "information loss" between stages. In practice, if your loss function isn't weighted perfectly, the model tends to prioritize the sequence (which is easier to learn) and ignores the structural constraints, leading to sequences that don't fold into the predicted shape.
The specific failure points I hit
When I first ran the joint training, I kept hitting a divergence issue where the structure loss would spike while the sequence loss plummeted. It looked like this in the logs:
Epoch 42: Seq_Loss: 0.124 | Struct_Loss: 4.892 | Gradient_Norm: 12.45
Epoch 43: Seq_Loss: 0.118 | Struct_Loss: 7.110 | Gradient_Norm: 28.12
ERROR: CUDA out of memory. Tried to allocate 12.00 GiB (GPU 0); has 8.00 GiB total.
The gradient explosion usually happens because the 3D coordinate updates are far more volatile than the categorical amino acid updates. If you're using a standard Adam optimizer without a very tight learning rate decay, the structure latent space just drifts away from the sequence space.
How to actually make it work
If you're attempting to implement a joint sequence-structure model, don't just throw them into one loss function. I found that you need a contrastive loss layer to force the sequence and structure representations to cluster together.
1. Initialize the sequence and structure encoders separately for about 10k steps before enabling the joint loss.
2. Use a weighted sum for the loss: Total_Loss = L_seq + (lambda * L_struct). I found lambda = 0.1 was the only way to stop the structure loss from dominating the gradients.
3. Use a coordinate-based representation (like distance matrices) rather than raw XYZ coordinates to reduce the variance in the latent space.
The cost of joint training
Don't be fooled by the "simple" in the name. Joint models are computationally expensive. Running a batch of 32 proteins with a sequence length of 128 residues on an A100 40GB barely fit. If you try to scale this to larger proteins (256+ residues), the memory overhead for the joint attention mechanism grows quadratically. I spent about $400 on cloud compute just to find the stability point for the hyperparameters, and that's not even counting the time spent debugging the latent drift.
It's a powerful approach for drug discovery if you get the alignment right, but for most people, the old-school multi-stage autoencoder is safer because you can debug the tokenizer and the generator independently.
All Replies (4)
Frustrated by this. My last batch crashed constantly until I tweaked the latent dim to 256. Wondering if CUDA 12.2 fixes it.
Curious if this happens with batch sizes over 16. I suspect the gradient clipping in the AdamW optimizer is actually the culprit.
Finally! This burned me for weeks during my last run. I only got it stable using PyTorch 2.1 with a specific learning rate...
@GhostGeek Curious if that worked on CUDA 12.1? I'm still hitting that specific memory leak.