coreml-complexity-analyzer 0.1.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.
- coreml_complexity_analyzer-0.1.0/LICENSE +28 -0
- coreml_complexity_analyzer-0.1.0/PKG-INFO +200 -0
- coreml_complexity_analyzer-0.1.0/README.md +165 -0
- coreml_complexity_analyzer-0.1.0/coreml_complexity_analyzer/__init__.py +29 -0
- coreml_complexity_analyzer-0.1.0/coreml_complexity_analyzer/compute_cost_report.py +214 -0
- coreml_complexity_analyzer-0.1.0/coreml_complexity_analyzer/flops_analyzer.py +550 -0
- coreml_complexity_analyzer-0.1.0/coreml_complexity_analyzer/layer_profiler.py +408 -0
- coreml_complexity_analyzer-0.1.0/coreml_complexity_analyzer/memory_estimator.py +365 -0
- coreml_complexity_analyzer-0.1.0/coreml_complexity_analyzer.egg-info/PKG-INFO +200 -0
- coreml_complexity_analyzer-0.1.0/coreml_complexity_analyzer.egg-info/SOURCES.txt +14 -0
- coreml_complexity_analyzer-0.1.0/coreml_complexity_analyzer.egg-info/dependency_links.txt +1 -0
- coreml_complexity_analyzer-0.1.0/coreml_complexity_analyzer.egg-info/requires.txt +6 -0
- coreml_complexity_analyzer-0.1.0/coreml_complexity_analyzer.egg-info/top_level.txt +1 -0
- coreml_complexity_analyzer-0.1.0/pyproject.toml +67 -0
- coreml_complexity_analyzer-0.1.0/setup.cfg +4 -0
- coreml_complexity_analyzer-0.1.0/tests/test_complexity_analyzer.py +296 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, Devavarapu Yashwanth, Ireddi Rakshitha
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: coreml-complexity-analyzer
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: FLOPS estimation, memory analysis, and per-layer profiling for Core ML models
|
|
5
|
+
Author: Devavarapu Yashwanth, Ireddi Rakshitha
|
|
6
|
+
License: BSD-3-Clause
|
|
7
|
+
Project-URL: Homepage, https://github.com/yaswanth169/coreml-complexity-analyzer
|
|
8
|
+
Project-URL: Repository, https://github.com/yaswanth169/coreml-complexity-analyzer
|
|
9
|
+
Project-URL: Issues, https://github.com/yaswanth169/coreml-complexity-analyzer/issues
|
|
10
|
+
Project-URL: Documentation, https://github.com/yaswanth169/coreml-complexity-analyzer#readme
|
|
11
|
+
Keywords: coreml,flops,model-analysis,complexity,apple,mlmodel,machine-learning,model-profiling,neural-network
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
|
+
Classifier: Operating System :: MacOS
|
|
24
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
25
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
26
|
+
Requires-Python: >=3.8
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: coremltools>=7.0
|
|
30
|
+
Requires-Dist: numpy
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
33
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# coreml-complexity-analyzer
|
|
37
|
+
|
|
38
|
+
FLOPS estimation, memory analysis, and per-layer profiling for Core ML models.
|
|
39
|
+
|
|
40
|
+
[](https://pypi.org/project/coreml-complexity-analyzer/)
|
|
41
|
+
[](https://opensource.org/licenses/BSD-3-Clause)
|
|
42
|
+
|
|
43
|
+
## Why This Exists
|
|
44
|
+
|
|
45
|
+
Before deploying Core ML models to Apple devices, developers need to understand:
|
|
46
|
+
|
|
47
|
+
- **Compute cost**: How many FLOPS/MACs does the model require?
|
|
48
|
+
- **Memory footprint**: How much memory for parameters and activations?
|
|
49
|
+
- **Bottleneck layers**: Which layers dominate compute and memory?
|
|
50
|
+
|
|
51
|
+
`coremltools` does not provide these analysis capabilities out of the box. This package fills that gap.
|
|
52
|
+
|
|
53
|
+
## Installation
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install coreml-complexity-analyzer
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Requirements: `coremltools >= 7.0`, `numpy`
|
|
60
|
+
|
|
61
|
+
## Quick Start
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import coremltools as ct
|
|
65
|
+
from coreml_complexity_analyzer import generate_report
|
|
66
|
+
|
|
67
|
+
model = ct.models.MLModel("my_model.mlpackage")
|
|
68
|
+
report = generate_report(model, "ResNet50")
|
|
69
|
+
|
|
70
|
+
print(f"Total GFLOPS: {report.total_gflops:.2f}")
|
|
71
|
+
print(f"Parameters: {report.parameters_millions:.2f}M")
|
|
72
|
+
print(f"Memory: {report.memory_breakdown.total_mb:.2f} MB")
|
|
73
|
+
|
|
74
|
+
# Full markdown report
|
|
75
|
+
print(report.to_markdown())
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## API
|
|
79
|
+
|
|
80
|
+
### FLOPSAnalyzer
|
|
81
|
+
|
|
82
|
+
Compute floating-point operations for each layer in a model.
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from coreml_complexity_analyzer import FLOPSAnalyzer
|
|
86
|
+
|
|
87
|
+
analyzer = FLOPSAnalyzer(model)
|
|
88
|
+
total = analyzer.get_total_flops()
|
|
89
|
+
breakdown = analyzer.get_layer_breakdown()
|
|
90
|
+
by_type = analyzer.get_flops_by_op_type()
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### MemoryEstimator
|
|
94
|
+
|
|
95
|
+
Estimate memory requirements (parameters + activations + overhead).
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from coreml_complexity_analyzer import MemoryEstimator
|
|
99
|
+
|
|
100
|
+
estimator = MemoryEstimator(model)
|
|
101
|
+
breakdown = estimator.estimate()
|
|
102
|
+
param_count = estimator.get_parameter_count()
|
|
103
|
+
|
|
104
|
+
print(f"Total: {breakdown.total_mb:.2f} MB")
|
|
105
|
+
print(f"Parameters: {breakdown.parameter_mb:.2f} MB")
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### LayerProfiler
|
|
109
|
+
|
|
110
|
+
Detailed per-layer analysis combining FLOPS, memory, and shape information.
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from coreml_complexity_analyzer import LayerProfiler
|
|
114
|
+
|
|
115
|
+
profiler = LayerProfiler(model)
|
|
116
|
+
profiles = profiler.profile()
|
|
117
|
+
|
|
118
|
+
top_layers = profiler.get_top_layers(n=5, by="flops")
|
|
119
|
+
for layer in top_layers:
|
|
120
|
+
print(f"{layer.name}: {layer.mflops:.2f} MFLOPS")
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### generate_report
|
|
124
|
+
|
|
125
|
+
Generate comprehensive reports combining all analyses.
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from coreml_complexity_analyzer import generate_report
|
|
129
|
+
|
|
130
|
+
report = generate_report(model, "ModelName")
|
|
131
|
+
|
|
132
|
+
# Output formats
|
|
133
|
+
print(report.to_markdown()) # Markdown table
|
|
134
|
+
print(report.to_text()) # Plain text
|
|
135
|
+
data = report.to_dict() # Dictionary
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Supported Operations
|
|
139
|
+
|
|
140
|
+
| Category | Operations |
|
|
141
|
+
|----------|-----------|
|
|
142
|
+
| Convolutions | `conv`, `conv_transpose` |
|
|
143
|
+
| Linear | `linear`, `matmul`, `einsum` |
|
|
144
|
+
| Activations | `relu`, `sigmoid`, `tanh`, `gelu`, `silu`, `softplus` |
|
|
145
|
+
| Normalization | `batch_norm`, `layer_norm`, `instance_norm` |
|
|
146
|
+
| Pooling | `max_pool`, `avg_pool` |
|
|
147
|
+
| Element-wise | `add`, `sub`, `mul`, `div` |
|
|
148
|
+
| Reductions | `reduce_sum`, `reduce_mean`, `reduce_max`, `reduce_min` |
|
|
149
|
+
| Other | `softmax` |
|
|
150
|
+
|
|
151
|
+
## Example Output
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
============================================================
|
|
155
|
+
Model Complexity Report: ResNet50
|
|
156
|
+
============================================================
|
|
157
|
+
SUMMARY
|
|
158
|
+
----------------------------------------
|
|
159
|
+
Total FLOPS: 4,089,184,256
|
|
160
|
+
Total GFLOPS: 4.09
|
|
161
|
+
Parameters: 25,557,032
|
|
162
|
+
Parameters (M): 25.56
|
|
163
|
+
|
|
164
|
+
MEMORY ANALYSIS
|
|
165
|
+
----------------------------------------
|
|
166
|
+
Total Memory: 106.42 MB
|
|
167
|
+
Parameters: 97.52 MB
|
|
168
|
+
|
|
169
|
+
TOP OPERATIONS BY FLOPS
|
|
170
|
+
----------------------------------------
|
|
171
|
+
conv 3,891,200,000 ( 95.2%)
|
|
172
|
+
linear 102,400,000 ( 2.5%)
|
|
173
|
+
batch_norm 51,200,000 ( 1.3%)
|
|
174
|
+
============================================================
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Use Cases
|
|
178
|
+
|
|
179
|
+
- **Model Optimization**: Identify bottleneck layers before applying compression
|
|
180
|
+
- **Deployment Planning**: Estimate if a model fits device constraints
|
|
181
|
+
- **Model Comparison**: Compare efficiency across architectures
|
|
182
|
+
- **Research**: Analyze compute/memory trade-offs
|
|
183
|
+
|
|
184
|
+
## Development
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
git clone https://github.com/yaswanth169/coreml-complexity-analyzer.git
|
|
188
|
+
cd coreml-complexity-analyzer
|
|
189
|
+
pip install -e ".[dev]"
|
|
190
|
+
pytest
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## License
|
|
194
|
+
|
|
195
|
+
BSD-3-Clause
|
|
196
|
+
|
|
197
|
+
## Authors
|
|
198
|
+
|
|
199
|
+
- Devavarapu Yashwanth
|
|
200
|
+
- Ireddi Rakshitha
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# coreml-complexity-analyzer
|
|
2
|
+
|
|
3
|
+
FLOPS estimation, memory analysis, and per-layer profiling for Core ML models.
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/coreml-complexity-analyzer/)
|
|
6
|
+
[](https://opensource.org/licenses/BSD-3-Clause)
|
|
7
|
+
|
|
8
|
+
## Why This Exists
|
|
9
|
+
|
|
10
|
+
Before deploying Core ML models to Apple devices, developers need to understand:
|
|
11
|
+
|
|
12
|
+
- **Compute cost**: How many FLOPS/MACs does the model require?
|
|
13
|
+
- **Memory footprint**: How much memory for parameters and activations?
|
|
14
|
+
- **Bottleneck layers**: Which layers dominate compute and memory?
|
|
15
|
+
|
|
16
|
+
`coremltools` does not provide these analysis capabilities out of the box. This package fills that gap.
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install coreml-complexity-analyzer
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Requirements: `coremltools >= 7.0`, `numpy`
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import coremltools as ct
|
|
30
|
+
from coreml_complexity_analyzer import generate_report
|
|
31
|
+
|
|
32
|
+
model = ct.models.MLModel("my_model.mlpackage")
|
|
33
|
+
report = generate_report(model, "ResNet50")
|
|
34
|
+
|
|
35
|
+
print(f"Total GFLOPS: {report.total_gflops:.2f}")
|
|
36
|
+
print(f"Parameters: {report.parameters_millions:.2f}M")
|
|
37
|
+
print(f"Memory: {report.memory_breakdown.total_mb:.2f} MB")
|
|
38
|
+
|
|
39
|
+
# Full markdown report
|
|
40
|
+
print(report.to_markdown())
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## API
|
|
44
|
+
|
|
45
|
+
### FLOPSAnalyzer
|
|
46
|
+
|
|
47
|
+
Compute floating-point operations for each layer in a model.
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from coreml_complexity_analyzer import FLOPSAnalyzer
|
|
51
|
+
|
|
52
|
+
analyzer = FLOPSAnalyzer(model)
|
|
53
|
+
total = analyzer.get_total_flops()
|
|
54
|
+
breakdown = analyzer.get_layer_breakdown()
|
|
55
|
+
by_type = analyzer.get_flops_by_op_type()
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### MemoryEstimator
|
|
59
|
+
|
|
60
|
+
Estimate memory requirements (parameters + activations + overhead).
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from coreml_complexity_analyzer import MemoryEstimator
|
|
64
|
+
|
|
65
|
+
estimator = MemoryEstimator(model)
|
|
66
|
+
breakdown = estimator.estimate()
|
|
67
|
+
param_count = estimator.get_parameter_count()
|
|
68
|
+
|
|
69
|
+
print(f"Total: {breakdown.total_mb:.2f} MB")
|
|
70
|
+
print(f"Parameters: {breakdown.parameter_mb:.2f} MB")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### LayerProfiler
|
|
74
|
+
|
|
75
|
+
Detailed per-layer analysis combining FLOPS, memory, and shape information.
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from coreml_complexity_analyzer import LayerProfiler
|
|
79
|
+
|
|
80
|
+
profiler = LayerProfiler(model)
|
|
81
|
+
profiles = profiler.profile()
|
|
82
|
+
|
|
83
|
+
top_layers = profiler.get_top_layers(n=5, by="flops")
|
|
84
|
+
for layer in top_layers:
|
|
85
|
+
print(f"{layer.name}: {layer.mflops:.2f} MFLOPS")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### generate_report
|
|
89
|
+
|
|
90
|
+
Generate comprehensive reports combining all analyses.
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from coreml_complexity_analyzer import generate_report
|
|
94
|
+
|
|
95
|
+
report = generate_report(model, "ModelName")
|
|
96
|
+
|
|
97
|
+
# Output formats
|
|
98
|
+
print(report.to_markdown()) # Markdown table
|
|
99
|
+
print(report.to_text()) # Plain text
|
|
100
|
+
data = report.to_dict() # Dictionary
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Supported Operations
|
|
104
|
+
|
|
105
|
+
| Category | Operations |
|
|
106
|
+
|----------|-----------|
|
|
107
|
+
| Convolutions | `conv`, `conv_transpose` |
|
|
108
|
+
| Linear | `linear`, `matmul`, `einsum` |
|
|
109
|
+
| Activations | `relu`, `sigmoid`, `tanh`, `gelu`, `silu`, `softplus` |
|
|
110
|
+
| Normalization | `batch_norm`, `layer_norm`, `instance_norm` |
|
|
111
|
+
| Pooling | `max_pool`, `avg_pool` |
|
|
112
|
+
| Element-wise | `add`, `sub`, `mul`, `div` |
|
|
113
|
+
| Reductions | `reduce_sum`, `reduce_mean`, `reduce_max`, `reduce_min` |
|
|
114
|
+
| Other | `softmax` |
|
|
115
|
+
|
|
116
|
+
## Example Output
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
============================================================
|
|
120
|
+
Model Complexity Report: ResNet50
|
|
121
|
+
============================================================
|
|
122
|
+
SUMMARY
|
|
123
|
+
----------------------------------------
|
|
124
|
+
Total FLOPS: 4,089,184,256
|
|
125
|
+
Total GFLOPS: 4.09
|
|
126
|
+
Parameters: 25,557,032
|
|
127
|
+
Parameters (M): 25.56
|
|
128
|
+
|
|
129
|
+
MEMORY ANALYSIS
|
|
130
|
+
----------------------------------------
|
|
131
|
+
Total Memory: 106.42 MB
|
|
132
|
+
Parameters: 97.52 MB
|
|
133
|
+
|
|
134
|
+
TOP OPERATIONS BY FLOPS
|
|
135
|
+
----------------------------------------
|
|
136
|
+
conv 3,891,200,000 ( 95.2%)
|
|
137
|
+
linear 102,400,000 ( 2.5%)
|
|
138
|
+
batch_norm 51,200,000 ( 1.3%)
|
|
139
|
+
============================================================
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Use Cases
|
|
143
|
+
|
|
144
|
+
- **Model Optimization**: Identify bottleneck layers before applying compression
|
|
145
|
+
- **Deployment Planning**: Estimate if a model fits device constraints
|
|
146
|
+
- **Model Comparison**: Compare efficiency across architectures
|
|
147
|
+
- **Research**: Analyze compute/memory trade-offs
|
|
148
|
+
|
|
149
|
+
## Development
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
git clone https://github.com/yaswanth169/coreml-complexity-analyzer.git
|
|
153
|
+
cd coreml-complexity-analyzer
|
|
154
|
+
pip install -e ".[dev]"
|
|
155
|
+
pytest
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## License
|
|
159
|
+
|
|
160
|
+
BSD-3-Clause
|
|
161
|
+
|
|
162
|
+
## Authors
|
|
163
|
+
|
|
164
|
+
- Devavarapu Yashwanth
|
|
165
|
+
- Ireddi Rakshitha
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Copyright (c) 2025, Devavarapu Yashwanth, Ireddi Rakshitha. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# Use of this source code is governed by a BSD-3-clause license that can be
|
|
4
|
+
# found in the LICENSE file.
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
Model Complexity Analyzer for Core ML Models.
|
|
8
|
+
|
|
9
|
+
Provides FLOPS estimation, memory footprint analysis, and
|
|
10
|
+
detailed per-layer profiling for Core ML models.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__version__ = "0.1.0"
|
|
14
|
+
|
|
15
|
+
from .flops_analyzer import FLOPSAnalyzer, LayerFLOPS
|
|
16
|
+
from .memory_estimator import MemoryEstimator, MemoryBreakdown
|
|
17
|
+
from .compute_cost_report import ComputeCostReport, generate_report
|
|
18
|
+
from .layer_profiler import LayerProfiler, LayerProfile
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"FLOPSAnalyzer",
|
|
22
|
+
"LayerFLOPS",
|
|
23
|
+
"MemoryEstimator",
|
|
24
|
+
"MemoryBreakdown",
|
|
25
|
+
"ComputeCostReport",
|
|
26
|
+
"generate_report",
|
|
27
|
+
"LayerProfiler",
|
|
28
|
+
"LayerProfile",
|
|
29
|
+
]
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# Copyright (c) 2025, Devavarapu Yashwanth, Ireddi Rakshitha. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# Use of this source code is governed by a BSD-3-clause license that can be
|
|
4
|
+
# found in the LICENSE file.
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
Compute Cost Report Generator for Core ML Models.
|
|
8
|
+
|
|
9
|
+
Generates human-readable reports summarizing model complexity metrics
|
|
10
|
+
including FLOPS, memory, and computational cost analysis.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from typing import Dict, List, Optional, Any
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
|
|
17
|
+
from .flops_analyzer import FLOPSAnalyzer, LayerFLOPS
|
|
18
|
+
from .memory_estimator import MemoryEstimator, MemoryBreakdown
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class ComputeCostReport:
|
|
23
|
+
"""Complete compute cost report for a Core ML model."""
|
|
24
|
+
|
|
25
|
+
model_name: str
|
|
26
|
+
total_flops: int
|
|
27
|
+
total_mac_ops: int
|
|
28
|
+
total_parameters: int
|
|
29
|
+
memory_breakdown: MemoryBreakdown
|
|
30
|
+
layer_breakdown: List[LayerFLOPS]
|
|
31
|
+
flops_by_op_type: Dict[str, int]
|
|
32
|
+
generated_at: str = field(default_factory=lambda: datetime.now().isoformat())
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def total_gflops(self) -> float:
|
|
36
|
+
"""Total FLOPS in billions."""
|
|
37
|
+
return self.total_flops / 1e9
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def total_mflops(self) -> float:
|
|
41
|
+
"""Total FLOPS in millions."""
|
|
42
|
+
return self.total_flops / 1e6
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def parameters_millions(self) -> float:
|
|
46
|
+
"""Parameters in millions."""
|
|
47
|
+
return self.total_parameters / 1e6
|
|
48
|
+
|
|
49
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
50
|
+
"""Convert report to dictionary."""
|
|
51
|
+
return {
|
|
52
|
+
"model_name": self.model_name,
|
|
53
|
+
"generated_at": self.generated_at,
|
|
54
|
+
"summary": {
|
|
55
|
+
"total_flops": self.total_flops,
|
|
56
|
+
"total_gflops": self.total_gflops,
|
|
57
|
+
"total_mac_ops": self.total_mac_ops,
|
|
58
|
+
"total_parameters": self.total_parameters,
|
|
59
|
+
"parameters_millions": self.parameters_millions,
|
|
60
|
+
},
|
|
61
|
+
"memory": self.memory_breakdown.to_dict(),
|
|
62
|
+
"flops_by_op_type": self.flops_by_op_type,
|
|
63
|
+
"top_layers": [
|
|
64
|
+
{
|
|
65
|
+
"name": layer.name,
|
|
66
|
+
"op_type": layer.op_type,
|
|
67
|
+
"flops": layer.flops,
|
|
68
|
+
"mflops": layer.mflops,
|
|
69
|
+
}
|
|
70
|
+
for layer in self.layer_breakdown[:10]
|
|
71
|
+
],
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
def to_markdown(self) -> str:
|
|
75
|
+
"""Generate a markdown formatted report."""
|
|
76
|
+
lines = [
|
|
77
|
+
f"# Model Complexity Report: {self.model_name}",
|
|
78
|
+
"",
|
|
79
|
+
f"*Generated at: {self.generated_at}*",
|
|
80
|
+
"",
|
|
81
|
+
"## Summary",
|
|
82
|
+
"",
|
|
83
|
+
"| Metric | Value |",
|
|
84
|
+
"|--------|-------|",
|
|
85
|
+
f"| Total FLOPS | {self.total_flops:,} |",
|
|
86
|
+
f"| Total GFLOPS | {self.total_gflops:.2f} |",
|
|
87
|
+
f"| Total MAC Ops | {self.total_mac_ops:,} |",
|
|
88
|
+
f"| Total Parameters | {self.total_parameters:,} |",
|
|
89
|
+
f"| Parameters (M) | {self.parameters_millions:.2f} |",
|
|
90
|
+
"",
|
|
91
|
+
"## Memory Analysis",
|
|
92
|
+
"",
|
|
93
|
+
"| Component | Size |",
|
|
94
|
+
"|-----------|------|",
|
|
95
|
+
f"| Total Memory | {self.memory_breakdown.total_mb:.2f} MB |",
|
|
96
|
+
f"| Parameter Memory | {self.memory_breakdown.parameter_mb:.2f} MB |",
|
|
97
|
+
f"| Activation Memory | {self.memory_breakdown.activation_mb:.2f} MB |",
|
|
98
|
+
f"| Overhead | {self.memory_breakdown.overhead_bytes / (1024*1024):.2f} MB |",
|
|
99
|
+
"",
|
|
100
|
+
"## FLOPS by Operation Type",
|
|
101
|
+
"",
|
|
102
|
+
"| Operation | FLOPS | Percentage |",
|
|
103
|
+
"|-----------|-------|------------|",
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
for op_type, flops in list(self.flops_by_op_type.items())[:15]:
|
|
107
|
+
percentage = (
|
|
108
|
+
(flops / self.total_flops * 100) if self.total_flops > 0 else 0
|
|
109
|
+
)
|
|
110
|
+
lines.append(f"| {op_type} | {flops:,} | {percentage:.1f}% |")
|
|
111
|
+
|
|
112
|
+
lines.extend(
|
|
113
|
+
[
|
|
114
|
+
"",
|
|
115
|
+
"## Top 10 Layers by FLOPS",
|
|
116
|
+
"",
|
|
117
|
+
"| Layer | Type | FLOPS | MFLOPS |",
|
|
118
|
+
"|-------|------|-------|--------|",
|
|
119
|
+
]
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
for layer in self.layer_breakdown[:10]:
|
|
123
|
+
lines.append(
|
|
124
|
+
f"| {layer.name[:40]} | {layer.op_type} | "
|
|
125
|
+
f"{layer.flops:,} | {layer.mflops:.2f} |"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
return "\n".join(lines)
|
|
129
|
+
|
|
130
|
+
def to_text(self) -> str:
|
|
131
|
+
"""Generate a plain text report."""
|
|
132
|
+
separator = "=" * 60
|
|
133
|
+
lines = [
|
|
134
|
+
separator,
|
|
135
|
+
f"Model Complexity Report: {self.model_name}",
|
|
136
|
+
separator,
|
|
137
|
+
f"Generated: {self.generated_at}",
|
|
138
|
+
"",
|
|
139
|
+
"SUMMARY",
|
|
140
|
+
"-" * 40,
|
|
141
|
+
f" Total FLOPS: {self.total_flops:>15,}",
|
|
142
|
+
f" Total GFLOPS: {self.total_gflops:>15.2f}",
|
|
143
|
+
f" Total MAC Ops: {self.total_mac_ops:>15,}",
|
|
144
|
+
f" Parameters: {self.total_parameters:>15,}",
|
|
145
|
+
f" Parameters (M): {self.parameters_millions:>15.2f}",
|
|
146
|
+
"",
|
|
147
|
+
"MEMORY ANALYSIS",
|
|
148
|
+
"-" * 40,
|
|
149
|
+
f" Total Memory: {self.memory_breakdown.total_mb:>12.2f} MB",
|
|
150
|
+
f" Parameters: {self.memory_breakdown.parameter_mb:>12.2f} MB",
|
|
151
|
+
f" Activations: {self.memory_breakdown.activation_mb:>12.2f} MB",
|
|
152
|
+
"",
|
|
153
|
+
"TOP OPERATIONS BY FLOPS",
|
|
154
|
+
"-" * 40,
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
for op_type, flops in list(self.flops_by_op_type.items())[:10]:
|
|
158
|
+
percentage = (
|
|
159
|
+
(flops / self.total_flops * 100) if self.total_flops > 0 else 0
|
|
160
|
+
)
|
|
161
|
+
lines.append(f" {op_type:<20} {flops:>12,} ({percentage:>5.1f}%)")
|
|
162
|
+
|
|
163
|
+
lines.extend(["", separator])
|
|
164
|
+
|
|
165
|
+
return "\n".join(lines)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def generate_report(model, model_name: Optional[str] = None) -> ComputeCostReport:
|
|
169
|
+
"""
|
|
170
|
+
Generate a comprehensive compute cost report for a Core ML model.
|
|
171
|
+
|
|
172
|
+
Parameters
|
|
173
|
+
----------
|
|
174
|
+
model : MLModel or str
|
|
175
|
+
A loaded MLModel instance or path to a .mlmodel/.mlpackage file.
|
|
176
|
+
model_name : str, optional
|
|
177
|
+
Name to use in the report. Defaults to "Unnamed Model".
|
|
178
|
+
|
|
179
|
+
Returns
|
|
180
|
+
-------
|
|
181
|
+
ComputeCostReport
|
|
182
|
+
Complete report with FLOPS, memory, and layer breakdown.
|
|
183
|
+
|
|
184
|
+
Examples
|
|
185
|
+
--------
|
|
186
|
+
>>> import coremltools as ct
|
|
187
|
+
>>> from coreml_complexity_analyzer import generate_report
|
|
188
|
+
>>>
|
|
189
|
+
>>> model = ct.models.MLModel("my_model.mlpackage")
|
|
190
|
+
>>> report = generate_report(model, "MyModel")
|
|
191
|
+
>>> print(report.to_markdown())
|
|
192
|
+
>>>
|
|
193
|
+
>>> print(f"Total GFLOPS: {report.total_gflops:.2f}")
|
|
194
|
+
>>> print(f"Memory: {report.memory_breakdown.total_mb:.2f} MB")
|
|
195
|
+
"""
|
|
196
|
+
if model_name is None:
|
|
197
|
+
model_name = "Unnamed Model"
|
|
198
|
+
|
|
199
|
+
flops_analyzer = FLOPSAnalyzer(model)
|
|
200
|
+
memory_estimator = MemoryEstimator(model)
|
|
201
|
+
|
|
202
|
+
layer_breakdown = flops_analyzer.analyze()
|
|
203
|
+
flops_by_op_type = flops_analyzer.get_flops_by_op_type()
|
|
204
|
+
memory_breakdown = memory_estimator.estimate()
|
|
205
|
+
|
|
206
|
+
return ComputeCostReport(
|
|
207
|
+
model_name=model_name,
|
|
208
|
+
total_flops=flops_analyzer.get_total_flops(),
|
|
209
|
+
total_mac_ops=flops_analyzer.get_total_mac_ops(),
|
|
210
|
+
total_parameters=memory_estimator.get_parameter_count(),
|
|
211
|
+
memory_breakdown=memory_breakdown,
|
|
212
|
+
layer_breakdown=layer_breakdown,
|
|
213
|
+
flops_by_op_type=flops_by_op_type,
|
|
214
|
+
)
|