# Estructura de proteínas ESMFold

**Predicción ultrarrápida de estructuras proteicas por Meta AI** — predecir estructuras proteicas 3D a partir de secuencias de aminoácidos en segundos, sin alineamientos múltiples de secuencias.

> 🧬 Desarrollado por **Meta AI Research** | Licencia MIT | 10x–60x más rápido que AlphaFold2

***

## ¿Qué es ESMFold?

ESMFold es el sistema de predicción de estructuras proteicas de Meta AI que aprovecha **Evolutionary Scale Modeling (ESM-2)** — el modelo de lenguaje de proteínas más grande del mundo (15 mil millones de parámetros) — para predecir estructuras proteicas 3D directamente a partir de secuencias de aminoácidos.

### Ventajas clave frente a AlphaFold2

| Característica              | ESMFold          | AlphaFold2     |
| --------------------------- | ---------------- | -------------- |
| ¿Se requiere MSA?           | ❌ No             | ✅ Sí           |
| Velocidad (proteína típica) | **\~2 segundos** | \~10 min–horas |
| Precisión (TM-score)        | \~0.87           | \~0.92         |
| VRAM de GPU (650 aa)        | \~8GB            | \~8GB          |
| Entrada de secuencia única  | ✅ Sí             | Limitado       |
| Proteínas huérfanas         | ✅ Excelente      | Dificultades   |

### ¿Por qué sin MSA?

AlphaFold2 requiere **Alineamiento Múltiple de Secuencias (MSA)** — recopilar y alinear parientes evolutivos de la proteína consulta. Esto es computacionalmente costoso e imposible para proteínas novedosas o diseñadas sin parientes evolutivos.

ESMFold almacena información evolutiva **en los pesos de su modelo de lenguaje** (entrenado con 250 millones de secuencias proteicas), eliminando completamente el MSA. Esto lo hace:

* **Más rápido:** Sin búsqueda MSA (minutos ahorrados por predicción)
* **Más escalable:** Procesar proteomas completos eficientemente
* **Mejor para proteínas novedosas:** Las secuencias diseñadas no tienen parientes evolutivos

***

## Inicio rápido en Clore.ai

### Paso 1: Seleccione un servidor

En [clore.ai](https://clore.ai) mercado:

* **Mínimo:** GPU NVIDIA con **16GB de VRAM** (el modelo de lenguaje ESM-2 es grande)
* **Recomendado:** A100 40GB, RTX 3090, RTX 4090 para el modelo completo
* **Opción más pequeña:** Usa `esm2_t33_650M_UR50D` para 8GB de VRAM

Guía de VRAM de GPU:

| Longitud de la proteína | Variante del modelo | VRAM requerida |
| ----------------------- | ------------------- | -------------- |
| Hasta 300 aa            | ESMFold (3B)        | \~16GB         |
| Hasta 500 aa            | ESMFold (3B)        | \~20GB         |
| Hasta 1000 aa           | ESMFold (3B)        | \~40GB         |
| Hasta 600 aa            | ESMFold (chunk)     | \~8GB          |

### Paso 2: Construir imagen Docker personalizada

```dockerfile
FROM pytorch/pytorch:2.1.0-cuda12.1-cudnn8-devel

# Dependencias del sistema
RUN apt-get update && apt-get install -y \
    git \
    wget \
    curl \
    openssh-server \
    libhdf5-dev \
    pkg-config \
    && rm -rf /var/lib/apt/lists/*

# Configurar SSH
RUN mkdir /var/run/sshd && \
    echo 'root:esmfold' | chpasswd && \
    sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

# Instalar ESMFold y dependencias
RUN pip install --no-cache-dir \
    fair-esm[esmfold] \
    torch \
    biopython \
    biotite \
    fastapi \
    uvicorn \
    pydantic \
    openmm==8.0.0 \
    pdbfixer

# Instalar OpenFold (requerido para ESMFold)
RUN pip install "git+https://github.com/aqlaboratory/openfold.git@4b41059694619831a7db195b7e0988fc4ff3a307"

EXPOSE 22

CMD ["/usr/sbin/sshd", "-D"]
```

### Paso 3: Desplegar en Clore.ai

* **Imagen Docker:** `yourname/esmfold:latest`
* **Puertos:** `22` (SSH)
* **Entorno:** `NVIDIA_VISIBLE_DEVICES=all`

***

## Instalación y configuración

### Método 1: pip install

```bash
# Instalar ESMFold
pip install fair-esm[esmfold]

# Instalar OpenFold (dependencia requerida)
pip install "git+https://github.com/aqlaboratory/openfold.git@4b41059694619831a7db195b7e0988fc4ff3a307"

# Opcional pero recomendado
pip install biotite biopython
```

### Método 2: Desde el código fuente

```bash
git clone https://github.com/facebookresearch/esm.git
cd esm
pip install -e ".[esmfold]"
```

### Verificar la instalación

```python
import esm
print("Versión de ESM:", esm.__version__)

# Prueba rápida de carga del modelo
model = esm.pretrained.esmfold_v1()
print("¡ESMFold cargado con éxito!")
```

***

## Uso básico

### Predecir la estructura de una sola proteína

```python
import torch
import esm

# Cargar el modelo ESMFold
model = esm.pretrained.esmfold_v1()
model = model.eval().cuda()

# Opcional: Habilitar tamaño de chunk para ahorrar VRAM
# Aumenta el tiempo de cómputo pero reduce el uso de VRAM
model.set_chunk_size(64)  # Reducir para menos VRAM

# Secuencia de proteína (ejemplo: Lisocima C)
sequence = "KVFGRCELAAAMKRHGLDNYRGYSLGNWVCAAKFESNFNTQATNRNTDGSTDYGILQINSRWWCNDGRTPGSRNLCNIPCSALLSSDITASVNCAKKIVSDGNGMNAWVAWRNRCKGTDVQAWIRGCRL"

# Predecir estructura
with torch.no_grad():
    output = model.infer_pdb(sequence)

# Guardar archivo PDB
with open("lysozyme.pdb", "w") as f:
    f.write(output)

print(f"¡Estructura predicha! Guardada en lysozyme.pdb")
print(f"Longitud de la secuencia: {len(sequence)} aminoácidos")
```

### Predecir múltiples secuencias (lote)

```python
import torch
import esm

model = esm.pretrained.esmfold_v1()
model = model.eval().cuda()

sequences = {
    "protein_A": "MKTAYIAKQRQISFVKSHFSRQ...",
    "protein_B": "MGDVEKGKKIFVQKCAQCHTVEK...",
    "ubiquitin": "MQIFVKTLTGKTITLEVEPSDTIENVKAKIQDKEGIPPDQQRLIFAGKQLEDGRTLSDYNIQKESTLHLVLRLRGG",
}

for name, seq in sequences.items():
    with torch.no_grad():
        output = model.infer_pdb(seq)
    
    with open(f"{name}.pdb", "w") as f:
        f.write(output)
    
    print(f"Predicho {name}: {len(seq)} aa")

print("¡Todas las predicciones completadas!")
```

### Obtener confianza por residuo (pLDDT)

```python
import torch
import esm
import numpy as np

model = esm.pretrained.esmfold_v1()
model = model.eval().cuda()

sequence = "MQIFVKTLTGKTITLEVEPSDTIENVKAKIQDKEGIPPDQQRLIFAGKQLEDGRTLSDYNIQKESTLHLVLRLRGG"

with torch.no_grad():
    output = model.infer(sequence)

# Extraer puntuaciones pLDDT (confianza por residuo)
plddt = output["plddt"].cpu().numpy()  # Forma: [1, seq_len]
plddt_per_residue = plddt[0]

print(f"pLDDT medio: {plddt_per_residue.mean():.2f}")
print(f"Residuos con alta confianza (>90): {(plddt_per_residue > 90).sum()}")
print(f"Residuos con baja confianza (<50): {(plddt_per_residue < 50).sum()}")

# Clasificar regiones por confianza
for i, score in enumerate(plddt_per_residue):
    if score >= 90:
        confidence = "Muy alta (azul)"
    elif score >= 70:
        confidence = "Confiable (azul claro)"
    elif score >= 50:
        confidence = "Baja (amarillo)"
    else:
        confidence = "Muy baja (naranja)"
    # print(f"Residuo {i+1}: {score:.1f} - {confidence}")  # Descomentar para salida completa
```

***

## Servidor REST API

Construir una API de producción para ESMFold:

```python
# api_server.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import torch
import esm
import time
from typing import Optional

app = FastAPI(
    title="ESMFold Protein Structure Prediction API",
    description="Predecir estructuras 3D de proteínas a partir de secuencias de aminoácidos",
    version="1.0.0"
)

# Cargar modelo al iniciar
print("Cargando el modelo ESMFold (esto toma ~30 segundos)...")
model = esm.pretrained.esmfold_v1()
model = model.eval().cuda()
model.set_chunk_size(64)  # Optimización de memoria
print("¡ESMFold listo!")

class PredictionRequest(BaseModel):
    sequence: str
    name: Optional[str] = "protein"

class PredictionResponse(BaseModel):
    name: str
    sequence_length: int
    pdb_content: str
    mean_plddt: float
    inference_time_seconds: float

@app.post("/predict", response_model=PredictionResponse)
async def predict_structure(request: PredictionRequest):
    """Predecir la estructura 3D de una proteína a partir de la secuencia de aminoácidos."""
    
    # Validar secuencia
    valid_aa = set("ACDEFGHIKLMNPQRSTVWY")
    sequence = request.sequence.upper().strip()
    
    invalid = set(sequence) - valid_aa
    if invalid:
        raise HTTPException(
            status_code=400,
            detail=f"Aminoácidos inválidos en la secuencia: {invalid}. Use los 20 aminoácidos estándar."
        )
    
    if len(sequence) > 2000:
        raise HTTPException(
            status_code=400,
            detail="Secuencia demasiado larga (máx. 2000 aminoácidos). Para secuencias más largas, use predicción en fragmentos."
        )
    
    start_time = time.time()
    
    try:
        with torch.no_grad():
            output = model.infer(sequence)
            pdb_content = model.output_to_pdb(output)[0]
            
        plddt = output["plddt"].cpu().numpy()[0]
        mean_plddt = float(plddt.mean())
        
    except torch.cuda.OutOfMemoryError:
        torch.cuda.empty_cache()
        raise HTTPException(
            status_code=507,
            detail="GPU sin memoria. Intente una secuencia más corta o reduzca el tamaño de chunk."
        )
    
    inference_time = time.time() - start_time
    
    return PredictionResponse(
        name=request.name,
        sequence_length=len(sequence),
        pdb_content=pdb_content,
        mean_plddt=mean_plddt,
        inference_time_seconds=round(inference_time, 2)
    )

@app.get("/health")
def health():
    gpu_mem = torch.cuda.memory_allocated() / 1024**3 if torch.cuda.is_available() else 0
    return {
        "status": "ok",
        "model": "ESMFold v1",
        "device": str(next(model.parameters()).device),
        "gpu_memory_gb": round(gpu_mem, 2)
    }

@app.get("/")
def root():
    return {"message": "ESMFold API — /predict para predecir estructuras, /docs para Swagger UI"}
```

```bash
# Ejecutar la API
pip install fastapi uvicorn
uvicorn api_server:app --host 0.0.0.0 --port 8080 --workers 1
```

***

## Ejemplos de uso de la API

```bash
# Predecir estructura vía API
curl -X POST http://localhost:8080/predict \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ubiquitina",
    "sequence": "MQIFVKTLTGKTITLEVEPSDTIENVKAKIQDKEGIPPDQQRLIFAGKQLEDGRTLSDYNIQKESTLHLVLRLRGG"
  }' | python3 -c "
import sys, json
data = json.load(sys.stdin)
print(f\"Nombre: {data['name']}\")
print(f\"Longitud: {data['sequence_length']} aa\")
print(f\"pLDDT medio: {data['mean_plddt']:.1f}\")
print(f\"Tiempo: {data['inference_time_seconds']}s\")
# Guardar PDB
open('ubiquitin.pdb', 'w').write(data['pdb_content'])
print('¡PDB guardado!')
"
```

***

## Script de procesamiento por lotes

```python
# batch_predict.py
import torch
import esm
import os
from pathlib import Path
from Bio import SeqIO  # pip install biopython

def predict_fasta(fasta_file: str, output_dir: str, chunk_size: int = 64):
    """Predecir estructuras para todas las secuencias en un archivo FASTA."""
    
    Path(output_dir).mkdir(parents=True, exist_ok=True)
    
    # Cargar modelo
    model = esm.pretrained.esmfold_v1()
    model = model.eval().cuda()
    model.set_chunk_size(chunk_size)
    
    # Leer FASTA
    sequences = list(SeqIO.parse(fasta_file, "fasta"))
    print(f"Prediciendo estructuras para {len(sequences)} proteínas...")
    
    results = []
    for i, record in enumerate(sequences):
        seq = str(record.seq).upper()
        name = record.id
        
        print(f"[{i+1}/{len(sequences)}] Prediciendo {name} ({len(seq)} aa)...")
        
        try:
            with torch.no_grad():
                output = model.infer(seq)
                pdb = model.output_to_pdb(output)[0]
            
            plddt = output["plddt"].cpu().numpy()[0].mean()
            
            # Guardar PDB
            output_path = os.path.join(output_dir, f"{name}.pdb")
            with open(output_path, "w") as f:
                f.write(pdb)
            
            results.append({
                "name": name,
                "length": len(seq),
                "mean_plddt": round(float(plddt), 2),
                "output": output_path,
                "status": "success"
            })
            
        except Exception as e:
            print(f"  Error: {e}")
            results.append({"name": name, "status": f"error: {e}"})
    
    # Escribir resumen
    import csv
    with open(os.path.join(output_dir, "summary.csv"), "w") as f:
        writer = csv.DictWriter(f, fieldnames=["name", "length", "mean_plddt", "output", "status"])
        writer.writeheader()
        writer.writerows(results)
    
    success = sum(1 for r in results if r.get("status") == "success")
    print(f"\n¡Hecho! {success}/{len(sequences)} estructuras predichas con éxito")
    print(f"Resultados guardados en {output_dir}/")

if __name__ == "__main__":
    predict_fasta(
        fasta_file="./proteins.fasta",
        output_dir="./predicted_structures",
        chunk_size=64
    )
```

***

## Visualización de estructuras

### Usando Py3Dmol (Jupyter / Python)

```python
import py3Dmol  # pip install py3Dmol

with open("protein.pdb") as f:
    pdb_data = f.read()

view = py3Dmol.view(width=800, height=600)
view.addModel(pdb_data, "pdb")
view.setStyle({"cartoon": {"colorscheme": "ssJmol"}})
view.zoomTo()
view.show()
```

### Usando PyMOL

```bash
# Instalar PyMOL
apt-get install pymol

# Abrir estructura
pymol lysozyme.pdb
```

### Visualización programática con Biotite

```python
import biotite.structure.io.pdb as pdb
import biotite.structure as struc
import numpy as np

# Cargar estructura predicha
pdb_file = pdb.PDBFile.read("lysozyme.pdb")
structure = pdb.get_structure(pdb_file, model=1)

# Analizar estructura secundaria
sse = struc.annotate_sse(structure)

helix_frac = (sse == 'a').mean() * 100
sheet_frac = (sse == 'b').mean() * 100
coil_frac = (sse == 'c').mean() * 100

print(f"Composición de estructura secundaria:")
print(f"  Hélice alfa:  {helix_frac:.1f}%")
print(f"  Hoja beta:    {sheet_frac:.1f}%")
print(f"  Coil/Otro:    {coil_frac:.1f}%")
```

***

## Optimización de memoria

### Guía de tamaño de chunk

```python
# Menor chunk_size = menos VRAM, predicción más lenta
# Mayor chunk_size = más VRAM, predicción más rápida

# Para 8GB de VRAM (permite hasta ~400 aa)
model.set_chunk_size(32)

# Para 16GB de VRAM (hasta ~700 aa)
model.set_chunk_size(64)

# Para 40GB de VRAM (hasta ~2000 aa, sin chunking)
model.set_chunk_size(None)  # Desactivar chunking
```

### Descarga a CPU para secuencias muy largas

```python
# Cargar modelo en CPU, mover a GPU por inferencia
model = esm.pretrained.esmfold_v1()
model = model.eval()

# Mover a GPU para inferencia, volver a CPU después
model = model.cuda()
with torch.no_grad():
    output = model.infer(sequence)
model = model.cpu()  # Liberar memoria GPU
torch.cuda.empty_cache()
```

***

## Solución de problemas

### CUDA Fuera de memoria

```bash
# Reducir tamaño de chunk
model.set_chunk_size(32)  # o incluso 16

# Comprobar VRAM libre
nvidia-smi --query-gpu=memory.free --format=csv,noheader

# Para proteínas muy largas, dividir en dominios
# Normalmente seguro dividir proteínas > 1000 aa en dominios de 300-500 aa
```

### ImportError para openfold

```bash
# Reinstalar con commit específico
pip install "git+https://github.com/aqlaboratory/openfold.git@4b41059694619831a7db195b7e0988fc4ff3a307"

# Comprobar la instalación
python -c "import openfold; print('OpenFold OK')"
```

### Carga lenta del modelo

```bash
# La primera carga descarga pesos del modelo de 2.7GB — esto es normal
# Cargas posteriores usan pesos en caché (~30s de tiempo de carga)

# Comprobar ubicación de la caché
python -c "import torch; print(torch.hub.get_dir())"
ls ~/.cache/torch/hub/
```

{% hint style="warning" %}
**Nota sobre memoria:** El modelo de lenguaje de ESMFold (ESM-2 de 15B parámetros) requiere VRAM significativa. Para servidores GPU con menos de 16GB de VRAM, use la `esm2_t33_650M_UR50D` variante backbone o habilite un chunking agresivo.
{% endhint %}

{% hint style="info" %}
**Interpretación de pLDDT:**

* **>90** = Confianza muy alta (azul en la coloración de AlphaFold)
* **70–90** = Confiable (cian/azul claro)
* **50–70** = Baja confianza (amarillo) — trate con precaución
* **<50** = Muy baja confianza (naranja/rojo) — probablemente región desordenada
  {% endhint %}

***

## Recomendaciones de GPU en Clore.ai

El requisito de VRAM de ESMFold está dominado por el modelo de lenguaje ESM-2 de 15B parámetros. La longitud de la secuencia añade sobrecarga de memoria adicional.

| GPU       | VRAM  | Precio en Clore.ai | Longitud máxima de secuencia  | Tiempo de predicción (300 aa) |
| --------- | ----- | ------------------ | ----------------------------- | ----------------------------- |
| RTX 3090  | 24 GB | \~$0.12/h          | \~400 aa (con chunking)       | \~8 segundos                  |
| RTX 4090  | 24 GB | \~$0.70/h          | \~400 aa (con chunking)       | \~5 segundos                  |
| A100 40GB | 40 GB | \~$1.20/h          | \~800 aa cómodamente          | \~3 segundos                  |
| A100 80GB | 80 GB | \~$2.00/h          | \~1500+ aa, proteínas grandes | \~4 segundos                  |

{% hint style="warning" %}
**VRAM mínima: 16GB.** ESMFold no puede ejecutarse en GPUs de 8GB con el backbone ESM-2 completo. La RTX 3090/4090 (24GB) puede manejar proteínas de hasta \~400 aminoácidos sin chunking — habilite `chunk_size=64` en la API para secuencias más largas.
{% endhint %}

**Mejor relación calidad-precio para investigación:** La RTX 3090 a \~$0.12/h maneja la gran mayoría de tareas de predicción de estructuras proteicas (proteína humana promedio: \~300–400 aa). A \~8 segundos por predicción, puede procesar \~450 estructuras por hora por \~$0.12 en total — en comparación con AlphaFold2 que requiere cálculo de MSA que toma minutos por estructura.

**Proteómica de alto rendimiento:** Para cribar miles de secuencias, A100 40GB (\~$1.20/h) con inferencia por lotes procesa \~1,200+ predicciones por hora — viable para estudios a escala de proteomas.

***

## Recursos

* 🐙 **GitHub:** [github.com/facebookresearch/esm](https://github.com/facebookresearch/esm)
* 🤗 **Modelos:** [huggingface.co/facebook/esmfold\_v1](https://huggingface.co/facebook/esmfold_v1)
* 📄 **Artículo:** [Predicción a escala evolutiva de la estructura proteica a nivel atómico con un modelo de lenguaje (Science, 2023)](https://www.science.org/doi/10.1126/science.ade2574)
* 🌐 **Atlas metagenómico ESM:** [esmatlas.com](https://esmatlas.com) — 772M de estructuras predichas con ESMFold
* 💻 **Blog de Meta AI:** [ai.meta.com/blog/protein-folding-esmfold-metagenomics](https://ai.meta.com/blog/protein-folding-esmfold-metagenomics/)
* 🔬 **Registro de cambios de ESM:** [github.com/facebookresearch/esm/blob/main/CHANGELOG.md](https://github.com/facebookresearch/esm/blob/main/CHANGELOG.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.clore.ai/guides/guides_v2-es/ciencia-e-investigacion/esmfold.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
