coreml-complexity-analyzer 0.1.0__py3-none-any.whl
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/__init__.py +29 -0
- coreml_complexity_analyzer/compute_cost_report.py +214 -0
- coreml_complexity_analyzer/flops_analyzer.py +550 -0
- coreml_complexity_analyzer/layer_profiler.py +408 -0
- coreml_complexity_analyzer/memory_estimator.py +365 -0
- coreml_complexity_analyzer-0.1.0.dist-info/METADATA +200 -0
- coreml_complexity_analyzer-0.1.0.dist-info/RECORD +10 -0
- coreml_complexity_analyzer-0.1.0.dist-info/WHEEL +5 -0
- coreml_complexity_analyzer-0.1.0.dist-info/licenses/LICENSE +28 -0
- coreml_complexity_analyzer-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -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
|
+
)
|