Remove tests directory and refresh README references
Browse filesRemove BioMod/tests/test_training_utils.py as requested. Remove the test command, links and tree entries from both project READMEs while retaining pretraining requirements. Runtime training utilities, task code, model weights, paired configuration and all data files remain unchanged.
- BioMod/README.md +2 -20
- BioMod/tests/test_training_utils.py +0 -262
- README.md +0 -5
BioMod/README.md
CHANGED
|
@@ -60,8 +60,6 @@ BioMod/ # Task code: trai
|
|
| 60 |
β βββ README.md
|
| 61 |
β βββ train.py
|
| 62 |
β βββ tutorial.ipynb
|
| 63 |
-
βββ tests/ # CPU tests for shared training utilities
|
| 64 |
-
β βββ test_training_utils.py
|
| 65 |
βββ zero_shot_batch/ # Zero-shot integration and evaluation
|
| 66 |
β βββ tools/ # Optional visualization and evaluation tools
|
| 67 |
β β βββ sequencing_depth/ # Low-depth expression generation and evaluation
|
|
@@ -113,25 +111,9 @@ jupyter lab tutorial.ipynb
|
|
| 113 |
Use `drug_response`, `drug_combination`, `gene_perturbation`, or `zero_shot_batch`
|
| 114 |
in place of `cell_annotation` to open another task.
|
| 115 |
|
| 116 |
-
###
|
| 117 |
|
| 118 |
-
The pretraining entry point
|
| 119 |
-
module supplies random seeding, a sequential distributed validation sampler,
|
| 120 |
-
cosine learning-rate scheduling with warmup and restarts, scalar metric
|
| 121 |
-
reduction, and resumable checkpoint saving. It does not depend on a separate
|
| 122 |
-
package named `utils` or on a downstream task's utility module.
|
| 123 |
-
|
| 124 |
-
From this source directory, run the CPU utility tests and check entry-point
|
| 125 |
-
imports after installing the dependencies:
|
| 126 |
-
|
| 127 |
-
```bash
|
| 128 |
-
python -B -m unittest discover -s tests -p test_training_utils.py -v
|
| 129 |
-
python -B biomod.py --help
|
| 130 |
-
```
|
| 131 |
-
|
| 132 |
-
The utility tests use synthetic tensors and temporary checkpoints; they do not
|
| 133 |
-
load the supplied pretrained weights. Passing these checks does not validate a
|
| 134 |
-
full training run. The pretraining entry point requires CUDA and an NCCL
|
| 135 |
process group. Supply `--data_path` explicitly: the pretraining corpus is not
|
| 136 |
bundled. Configure module inputs with `--biomod_data_dir` or `--biomod_data_path`.
|
| 137 |
Generated checkpoints default to `tutorial_runs/pretraining/` under the outer
|
|
|
|
| 60 |
β βββ README.md
|
| 61 |
β βββ train.py
|
| 62 |
β βββ tutorial.ipynb
|
|
|
|
|
|
|
| 63 |
βββ zero_shot_batch/ # Zero-shot integration and evaluation
|
| 64 |
β βββ tools/ # Optional visualization and evaluation tools
|
| 65 |
β β βββ sequencing_depth/ # Low-depth expression generation and evaluation
|
|
|
|
| 111 |
Use `drug_response`, `drug_combination`, `gene_perturbation`, or `zero_shot_batch`
|
| 112 |
in place of `cell_annotation` to open another task.
|
| 113 |
|
| 114 |
+
### Pretraining requirements
|
| 115 |
|
| 116 |
+
The pretraining entry point requires CUDA and an NCCL
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
process group. Supply `--data_path` explicitly: the pretraining corpus is not
|
| 118 |
bundled. Configure module inputs with `--biomod_data_dir` or `--biomod_data_path`.
|
| 119 |
Generated checkpoints default to `tutorial_runs/pretraining/` under the outer
|
BioMod/tests/test_training_utils.py
DELETED
|
@@ -1,262 +0,0 @@
|
|
| 1 |
-
"""CPU-only checks for the utilities used by the pretraining entry point.
|
| 2 |
-
|
| 3 |
-
Run from the source directory with:
|
| 4 |
-
python -m unittest discover -s tests -p "test_training_utils.py" -v
|
| 5 |
-
"""
|
| 6 |
-
|
| 7 |
-
import copy
|
| 8 |
-
import math
|
| 9 |
-
import random
|
| 10 |
-
import sys
|
| 11 |
-
import tempfile
|
| 12 |
-
import unittest
|
| 13 |
-
from pathlib import Path
|
| 14 |
-
|
| 15 |
-
import numpy as np
|
| 16 |
-
import torch
|
| 17 |
-
|
| 18 |
-
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
| 19 |
-
|
| 20 |
-
from training_utils import (
|
| 21 |
-
CosineAnnealingWarmupRestarts,
|
| 22 |
-
SequentialDistributedSampler,
|
| 23 |
-
get_reduced,
|
| 24 |
-
save_scaler_ckpt,
|
| 25 |
-
seed_all,
|
| 26 |
-
)
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
class SeedTests(unittest.TestCase):
|
| 30 |
-
def test_seed_reproduces_python_numpy_and_torch_sequences(self):
|
| 31 |
-
original_deterministic = torch.backends.cudnn.deterministic
|
| 32 |
-
original_benchmark = torch.backends.cudnn.benchmark
|
| 33 |
-
try:
|
| 34 |
-
seed_all(1234, cuda_deterministic=True)
|
| 35 |
-
first = (random.random(), np.random.random(4), torch.rand(4))
|
| 36 |
-
seed_all(1234, cuda_deterministic=True)
|
| 37 |
-
second = (random.random(), np.random.random(4), torch.rand(4))
|
| 38 |
-
self.assertEqual(first[0], second[0])
|
| 39 |
-
np.testing.assert_array_equal(first[1], second[1])
|
| 40 |
-
torch.testing.assert_close(first[2], second[2], rtol=0, atol=0)
|
| 41 |
-
self.assertTrue(torch.backends.cudnn.deterministic)
|
| 42 |
-
self.assertFalse(torch.backends.cudnn.benchmark)
|
| 43 |
-
|
| 44 |
-
seed_all(4321, cuda_deterministic=False)
|
| 45 |
-
self.assertNotEqual(first[0], random.random())
|
| 46 |
-
self.assertFalse(torch.backends.cudnn.deterministic)
|
| 47 |
-
self.assertTrue(torch.backends.cudnn.benchmark)
|
| 48 |
-
finally:
|
| 49 |
-
torch.backends.cudnn.deterministic = original_deterministic
|
| 50 |
-
torch.backends.cudnn.benchmark = original_benchmark
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
class SequentialSamplerTests(unittest.TestCase):
|
| 54 |
-
def test_rank_chunks_recover_input_order_then_last_item_padding(self):
|
| 55 |
-
for size, batch_size, world_size in [(11, 2, 3), (2, 4, 3), (12, 2, 3)]:
|
| 56 |
-
with self.subTest(size=size, batch_size=batch_size, world_size=world_size):
|
| 57 |
-
shards = []
|
| 58 |
-
expected_length = math.ceil(size / (batch_size * world_size)) * batch_size
|
| 59 |
-
for rank in range(world_size):
|
| 60 |
-
sampler = SequentialDistributedSampler(
|
| 61 |
-
range(size), batch_size, world_size, rank=rank
|
| 62 |
-
)
|
| 63 |
-
shard = list(sampler)
|
| 64 |
-
self.assertEqual(len(sampler), expected_length)
|
| 65 |
-
self.assertEqual(len(shard), expected_length)
|
| 66 |
-
self.assertEqual(len(shard) % batch_size, 0)
|
| 67 |
-
self.assertEqual(shard, sorted(shard))
|
| 68 |
-
shards.extend(shard)
|
| 69 |
-
self.assertEqual(shards[:size], list(range(size)))
|
| 70 |
-
self.assertEqual(shards[size:], [size - 1] * (len(shards) - size))
|
| 71 |
-
|
| 72 |
-
def test_empty_dataset_has_empty_shards(self):
|
| 73 |
-
for rank in range(3):
|
| 74 |
-
sampler = SequentialDistributedSampler([], 2, 3, rank=rank)
|
| 75 |
-
self.assertEqual(len(sampler), 0)
|
| 76 |
-
self.assertEqual(list(sampler), [])
|
| 77 |
-
|
| 78 |
-
def test_single_process_can_infer_rank_without_process_group(self):
|
| 79 |
-
sampler = SequentialDistributedSampler(range(3), 2, 1)
|
| 80 |
-
self.assertEqual(list(sampler), [0, 1, 2, 2])
|
| 81 |
-
|
| 82 |
-
def test_invalid_batch_world_size_and_rank_are_rejected(self):
|
| 83 |
-
for batch_size, world_size, rank in [(0, 1, 0), (-1, 1, 0), (2, 0, 0),
|
| 84 |
-
(2, -1, 0), (2, 2, -1), (2, 2, 2)]:
|
| 85 |
-
with self.subTest(batch_size=batch_size, world_size=world_size, rank=rank):
|
| 86 |
-
with self.assertRaises(ValueError):
|
| 87 |
-
SequentialDistributedSampler(range(5), batch_size, world_size, rank=rank)
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
class ReductionTests(unittest.TestCase):
|
| 91 |
-
def test_scalar_reduction_without_process_group(self):
|
| 92 |
-
self.assertAlmostEqual(get_reduced(2.75, "cpu", 0, 1), 2.75)
|
| 93 |
-
self.assertAlmostEqual(get_reduced(3, "cpu", 0, 1), 3.0)
|
| 94 |
-
|
| 95 |
-
def test_tensor_input_is_not_modified_or_attached_to_autograd(self):
|
| 96 |
-
value = torch.tensor(3.25, requires_grad=True)
|
| 97 |
-
original = value.detach().clone()
|
| 98 |
-
result = get_reduced(value, "cpu", 0, 1)
|
| 99 |
-
self.assertIsInstance(result, float)
|
| 100 |
-
self.assertEqual(result, 3.25)
|
| 101 |
-
torch.testing.assert_close(value.detach(), original, rtol=0, atol=0)
|
| 102 |
-
self.assertTrue(value.requires_grad)
|
| 103 |
-
self.assertIsNone(value.grad)
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
class SchedulerTests(unittest.TestCase):
|
| 107 |
-
@staticmethod
|
| 108 |
-
def make_scheduler(**overrides):
|
| 109 |
-
parameter = torch.nn.Parameter(torch.tensor([1.0]))
|
| 110 |
-
optimizer = torch.optim.SGD([parameter], lr=0.02, momentum=0.9)
|
| 111 |
-
options = dict(first_cycle_steps=6, cycle_mult=2.0, max_lr=1.0,
|
| 112 |
-
min_lr=0.0, warmup_steps=2, gamma=0.5)
|
| 113 |
-
options.update(overrides)
|
| 114 |
-
scheduler = CosineAnnealingWarmupRestarts(optimizer, **options)
|
| 115 |
-
return parameter, optimizer, scheduler
|
| 116 |
-
|
| 117 |
-
def assert_lr(self, optimizer, scheduler, expected):
|
| 118 |
-
for group in optimizer.param_groups:
|
| 119 |
-
self.assertAlmostEqual(group["lr"], expected, places=12)
|
| 120 |
-
self.assertEqual(scheduler.get_last_lr(), [group["lr"] for group in optimizer.param_groups])
|
| 121 |
-
|
| 122 |
-
def test_zero_warmup_starts_at_max_and_decays_before_restart(self):
|
| 123 |
-
_, optimizer, scheduler = self.make_scheduler(
|
| 124 |
-
first_cycle_steps=4, cycle_mult=1.0, warmup_steps=0
|
| 125 |
-
)
|
| 126 |
-
expected = [1.0, (1 + math.cos(math.pi / 4)) / 2, 0.5,
|
| 127 |
-
(1 + math.cos(3 * math.pi / 4)) / 2, 0.5]
|
| 128 |
-
self.assert_lr(optimizer, scheduler, expected[0])
|
| 129 |
-
for target in expected[1:]:
|
| 130 |
-
optimizer.step()
|
| 131 |
-
scheduler.step()
|
| 132 |
-
self.assert_lr(optimizer, scheduler, target)
|
| 133 |
-
|
| 134 |
-
def test_warmup_and_restart_use_decayed_peak_and_longer_cycle(self):
|
| 135 |
-
_, optimizer, scheduler = self.make_scheduler()
|
| 136 |
-
expected = [0.0, 0.5, 1.0, (1 + math.cos(math.pi / 4)) / 2,
|
| 137 |
-
0.5, (1 + math.cos(3 * math.pi / 4)) / 2, 0.0, 0.25, 0.5]
|
| 138 |
-
self.assert_lr(optimizer, scheduler, expected[0])
|
| 139 |
-
for target in expected[1:]:
|
| 140 |
-
optimizer.step()
|
| 141 |
-
scheduler.step()
|
| 142 |
-
self.assert_lr(optimizer, scheduler, target)
|
| 143 |
-
scheduler.step(16)
|
| 144 |
-
self.assert_lr(optimizer, scheduler, 0.0)
|
| 145 |
-
scheduler.step(18)
|
| 146 |
-
self.assert_lr(optimizer, scheduler, 0.25)
|
| 147 |
-
|
| 148 |
-
def test_explicit_epoch_and_incremental_steps_match_across_cycles(self):
|
| 149 |
-
for cycle_mult in (1.0, 1.5, 2.0):
|
| 150 |
-
for warmup_steps in (0, 2):
|
| 151 |
-
with self.subTest(cycle_mult=cycle_mult, warmup_steps=warmup_steps):
|
| 152 |
-
options = dict(first_cycle_steps=5, cycle_mult=cycle_mult,
|
| 153 |
-
warmup_steps=warmup_steps)
|
| 154 |
-
_, sequential_optimizer, sequential = self.make_scheduler(**options)
|
| 155 |
-
_, explicit_optimizer, explicit = self.make_scheduler(**options)
|
| 156 |
-
for step in range(41):
|
| 157 |
-
if step:
|
| 158 |
-
sequential_optimizer.step()
|
| 159 |
-
sequential.step()
|
| 160 |
-
explicit.step(step)
|
| 161 |
-
self.assertAlmostEqual(
|
| 162 |
-
sequential_optimizer.param_groups[0]["lr"],
|
| 163 |
-
explicit_optimizer.param_groups[0]["lr"], places=12,
|
| 164 |
-
msg=f"Schedules differ at step {step}",
|
| 165 |
-
)
|
| 166 |
-
self.assertEqual(sequential.get_last_lr(), explicit.get_last_lr())
|
| 167 |
-
|
| 168 |
-
def test_resume_restores_learning_rates_and_optimizer_trajectory(self):
|
| 169 |
-
options = dict(max_lr=0.1, min_lr=0.001, gamma=0.7)
|
| 170 |
-
parameter, optimizer, scheduler = self.make_scheduler(**options)
|
| 171 |
-
|
| 172 |
-
def update(parameter, optimizer, scheduler):
|
| 173 |
-
parameter.grad = torch.ones_like(parameter)
|
| 174 |
-
optimizer.step()
|
| 175 |
-
optimizer.zero_grad()
|
| 176 |
-
scheduler.step()
|
| 177 |
-
return optimizer.param_groups[0]["lr"], parameter.detach().clone()
|
| 178 |
-
|
| 179 |
-
for _ in range(13):
|
| 180 |
-
update(parameter, optimizer, scheduler)
|
| 181 |
-
saved_parameter = parameter.detach().clone()
|
| 182 |
-
optimizer_state = copy.deepcopy(optimizer.state_dict())
|
| 183 |
-
scheduler_state = copy.deepcopy(scheduler.state_dict())
|
| 184 |
-
expected = [update(parameter, optimizer, scheduler) for _ in range(12)]
|
| 185 |
-
|
| 186 |
-
resumed_parameter, resumed_optimizer, resumed_scheduler = self.make_scheduler(**options)
|
| 187 |
-
with torch.no_grad():
|
| 188 |
-
resumed_parameter.copy_(saved_parameter)
|
| 189 |
-
resumed_optimizer.load_state_dict(optimizer_state)
|
| 190 |
-
resumed_scheduler.load_state_dict(scheduler_state)
|
| 191 |
-
self.assertEqual(resumed_scheduler.get_last_lr(),
|
| 192 |
-
[group["lr"] for group in resumed_optimizer.param_groups])
|
| 193 |
-
for expected_lr, expected_parameter in expected:
|
| 194 |
-
actual_lr, actual_parameter = update(resumed_parameter, resumed_optimizer, resumed_scheduler)
|
| 195 |
-
self.assertAlmostEqual(actual_lr, expected_lr, places=12)
|
| 196 |
-
torch.testing.assert_close(actual_parameter, expected_parameter, rtol=0, atol=0)
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
class _CompiledLike(torch.nn.Module):
|
| 200 |
-
"""Model the wrapper attribute exposed by torch.compile without compiling."""
|
| 201 |
-
|
| 202 |
-
def __init__(self, module):
|
| 203 |
-
super().__init__()
|
| 204 |
-
self._orig_mod = module
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
class _ScalerState:
|
| 208 |
-
def state_dict(self):
|
| 209 |
-
return {"scale": 1024.0, "_growth_tracker": 7}
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
class CheckpointTests(unittest.TestCase):
|
| 213 |
-
def test_checkpoint_schema_paths_and_unwrapped_model_parameters(self):
|
| 214 |
-
for use_wrappers in (False, True):
|
| 215 |
-
with self.subTest(use_wrappers=use_wrappers), tempfile.TemporaryDirectory() as temp_dir:
|
| 216 |
-
model = torch.nn.Linear(2, 1)
|
| 217 |
-
wrapped = _CompiledLike(torch.nn.DataParallel(model)) if use_wrappers else model
|
| 218 |
-
optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
|
| 219 |
-
scheduler = CosineAnnealingWarmupRestarts(
|
| 220 |
-
optimizer, first_cycle_steps=4, max_lr=0.1, min_lr=0.001,
|
| 221 |
-
warmup_steps=0,
|
| 222 |
-
)
|
| 223 |
-
optimizer.zero_grad()
|
| 224 |
-
model(torch.ones(1, 2)).sum().backward()
|
| 225 |
-
optimizer.step()
|
| 226 |
-
scheduler.step()
|
| 227 |
-
scaler = _ScalerState()
|
| 228 |
-
destination = Path(temp_dir) / "nested" / "checkpoints"
|
| 229 |
-
saved_path = save_scaler_ckpt(
|
| 230 |
-
"epoch3", wrapped, optimizer, scheduler, scaler, 0.125,
|
| 231 |
-
"tiny", str(destination),
|
| 232 |
-
)
|
| 233 |
-
self.assertIsInstance(saved_path, Path)
|
| 234 |
-
self.assertEqual(saved_path, destination / "tiny_epoch3.pth")
|
| 235 |
-
self.assertTrue(saved_path.is_file())
|
| 236 |
-
checkpoint = torch.load(saved_path, map_location="cpu", weights_only=True)
|
| 237 |
-
self.assertEqual(set(checkpoint), {
|
| 238 |
-
"epoch", "model_state_dict", "optimizer_state_dict",
|
| 239 |
-
"scheduler_state_dict", "scaler_state_dict", "losses",
|
| 240 |
-
})
|
| 241 |
-
self.assertEqual(checkpoint["epoch"], "epoch3")
|
| 242 |
-
self.assertEqual(checkpoint["losses"], 0.125)
|
| 243 |
-
self.assertEqual(checkpoint["scaler_state_dict"], scaler.state_dict())
|
| 244 |
-
self.assertEqual(checkpoint["scheduler_state_dict"], scheduler.state_dict())
|
| 245 |
-
self.assertEqual(checkpoint["optimizer_state_dict"]["param_groups"],
|
| 246 |
-
optimizer.state_dict()["param_groups"])
|
| 247 |
-
self.assertEqual(set(checkpoint["model_state_dict"]), {"weight", "bias"})
|
| 248 |
-
for name, expected in model.state_dict().items():
|
| 249 |
-
torch.testing.assert_close(checkpoint["model_state_dict"][name], expected, rtol=0, atol=0)
|
| 250 |
-
loaded_model = torch.nn.Linear(2, 1)
|
| 251 |
-
loaded_model.load_state_dict(checkpoint["model_state_dict"], strict=True)
|
| 252 |
-
loaded_optimizer = torch.optim.SGD(loaded_model.parameters(), lr=0.9, momentum=0.9)
|
| 253 |
-
loaded_optimizer.load_state_dict(checkpoint["optimizer_state_dict"])
|
| 254 |
-
for original_parameter, loaded_parameter in zip(model.parameters(), loaded_model.parameters()):
|
| 255 |
-
torch.testing.assert_close(
|
| 256 |
-
loaded_optimizer.state[loaded_parameter]["momentum_buffer"],
|
| 257 |
-
optimizer.state[original_parameter]["momentum_buffer"], rtol=0, atol=0,
|
| 258 |
-
)
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
if __name__ == "__main__":
|
| 262 |
-
unittest.main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
README.md
CHANGED
|
@@ -203,9 +203,6 @@ The drug-response and drug-combination workflows use validation metrics for
|
|
| 203 |
checkpoint selection. Their validation results should not be presented as
|
| 204 |
performance on an independent final test set.
|
| 205 |
|
| 206 |
-
For checks of the shared training utilities, see
|
| 207 |
-
[Training utility checks](BioMod/README.md#training-utility-checks).
|
| 208 |
-
|
| 209 |
## Repository layout
|
| 210 |
|
| 211 |
The tree below includes source files, model dependencies, and the pretrained
|
|
@@ -243,8 +240,6 @@ BioMod/ # Project root: s
|
|
| 243 |
β β βββ README.md
|
| 244 |
β β βββ train.py
|
| 245 |
β β βββ tutorial.ipynb
|
| 246 |
-
β βββ tests/ # CPU tests for shared training utilities
|
| 247 |
-
β β βββ test_training_utils.py
|
| 248 |
β βββ zero_shot_batch/ # Zero-shot integration and evaluation
|
| 249 |
β β βββ tools/ # Optional visualization and evaluation tools
|
| 250 |
β β β βββ sequencing_depth/ # Low-depth expression generation and evaluation
|
|
|
|
| 203 |
checkpoint selection. Their validation results should not be presented as
|
| 204 |
performance on an independent final test set.
|
| 205 |
|
|
|
|
|
|
|
|
|
|
| 206 |
## Repository layout
|
| 207 |
|
| 208 |
The tree below includes source files, model dependencies, and the pretrained
|
|
|
|
| 240 |
β β βββ README.md
|
| 241 |
β β βββ train.py
|
| 242 |
β β βββ tutorial.ipynb
|
|
|
|
|
|
|
| 243 |
β βββ zero_shot_batch/ # Zero-shot integration and evaluation
|
| 244 |
β β βββ tools/ # Optional visualization and evaluation tools
|
| 245 |
β β β βββ sequencing_depth/ # Low-depth expression generation and evaluation
|