torch-floating-point 0.0.1__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.
- torch_floating_point-0.0.1/PKG-INFO +274 -0
- torch_floating_point-0.0.1/README.md +242 -0
- torch_floating_point-0.0.1/floating_point/__init__.py +1 -0
- torch_floating_point-0.0.1/floating_point/data_types.py +140 -0
- torch_floating_point-0.0.1/floating_point/float_round.cpp +113 -0
- torch_floating_point-0.0.1/floating_point/float_round_cuda.cu +87 -0
- torch_floating_point-0.0.1/floating_point/round.py +46 -0
- torch_floating_point-0.0.1/floating_point/setup.py +70 -0
- torch_floating_point-0.0.1/pyproject.toml +115 -0
- torch_floating_point-0.0.1/setup.cfg +4 -0
- torch_floating_point-0.0.1/torch_floating_point.egg-info/PKG-INFO +274 -0
- torch_floating_point-0.0.1/torch_floating_point.egg-info/SOURCES.txt +13 -0
- torch_floating_point-0.0.1/torch_floating_point.egg-info/dependency_links.txt +1 -0
- torch_floating_point-0.0.1/torch_floating_point.egg-info/requires.txt +4 -0
- torch_floating_point-0.0.1/torch_floating_point.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: torch-floating-point
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A PyTorch library for custom floating point quantization with autograd support
|
|
5
|
+
Author-email: Samir Moustafa <samir.moustafa.97@gmail.com>
|
|
6
|
+
Maintainer-email: Samir Moustafa <samir.moustafa.97@gmail.com>
|
|
7
|
+
Project-URL: Homepage, https://github.com/SamirMoustafa/torch-floating-point
|
|
8
|
+
Project-URL: Documentation, https://torch-floating-point.readthedocs.io/
|
|
9
|
+
Project-URL: Repository, https://github.com/SamirMoustafa/torch-floating-point
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/SamirMoustafa/torch-floating-point/issues
|
|
11
|
+
Project-URL: Source Code, https://github.com/SamirMoustafa/torch-floating-point
|
|
12
|
+
Keywords: pytorch,floating-point,quantization,autograd,machine-learning,deep-learning
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
|
+
Classifier: Framework :: Pytest
|
|
27
|
+
Requires-Python: >=3.8
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
31
|
+
Requires-Dist: pre-commit>=3.0.0; extra == "dev"
|
|
32
|
+
|
|
33
|
+
# Torch Floating Point
|
|
34
|
+
|
|
35
|
+
A PyTorch library for custom floating point quantization with autograd support. This library provides efficient implementations of custom floating point formats with automatic differentiation capabilities.
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
- **Custom Floating Point Formats**: Support for arbitrary floating point configurations (sign bits, exponent bits, mantissa bits, bias)
|
|
40
|
+
- **Autograd Support**: Full PyTorch autograd integration for training with quantized weights
|
|
41
|
+
- **CUDA Support**: GPU acceleration for both forward and backward passes
|
|
42
|
+
- **Multiple Precision**: Support for various bit widths (4-bit, 8-bit, 16-bit, 32-bit)
|
|
43
|
+
- **Straight-Through Estimator**: Gradient-friendly quantization for training
|
|
44
|
+
- **Comprehensive Testing**: Extensive test suite covering differentiability and accuracy
|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
### From PyPI (Recommended)
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install torch-floating-point
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### From Source
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
git clone https://github.com/SamirMoustafa/torch-floating-point.git
|
|
58
|
+
cd torch-floating-point
|
|
59
|
+
pip install -e .
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Development Installation
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
git clone https://github.com/SamirMoustafa/torch-floating-point.git
|
|
66
|
+
cd torch-floating-point
|
|
67
|
+
pip install -e ".[dev,test]"
|
|
68
|
+
pre-commit install
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Quick Start
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
import torch
|
|
75
|
+
from floating_point import FloatingPoint, Round
|
|
76
|
+
|
|
77
|
+
# Define a custom 8-bit floating point format (1 sign, 4 exponent, 3 mantissa bits)
|
|
78
|
+
fp8 = FloatingPoint(sign_bits=1, exponent_bits=4, mantissa_bits=3, bias=7, bits=8)
|
|
79
|
+
|
|
80
|
+
# Create a rounding function
|
|
81
|
+
rounder = Round(fp8)
|
|
82
|
+
|
|
83
|
+
# Create a tensor with gradients
|
|
84
|
+
x = torch.randn(10, requires_grad=True)
|
|
85
|
+
|
|
86
|
+
# Quantize the tensor
|
|
87
|
+
quantized = rounder(x)
|
|
88
|
+
|
|
89
|
+
# Use in training (gradients flow through)
|
|
90
|
+
loss = quantized.sum()
|
|
91
|
+
loss.backward()
|
|
92
|
+
|
|
93
|
+
print(f"Original: {x}")
|
|
94
|
+
print(f"Quantized: {quantized}")
|
|
95
|
+
print(f"Gradients: {x.grad}")
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Usage Examples
|
|
99
|
+
|
|
100
|
+
### Custom Floating Point Configuration
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from floating_point import FloatingPoint
|
|
104
|
+
|
|
105
|
+
# 4-bit floating point (1 sign, 2 exponent, 1 mantissa)
|
|
106
|
+
fp4 = FloatingPoint(sign_bits=1, exponent_bits=2, mantissa_bits=1, bias=1, bits=4)
|
|
107
|
+
|
|
108
|
+
# 8-bit floating point with custom max mantissa
|
|
109
|
+
fp8_custom = FloatingPoint(
|
|
110
|
+
sign_bits=1,
|
|
111
|
+
exponent_bits=4,
|
|
112
|
+
mantissa_bits=3,
|
|
113
|
+
bias=7,
|
|
114
|
+
bits=8,
|
|
115
|
+
max_mantissa_at_max_exponent=6, # Custom max mantissa
|
|
116
|
+
reserved_exponent=False # No reserved exponent for inf/nan
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# 16-bit floating point (standard)
|
|
120
|
+
fp16 = FloatingPoint(sign_bits=1, exponent_bits=5, mantissa_bits=10, bias=15, bits=16)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Training with Quantized Weights
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
import torch
|
|
127
|
+
import torch.nn as nn
|
|
128
|
+
from floating_point import FloatingPoint, Round
|
|
129
|
+
|
|
130
|
+
class QuantizedLinear(nn.Module):
|
|
131
|
+
def __init__(self, in_features, out_features, fp_config):
|
|
132
|
+
super().__init__()
|
|
133
|
+
self.weight = nn.Parameter(torch.randn(out_features, in_features))
|
|
134
|
+
self.rounder = Round(fp_config)
|
|
135
|
+
|
|
136
|
+
def forward(self, x):
|
|
137
|
+
quantized_weight = self.rounder(self.weight)
|
|
138
|
+
return torch.nn.functional.linear(x, quantized_weight)
|
|
139
|
+
|
|
140
|
+
# Define quantization format
|
|
141
|
+
fp8 = FloatingPoint(sign_bits=1, exponent_bits=4, mantissa_bits=3, bias=7, bits=8)
|
|
142
|
+
|
|
143
|
+
# Create model with quantized weights
|
|
144
|
+
model = QuantizedLinear(784, 10, fp8)
|
|
145
|
+
optimizer = torch.optim.Adam(model.parameters())
|
|
146
|
+
|
|
147
|
+
# Training loop
|
|
148
|
+
for epoch in range(10):
|
|
149
|
+
# ... your training code ...
|
|
150
|
+
loss.backward()
|
|
151
|
+
optimizer.step()
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Direct Function Usage
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
import torch
|
|
158
|
+
from floating_point import autograd
|
|
159
|
+
|
|
160
|
+
# Direct quantization function
|
|
161
|
+
x = torch.randn(100, requires_grad=True)
|
|
162
|
+
quantized = autograd(x, exponent_bits=4, mantissa_bits=3, bias=7)
|
|
163
|
+
|
|
164
|
+
# Gradients work automatically
|
|
165
|
+
loss = quantized.sum()
|
|
166
|
+
loss.backward()
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Supported Formats
|
|
170
|
+
|
|
171
|
+
The library supports various floating point formats:
|
|
172
|
+
|
|
173
|
+
| Format | Sign Bits | Exponent Bits | Mantissa Bits | Bias | Total Bits |
|
|
174
|
+
|--------|-----------|---------------|---------------|------|------------|
|
|
175
|
+
| FP4 | 1 | 2 | 1 | 1 | 4 |
|
|
176
|
+
| FP8 | 1 | 4 | 3 | 7 | 8 |
|
|
177
|
+
| FP16 | 1 | 5 | 10 | 15 | 16 |
|
|
178
|
+
| BF16 | 1 | 8 | 7 | 127 | 16 |
|
|
179
|
+
| FP32 | 1 | 8 | 23 | 127 | 32 |
|
|
180
|
+
|
|
181
|
+
## Development
|
|
182
|
+
|
|
183
|
+
### Testing
|
|
184
|
+
|
|
185
|
+
The project includes two testing approaches:
|
|
186
|
+
|
|
187
|
+
1. **CI/CD Tests** (GitHub Actions): Fast, lightweight tests that verify core functionality without heavy numerical computations
|
|
188
|
+
2. **Full Test Suite**: Complete test coverage including all numerical precision tests (run locally or via manual workflow trigger)
|
|
189
|
+
|
|
190
|
+
To run the full test suite locally:
|
|
191
|
+
```bash
|
|
192
|
+
export LD_LIBRARY_PATH=$(python -c "import torch; print(torch.__file__)")/lib:$LD_LIBRARY_PATH
|
|
193
|
+
python -m pytest test/round.py test/data_types.py -v
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Running Tests
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
# Run all tests
|
|
200
|
+
make test
|
|
201
|
+
|
|
202
|
+
# Run tests with coverage
|
|
203
|
+
make test-cov
|
|
204
|
+
|
|
205
|
+
# Run specific test file
|
|
206
|
+
python -m pytest test/round.py -v
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Code Quality
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
# Run linting
|
|
213
|
+
make lint
|
|
214
|
+
|
|
215
|
+
# Format code
|
|
216
|
+
make format
|
|
217
|
+
|
|
218
|
+
# Run all checks
|
|
219
|
+
make full-check
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Building
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
# Build extension
|
|
226
|
+
cd floating_point && python setup.py build_ext --inplace
|
|
227
|
+
|
|
228
|
+
# Build package
|
|
229
|
+
make build
|
|
230
|
+
|
|
231
|
+
# Clean build artifacts
|
|
232
|
+
make clean
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Contributing
|
|
236
|
+
|
|
237
|
+
1. Fork the repository
|
|
238
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
239
|
+
3. Install development dependencies (`make setup-dev`)
|
|
240
|
+
4. Make your changes
|
|
241
|
+
5. Run tests (`make test`)
|
|
242
|
+
6. Run linting (`make lint`)
|
|
243
|
+
7. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
244
|
+
8. Push to the branch (`git push origin feature/amazing-feature`)
|
|
245
|
+
9. Open a Pull Request
|
|
246
|
+
|
|
247
|
+
## License
|
|
248
|
+
|
|
249
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
250
|
+
|
|
251
|
+
## Citation
|
|
252
|
+
|
|
253
|
+
If you use this library in your research, please cite:
|
|
254
|
+
|
|
255
|
+
```bibtex
|
|
256
|
+
@software{torch_floating_point,
|
|
257
|
+
title={Torch Floating Point: A PyTorch library for custom floating point quantization},
|
|
258
|
+
author={Samir Moustafa},
|
|
259
|
+
year={2024},
|
|
260
|
+
url={https://github.com/SamirMoustafa/torch-floating-point}
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Acknowledgments
|
|
265
|
+
|
|
266
|
+
- PyTorch team for the excellent autograd system
|
|
267
|
+
- The PyTorch C++ extension community for guidance on extension development
|
|
268
|
+
- Contributors and users of this library
|
|
269
|
+
|
|
270
|
+
## Support
|
|
271
|
+
|
|
272
|
+
- **Issues**: [GitHub Issues](https://github.com/SamirMoustafa/torch-floating-point/issues)
|
|
273
|
+
- **Discussions**: [GitHub Discussions](https://github.com/SamirMoustafa/torch-floating-point/discussions)
|
|
274
|
+
- **Email**: samir.moustafa.97@gmail.com
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# Torch Floating Point
|
|
2
|
+
|
|
3
|
+
A PyTorch library for custom floating point quantization with autograd support. This library provides efficient implementations of custom floating point formats with automatic differentiation capabilities.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Custom Floating Point Formats**: Support for arbitrary floating point configurations (sign bits, exponent bits, mantissa bits, bias)
|
|
8
|
+
- **Autograd Support**: Full PyTorch autograd integration for training with quantized weights
|
|
9
|
+
- **CUDA Support**: GPU acceleration for both forward and backward passes
|
|
10
|
+
- **Multiple Precision**: Support for various bit widths (4-bit, 8-bit, 16-bit, 32-bit)
|
|
11
|
+
- **Straight-Through Estimator**: Gradient-friendly quantization for training
|
|
12
|
+
- **Comprehensive Testing**: Extensive test suite covering differentiability and accuracy
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
### From PyPI (Recommended)
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install torch-floating-point
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### From Source
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
git clone https://github.com/SamirMoustafa/torch-floating-point.git
|
|
26
|
+
cd torch-floating-point
|
|
27
|
+
pip install -e .
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Development Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
git clone https://github.com/SamirMoustafa/torch-floating-point.git
|
|
34
|
+
cd torch-floating-point
|
|
35
|
+
pip install -e ".[dev,test]"
|
|
36
|
+
pre-commit install
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import torch
|
|
43
|
+
from floating_point import FloatingPoint, Round
|
|
44
|
+
|
|
45
|
+
# Define a custom 8-bit floating point format (1 sign, 4 exponent, 3 mantissa bits)
|
|
46
|
+
fp8 = FloatingPoint(sign_bits=1, exponent_bits=4, mantissa_bits=3, bias=7, bits=8)
|
|
47
|
+
|
|
48
|
+
# Create a rounding function
|
|
49
|
+
rounder = Round(fp8)
|
|
50
|
+
|
|
51
|
+
# Create a tensor with gradients
|
|
52
|
+
x = torch.randn(10, requires_grad=True)
|
|
53
|
+
|
|
54
|
+
# Quantize the tensor
|
|
55
|
+
quantized = rounder(x)
|
|
56
|
+
|
|
57
|
+
# Use in training (gradients flow through)
|
|
58
|
+
loss = quantized.sum()
|
|
59
|
+
loss.backward()
|
|
60
|
+
|
|
61
|
+
print(f"Original: {x}")
|
|
62
|
+
print(f"Quantized: {quantized}")
|
|
63
|
+
print(f"Gradients: {x.grad}")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Usage Examples
|
|
67
|
+
|
|
68
|
+
### Custom Floating Point Configuration
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from floating_point import FloatingPoint
|
|
72
|
+
|
|
73
|
+
# 4-bit floating point (1 sign, 2 exponent, 1 mantissa)
|
|
74
|
+
fp4 = FloatingPoint(sign_bits=1, exponent_bits=2, mantissa_bits=1, bias=1, bits=4)
|
|
75
|
+
|
|
76
|
+
# 8-bit floating point with custom max mantissa
|
|
77
|
+
fp8_custom = FloatingPoint(
|
|
78
|
+
sign_bits=1,
|
|
79
|
+
exponent_bits=4,
|
|
80
|
+
mantissa_bits=3,
|
|
81
|
+
bias=7,
|
|
82
|
+
bits=8,
|
|
83
|
+
max_mantissa_at_max_exponent=6, # Custom max mantissa
|
|
84
|
+
reserved_exponent=False # No reserved exponent for inf/nan
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# 16-bit floating point (standard)
|
|
88
|
+
fp16 = FloatingPoint(sign_bits=1, exponent_bits=5, mantissa_bits=10, bias=15, bits=16)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Training with Quantized Weights
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
import torch
|
|
95
|
+
import torch.nn as nn
|
|
96
|
+
from floating_point import FloatingPoint, Round
|
|
97
|
+
|
|
98
|
+
class QuantizedLinear(nn.Module):
|
|
99
|
+
def __init__(self, in_features, out_features, fp_config):
|
|
100
|
+
super().__init__()
|
|
101
|
+
self.weight = nn.Parameter(torch.randn(out_features, in_features))
|
|
102
|
+
self.rounder = Round(fp_config)
|
|
103
|
+
|
|
104
|
+
def forward(self, x):
|
|
105
|
+
quantized_weight = self.rounder(self.weight)
|
|
106
|
+
return torch.nn.functional.linear(x, quantized_weight)
|
|
107
|
+
|
|
108
|
+
# Define quantization format
|
|
109
|
+
fp8 = FloatingPoint(sign_bits=1, exponent_bits=4, mantissa_bits=3, bias=7, bits=8)
|
|
110
|
+
|
|
111
|
+
# Create model with quantized weights
|
|
112
|
+
model = QuantizedLinear(784, 10, fp8)
|
|
113
|
+
optimizer = torch.optim.Adam(model.parameters())
|
|
114
|
+
|
|
115
|
+
# Training loop
|
|
116
|
+
for epoch in range(10):
|
|
117
|
+
# ... your training code ...
|
|
118
|
+
loss.backward()
|
|
119
|
+
optimizer.step()
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Direct Function Usage
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
import torch
|
|
126
|
+
from floating_point import autograd
|
|
127
|
+
|
|
128
|
+
# Direct quantization function
|
|
129
|
+
x = torch.randn(100, requires_grad=True)
|
|
130
|
+
quantized = autograd(x, exponent_bits=4, mantissa_bits=3, bias=7)
|
|
131
|
+
|
|
132
|
+
# Gradients work automatically
|
|
133
|
+
loss = quantized.sum()
|
|
134
|
+
loss.backward()
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Supported Formats
|
|
138
|
+
|
|
139
|
+
The library supports various floating point formats:
|
|
140
|
+
|
|
141
|
+
| Format | Sign Bits | Exponent Bits | Mantissa Bits | Bias | Total Bits |
|
|
142
|
+
|--------|-----------|---------------|---------------|------|------------|
|
|
143
|
+
| FP4 | 1 | 2 | 1 | 1 | 4 |
|
|
144
|
+
| FP8 | 1 | 4 | 3 | 7 | 8 |
|
|
145
|
+
| FP16 | 1 | 5 | 10 | 15 | 16 |
|
|
146
|
+
| BF16 | 1 | 8 | 7 | 127 | 16 |
|
|
147
|
+
| FP32 | 1 | 8 | 23 | 127 | 32 |
|
|
148
|
+
|
|
149
|
+
## Development
|
|
150
|
+
|
|
151
|
+
### Testing
|
|
152
|
+
|
|
153
|
+
The project includes two testing approaches:
|
|
154
|
+
|
|
155
|
+
1. **CI/CD Tests** (GitHub Actions): Fast, lightweight tests that verify core functionality without heavy numerical computations
|
|
156
|
+
2. **Full Test Suite**: Complete test coverage including all numerical precision tests (run locally or via manual workflow trigger)
|
|
157
|
+
|
|
158
|
+
To run the full test suite locally:
|
|
159
|
+
```bash
|
|
160
|
+
export LD_LIBRARY_PATH=$(python -c "import torch; print(torch.__file__)")/lib:$LD_LIBRARY_PATH
|
|
161
|
+
python -m pytest test/round.py test/data_types.py -v
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Running Tests
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# Run all tests
|
|
168
|
+
make test
|
|
169
|
+
|
|
170
|
+
# Run tests with coverage
|
|
171
|
+
make test-cov
|
|
172
|
+
|
|
173
|
+
# Run specific test file
|
|
174
|
+
python -m pytest test/round.py -v
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Code Quality
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
# Run linting
|
|
181
|
+
make lint
|
|
182
|
+
|
|
183
|
+
# Format code
|
|
184
|
+
make format
|
|
185
|
+
|
|
186
|
+
# Run all checks
|
|
187
|
+
make full-check
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Building
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# Build extension
|
|
194
|
+
cd floating_point && python setup.py build_ext --inplace
|
|
195
|
+
|
|
196
|
+
# Build package
|
|
197
|
+
make build
|
|
198
|
+
|
|
199
|
+
# Clean build artifacts
|
|
200
|
+
make clean
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Contributing
|
|
204
|
+
|
|
205
|
+
1. Fork the repository
|
|
206
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
207
|
+
3. Install development dependencies (`make setup-dev`)
|
|
208
|
+
4. Make your changes
|
|
209
|
+
5. Run tests (`make test`)
|
|
210
|
+
6. Run linting (`make lint`)
|
|
211
|
+
7. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
212
|
+
8. Push to the branch (`git push origin feature/amazing-feature`)
|
|
213
|
+
9. Open a Pull Request
|
|
214
|
+
|
|
215
|
+
## License
|
|
216
|
+
|
|
217
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
218
|
+
|
|
219
|
+
## Citation
|
|
220
|
+
|
|
221
|
+
If you use this library in your research, please cite:
|
|
222
|
+
|
|
223
|
+
```bibtex
|
|
224
|
+
@software{torch_floating_point,
|
|
225
|
+
title={Torch Floating Point: A PyTorch library for custom floating point quantization},
|
|
226
|
+
author={Samir Moustafa},
|
|
227
|
+
year={2024},
|
|
228
|
+
url={https://github.com/SamirMoustafa/torch-floating-point}
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Acknowledgments
|
|
233
|
+
|
|
234
|
+
- PyTorch team for the excellent autograd system
|
|
235
|
+
- The PyTorch C++ extension community for guidance on extension development
|
|
236
|
+
- Contributors and users of this library
|
|
237
|
+
|
|
238
|
+
## Support
|
|
239
|
+
|
|
240
|
+
- **Issues**: [GitHub Issues](https://github.com/SamirMoustafa/torch-floating-point/issues)
|
|
241
|
+
- **Discussions**: [GitHub Discussions](https://github.com/SamirMoustafa/torch-floating-point/discussions)
|
|
242
|
+
- **Email**: samir.moustafa.97@gmail.com
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .floating_point import autograd
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from itertools import product
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class FloatingPoint:
|
|
7
|
+
"""
|
|
8
|
+
A class representing a custom floating-point format.
|
|
9
|
+
Parameters:
|
|
10
|
+
- sign_bits: Number of bits for the sign (0 or 1).
|
|
11
|
+
- exponent_bits: Number of bits for the exponent.
|
|
12
|
+
- mantissa_bits: Number of bits for the mantissa.
|
|
13
|
+
- bias: Bias for the exponent.
|
|
14
|
+
- bits: Total number of bits (sign + exponent + mantissa).
|
|
15
|
+
- max_mantissa_at_max_exponent: Maximum mantissa value at maximum exponent.
|
|
16
|
+
- reserved_exponent: Whether the exponent has reserved values (default is True).
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
sign_bits: int,
|
|
22
|
+
exponent_bits: int,
|
|
23
|
+
mantissa_bits: int,
|
|
24
|
+
bias: int,
|
|
25
|
+
bits: int,
|
|
26
|
+
max_mantissa_at_max_exponent: Optional[int] = None,
|
|
27
|
+
reserved_exponent: bool = True,
|
|
28
|
+
):
|
|
29
|
+
assert bits > 0, "Total bits must be positive."
|
|
30
|
+
assert bits == sign_bits + exponent_bits + mantissa_bits, (
|
|
31
|
+
"Sum of sign, exponent, and mantissa bits must equal bits."
|
|
32
|
+
)
|
|
33
|
+
assert 0 <= sign_bits <= 1, "Sign bits must be 0 or 1."
|
|
34
|
+
self.bits = bits
|
|
35
|
+
self.sign_bits = sign_bits
|
|
36
|
+
self.exponent_bits = exponent_bits
|
|
37
|
+
self.mantissa_bits = mantissa_bits
|
|
38
|
+
self.bias = bias
|
|
39
|
+
self.reserved_exponent = reserved_exponent
|
|
40
|
+
if max_mantissa_at_max_exponent is not None:
|
|
41
|
+
self.max_mantissa_at_max_exponent = max_mantissa_at_max_exponent
|
|
42
|
+
else:
|
|
43
|
+
self.max_mantissa_at_max_exponent = 2**mantissa_bits - 1
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def is_signed(self) -> bool:
|
|
47
|
+
return self.sign_bits > 0
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def epsilon(self) -> float:
|
|
51
|
+
# Smallest positive subnormal value
|
|
52
|
+
return float(2 ** (-self.mantissa_bits))
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def minimum(self) -> float:
|
|
56
|
+
# Negative of the max finite value
|
|
57
|
+
return -self.maximum if self.is_signed else 0.0
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def maximum(self) -> float:
|
|
61
|
+
if self.exponent_bits == 0:
|
|
62
|
+
# Subnormal maximum: (max_mantissa / 2^mantissa_bits) * 2^(1 - bias)
|
|
63
|
+
max_exponent = 1 - self.bias
|
|
64
|
+
max_mantissa = (2**self.mantissa_bits) - 1
|
|
65
|
+
return float((max_mantissa / (2**self.mantissa_bits)) * (2**max_exponent))
|
|
66
|
+
else:
|
|
67
|
+
# Calculate max stored exponent based on reserved status
|
|
68
|
+
max_stored_exponent = (2**self.exponent_bits - 2) if self.reserved_exponent else (2**self.exponent_bits - 1)
|
|
69
|
+
max_exponent = max_stored_exponent - self.bias
|
|
70
|
+
return float((1 + self.max_mantissa_at_max_exponent / (2**self.mantissa_bits)) * (2**max_exponent))
|
|
71
|
+
|
|
72
|
+
def generate_bit_combinations(self) -> List[int]:
|
|
73
|
+
"""Generate all possible bit patterns for the given configuration."""
|
|
74
|
+
total_bits = self.bits
|
|
75
|
+
bit_combinations = list(product([0, 1], repeat=total_bits))
|
|
76
|
+
return [int("".join(map(str, bits)), 2) for bits in bit_combinations]
|
|
77
|
+
|
|
78
|
+
def bit_pattern_to_custom_fp(self, bit_pattern: int) -> float:
|
|
79
|
+
total_bits = self.sign_bits + self.exponent_bits + self.mantissa_bits
|
|
80
|
+
# Mask definitions
|
|
81
|
+
sign_mask = (1 << (total_bits - 1)) if self.is_signed else 0
|
|
82
|
+
exponent_mask = ((1 << self.exponent_bits) - 1) << self.mantissa_bits
|
|
83
|
+
mantissa_mask = (1 << self.mantissa_bits) - 1
|
|
84
|
+
sign = (bit_pattern & sign_mask) >> (self.exponent_bits + self.mantissa_bits) if self.is_signed else 0
|
|
85
|
+
exponent = (bit_pattern & exponent_mask) >> self.mantissa_bits
|
|
86
|
+
mantissa = bit_pattern & mantissa_mask
|
|
87
|
+
# Decode components
|
|
88
|
+
sign_factor = -1 if sign else 1
|
|
89
|
+
if self.exponent_bits == 0:
|
|
90
|
+
# Only subnormals
|
|
91
|
+
exponent_value = 1 - self.bias
|
|
92
|
+
mantissa_value = mantissa / (2**self.mantissa_bits)
|
|
93
|
+
if mantissa == 0:
|
|
94
|
+
return sign_factor * 0.0
|
|
95
|
+
return float(sign_factor * mantissa_value * (2**exponent_value))
|
|
96
|
+
else:
|
|
97
|
+
max_exponent = (1 << self.exponent_bits) - 1
|
|
98
|
+
if self.reserved_exponent and exponent == max_exponent:
|
|
99
|
+
if mantissa == 0:
|
|
100
|
+
return sign_factor * math.inf
|
|
101
|
+
else:
|
|
102
|
+
return math.nan
|
|
103
|
+
elif exponent == 0:
|
|
104
|
+
if mantissa == 0:
|
|
105
|
+
return sign_factor * 0.0
|
|
106
|
+
else:
|
|
107
|
+
mantissa_value = mantissa / (2**self.mantissa_bits)
|
|
108
|
+
return float(sign_factor * mantissa_value * (2 ** (1 - self.bias)))
|
|
109
|
+
else:
|
|
110
|
+
exponent_value = exponent - self.bias
|
|
111
|
+
mantissa_value = 1 + (mantissa / (2**self.mantissa_bits))
|
|
112
|
+
return float(sign_factor * mantissa_value * (2**exponent_value))
|
|
113
|
+
|
|
114
|
+
def generate_all_custom_fp_values(self) -> List[float]:
|
|
115
|
+
bit_combinations = self.generate_bit_combinations()
|
|
116
|
+
values = [self.bit_pattern_to_custom_fp(b) for b in bit_combinations]
|
|
117
|
+
values = sorted(
|
|
118
|
+
values,
|
|
119
|
+
key=lambda x: (
|
|
120
|
+
math.inf if math.isnan(x) else math.copysign(1, x),
|
|
121
|
+
math.inf if math.isnan(x) else x,
|
|
122
|
+
),
|
|
123
|
+
)
|
|
124
|
+
assert len(values) == 2**self.bits, f"Incorrect number of values generated: {len(values)} != {2**self.bits}"
|
|
125
|
+
return values
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def values(self) -> List[float]:
|
|
129
|
+
return self.generate_all_custom_fp_values()
|
|
130
|
+
|
|
131
|
+
def __repr__(self) -> str:
|
|
132
|
+
return (
|
|
133
|
+
f"Float{self.bits}-"
|
|
134
|
+
f"S{self.sign_bits}"
|
|
135
|
+
f"E{self.exponent_bits}"
|
|
136
|
+
f"M{self.mantissa_bits}"
|
|
137
|
+
f"B{self.bias}"
|
|
138
|
+
f"MaxM{self.max_mantissa_at_max_exponent}"
|
|
139
|
+
f"{'R' if self.reserved_exponent else ''}"
|
|
140
|
+
)
|