MetalTensor is a lightweight neural network inference framework built on Apple Metal / Metal Performance Shaders for real-time vision workloads on iOS. It uses plist files to describe network structure, supports loading weights either from separate files or a single binary blob, and plugs directly into the MetalImage video processing pipeline.
The repository currently includes three complete demos:
- MobileNetV2: real-time image classification
- PortraitSegment: portrait segmentation
- RapidFaceDetect: face detection with 68 facial landmarks
Note
MetalTensoris now distributed through Swift Package Manager and resolvesMetalImagefromhttps://github.com/feng1919/MetalImage- The legacy demo projects in
Examples/are still Xcode-project based- Metal code must run on a real device; the simulator is not supported
MetalTensor is a good fit for:
- deploying trained CNN models to iPhone / iPad
- processing live camera frames with a GPU preprocessing + inference + rendering pipeline
- building inference graphs from configuration files instead of wiring every layer manually
- reusing the same inference infrastructure across classification, segmentation, and detection tasks
.
├── Framework/ # MetalTensor framework sources and Xcode project
│ └── MetalTensor/
├── Package.swift # Swift Package Manager manifest
├── Examples/
│ ├── MobileNetV2/ # Image classification demo
│ ├── PortraitSegment/ # Portrait segmentation demo
│ └── RapidFaceDetect/ # Face detection / landmarks demo
└── LICENSE
- inference runtime centered on
MetalNeuralNetwork - network topology in
plist, weight-range mapping injson, and weight blobs inbin - synchronous and asynchronous inference
float16/float32precision selection- direct input from either
MTLTextureorMetalTensor - output retrieval through output layers or completion callbacks
- built-in SSD decoding utilities for detection workflows
Add MetalTensor as a package dependency:
.package(url: "https://github.com/feng1919/MetalTensor", branch: "master")Then depend on the MetalTensor product:
.product(name: "MetalTensor", package: "MetalTensor")MetalImage is pulled in automatically by MetalTensor through Swift Package Manager, so you no longer need to vendor MetalImage.framework inside your app or framework target.
Until release tags are published, use the master branch in Swift Package Manager.
Layer types visible in the current codebase include:
inputoutputconvolutiondensesoftmaxpooling_averagepooling_maxreshapeconcatenateinverted_residualarithmeticneurontrans_conv
You can open any of these demo projects directly:
Examples/MobileNetV2/MobileNetV2.xcodeprojExamples/PortraitSegment/PortraitSegment.xcodeprojExamples/RapidFaceDetect/RapidFaceDetect.xcodeproj
Each demo references the local Framework/MetalTensor.xcodeproj. The Swift package target uses the remote MetalImage package dependency instead of the vendored binary framework.
The demos depend on Metal and camera input, so they need to run on an iPhone / iPad device.
Camera-based demos require camera permission the first time they are launched.
A typical setup uses three files:
YourModel.plist: network structure descriptionYourModel.bin: merged weights fileYourModel.json: mapping from weight names to binary ranges
If your weights are stored per layer, you can also use loadWeights to load them individually.
The common pattern is to subclass MetalNeuralNetwork:
#import <MetalTensor/MetalNeuralNetwork.h>
@interface YourNet : MetalNeuralNetwork
@end
@implementation YourNet
- (instancetype)init {
NSString *plist = [[NSBundle mainBundle] pathForResource:@"YourModel" ofType:@"plist"];
return [self initWithPlist:plist];
}
- (void)loadWeights {
NSString *weights = [[NSBundle mainBundle] pathForResource:@"YourModel" ofType:@"bin"];
NSString *map = [[NSBundle mainBundle] pathForResource:@"YourModel" ofType:@"json"];
[self loadWeights:weights mapFile:map];
}
@endYourNet *net = [[YourNet alloc] init];
net.synchronizedProcessing = NO; // optional
net.dataType = MPSDataTypeFloat16; // float16 is the default
[net compile:[MetalDevice sharedMTLDevice]];
[net loadWeights];If you are already inside a MetalImage pipeline, the network can be added as a node. If you already have a texture, you can call:
[net predict:bgraTexture];Tensor input is also supported:
[net predictWithTensor:tensor];Two common patterns are:
- attach a
completedHandlerand read outputs when the command buffer finishes - fetch a
MetalTensorOutputLayerand continue processing itsMPSImage/ tensor output
Examples/MobileNetV2/MobileNetV2/MobileNetV2.m shows how to convert float16 output into classification results inside completedHandler.
MobileNetV2_1.0.plist shows the basic MetalTensor graph format:
<key>input</key>
<dict>
<key>inputs</key>
<string>224, 224, 3</string>
<key>targets</key>
<string>preprocess</string>
<key>type</key>
<string>input</string>
</dict>Each node typically defines:
type: layer typeinputs: input shapetargets: downstream layersweight/weights: weight nameskernel/stride/padding/activation: layer parameters
During compile:, the framework will:
- parse the configuration
- instantiate layer descriptors
- create the corresponding layer objects
- connect the full computation graph
- captures camera frames
- crops the center region and resizes it to the network input size
- overlays classification results and FPS on screen
Key files:
Examples/MobileNetV2/MobileNetV2/MobileNetV2.mExamples/MobileNetV2/MobileNetV2/ViewController.m
- sends camera frames into a segmentation network
- outputs a single-channel portrait mask
- composites the mask with the original image in a custom fragment shader
Key files:
Examples/PortraitSegment/PortraitSegment/PortraitSegmentNet.hExamples/PortraitSegment/PortraitSegment/PortraitSegmentFilter.mExamples/PortraitSegment/PortraitSegment/ViewController.m
- runs face detection first
- predicts facial landmarks on the detected face region
- draws bounding boxes and landmark points back onto the image
Key files:
Examples/RapidFaceDetect/RapidFaceDetect/RapidFaceDetectNet.hExamples/RapidFaceDetect/RapidFaceDetect/RapidFaceDetectFilter.mExamples/RapidFaceDetect/RapidFaceDetect/LandmarksNet.hExamples/RapidFaceDetect/RapidFaceDetect/LandmarksFilter.m
MetalTensor is designed around the MetalImage ecosystem. MetalNeuralNetwork subclasses MetalImageOutput and conforms to MetalImageInput, so it can be inserted into an existing GPU image pipeline like a regular MetalImage filter.
That is why the demo projects use chain-style connections like this:
[videoCamera addTarget:cropFilter];
[cropFilter addTarget:resizeFilter];
[resizeFilter addTarget:net];If your app already uses MetalImage, integration is relatively straightforward.
- the current repository is primarily organized around iOS framework code and demos
- demo projects depend on the bundled
MetalImage.framework - there is no model conversion tool in this repository; model descriptors and weights must be prepared separately
- this repository focuses on inference, not training
This project is released under the MIT License. See LICENSE.