{ "cells": [ { "cell_type": "markdown", "id": "2ed96b3f-86b6-4492-ba3b-346d0a94e1d4", "metadata": {}, "source": [ "[![Open In Colab](/_static/colab-badge.svg)](https://colab.research.google.com/github/OpenProteinAI/openprotein-docs/blob/main/source/python-api/foundation-models/Using_AbLang2.ipynb)\n", "[![Get Notebook](/_static/get-notebook-badge.svg)](https://raw.githubusercontent.com/OpenProteinAI/openprotein-docs/refs/heads/main/source/python-api/foundation-models/Using_AbLang2.ipynb)\n", "[![View In GitHub](/_static/view-in-github-badge.svg)](https://github.com/OpenProteinAI/openprotein-docs/blob/main/source/python-api/foundation-models/Using_AbLang2.ipynb)\n", "\n", "# Using AbLang2\n", "\n", "This tutorial shows you how to use the community AbLang2 model\n", "(`` :py:class:`~openprotein.embeddings.AbLang2Model` ``{=rst}) to embed\n", "antibody sequences and recover residue-level likelihoods. AbLang2 is an\n", "antibody-specific protein language model trained on paired heavy and\n", "light variable domains, so it produces representations that are tuned to\n", "antibody biology rather than generic protein space.\n", "\n", "AbLang2 is most useful when you are:\n", "\n", "- working with paired antibody variable regions (VH + VL) and want a\n", " representation that respects chain context,\n", "- restoring or scoring missing or uncertain residues (e.g. residues that\n", " came in as ambiguous from sequencing),\n", "- ranking candidate mutations for antibody design where germline bias in\n", " generic PLMs would otherwise dominate.\n", "\n", "Upstream reference: [oxpig/AbLang2](https://github.com/oxpig/AbLang2).\n", "Olsen, Moal, and Deane, *Addressing the antibody germline bias and its\n", "effect on language models for improved antibody design*, bioRxiv 2024\n", "([10.1101/2024.02.02.578678](https://doi.org/10.1101/2024.02.02.578678)).\n", "\n", "## Input format: `:`\n", "\n", "AbLang2 always expects a **paired-chain** input. Heavy and light chains\n", "are concatenated with a single colon (`:`) delimiter:\n", "\n", "``` example\n", ":\n", "```\n", "\n", "The colon is a real token in the AbLang2 vocabulary \u2014 it is not a\n", "residue and it is not stripped by the backend. Two consequences fall out\n", "of this:\n", "\n", "1. **Single-chain inputs still need the colon.** If you only have a\n", " heavy chain, send `:` (trailing colon, empty light side). If you\n", " only have a light chain, send `:` (leading colon, empty heavy\n", " side). Submitting a bare sequence without a colon will be rejected\n", " as malformed antibody input.\n", "2. **Order matters.** The heavy chain always goes on the left of the\n", " colon, the light chain on the right. Swapping them will silently\n", " produce embeddings that are biologically meaningless because the\n", " chain-position priors AbLang2 learned during training no longer line\n", " up.\n", "\n", "## Masking residues with `X`\n", "\n", "Across the OpenProtein platform, `X` in an input sequence means \"mask\n", "this position\" \u2014 the model treats it as a position to predict rather\n", "than as an unknown amino acid. For AbLang2 this is what you want when\n", "computing residue likelihoods: `X` is rewritten to the ablang mask token\n", "(`*`) before tokenization, so logits at that position are masked-LM\n", "predictions over the full vocabulary, matching what AbLang2's\n", "`pseudo_log_likelihood` mode does locally.\n", "\n", "``` example\n", "masked = f\"X{vh[1:]}:{vl}\" # mask the first heavy-chain residue\n", "```\n", "\n", "This convention is consistent across embedding models on the platform \u2014\n", "you don't need to look up each model's mask character.\n", "\n", "## What you need before getting started\n", "\n", "You need one or more antibody sequences expressed in the `:`\n", "format described above. The example below uses trastuzumab (Herceptin)\n", "variable regions:" ] }, { "cell_type": "code", "execution_count": 1, "id": "87042978-c05b-4a3a-b45c-d543e9bbe5c7", "metadata": { "execution": { "iopub.execute_input": "2026-05-07T17:28:58.443935Z", "iopub.status.busy": "2026-05-07T17:28:58.443777Z", "iopub.status.idle": "2026-05-07T17:28:59.309040Z", "shell.execute_reply": "2026-05-07T17:28:59.308566Z" } }, "outputs": [], "source": [ "import openprotein\n", "\n", "# Login to your session\n", "session = openprotein.connect()\n", "\n", "# Trastuzumab VH and VL.\n", "vh = \"EVQLVESGGGLVQPGGSLRLSCAASGFNIKDTYIHWVRQAPGKGLEWVARIYPTNGYTRYADSVKGRFTISADTSKNTAYLQMNSLRAEDTAVYYCSRWGGDGFYAMDYWGQGTLVTVSS\"\n", "vl = \"DIQMTQSPSSLSASVGDRVTITCRASQDVNTAVAWYQQKPGKAPKLLIYSASFLYSGVPSRFSGSRSGTDFTLTISSLQPEDFATYYCQQHYTTPPTFGQGTKVEIK\"\n", "\n", "paired = f\"{vh}:{vl}\"\n", "heavy_only = f\"{vh}:\" # trailing colon \u2014 heavy chain alone\n", "light_only = f\":{vl}\" # leading colon \u2014 light chain alone" ] }, { "cell_type": "markdown", "id": "fcc5b762-7c07-4723-b6cd-701544de0a20", "metadata": {}, "source": [ "## Getting the model\n", "\n", "Create the `` :py:class:`~openprotein.embeddings.AbLang2Model` ``{=rst}\n", "object from your session:" ] }, { "cell_type": "code", "execution_count": 2, "id": "1f979d9b-6802-4c55-9e11-db08ddd064a7", "metadata": { "execution": { "iopub.execute_input": "2026-05-07T17:28:59.310426Z", "iopub.status.busy": "2026-05-07T17:28:59.310313Z", "iopub.status.idle": "2026-05-07T17:28:59.423265Z", "shell.execute_reply": "2026-05-07T17:28:59.422837Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on AbLang2Model in module openprotein.embeddings.ablang:\n", "\n", "ablang2\n", " AbLang2 foundational model for antibodies.\n", " max_sequence_length = 4096\n", " supported outputs = ['embed', 'logits']\n", " supported tokens = ['M', 'R', 'H', 'K', 'D', 'E', 'S', 'T', 'N', 'Q', 'C', 'G', 'P', 'A', 'V', 'I', 'F', 'Y', 'W', 'L', '-', 'X', ':']\n", "\n" ] } ], "source": [ "ablang2 = session.embedding.ablang2\n", "help(ablang2)" ] }, { "cell_type": "markdown", "id": "0bfa508a-7955-4dc7-9982-941d8c2f3c53", "metadata": {}, "source": [ "The model object exposes its metadata: maximum sequence length, the\n", "supported output types\n", "(`` :py:meth:`~openprotein.embeddings.AbLang2Model.embed` ``{=rst},\n", "`` :py:meth:`~openprotein.embeddings.AbLang2Model.logits` ``{=rst},\n", "etc.), and the full vocabulary \u2014 note the `:` token in\n", "`supported tokens`, which is what makes paired-chain input work.\n", "\n", "## Embedding a paired antibody\n", "\n", "Submit your `:` sequence to\n", "`` :py:meth:`~openprotein.embeddings.AbLang2Model.embed` ``{=rst}. As\n", "with other embedding models you can pass a list of sequences to batch\n", "the request, and an optional `reduction` (defaulting to `MEAN` over\n", "residues):" ] }, { "cell_type": "code", "execution_count": 3, "id": "8aeb6688-798c-4fb1-b348-af470c89c8f5", "metadata": { "execution": { "iopub.execute_input": "2026-05-07T17:28:59.424455Z", "iopub.status.busy": "2026-05-07T17:28:59.424385Z", "iopub.status.idle": "2026-05-07T17:28:59.676108Z", "shell.execute_reply": "2026-05-07T17:28:59.675624Z" } }, "outputs": [ { "data": { "text/plain": [ "EmbeddingsJob(num_records=1, job_id='f95c3911-7329-4db4-b34b-e0c150f3e424', job_type=, status=, created_date=datetime.datetime(2026, 5, 7, 17, 28, 59, 495307, tzinfo=TzInfo(0)), start_date=None, end_date=None, prerequisite_job_id=None, progress_message=None, progress_counter=0, sequence_length=None, failure_message=None)" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "future = ablang2.embed(sequences=[paired.encode()])\n", "future" ] }, { "cell_type": "markdown", "id": "abe0ab2e-2512-4921-ba9e-b765bb0f2fa5", "metadata": {}, "source": [ "Wait for the job to complete:" ] }, { "cell_type": "code", "execution_count": 4, "id": "7d0a9e7c-64a0-4123-8d7a-a4e4cdec503f", "metadata": { "execution": { "iopub.execute_input": "2026-05-07T17:28:59.677853Z", "iopub.status.busy": "2026-05-07T17:28:59.677754Z", "iopub.status.idle": "2026-05-07T17:28:59.810405Z", "shell.execute_reply": "2026-05-07T17:28:59.809833Z" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "\r", "Waiting: 0%| | 0/100 [00:00