Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
2964 lines (2627 sloc) 158 KB
/*
Copyright (C) 2016 Apple Inc. All Rights Reserved.
See LICENSE.txt for this sample’s licensing information
Abstract:
This is the main inception network coded
*/
import Foundation
import UIKit
import MetalKit
import MetalPerformanceShaders
let textureFormat = MPSImageFeatureChannelFormat.float16
/**
This class has our entire network with all layers from preprocessing to getting the final label
Resources:
* [Instructions](https://www.tensorflow.org/versions/r0.8/tutorials/image_recognition/index.html#image-recognition) to run this network on TensorFlow.
* The [Network](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/models/image/imagenet/classify_image.py)
* [Original Inception_v3 Network Paper](http://arxiv.org/pdf/1512.00567v3.pdf)
*/
class Inception3Net{
// we keep the MTLDevice and MTLCommandQueue objects around for ease of use
var device : MTLDevice!
var commandQueue : MTLCommandQueue
// pre-processing layers and an MPSTemporaryImage for it
var lanczos : MPSImageLanczosScale!
var scale : MPSCNNNeuronLinear!
var preImage : MPSTemporaryImage!
// MPSImages are declared we need srcImage and final softMax output as MPSImages so we can read/write to underlying textures
var srcImage, sftImage : MPSImage
// standard neuron and softmax layers are declared
var relu : MPSCNNNeuronReLU
var softmax : MPSCNNSoftMax
// convolution and fully connected layers
let conv0, conv1, conv2, conv3, conv4 : SlimMPSCNNConvolution
let m0t0conv0, m0t1conv0, m0t1conv1, m0t2conv0, m0t2conv1, m0t2conv2, m0t3conv0 : SlimMPSCNNConvolution
let m1t0conv0, m1t1conv0, m1t1conv1, m1t2conv0, m1t2conv1, m1t2conv2, m1t3conv0 : SlimMPSCNNConvolution
let m2t0conv0, m2t1conv0, m2t1conv1, m2t2conv0, m2t2conv1, m2t2conv2, m2t3conv0 : SlimMPSCNNConvolution
let m3t0conv0, m3t1conv0, m3t1conv1, m3t1conv2 : SlimMPSCNNConvolution
let m4t0conv0, m4t1conv0, m4t1conv1, m4t1conv2, m4t2conv0, m4t2conv1, m4t2conv2, m4t2conv3, m4t2conv4, m4t3conv0 : SlimMPSCNNConvolution
let m5t0conv0, m5t1conv0, m5t1conv1, m5t1conv2, m5t2conv0, m5t2conv1, m5t2conv2, m5t2conv3, m5t2conv4, m5t3conv0 : SlimMPSCNNConvolution
let m6t0conv0, m6t1conv0, m6t1conv1, m6t1conv2, m6t2conv0, m6t2conv1, m6t2conv2, m6t2conv3, m6t2conv4, m6t3conv0 : SlimMPSCNNConvolution
let m7t0conv0, m7t1conv0, m7t1conv1, m7t1conv2, m7t2conv0, m7t2conv1, m7t2conv2, m7t2conv3, m7t2conv4, m7t3conv0 : SlimMPSCNNConvolution
let m8t0conv0, m8t0conv1, m8t1conv0, m8t1conv1, m8t1conv2, m8t1conv3 : SlimMPSCNNConvolution
let m9t0conv0, m9t1conv0, m9t1conv1, m9t1conv2, m9t2conv0, m9t2conv1, m9t2conv2, m9t2conv3, m9t3conv0 : SlimMPSCNNConvolution
let m10t0conv0, m10t1conv0, m10t1conv1, m10t1conv2, m10t2conv0, m10t2conv1, m10t2conv2, m10t2conv3, m10t3conv0 : SlimMPSCNNConvolution
let fc0 : SlimMPSCNNFullyConnected
// pooling layers
var mPoolinit, mPool3, mPool8, mPool10 : MPSCNNPoolingMax
let aPool, aPoolLogits : MPSCNNPoolingAverage
// MPSImageDescriptor for different mixed layer outputs
let sid = MPSImageDescriptor(channelFormat: textureFormat, width: 299, height: 299, featureChannels: 3)
let inid = MPSImageDescriptor(channelFormat: textureFormat, width: 35 , height: 35 , featureChannels: 192)
let m0id = MPSImageDescriptor(channelFormat: textureFormat, width: 35 , height: 35 , featureChannels: 256)
let m1id = MPSImageDescriptor(channelFormat: textureFormat, width: 35 , height: 35 , featureChannels: 288)
let m2id = MPSImageDescriptor(channelFormat: textureFormat, width: 35 , height: 35 , featureChannels: 288)
let m3id = MPSImageDescriptor(channelFormat: textureFormat, width: 17 , height: 17 , featureChannels: 768)
let m4id = MPSImageDescriptor(channelFormat: textureFormat, width: 17 , height: 17 , featureChannels: 768)
let m5id = MPSImageDescriptor(channelFormat: textureFormat, width: 17 , height: 17 , featureChannels: 768)
let m6id = MPSImageDescriptor(channelFormat: textureFormat, width: 17 , height: 17 , featureChannels: 768)
let m7id = MPSImageDescriptor(channelFormat: textureFormat, width: 17 , height: 17 , featureChannels: 768)
let m8id = MPSImageDescriptor(channelFormat: textureFormat, width: 8 , height: 8 , featureChannels: 1280)
let m9id = MPSImageDescriptor(channelFormat: textureFormat, width: 8 , height: 8 , featureChannels: 2048)
let m10id = MPSImageDescriptor(channelFormat: textureFormat, width: 8 , height: 8 , featureChannels: 2048)
let sftid = MPSImageDescriptor(channelFormat: textureFormat, width: 1 , height: 1 , featureChannels: 1008)
/**
This function encodes all the layers of the network into given commandBuffer,
it calls subroutines for each piece of the network
- Parameters:
- inputCommandQueue: Metal CommandQueue we got from the device to be used to do computes in future
- Returns:
Void
*/
init(withCommandQueue inputCommandQueue : MTLCommandQueue){
// keep an instance of device and commandQueue around for use
device = inputCommandQueue.device
commandQueue = inputCommandQueue
// we will resize the input image to 299x299x3 (input size to inception_v3) size using lanczos
lanczos = MPSImageLanczosScale(device: device)
// we will scale pixel values to [-1,1]
scale = MPSCNNNeuronLinear(device: device!, a: Float(2), b: Float(-1))
// initialize activation layers
relu = MPSCNNNeuronReLU(device: device!, a: 0)
softmax = MPSCNNSoftMax(device: device!)
// Initialize MPSImage from descriptors
srcImage = MPSImage(device: device!, imageDescriptor: sid)
sftImage = MPSImage(device: device!, imageDescriptor: sftid)
// define convolution, pooling and fullyConnected layers and initialize them with proper weights
// this will occur as a 1 time cost during app launch, which is beneficial to us
conv0 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 3,
inputFeatureChannels: 3,
outputFeatureChannels: 32,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "conv" ,
padding: true,
strideX: 2, strideY: 2)
conv1 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 3,
inputFeatureChannels: 32,
outputFeatureChannels: 32,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "conv_1" ,
padding: false)
conv2 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 3,
inputFeatureChannels: 32,
outputFeatureChannels: 64,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "conv_2")
conv3 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 64,
outputFeatureChannels: 80,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "conv_3",
padding: false)
conv4 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 3,
inputFeatureChannels: 80,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "conv_4",
padding: false)
mPoolinit = MPSCNNPoolingMax(device: device!, kernelWidth: 3, kernelHeight: 3, strideInPixelsX: 2, strideInPixelsY: 2)
mPoolinit.offset = MPSOffset( x: 1, y: 1, z: 0 );
mPoolinit.edgeMode = MPSImageEdgeMode.clamp
// branch1x1
m0t0conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 192,
outputFeatureChannels: 64,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_conv")
// branch5x5
m0t1conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 192,
outputFeatureChannels: 48,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_tower_conv")
m0t1conv1 = SlimMPSCNNConvolution(kernelWidth: 5,
kernelHeight: 5,
inputFeatureChannels: 48,
outputFeatureChannels: 64,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_tower_conv_1",
padding: true,
destinationFeatureChannelOffset: 64)
// branch3x3dbl
m0t2conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 192,
outputFeatureChannels: 64,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_tower_1_conv")
m0t2conv1 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 3,
inputFeatureChannels: 64,
outputFeatureChannels: 96,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_tower_1_conv_1")
m0t2conv2 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 3,
inputFeatureChannels: 96,
outputFeatureChannels: 96,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_tower_1_conv_2",
padding: true,
destinationFeatureChannelOffset: 128)
// branch_pool
m0t3conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 192,
outputFeatureChannels: 32,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_tower_2_conv",
padding: true,
destinationFeatureChannelOffset: 224)
aPool = MPSCNNPoolingAverage(device: device!, kernelWidth: 3, kernelHeight: 3, strideInPixelsX: 1, strideInPixelsY: 1)
aPool.edgeMode = MPSImageEdgeMode.clamp
// mixed 1
// branch1x1
m1t0conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 256,
outputFeatureChannels: 64,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_1_conv")
// branch5x5
m1t1conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 256,
outputFeatureChannels: 48,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_1_tower_conv")
m1t1conv1 = SlimMPSCNNConvolution(kernelWidth: 5,
kernelHeight: 5,
inputFeatureChannels: 48,
outputFeatureChannels: 64,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_1_tower_conv_1",
destinationFeatureChannelOffset: 64)
// branch3x3dbl
m1t2conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 256,
outputFeatureChannels: 64,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_1_tower_1_conv")
m1t2conv1 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 3,
inputFeatureChannels: 64,
outputFeatureChannels: 96,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_1_tower_1_conv_1")
m1t2conv2 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 3,
inputFeatureChannels: 96,
outputFeatureChannels: 96,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_1_tower_1_conv_2",
destinationFeatureChannelOffset: 128)
// branch_pool
m1t3conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 256,
outputFeatureChannels: 64,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_1_tower_2_conv",
destinationFeatureChannelOffset: 224)
// mixed 2
// branch1x1
m2t0conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 288,
outputFeatureChannels: 64,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_2_conv")
// branch5x5
m2t1conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 288,
outputFeatureChannels: 48,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_2_tower_conv")
m2t1conv1 = SlimMPSCNNConvolution(kernelWidth: 5,
kernelHeight: 5,
inputFeatureChannels: 48,
outputFeatureChannels: 64,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_2_tower_conv_1",
destinationFeatureChannelOffset: 64)
// branch3x3dbl
m2t2conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 288,
outputFeatureChannels: 64,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_2_tower_1_conv")
m2t2conv1 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 3,
inputFeatureChannels: 64,
outputFeatureChannels: 96,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_2_tower_1_conv_1")
m2t2conv2 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 3,
inputFeatureChannels: 96,
outputFeatureChannels: 96,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_2_tower_1_conv_2",
destinationFeatureChannelOffset: 128)
// branch_pool
m2t3conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 288,
outputFeatureChannels: 64,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_2_tower_2_conv",
destinationFeatureChannelOffset: 224)
// mixed 3
// branch3x3
m3t0conv0 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 3,
inputFeatureChannels: 288,
outputFeatureChannels: 384,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_3_conv",
padding: false,
strideX: 2,
strideY: 2)
// branch3x3dbl
m3t1conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 288,
outputFeatureChannels: 64,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_3_tower_conv")
m3t1conv1 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 3,
inputFeatureChannels: 64,
outputFeatureChannels: 96,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_3_tower_conv_1")
m3t1conv2 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 3,
inputFeatureChannels: 96,
outputFeatureChannels: 96,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_3_tower_conv_2",
padding: false,
strideX: 2,
strideY: 2,
destinationFeatureChannelOffset: 384)
// branch_pool
mPool3 = MPSCNNPoolingMax(device: device!, kernelWidth: 3, kernelHeight: 3, strideInPixelsX: 2, strideInPixelsY: 2)
mPool3.offset = MPSOffset( x: 1, y: 1, z: 0 );
mPool3.edgeMode = MPSImageEdgeMode.clamp
mPool3.destinationFeatureChannelOffset = 480
// mixed 4
// branch1x1
m4t0conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_4_conv")
// branch7x7
m4t1conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 128,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_4_tower_conv")
m4t1conv1 = SlimMPSCNNConvolution(kernelWidth: 7,
kernelHeight: 1,
inputFeatureChannels: 128,
outputFeatureChannels: 128,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_4_tower_conv_1")
m4t1conv2 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 7,
inputFeatureChannels: 128,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_4_tower_conv_2",
destinationFeatureChannelOffset: 192)
// branch7x7dbl
m4t2conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 128,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_4_tower_1_conv")
m4t2conv1 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 7,
inputFeatureChannels: 128,
outputFeatureChannels: 128,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_4_tower_1_conv_1")
m4t2conv2 = SlimMPSCNNConvolution(kernelWidth: 7,
kernelHeight: 1,
inputFeatureChannels: 128,
outputFeatureChannels: 128,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_4_tower_1_conv_2")
m4t2conv3 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 7,
inputFeatureChannels: 128,
outputFeatureChannels: 128,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_4_tower_1_conv_3")
m4t2conv4 = SlimMPSCNNConvolution(kernelWidth: 7,
kernelHeight: 1,
inputFeatureChannels: 128,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_4_tower_1_conv_4",
destinationFeatureChannelOffset: 384)
// branch_pool
m4t3conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_4_tower_2_conv",
destinationFeatureChannelOffset: 576)
// mixed 5
// branch1x1
m5t0conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_5_conv")
// branch7x7
m5t1conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 160,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_5_tower_conv")
m5t1conv1 = SlimMPSCNNConvolution(kernelWidth: 7,
kernelHeight: 1,
inputFeatureChannels: 160,
outputFeatureChannels: 160,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_5_tower_conv_1")
m5t1conv2 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 7,
inputFeatureChannels: 160,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_5_tower_conv_2",
destinationFeatureChannelOffset: 192)
// branch7x7dbl
m5t2conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 160,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_5_tower_1_conv")
m5t2conv1 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 7,
inputFeatureChannels: 160,
outputFeatureChannels: 160,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_5_tower_1_conv_1")
m5t2conv2 = SlimMPSCNNConvolution(kernelWidth: 7,
kernelHeight: 1,
inputFeatureChannels: 160,
outputFeatureChannels: 160,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_5_tower_1_conv_2")
m5t2conv3 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 7,
inputFeatureChannels: 160,
outputFeatureChannels: 160,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_5_tower_1_conv_3")
m5t2conv4 = SlimMPSCNNConvolution(kernelWidth: 7,
kernelHeight: 1,
inputFeatureChannels: 160,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_5_tower_1_conv_4",
destinationFeatureChannelOffset: 384)
// branch_pool
m5t3conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_5_tower_2_conv",
destinationFeatureChannelOffset: 576)
// mixed 6
// branch1x1
m6t0conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_6_conv")
// branch7x7
m6t1conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 160,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_6_tower_conv")
m6t1conv1 = SlimMPSCNNConvolution(kernelWidth: 7,
kernelHeight: 1,
inputFeatureChannels: 160,
outputFeatureChannels: 160,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_6_tower_conv_1")
m6t1conv2 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 7,
inputFeatureChannels: 160,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_6_tower_conv_2",
destinationFeatureChannelOffset: 192)
// branch7x7dbl
m6t2conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 160,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_6_tower_1_conv")
m6t2conv1 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 7,
inputFeatureChannels: 160,
outputFeatureChannels: 160,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_6_tower_1_conv_1")
m6t2conv2 = SlimMPSCNNConvolution(kernelWidth: 7,
kernelHeight: 1,
inputFeatureChannels: 160,
outputFeatureChannels: 160,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_6_tower_1_conv_2")
m6t2conv3 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 7,
inputFeatureChannels: 160,
outputFeatureChannels: 160,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_6_tower_1_conv_3")
m6t2conv4 = SlimMPSCNNConvolution(kernelWidth: 7,
kernelHeight: 1,
inputFeatureChannels: 160,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_6_tower_1_conv_4",
destinationFeatureChannelOffset: 384)
// branch_pool
m6t3conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_6_tower_2_conv",
destinationFeatureChannelOffset: 576)
// mixed 7
// branch1x1
m7t0conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_7_conv")
// branch7x7
m7t1conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_7_tower_conv")
m7t1conv1 = SlimMPSCNNConvolution(kernelWidth: 7,
kernelHeight: 1,
inputFeatureChannels: 192,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_7_tower_conv_1")
m7t1conv2 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 7,
inputFeatureChannels: 192,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_7_tower_conv_2",
destinationFeatureChannelOffset: 192)
// branch7x7dbl
m7t2conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_7_tower_1_conv")
m7t2conv1 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 7,
inputFeatureChannels: 192,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_7_tower_1_conv_1")
m7t2conv2 = SlimMPSCNNConvolution(kernelWidth: 7,
kernelHeight: 1,
inputFeatureChannels: 192,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_7_tower_1_conv_2")
m7t2conv3 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 7,
inputFeatureChannels: 192,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_7_tower_1_conv_3")
m7t2conv4 = SlimMPSCNNConvolution(kernelWidth: 7,
kernelHeight: 1,
inputFeatureChannels: 192,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_7_tower_1_conv_4",
destinationFeatureChannelOffset: 384)
// branch_pool
m7t3conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_7_tower_2_conv",
destinationFeatureChannelOffset: 576)
// mixed 8
// branch3x3
m8t0conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_8_tower_conv")
m8t0conv1 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 3,
inputFeatureChannels: 192,
outputFeatureChannels: 320,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_8_tower_conv_1",
padding: false,
strideX: 2,
strideY: 2)
// branch7x7x3dbl
m8t1conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 768,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_8_tower_1_conv")
m8t1conv1 = SlimMPSCNNConvolution(kernelWidth: 7,
kernelHeight: 1,
inputFeatureChannels: 192,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_8_tower_1_conv_1")
m8t1conv2 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 7,
inputFeatureChannels: 192,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_8_tower_1_conv_2")
m8t1conv3 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 3,
inputFeatureChannels: 192,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_8_tower_1_conv_3",
padding: false,
strideX: 2,
strideY: 2,
destinationFeatureChannelOffset: 320)
// branch_pool
mPool8 = MPSCNNPoolingMax(device: device!, kernelWidth: 3, kernelHeight: 3, strideInPixelsX: 2, strideInPixelsY: 2)
mPool8.offset = MPSOffset( x: 1, y: 1, z: 0 );
mPool8.destinationFeatureChannelOffset = 512
mPool8.edgeMode = MPSImageEdgeMode.clamp
// mixed 9
// branch1x1
m9t0conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 1280,
outputFeatureChannels: 320,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_9_conv")
// branch5x5
m9t1conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 1280,
outputFeatureChannels: 384,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_9_tower_conv")
m9t1conv1 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 1,
inputFeatureChannels: 384,
outputFeatureChannels: 384,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_9_tower_mixed_conv",
destinationFeatureChannelOffset: 320)
m9t1conv2 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 3,
inputFeatureChannels: 384,
outputFeatureChannels: 384,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_9_tower_mixed_conv_1",
destinationFeatureChannelOffset: 704)
// branch3x3
m9t2conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 1280,
outputFeatureChannels: 448,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_9_tower_1_conv")
m9t2conv1 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 3,
inputFeatureChannels: 448,
outputFeatureChannels: 384,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_9_tower_1_conv_1")
m9t2conv2 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 1,
inputFeatureChannels: 384,
outputFeatureChannels: 384,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_9_tower_1_mixed_conv",
destinationFeatureChannelOffset: 1088)
m9t2conv3 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 3,
inputFeatureChannels: 384,
outputFeatureChannels: 384,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_9_tower_1_mixed_conv_1",
destinationFeatureChannelOffset: 1472)
// branch_pool
m9t3conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 1280,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_9_tower_2_conv",
destinationFeatureChannelOffset: 1856)
// mixed 10
// branch1x1
m10t0conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 2048,
outputFeatureChannels: 320,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_10_conv")
// branch5x5
m10t1conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 2048,
outputFeatureChannels: 384,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_10_tower_conv")
m10t1conv1 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 1,
inputFeatureChannels: 384,
outputFeatureChannels: 384,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_10_tower_mixed_conv",
destinationFeatureChannelOffset: 320)
m10t1conv2 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 3,
inputFeatureChannels: 384,
outputFeatureChannels: 384,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_10_tower_mixed_conv_1",
destinationFeatureChannelOffset: 704)
// branch3x3
m10t2conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 2048,
outputFeatureChannels: 448,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_10_tower_1_conv")
m10t2conv1 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 3,
inputFeatureChannels: 448,
outputFeatureChannels: 384,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_10_tower_1_conv_1")
m10t2conv2 = SlimMPSCNNConvolution(kernelWidth: 3,
kernelHeight: 1,
inputFeatureChannels: 384,
outputFeatureChannels: 384,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_10_tower_1_mixed_conv",
destinationFeatureChannelOffset: 1088)
m10t2conv3 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 3,
inputFeatureChannels: 384,
outputFeatureChannels: 384,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_10_tower_1_mixed_conv_1",
destinationFeatureChannelOffset: 1472)
// branch_pool
m10t3conv0 = SlimMPSCNNConvolution(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 2048,
outputFeatureChannels: 192,
neuronFilter: relu,
device: device,
kernelParamsBinaryName: "mixed_10_tower_2_conv",
destinationFeatureChannelOffset: 1856)
mPool10 = MPSCNNPoolingMax(device: device, kernelWidth: 3, kernelHeight: 3)
mPool10.edgeMode = MPSImageEdgeMode.clamp
// logits
aPoolLogits = MPSCNNPoolingAverage(device: device!, kernelWidth: 8, kernelHeight: 8, strideInPixelsX: 4, strideInPixelsY: 4)
aPoolLogits.offset = MPSOffset( x: 4, y: 4, z: 0 )
aPoolLogits.edgeMode = MPSImageEdgeMode.clamp
fc0 = SlimMPSCNNFullyConnected(kernelWidth: 1,
kernelHeight: 1,
inputFeatureChannels: 2048,
outputFeatureChannels: 1008,
neuronFilter: nil,
device: device,
kernelParamsBinaryName: "softmax")
}
/**
This function encodes all the layers of the network into given commandBuffer, it calls subroutines for each piece of the network
- Parameters:
- commandBuffer: CommandBuffer to be used for encoding layer kernels and allocating MPSImage on
- Returns:
Void
*/
func forward( commandBuffer: MTLCommandBuffer, sourceTexture : MTLTexture?){
// CNN graphs usually work best if we populate MPS's internal texture cache
// with a couple of large textures, which will then be used to back most or
// all of the temporary images here. The function looks through the image
// descriptor list and finds some representative large allocation sizes and
// automatically prepopulates the cache to help make sure they run well. If
// we do not do this, then the cache is populated in usuage order, which may
// be suboptimal if the first textures are small. This is a hint.
//
// In this sample code, the aggregate benefit of the use of MPSTemporaryImages
// is to reduce the area of memory allocated to 1/4 and save about 3 ms of CPU
// time.
let descriptors = [sid, inid, m0id, m1id, m2id, m3id, m4id, m5id, m6id, m7id, m8id, m9id, m10id]
for descriptor in descriptors {
descriptor.storageMode = .private
}
MPSTemporaryImage.prefetchStorage(with: commandBuffer, imageDescriptorList: descriptors)
// we use preImage to hold preprocesing intermediate results
preImage = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: sid)
// encode pre-processing layers to change input image to a size 299x299x3 with values in range [-1,1]
lanczos.encode (commandBuffer: commandBuffer, sourceTexture: sourceTexture!, destinationTexture: preImage.texture)
scale.encode(commandBuffer: commandBuffer, sourceImage: preImage, destinationImage: srcImage)
// Do initial CNN layers before mixing occurs
init_layer(commandBuffer: commandBuffer)
// Do 11 mixing layers
mixed_0_layer (commandBuffer: commandBuffer)
mixed_1_layer (commandBuffer: commandBuffer)
mixed_2_layer (commandBuffer: commandBuffer)
mixed_3_layer (commandBuffer: commandBuffer)
mixed_4_layer (commandBuffer: commandBuffer)
mixed_5_layer (commandBuffer: commandBuffer)
mixed_6_layer (commandBuffer: commandBuffer)
mixed_7_layer (commandBuffer: commandBuffer)
mixed_8_layer (commandBuffer: commandBuffer)
mixed_9_layer (commandBuffer: commandBuffer)
mixed_10_layer(commandBuffer: commandBuffer)
// find the final result from the mixing layers
logits_layer(commandBuffer: commandBuffer)
}
// MPSImageDescriptor for init layers
let c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 149, height: 149, featureChannels: 32)
let c1id = MPSImageDescriptor(channelFormat: textureFormat, width: 147, height: 147, featureChannels: 32)
let c2id = MPSImageDescriptor(channelFormat: textureFormat, width: 147, height: 147, featureChannels: 64)
let p1id = MPSImageDescriptor(channelFormat: textureFormat, width: 73 , height: 73 , featureChannels: 64)
let c3id = MPSImageDescriptor(channelFormat: textureFormat, width: 73 , height: 73 , featureChannels: 80)
let c4id = MPSImageDescriptor(channelFormat: textureFormat, width: 71 , height: 71 , featureChannels: 192)
var c0Image, c1Image, c2Image, p1Image, c3Image, c4Image, initImage : MPSTemporaryImage!
func init_layer(commandBuffer: MTLCommandBuffer){
// These images are only needed in this layer and will not be read by the CPU or
// outside of the command bufer, so we can allocate them as MPSTemporaryImages and
// save the CPU cost and memory size of allocating reserved storage for them.
//
// These objects can not be reused outside of the command buffer, which is why
// we did not make them in the init(withDevice:commandQueue:) call.
//
// Temporary images are designed to be efficiently created as needed, used a few times
// and thrown away almost immediately
c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: c0id)
c1Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: c1id)
c2Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: c2id)
p1Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: p1id)
c3Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: c3id)
c4Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: c4id)
initImage = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: inid)
// encode layers to metal commandBuffer
conv0.encode (commandBuffer: commandBuffer, sourceImage: srcImage , destinationImage: c0Image)
conv1.encode (commandBuffer: commandBuffer, sourceImage: c0Image , destinationImage: c1Image)
conv2.encode (commandBuffer: commandBuffer, sourceImage: c1Image , destinationImage: c2Image)
mPoolinit.encode (commandBuffer: commandBuffer, sourceImage: c2Image , destinationImage: p1Image)
conv3.encode (commandBuffer: commandBuffer, sourceImage: p1Image , destinationImage: c3Image)
conv4.encode (commandBuffer: commandBuffer, sourceImage: c3Image , destinationImage: c4Image)
mPoolinit.encode (commandBuffer: commandBuffer, sourceImage: c4Image , destinationImage: initImage)
}
// MPSImageDescriptor for mixed0 layers
// branch5x5
let m0t1c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 35, height: 35, featureChannels: 48)
// branch3x3dbl
let m0t2c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 35, height: 35, featureChannels: 64)
let m0t2c1id = MPSImageDescriptor(channelFormat: textureFormat, width: 35, height: 35, featureChannels: 96)
// branch_pool
let m0t3p0id = MPSImageDescriptor(channelFormat: textureFormat, width: 35, height: 35, featureChannels: 192)
var m0t1c0Image, m0t2c0Image, m0t2c1Image, m0t3p0Image, image0 : MPSTemporaryImage!
func mixed_0_layer( commandBuffer: MTLCommandBuffer){
// These images are only needed in this layer and will not be read by the CPU or
// outside of the command bufer, so we can allocate them as MPSTemporaryImages and
// save the CPU cost and memory size of allocating reserved storage for them.
//
// These objects can not be reused outside of the command buffer, which is why
// we did not make them in the init(withDevice:commandQueue:) call.
//
// Temporary images are designed to be efficiently created as needed, used a few times
// and thrown away almost immediately
// branch5x5
m0t1c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m0t1c0id)
// branch3x3dbl
m0t2c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m0t2c0id)
m0t2c1Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m0t2c1id)
// branch_pool
m0t3p0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m0t3p0id)
image0 = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m0id)
// MPS must be able to understand with reasonably precise timing the lifetime of the
// MPSTemporaryImage in the command buffer. The pixel storage for the MPSTemporaryImage
// is not allocated until it is first used (or the .texture property is invoked) and
// the storage is promptly returned for reuse after last use. Since ARC can be a bit
// tardy about releasing the object, the MPSTemporaryImage makes use of a read counter
// to track its lifetime. The read counter tells MPS how many times the MPSTemporaryImage
// will be read (by a MPS -encode method) before its backing store can be reclaimed for
// reuse. By default, the read count is 1, meaning that the contents of the MPSTemporaryImage
// are written to the image any number of times (but typically once, since more would be
// wasteful), then read once. After it is read once, the -encode call will automatically
// return the storage for use by other MPSTemporaryImages.
//
// In the case, the layer reads initImage four times, not once. So we must set the readCount to
// four to make sure that the contents stay valid until the last time it is used.
initImage.readCount = 4
// encode layers to metal commandBuffer
// branch1x1
m0t0conv0.encode (commandBuffer: commandBuffer, sourceImage: initImage, destinationImage: image0)
// branch5x5
m0t1conv0.encode (commandBuffer: commandBuffer, sourceImage: initImage, destinationImage: m0t1c0Image)
m0t1conv1.encode (commandBuffer: commandBuffer, sourceImage: m0t1c0Image, destinationImage: image0)
// branch3x3dbl
m0t2conv0.encode (commandBuffer: commandBuffer, sourceImage: initImage, destinationImage: m0t2c0Image)
m0t2conv1.encode (commandBuffer: commandBuffer, sourceImage: m0t2c0Image, destinationImage: m0t2c1Image)
m0t2conv2.encode (commandBuffer: commandBuffer, sourceImage: m0t2c1Image, destinationImage: image0)
// branch_pool
aPool.encode (commandBuffer: commandBuffer, sourceImage: initImage, destinationImage: m0t3p0Image)
m0t3conv0.encode (commandBuffer: commandBuffer, sourceImage: m0t3p0Image, destinationImage: image0)
}
// MPSImageDescriptor for mixed1 layers
// branch5x5
let m1t1c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 35, height: 35, featureChannels: 48)
// branch3x3dbl
let m1t2c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 35, height: 35, featureChannels: 64)
let m1t2c1id = MPSImageDescriptor(channelFormat: textureFormat, width: 35, height: 35, featureChannels: 96)
// branch_pool
let m1t3p0id = MPSImageDescriptor(channelFormat: textureFormat, width: 35, height: 35, featureChannels: 256)
var m1t1c0Image, m1t2c0Image, m1t2c1Image, m1t3p0Image, image1 : MPSTemporaryImage!
func mixed_1_layer(commandBuffer: MTLCommandBuffer){
// These images are only needed in this layer and will not be read by the CPU or
// outside of the command bufer, so we can allocate them as MPSTemporaryImages and
// save the CPU cost and memory size of allocating reserved storage for them.
//
// These objects can not be reused outside of the command buffer, which is why
// we did not make them in the init(withDevice:commandQueue:) call.
//
// Temporary images are designed to be efficiently created as needed, used a few times
// and thrown away almost immediately
// branch5x5
m1t1c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m1t1c0id)
// branch3x3dbl
m1t2c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m1t2c0id)
m1t2c1Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m1t2c1id)
// branch_pool
m1t3p0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m1t3p0id)
image1 = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m1id)
// MPS must be able to understand with reasonably precise timing the lifetime of the
// MPSTemporaryImage in the command buffer. The pixel storage for the MPSTemporaryImage
// is not allocated until it is first used (or the .texture property is invoked) and
// the storage is promptly returned for reuse after last use. Since ARC can be a bit
// tardy about releasing the object, the MPSTemporaryImage makes use of a read counter
// to track its lifetime. The read counter tells MPS how many times the MPSTemporaryImage
// will be read (by a MPS -encode method) before its backing store can be reclaimed for
// reuse. By default, the read count is 1, meaning that the contents of the MPSTemporaryImage
// are written to the image any number of times (but typically once, since more would be
// wasteful), then read once. After it is read once, the -encode call will automatically
// return the storage for use by other MPSTemporaryImages.
//
// In the case, the layer reads initImage four times, not once. So we must set the readCount to
// four to make sure that the contents stay valid until the last time it is used.
image0.readCount = 4
// encode layers to metal commandBuffer
// branch1x1
m1t0conv0.encode (commandBuffer: commandBuffer, sourceImage: image0 , destinationImage: image1)
// branch5x5
m1t1conv0.encode (commandBuffer: commandBuffer, sourceImage: image0 , destinationImage: m1t1c0Image)
m1t1conv1.encode (commandBuffer: commandBuffer, sourceImage: m1t1c0Image, destinationImage: image1)
// branch3x3dbl
m1t2conv0.encode (commandBuffer: commandBuffer, sourceImage: image0 , destinationImage: m1t2c0Image)
m1t2conv1.encode (commandBuffer: commandBuffer, sourceImage: m1t2c0Image, destinationImage: m1t2c1Image)
m1t2conv2.encode (commandBuffer: commandBuffer, sourceImage: m1t2c1Image, destinationImage: image1)
// branch_pool
aPool.encode (commandBuffer: commandBuffer, sourceImage: image0 , destinationImage: m1t3p0Image)
m1t3conv0.encode (commandBuffer: commandBuffer, sourceImage: m1t3p0Image, destinationImage: image1)
}
// MPSImageDescriptor for mixed2 layers
// branch5x5
let m2t1c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 35, height: 35, featureChannels: 48)
// branch3x3dbl
let m2t2c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 35, height: 35, featureChannels: 64)
let m2t2c1id = MPSImageDescriptor(channelFormat: textureFormat, width: 35, height: 35, featureChannels: 96)
// branch_pool
let m2t3p0id = MPSImageDescriptor(channelFormat: textureFormat, width: 35, height: 35, featureChannels: 288)
var m2t1c0Image, m2t2c0Image, m2t2c1Image, m2t3p0Image, image2 : MPSTemporaryImage!
func mixed_2_layer(commandBuffer: MTLCommandBuffer) {
// These images are only needed in this layer and will not be read by the CPU or
// outside of the command bufer, so we can allocate them as MPSTemporaryImages and
// save the CPU cost and memory size of allocating reserved storage for them.
//
// These objects can not be reused outside of the command buffer, which is why
// we did not make them in the init(withDevice:commandQueue:) call.
//
// Temporary images are designed to be efficiently created as needed, used a few times
// and thrown away almost immediately
// branch5x5
m2t1c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m2t1c0id)
// branch3x3dbl
m2t2c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m2t2c0id)
m2t2c1Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m2t2c1id)
// branch_pool
m2t3p0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m2t3p0id)
image2 = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m2id)
// MPS must be able to understand with reasonably precise timing the lifetime of the
// MPSTemporaryImage in the command buffer. The pixel storage for the MPSTemporaryImage
// is not allocated until it is first used (or the .texture property is invoked) and
// the storage is promptly returned for reuse after last use. Since ARC can be a bit
// tardy about releasing the object, the MPSTemporaryImage makes use of a read counter
// to track its lifetime. The read counter tells MPS how many times the MPSTemporaryImage
// will be read (by a MPS -encode method) before its backing store can be reclaimed for
// reuse. By default, the read count is 1, meaning that the contents of the MPSTemporaryImage
// are written to the image any number of times (but typically once, since more would be
// wasteful), then read once. After it is read once, the -encode call will automatically
// return the storage for use by other MPSTemporaryImages.
//
// In the case, the layer reads initImage four times, not once. So we must set the readCount to
// four to make sure that the contents stay valid until the last time it is used.
image1.readCount = 4
// encode layers to metal commandBuffer
// branch1x1
m2t0conv0.encode (commandBuffer: commandBuffer, sourceImage: image1 , destinationImage: image2)
// branch5x5
m2t1conv0.encode (commandBuffer: commandBuffer, sourceImage: image1 , destinationImage: m2t1c0Image)
m2t1conv1.encode (commandBuffer: commandBuffer, sourceImage: m2t1c0Image, destinationImage: image2)
// branch3x3dbl
m2t2conv0.encode (commandBuffer: commandBuffer, sourceImage: image1 , destinationImage: m2t2c0Image)
m2t2conv1.encode (commandBuffer: commandBuffer, sourceImage: m2t2c0Image, destinationImage: m2t2c1Image)
m2t2conv2.encode (commandBuffer: commandBuffer, sourceImage: m2t2c1Image, destinationImage: image2)
// branch_pool
aPool.encode (commandBuffer: commandBuffer, sourceImage: image1 , destinationImage: m2t3p0Image)
m2t3conv0.encode (commandBuffer: commandBuffer, sourceImage: m2t3p0Image, destinationImage: image2)
}
// MPSImageDescriptor for mixed3 layers
// branch3x3dbl
let m3t1c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 35, height: 35, featureChannels: 64)
let m3t1c1id = MPSImageDescriptor(channelFormat: textureFormat, width: 35, height: 35, featureChannels: 96)
var m3t1c0Image, m3t1c1Image, image3 : MPSTemporaryImage!
func mixed_3_layer(commandBuffer: MTLCommandBuffer) {
// These images are only needed in this layer and will not be read by the CPU or
// outside of the command bufer, so we can allocate them as MPSTemporaryImages and
// save the CPU cost and memory size of allocating reserved storage for them.
//
// These objects can not be reused outside of the command buffer, which is why
// we did not make them in the init(withDevice:commandQueue:) call.
//
// Temporary images are designed to be efficiently created as needed, used a few times
// and thrown away almost immediately
// branch3x3dbl
m3t1c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m3t1c0id)
m3t1c1Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m3t1c1id)
image3 = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m3id)
// MPS must be able to understand with reasonably precise timing the lifetime of the
// MPSTemporaryImage in the command buffer. The pixel storage for the MPSTemporaryImage
// is not allocated until it is first used (or the .texture property is invoked) and
// the storage is promptly returned for reuse after last use. Since ARC can be a bit
// tardy about releasing the object, the MPSTemporaryImage makes use of a read counter
// to track its lifetime. The read counter tells MPS how many times the MPSTemporaryImage
// will be read (by a MPS -encode method) before its backing store can be reclaimed for
// reuse. By default, the read count is 1, meaning that the contents of the MPSTemporaryImage
// are written to the image any number of times (but typically once, since more would be
// wasteful), then read once. After it is read once, the -encode call will automatically
// return the storage for use by other MPSTemporaryImages.
//
// In the case, the layer reads initImage three times, not once. So we must set the readCount to
// three to make sure that the contents stay valid until the last time it is used.
image2.readCount = 3
// encode layers to metal commandBuffer
// branch3x3
m3t0conv0.encode (commandBuffer: commandBuffer, sourceImage: image2 , destinationImage: image3)
// branch3x3dbl
m3t1conv0.encode (commandBuffer: commandBuffer, sourceImage: image2 , destinationImage: m3t1c0Image)
m3t1conv1.encode (commandBuffer: commandBuffer, sourceImage: m3t1c0Image, destinationImage: m3t1c1Image)
m3t1conv2.encode (commandBuffer: commandBuffer, sourceImage: m3t1c1Image, destinationImage: image3)
// branch_pool
mPool3.encode (commandBuffer: commandBuffer, sourceImage: image2 , destinationImage: image3)
}
// MPSImageDescriptor for mixed4 layers
// branch7x7
let m4t1c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 128)
let m4t1c1id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 128)
// branch7x7dbl
let m4t2c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 128)
let m4t2c1id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 128)
let m4t2c2id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 128)
let m4t2c3id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 128)
// branch_pool
let m4t3p0id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 768)
var m4t1c0Image, m4t1c1Image, m4t2c0Image, m4t2c1Image, m4t2c2Image, m4t2c3Image, m4t3p0Image, image4 : MPSTemporaryImage!
func mixed_4_layer(commandBuffer: MTLCommandBuffer){
// These images are only needed in this layer and will not be read by the CPU or
// outside of the command bufer, so we can allocate them as MPSTemporaryImages and
// save the CPU cost and memory size of allocating reserved storage for them.
//
// These objects can not be reused outside of the command buffer, which is why
// we did not make them in the init(withDevice:commandQueue:) call.
//
// Temporary images are designed to be efficiently created as needed, used a few times
// and thrown away almost immediately
// branch7x7
m4t1c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m4t1c0id)
m4t1c1Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m4t1c1id)
// branch7x7dbl
m4t2c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m4t2c0id)
m4t2c1Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m4t2c1id)
m4t2c2Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m4t2c2id)
m4t2c3Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m4t2c3id)
// branch_pool
m4t3p0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m4t3p0id)
image4 = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m4id)
// MPS must be able to understand with reasonably precise timing the lifetime of the
// MPSTemporaryImage in the command buffer. The pixel storage for the MPSTemporaryImage
// is not allocated until it is first used (or the .texture property is invoked) and
// the storage is promptly returned for reuse after last use. Since ARC can be a bit
// tardy about releasing the object, the MPSTemporaryImage makes use of a read counter
// to track its lifetime. The read counter tells MPS how many times the MPSTemporaryImage
// will be read (by a MPS -encode method) before its backing store can be reclaimed for
// reuse. By default, the read count is 1, meaning that the contents of the MPSTemporaryImage
// are written to the image any number of times (but typically once, since more would be
// wasteful), then read once. After it is read once, the -encode call will automatically
// return the storage for use by other MPSTemporaryImages.
//
// In the case, the layer reads initImage four times, not once. So we must set the readCount to
// four to make sure that the contents stay valid until the last time it is used.
image3.readCount = 4
// encode layers to metal commandBuffer
// branch1x1
m4t0conv0.encode (commandBuffer: commandBuffer, sourceImage: image3 , destinationImage: image4)
// branch7x7
m4t1conv0.encode (commandBuffer: commandBuffer, sourceImage: image3 , destinationImage: m4t1c0Image)
m4t1conv1.encode (commandBuffer: commandBuffer, sourceImage: m4t1c0Image, destinationImage: m4t1c1Image)
m4t1conv2.encode (commandBuffer: commandBuffer, sourceImage: m4t1c1Image, destinationImage: image4)
// branch7x7dbl
m4t2conv0.encode (commandBuffer: commandBuffer, sourceImage: image3 , destinationImage: m4t2c0Image)
m4t2conv1.encode (commandBuffer: commandBuffer, sourceImage: m4t2c0Image, destinationImage: m4t2c1Image)
m4t2conv2.encode (commandBuffer: commandBuffer, sourceImage: m4t2c1Image, destinationImage: m4t2c2Image)
m4t2conv3.encode (commandBuffer: commandBuffer, sourceImage: m4t2c2Image, destinationImage: m4t2c3Image)
m4t2conv4.encode (commandBuffer: commandBuffer, sourceImage: m4t2c3Image, destinationImage: image4)
// branch_pool
aPool.encode (commandBuffer: commandBuffer, sourceImage: image3 , destinationImage: m4t3p0Image)
m4t3conv0.encode (commandBuffer: commandBuffer, sourceImage: m4t3p0Image, destinationImage: image4)
}
// MPSImageDescriptor for mixed5 layers
// branch5x5
let m5t1c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 160)
let m5t1c1id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 160)
// branch3x3
let m5t2c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 160)
let m5t2c1id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 160)
let m5t2c2id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 160)
let m5t2c3id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 160)
// branch_pool
let m5t3p0id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 768)
var m5t1c0Image, m5t1c1Image, m5t2c0Image, m5t2c1Image, m5t2c2Image, m5t2c3Image, m5t3p0Image, image5 : MPSTemporaryImage!
func mixed_5_layer(commandBuffer: MTLCommandBuffer) {
// These images are only needed in this layer and will not be read by the CPU or
// outside of the command bufer, so we can allocate them as MPSTemporaryImages and
// save the CPU cost and memory size of allocating reserved storage for them.
//
// These objects can not be reused outside of the command buffer, which is why
// we did not make them in the init(withDevice:commandQueue:) call.
//
// Temporary images are designed to be efficiently created as needed, used a few times
// and thrown away almost immediately
// branch5x5
m5t1c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m5t1c0id)
m5t1c1Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m5t1c1id)
// branch3x3
m5t2c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m5t2c0id)
m5t2c1Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m5t2c1id)
m5t2c2Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m5t2c2id)
m5t2c3Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m5t2c3id)
// branch_pool
m5t3p0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m5t3p0id)
image5 = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m5id)
// MPS must be able to understand with reasonably precise timing the lifetime of the
// MPSTemporaryImage in the command buffer. The pixel storage for the MPSTemporaryImage
// is not allocated until it is first used (or the .texture property is invoked) and
// the storage is promptly returned for reuse after last use. Since ARC can be a bit
// tardy about releasing the object, the MPSTemporaryImage makes use of a read counter
// to track its lifetime. The read counter tells MPS how many times the MPSTemporaryImage
// will be read (by a MPS -encode method) before its backing store can be reclaimed for
// reuse. By default, the read count is 1, meaning that the contents of the MPSTemporaryImage
// are written to the image any number of times (but typically once, since more would be
// wasteful), then read once. After it is read once, the -encode call will automatically
// return the storage for use by other MPSTemporaryImages.
//
// In the case, the layer reads initImage four times, not once. So we must set the readCount to
// four to make sure that the contents stay valid until the last time it is used.
image4.readCount = 4
// encode layers to metal commandBuffer
// branch1x1
m5t0conv0.encode (commandBuffer: commandBuffer, sourceImage: image4 , destinationImage: image5)
// branch5x5
m5t1conv0.encode (commandBuffer: commandBuffer, sourceImage: image4 , destinationImage: m5t1c0Image)
m5t1conv1.encode (commandBuffer: commandBuffer, sourceImage: m5t1c0Image, destinationImage: m5t1c1Image)
m5t1conv2.encode (commandBuffer: commandBuffer, sourceImage: m5t1c1Image, destinationImage: image5)
// branch3x3
m5t2conv0.encode (commandBuffer: commandBuffer, sourceImage: image4 , destinationImage: m5t2c0Image)
m5t2conv1.encode (commandBuffer: commandBuffer, sourceImage: m5t2c0Image, destinationImage: m5t2c1Image)
m5t2conv2.encode (commandBuffer: commandBuffer, sourceImage: m5t2c1Image, destinationImage: m5t2c2Image)
m5t2conv3.encode (commandBuffer: commandBuffer, sourceImage: m5t2c2Image, destinationImage: m5t2c3Image)
m5t2conv4.encode (commandBuffer: commandBuffer, sourceImage: m5t2c3Image, destinationImage: image5)
// branch_pool
aPool.encode (commandBuffer: commandBuffer, sourceImage: image4 , destinationImage: m5t3p0Image)
m5t3conv0.encode (commandBuffer: commandBuffer, sourceImage: m5t3p0Image, destinationImage: image5)
}
// MPSImageDescriptor for mixed6 layers
// branch5x5
let m6t1c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 160)
let m6t1c1id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 160)
// branch3x3
let m6t2c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 160)
let m6t2c1id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 160)
let m6t2c2id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 160)
let m6t2c3id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 160)
// branch_pool
let m6t3p0id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 768)
var m6t1c0Image, m6t1c1Image, m6t2c0Image, m6t2c1Image, m6t2c2Image, m6t2c3Image, m6t3p0Image, image6 : MPSTemporaryImage!
func mixed_6_layer(commandBuffer: MTLCommandBuffer){
// These images are only needed in this layer and will not be read by the CPU or
// outside of the command bufer, so we can allocate them as MPSTemporaryImages and
// save the CPU cost and memory size of allocating reserved storage for them.
//
// These objects can not be reused outside of the command buffer, which is why
// we did not make them in the init(withDevice:commandQueue:) call.
//
// Temporary images are designed to be efficiently created as needed, used a few times
// and thrown away almost immediately
// branch5x5
m6t1c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m6t1c0id)
m6t1c1Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m6t1c1id)
// branch3x3
m6t2c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m6t2c0id)
m6t2c1Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m6t2c1id)
m6t2c2Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m6t2c2id)
m6t2c3Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m6t2c3id)
// branch_pool
m6t3p0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m6t3p0id)
image6 = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m6id)
// MPS must be able to understand with reasonably precise timing the lifetime of the
// MPSTemporaryImage in the command buffer. The pixel storage for the MPSTemporaryImage
// is not allocated until it is first used (or the .texture property is invoked) and
// the storage is promptly returned for reuse after last use. Since ARC can be a bit
// tardy about releasing the object, the MPSTemporaryImage makes use of a read counter
// to track its lifetime. The read counter tells MPS how many times the MPSTemporaryImage
// will be read (by a MPS -encode method) before its backing store can be reclaimed for
// reuse. By default, the read count is 1, meaning that the contents of the MPSTemporaryImage
// are written to the image any number of times (but typically once, since more would be
// wasteful), then read once. After it is read once, the -encode call will automatically
// return the storage for use by other MPSTemporaryImages.
//
// In the case, the layer reads initImage four times, not once. So we must set the readCount to
// four to make sure that the contents stay valid until the last time it is used.
image5.readCount = 4
// encode layers to metal commandBuffer
// branch1x1
m6t0conv0.encode (commandBuffer: commandBuffer, sourceImage: image5 , destinationImage: image6)
// branch5x5
m6t1conv0.encode (commandBuffer: commandBuffer, sourceImage: image5 , destinationImage: m6t1c0Image)
m6t1conv1.encode (commandBuffer: commandBuffer, sourceImage: m6t1c0Image, destinationImage: m6t1c1Image)
m6t1conv2.encode (commandBuffer: commandBuffer, sourceImage: m6t1c1Image, destinationImage: image6)
// branch3x3
m6t2conv0.encode (commandBuffer: commandBuffer, sourceImage: image5 , destinationImage: m6t2c0Image)
m6t2conv1.encode (commandBuffer: commandBuffer, sourceImage: m6t2c0Image, destinationImage: m6t2c1Image)
m6t2conv2.encode (commandBuffer: commandBuffer, sourceImage: m6t2c1Image, destinationImage: m6t2c2Image)
m6t2conv3.encode (commandBuffer: commandBuffer, sourceImage: m6t2c2Image, destinationImage: m6t2c3Image)
m6t2conv4.encode (commandBuffer: commandBuffer, sourceImage: m6t2c3Image, destinationImage: image6)
// branch_pool
aPool.encode (commandBuffer: commandBuffer, sourceImage: image5 , destinationImage: m6t3p0Image)
m6t3conv0.encode (commandBuffer: commandBuffer, sourceImage: m6t3p0Image, destinationImage: image6)
}
// MPSImageDescriptor for mixed7 layers
// branch5x5
let m7t1c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 192)
let m7t1c1id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 192)
// branch3x3
let m7t2c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 192)
let m7t2c1id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 192)
let m7t2c2id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 192)
let m7t2c3id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 192)
// branch_pool
let m7t3p0id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 768)
var m7t1c0Image, m7t1c1Image, m7t2c0Image, m7t2c1Image, m7t2c2Image, m7t2c3Image, m7t3p0Image, image7 : MPSTemporaryImage!
func mixed_7_layer(commandBuffer: MTLCommandBuffer){
// These images are only needed in this layer and will not be read by the CPU or
// outside of the command bufer, so we can allocate them as MPSTemporaryImages and
// save the CPU cost and memory size of allocating reserved storage for them.
//
// These objects can not be reused outside of the command buffer, which is why
// we did not make them in the init(withDevice:commandQueue:) call.
//
// Temporary images are designed to be efficiently created as needed, used a few times
// and thrown away almost immediately
// branch5x5
m7t1c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m7t1c0id)
m7t1c1Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m7t1c1id)
// branch3x3
m7t2c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m7t2c0id)
m7t2c1Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m7t2c1id)
m7t2c2Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m7t2c2id)
m7t2c3Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m7t2c3id)
// branch_pool
m7t3p0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m7t3p0id)
image7 = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m7id)
// MPS must be able to understand with reasonably precise timing the lifetime of the
// MPSTemporaryImage in the command buffer. The pixel storage for the MPSTemporaryImage
// is not allocated until it is first used (or the .texture property is invoked) and
// the storage is promptly returned for reuse after last use. Since ARC can be a bit
// tardy about releasing the object, the MPSTemporaryImage makes use of a read counter
// to track its lifetime. The read counter tells MPS how many times the MPSTemporaryImage
// will be read (by a MPS -encode method) before its backing store can be reclaimed for
// reuse. By default, the read count is 1, meaning that the contents of the MPSTemporaryImage
// are written to the image any number of times (but typically once, since more would be
// wasteful), then read once. After it is read once, the -encode call will automatically
// return the storage for use by other MPSTemporaryImages.
//
// In the case, the layer reads initImage four times, not once. So we must set the readCount to
// four to make sure that the contents stay valid until the last time it is used.
image6.readCount = 4
// encode layers to metal commandBuffer
// branch1x1
m7t0conv0.encode (commandBuffer: commandBuffer, sourceImage: image6 , destinationImage: image7)
// branch5x5
m7t1conv0.encode (commandBuffer: commandBuffer, sourceImage: image6 , destinationImage: m7t1c0Image)
m7t1conv1.encode (commandBuffer: commandBuffer, sourceImage: m7t1c0Image, destinationImage: m7t1c1Image)
m7t1conv2.encode (commandBuffer: commandBuffer, sourceImage: m7t1c1Image, destinationImage: image7)
// branch3x3
m7t2conv0.encode (commandBuffer: commandBuffer, sourceImage: image6 , destinationImage: m7t2c0Image)
m7t2conv1.encode (commandBuffer: commandBuffer, sourceImage: m7t2c0Image, destinationImage: m7t2c1Image)
m7t2conv2.encode (commandBuffer: commandBuffer, sourceImage: m7t2c1Image, destinationImage: m7t2c2Image)
m7t2conv3.encode (commandBuffer: commandBuffer, sourceImage: m7t2c2Image, destinationImage: m7t2c3Image)
m7t2conv4.encode (commandBuffer: commandBuffer, sourceImage: m7t2c3Image, destinationImage: image7)
// branch_pool
aPool.encode (commandBuffer: commandBuffer, sourceImage: image6 , destinationImage: m7t3p0Image)
m7t3conv0.encode (commandBuffer: commandBuffer, sourceImage: m7t3p0Image, destinationImage: image7)
}
// MPSImageDescriptor for mixed8 layers
// branch3x3
let m8t0c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 192)
// branch7x7x3dbl
let m8t1c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 192)
let m8t1c1id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 192)
let m8t1c2id = MPSImageDescriptor(channelFormat: textureFormat, width: 17, height: 17, featureChannels: 192)
var m8t0c0Image, m8t1c0Image, m8t1c1Image, m8t1c2Image, image8 : MPSTemporaryImage!
func mixed_8_layer(commandBuffer: MTLCommandBuffer){
// These images are only needed in this layer and will not be read by the CPU or
// outside of the command bufer, so we can allocate them as MPSTemporaryImages and
// save the CPU cost and memory size of allocating reserved storage for them.
//
// These objects can not be reused outside of the command buffer, which is why
// we did not make them in the init(withDevice:commandQueue:) call.
//
// Temporary images are designed to be efficiently created as needed, used a few times
// and thrown away almost immediately
// branch3x3
m8t0c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m8t0c0id)
// branch7x7x3dbl
m8t1c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m8t1c0id)
m8t1c1Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m8t1c1id)
m8t1c2Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m8t1c2id)
image8 = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m8id)
// MPS must be able to understand with reasonably precise timing the lifetime of the
// MPSTemporaryImage in the command buffer. The pixel storage for the MPSTemporaryImage
// is not allocated until it is first used (or the .texture property is invoked) and
// the storage is promptly returned for reuse after last use. Since ARC can be a bit
// tardy about releasing the object, the MPSTemporaryImage makes use of a read counter
// to track its lifetime. The read counter tells MPS how many times the MPSTemporaryImage
// will be read (by a MPS -encode method) before its backing store can be reclaimed for
// reuse. By default, the read count is 1, meaning that the contents of the MPSTemporaryImage
// are written to the image any number of times (but typically once, since more would be
// wasteful), then read once. After it is read once, the -encode call will automatically
// return the storage for use by other MPSTemporaryImages.
//
// In the case, the layer reads initImage three times, not once. So we must set the readCount to
// three to make sure that the contents stay valid until the last time it is used.
image7.readCount = 3
// encode layers to metal commandBuffer
// branch3x3
m8t0conv0.encode (commandBuffer: commandBuffer, sourceImage: image7 , destinationImage: m8t0c0Image)
m8t0conv1.encode (commandBuffer: commandBuffer, sourceImage: m8t0c0Image, destinationImage: image8)
// branch7x7x3dbl
m8t1conv0.encode (commandBuffer: commandBuffer, sourceImage: image7 , destinationImage: m8t1c0Image)
m8t1conv1.encode (commandBuffer: commandBuffer, sourceImage: m8t1c0Image, destinationImage: m8t1c1Image)
m8t1conv2.encode (commandBuffer: commandBuffer, sourceImage: m8t1c1Image, destinationImage: m8t1c2Image)
m8t1conv3.encode (commandBuffer: commandBuffer, sourceImage: m8t1c2Image, destinationImage: image8)
// branch_pool
mPool8.encode (commandBuffer: commandBuffer, sourceImage: image7 , destinationImage: image8)
}
// MPSImageDescriptor for mixed9 layers
// branch3x3
let m9t1c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 8, height: 8, featureChannels: 384)
// branch3x3dbl
let m9t2c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 8, height: 8, featureChannels: 448)
let m9t2c1id = MPSImageDescriptor(channelFormat: textureFormat, width: 8, height: 8, featureChannels: 384)
// branch_pool
let m9t3p0id = MPSImageDescriptor(channelFormat: textureFormat, width: 8, height: 8, featureChannels: 1280)
var m9t1c0Image, m9t2c0Image, m9t2c1Image, m9t3p0Image, image9 : MPSTemporaryImage!
func mixed_9_layer(commandBuffer: MTLCommandBuffer){
// These images are only needed in this layer and will not be read by the CPU or
// outside of the command bufer, so we can allocate them as MPSTemporaryImages and
// save the CPU cost and memory size of allocating reserved storage for them.
//
// These objects can not be reused outside of the command buffer, which is why
// we did not make them in the init(withDevice:commandQueue:) call.
//
// Temporary images are designed to be efficiently created as needed, used a few times
// and thrown away almost immediately
// branch5x5
m9t1c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m9t1c0id)
// branch3x3
m9t2c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m9t2c0id)
m9t2c1Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m9t2c1id)
// branch_pool
m9t3p0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m9t3p0id)
image9 = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m9id)
// MPS must be able to understand with reasonably precise timing the lifetime of the
// MPSTemporaryImage in the command buffer. The pixel storage for the MPSTemporaryImage
// is not allocated until it is first used (or the .texture property is invoked) and
// the storage is promptly returned for reuse after last use. Since ARC can be a bit
// tardy about releasing the object, the MPSTemporaryImage makes use of a read counter
// to track its lifetime. The read counter tells MPS how many times the MPSTemporaryImage
// will be read (by a MPS -encode method) before its backing store can be reclaimed for
// reuse. By default, the read count is 1, meaning that the contents of the MPSTemporaryImage
// are written to the image any number of times (but typically once, since more would be
// wasteful), then read once. After it is read once, the -encode call will automatically
// return the storage for use by other MPSTemporaryImages.
//
// In the case, the layer reads initImage four times, not once. So we must set the readCount to
// four to make sure that the contents stay valid until the last time it is used.
image8.readCount = 4
// encode layers to metal commandBuffer
// branch1x1
m9t0conv0.encode (commandBuffer: commandBuffer, sourceImage: image8 , destinationImage: image9)
// branch5x5
m9t1conv0.encode (commandBuffer: commandBuffer, sourceImage: image8 , destinationImage: m9t1c0Image)
m9t1c0Image.readCount = 2
m9t1conv1.encode (commandBuffer: commandBuffer, sourceImage: m9t1c0Image, destinationImage: image9)
m9t1conv2.encode (commandBuffer: commandBuffer, sourceImage: m9t1c0Image, destinationImage: image9)
// branch3x3
m9t2conv0.encode (commandBuffer: commandBuffer, sourceImage: image8 , destinationImage: m9t2c0Image)
m9t2conv1.encode (commandBuffer: commandBuffer, sourceImage: m9t2c0Image, destinationImage: m9t2c1Image)
m9t2c1Image.readCount = 2
m9t2conv2.encode (commandBuffer: commandBuffer, sourceImage: m9t2c1Image, destinationImage: image9)
m9t2conv3.encode (commandBuffer: commandBuffer, sourceImage: m9t2c1Image, destinationImage: image9)
// branch_pool
aPool.encode (commandBuffer: commandBuffer, sourceImage: image8 , destinationImage: m9t3p0Image)
m9t3conv0.encode (commandBuffer: commandBuffer, sourceImage: m9t3p0Image, destinationImage: image9)
}
// MPSImageDescriptor for mixed10 layers
// branch3x3
let m10t1c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 8, height: 8, featureChannels: 384)
// branch3x3dbl
let m10t2c0id = MPSImageDescriptor(channelFormat: textureFormat, width: 8, height: 8, featureChannels: 448)
let m10t2c1id = MPSImageDescriptor(channelFormat: textureFormat, width: 8, height: 8, featureChannels: 384)
// branch_pool
let m10t3p0id = MPSImageDescriptor(channelFormat: textureFormat, width: 8, height: 8, featureChannels: 2048)
var m10t1c0Image, m10t2c0Image, m10t2c1Image, m10t3p0Image, image10 : MPSTemporaryImage!
func mixed_10_layer(commandBuffer: MTLCommandBuffer){
// These images are only needed in this layer and will not be read by the CPU or
// outside of the command bufer, so we can allocate them as MPSTemporaryImages and
// save the CPU cost and memory size of allocating reserved storage for them.
//
// These objects can not be reused outside of the command buffer, which is why
// we did not make them in the init(withDevice:commandQueue:) call.
//
// Temporary images are designed to be efficiently created as needed, used a few times
// and thrown away almost immediately
// branch5x5
m10t1c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m10t1c0id)
// branch3x3
m10t2c0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m10t2c0id)
m10t2c1Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m10t2c1id)
// branch_pool
m10t3p0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m10t3p0id)
image10 = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: m10id)
// MPS must be able to understand with reasonably precise timing the lifetime of the
// MPSTemporaryImage in the command buffer. The pixel storage for the MPSTemporaryImage
// is not allocated until it is first used (or the .texture property is invoked) and
// the storage is promptly returned for reuse after last use. Since ARC can be a bit
// tardy about releasing the object, the MPSTemporaryImage makes use of a read counter
// to track its lifetime. The read counter tells MPS how many times the MPSTemporaryImage
// will be read (by a MPS -encode method) before its backing store can be reclaimed for
// reuse. By default, the read count is 1, meaning that the contents of the MPSTemporaryImage
// are written to the image any number of times (but typically once, since more would be
// wasteful), then read once. After it is read once, the -encode call will automatically
// return the storage for use by other MPSTemporaryImages.
//
// In the case, the layer reads initImage four times, not once. So we must set the readCount to
// four to make sure that the contents stay valid until the last time it is used.
image9.readCount = 4
// encode layers to metal commandBuffer
// branch1x1
m10t0conv0.encode (commandBuffer: commandBuffer, sourceImage: image9 , destinationImage: image10)
// branch5x5
m10t1conv0.encode (commandBuffer: commandBuffer, sourceImage: image9 , destinationImage: m10t1c0Image)
m10t1c0Image.readCount = 2
m10t1conv1.encode (commandBuffer: commandBuffer, sourceImage: m10t1c0Image, destinationImage: image10)
m10t1conv2.encode (commandBuffer: commandBuffer, sourceImage: m10t1c0Image, destinationImage: image10)
// branch3x3
m10t2conv0.encode (commandBuffer: commandBuffer, sourceImage: image9 , destinationImage: m10t2c0Image)
m10t2conv1.encode (commandBuffer: commandBuffer, sourceImage: m10t2c0Image, destinationImage: m10t2c1Image)
m10t2c1Image.readCount = 2
m10t2conv2.encode (commandBuffer: commandBuffer, sourceImage: m10t2c1Image, destinationImage: image10)
m10t2conv3.encode (commandBuffer: commandBuffer, sourceImage: m10t2c1Image, destinationImage: image10)
// branch_pool
mPool10.encode (commandBuffer: commandBuffer, sourceImage: image9 , destinationImage: m10t3p0Image)
m10t3conv0.encode (commandBuffer: commandBuffer, sourceImage: m10t3p0Image, destinationImage: image10)
}
// MPSImageDescriptor for final logits generating layers
let fp0id = MPSImageDescriptor(channelFormat: textureFormat, width: 1, height: 1, featureChannels: 2048)
var fp0Image, fc0Image : MPSTemporaryImage!
func logits_layer(commandBuffer: MTLCommandBuffer){
// These images are only needed in this layer and will not be read by the CPU or
// outside of the command bufer, so we can allocate them as MPSTemporaryImages and
// save the CPU cost and memory size of allocating reserved storage for them.
//
// These objects can not be reused outside of the command buffer, which is why
// we did not make them in the init(withDevice:commandQueue:) call.
//
// Temporary images are designed to be efficiently created as needed, used a few times
// and thrown away almost immediately
fp0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: fp0id)
fc0Image = MPSTemporaryImage(commandBuffer: commandBuffer, imageDescriptor: sftid)
// encode layers to metal commandBuffer
aPoolLogits.encode (commandBuffer: commandBuffer, sourceImage: image10, destinationImage: fp0Image)
fc0.encode (commandBuffer: commandBuffer, sourceImage: fp0Image, destinationImage: fc0Image)
softmax.encode(commandBuffer: commandBuffer, sourceImage: fc0Image, destinationImage: sftImage)
}
// these are labels corresponding to output classes, these are defined by ImageNet2012 dataset which has these 1000 classes
// the network given by tensrFlow outputs 1008 class probabilities however as we have no labels for index 0, 1001-1007, we
// have classes from original ImageNet2012
let labels = [
"",
"kit fox, Vulpes macrotis",
"English setter",
"Siberian husky",
"Australian terrier",
"English springer, English springer spaniel",
"grey whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus",
"lesser panda, red panda, panda, bear cat, cat bear, Ailurus fulgens",
"Egyptian cat",
"ibex, Capra ibex",
"Persian cat",
"cougar, puma, catamount, mountain lion, painter, panther, Felis concolor",
"gazelle",
"porcupine, hedgehog",
"sea lion",
"malamute, malemute, Alaskan malamute",
"badger",
"Great Dane",
"Walker hound, Walker foxhound",
"Welsh springer spaniel",
"whippet",
"Scottish deerhound, deerhound",
"killer whale, killer, orca, grampus, sea wolf, Orcinus orca",
"mink",
"African elephant, Loxodonta africana",
"Weimaraner",
"soft-coated wheaten terrier",
"Dandie Dinmont, Dandie Dinmont terrier",
"red wolf, maned wolf, Canis rufus, Canis niger",
"Old English sheepdog, bobtail",
"jaguar, panther, Panthera onca, Felis onca",
"otterhound, otter hound",
"bloodhound, sleuthhound",
"Airedale, Airedale terrier",
"hyena, hyaena",
"meerkat, mierkat",
"giant schnauzer",
"titi, titi monkey",
"three-toed sloth, ai, Bradypus tridactylus",
"sorrel",
"black-footed ferret, ferret, Mustela nigripes",
"dalmatian, coach dog, carriage dog",
"black-and-tan coonhound",
"papillon",
"skunk, polecat, wood pussy",
"Staffordshire bullterrier, Staffordshire bull terrier",
"Mexican hairless",
"Bouvier des Flandres, Bouviers des Flandres",
"weasel",
"miniature poodle",
"Cardigan, Cardigan Welsh corgi",
"malinois",
"bighorn, bighorn sheep, cimarron, Rocky Mountain bighorn, Rocky Mountain sheep, Ovis canadensis",
"fox squirrel, eastern fox squirrel, Sciurus niger",
"colobus, colobus monkey",
"tiger cat",
"Lhasa, Lhasa apso",
"impala, Aepyceros melampus",
"coyote, prairie wolf, brush wolf, Canis latrans",
"Yorkshire terrier",
"Newfoundland, Newfoundland dog",
"brown bear, bruin, Ursus arctos",
"red fox, Vulpes vulpes",
"Norwegian elkhound, elkhound",
"Rottweiler",
"hartebeest",
"Saluki, gazelle hound",
"grey fox, gray fox, Urocyon cinereoargenteus",
"schipperke",
"Pekinese, Pekingese, Peke",
"Brabancon griffon",
"West Highland white terrier",
"Sealyham terrier, Sealyham",
"guenon, guenon monkey",
"mongoose",
"indri, indris, Indri indri, Indri brevicaudatus",
"tiger, Panthera tigris",
"Irish wolfhound",
"wild boar, boar, Sus scrofa",
"EntleBucher",
"zebra",
"ram, tup",
"French bulldog",
"orangutan, orang, orangutang, Pongo pygmaeus",
"basenji",
"leopard, Panthera pardus",
"Bernese mountain dog",
"Maltese dog, Maltese terrier, Maltese",
"Norfolk terrier",
"toy terrier",
"vizsla, Hungarian pointer",
"cairn, cairn terrier",
"squirrel monkey, Saimiri sciureus",
"groenendael",
"clumber, clumber spaniel",
"Siamese cat, Siamese",
"chimpanzee, chimp, Pan troglodytes",
"komondor",
"Afghan hound, Afghan",
"Japanese spaniel",
"proboscis monkey, Nasalis larvatus",
"guinea pig, Cavia cobaya",
"white wolf, Arctic wolf, Canis lupus tundrarum",
"ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus",
"gorilla, Gorilla gorilla",
"borzoi, Russian wolfhound",
"toy poodle",
"Kerry blue terrier",
"ox",
"Scotch terrier, Scottish terrier, Scottie",
"Tibetan mastiff",
"spider monkey, Ateles geoffroyi",
"Doberman, Doberman pinscher",
"Boston bull, Boston terrier",
"Greater Swiss Mountain dog",
"Appenzeller",
"Shih-Tzu",
"Irish water spaniel",
"Pomeranian",
"Bedlington terrier",
"warthog",
"Arabian camel, dromedary, Camelus dromedarius",
"siamang, Hylobates syndactylus, Symphalangus syndactylus",
"miniature schnauzer",
"collie",
"golden retriever",
"Irish terrier",
"affenpinscher, monkey pinscher, monkey dog",
"Border collie",
"hare",
"boxer",
"silky terrier, Sydney silky",
"beagle",
"Leonberg",
"German short-haired pointer",
"patas, hussar monkey, Erythrocebus patas",
"dhole, Cuon alpinus",
"baboon",
"macaque",
"Chesapeake Bay retriever",
"bull mastiff",
"kuvasz",
"capuchin, ringtail, Cebus capucinus",
"pug, pug-dog",
"curly-coated retriever",
"Norwich terrier",
"flat-coated retriever",
"hog, pig, grunter, squealer, Sus scrofa",
"keeshond",
"Eskimo dog, husky",
"Brittany spaniel",
"standard poodle",
"Lakeland terrier",
"snow leopard, ounce, Panthera uncia",
"Gordon setter",
"dingo, warrigal, warragal, Canis dingo",
"standard schnauzer",
"hamster",
"Tibetan terrier, chrysanthemum dog",
"Arctic fox, white fox, Alopex lagopus",
"wire-haired fox terrier",
"basset, basset hound",
"water buffalo, water ox, Asiatic buffalo, Bubalus bubalis",
"American black bear, black bear, Ursus americanus, Euarctos americanus",
"Angora, Angora rabbit",
"bison",
"howler monkey, howler",
"hippopotamus, hippo, river horse, Hippopotamus amphibius",
"chow, chow chow",
"giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca",
"American Staffordshire terrier, Staffordshire terrier, American pit bull terrier, pit bull terrier",
"Shetland sheepdog, Shetland sheep dog, Shetland",
"Great Pyrenees",
"Chihuahua",
"tabby, tabby cat",
"marmoset",
"Labrador retriever",
"Saint Bernard, St Bernard",
"armadillo",
"Samoyed, Samoyede",
"bluetick",
"redbone",
"polecat, fitch, foulmart, foumart, Mustela putorius",
"marmot",
"kelpie",
"gibbon, Hylobates lar",
"llama",
"miniature pinscher",
"wood rabbit, cottontail, cottontail rabbit",
"Italian greyhound",
"lion, king of beasts, Panthera leo",
"cocker spaniel, English cocker spaniel, cocker",
"Irish setter, red setter",
"dugong, Dugong dugon",
"Indian elephant, Elephas maximus",
"beaver",
"Sussex spaniel",
"Pembroke, Pembroke Welsh corgi",
"Blenheim spaniel",
"Madagascar cat, ring-tailed lemur, Lemur catta",
"Rhodesian ridgeback",
"lynx, catamount",
"African hunting dog, hyena dog, Cape hunting dog, Lycaon pictus",
"langur",
"Ibizan hound, Ibizan Podenco",
"timber wolf, grey wolf, gray wolf, Canis lupus",
"cheetah, chetah, Acinonyx jubatus",
"English foxhound",
"briard",
"sloth bear, Melursus ursinus, Ursus ursinus",
"Border terrier",
"German shepherd, German shepherd dog, German police dog, alsatian",
"otter",
"koala, koala bear, kangaroo bear, native bear, Phascolarctos cinereus",
"tusker",
"echidna, spiny anteater, anteater",
"wallaby, brush kangaroo",
"platypus, duckbill, duckbilled platypus, duck-billed platypus, Ornithorhynchus anatinus",
"wombat",
"revolver, six-gun, six-shooter",
"umbrella",
"schooner",
"soccer ball",
"accordion, piano accordion, squeeze box",
"ant, emmet, pismire",
"starfish, sea star",
"chambered nautilus, pearly nautilus, nautilus",
"grand piano, grand",
"laptop, laptop computer",
"strawberry",
"airliner",
"warplane, military plane",
"airship, dirigible",
"balloon",
"space shuttle",
"fireboat",
"gondola",
"speedboat",
"lifeboat",
"canoe",
"yawl",
"catamaran",
"trimaran",
"container ship, containership, container vessel",
"liner, ocean liner",
"pirate, pirate ship",
"aircraft carrier, carrier, flattop, attack aircraft carrier",
"submarine, pigboat, sub, U-boat",
"wreck",
"half track",
"tank, army tank, armored combat vehicle, armoured combat vehicle",
"missile",
"bobsled, bobsleigh, bob",
"dogsled, dog sled, dog sleigh",
"bicycle-built-for-two, tandem bicycle, tandem",
"mountain bike, all-terrain bike, off-roader",
"freight car",
"passenger car, coach, carriage",
"barrow, garden cart, lawn cart, wheelbarrow",
"shopping cart",
"motor scooter, scooter",
"forklift",
"electric locomotive",
"steam locomotive",
"amphibian, amphibious vehicle",
"ambulance",
"beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon",
"cab, hack, taxi, taxicab",
"convertible",
"jeep, landrover",
"limousine, limo",
"minivan",
"Model T",
"racer, race car, racing car",
"sports car, sport car",
"go-kart",
"golfcart, golf cart",
"moped",
"snowplow, snowplough",
"fire engine, fire truck",
"garbage truck, dustcart",
"pickup, pickup truck",
"tow truck, tow car, wrecker",
"trailer truck, tractor trailer, trucking rig, rig, articulated lorry, semi",
"moving van",
"police van, police wagon, paddy wagon, patrol wagon, wagon, black Maria",
"recreational vehicle, RV, R.V.",
"streetcar, tram, tramcar, trolley, trolley car",
"snowmobile",
"tractor",
"mobile home, manufactured home",
"tricycle, trike, velocipede",
"unicycle, monocycle",
"horse cart, horse-cart",
"jinrikisha, ricksha, rickshaw",
"oxcart",
"bassinet",
"cradle",
"crib, cot",
"four-poster",
"bookcase",
"china cabinet, china closet",
"medicine chest, medicine cabinet",
"chiffonier, commode",
"table lamp",
"file, file cabinet, filing cabinet",
"park bench",
"barber chair",
"throne",
"folding chair",
"rocking chair, rocker",
"studio couch, day bed",
"toilet seat",
"desk",
"pool table, billiard table, snooker table",
"dining table, board",
"entertainment center",
"wardrobe, closet, press",
"Granny Smith",
"orange",
"lemon",
"fig",
"pineapple, ananas",
"banana",
"jackfruit, jak, jack",
"custard apple",
"pomegranate",
"acorn",
"hip, rose hip, rosehip",
"ear, spike, capitulum",
"rapeseed",
"corn",
"buckeye, horse chestnut, conker",
"organ, pipe organ",
"upright, upright piano",
"chime, bell, gong",
"drum, membranophone, tympan",
"gong, tam-tam",
"maraca",
"marimba, xylophone",
"steel drum",
"banjo",
"cello, violoncello",
"violin, fiddle",
"harp",
"acoustic guitar",
"electric guitar",
"cornet, horn, trumpet, trump",
"French horn, horn",
"trombone",
"harmonica, mouth organ, harp, mouth harp",
"ocarina, sweet potato",
"panpipe, pandean pipe, syrinx",
"bassoon",
"oboe, hautboy, hautbois",
"sax, saxophone",
"flute, transverse flute",
"daisy",
"yellow lady's slipper, yellow lady-slipper, Cypripedium calceolus, Cypripedium parviflorum",
"cliff, drop, drop-off",
"valley, vale",
"alp",
"volcano",
"promontory, headland, head, foreland",
"sandbar, sand bar",
"coral reef",
"lakeside, lakeshore",
"seashore, coast, seacoast, sea-coast",
"geyser",
"hatchet",
"cleaver, meat cleaver, chopper",
"letter opener, paper knife, paperknife",
"plane, carpenter's plane, woodworking plane",
"power drill",
"lawn mower, mower",
"hammer",
"corkscrew, bottle screw",
"can opener, tin opener",
"plunger, plumber's helper",
"screwdriver",
"shovel",
"plow, plough",
"chain saw, chainsaw",
"cock",
"hen",
"ostrich, Struthio camelus",
"brambling, Fringilla montifringilla",
"goldfinch, Carduelis carduelis",
"house finch, linnet, Carpodacus mexicanus",
"junco, snowbird",
"indigo bunting, indigo finch, indigo bird, Passerina cyanea",
"robin, American robin, Turdus migratorius",
"bulbul",
"jay",
"magpie",
"chickadee",
"water ouzel, dipper",
"kite",
"bald eagle, American eagle, Haliaeetus leucocephalus",
"vulture",
"great grey owl, great gray owl, Strix nebulosa",
"black grouse",
"ptarmigan",
"ruffed grouse, partridge, Bonasa umbellus",
"prairie chicken, prairie grouse, prairie fowl",
"peacock",
"quail",
"partridge",
"African grey, African gray, Psittacus erithacus",
"macaw",
"sulphur-crested cockatoo, Kakatoe galerita, Cacatua galerita",
"lorikeet",
"coucal",
"bee eater",
"hornbill",
"hummingbird",
"jacamar",
"toucan",
"drake",
"red-breasted merganser, Mergus serrator",
"goose",
"black swan, Cygnus atratus",
"white stork, Ciconia ciconia",
"black stork, Ciconia nigra",
"spoonbill",
"flamingo",
"American egret, great white heron, Egretta albus",
"little blue heron, Egretta caerulea",
"bittern",
"crane",
"limpkin, Aramus pictus",
"American coot, marsh hen, mud hen, water hen, Fulica americana",
"bustard",
"ruddy turnstone, Arenaria interpres",
"red-backed sandpiper, dunlin, Erolia alpina",
"redshank, Tringa totanus",
"dowitcher",
"oystercatcher, oyster catcher",
"European gallinule, Porphyrio porphyrio",
"pelican",
"king penguin, Aptenodytes patagonica",
"albatross, mollymawk",
"great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias",
"tiger shark, Galeocerdo cuvieri",
"hammerhead, hammerhead shark",
"electric ray, crampfish, numbfish, torpedo",
"stingray",
"barracouta, snoek",
"coho, cohoe, coho salmon, blue jack, silver salmon, Oncorhynchus kisutch",
"tench, Tinca tinca",
"goldfish, Carassius auratus",
"eel",
"rock beauty, Holocanthus tricolor",
"anemone fish",
"lionfish",
"puffer, pufferfish, blowfish, globefish",
"sturgeon",
"gar, garfish, garpike, billfish, Lepisosteus osseus",
"loggerhead, loggerhead turtle, Caretta caretta",
"leatherback turtle, leatherback, leathery turtle, Dermochelys coriacea",
"mud turtle",
"terrapin",
"box turtle, box tortoise",
"banded gecko",
"common iguana, iguana, Iguana iguana",
"American chameleon, anole, Anolis carolinensis",
"whiptail, whiptail lizard",
"agama",
"frilled lizard, Chlamydosaurus kingi",
"alligator lizard",
"Gila monster, Heloderma suspectum",
"green lizard, Lacerta viridis",
"African chameleon, Chamaeleo chamaeleon",
"Komodo dragon, Komodo lizard, dragon lizard, giant lizard, Varanus komodoensis",
"triceratops",
"African crocodile, Nile crocodile, Crocodylus niloticus",
"American alligator, Alligator mississipiensis",
"thunder snake, worm snake, Carphophis amoenus",
"ringneck snake, ring-necked snake, ring snake",
"hognose snake, puff adder, sand viper",
"green snake, grass snake",
"king snake, kingsnake",
"garter snake, grass snake",
"water snake",
"vine snake",
"night snake, Hypsiglena torquata",
"boa constrictor, Constrictor constrictor",
"rock python, rock snake, Python sebae",
"Indian cobra, Naja naja",
"green mamba",
"sea snake",
"horned viper, cerastes, sand viper, horned asp, Cerastes cornutus",
"diamondback, diamondback rattlesnake, Crotalus adamanteus",
"sidewinder, horned rattlesnake, Crotalus cerastes",
"European fire salamander, Salamandra salamandra",
"common newt, Triturus vulgaris",
"eft",
"spotted salamander, Ambystoma maculatum",
"axolotl, mud puppy, Ambystoma mexicanum",
"bullfrog, Rana catesbeiana",
"tree frog, tree-frog",
"tailed frog, bell toad, ribbed toad, tailed toad, Ascaphus trui",
"whistle",
"wing",
"paintbrush",
"hand blower, blow dryer, blow drier, hair dryer, hair drier",
"oxygen mask",
"snorkel",
"loudspeaker, speaker, speaker unit, loudspeaker system, speaker system",
"microphone, mike",
"screen, CRT screen",
"mouse, computer mouse",
"electric fan, blower",
"oil filter",
"strainer",
"space heater",
"stove",
"guillotine",
"barometer",
"rule, ruler",
"odometer, hodometer, mileometer, milometer",
"scale, weighing machine",
"analog clock",
"digital clock",
"wall clock",
"hourglass",
"sundial",
"parking meter",
"stopwatch, stop watch",
"digital watch",
"stethoscope",
"syringe",
"magnetic compass",
"binoculars, field glasses, opera glasses",
"projector",
"sunglasses, dark glasses, shades",
"loupe, jeweler's loupe",
"radio telescope, radio reflector",
"bow",
"cannon",
"assault rifle, assault gun",
"rifle",
"projectile, missile",
"computer keyboard, keypad",
"typewriter keyboard",
"crane",
"lighter, light, igniter, ignitor",
"abacus",
"cash machine, cash dispenser, automated teller machine, automatic teller machine, automated teller, automatic teller, ATM",
"slide rule, slipstick",
"desktop computer",
"hand-held computer, hand-held microcomputer",
"notebook, notebook computer",
"web site, website, internet site, site",
"harvester, reaper",
"thresher, thrasher, threshing machine",
"printer",
"slot, one-armed bandit",
"vending machine",
"sewing machine",
"joystick",
"switch, electric switch, electrical switch",
"hook, claw",
"car wheel",
"paddlewheel, paddle wheel",
"pinwheel",
"potter's wheel",
"gas pump, gasoline pump, petrol pump, island dispenser",
"carousel, carrousel, merry-go-round, roundabout, whirligig",
"swing",
"reel",
"radiator",
"puck, hockey puck",
"hard disc, hard disk, fixed disk",
"sunglass",
"pick, plectrum, plectron",
"car mirror",
"solar dish, solar collector, solar furnace",
"remote control, remote",
"disk brake, disc brake",
"buckle",
"hair slide",
"knot",
"combination lock",
"padlock",
"nail",
"safety pin",
"screw",
"muzzle",
"seat belt, seatbelt",
"ski",
"candle, taper, wax light",
"jack-o'-lantern",
"spotlight, spot",
"torch",
"neck brace",
"pier",
"tripod",
"maypole",
"mousetrap",
"spider web, spider's web",
"trilobite",
"harvestman, daddy longlegs, Phalangium opilio",
"scorpion",
"black and gold garden spider, Argiope aurantia",
"barn spider, Araneus cavaticus",
"garden spider, Aranea diademata",
"black widow, Latrodectus mactans",
"tarantula",
"wolf spider, hunting spider",
"tick",
"centipede",
"isopod",
"Dungeness crab, Cancer magister",
"rock crab, Cancer irroratus",
"fiddler crab",
"king crab, Alaska crab, Alaskan king crab, Alaska king crab, Paralithodes camtschatica",
"American lobster, Northern lobster, Maine lobster, Homarus americanus",
"spiny lobster, langouste, rock lobster, crawfish, crayfish, sea crawfish",
"crayfish, crawfish, crawdad, crawdaddy",
"hermit crab",
"tiger beetle",
"ladybug, ladybeetle, lady beetle, ladybird, ladybird beetle",
"ground beetle, carabid beetle",
"long-horned beetle, longicorn, longicorn beetle",
"leaf beetle, chrysomelid",
"dung beetle",
"rhinoceros beetle",
"weevil",
"fly",
"bee",
"grasshopper, hopper",
"cricket",
"walking stick, walkingstick, stick insect",
"cockroach, roach",
"mantis, mantid",
"cicada, cicala",
"leafhopper",
"lacewing, lacewing fly",
"dragonfly, darning needle, devil's darning needle, sewing needle, snake feeder, snake doctor, mosquito hawk, skeeter hawk",
"damselfly",
"admiral",
"ringlet, ringlet butterfly",
"monarch, monarch butterfly, milkweed butterfly, Danaus plexippus",
"cabbage butterfly",
"sulphur butterfly, sulfur butterfly",
"lycaenid, lycaenid butterfly",
"jellyfish",
"sea anemone, anemone",
"brain coral",
"flatworm, platyhelminth",
"nematode, nematode worm, roundworm",
"conch",
"snail",
"slug",
"sea slug, nudibranch",
"chiton, coat-of-mail shell, sea cradle, polyplacophore",
"sea urchin",
"sea cucumber, holothurian",
"iron, smoothing iron",
"espresso maker",
"microwave, microwave oven",
"Dutch oven",
"rotisserie",
"toaster",
"waffle iron",
"vacuum, vacuum cleaner",
"dishwasher, dish washer, dishwashing machine",
"refrigerator, icebox",
"washer, automatic washer, washing machine",
"Crock Pot",
"frying pan, frypan, skillet",
"wok",
"caldron, cauldron",
"coffeepot",
"teapot",
"spatula",
"altar",
"triumphal arch",
"patio, terrace",
"steel arch bridge",
"suspension bridge",
"viaduct",
"barn",
"greenhouse, nursery, glasshouse",
"palace",
"monastery",
"library",
"apiary, bee house",
"boathouse",
"church, church building",
"mosque",
"stupa, tope",
"planetarium",
"restaurant, eating house, eating place, eatery",
"cinema, movie theater, movie theatre, movie house, picture palace",
"home theater, home theatre",
"lumbermill, sawmill",
"coil, spiral, volute, whorl, helix",
"obelisk",
"totem pole",
"castle",
"prison, prison house",
"grocery store, grocery, food market, market",
"bakery, bakeshop, bakehouse",
"barbershop",
"bookshop, bookstore, bookstall",
"butcher shop, meat market",
"confectionery, confectionary, candy store",
"shoe shop, shoe-shop, shoe store",
"tobacco shop, tobacconist shop, tobacconist",
"toyshop",
"fountain",
"cliff dwelling",
"yurt",
"dock, dockage, docking facility",
"brass, memorial tablet, plaque",
"megalith, megalithic structure",
"bannister, banister, balustrade, balusters, handrail",
"breakwater, groin, groyne, mole, bulwark, seawall, jetty",
"dam, dike, dyke",
"chainlink fence",
"picket fence, paling",
"worm fence, snake fence, snake-rail fence, Virginia fence",
"stone wall",
"grille, radiator grille",
"sliding door",
"turnstile",
"mountain tent",
"scoreboard",
"honeycomb",
"plate rack",
"pedestal, plinth, footstall",
"beacon, lighthouse, beacon light, pharos",
"mashed potato",
"bell pepper",
"head cabbage",
"broccoli",
"cauliflower",
"zucchini, courgette",
"spaghetti squash",
"acorn squash",
"butternut squash",
"cucumber, cuke",
"artichoke, globe artichoke",
"cardoon",
"mushroom",
"shower curtain",
"jean, blue jean, denim",
"carton",
"handkerchief, hankie, hanky, hankey",
"sandal",
"ashcan, trash can, garbage can, wastebin, ash bin, ash-bin, ashbin, dustbin, trash barrel, trash bin",
"safe",
"plate",
"necklace",
"croquet ball",
"fur coat",
"thimble",
"pajama, pyjama, pj's, jammies",
"running shoe",
"cocktail shaker",
"chest",
"manhole cover",
"modem",
"tub, vat",
"tray",
"balance beam, beam",
"bagel, beigel",
"prayer rug, prayer mat",
"kimono",
"hot pot, hotpot",
"whiskey jug",
"knee pad",
"book jacket, dust cover, dust jacket, dust wrapper",
"spindle",
"ski mask",
"beer bottle",
"crash helmet",
"bottlecap",
"tile roof",
"mask",
"maillot",
"Petri dish",
"football helmet",
"bathing cap, swimming cap",
"teddy, teddy bear",
"holster",
"pop bottle, soda bottle",
"photocopier",
"vestment",
"crossword puzzle, crossword",
"golf ball",
"trifle",
"suit, suit of clothes",
"water tower",
"feather boa, boa",
"cloak",
"red wine",
"drumstick",
"shield, buckler",
"Christmas stocking",
"hoopskirt, crinoline",
"menu",
"stage",
"bonnet, poke bonnet",
"meat loaf, meatloaf",
"baseball",
"face powder",
"scabbard",
"sunscreen, sunblock, sun blocker",
"beer glass",
"hen-of-the-woods, hen of the woods, Polyporus frondosus, Grifola frondosa",
"guacamole",
"lampshade, lamp shade",
"wool, woolen, woollen",
"hay",
"bow tie, bow-tie, bowtie",
"mailbag, postbag",
"water jug",
"bucket, pail",
"dishrag, dishcloth",
"soup bowl",
"eggnog",
"mortar",
"trench coat",
"paddle, boat paddle",
"chain",
"swab, swob, mop",
"mixing bowl",
"potpie",
"wine bottle",
"shoji",
"bulletproof vest",
"drilling platform, offshore rig",
"binder, ring-binder",
"cardigan",
"sweatshirt",
"pot, flowerpot",
"birdhouse",
"hamper",
"ping-pong ball",
"pencil box, pencil case",
"pay-phone, pay-station",
"consomme",
"apron",
"punching bag, punch bag, punching ball, punchball",
"backpack, back pack, knapsack, packsack, rucksack, haversack",
"groom, bridegroom",
"bearskin, busby, shako",
"pencil sharpener",
"broom",
"mosquito net",
"abaya",
"mortarboard",
"poncho",
"crutch",
"Polaroid camera, Polaroid Land camera",
"space bar",
"cup",
"racket, racquet",
"traffic light, traffic signal, stoplight",
"quill, quill pen",
"radio, wireless",
"dough",
"cuirass",
"military uniform",
"lipstick, lip rouge",
"shower cap",
"monitor",
"oscilloscope, scope, cathode-ray oscilloscope, CRO",
"mitten",
"brassiere, bra, bandeau",
"French loaf",
"vase",
"milk can",
"rugby ball",
"paper towel",
"earthstar",
"envelope",
"miniskirt, mini",
"cowboy hat, ten-gallon hat",
"trolleybus, trolley coach, trackless trolley",
"perfume, essence",
"bathtub, bathing tub, bath, tub",
"hotdog, hot dog, red hot",
"coral fungus",
"bullet train, bullet",
"pillow",
"toilet tissue, toilet paper, bathroom tissue",
"cassette",
"carpenter's kit, tool kit",
"ladle",
"stinkhorn, carrion fungus",
"lotion",
"hair spray",
"academic gown, academic robe, judge's robe",
"dome",
"crate",
"wig",
"burrito",
"pill bottle",
"chain mail, ring mail, mail, chain armor, chain armour, ring armor, ring armour",
"theater curtain, theatre curtain",
"window shade",
"barrel, cask",
"washbasin, handbasin, washbowl, lavabo, wash-hand basin",
"ballpoint, ballpoint pen, ballpen, Biro",
"basketball",
"bath towel",
"cowboy boot",
"gown",
"window screen",
"agaric",
"cellular telephone, cellular phone, cellphone, cell, mobile phone",
"nipple",
"barbell",
"mailbox, letter box",
"lab coat, laboratory coat",
"fire screen, fireguard",
"minibus",
"packet",
"maze, labyrinth",
"pole",
"horizontal bar, high bar",
"sombrero",
"pickelhaube",
"rain barrel",
"wallet, billfold, notecase, pocketbook",
"cassette player",
"comic book",
"piggy bank, penny bank",
"street sign",
"bell cote, bell cot",
"fountain pen",
"Windsor tie",
"volleyball",
"overskirt",
"sarong",
"purse",
"bolo tie, bolo, bola tie, bola",
"bib",
"parachute, chute",
"sleeping bag",
"television, television system",
"swimming trunks, bathing trunks",
"measuring cup",
"espresso",
"pizza, pizza pie",
"breastplate, aegis, egis",
"shopping basket",
"wooden spoon",
"saltshaker, salt shaker",
"chocolate sauce, chocolate syrup",
"ballplayer, baseball player",
"goblet",
"gyromitra",
"stretcher",
"water bottle",
"dial telephone, dial phone",
"soap dispenser",
"jersey, T-shirt, tee shirt",
"school bus",
"jigsaw puzzle",
"plastic bag",
"reflex camera",
"diaper, nappy, napkin",
"Band Aid",
"ice lolly, lolly, lollipop, popsicle",
"velvet",
"tennis ball",
"gasmask, respirator, gas helmet",
"doormat, welcome mat",
"Loafer",
"ice cream, icecream",
"pretzel",
"quilt, comforter, comfort, puff",
"maillot, tank suit",
"tape player",
"clog, geta, patten, sabot",
"iPod",
"bolete",
"scuba diver",
"pitcher, ewer",
"matchstick",
"bikini, two-piece",
"sock",
"CD player",
"lens cap, lens cover",
"thatch, thatched roof",
"vault",
"beaker",
"bubble",
"cheeseburger",
"parallel bars, bars",
"flagpole, flagstaff",
"coffee mug",
"rubber eraser, rubber, pencil eraser",
"stole",
"carbonara",
"dumbbell"]
}
You can’t perform that action at this time.