Skip to content

Commit 16dda06

Browse files
authored
Reapply chunker (#37292)
* Reapply chunker * good size * rm glob * cleaner * back to 45mb * warp need not be fixed * add manifest path * lil cleaner
1 parent 76d084d commit 16dda06

6 files changed

Lines changed: 60 additions & 68 deletions

File tree

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,7 @@ flycheck_*
6464
cppcheck_report.txt
6565
comma*.sh
6666

67-
selfdrive/modeld/models/*.pkl
68-
selfdrive/modeld/models/*.pkl.*
67+
selfdrive/modeld/models/*.pkl*
6968

7069
# openpilot log files
7170
*.bz2

common/file_chunker.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import math
2+
import os
3+
from pathlib import Path
4+
5+
CHUNK_SIZE = 45 * 1024 * 1024 # 45MB, under GitHub's 50MB limit
6+
7+
def get_chunk_name(name, idx, num_chunks):
8+
return f"{name}.chunk{idx+1:02d}of{num_chunks:02d}"
9+
10+
def get_manifest_path(name):
11+
return f"{name}.chunkmanifest"
12+
13+
def get_chunk_paths(path, file_size):
14+
num_chunks = math.ceil(file_size / CHUNK_SIZE)
15+
return [get_manifest_path(path)] + [get_chunk_name(path, i, num_chunks) for i in range(num_chunks)]
16+
17+
def chunk_file(path, targets):
18+
manifest_path, *chunk_paths = targets
19+
with open(path, 'rb') as f:
20+
data = f.read()
21+
actual_num_chunks = max(1, math.ceil(len(data) / CHUNK_SIZE))
22+
assert len(chunk_paths) >= actual_num_chunks, f"Allowed {len(chunk_paths)} chunks but needs at least {actual_num_chunks}, for path {path}"
23+
for i, chunk_path in enumerate(chunk_paths):
24+
with open(chunk_path, 'wb') as f:
25+
f.write(data[i * CHUNK_SIZE:(i + 1) * CHUNK_SIZE])
26+
Path(manifest_path).write_text(str(len(chunk_paths)))
27+
os.remove(path)
28+
29+
30+
def read_file_chunked(path):
31+
manifest_path = get_manifest_path(path)
32+
if os.path.isfile(manifest_path):
33+
num_chunks = int(Path(manifest_path).read_text().strip())
34+
return b''.join(Path(get_chunk_name(path, i, num_chunks)).read_bytes() for i in range(num_chunks))
35+
if os.path.isfile(path):
36+
return Path(path).read_bytes()
37+
raise FileNotFoundError(path)

selfdrive/modeld/SConscript

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import os
22
import glob
3+
from openpilot.common.file_chunker import chunk_file, get_chunk_paths
34

45
Import('env', 'arch')
6+
chunker_file = File("#common/file_chunker.py")
57
lenv = env.Clone()
6-
CHUNK_BYTES = int(os.environ.get("TG_CHUNK_BYTES", str(45 * 1024 * 1024)))
78

89
tinygrad_root = env.Dir("#").abspath
910
tinygrad_files = ["#"+x for x in glob.glob(env.Dir("#tinygrad_repo").relpath + "/**", recursive=True, root_dir=tinygrad_root)
1011
if 'pycache' not in x and os.path.isfile(os.path.join(tinygrad_root, x))]
1112

13+
def estimate_pickle_max_size(onnx_size):
14+
return 1.2 * onnx_size + 10 * 1024 * 1024 # 20% + 10MB is plenty
15+
1216
# Get model metadata
1317
for model_name in ['driving_vision', 'driving_policy', 'dmonitoring_model']:
1418
fn = File(f"models/{model_name}").abspath
@@ -26,39 +30,29 @@ image_flag = {
2630
'larch64': 'IMAGE=2',
2731
}.get(arch, 'IMAGE=0')
2832
script_files = [File(Dir("#selfdrive/modeld").File("compile_warp.py").abspath)]
29-
cmd = f'{tg_flags} python3 {Dir("#selfdrive/modeld").abspath}/compile_warp.py '
33+
compile_warp_cmd = f'{tg_flags} python3 {Dir("#selfdrive/modeld").abspath}/compile_warp.py '
3034
from openpilot.common.transformations.camera import _ar_ox_fisheye, _os_fisheye
3135
warp_targets = []
3236
for cam in [_ar_ox_fisheye, _os_fisheye]:
3337
w, h = cam.width, cam.height
3438
warp_targets += [File(f"models/warp_{w}x{h}_tinygrad.pkl").abspath, File(f"models/dm_warp_{w}x{h}_tinygrad.pkl").abspath]
35-
lenv.Command(warp_targets, tinygrad_files + script_files, cmd)
39+
lenv.Command(warp_targets, tinygrad_files + script_files, compile_warp_cmd)
3640

3741
def tg_compile(flags, model_name):
3842
pythonpath_string = 'PYTHONPATH="${PYTHONPATH}:' + env.Dir("#tinygrad_repo").abspath + '"'
3943
fn = File(f"models/{model_name}").abspath
40-
41-
out = fn + "_tinygrad.pkl"
42-
full = out + ".full"
43-
parts = out + ".parts"
44-
45-
full_node = lenv.Command(
46-
full,
47-
[fn + ".onnx"] + tinygrad_files,
48-
f'{pythonpath_string} {flags} {image_flag} python3 {Dir("#tinygrad_repo").abspath}/examples/openpilot/compile3.py {fn}.onnx {full}'
44+
pkl = fn + "_tinygrad.pkl"
45+
onnx_path = fn + ".onnx"
46+
chunk_targets = get_chunk_paths(pkl, estimate_pickle_max_size(os.path.getsize(onnx_path)))
47+
def do_chunk(target, source, env):
48+
chunk_file(pkl, chunk_targets)
49+
return lenv.Command(
50+
chunk_targets,
51+
[onnx_path] + tinygrad_files + [chunker_file],
52+
[f'{pythonpath_string} {flags} {image_flag} python3 {Dir("#tinygrad_repo").abspath}/examples/openpilot/compile3.py {fn}.onnx {pkl}',
53+
do_chunk]
4954
)
5055

51-
split_script = File(Dir("#selfdrive/modeld").File("external_pickle.py").abspath)
52-
parts_node = lenv.Command(
53-
parts,
54-
[full_node, split_script, Value(str(CHUNK_BYTES))],
55-
[f'python3 {split_script.abspath} {full} {out} {CHUNK_BYTES}', Delete(full)],
56-
)
57-
58-
lenv.NoCache(parts_node)
59-
lenv.AlwaysBuild(parts_node)
60-
return parts_node
61-
6256
# Compile small models
6357
for model_name in ['driving_vision', 'driving_policy', 'dmonitoring_model']:
6458
tg_compile(tg_flags, model_name)

selfdrive/modeld/dmonitoringmodeld.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
from openpilot.common.transformations.model import dmonitoringmodel_intrinsics
1717
from openpilot.common.transformations.camera import _ar_ox_fisheye, _os_fisheye
1818
from openpilot.system.camerad.cameras.nv12_info import get_nv12_info
19+
from openpilot.common.file_chunker import read_file_chunked
1920
from openpilot.selfdrive.modeld.parse_model_outputs import sigmoid, safe_exp
20-
from openpilot.selfdrive.modeld.external_pickle import load_external_pickle
2121

2222
PROCESS_NAME = "selfdrive.modeld.dmonitoringmodeld"
2323
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
@@ -45,7 +45,7 @@ def __init__(self):
4545
self.tensor_inputs = {k: Tensor(v, device='NPY').realize() for k,v in self.numpy_inputs.items()}
4646
self._blob_cache : dict[int, Tensor] = {}
4747
self.image_warp = None
48-
self.model_run = load_external_pickle(MODEL_PKL_PATH)
48+
self.model_run = pickle.loads(read_file_chunked(str(MODEL_PKL_PATH)))
4949

5050
def run(self, buf: VisionBuf, calib: np.ndarray, transform: np.ndarray) -> tuple[np.ndarray, float]:
5151
self.numpy_inputs['calib'][0,:] = calib

selfdrive/modeld/external_pickle.py

Lines changed: 0 additions & 38 deletions
This file was deleted.

selfdrive/modeld/modeld.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
from openpilot.selfdrive.controls.lib.drive_helpers import get_accel_from_plan, smooth_value, get_curvature_from_plan
2828
from openpilot.selfdrive.modeld.parse_model_outputs import Parser
2929
from openpilot.selfdrive.modeld.fill_model_msg import fill_model_msg, fill_pose_msg, PublishState
30+
from openpilot.common.file_chunker import read_file_chunked
3031
from openpilot.selfdrive.modeld.constants import ModelConstants, Plan
31-
from openpilot.selfdrive.modeld.external_pickle import load_external_pickle
3232

3333

3434
PROCESS_NAME = "selfdrive.modeld.modeld"
@@ -178,8 +178,8 @@ def __init__(self):
178178
self.parser = Parser()
179179
self.frame_buf_params : dict[str, tuple[int, int, int, int]] = {}
180180
self.update_imgs = None
181-
self.vision_run = load_external_pickle(VISION_PKL_PATH)
182-
self.policy_run = load_external_pickle(POLICY_PKL_PATH)
181+
self.vision_run = pickle.loads(read_file_chunked(str(VISION_PKL_PATH)))
182+
self.policy_run = pickle.loads(read_file_chunked(str(POLICY_PKL_PATH)))
183183

184184
def slice_outputs(self, model_outputs: np.ndarray, output_slices: dict[str, slice]) -> dict[str, np.ndarray]:
185185
parsed_model_outputs = {k: model_outputs[np.newaxis, v] for k,v in output_slices.items()}

0 commit comments

Comments
 (0)