Documentation
¶
Overview ¶
Package coreml runs a trained model on a Mac's Neural Engine from pure Go, with no cgo and no Xcode.
The Neural Engine is the part of an Apple chip that costs almost nothing to use. Depth Anything V2 Small, on an M4 Max, one 518x392 frame:
processor only 46 ms per frame, 114 ms of processor time processor and GPU 13 ms per frame, 5.1 ms of processor time processor and Neural Engine 23 ms per frame, 0.4 ms of processor time
The Neural Engine is not the fastest of the three. It is the one that leaves the machine alone: a frame costs four tenths of a millisecond of CPU, which is nearly three hundred times less than doing it on the processor. On a laptop that is also drawing a browser and syncing files, that is the number a person feels.
// once, and it is kept: compiling is slow and the result is durable
err := coreml.Compile("Depth.mlpackage", "Depth.mlmodelc")
m, err := coreml.Open("Depth.mlmodelc", coreml.CPUAndNeuralEngine)
defer m.Close()
in := m.Inputs()[0] // says what size the model wants
res, err := m.Predict(map[string]Value{in.Name: coreml.Image(bgra, in.Width, in.Height)})
defer res.Close()
plane, err := res.Plane("depth") // one channel, as float32
A model has to be compiled before it can be opened ¶
What a model is distributed as — an .mlpackage — is not what CoreML runs. Compile turns one into the other using the system compiler, at run time, with nothing installed. It takes seconds, so the result belongs somewhere durable: macOS compiles into a temporary directory it is free to empty, and a program that does not move the result out pays that cost on every start.
Everywhere else ¶
On a platform that is not macOS every constructor returns ErrUnsupported, so a program that offers a Neural Engine path and a portable one cross-compiles without build tags of its own.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrUnsupported = errors.New("coreml: only macOS has Core ML")
ErrUnsupported is returned on any platform that is not macOS.
Functions ¶
func Compile ¶
Compile turns a distributed .mlpackage into the .mlmodelc that Core ML actually runs, and puts it where you asked.
It does nothing if dst already exists, because compiling takes seconds and the result does not change. Moving it out of the temporary directory macOS compiles into is the whole point: that directory is emptied whenever the system feels like it, and a program that leaves the result there pays the seconds again on every start.
Types ¶
type Feature ¶
Feature describes one input or output of a model. Width and Height are set only for an image, and are what the model demands: a picture of any other size is refused, so this is the size to scale to.
type Kind ¶
type Kind int
Kind is what sort of thing a model takes or returns.
const ( // KindOther is anything this package does not yet describe: a dictionary, // a sequence, a number. Naming it is more useful than leaving it out, // because a model whose input is KindOther cannot be fed from here and the // caller should be told so rather than left guessing. KindOther Kind = iota // KindImage is a picture, and the only input this package can supply. KindImage // KindMultiArray is a tensor. KindMultiArray )
type Model ¶
type Model struct {
// contains filtered or unexported fields
}
Model is a compiled model, open and ready to predict.
func (*Model) Predict ¶
Predict runs the model once.
The picture is copied into memory CoreVideo owns rather than wrapped where it lies. It is one copy of a small image against tens of milliseconds of inference, and it removes the whole question of what Core ML may still be holding when the Go slice is collected.
type Plane ¶
Plane is one channel of an image output, as float32 whatever the model stored it as.
func (Plane) Normalised ¶
Normalised stretches the plane onto 0..255 for looking at.
A depth model's scale is relative — it says which of two things is nearer, not how far either is — so an unstretched map of a scene with no sky in it is a uniform grey that tells you nothing about whether the model worked.
Values that are not numbers are left at zero rather than poisoning the range.
type Result ¶
type Result struct {
// contains filtered or unexported fields
}
Result is what a prediction returned. Close it.
type Units ¶
type Units int
Units says which processors a model may run on.
It is a request, not an instruction: Core ML decides for itself, per layer, and a model with a layer the Neural Engine cannot do will run that layer elsewhere. Asking for CPUAndNeuralEngine is how a model reaches the Neural Engine at all — the default leaves it out.
const ( // CPUOnly is the slowest and the most predictable. CPUOnly Units = 0 // CPUAndGPU is usually the fastest in wall-clock time. CPUAndGPU Units = 1 // All lets Core ML choose, which in practice means mostly the GPU. All Units = 2 // CPUAndNeuralEngine is the cheapest in processor time by a wide margin. CPUAndNeuralEngine Units = 3 )