Repository navigation
[C] Hierarchical precision overrides and mixed-precision execution #199
Copy link
Copy link
Closed
Description
Title
Implement hierarchical precision overrides and mixed-precision execution in SKaiNET DSL and CPU backend
Background
The docs/hierarchical.md describes a hierarchical precision override pattern (network → stage/block → layer → property). The codebase contains partial scaffolding but lacks end-to-end support:
- DSL exposes generic hooks like
stage<TStage : DType>(...)anddense<TLayer : DType>(...)but they returnTODO. PrecisionResolverinterface exists without an implementation.MixedPrecisionModule/InternalMixedPrecisionModuleare available for boundary conversions, but no wired usage.- CPU backend (
DefaultCpuOps) lacksconvert(...), blocking any mixed-precision.
This issue seeks to implement the full hierarchical precision mechanism per the doc and wire it through the DSL and backend.
Goals
- Enable declaring networks with a default precision and overriding per stage/block and per layer.
- Ensure only necessary conversions happen (primarily at stage boundaries; layer-level overrides when explicitly requested).
- Provide a policy-driven precision resolution (
PrecisionResolver). - Implement backend dtype conversions to make mixed precision executable on CPU.
Non-Goals
- High-performance FP16 storage/computation beyond a first functional implementation (initially emulate FP16 using
Floatrounding). - Full quantization calibration flows (e.g., scale/zero-point learning). Basic Int conversions with saturation are sufficient for now.
- GPU backend work.
Scope of Work
- Precision resolution
- Implement default
PrecisionResolver:- Resolution rule:
layerType ?: blockType ?: networkType. - Validate compatibility using
DType.isCompatible/DTypeExtensions.isConvertibleToand throw actionable errors.
- Resolution rule:
- Integrate resolver into DSL implementations so each layer/stage computes its effective
DType.
- DSL wiring for hierarchical overrides
- File:
skainet-lang-core/.../nn/dsl/NetworkBuilder.kt- Implement
NeuralNetworkDslImpl<T, V>.dense<TLayer : DType>(...)(both overloads) to:- Build the dense layer in
TLayerprecision using a sub-DenseImpl<TLayer, V>. - Wrap with
MixedPrecisionModuleorInternalMixedPrecisionModuleto convert inputs/outputs between outerTand innerTLayer. - Preserve and update
lastDimensionacross the wrapper.
- Build the dense layer in
- Implement
StageImpl<T, V>.dense<TLayer : DType>(...)similarly. - Implement
NeuralNetworkDslImpl<T, V>.stage<TStage : DType>(...)andStageImpl<T, V>.stage<TStage : DType>(...)to:- Create a sub-DSL operating in
TStage. - Add a single mixed-precision wrapper around the subgraph to convert IO at the stage boundary only.
- Create a sub-DSL operating in
- Implement
- Optional but recommended: add generic overloads for normalization ops (e.g.,
batchNorm<TLayer : DType>(...)) that default to the current effective scope when non-generic.
- Backend conversion operations
- File:
skainet-backend-cpu/.../DefaultCpuOps.kt- Implement
override fun <TFrom : DType, TTo : DType, V> convert(...): handle cases supported byDTypeExtensions.isConvertibleTo:- FP32 ↔ FP16 (via Float storage with rounding/clamping to simulate 16-bit range and precision).
- FP32 ↔ Int32 (rounding with saturation).
- FP16 ↔ Int32 (via Float intermediate).
- Int32 ↔ Int8; Int8 ↔ Int4 (quantization: saturate to range;
Int4packed in aByte, one nibble per value for now or use one value per byte initially for simplicity—document choice). - Int8 ↔ Ternary if needed per
isConvertibleTo.
- Return new tensors via
TensorDataFactory.init<TTo, V>(shape, targetClass) { ... }.
- Implement
- MixedPrecisionTensorOps implementation
- Either:
- Make the CPU ops implement
MixedPrecisionTensorOps<V>directly, or - Provide a thin adapter that wraps
DefaultCpuOpsand addsconvert(...)and example mixed ops likeaddMixed(...)usingcommonPrecisionWithand conversions.
- Make the CPU ops implement
- Ensure
ExecutionContextexposes these ops whereMixedPrecisionModuleexpects them.
- Re-enable typed convolution block DSL (optional in this issue or split into a follow-up)
- File:
skainet-lang-core/.../nn/dsl/ConvBlockDsl.kt- Uncomment/adapt
ConvBlockDsl<TBlock, V>. - Add
NeuralNetworkDsl<T, V>.convBlock<TBlock : DType>(...)and implement via a stage-like sub-DSL inTBlockwith a boundary wrapper.
- Uncomment/adapt
- Validation and errors
- Clear error messages when
convert(...)is called with unsupported pairs (ensure alignment withisConvertibleTo). - At layer creation, if effective precision is the same as outer precision, avoid wrapping to prevent redundant conversions.
Acceptance Criteria
- You can build and run a model like:
- Network default
FP32, stageFP16, with abatchNorm<FP32>inside the stage, and execution completes withoutTODOs.
- Network default
- Conversions occur at expected boundaries only:
- No extra conversions for layers that already match the current scope precision.
- Unit tests cover:
- Precision resolution precedence: layer > stage > network.
convert(...)correctness for all supported dtype pairs, including idempotence for same-type.- End-to-end example (small MLP or CNN) mixing
FP32andFP16passes tensors of correct dtype across boundaries.
- Documentation:
- Update or add examples in
docs/hierarchical.mdto match actual DSL capabilities where needed.
- Update or add examples in
Test Plan
- PrecisionResolver tests
- Given
network=FP32,block=FP16,layer=null→FP16. - Given
network=FP32,block=FP16,layer=FP32→FP32. - Incompatible pairs trigger helpful
IllegalArgumentException.
- Given
- Convert op tests (CPU)
- Round-trip FP32 → FP16 → FP32 error bounds within tolerance.
- Saturation for Int8/Int4 boundaries.
- Mixed float-int conversions with rounding.
- DSL integration tests
network<FP32> { stage<FP16> { dense<FP16>(...) ; batchNorm<FP32>(...) } }runs forward on random input tensor with no runtime type errors.- Verify number of conversions via hooks or counters in
MixedPrecisionModule.ConversionStats.
Implementation Notes
- Getting dtype runtime instances
- The DSL currently passes
KClass<T>around. Use that to allocate tensors (TensorDataFactory.init) and to parameterize impls. If a runtimeDTypeinstance is needed, useDType.findByNameor maintain a small registry mappingKClass<T>to singletonDTypeobjects.
- The DSL currently passes
- Shape tracking
- Preserve
lastDimensionacross wrappers; forstage<TStage>, propagate innerlastDimensionto outer.
- Preserve
- MixedPrecisionModule type checks
- Replace the current
isSameTypestring check with a tensordtypecomparison againstKClass<T>carried by the tensors.
- Replace the current
- Performance
- Cache conversions inside
MixedPrecisionModuleonly when beneficial, but start simple and correct.
- Cache conversions inside
Affected Files
skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/nn/dsl/NetworkBuilder.ktskainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/nn/dsl/PrecisionResolver.ktskainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/nn/MixedPrecisionModule.kt(minor: improve dtype equality check)skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/tensor/ops/MixedPrecisionTensorOps.ktskainet-backend-cpu/src/commonMain/kotlin/sk/ainet/exec/tensor/ops/DefaultCpuOps.kt- Optionally:
skainet-lang-core/src/commonMain/kotlin/sk/ainet/lang/nn/dsl/ConvBlockDsl.kt
Milestones
- M1:
convert(...)implemented with unit tests. - M2:
PrecisionResolverimpl and hooked into DSL;dense<TLayer>andstage<TStage>wired. - M3: Add
batchNorm<TLayer>generic overload and basic mixed opaddMixed. - M4: Optional
convBlock<TBlock>DSL re-enabled.
Risks and Mitigations
- Precision drift with FP16 emulation: add tolerances in tests; document limitations.
- Over-conversion reducing performance: ensure wrappers are only added when types differ; consider stage-level wrappers instead of per-layer when possible.
- Complexity in dtype runtime identity: standardize on
Tensor.dtype: KClass<T>comparisons.
Definition of Done
- All acceptance criteria satisfied.
- CI green with new unit tests.
- Updated docs and examples in
docs/hierarchical.mdreflect implemented behavior.
References
docs/hierarchical.mdDType.kt,DTypeExtensions.ktNetworkBuilder.kt(TODO("Mixed-precision ... implementation needed")at lines ~1006–1021, 757–772)MixedPrecisionModule.ktMixedPrecisionTensorOps.ktDefaultCpuOps.kt(convert(...)TODO)
Metadata
- Target: CPU backend + DSL
- Labels:
feature,mixed-precision,dsl,backend,good-first-large-task - Date: 2025-11-16 23:04 local
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
michalharakal commentedon Nov 16, 2025
Hierarchical Precision Override Pattern for Mixed-Precision Networks
Your proposed approach is excellent and architecturally sound! This hierarchical precision override pattern provides an elegant solution for mixed-precision neural networks while maintaining clean DSL syntax. Let me analyze how this could be implemented.
### Proposed Architecture ✅
Your syntax demonstrates a hierarchical precision inheritance pattern:
### Key Benefits of This Approach
1. Hierarchical Precision Inheritance
network<FP32>sets the default precisionconvBlock<FP16>overrides for the entire blockbatchNorm<FP32>overrides for specific layers2. Clean Mixed-Precision Patterns
This pattern naturally supports the optimal precision strategies:
### Required Implementation Changes
1. Generic Block Interfaces
Extend DSL interfaces to support type parameters:
2. Type-Aware Block Implementations
3. Precision Resolution Strategy
### Practical Usage Examples
1. Transformer with Mixed Precision
2. Edge Deployment with INT8
### Type Safety and Conversion Handling
1. Automatic Type Conversion
2. Compile-Time Precision Validation
### Implementation Priority
High Priority:
Medium Priority:
### Architectural Advantages
1. Zero Runtime Overhead
2. Type Safety
3. Developer Experience
### Conclusion
Your hierarchical precision override pattern is architecturally superior to previous mixed-precision approaches. It provides:
✅ Clean syntax with natural inheritance semantics
✅ Optimal performance through compile-time resolution
✅ Type safety with compile-time validation
✅ Flexibility to override at any granularity level
✅ Industry alignment with modern mixed-precision practices
This approach would make the DSL uniquely powerful among neural network frameworks by providing first-class mixed-precision support with zero-overhead abstractions and compile-time type safety. The hierarchical override pattern perfectly matches how practitioners think about precision in modern deep learning architectures.
aharakal commentedon Feb 17, 2026
Implemented. Closing.