Voltline's picture
Release VimeML V2.1 step40000 FP32 and Core ML INT8 (GPL-2.0)
29f25be verified
Raw History Blame Contribute Delete
2.76 kB
"""Report where Core ML would place each op of a package (CPU / GPU / Neural Engine).
Uses MLComputePlan on this Mac. Placement on iPhone can differ; confirm with a device run.
"""
import argparse
import json
import shutil
import tempfile
from collections import Counter
from pathlib import Path
def plan(package, units):
import coremltools as ct
from coremltools.models.compute_plan import MLComputePlan
from coremltools.models.compute_device import MLCPUComputeDevice, MLGPUComputeDevice, MLNeuralEngineComputeDevice
names = {MLCPUComputeDevice: "cpu", MLGPUComputeDevice: "gpu", MLNeuralEngineComputeDevice: "ane"}
temporary = Path(tempfile.mkdtemp())
try:
compiled = ct.utils.compile_model(str(package), str(temporary / "model.mlmodelc"))
compute_plan = MLComputePlan.load_from_path(path=str(compiled), compute_units=getattr(ct.ComputeUnit, units))
program = compute_plan.model_structure.program
placement, cost, details = Counter(), Counter(), []
for function in program.functions.values():
for operation in function.block.operations:
usage = compute_plan.get_compute_device_usage_for_mlprogram_operation(operation)
if usage is None:
continue
device = names.get(type(usage.preferred_compute_device), "other")
estimate = compute_plan.get_estimated_cost_for_mlprogram_operation(operation)
weight = estimate.weight if estimate else 0.0
placement[device] += 1
cost[device] += weight
details.append({"op": operation.operator_name, "device": device, "cost": weight,
"supported": sorted({names.get(type(d), "other")
for d in usage.supported_compute_devices})})
return {"package": str(package), "compute_units": units, "ops_by_device": dict(placement),
"estimated_cost_by_device": {k: round(v, 4) for k, v in cost.items()}, "ops": details}
finally:
shutil.rmtree(temporary, ignore_errors=True)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--model", type=Path, required=True, help="Experiment directory with model.mlpackage")
parser.add_argument("--compute-units", default="CPU_AND_NE", choices=("CPU_ONLY", "CPU_AND_GPU", "CPU_AND_NE", "ALL"))
parser.add_argument("--details", action="store_true", help="Print every op")
args = parser.parse_args()
report = plan(args.model / "model.mlpackage", args.compute_units)
if not args.details:
report.pop("ops")
print(json.dumps(report, indent=2))
if __name__ == "__main__":
main()