mix_fingerprint: fold the manifest's per-shard sha256 into the corpus identity (names+sizes could collide across rebuilds); phase4_session repins shard_dataset
Browse files- train/shard_dataset.py +11 -3
train/shard_dataset.py
CHANGED
|
@@ -151,12 +151,20 @@ def save_cursor(dirpath, cur):
|
|
| 151 |
|
| 152 |
|
| 153 |
def mix_fingerprint(root, manifest=None):
|
| 154 |
-
"""Cheap, stable identity for the exact data being trained on
|
| 155 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
import hashlib
|
| 157 |
man = manifest or json.load(open(os.path.join(root, "manifest.json")))
|
| 158 |
h = hashlib.sha256()
|
| 159 |
for s in man["shards"]:
|
| 160 |
p = os.path.join(root, s["file"])
|
| 161 |
-
h.update(f"{s['file']}:{
|
|
|
|
| 162 |
return h.hexdigest()[:16]
|
|
|
|
| 151 |
|
| 152 |
|
| 153 |
def mix_fingerprint(root, manifest=None):
|
| 154 |
+
"""Cheap, stable identity for the exact data being trained on. Used by the trainer to refuse a resume
|
| 155 |
+
onto a different corpus, so it has to be computed the same way in every session.
|
| 156 |
+
|
| 157 |
+
Names alone (or names and sizes, as this function did until the E-031 review) are too weak: a rebuilt
|
| 158 |
+
mix whose shards happen to land on the same sizes is a different corpus, and the whole point of the
|
| 159 |
+
check is to catch a corpus swap between sessions. The manifest already certifies a sha256 per shard,
|
| 160 |
+
so folding it in costs nothing and needs no file reads; the local size is included as well so a
|
| 161 |
+
truncated file on disk cannot hide behind a manifest that still describes the good one.
|
| 162 |
+
"""
|
| 163 |
import hashlib
|
| 164 |
man = manifest or json.load(open(os.path.join(root, "manifest.json")))
|
| 165 |
h = hashlib.sha256()
|
| 166 |
for s in man["shards"]:
|
| 167 |
p = os.path.join(root, s["file"])
|
| 168 |
+
h.update(f"{s['file']}:{s.get('sha256')}:"
|
| 169 |
+
f"{os.path.getsize(p) if os.path.exists(p) else 'missing'}\n".encode())
|
| 170 |
return h.hexdigest()[:16]
|