lhallee commited on
Commit
a645a8c
·
verified ·
1 Parent(s): b113c04

Update FastPLMs runtime and model cards

Browse files
README.md CHANGED
@@ -36,9 +36,8 @@ This model requires Python 3.11-3.14, PyTorch 2.13, and Transformers 5.13.
36
 
37
  The artifact requirements include the structure dependencies.
38
 
39
- The release contract requires a CUDA device. The current validated target is
40
- the exact NVIDIA GH200 on Linux aarch64. Linux x86-64, CPU-only, Windows, and
41
- macOS structure runs are not release evidence.
42
 
43
  The Hub quick start needs network access for the first download. For an
44
  air-gapped run, build the manifest-pinned local artifact first and use the
@@ -113,6 +112,7 @@ output = model.predict_structure(
113
  num_sampling_steps=50,
114
  diffusion_samples=1,
115
  seed=7,
 
116
  )
117
  model.save_as_cif(output, "prediction.cif")
118
 
@@ -149,7 +149,7 @@ continues independently of the ESM++ and ESMFold2 release gates.
149
  - Redistributable: `true`
150
  - Complete weight publication required: `false`
151
 
152
- ## Validation and provenance
153
 
154
  FastPLMs pins the checkpoint, upstream source revisions, state transformation,
155
  and required files in `models.toml`. Built artifacts record exact source
 
36
 
37
  The artifact requirements include the structure dependencies.
38
 
39
+ Validation runs in Docker on any compatible CUDA device. Record the container,
40
+ hardware, precision, and inputs; no GPU product or workstation is required.
 
41
 
42
  The Hub quick start needs network access for the first download. For an
43
  air-gapped run, build the manifest-pinned local artifact first and use the
 
112
  num_sampling_steps=50,
113
  diffusion_samples=1,
114
  seed=7,
115
+ verbose=False,
116
  )
117
  model.save_as_cif(output, "prediction.cif")
118
 
 
149
  - Redistributable: `true`
150
  - Complete weight publication required: `false`
151
 
152
+ ## Validation and sources
153
 
154
  FastPLMs pins the checkpoint, upstream source revisions, state transformation,
155
  and required files in `models.toml`. Built artifacts record exact source
fastplms/models.toml CHANGED
@@ -392,7 +392,7 @@ checkpoint_license = "MIT"
392
  hub_license = "mit"
393
  weights_publication_allowed = true
394
  state_transform = "identity"
395
- conversion_provenance = "Input: each pinned Biohub ESMFold2 checkpoint and its separately pinned ESMC checkpoint. Transformation: apply identity to preserve the folding checkpoint exactly, load its parameters in FP32 for CUDA BF16-autocast execution, retain canonical BF16 ESMC weights, and optionally rebuild exactly 80 ESMC attention output projections as transient Transformer Engine linears. Output: the corresponding pinned Synthyra ESMFold2 checkpoint plus its declared ESMC precision policy. Validation: release parity covers exact canonical state, learned projection, prepared features, and seeded BF16 folding; experimental FP8 validation covers strict unavailable-device behavior, all four variants, and three BF16-to-FP8 reload cycles on the standard variant. Limitation: only the four manifest-listed ESMFold2 variants are supported; FP8 is experimental, applies only to inference-time ESMC execution, and requires direct CUDA loading with Transformer Engine availability."
396
  representative = "esmfold2"
397
  documentation = "docs/esmfold2.md"
398
  test_tiers = ["check", "compliance", "structure", "feature", "artifact", "benchmark"]
@@ -1237,3 +1237,39 @@ official_files = [
1237
  "model.safetensors=sha256:4e903b740ad6ad704ec60881bfd593e0d6c874a630ffa0f0838276e0b665088f",
1238
  ]
1239
  auto_map = { AutoConfig = "fastplms.models.esmfold2.configuration_esmfold2.ESMFold2Config", AutoModel = "fastplms.models.esmfold2.modeling_esmfold2_experimental.ESMFold2ExperimentalModel", AutoModelForSequenceClassification = "fastplms.models.esmfold2.modeling_esmfold2_classification.ESMFold2ExperimentalForSequenceClassification", AutoModelForTokenClassification = "fastplms.models.esmfold2.modeling_esmfold2_classification.ESMFold2ExperimentalForTokenClassification" }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
392
  hub_license = "mit"
393
  weights_publication_allowed = true
394
  state_transform = "identity"
395
+ conversion_provenance = "Input: each pinned Biohub ESMFold2 checkpoint and its separately pinned ESMC checkpoint. Transformation: apply identity to preserve the folding checkpoint exactly, load its parameters in FP32 for CUDA BF16-autocast execution, retain canonical BF16 ESMC weights, and optionally rebuild exactly 80 ESMC attention output projections as transient Transformer Engine linears. Output: the corresponding pinned Synthyra ESMFold2 checkpoint plus its declared ESMC precision policy. Validation: release parity covers exact canonical state, learned projection, prepared features, and seeded BF16 folding; experimental FP8 validation covers strict unavailable-device behavior, the four 6B-backbone variants, and three BF16-to-FP8 reload cycles on the standard variant. Limitation: only the six manifest-listed ESMFold2 variants are supported; FP8 is experimental, applies only to inference-time ESMC execution, and requires direct CUDA loading with Transformer Engine availability."
396
  representative = "esmfold2"
397
  documentation = "docs/esmfold2.md"
398
  test_tiers = ["check", "compliance", "structure", "feature", "artifact", "benchmark"]
 
1237
  "model.safetensors=sha256:4e903b740ad6ad704ec60881bfd593e0d6c874a630ffa0f0838276e0b665088f",
1238
  ]
1239
  auto_map = { AutoConfig = "fastplms.models.esmfold2.configuration_esmfold2.ESMFold2Config", AutoModel = "fastplms.models.esmfold2.modeling_esmfold2_experimental.ESMFold2ExperimentalModel", AutoModelForSequenceClassification = "fastplms.models.esmfold2.modeling_esmfold2_classification.ESMFold2ExperimentalForSequenceClassification", AutoModelForTokenClassification = "fastplms.models.esmfold2.modeling_esmfold2_classification.ESMFold2ExperimentalForTokenClassification" }
1240
+
1241
+ [[models]]
1242
+ id = "esmfold2_300"
1243
+ family = "esmfold2"
1244
+ size_category = "structure"
1245
+ generation_contract = "not_applicable"
1246
+ msa_conditioning = false
1247
+ publication_status = "published"
1248
+ fast_repo = "Synthyra/ESMFold2-300"
1249
+ fast_revision = "a38a62ae930d157484b331c2bf4241684573adba"
1250
+ fast_files = ["config.json=git-sha1:47ec20cf8b234c3b41d6f3ae1bdfe95d4eb4849e", "model.safetensors=sha256:44d6797c5efebf24753d502b40950e0874871c96ceea14f2d7f7e39cebac67fd"]
1251
+ official_repo = "biohub/ESMFold2-Experimental-Fast-base300M-step1500k"
1252
+ official_revision = "21531e59002c9205284715e28ee802dafb430637"
1253
+ official_files = ["config.json=git-sha1:8c9a04fe22b0e5fca77bc4e2861a12c9494ef4d4", "model.safetensors=sha256:44d6797c5efebf24753d502b40950e0874871c96ceea14f2d7f7e39cebac67fd"]
1254
+ notes = "Experimental Fast checkpoint with a frozen 300M ESM++ backbone, tensor-exact in BF16 with the pinned step-1500000 source, 24 folding blocks, no MSA conditioning, and no confidence head. BF16 execution uses FP32 folding parameters with CUDA autocast. FP8 is unsupported. Docker BF16 inference validation passed on the compact Protein G case."
1255
+ auto_map = { AutoConfig = "fastplms.models.esmfold2.configuration_esmfold2.ESMFold2Config", AutoModel = "fastplms.models.esmfold2.modeling_esmfold2_experimental.ESMFold2ExperimentalModel", AutoModelForSequenceClassification = "fastplms.models.esmfold2.modeling_esmfold2_classification.ESMFold2ExperimentalForSequenceClassification", AutoModelForTokenClassification = "fastplms.models.esmfold2.modeling_esmfold2_classification.ESMFold2ExperimentalForTokenClassification" }
1256
+ backbone_model = "esmc_small"
1257
+ backbone = { repo = "biohub/ESMC-300M-1500000", revision = "56803b6378b82e16c3b24aac49d1fce4445540b7", files = ["config.json=git-sha1:7fe728a0eb3fb81b24491d6cc1de816bf7797c27", "model.safetensors=sha256:8bd6cacf9b5a92d51954b64b20407f1f9f564a7e4849b8663470784d2a8b7ed2", "tokenizer.json=git-sha1:81c797f56768b22dec0301fa771f018b7e43e98c", "tokenizer_config.json=git-sha1:f49f57b24a1c93bd544974811e8ecbd61b7fae89", "special_tokens_map.json=git-sha1:c907ee1dc19b24241749b32d665c291c7e6e8e4b"] }
1258
+
1259
+ [[models]]
1260
+ id = "esmfold2_600"
1261
+ family = "esmfold2"
1262
+ size_category = "structure"
1263
+ generation_contract = "not_applicable"
1264
+ msa_conditioning = false
1265
+ publication_status = "published"
1266
+ fast_repo = "Synthyra/ESMFold2-600"
1267
+ fast_revision = "71c67d0b2b73dc245ea7c3cc0d0476439a882d08"
1268
+ fast_files = ["config.json=git-sha1:8e271837cbdada96c4974c8e543f84065e0f06f1", "model.safetensors=sha256:11a53c1b4700b6c62a5a464fc3ec7076160c19e8584157f88e13275116cfd602"]
1269
+ official_repo = "biohub/ESMFold2-Experimental-Fast-base600M-step1500k"
1270
+ official_revision = "15cf2d6648692f6c17cee1297d8a285476fffa9b"
1271
+ official_files = ["config.json=git-sha1:95517e555f17a1eca4b68866c89033a1f6916a5d", "model.safetensors=sha256:11a53c1b4700b6c62a5a464fc3ec7076160c19e8584157f88e13275116cfd602"]
1272
+ notes = "Experimental Fast checkpoint with a frozen 600M ESM++ backbone, tensor-exact in BF16 with the pinned step-1500000 source, 24 folding blocks, no MSA conditioning, and no confidence head. BF16 execution uses FP32 folding parameters with CUDA autocast. FP8 is unsupported. Configuration, weight identities, and artifact reload are verified; this model is not inference-validated."
1273
+ auto_map = { AutoConfig = "fastplms.models.esmfold2.configuration_esmfold2.ESMFold2Config", AutoModel = "fastplms.models.esmfold2.modeling_esmfold2_experimental.ESMFold2ExperimentalModel", AutoModelForSequenceClassification = "fastplms.models.esmfold2.modeling_esmfold2_classification.ESMFold2ExperimentalForSequenceClassification", AutoModelForTokenClassification = "fastplms.models.esmfold2.modeling_esmfold2_classification.ESMFold2ExperimentalForTokenClassification" }
1274
+ backbone_model = "esmc_large"
1275
+ backbone = { repo = "biohub/ESMC-600M-1500000", revision = "21af9cc429af76ebda6c48074fb624db4735aaaf", files = ["config.json=git-sha1:ec29f6009b21d710f64bf1c058f3a9710833d692", "model.safetensors=sha256:d6869f5ae0f11e5dc829b195e062e87cfcc2f851a08a5edbaf5d1083ae7f76cc", "tokenizer.json=git-sha1:81c797f56768b22dec0301fa771f018b7e43e98c", "tokenizer_config.json=git-sha1:f49f57b24a1c93bd544974811e8ecbd61b7fae89", "special_tokens_map.json=git-sha1:c907ee1dc19b24241749b32d665c291c7e6e8e4b"] }
fastplms/models/boltz/modeling_boltz2.py CHANGED
@@ -9,6 +9,7 @@ from contextlib import contextmanager, nullcontext
9
  from dataclasses import dataclass
10
  from typing import Any, ClassVar
11
  from torch import Tensor
 
12
  from transformers import PretrainedConfig, PreTrainedModel
13
  from transformers.modeling_outputs import ModelOutput
14
 
@@ -572,10 +573,19 @@ class Boltz2InferenceCore(nn.Module):
572
  max_parallel_samples: int | None = None,
573
  run_confidence_sequentially: bool = True,
574
  detach_confidence: bool = True,
 
575
  ) -> dict[str, Tensor]:
576
  # b is the batch size, t the token count, a the padded atom count,
577
  # d_s the token width, d_z the pair width, and m the diffusion multiplicity.
578
- s_inputs = self.input_embedder(feats) # (b, t, d_s)
 
 
 
 
 
 
 
 
579
  s_init = self.s_init(s_inputs) # (b, t, d_s)
580
 
581
  z_init = (
@@ -598,7 +608,14 @@ class Boltz2InferenceCore(nn.Module):
598
  pair_mask = mask[:, :, None] * mask[:, None, :] # (b, t, t)
599
 
600
  if self.run_trunk_and_structure:
601
- for _ in range(recycling_steps + 1):
 
 
 
 
 
 
 
602
  s = s_init + self.s_recycle(self.s_norm(s)) # (b, t, d_s)
603
  z = z_init + self.z_recycle(self.z_norm(z)) # (b, t, t, d_z)
604
  z = z + self.msa_module(
@@ -650,6 +667,7 @@ class Boltz2InferenceCore(nn.Module):
650
  max_parallel_samples=max_parallel_samples,
651
  steering_args=self.steering_args,
652
  diffusion_conditioning=diffusion_conditioning,
 
653
  ) # tensor values include sample_atom_coords: (b * m, a, 3)
654
  output.update(struct_out)
655
 
@@ -676,19 +694,27 @@ class Boltz2InferenceCore(nn.Module):
676
  x_pred_c = x_pred # (b * m, ..., a, 3)
677
  pdist_c = output["pdistogram"][:, :, :, 0] # (b, t, t, n_bin)
678
 
679
- output.update(
680
- self.confidence_module(
681
- s_inputs=s_inputs_c,
682
- s=s_c,
683
- z=z_c,
684
- x_pred=x_pred_c,
685
- feats=feats,
686
- pred_distogram_logits=pdist_c,
687
- multiplicity=diffusion_samples,
688
- run_sequentially=run_confidence_sequentially,
689
- use_kernels=self.use_kernels,
 
 
 
 
 
 
 
 
690
  )
691
- )
692
 
693
  return output # named tensors retain the shapes traced above
694
 
@@ -836,6 +862,7 @@ class Boltz2Model(PreTrainedModel):
836
  output_attentions: bool | None = None,
837
  output_hidden_states: bool | None = None,
838
  return_dict: bool | None = None,
 
839
  ) -> Boltz2ModelOutput | tuple[Any, ...]:
840
  # Feature shapes follow build_boltz2_features; b and t are batch and token counts.
841
  output_attentions = (
@@ -866,6 +893,7 @@ class Boltz2Model(PreTrainedModel):
866
  max_parallel_samples=max_parallel_samples,
867
  run_confidence_sequentially=run_confidence_sequentially,
868
  detach_confidence=detach_confidence,
 
869
  ) # named tensors use the Boltz2InferenceCore.forward shapes
870
  token_state = raw_output.get("s") # (b, t, d_s) or None
871
  pair_state = raw_output.get("z") # (b, t, t, d_z) or None
@@ -907,6 +935,7 @@ class Boltz2Model(PreTrainedModel):
907
  run_confidence_sequentially: bool = True,
908
  float_dtype: torch.dtype = torch.float32,
909
  seed: int | None = None,
 
910
  ) -> Boltz2StructureOutput:
911
  if float_dtype != torch.float32:
912
  raise ValueError(
@@ -923,16 +952,24 @@ class Boltz2Model(PreTrainedModel):
923
  )
924
 
925
  with _seed_context(seed):
926
- feats, template = build_boltz2_features(
927
- amino_acid_sequence=amino_acid_sequence,
928
- num_bins=self.config.num_bins,
929
- atoms_per_window_queries=(
930
- self.core.input_embedder.atom_encoder.atoms_per_window_queries
931
- ),
932
- ) # feature shapes are traced in build_boltz2_features
933
- feats = self._to_model_device(
934
- feats, float_dtype=torch.float32
935
- ) # unchanged feature shapes
 
 
 
 
 
 
 
 
936
  autocast_context = (
937
  torch.autocast(device_type="cuda", dtype=torch.bfloat16)
938
  if self.device.type == "cuda"
@@ -947,6 +984,7 @@ class Boltz2Model(PreTrainedModel):
947
  max_parallel_samples=max_parallel_samples,
948
  run_confidence_sequentially=run_confidence_sequentially,
949
  return_dict=True,
 
950
  ) # named tensors use Boltz2InferenceCore.forward shapes
951
 
952
  sample_atom_coords_value = output.get(
 
9
  from dataclasses import dataclass
10
  from typing import Any, ClassVar
11
  from torch import Tensor
12
+ from tqdm.auto import tqdm
13
  from transformers import PretrainedConfig, PreTrainedModel
14
  from transformers.modeling_outputs import ModelOutput
15
 
 
573
  max_parallel_samples: int | None = None,
574
  run_confidence_sequentially: bool = True,
575
  detach_confidence: bool = True,
576
+ verbose: bool = False,
577
  ) -> dict[str, Tensor]:
578
  # b is the batch size, t the token count, a the padded atom count,
579
  # d_s the token width, d_z the pair width, and m the diffusion multiplicity.
580
+ with tqdm(
581
+ total=1,
582
+ desc="Boltz2: Input embeddings",
583
+ disable=not verbose,
584
+ dynamic_ncols=True,
585
+ leave=False,
586
+ ) as progress:
587
+ s_inputs = self.input_embedder(feats) # (b, t, d_s)
588
+ progress.update()
589
  s_init = self.s_init(s_inputs) # (b, t, d_s)
590
 
591
  z_init = (
 
608
  pair_mask = mask[:, :, None] * mask[:, None, :] # (b, t, t)
609
 
610
  if self.run_trunk_and_structure:
611
+ for _ in tqdm(
612
+ range(recycling_steps + 1),
613
+ desc="Boltz2: Recycling",
614
+ unit="cycle",
615
+ disable=not verbose,
616
+ dynamic_ncols=True,
617
+ leave=False,
618
+ ):
619
  s = s_init + self.s_recycle(self.s_norm(s)) # (b, t, d_s)
620
  z = z_init + self.z_recycle(self.z_norm(z)) # (b, t, t, d_z)
621
  z = z + self.msa_module(
 
667
  max_parallel_samples=max_parallel_samples,
668
  steering_args=self.steering_args,
669
  diffusion_conditioning=diffusion_conditioning,
670
+ verbose=verbose,
671
  ) # tensor values include sample_atom_coords: (b * m, a, 3)
672
  output.update(struct_out)
673
 
 
694
  x_pred_c = x_pred # (b * m, ..., a, 3)
695
  pdist_c = output["pdistogram"][:, :, :, 0] # (b, t, t, n_bin)
696
 
697
+ with tqdm(
698
+ total=1,
699
+ desc="Boltz2: Confidence",
700
+ disable=not verbose,
701
+ dynamic_ncols=True,
702
+ leave=False,
703
+ ) as progress:
704
+ output.update(
705
+ self.confidence_module(
706
+ s_inputs=s_inputs_c,
707
+ s=s_c,
708
+ z=z_c,
709
+ x_pred=x_pred_c,
710
+ feats=feats,
711
+ pred_distogram_logits=pdist_c,
712
+ multiplicity=diffusion_samples,
713
+ run_sequentially=run_confidence_sequentially,
714
+ use_kernels=self.use_kernels,
715
+ )
716
  )
717
+ progress.update()
718
 
719
  return output # named tensors retain the shapes traced above
720
 
 
862
  output_attentions: bool | None = None,
863
  output_hidden_states: bool | None = None,
864
  return_dict: bool | None = None,
865
+ verbose: bool = False,
866
  ) -> Boltz2ModelOutput | tuple[Any, ...]:
867
  # Feature shapes follow build_boltz2_features; b and t are batch and token counts.
868
  output_attentions = (
 
893
  max_parallel_samples=max_parallel_samples,
894
  run_confidence_sequentially=run_confidence_sequentially,
895
  detach_confidence=detach_confidence,
896
+ verbose=verbose,
897
  ) # named tensors use the Boltz2InferenceCore.forward shapes
898
  token_state = raw_output.get("s") # (b, t, d_s) or None
899
  pair_state = raw_output.get("z") # (b, t, t, d_z) or None
 
935
  run_confidence_sequentially: bool = True,
936
  float_dtype: torch.dtype = torch.float32,
937
  seed: int | None = None,
938
+ verbose: bool = False,
939
  ) -> Boltz2StructureOutput:
940
  if float_dtype != torch.float32:
941
  raise ValueError(
 
952
  )
953
 
954
  with _seed_context(seed):
955
+ with tqdm(
956
+ total=1,
957
+ desc="Boltz2: Prepare features",
958
+ disable=not verbose,
959
+ dynamic_ncols=True,
960
+ leave=False,
961
+ ) as progress:
962
+ feats, template = build_boltz2_features(
963
+ amino_acid_sequence=amino_acid_sequence,
964
+ num_bins=self.config.num_bins,
965
+ atoms_per_window_queries=(
966
+ self.core.input_embedder.atom_encoder.atoms_per_window_queries
967
+ ),
968
+ ) # feature shapes are traced in build_boltz2_features
969
+ feats = self._to_model_device(
970
+ feats, float_dtype=torch.float32
971
+ ) # unchanged feature shapes
972
+ progress.update()
973
  autocast_context = (
974
  torch.autocast(device_type="cuda", dtype=torch.bfloat16)
975
  if self.device.type == "cuda"
 
984
  max_parallel_samples=max_parallel_samples,
985
  run_confidence_sequentially=run_confidence_sequentially,
986
  return_dict=True,
987
+ verbose=verbose,
988
  ) # named tensors use Boltz2InferenceCore.forward shapes
989
 
990
  sample_atom_coords_value = output.get(
fastplms/models/boltz/vb_modules_diffusionv2.py CHANGED
@@ -11,6 +11,7 @@ import torch.nn.functional as F
11
  from einops import rearrange
12
  from torch import nn
13
  from torch.nn import Module
 
14
 
15
  from . import vb_const as const
16
  from . import vb_layers_initialize as init
@@ -294,6 +295,7 @@ class AtomDiffusion(Module):
294
  multiplicity=1,
295
  max_parallel_samples=None,
296
  steering_args=None,
 
297
  **network_condition_kwargs,
298
  ):
299
  if steering_args is not None and (
@@ -339,7 +341,16 @@ class AtomDiffusion(Module):
339
  atom_coords_denoised = None
340
 
341
  # gradually denoise
342
- for step_idx, (sigma_tm, sigma_t, gamma) in enumerate(sigmas_and_gammas):
 
 
 
 
 
 
 
 
 
343
  random_R, random_tr = compute_random_augmentation(
344
  multiplicity, device=atom_coords.device, dtype=atom_coords.dtype
345
  )
 
11
  from einops import rearrange
12
  from torch import nn
13
  from torch.nn import Module
14
+ from tqdm.auto import tqdm
15
 
16
  from . import vb_const as const
17
  from . import vb_layers_initialize as init
 
295
  multiplicity=1,
296
  max_parallel_samples=None,
297
  steering_args=None,
298
+ verbose: bool = False,
299
  **network_condition_kwargs,
300
  ):
301
  if steering_args is not None and (
 
341
  atom_coords_denoised = None
342
 
343
  # gradually denoise
344
+ for step_idx, (sigma_tm, sigma_t, gamma) in enumerate(
345
+ tqdm(
346
+ sigmas_and_gammas,
347
+ desc="Boltz2: Diffusion sampling",
348
+ unit="step",
349
+ disable=not verbose,
350
+ dynamic_ncols=True,
351
+ leave=False,
352
+ )
353
+ ):
354
  random_R, random_tr = compute_random_augmentation(
355
  multiplicity, device=atom_coords.device, dtype=atom_coords.dtype
356
  )
fastplms/registry.py CHANGED
The diff for this file is too large to render. See raw diff
 
fastplms_bundle.py CHANGED
The diff for this file is too large to render. See raw diff
 
modeling_fastplms.py CHANGED
@@ -13,7 +13,7 @@ from zipfile import ZIP_DEFLATED, ZipFile
13
 
14
  from .fastplms_bundle import RUNTIME_DATA, RUNTIME_HASH
15
 
16
- if RUNTIME_HASH != "0330cc826ad0679e7cd04c9d916dcfa3295c742d5b11cd04939474a4769a811a":
17
  raise RuntimeError("FastPLMs runtime identity differs from the bridge.")
18
 
19
  _RUNTIME_TEMPORARIES = []
 
13
 
14
  from .fastplms_bundle import RUNTIME_DATA, RUNTIME_HASH
15
 
16
+ if RUNTIME_HASH != "2a836472955d444f9225171d39c36613f23a449e58266491bb1db834a559df43":
17
  raise RuntimeError("FastPLMs runtime identity differs from the bridge.")
18
 
19
  _RUNTIME_TEMPORARIES = []