NLP execution and numerical replay
Select explicit CPU/GPU numerical phases or admitted tagger workers, inspect execution evidence and preserve same profile checkpoint continuation.
Development APIsDevelopment API, unreleased. The execution selected overloads and nlp.execution_summary require the matching development runtime and editor source. They are absent from the published Aner 0.0.5 runtime and VS Code 0.1.48 package. Existing serial NLP signatures retain their Aner 0.0.5 contract. This guide does not publish a runtime, extension or backend.
Execution is an explicit operation argument. Source text, Unicode analysis, token boundaries, corpus roles, overlap checks and document IDs stay on the host. Eligible numerical phases can run on an admitted CPU or GPU backend. Stable source alignment is preserved even when numerical precision changes a score or predicted path.
Choose an execution context
| Context | Intended route | Admission |
|---|---|---|
parallel.local(workers: 1) | Reusable local CPU worker pool | The requested count must fit the effective CPU budget. Zero selects the existing automatic policy. |
nn.execution_context(device: "cpu", dtype: "Float64") | Strict local CPU arithmetic | No executor pool or distributed Tensor graph is implied. |
nn.execution_context(device: "mps", dtype: "Float32") | Strict native Metal/MPS numerical phases | Compatible build, available Apple backend and Float32 support are required. |
nn.execution_context(device: "cuda", dtype: "Float64") | Strict native CUDA numerical phases | Compatible source runtime, CUDA backend/device and requested precision are required. Float32 is an explicit alternative. |
parallel.cluster(config: "private.cluster") | Explicit admitted tagger workers | Compatible prepared native workers and a private reviewed descriptor are required. No discovery or automatic remote installation occurs. |
The zero argument nn.execution_context() uses the active resolved neural profile. Read that profile before using it in a reproducibility record. Its trace retains the original requested device/precision and resolution reason as well as effective placement; a profile resolved earlier under an explicit adaptation policy must not be mistaken for a new strict placement request. The explicit two argument form is strict: unsupported placement or precision fails without fallback or silent adaptation. In particular, requesting MPS Float64 does not authorize CPU execution or Float32 conversion.
Omitting execution keeps the existing serial CPU Float64 route for the released signatures. Omission is not an alias for nn.execution_context() and does not follow a CLI GPU setting. The reference notation omitted (serial CPU Float64) describes this behavior; it is not an Aner expression or a nullable context value.
Supported operation boundaries
Operation with final execution argument | Local routes | Cluster route | Work retained on the host |
|---|---|---|---|
nlp.fit_tagger(training, epochs, seed, shuffle, normalization, casefold, execution) | CPU and admitted GPU emission arithmetic | Tagger numeric worker session | Feature text preparation, canonical sequence updates and averaging schedule; Viterbi and BIO2 constraints. |
model.resume_tagger(training, epochs, execution) | Saved training arithmetic/backend contract | Compatible tagger session under that contract | Complete checkpoint state, cumulative epoch shuffle and ordered updates. |
model.tag(tokens, execution) | Independent sequence rows on local workers or strict device | Tagger numeric worker session | Original tokens/spans on the coordinator; Viterbi and global path ties on each assigned worker CPU; ordered result assembly on the coordinator. |
model.evaluate_tagger(gold, execution) | Same routes as tagging | Same tagger session | Held out provenance checks and exact token/entity metric accumulation. |
encoder.transform(corpus, execution) | Local CPU or admitted GPU numerical weighting | Rejected before work | Unicode analysis, vocabulary lookup, fitted IDF preparation and ordered CSR assembly. Numeric weighting and row normalization use the selected backend. |
memory.search(query, top_k, execution) | Local CPU or admitted GPU BM25 contributions | Rejected before work | Query analysis, canonical positive filtering, source row ties and ranking. |
features.dense(max_cells, execution) | Detached local Tensor placement | Rejected before work | CSR/source metadata and explicit shape admission. |
batch.mask(execution) | Detached local Tensor placement | Rejected before work | Exact integer token IDs, lengths, source IDs and truncation metadata. |
The optional execution label follows existing arguments. Other defaults retain their previous values. Namespace calls and receiver calls select the same operation, for example nlp.tag(model, tokens, execution: context) and model.tag(tokens, execution: context).
A GPU route executes actual admitted numerical work. It does not move strings, Unicode segmentation, ranking or dynamic programming path decisions onto the GPU. Transfers, small matrices and host work can outweigh acceleration; no speedup is promised. Dense conversion and masks create local detached Tensors, without transporting autograd graphs or remote Tensor capabilities.
Preserve learning and checkpoint semantics
The tagger remains an averaged structured perceptron. Each training sequence observes the current model after the preceding canonical update. Parallel feature preparation or emission computation does not permit concurrent independent weight updates. The cumulative seeded shuffle, empty row rules, mistake count and exact averaging clock keep their meanings from the tagging reference.
A selected arithmetic profile is part of the training continuation contract. Save the model, its training source identity and its execution report. Resume under the same admitted arithmetic/backend profile, using the exact annotated training population. CPU serial and local pool contexts can continue under the same effective device/dtype/source contract; local worker count, chunking and timing are excluded from that contract. Cluster membership/order, node device/transport/endpoint/executable/subsystem, CPU admission slots and batch weights are retained and changes are rejected. Descriptor whitespace and the original auto selection intent are not numerical continuation identities, while the raw descriptor hash remains execution evidence. A new worker schedule does not authorize a different dtype or backend. Explicitly trained GPU checkpoints need their matching execution context; the shorter legacy CPU resume form does not silently recreate a GPU profile.
Same profile continuation is tested against uninterrupted training. Seeds control shuffle and algorithm owned random choices; they do not make different devices, precisions, libraries or arithmetic profiles bitwise identical. The emission arithmetic identities are ordered-float64/v1 and quantized-ordered-float32/v1. The Float32 profile quantizes canonical weights once and rounds the ordered feature accumulation after each addition; transitions and boundary weights follow the same quantization. CPU Viterbi accumulates path scores in Float64 for both profiles. Float32 emission rounding can change a score, global tie or predicted sequence, which then changes later perceptron updates. Compare validation metrics and recorded source aligned decisions separately when evaluating a changed profile.
Development tagger checkpoints use aner.nlp.tagger/2 and require the matching format/protocol. They retain the typed training device, dtype, arithmetic identity, context/source hashes and prior receipt hash, rather than serializing a live executor, executable or raw session report. Loading performs no GPU initialization: the load receipt marks restored_without_backend_initialization: true and retains prior_receipt_sha256. Resume performs fresh strict execution admission. This development loader rejects the protocol1 tagger artifacts produced by published Aner 0.0.5; the published loader likewise cannot read protocol2 artifacts. Keep each artifact with its matching runtime/protocol. There is no implicit migration or cross version continuation promise.
The immutable execution_summary() String contains bounded JSON describing the operation's retained execution trace. It applies to TextTagger, TextTagging, TaggingEvaluation, TextFeatures and TextMatches. Record requested/effective route, numerical phase boundaries, arithmetic identity and admitted worker participation as supplied by that report. Timing is observational. tag_score remains the canonical CPU Float64 diagnostic, with no execution overload in this iteration; tagger_weights also exports canonical Float64 values. A prediction's complete sequence score follows its actual selected numerical profile, so equality with tag_score is not promised across profiles. The logical model fingerprint includes its training arithmetic identity and excludes physical device, context and timing receipts. Prediction records retain their own actual inference profile, which may differ from training. Semantic model/prediction identity and operation execution evidence are distinct; a faster run is not evidence of a different linguistic model.
Case study: inspect local CPU execution and resume
The complete CPU case study fits a small synthetic POS model, evaluates independently identified validation sentences, inspects original tokens and execution traces, and compares five uninterrupted epochs with two saved epochs plus three resumed epochs. It also applies the same local context to TF IDF transformation and BM25 retrieval.
aner check examples/nlp_execution_cpu.aner
aner run examples/nlp_execution_cpu.aner --prodUse the matching development executable from a fresh writable directory. The program exclusively creates execution-pos-stage.anertagger. One worker fits even a one slot allocation. For a concurrency experiment, change only the admitted worker count, retain the reported source/model identities and compare complete elapsed time under the same population and arithmetic profile. A worker count bounds concurrency; it does not reserve physical cores or measure CPU occupancy. The synthetic data demonstrates the contract and supplies no linguistic quality benchmark.
Case study: explicit GPU numerical phases
The complete GPU case study explicitly requests MPS Float32, trains and predicts a small POS model, transforms text and creates a local dense feature Tensor and padding mask. It prints the effective Tensor device/dtype and retained execution traces, then compares three uninterrupted fitting epochs with one saved epoch plus two resumed epochs under the same strict GPU context. Run in a fresh writable directory: execution-gpu-pos-stage.anertagger is created exclusively. Use a compatible development MPS build and device. For CUDA, deliberately replace the context with a supported strict CUDA precision and record that change as a new experiment.
aner check examples/nlp_execution_gpu.aner
aner run examples/nlp_execution_gpu.aner --prodChecking the source does not establish GPU availability. Running an unavailable strict route must fail explicitly. Keep the source tokens and labels next to the trace: device placement alone neither validates annotation quality nor establishes useful generalization. See Tensor execution for backend capabilities and precision policy.
Configured cluster case
Use the same model and exact source tokens with an explicit private context:
let workers = parallel.cluster(config: "private.cluster")
let prediction = model.tag(tokens, execution: workers)
print(prediction.execution_summary())The descriptor and enrolled workers are prerequisites, not tutorial files to copy from an unrelated host. The dedicated tagger worker protocol transfers bounded prepared numerical model/row payloads, rather than raw source strings, host object handles, checkpoints or an autograd graph. Each assigned worker computes emissions and performs CPU Viterbi for its complete sequences. The coordinator retains raw source identity and validates ordered label assembly. Source/runtime/protocol, shape, row identity, label inventory, numerical profile and payload integrity are checked before accepting results. Failure does not publish a partial prediction. Transport integrity is not a guarantee that an untrusted worker performed honest computation.
This integration does not make NLP handles valid parameters to checked parallel.repeat, nor does it add NLP types to the native compiled user code subset. Keep those independently documented capability boundaries. Cluster contexts remain unsupported for sparse transformation, BM25 search, dense conversion and mask placement in this scope. See parallel execution for private configuration, worker allocation and source/compiled protocol distinctions.
Local lexical and Tensor evidence
Local TF IDF numerical weighting and row normalization execute under the chosen backend. The GPU path performs admitted log/add/multiply and sum/sqrt/broadcast/divide operations over retained nonzeros; source text processing, vocabulary/IDF preparation and ordered CSR assembly remain CPU work. BM25 processes bounded posting chunks of at most 65,536 entries: the selected backend computes numerical contributions, the CPU accumulates scores in canonical term order, and explanations retain the actual computed contributions. Ranking and source row tie decisions remain on the CPU.
TextFeatures and TextMatches report schema aner.nlp.local-execution/1. Its fields identify operation, requested/effective device/dtype, resolution_reason, numeric_backend, source/model/input hashes, rows and numeric item counts, native/GPU numerical operation counts, logical upload/download elements, workers with worker_count_semantics: configured_local_capacity, elapsed time, lexical_phase: coordinator_cpu, order: source_row and successful completion. workers reports configured Executor capacity, rather than measured simultaneous tasks or occupied CPUs. Native/GPU operation counts describe Tensor primitive calls, rather than internal provider kernels. The legacy serial path reports elapsed_seconds: null instead of inventing a timing. A count-only/no-normalization request may require placement without a numerical kernel and reports numeric_backend: placement_only; an empty or entirely OOV population reports no_numeric_work. Both retain zero GPU numerical calls instead of adding artificial work to claim acceleration.
Execution metadata is excluded from logical feature/match fingerprints; actual numerical weights and scores still affect those identities. Dense conversion and mask placement return local Tensors, so inspect their existing nn.device/nn.dtype readouts; those calls do not create a separate NLP result execution receipt. A GPU Float32 feature population can differ numerically from CPU Float64 even with identical corpus and fitted vocabulary.
Numeric session evidence and limits
Tagger model, prediction and evaluation reports use schema aner.nlp.execution/1. They record operation, feature_phase, update_phase, training device/dtype/arithmetic, training_context_sha256, source_sha256, logical_model_sha256, input_sha256 and the load flag. Fit and resume reports retain ordered_cpu_int64 as the update phase. Normal operation receipts embed their actual session; a restored checkpoint instead binds its prior receipt hash. A training profile is not a substitute for inspecting the session's actual inference backend.
The retained numeric session report uses schema aner.parallel-nlp/1 and protocol ANERNLP/1. These are implementation compatibility identities, rather than a claim that arbitrary ParallelContext workloads share one transport.
| Session evidence | Meaning |
|---|---|
source_sha256, model_sha256, input_sha256, ordered_invocations_sha256 | Exact numeric implementation, frozen model, prepared input and ordered call identities. They do not authenticate an untrusted worker. |
dtype, arithmetic, device, backend, tensor_provider, target, emission_phase, decode_phase, decode_device | Actual numerical profile and native target; decode_device is CPU even when emission arithmetic uses a GPU. |
max_calls, calls, completed_calls, rows, tokens, emission_terms, assignment_offset | Admitted attempts, successfully published calls, workload accounting and ordered assignment provenance. |
local_pool_workers and nodes | Admitted local worker count and actual per node participation; these are not occupied core counts or utilization measurements. |
gpu_operations, uploaded_elements, downloaded_elements | Admitted native embedding/reduction calls and logical transfer elements. GPU operation counts are two calls per tile, not provider internal GPU kernel counts. |
initialization_seconds, elapsed_seconds, per node exchange_seconds | Observed session timings, separate from semantic prediction identity. No unrecorded phase timing is inferred. |
failed, finished | Session lifecycle evidence. calls counts admitted attempts and completed_calls counts successfully published calls; failed sessions do not publish partial results. |
Per node records include ID, actual device/backend/target, CPU admission slots, requests, accepted rows/tokens, GPU call/transfer counts, transferred bytes and exchange time. CPU emission loops identify backend: native_cpp separately from the compiled Tensor provider; emission and decode phase placement remain explicit. A cluster descriptor hash identifies the immutable configuration snapshot used for admission. Source hashes and node IDs can reveal provenance; they are traceability values, rather than anonymity guarantees.
Numeric worker requests/results are bounded to 64 MiB per frame. Headers are bounded to 4,096 bytes and strict ASCII profile fields to 128 bytes. The numeric stage also has a one million scalar element ceiling even when the owning neural runtime permits a larger budget. A numeric session admits at most 1,000,000 calls. Explicit fit/resume preflights nonempty_sequences × requested_epochs <= 1,000,000 before launching workers or updating weights; one training call scores one canonical nonempty sequence. This explicit session limit does not impose a new cap on the shorter legacy serial training path. A larger continuation can be split into separate admitted fit/resume operations, including checkpoint save/load, while retaining the same training source/backend contract, cumulative shuffle/averaging state and the existing 1,000 epoch ceiling. Every operation must still pass its own work, payload and memory limits. Prepared requests admit at most 100,000 rows, 100,000 tokens, 64 labels, 32 feature IDs per token and 1,000,000 model cells, alongside the existing 100,000,000 work limit and operation specific limits. This numeric transport does not enlarge source token, checkpoint, Tensor, graph or language heap budgets. An invalid context, profile or request must fail before row work; any later worker/backend failure prevents partial publication.
Reproducible comparison checklist
Retain the complete source IDs/order/roles, raw token spans, fitted preprocessing/model identities, seeds and cumulative training state, requested/effective backend and precision, operation trace, worker/runtime compatibility evidence and validation predictions. Measure warm up, host preparation, transfer, numerical work and end to end latency explicitly when those observations are available; do not fabricate unavailable phase timings. Existing corpus, work, Tensor, artifact and language export bounds still apply. Execution selection is not an unlimited memory or fault recovery scheduler.
Development verification
The verification only nlp-execution.yml workflow builds numeric, transport, lexical, tagger and language targets. Its helper requires all 13 named CPU regression cases to run and pass, then admits registered GPU cases only as passed or explicit backend unavailable skip code 77. A failure cannot be converted to a skip. MPS enabled macOS builds must register all three new MPS admission cases; CUDA enabled builds likewise must register both precisions. Hosted CPU builds do not establish CUDA hardware support, and no workflow packages or publishes a runtime or extension.
See the Natural language processing module reference for the shared API.