Skip to content

Commit 3f98938

Browse files
authored
Merge pull request #311 from openvax/rc10-class1-neural-network-helper-split
Split class I neural network helpers
2 parents 191a9b8 + 9245bb0 commit 3f98938

23 files changed

Lines changed: 1164 additions & 1056 deletions

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ Have a bugfix or other contribution? We would love your help. See our [contribut
2020
## 2.3.0 release candidate
2121

2222
> [!IMPORTANT]
23-
> 2.3.0 is currently a release candidate (`2.3.0rc9`), not yet a final release.
23+
> 2.3.0 is currently a release candidate (`2.3.0rc10`), not yet a final release.
2424
> It keeps the same public API and pre-trained models as 2.2.x. Install it with
2525
> `pip install --pre mhcflurry`, or pin the version with
26-
> `pip install mhcflurry==2.3.0rc9`. A plain `pip install --upgrade mhcflurry`
26+
> `pip install mhcflurry==2.3.0rc10`. A plain `pip install --upgrade mhcflurry`
2727
> stays on the latest stable release (2.2.x) until 2.3.0 is final, since pip
2828
> skips pre-releases.
2929

mhcflurry/class1_affinity_predictor.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,7 +1404,7 @@ def predict_cartesian_pan_allele(
14041404
return None
14051405

14061406
import torch
1407-
from .class1_neural_network import (
1407+
from .pytorch_sizing import (
14081408
DEFAULT_PREDICT_BATCH_SIZE,
14091409
resolve_prediction_batch_size,
14101410
)
@@ -2048,7 +2048,7 @@ def _auto_size_calibration_batches(
20482048
20492049
Returns the chosen ``(peptide_batch, allele_batch)``.
20502050
"""
2051-
from .class1_neural_network import (
2051+
from .pytorch_sizing import (
20522052
compute_prediction_batch_size,
20532053
_free_device_memory_bytes,
20542054
_AUTO_BATCH_MAX_ROWS,
@@ -2239,7 +2239,7 @@ def _estimate_calibration_peak_bytes_per_row(model):
22392239
before combining them. Hidden-layer peak memory is therefore the max
22402240
sub-network peak, not the sum of every sub-network peak.
22412241
"""
2242-
from .class1_neural_network import _estimate_peak_bytes_per_row
2242+
from .pytorch_sizing import _estimate_peak_bytes_per_row
22432243

22442244
if model is None:
22452245
return _estimate_peak_bytes_per_row(model)

mhcflurry/class1_encoding.py

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License");
2+
# you may not use this file except in compliance with the License.
3+
# You may obtain a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS,
9+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
# See the License for the specific language governing permissions and
11+
# limitations under the License.
12+
13+
"""Peptide encoding helpers for class I neural networks."""
14+
15+
import logging
16+
17+
from . import amino_acid
18+
from .encodable_sequences import EncodableSequences
19+
20+
_DEVICE_PEPTIDE_ENCODING_TRUE_VALUES = {
21+
"1",
22+
"true",
23+
"yes",
24+
"on",
25+
"auto",
26+
"cpu",
27+
"device",
28+
"torch",
29+
"gpu",
30+
"mps",
31+
}
32+
_DEVICE_PEPTIDE_ENCODING_FALSE_VALUES = {
33+
"0",
34+
"false",
35+
"no",
36+
"off",
37+
"numpy",
38+
"legacy",
39+
}
40+
41+
_warned_legacy_peptide_vector_encoding = []
42+
43+
44+
def _warn_legacy_peptide_vector_encoding(value):
45+
"""Warn once that the legacy dense-vector peptide path is gone."""
46+
if not _warned_legacy_peptide_vector_encoding:
47+
_warned_legacy_peptide_vector_encoding.append(True)
48+
logging.warning(
49+
"peptide_amino_acid_encoding_torch=%r is deprecated and ignored: "
50+
"peptides are always index-encoded ((N, L) int8) and embedded on "
51+
"device via a frozen table. The legacy dense-vector peptide "
52+
"encoding path has been removed.", value)
53+
54+
55+
def _peptide_torch_encoding_name(hyperparameters):
56+
"""Return the fixed amino-acid encoding for the peptide embedding table.
57+
58+
Peptides are always index-encoded ((N, L) int8) and embedded via a frozen
59+
``torch.nn.functional.embedding`` table (device-agnostic: CUDA/MPS/CPU). The
60+
table comes from ``amino_acid.get_vector_encoding_df`` and is registered as
61+
a non-persistent buffer, so it moves with ``.to(device)`` but never trains
62+
or bloats the NPZ weight list.
63+
64+
The legacy ``peptide_amino_acid_encoding_torch=False`` dense-vector path has
65+
been removed; a falsy value is accepted but ignored (with a one-time
66+
deprecation warning) so older configs still load. A non-default value names
67+
the encoding directly; an unknown name still raises.
68+
"""
69+
mode = hyperparameters.get("peptide_amino_acid_encoding_torch", True)
70+
if isinstance(mode, str):
71+
mode_normalized = mode.strip().lower()
72+
if mode_normalized in _DEVICE_PEPTIDE_ENCODING_FALSE_VALUES:
73+
_warn_legacy_peptide_vector_encoding(mode)
74+
else:
75+
try:
76+
amino_acid.get_vector_encoding_df(mode)
77+
return mode
78+
except KeyError:
79+
pass
80+
if mode_normalized not in _DEVICE_PEPTIDE_ENCODING_TRUE_VALUES:
81+
raise ValueError(
82+
"Unsupported peptide_amino_acid_encoding_torch value %r. "
83+
"Expected bool, a true/false string, or one of %s."
84+
% (mode, sorted(amino_acid.ENCODING_DATA_FRAMES))
85+
)
86+
elif not mode:
87+
_warn_legacy_peptide_vector_encoding(mode)
88+
89+
peptide_encoding = hyperparameters.get("peptide_encoding", {})
90+
encoding_name = peptide_encoding.get("vector_encoding_name", "BLOSUM62")
91+
try:
92+
amino_acid.get_vector_encoding_df(encoding_name)
93+
except KeyError:
94+
raise ValueError(
95+
"Peptide encoding requires a fixed vector encoding with a torch "
96+
"lookup table; got %r. Available: %s"
97+
% (encoding_name, sorted(amino_acid.ENCODING_DATA_FRAMES))
98+
) from None
99+
return encoding_name
100+
101+
102+
def _peptide_uses_torch_encoding(hyperparameters):
103+
"""Deprecated: peptides are always index-encoded now (always True)."""
104+
return True
105+
106+
107+
def _peptide_torch_encoding_table(encoding_name):
108+
"""Return a float32 lookup table indexed by ``AMINO_ACID_INDEX``."""
109+
return amino_acid.vector_encoding_index_table(encoding_name)
110+
111+
112+
def _peptide_torch_encoding_shape(index_shape, encoding_name):
113+
"""Expand an ``(L,)`` categorical peptide shape to ``(L, V)``."""
114+
return (
115+
index_shape[0],
116+
amino_acid.vector_encoding_length(encoding_name),
117+
)
118+
119+
120+
def _categorical_kwargs_for_peptide_encoding(peptide_encoding):
121+
"""Extract kwargs shared by vector and categorical peptide encoders."""
122+
return {
123+
key: value
124+
for key, value in peptide_encoding.items()
125+
if key in (
126+
"alignment_method",
127+
"left_edge",
128+
"right_edge",
129+
"max_length",
130+
"trim",
131+
"allow_unsupported_amino_acids",
132+
)
133+
}
134+
135+
136+
def peptide_sequences_to_network_input(
137+
peptides,
138+
peptide_encoding,
139+
peptide_amino_acid_encoding_torch=True):
140+
"""Encode peptide strings to the representation consumed by a network.
141+
142+
This is the central peptide-only string-to-array conversion. Peptides are
143+
always returned as compact ``(N, L)`` int8 amino-acid indices; the
144+
fixed-vector lookup then happens through the network's frozen torch
145+
embedding table. (``peptide_amino_acid_encoding_torch`` is accepted for
146+
config compatibility but the legacy dense-vector path is gone.)
147+
"""
148+
if not peptide_amino_acid_encoding_torch:
149+
_warn_legacy_peptide_vector_encoding(peptide_amino_acid_encoding_torch)
150+
encoder = EncodableSequences.create(peptides)
151+
return (
152+
encoder.variable_length_to_fixed_length_categorical(
153+
**_categorical_kwargs_for_peptide_encoding(peptide_encoding)
154+
)
155+
.astype("int8", copy=False)
156+
)

0 commit comments

Comments
 (0)