faultforge 0.2.1__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- faultforge-0.3.0/LICENSE +35 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/PKG-INFO +46 -37
- {faultforge-0.2.1 → faultforge-0.3.0}/README.md +39 -35
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/bindings/src/secded.rs +5 -1
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/bit_buffer/impls_numpy.rs +9 -3
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/sequence/non_uniform.rs +3 -1
- {faultforge-0.2.1 → faultforge-0.3.0}/pyproject.toml +26 -2
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/__init__.py +11 -25
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/dataset.py +51 -49
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/dtype.py +20 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/experiment.py +3 -2
- faultforge-0.2.1/src/faultforge/_internal/common.py → faultforge-0.3.0/src/faultforge/_internal/io.py +1 -10
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/loading/abc.py +20 -8
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/loading/cifar.py +43 -11
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/loading/imagenet.py +40 -9
- faultforge-0.3.0/src/faultforge/_internal/loading/transform.py +20 -0
- faultforge-0.3.0/src/faultforge/_internal/metric.py +518 -0
- faultforge-0.3.0/src/faultforge/_internal/progress.py +259 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/tensor.py +3 -1
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/dataset.py +6 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/dtype.py +4 -0
- faultforge-0.3.0/src/faultforge/io.py +14 -0
- faultforge-0.3.0/src/faultforge/metric.py +42 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/progress.py +8 -0
- faultforge-0.2.1/src/faultforge/_internal/experiments/__init__.py +0 -0
- faultforge-0.2.1/src/faultforge/_internal/experiments/encoded_memory.py +0 -728
- faultforge-0.2.1/src/faultforge/_internal/progress.py +0 -198
- faultforge-0.2.1/src/faultforge/experiments/__init__.py +0 -1
- faultforge-0.2.1/src/faultforge/experiments/encoded_memory.py +0 -26
- {faultforge-0.2.1 → faultforge-0.3.0}/Cargo.lock +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/Cargo.toml +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/bindings/Cargo.toml +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/bindings/src/cep.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/bindings/src/common.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/bindings/src/fault.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/bindings/src/fault_injection.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/bindings/src/lib.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/bindings/src/mset.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/bindings/src/picker.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/Cargo.toml +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/benches/chunking.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/bit_buffer/bit.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/bit_buffer/impls.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/bit_buffer/iter.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/bit_buffer/result.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/bit_buffer/tests.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/bit_buffer.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/byte_buffer/impls.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/byte_buffer/tests.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/byte_buffer.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/chunks/tests.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/chunks.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/encoding/embedded_parity/tests.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/encoding/embedded_parity.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/encoding/majority/tests.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/encoding/majority.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/encoding/secded/tests.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/encoding/secded.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/encoding.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/fault.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/lib.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/limited.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/sequence/uniform.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/memory/src/sequence.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/picker/Cargo.toml +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/crates/picker/src/lib.rs +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/__init__.py +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/encoding/__init__.py +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/encoding/abc.py +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/encoding/cep.py +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/encoding/identity.py +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/encoding/mset.py +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/encoding/nn.py +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/encoding/secded.py +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/encoding/sequence.py +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/fault.py +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/fingerprint.py +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_internal/loading/__init__.py +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_rust/__init__.pyi +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_rust/cep.pyi +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_rust/mset.pyi +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/_rust/secded.pyi +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/encoding.py +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/experiment.py +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/fingerprint.py +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/loading.py +0 -0
- {faultforge-0.2.1 → faultforge-0.3.0}/src/faultforge/py.typed +0 -0
faultforge-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
Copyright (c) 2025 Marten Roots
|
|
2
|
+
|
|
3
|
+
The Universal Permissive License (UPL), Version 1.0
|
|
4
|
+
|
|
5
|
+
Subject to the condition set forth below, permission is hereby granted to any
|
|
6
|
+
person obtaining a copy of this software, associated documentation and/or data
|
|
7
|
+
(collectively the "Software"), free of charge and under any and all copyright
|
|
8
|
+
rights in the Software, and any and all patent rights owned or freely
|
|
9
|
+
licensable by each licensor hereunder covering either (i) the unmodified
|
|
10
|
+
Software as contributed to or provided by such licensor, or (ii) the Larger
|
|
11
|
+
Works (as defined below), to deal in both
|
|
12
|
+
|
|
13
|
+
(a) the Software, and
|
|
14
|
+
(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
|
|
15
|
+
one is included with the Software (each a "Larger Work" to which the Software
|
|
16
|
+
is contributed by such licensors),
|
|
17
|
+
|
|
18
|
+
without restriction, including without limitation the rights to copy, create
|
|
19
|
+
derivative works of, display, perform, and distribute the Software and make,
|
|
20
|
+
use, sell, offer for sale, import, export, have made, and have sold the
|
|
21
|
+
Software and the Larger Work(s), and to sublicense the foregoing rights on
|
|
22
|
+
either these or other terms.
|
|
23
|
+
|
|
24
|
+
This license is subject to the following condition:
|
|
25
|
+
The above copyright notice and either this complete permission notice or at
|
|
26
|
+
a minimum a reference to the UPL must be included in all copies or
|
|
27
|
+
substantial portions of the Software.
|
|
28
|
+
|
|
29
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
30
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
31
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
32
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
33
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
34
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
35
|
+
SOFTWARE.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: faultforge
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
@@ -11,10 +11,15 @@ Requires-Dist: scipy>=1.17.1
|
|
|
11
11
|
Requires-Dist: timm>=1.0.22
|
|
12
12
|
Requires-Dist: torch>=2.7.1
|
|
13
13
|
Requires-Dist: torchvision>=0.22.1
|
|
14
|
+
License-File: LICENSE
|
|
14
15
|
Summary: A framework for reproducible hardware fault-injection experiments on PyTorch models
|
|
15
|
-
Author-email: Marten Roots <marten.roots@gmail.com>
|
|
16
|
+
Author-email: Marten Roots <marten.roots@gmail.com>, Sven-Markus Loorits <sven.loorits@proton.me>
|
|
17
|
+
License-Expression: UPL-1.0
|
|
16
18
|
Requires-Python: >=3.14
|
|
17
19
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
20
|
+
Project-URL: Changelog, https://github.com/rezzubs/faultforge/blob/main/CHANGELOG.md
|
|
21
|
+
Project-URL: Issues, https://github.com/rezzubs/faultforge/issues
|
|
22
|
+
Project-URL: Repository, https://github.com/rezzubs/faultforge
|
|
18
23
|
|
|
19
24
|
# FaultForge
|
|
20
25
|
|
|
@@ -34,7 +39,9 @@ its first experiment.
|
|
|
34
39
|
- [`Fingerprint`](docs/library.md#fingerprint)-based verification: resuming or
|
|
35
40
|
comparing a saved result against a changed configuration fails loudly with
|
|
36
41
|
a precise diff, instead of silently mixing incompatible data.
|
|
37
|
-
- A
|
|
42
|
+
- A generic and extensible system for [reliabilty
|
|
43
|
+
metrics](src/faultforge/metric.py).
|
|
44
|
+
- A composable [encoding framework](experiments/encoded_memory/README.md#encoding-techniques)
|
|
38
45
|
(`Encoder`/`Encoding`, chainable via `EncoderSequence`) with three built-in
|
|
39
46
|
ECC-style techniques - SECDED (Hamming codes), MSET, and CEP - usable
|
|
40
47
|
standalone or combined.
|
|
@@ -42,7 +49,7 @@ its first experiment.
|
|
|
42
49
|
repeat-free fault-location sampler, and a batched injection API built for
|
|
43
50
|
performance.
|
|
44
51
|
- One ready-made experiment today,
|
|
45
|
-
[`encoded_memory`](
|
|
52
|
+
[`encoded_memory`](experiments/encoded_memory/README.md): fault injection into
|
|
46
53
|
ECC-protected model parameters, with built-in CIFAR-10/100 and ImageNet
|
|
47
54
|
model/dataset loading and a CLI for recording and plotting results. It
|
|
48
55
|
doubles as the reference implementation to follow when adding a new
|
|
@@ -52,58 +59,59 @@ its first experiment.
|
|
|
52
59
|
|
|
53
60
|
## Installation
|
|
54
61
|
|
|
55
|
-
|
|
62
|
+
### Prebuilt packages from PyPI
|
|
56
63
|
|
|
57
|
-
|
|
58
|
-
- [`faultforge-cli`](https://pypi.org/project/faultforge-cli/) - a CLI built
|
|
59
|
-
on top of it (installs a `faultforge` command).
|
|
64
|
+
Using pip:
|
|
60
65
|
|
|
61
66
|
```sh
|
|
62
|
-
pip install faultforge
|
|
63
|
-
pip install faultforge-cli # adds the `faultforge` CLI command
|
|
67
|
+
pip install faultforge
|
|
64
68
|
```
|
|
65
69
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
Using uv:
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
uv add faultforge
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
[`faultforge`](https://pypi.org/project/faultforge/) is the only package
|
|
78
|
+
published to PyPI - it's the framework only, with no CLI and no ready-made
|
|
79
|
+
experiments.
|
|
71
80
|
|
|
72
81
|
### Installing from source
|
|
73
82
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
you want:
|
|
83
|
+
Building from source requires a Rust toolchain. Install one with your system
|
|
84
|
+
package manager or via [rustup](https://rustup.rs/). This repository's root
|
|
85
|
+
package is the `faultforge` library. Point pip at whichever revision you want:
|
|
77
86
|
|
|
78
87
|
```sh
|
|
79
|
-
# latest (main is kept in sync with the newest code going forward)
|
|
80
|
-
pip install 'faultforge @ git+https://github.com/rezzubs/faultforge.git#subdirectory=packages/faultforge'
|
|
81
88
|
|
|
82
89
|
# latest release (the latest branch tracks the most recent tagged release)
|
|
83
|
-
pip install 'faultforge @ git+https://github.com/rezzubs/faultforge.git@latest
|
|
90
|
+
pip install 'faultforge @ git+https://github.com/rezzubs/faultforge.git@latest'
|
|
84
91
|
|
|
85
92
|
# a specific released version
|
|
86
|
-
pip install 'faultforge @ git+https://github.com/rezzubs/faultforge.git@v0.2.
|
|
93
|
+
pip install 'faultforge @ git+https://github.com/rezzubs/faultforge.git@v0.2.1'
|
|
87
94
|
|
|
88
95
|
# a specific commit
|
|
89
|
-
pip install 'faultforge @ git+https://github.com/rezzubs/faultforge.git@<commit-sha
|
|
90
|
-
```
|
|
96
|
+
pip install 'faultforge @ git+https://github.com/rezzubs/faultforge.git@<commit-sha>'
|
|
91
97
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
# development (main is kept in sync with the newest code, can break at any point)
|
|
99
|
+
pip install 'faultforge @ git+https://github.com/rezzubs/faultforge.git'
|
|
100
|
+
```
|
|
95
101
|
|
|
96
|
-
|
|
102
|
+
Ready-made experiments (see [Experiments](#experiments) below) aren't published
|
|
103
|
+
to PyPI - install one the same way, pointed at its own subdirectory under
|
|
104
|
+
`experiments/` See each experiment's README for details.
|
|
97
105
|
|
|
98
106
|
## Quick example
|
|
99
107
|
|
|
100
108
|
```python
|
|
101
|
-
from
|
|
102
|
-
from faultforge.experiment import MaxRuns
|
|
103
|
-
from faultforge.experiments.encoded_memory import (
|
|
109
|
+
from encoded_memory import (
|
|
104
110
|
EncodedFaultInjection,
|
|
105
111
|
ReliabilityMetric,
|
|
106
112
|
)
|
|
113
|
+
from faultforge.encoding import SecdedEncoder
|
|
114
|
+
from faultforge.experiment import MaxRuns
|
|
107
115
|
from faultforge.loading import Cifar, CifarDataset, CifarModel
|
|
108
116
|
|
|
109
117
|
bundle = Cifar(model=CifarModel.ResNet20, dataset=CifarDataset.Cifar10)
|
|
@@ -125,17 +133,18 @@ framework's pieces and how they compose.
|
|
|
125
133
|
|
|
126
134
|
## Experiments
|
|
127
135
|
|
|
128
|
-
|
|
129
|
-
|
|
136
|
+
Ready-made experiments live under [`experiments/`](experiments) as their own
|
|
137
|
+
packages, each pinned to a specific `faultforge` version rather than tracking
|
|
138
|
+
`main`. There's one today, serving as the reference implementation for
|
|
139
|
+
adding your own:
|
|
130
140
|
|
|
131
|
-
- [Encoded Memory](
|
|
141
|
+
- [Encoded Memory](experiments/encoded_memory/README.md) - fault injection into
|
|
132
142
|
ECC-protected model parameters, covering the available encoding techniques,
|
|
133
|
-
the `
|
|
134
|
-
library.
|
|
143
|
+
the `encoded-memory` CLI, and using the experiment directly as a library.
|
|
135
144
|
|
|
136
145
|
## Citation
|
|
137
146
|
|
|
138
|
-
### [Encoded Memory](
|
|
147
|
+
### [Encoded Memory](experiments/encoded_memory/README.md)
|
|
139
148
|
|
|
140
149
|
There are two papers related to the encoded memory experiment.
|
|
141
150
|
|
|
@@ -16,7 +16,9 @@ its first experiment.
|
|
|
16
16
|
- [`Fingerprint`](docs/library.md#fingerprint)-based verification: resuming or
|
|
17
17
|
comparing a saved result against a changed configuration fails loudly with
|
|
18
18
|
a precise diff, instead of silently mixing incompatible data.
|
|
19
|
-
- A
|
|
19
|
+
- A generic and extensible system for [reliabilty
|
|
20
|
+
metrics](src/faultforge/metric.py).
|
|
21
|
+
- A composable [encoding framework](experiments/encoded_memory/README.md#encoding-techniques)
|
|
20
22
|
(`Encoder`/`Encoding`, chainable via `EncoderSequence`) with three built-in
|
|
21
23
|
ECC-style techniques - SECDED (Hamming codes), MSET, and CEP - usable
|
|
22
24
|
standalone or combined.
|
|
@@ -24,7 +26,7 @@ its first experiment.
|
|
|
24
26
|
repeat-free fault-location sampler, and a batched injection API built for
|
|
25
27
|
performance.
|
|
26
28
|
- One ready-made experiment today,
|
|
27
|
-
[`encoded_memory`](
|
|
29
|
+
[`encoded_memory`](experiments/encoded_memory/README.md): fault injection into
|
|
28
30
|
ECC-protected model parameters, with built-in CIFAR-10/100 and ImageNet
|
|
29
31
|
model/dataset loading and a CLI for recording and plotting results. It
|
|
30
32
|
doubles as the reference implementation to follow when adding a new
|
|
@@ -34,58 +36,59 @@ its first experiment.
|
|
|
34
36
|
|
|
35
37
|
## Installation
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
### Prebuilt packages from PyPI
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
- [`faultforge-cli`](https://pypi.org/project/faultforge-cli/) - a CLI built
|
|
41
|
-
on top of it (installs a `faultforge` command).
|
|
41
|
+
Using pip:
|
|
42
42
|
|
|
43
43
|
```sh
|
|
44
|
-
pip install faultforge
|
|
45
|
-
pip install faultforge-cli # adds the `faultforge` CLI command
|
|
44
|
+
pip install faultforge
|
|
46
45
|
```
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
Using uv:
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
uv add faultforge
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
[`faultforge`](https://pypi.org/project/faultforge/) is the only package
|
|
55
|
+
published to PyPI - it's the framework only, with no CLI and no ready-made
|
|
56
|
+
experiments.
|
|
53
57
|
|
|
54
58
|
### Installing from source
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
you want:
|
|
60
|
+
Building from source requires a Rust toolchain. Install one with your system
|
|
61
|
+
package manager or via [rustup](https://rustup.rs/). This repository's root
|
|
62
|
+
package is the `faultforge` library. Point pip at whichever revision you want:
|
|
59
63
|
|
|
60
64
|
```sh
|
|
61
|
-
# latest (main is kept in sync with the newest code going forward)
|
|
62
|
-
pip install 'faultforge @ git+https://github.com/rezzubs/faultforge.git#subdirectory=packages/faultforge'
|
|
63
65
|
|
|
64
66
|
# latest release (the latest branch tracks the most recent tagged release)
|
|
65
|
-
pip install 'faultforge @ git+https://github.com/rezzubs/faultforge.git@latest
|
|
67
|
+
pip install 'faultforge @ git+https://github.com/rezzubs/faultforge.git@latest'
|
|
66
68
|
|
|
67
69
|
# a specific released version
|
|
68
|
-
pip install 'faultforge @ git+https://github.com/rezzubs/faultforge.git@v0.2.
|
|
70
|
+
pip install 'faultforge @ git+https://github.com/rezzubs/faultforge.git@v0.2.1'
|
|
69
71
|
|
|
70
72
|
# a specific commit
|
|
71
|
-
pip install 'faultforge @ git+https://github.com/rezzubs/faultforge.git@<commit-sha
|
|
72
|
-
```
|
|
73
|
+
pip install 'faultforge @ git+https://github.com/rezzubs/faultforge.git@<commit-sha>'
|
|
73
74
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
# development (main is kept in sync with the newest code, can break at any point)
|
|
76
|
+
pip install 'faultforge @ git+https://github.com/rezzubs/faultforge.git'
|
|
77
|
+
```
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
Ready-made experiments (see [Experiments](#experiments) below) aren't published
|
|
80
|
+
to PyPI - install one the same way, pointed at its own subdirectory under
|
|
81
|
+
`experiments/` See each experiment's README for details.
|
|
79
82
|
|
|
80
83
|
## Quick example
|
|
81
84
|
|
|
82
85
|
```python
|
|
83
|
-
from
|
|
84
|
-
from faultforge.experiment import MaxRuns
|
|
85
|
-
from faultforge.experiments.encoded_memory import (
|
|
86
|
+
from encoded_memory import (
|
|
86
87
|
EncodedFaultInjection,
|
|
87
88
|
ReliabilityMetric,
|
|
88
89
|
)
|
|
90
|
+
from faultforge.encoding import SecdedEncoder
|
|
91
|
+
from faultforge.experiment import MaxRuns
|
|
89
92
|
from faultforge.loading import Cifar, CifarDataset, CifarModel
|
|
90
93
|
|
|
91
94
|
bundle = Cifar(model=CifarModel.ResNet20, dataset=CifarDataset.Cifar10)
|
|
@@ -107,17 +110,18 @@ framework's pieces and how they compose.
|
|
|
107
110
|
|
|
108
111
|
## Experiments
|
|
109
112
|
|
|
110
|
-
|
|
111
|
-
|
|
113
|
+
Ready-made experiments live under [`experiments/`](experiments) as their own
|
|
114
|
+
packages, each pinned to a specific `faultforge` version rather than tracking
|
|
115
|
+
`main`. There's one today, serving as the reference implementation for
|
|
116
|
+
adding your own:
|
|
112
117
|
|
|
113
|
-
- [Encoded Memory](
|
|
118
|
+
- [Encoded Memory](experiments/encoded_memory/README.md) - fault injection into
|
|
114
119
|
ECC-protected model parameters, covering the available encoding techniques,
|
|
115
|
-
the `
|
|
116
|
-
library.
|
|
120
|
+
the `encoded-memory` CLI, and using the experiment directly as a library.
|
|
117
121
|
|
|
118
122
|
## Citation
|
|
119
123
|
|
|
120
|
-
### [Encoded Memory](
|
|
124
|
+
### [Encoded Memory](experiments/encoded_memory/README.md)
|
|
121
125
|
|
|
122
126
|
There are two papers related to the encoded memory experiment.
|
|
123
127
|
|
|
@@ -186,7 +186,11 @@ impl PyEncoding {
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
let mut encoding = self.to_rust(py)?;
|
|
189
|
-
encoding.apply_faults(
|
|
189
|
+
encoding.apply_faults(
|
|
190
|
+
faults
|
|
191
|
+
.into_iter()
|
|
192
|
+
.map(|(fault, target_bit)| (fault.0, target_bit)),
|
|
193
|
+
);
|
|
190
194
|
|
|
191
195
|
*self = PyEncoding::from_rust(py, encoding, self.data_bit_count, self.item_counts.clone())?;
|
|
192
196
|
|
|
@@ -95,7 +95,9 @@ mod tests {
|
|
|
95
95
|
fn bijective_1d() {
|
|
96
96
|
let shape = &[7usize];
|
|
97
97
|
let n = total_bits(shape, u8::BITS_COUNT);
|
|
98
|
-
let outputs: HashSet<_> = (0..n)
|
|
98
|
+
let outputs: HashSet<_> = (0..n)
|
|
99
|
+
.map(|i| bit_index_to_array_index::<u8>(i, shape))
|
|
100
|
+
.collect();
|
|
99
101
|
assert_eq!(outputs.len(), n);
|
|
100
102
|
}
|
|
101
103
|
|
|
@@ -103,7 +105,9 @@ mod tests {
|
|
|
103
105
|
fn bijective_2d() {
|
|
104
106
|
let shape = &[3usize, 5];
|
|
105
107
|
let n = total_bits(shape, u16::BITS_COUNT);
|
|
106
|
-
let outputs: HashSet<_> = (0..n)
|
|
108
|
+
let outputs: HashSet<_> = (0..n)
|
|
109
|
+
.map(|i| bit_index_to_array_index::<u16>(i, shape))
|
|
110
|
+
.collect();
|
|
107
111
|
assert_eq!(outputs.len(), n);
|
|
108
112
|
}
|
|
109
113
|
|
|
@@ -111,7 +115,9 @@ mod tests {
|
|
|
111
115
|
fn bijective_3d() {
|
|
112
116
|
let shape = &[2usize, 3, 4];
|
|
113
117
|
let n = total_bits(shape, u32::BITS_COUNT);
|
|
114
|
-
let outputs: HashSet<_> = (0..n)
|
|
118
|
+
let outputs: HashSet<_> = (0..n)
|
|
119
|
+
.map(|i| bit_index_to_array_index::<u32>(i, shape))
|
|
120
|
+
.collect();
|
|
115
121
|
assert_eq!(outputs.len(), n);
|
|
116
122
|
}
|
|
117
123
|
|
|
@@ -107,7 +107,9 @@ where
|
|
|
107
107
|
It: Iterator<Item = (Fault, usize)>,
|
|
108
108
|
{
|
|
109
109
|
let offsets = self.bit_offsets();
|
|
110
|
-
let total_bits = *offsets
|
|
110
|
+
let total_bits = *offsets
|
|
111
|
+
.last()
|
|
112
|
+
.expect("offsets always has at least one element");
|
|
111
113
|
|
|
112
114
|
for (fault, bit_index) in faults {
|
|
113
115
|
assert!(bit_index < total_bits, "out of bounds");
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "faultforge"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "A framework for reproducible hardware fault-injection experiments on PyTorch models"
|
|
5
5
|
readme = "README.md"
|
|
6
|
+
license = "UPL-1.0"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
6
8
|
authors = [
|
|
7
|
-
{ name = "Marten Roots", email = "marten.roots@gmail.com" }
|
|
9
|
+
{ name = "Marten Roots", email = "marten.roots@gmail.com" },
|
|
10
|
+
{ name = "Sven-Markus Loorits", email = "sven.loorits@proton.me" },
|
|
8
11
|
]
|
|
9
12
|
requires-python = ">=3.14"
|
|
10
13
|
dependencies = [
|
|
@@ -22,9 +25,24 @@ classifiers = [
|
|
|
22
25
|
"Programming Language :: Python :: Implementation :: PyPy",
|
|
23
26
|
]
|
|
24
27
|
|
|
28
|
+
[project.urls]
|
|
29
|
+
Repository = "https://github.com/rezzubs/faultforge"
|
|
30
|
+
Issues = "https://github.com/rezzubs/faultforge/issues"
|
|
31
|
+
Changelog = "https://github.com/rezzubs/faultforge/blob/main/CHANGELOG.md"
|
|
32
|
+
|
|
33
|
+
[tool.uv.workspace]
|
|
34
|
+
members = ["experiments/encoded_memory"]
|
|
35
|
+
|
|
36
|
+
[tool.uv]
|
|
37
|
+
default-groups = ["dev"]
|
|
38
|
+
|
|
25
39
|
[dependency-groups]
|
|
26
40
|
dev = [
|
|
41
|
+
"hypothesis>=6.148.7",
|
|
27
42
|
"maturin>=1.14.0",
|
|
43
|
+
"pytest>=9.0.2",
|
|
44
|
+
"ruff>=0.12.4",
|
|
45
|
+
"ty>=0.0.49",
|
|
28
46
|
]
|
|
29
47
|
|
|
30
48
|
[build-system]
|
|
@@ -36,3 +54,9 @@ features = ["pyo3/extension-module"]
|
|
|
36
54
|
module-name = "faultforge._rust"
|
|
37
55
|
manifest-path = "crates/bindings/Cargo.toml"
|
|
38
56
|
python-source = "src"
|
|
57
|
+
|
|
58
|
+
[tool.ty.rules]
|
|
59
|
+
missing-override-decorator = "warn"
|
|
60
|
+
|
|
61
|
+
[tool.ruff]
|
|
62
|
+
target-version = "py314"
|
|
@@ -20,21 +20,15 @@ submodules for details.
|
|
|
20
20
|
with its evaluation dataset.
|
|
21
21
|
- `faultforge.progress`: `Progress`, for reporting on long-running operations
|
|
22
22
|
(dataset loading, encoding, fault injection, ...) via periodic log messages.
|
|
23
|
+
- `faultforge.io`: File I/O helpers (`open_text`, `is_compressed`) for
|
|
24
|
+
reading/writing save files transparently through zstd compression.
|
|
23
25
|
|
|
24
26
|
To add a new kind of experiment, subclass `Experiment` and reuse
|
|
25
|
-
`faultforge.loading`/`faultforge.dataset` for model and data handling.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
`faultforge
|
|
30
|
-
Currently there is one, `faultforge.experiments.encoded_memory`: encoded-
|
|
31
|
-
memory fault injection, which measures model reliability under simulated
|
|
32
|
-
single-event upsets in error-corrected parameter memory. It's a complete
|
|
33
|
-
example to follow when adding a new experiment. It's built on:
|
|
34
|
-
|
|
35
|
-
- `faultforge.encoding`: `Encoder`/`Encoding` pairs that transform tensors into
|
|
36
|
-
a protected representation and back, plus `EncodedModule` for wrapping a
|
|
37
|
-
`torch.nn.Module` so its parameters live in simulated encoded memory.
|
|
27
|
+
`faultforge.loading`/`faultforge.dataset` for model and data handling. This
|
|
28
|
+
library only holds the reusable framework - ready-made experiments (e.g.
|
|
29
|
+
`encoded_memory`, built on `faultforge.encoding`) live in the repository's
|
|
30
|
+
top-level `experiments/` directory as their own packages, so pulling in
|
|
31
|
+
`faultforge` never drags in an experiment's own dependencies.
|
|
38
32
|
|
|
39
33
|
**Fault injection primitives**
|
|
40
34
|
|
|
@@ -49,20 +43,16 @@ root rather than in their own submodule:
|
|
|
49
43
|
`Encoding.apply_faults`/`EncodedModule.apply_faults`) over injecting one fault
|
|
50
44
|
at a time in a loop: applying a batch pays its conversion overhead once for the
|
|
51
45
|
whole batch rather than once per fault.
|
|
46
|
+
- `bitwise_xor`: elementwise bitwise xor of two same-shape, same-dtype tensors
|
|
47
|
+
(floats bitcast to same-width integers first).
|
|
52
48
|
"""
|
|
53
49
|
|
|
54
50
|
import sys
|
|
55
51
|
|
|
56
|
-
from faultforge._internal.common import (
|
|
57
|
-
DEFAULT_BATCH_SIZE,
|
|
58
|
-
DEFAULT_DEVICE,
|
|
59
|
-
AnyPath,
|
|
60
|
-
DeviceLike,
|
|
61
|
-
is_compressed,
|
|
62
|
-
)
|
|
63
52
|
from faultforge._internal.fault import BitFlip, Fault, StuckAt
|
|
64
53
|
from faultforge._internal.fingerprint import Fingerprint
|
|
65
54
|
from faultforge._internal.tensor import (
|
|
55
|
+
bitwise_xor,
|
|
66
56
|
tensor_list_dtype,
|
|
67
57
|
tensor_list_fault,
|
|
68
58
|
tensor_list_faults,
|
|
@@ -72,16 +62,12 @@ from faultforge._rust import Picker
|
|
|
72
62
|
from . import _rust
|
|
73
63
|
|
|
74
64
|
__all__ = [
|
|
75
|
-
"AnyPath",
|
|
76
65
|
"BitFlip",
|
|
77
|
-
"DEFAULT_BATCH_SIZE",
|
|
78
|
-
"DEFAULT_DEVICE",
|
|
79
|
-
"DeviceLike",
|
|
80
66
|
"Fault",
|
|
81
67
|
"Fingerprint",
|
|
82
68
|
"Picker",
|
|
83
69
|
"StuckAt",
|
|
84
|
-
"
|
|
70
|
+
"bitwise_xor",
|
|
85
71
|
"tensor_list_dtype",
|
|
86
72
|
"tensor_list_fault",
|
|
87
73
|
"tensor_list_faults",
|