Skip to content

Commit

Permalink
Merge pull request #19 from apple/dev/hot-fix-again-for-CPU
Browse files Browse the repository at this point in the history
Dev/hot fix again for cpu
  • Loading branch information
srikris authored Sep 1, 2017
2 parents e0f6ccd + 577dbbb commit 8dcad7e
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 33 deletions.
3 changes: 2 additions & 1 deletion coremlpython/CoreMLPython.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ namespace CoreML {
MLModel *m_model = nil;
NSURL *compiledUrl = nil;
public:
Model(const Model&) = delete;
Model& operator=(const Model&) = delete;
~Model();
explicit Model(const std::string& urlStr);
static Model fromSpec(const std::string& urlStr);
py::dict predict(const py::dict& input, bool useCPUOnly);
std::string toString() const;
};
Expand Down
51 changes: 23 additions & 28 deletions coremlpython/CoreMLPython.mm
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,14 @@
Model::~Model() {
NSError *error = nil;
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:[[compiledUrl URLByDeletingLastPathComponent] path] error:&error];
}

Model::Model(const std::string& urlStr) {
@autoreleasepool {
compiledUrl = Utils::stringToNSURL(urlStr);
NSError *error = nil;
m_model = [MLModel modelWithContentsOfURL:compiledUrl error:&error];
Utils::handleError(error);
}
}

py::dict Model::predict(const py::dict& input, bool useCPUOnly) {
@autoreleasepool {
NSError *error = nil;
MLDictionaryFeatureProvider *inFeatures = Utils::dictToFeatures(input, &error);
Utils::handleError(error);
MLPredictionOptions *options = [[MLPredictionOptions alloc] init];
options.usesCPUOnly = useCPUOnly;
id<MLFeatureProvider> outFeatures = [m_model predictionFromFeatures:static_cast<MLDictionaryFeatureProvider * _Nonnull>(inFeatures)
options:options
error:&error];
Utils::handleError(error);
return Utils::featuresToDict(outFeatures);
if (compiledUrl != nil) {
[fileManager removeItemAtPath:[[compiledUrl URLByDeletingLastPathComponent] path] error:&error];
}
}

Model Model::fromSpec(const std::string& urlStr) {
Model::Model(const std::string& urlStr) {
@autoreleasepool {

// Compile the model
NSError *error = nil;
NSURL *specUrl = Utils::stringToNSURL(urlStr);
Expand All @@ -56,7 +35,7 @@
dup2(devnull, STDOUT_FILENO);

// Compile the model
NSURL *compiledUrl = [MLModel compileModelAtURL:specUrl error:&error];
compiledUrl = [MLModel compileModelAtURL:specUrl error:&error];

// Close all the file descriptors and revert back to normal
dup2(stdoutBack, STDOUT_FILENO);
Expand All @@ -71,7 +50,24 @@
errmsg << "\".";
throw std::runtime_error(errmsg.str());
}
return Model(compiledUrl.fileSystemRepresentation);

m_model = [MLModel modelWithContentsOfURL:compiledUrl error:&error];
Utils::handleError(error);
}
}

py::dict Model::predict(const py::dict& input, bool useCPUOnly) {
@autoreleasepool {
NSError *error = nil;
MLDictionaryFeatureProvider *inFeatures = Utils::dictToFeatures(input, &error);
Utils::handleError(error);
MLPredictionOptions *options = [[MLPredictionOptions alloc] init];
options.usesCPUOnly = useCPUOnly;
id<MLFeatureProvider> outFeatures = [m_model predictionFromFeatures:static_cast<MLDictionaryFeatureProvider * _Nonnull>(inFeatures)
options:options
error:&error];
Utils::handleError(error);
return Utils::featuresToDict(outFeatures);
}
}

Expand All @@ -80,7 +76,6 @@

py::class_<Model>(m, "_MLModelProxy")
.def(py::init<const std::string&>())
.def_static("fromSpec", &Model::fromSpec)
.def("predict", &Model::predict);

return m.ptr();
Expand Down
2 changes: 1 addition & 1 deletion coremltools/models/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def _get_proxy_from_spec(filename):
_MLModelProxy = None

if _MLModelProxy:
return _MLModelProxy.fromSpec(filename)
return _MLModelProxy(filename)
else:
return None

Expand Down
72 changes: 71 additions & 1 deletion coremltools/test/test_numpy_nn_layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -769,9 +769,79 @@ def test_padding_reflection(self):
self.assertTrue(self._compare_shapes(numpy_preds, coreml_preds))
self.assertTrue(self._compare_predictions(numpy_preds, coreml_preds))

if os.path.exists(model_dir):
shutil.rmtree(model_dir)


class SimpleTestCPUOnly(CorrectnessTest):

def test_bias_matrix_CPU(self):

#create a tiny mlmodel
input_dim = (1,2,2)
input_features = [('data', datatypes.Array(*input_dim))]
output_features = [('output', None)]

builder = neural_network.NeuralNetworkBuilder(input_features, output_features)

b = np.reshape(np.arange(5,9), (1,2,2))

builder.add_bias(name = 'bias', b = b, input_name = 'data', output_name = 'output',
shape_bias = [1,2,2])

#save the model
model_dir = tempfile.mkdtemp()
model_path = os.path.join(model_dir, 'test_layer.mlmodel')
coremltools.utils.save_spec(builder.spec, model_path)

#preprare input and get predictions
coreml_model = coremltools.models.MLModel(model_path)
x = np.reshape(np.arange(4, dtype=np.float32), (1,2,2))
coreml_input = {'data': x}
coreml_preds = coreml_model.predict(coreml_input, useCPUOnly = True)['output']

#harcoded for this simple test case
numpy_preds = x + b
self.assertTrue(self._compare_shapes(numpy_preds, coreml_preds))
self.assertTrue(self._compare_predictions(numpy_preds, coreml_preds))

if os.path.exists(model_dir):
shutil.rmtree(model_dir)


def test_linear_activation_CPU(self):

#create a tiny mlmodel
input_dim = (10,15,15)
input_features = [('data', datatypes.Array(*input_dim))]
output_features = [('output', None)]

builder = neural_network.NeuralNetworkBuilder(input_features, output_features)

builder.add_activation(name = 'activation',
non_linearity = 'LINEAR',
input_name = 'data',
output_name = 'output', params= [34.0, 67.0])

#save the model
model_dir = tempfile.mkdtemp()
model_path = os.path.join(model_dir, 'test_layer.mlmodel')
coremltools.utils.save_spec(builder.spec, model_path)

#preprare input and get predictions
coreml_model = coremltools.models.MLModel(model_path)
x = np.random.rand(*input_dim)
coreml_input = {'data': x}
coreml_preds = coreml_model.predict(coreml_input, useCPUOnly = True)['output']

#harcoded for this simple test case
numpy_preds = 34.0 * x + 67.0
self.assertTrue(self._compare_shapes(numpy_preds, coreml_preds))
self.assertTrue(self._compare_predictions(numpy_preds, coreml_preds))

if os.path.exists(model_dir):
shutil.rmtree(model_dir)



class StressTest(CorrectnessTest):
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
try:
version = pkg_resources.require("coremltools")[0].version
except:
version = "0.6.2"
version = "0.6.3"

# The short X.Y version.
version = version
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
long_description = f.read()

setup(name='coremltools',
version='0.6.2',
version='0.6.3',
description='Community Tools for CoreML',
long_description=long_description,
author='Apple Inc.',
Expand Down

0 comments on commit 8dcad7e

Please sign in to comment.