Repository navigation
Running a County
The standing order for producing Year Built predictions for one county. Scope is one county — all of its polygon parts — per run, which is what the runner and the tray task are built for.
This page is the operator entry point. Using-the-ConsoleApp is the reference for every option and exit code; this page says what to run, in what order, and how to know it worked.
Important
The detections and scoring passes are now a single run. They used to be two, and the second one rebuilt its building list from the results file on disk rather than from the detection columns already stored — so a scratch directory cleaned between them skipped the county in silence. See §2. The split passes remain available for manual recovery (§6).
The tray application finds the runner in extensions\DiGi.GIS.YOLO.UI.ConsoleApp beside its own executable, an optional part of the deployment: a machine without it simply does not offer Predict year built. DiGi.GIS.YOLO.UI#7 still has to exercise that task on a deployed host for the first time.
Dating is detector-only. The stored year is no longer predicted by a model: a building is dated by the first confident detection — the first year the detector saw it at confidence ≥ 0.5, falling back to the first year it was seen at all — and every prediction is stamped first-confident-detection@0.5 instead of a model file's SHA-256. The rule reads the detection group of building_data — the 90 columns this pipeline writes — and never the detections the run has just parsed.
Different runs fill different parts of that table, and a group that is wholly absent or wholly default is a run that has not happened — which nothing can tell apart from a sparse county. The retired regressor proved the point the expensive way: Słupski was scored for 44 492 buildings with 108 of 172 features at zero, and exited 0.
Query.UnpopulatedColumnNames is the guard. A county whose required group — the detection group, since the dating reads it alone — is wholly empty is refused (exit 4), with the run that fills it named in the message; a partially empty group is a warning. The other feature groups are still checked and warned about but no longer gate a run: the regressor that needed them is retired. It is structural rather than a percentage on purpose — roughly 40 of the 90 detection columns are legitimately near-constant per county, and which 40 varies, so a percentage bound would have to be loosened until it stopped detecting anything.
| Feature group | Columns | Filled by |
|---|---|---|
| base | 31 |
Update building data — General, Database, Occupancy
|
| grid cell coverage | 25 |
Update building data — General
|
| radial ratio | 8 |
Update building data — RadialRatios
|
| population | 18 |
Update building data — Statistical
|
| detection | 90 |
this pipeline, with UpdateDetections
|
| total | 172 |
| # | Where | What | Cost |
|---|---|---|---|
| 0 | PowerShell | CheckBuildingDataColumns.ps1 -CountyId <id> -Group |
seconds |
| 1 | Tray app → Update building data |
General, Database, Occupancy, RadialRatios, Statistical
|
minutes to hours |
| 2 | Console app, or tray app → Predict year built | one run: export imagery, run the detector, write the 90 detection columns, score, write year_built_data and the column |
hours — dominated by inference |
| 3 | Tray app → Update building data |
YearBuilt only — skip when step 2 ran with UpdatePredictedYearBuilt
|
minutes |
Steps 2 and 3 used to be two separate runs, to make the ordering explicit rather than incidental. They are now one, because the split carried a gap that the explicitness did not pay for: the scoring pass rebuilds its list of buildings from results.bbrf on disk, never from the detection columns it had just written to building_data. A scratch directory cleaned between the two runs therefore skipped the county reporting exactly what a county with no detections at all reports — and only one of those is recoverable. A single run has no between, and CleanScratchDirectory (default true) removes the scratch folder of each county that completes, so nothing can grow the same dependency again.
The hazard that motivated the split is handled directly instead: when the detection write half-fails, the run now skips scoring that county rather than scoring it against columns that are partly this run's and partly whatever preceded them. The county is named in FailedStepNames and re-run.
The split passes are still available for manual recovery — §6 — and their templates set CleanScratchDirectory: false, which is what makes them work at all.
PowerShell -ExecutionPolicy Bypass -File "DiGi.Maintenance/Scripts/CheckBuildingDataColumns.ps1" -CountyId 104106 -GroupA prepared county (104106, m. Świnoujście) against one that has never been swept (73485, part of słupski):
base 31 / 31 fully filled: 29 base 31 / 31 fully filled: 29
grid cell coverage 25 / 25 fully filled: 25 grid cell coverage 25 / 25 fully filled: 25
detection 90 / 90 fully filled: 0 detection 90 / 90 fully filled: 0
population 18 / 18 fully filled: 16 population 18 / 18 fully filled: 0
radial ratio 8 / 8 fully filled: 8 radial ratio 8 / 8 fully filled: 8
104106 — ready 73485 — not ready
Warning
detection … fully filled: 0 is normal, including on a fully prepared county. The left column above is 104106 — 5 538 buildings scored and written — and it still reads 0. Detection columns are sparse by nature: a building is not detected in every year, so no per-year column is full for every row. Do not read that line as "no detections".
The readiness signal is the population row (16/18 versus 0/18) plus the pipeline's own refusal. The x / y figure on the left is existence in the catalogue, which is global — it is the same for every county and says nothing about this one.
Call this sequentially, never against several counties at once: concurrent coverage calls exhaust the connection pool and the host answers 500 on every terrain endpoint until the service is restarted.
Tray application (DiGi.GIS.PostgreSQL.UI) → Update building data, scoped to the county, with these update types selected:
General · Database · Occupancy · RadialRatios · Statistical
This is 82 of the 172 features, and it is the step słupski never got. Statistical needs a populated unit and statistical_data_collection hierarchy; without one it writes nothing, and the run now reports that as an unfulfilled update type rather than as success.
Doing this for every county is DiGi.GIS.PostgreSQL#61.
Tray application first. Predict year built asks for the run's scope and nothing else: the counties, the scratch directory, the interpreter, Max concurrent requests, and Clean scratch directory. Five controls.
Caution
A tray run has one shape, and it writes. OK means the full six-step flow — export, detector, write detections, score, write history, write column — over the deployed data of every county selected. There is no read-only tray run any more; the dialog says so above the county list, and the task names the counties back in a confirmation before it launches anything. For a dry run, or for either half of the split recovery passes, use the console app and a template below.
That is #8's decision applied: the six flags stay on the options class and the console app for hand-driven diagnostics, and "only the tray-driven default flow collapses them into one combined run." Eight checkboxes offered 256 combinations of which three were real — the three templates below — and the rest failed late, after the export and the inference had already been paid for.
Fourteen members are deliberately not in the dialog. A console run settles them in the options file below; a tray run has no options file to read, so it takes them from the defaults on YearBuiltPredictionPipelineOptions and writes the result into the scratch directory. Those defaults are therefore part of the tray contract rather than a convenience — see the note under ModelPath.
| Not in the dialog | Why |
|---|---|
ExportImages, RunPrediction, Score, UpdateDetections, UpdateYearBuiltData, UpdatePredictedYearBuilt
|
A tray run is all six. Written on by the prompt, so a run that stored nothing while reporting success is not reachable from the tray. |
Resume |
Fixed on. With the cleanup on it only helps inside one run and on the retry of a county that failed — which keeps its scratch folder for exactly that reason — so off is never the better answer. |
Years, Radiuses
|
They decide which columns the feature projection asks for. |
Confidence |
Passed to the detector as --conf; every detection it lets through is written into the ninety Prediction Confidence <year> columns the model reads back. |
ModelPath |
Different weights produce different detections, through the same columns. A path typed in the tray application would also be resolved in the runner's directory, so the dialog could not say whether the file exists. It defaults to user files/YOLO/models/model.pt, which is where the deployment puts the weights — a tray run has no other way to name them, and the default is what makes one work at all. |
WorkingDirectory |
Not a choice: the runner writes predict.py and utils.py into it, and left null it is the county's own scratch folder. |
BatchSize |
Sizes the write requests only — it never reaches the detector, so it does nothing at all until a write step is on. |
ReferenceBatchSize |
One sensible value: above the endpoint's 10 000 cap is refused server side, below it is the same work in more requests. |
The first four are one hazard: each of them changes what the dating is handed, and a value that disagrees with the predictor's contract drops columns the rule reads — a Years window that cuts off a building's first detection dates it late, by an amount nothing measures. Two of the four are now caught before any county is read: the run checks Years and Radiuses against the range and radiuses the predictor states it reads — the first-detection rule states exactly what the options' defaults name (2008..2025, the default radiuses) — so a projection that omits a feature it reads is refused (exit code 1) and one that adds features is reported as surplus and ignored (DiGi.GIS.ML#6). Confidence and ModelPath are not — they change the values the detector writes, not the columns the rule reads, and the guard sees only column names, so a wrong threshold or wrong weights still scores without failing. With UpdateDetections on, those are stored into building_data and read back by every later dating run, so the mistake outlives the run that made it. Leave Years and Radiuses null, and leave Confidence and ModelPath at the values the deployed weights were trained against.
A tray run — tray application → Predict year built — is the same run started for you: the task forces the six step and write flags on (ExportImages, RunPrediction, Score, UpdateDetections, UpdateYearBuiltData, UpdatePredictedYearBuilt), fixes Resume: true, supplies the county identifiers and an absolute ScratchDirectory, and leaves Years, Radiuses, Confidence and ModelPath at their defaults; CleanScratchDirectory is the one flag it offers as a choice.
One invocation does all six steps: export the imagery, run the detector, write the detection columns, score, write the history and write the column. The committed default already has its final name — put your county identifiers in, then run from the runner's own folder, so relative paths resolve against it:
.\DiGi.GIS.YOLO.UI.ConsoleApp.exe "YearBuiltPredictionPipelineOptions.json"The runner's own folder is not the same place on a deployed machine. In a workspace checkout it is DiGi.GIS.YOLO.UI\bin; on a deployed host the runner ships as an optional extension of the tray application and lives in <DiGi.GIS.PostgreSQL.UI>\extensions\DiGi.GIS.YOLO.UI.ConsoleApp. The weights, the .mlnet model and the runner's own GIS_WebAPI_Client.conf sit beside the executable in both.
Edits in the runner folder do not survive the next build — CopyFiles re-copies the committed default — so a permanent local configuration belongs in user files/YearBuiltPredictionPipelineOptions.json, which CopyUserFiles overwrites onto it. That overwrite reaches the deployed folder too, so the YearBuiltPredictionPipelineOptions.json sitting next to a deployed runner is whatever was in the build machine's user files, not the committed default — check its CountyIds before running it by name.
YearBuiltPredictionPipelineOptions.json — the combined template, and only that one — ships with all three write flags off, so copying it cannot write deployed data by accident. The two split templates in §6 do not: …Score.json ships UpdateYearBuiltData and UpdatePredictedYearBuilt both true, and …Detections.json ships UpdateDetections: true. Read the flags of whichever file you copied rather than trusting the folder.
The off-by-default combined template is not the configuration that populates a county — for a real run:
{
"CountyIds": [ 104106 ],
"ScratchDirectory": "scratch",
"ModelPath": "user files/YOLO/models/model.pt",
"PythonPath": null,
"WorkingDirectory": null,
"Confidence": 0.1,
"Years": null,
"Radiuses": null,
"MaxConcurrentRequests": 8,
"BatchSize": 5000,
"ReferenceBatchSize": 10000,
"Resume": true,
"CleanScratchDirectory": true,
"ExportImages": true,
"RunPrediction": true,
"Score": true,
"UpdateDetections": true,
"UpdateYearBuiltData": true,
"UpdatePredictedYearBuilt": true
}UpdateDetections writes the 90 detection columns before the dating step reads them back, inside the same loop — which is why one run works where two used to need an order between them.
Caution
A read-only pass is not the first pass over a new county. Dating reads the detection columns from building_data, so with UpdateDetections: false on a county that has never had them written, Score is refused with exit code 4 and the missing detection group named with its remedy. That is the guard working, not a misconfiguration. The first run over a county writes the detections; a dry run — every write flag false — is only meaningful afterwards.
What lands on disk while the run is working, per county identifier:
<ScratchDirectory>/<countyId>/images/<reference>_<year>.jpeg
<ScratchDirectory>/<countyId>/results.bbrf
With CleanScratchDirectory at its default this is gone once the county finishes — provided the county recorded no failed step. A county that failed keeps its folder, so correcting the cause and re-running costs seconds instead of repeating the export and the inference. A cancelled county is cleaned: stopping a run is a deliberate act, not a failure.
The scratch root is never removed: the tray application writes the options a run was started with into it, and that is the only record of what the run was asked to do.
Cost. Measured over słupski, both polygon parts: 417 034 images, 372 347 detections over 44 492 buildings, with the export taking 30.5 minutes. Inference dominates the rest at 11.9–12.8 ms/image on CUDA — roughly 85 minutes for that county. On CPU it is about fifteen times slower and not worth starting.
A successful run prints its tallies. This is 104106, the whole six-step flow in one run:
Buildings: 5538 Images: 55366 Detections: 52675
Predictions: 5538
Building Data updated: 11076 Year Built Data updated: 5538
Note
Building Data updated is not a row count, and on a combined run it is twice the building count. It accumulates at two places — once when the detection columns are written and once when the predicted year built column is — so a run with both steps on counts every building twice. 2 × 5538 = 11 076. Only a run with one of the two on prints a figure equal to the buildings, which is what the split templates in §6 do. Compare it against the buildings, doubled, rather than against the buildings.
Warning
Resume no longer helps across runs for a county that succeeded. Its folder is gone, which is the point of §2. A county that failed keeps everything, so Resume still makes the retry cheap — this is what saves the read-only pass over a fresh county, which is refused by the feature coverage guard only after the export and the inference have already been paid for. A cancelled county is cleaned and does restart from the export, so set CleanScratchDirectory: false before a run you expect to interrupt — the tray prompt's Clean scratch directory checkbox is where.
The two-pass templates are still committed and still work. Use them for a detections-only diagnostic pass, to score imagery a previous run left on disk, or to recover a run that failed after the expensive steps. Both set CleanScratchDirectory: false, which is what makes the hand-off between them possible at all.
.\DiGi.GIS.YOLO.UI.ConsoleApp.exe "YearBuiltPredictionPipelineOptions.Detections.json".\DiGi.GIS.YOLO.UI.ConsoleApp.exe "YearBuiltPredictionPipelineOptions.Score.json"The detections pass runs ExportImages/RunPrediction/UpdateDetections with Score off, so it never reaches the dating step and needs no model of any kind. The scoring pass runs with ExportImages/RunPrediction off, reading results.bbrf straight off disk — minutes rather than hours.
Important
The scoring pass depends on the detections pass's scratch directory still being there. If it is not, the county is refused with exit code 4 naming the path that was looked for. It is no longer reported as a county with no detections, which is what made this gap invisible in the first place.
Re-running is cheap. With Resume: true and CleanScratchDirectory: false, a second detections pass skipped the whole export in 4.5 seconds, and the detector reproduced results.bbrf byte for byte — so the frozen detector is demonstrably deterministic over the same imagery.
Want a read-only dry run? Take the combined file and set UpdateDetections, UpdateYearBuiltData and UpdatePredictedYearBuilt to false. It scores and reports without storing anything — on a county whose detections are already stored, per the caution in §5.
Tray application → Update building data with YearBuilt only. This rebuilds the three year-built columns from the stored year_built_data history: Predicted year built (the most frequent prediction when a building carries several), User year built (the most frequent entry when several users gave one) and Calculated year built (the user entry when one exists, otherwise the predicted year).
It is redundant for the predicted column when step 2 ran with UpdatePredictedYearBuilt: true, which writes that column from the same merged data. It is the path that (re)projects all three — use it after a history correction, after a user entry, or for a county predicted before the columns existed.
Through api.digiproject.uk, sequentially, never against a local .conf — a .conf reaches a partial development database.
| Check | How |
|---|---|
| The columns exist |
GET gis/buildingdata/columns — Predicted year built, User year built and Calculated year built are all in the catalogue |
| Features filled |
CheckBuildingDataColumns.ps1 -CountyId <id> -Group again; the population group full and the detection group no longer wholly default |
| History written |
GET gis/yearbuiltdata/itemsbyreferences — each reference carries a PredictedYearBuilt stamped with the run timestamp |
| Predictor identity | the run log carries Model SHA-256: 2dd833e4… for the weights and Year built predictor: first-confident-detection@0.5 for the dating rule |
| No stranded rows | reference count in equals stored object count out, none duplicated |
| Labels preserved | references that carried a UserYearBuilt still carry it — the run adds to the history, it does not replace it |
| Calculated follows the rule | where a building has both, Calculated year built equals its User year built; otherwise its Predicted year built
|
| Idempotent | run step 2 again: same object count, two run stamps, labels intact, column overwritten rather than duplicated |
One stamp per run: PredictedYearBuilt.Source is Prediction_{ticks} and the stored datum keys on it, so a re-run adds one history entry per county rather than one per building.
| Code | Meaning | First thing to check |
|---|---|---|
0 |
Succeeded | — |
1 |
Configuration | Options file found? CountyIds positive? ScratchDirectory non-empty? Identifiers, not codes? Or a Years/Radiuses projection narrower than the predictor's contract (feature-contract refusal)? |
2 |
Environment preflight | Python 3.9+ with ultralytics and torch, or the detector weights ModelPath resolves to. Both are checked before a single image is exported; the dating rule needs no model file |
3 |
Authorization |
GIS_WebAPI_Client.conf beside the runner — see §10 |
4 |
Pipeline failure | Read the [NOTE] lines: an unresolvable county, or a refused feature group naming the run that fills it |
5 |
Cancelled |
Ctrl+C. Written rows stay committed. Cancelling is not a failure, so the county in progress is still cleaned unless CleanScratchDirectory: false
|
Anything other than 0 means no run finished. The tallies of a cancelled or killed run are not a record of what was stored.
-
County identifiers, never four-character codes.
2212is a code; słupski is the two rows73482and73485. Eighteen counties have disconnected territory and BDOT10k stores each part as its own row, so a multi-part county needs every part listed inCountyIds.Query.UnknownCountyIdsrefuses a code up front and prints the identifiers it maps to — before this guard existed, a run scoped to2212exported nothing, wrote nothing and exited0. -
Leave
YearsandRadiusesnull. They decide which columns the projection asks for. The run now checks them against the range and radiuses the predictor states it reads — the first-detection rule states the same defaults (2008..2025, the default radiuses) — and refuses a narrower projection before it reads a county (exit code 1, naming the missing columns); a wider one runs with the surplus reported — DiGi.GIS.ML#6.Yearsis a range object ({ "Min": 2008, "Max": 2025 }), not a list. -
There are two
GIS_WebAPI_Client.conffiles. The tray application authorizes with its own; the runner authorizes with the one beside its own executable. An exit3from a tray-started run is almost always the runner's file, not the one the tray app uses. -
Host flags gate every write.
AllowUpdateBuildingDataandAllowUpdateYearBuiltDataare read with no default, so an absent flag isfalseand every write returns401however valid the key is. -
Misspelt options are dropped silently. Deserialization ignores unknown properties, so a typo means the default, not an error. Check casing against
YearBuiltPredictionPipelineOptions.json. -
Only detected buildings are dated. A building the detector never fired on has no detection series — the rule's only input — so it is skipped rather than dated on a blank vector, and its stored
Predicted year builtis cleared rather than left stale (#28): a building this run exported and the detector never fired on loses the year an earlier run stored for it, while its user entry is never touched. A building with no stored imagery was never exported, so it is neither dated nor cleared. The pipeline therefore predicts for fewer buildings than the deprecated file-based workflow, which scored every row of its table. -
Started from the tray app, paths behave differently — and a relative scratch path lands inside the deployment. The two processes do not share a working directory, so the tray task makes
ScratchDirectoryandWorkingDirectoryabsolute before handing them over, and writes the options it used into the scratch directory asYearBuiltPredictionPipelineOptions.json. It resolves them against the tray application's own folder, which on a deployed host is the deployment directory itself — so a barescratchexports tens of thousands of images into the installed application, and into whatever backs it up or syncs it. Type an absolute path on a local disk.ModelPathis deliberately left relative and is resolved against the runner instead, so the weights are found beside it in both a checkout and a deployment. -
CleanScratchDirectorydefaults totrue, and it fires on cancellation but not on failure. A county that completes has its scratch folder removed — that is what closes the pass 1 / pass 2 gap. A county that failed keeps everything, so the retry is cheap. A cancelled county is cleaned, because stopping a run is a deliberate act rather than a failure. Set it tofalsefor anything you intend to resume or to score in a second pass — the split templates already do. - Stopping the tray task kills the run. The whole process tree goes, detector included, so a batch being written may be half written. Every step is idempotent and a stopped run is re-runnable, but its tallies are not a record of what was stored.
-
On a machine that also holds a checkout, two tray applications carry the same icon.
DiGi.GIS.PostgreSQL.UI.Application.exeruns from the deployment and fromDiGi.GIS.PostgreSQL.UI\bin, both find a runner beside themselves underextensions\, and neither says which one you opened. Confirm it before concluding anything about a deployment: the log the run writes is under the folder the application was started from, andGet-Process DiGi.GIS.PostgreSQL.UI.Application | Select-Object Pathsettles it. A run started frombinalso holds its assemblies open against the next build.
The deployed identity, shipped on 2026-10-08:
| Identity | |
|---|---|
Detector model.pt: train9_fresh, YOLO26x, ultralytics 8.4.165
|
SHA-256 2dd833e438ffcb1352ae7675063c9f0c97ca1c39ce6410a0bfab96e8b3cbdc9a
|
| Dating rule, stamped on every stored prediction | first-confident-detection@0.5 |
The detector still ships with OrtoBuildingDetectionModel.mlnet (2e120f495e830f0917cace33ad21c5c4c7bb0c4e8f1711a363682932b7c0b7fa) beside the runner, but the regressor is retired from production: scored on counties it was not trained on, every retrained regressor came out years too late, while the first-detection rule matched those counties' labels with MAE 0.15 (DiGi.GIS.ML#15). It stays as the evaluation baseline every new model must beat.
-
The parked regressor's training data: 25 008 labelled buildings over 217 counties, on
train9_freshdetections. - Its held-out accuracy (through the deployed path): 0.338 MAE / 1.271 RMSE / R² 0.896 on the random 20 % holdout, against the first-detection rule's 0.358 / 1.797 / 0.791 on the same detections. On the 179 buildings no model has seen, the regressor scores 1.251 / 2.609 / 0.601.
The detections are still what the dating reads. The rule works off a building's stored detection columns, so before a county is dated its detections must have been written by train9_fresh. A run with RunPrediction, UpdateDetections and Score all on does that in one pass. A score-only run over a county whose stored detections are still train8's dates buildings from an old detector's series, and nothing refuses it: the coverage guard sees populated columns. The every-county rewrite is #23. The detection write replaces each scored building's detection columns (#21), so no train8 value survives on a building the new detector looked at. A building this run exported that the detector never fires on has its stored Predicted year built cleared — never left stale — and its user entry is untouched (#28); a building with no stored imagery was never exported and is never cleared.
Scoring one of the labelled counties measures fit and the write path, not generalisation. Most labelled buildings sit in five counties; the 179 clean buildings over 112 others are the only out-of-sample check, and they are few (DiGi.GIS.ML#4).
Narrowing a run to a list of buildings. ReferencesFilePath names a dataset_references.tsv manifest. Every step is then limited to its buildings within the named CountyIds, as for the detection rewrite before a regressor retrain (#22). A manifest that does not read refuses the run (exit 1). For such a training-side run, set an absolute ScratchDirectory in the training directory: a relative one lands in the runner's bin.
These are used when the detector is retrained (#12), not when a county is scored. All three modes read one options file, YOLOTrainingDatasetOptions.json, and only --dataset talks to the Web API. The full rules (labels, holdout, duplicates, Legacy, the manifest) are in the README.
| Step | Command | Stop if |
|---|---|---|
| 0 | Run the Year Built building-data update for the counties (§4). The labels are the User year built column it writes. |
— |
| 1 |
DiGi.GIS.YOLO.UI.ConsoleApp.exe --dataset options.json with "CountOnly": true (the template's default). Post the table on #12. |
the counts, the Legacy agreement table or the estimate look wrong |
| 2 | The same command with "CountOnly": false and an absolute, new or empty OutputDirectory. |
exit ≠ 0: read the [NOTE] lines. Re-running continues where it stopped. |
| 3 |
--check-labels options.json with ModelPath set to the current detector. Look at the overlays in ReportsDirectory/label_check. |
the mean IoU is low: the boxes are shifted or scaled, so raise it on #12 before training |
| 4 | Train on OutputDirectory/conf.yaml, normally with --train or the tray task, which also run steps 2, 3 and 5. See Training-the-Detector for a fresh model or for continuing an existing one. |
— |
| 5 |
--evaluate-detector options.json with WeightsPaths listing model.pt and every candidate. |
— the rows go to the gate on #12, with the subset sizes |
Traps:
-
OutputDirectorymust be absolute. It is written intoconf.yamlas the dataset path. A non-empty folder that is not a dataset this builder started is refused, and so is an existing dataset withResumeoff. -
The legacy list is required. Copy
DiGi.GIS.ML/Data/Data_2025.05.27.tsvintouser files/. If the list is missing, the build is refused rather than reporting every held-out building as clean. -
LegacySource = unknownis not clean. When a county part'syear_built_datacannot be read in full, its Test buildings are markedunknownand left out of the clean subset, and the run exits4. -
The manifest is the journal. Do not edit
dataset_references.tsvby hand. When a run is resumed, it deletes the image and label files of any reference the manifest does not name. -
The weights identity is logged. Every prediction run now logs the SHA-256 of its weights on its start line and in its
[NOTE]output. Use it to tell which detector wrote a county's detections.
- Using-the-ConsoleApp — every option, sample configurations, diagnostics
- Training-the-Detector — training the detector: fresh or continued, the data to keep, resume and the gate
- Home — wiki landing page
- Year Built Prediction Pipeline — architecture, the two models, checkpoint provenance
- Training the Year Built Model — retraining the regressor
- Running Scripts Manually — the detector outside the pipeline