diff --git a/winml/adapter/winml_adapter_apis.h b/winml/adapter/winml_adapter_apis.h index 079b650115..178ad5d290 100644 --- a/winml/adapter/winml_adapter_apis.h +++ b/winml/adapter/winml_adapter_apis.h @@ -24,6 +24,7 @@ ORT_API_STATUS(CreateModelFromData, _In_ void* data, _In_ size_t size, _Outptr_ ORT_API_STATUS(CloneModel, _In_ const OrtModel* in, _Outptr_ OrtModel** out); ORT_API_STATUS(ModelGetAuthor, _In_ const OrtModel* model, _Out_ const char** const author, _Out_ size_t* len); ORT_API_STATUS(ModelGetName, _In_ const OrtModel* model, _Out_ const char** const name, _Out_ size_t* len); +ORT_API_STATUS(ModelSetName, _In_ const OrtModel* model, _In_ const char* name); ORT_API_STATUS(ModelGetDomain, _In_ const OrtModel* model, _Out_ const char** const domain, _Out_ size_t* len); ORT_API_STATUS(ModelGetDescription, _In_ const OrtModel* model, _Out_ const char** const description, _Out_ size_t* len); ORT_API_STATUS(ModelGetVersion, _In_ const OrtModel* model, _Out_ int64_t* version); diff --git a/winml/adapter/winml_adapter_c_api.cpp b/winml/adapter/winml_adapter_c_api.cpp index d3b29630e1..9d7f8c064c 100644 --- a/winml/adapter/winml_adapter_c_api.cpp +++ b/winml/adapter/winml_adapter_c_api.cpp @@ -26,6 +26,7 @@ static constexpr WinmlAdapterApi winml_adapter_api_1 = { &winmla::CloneModel, &winmla::ModelGetAuthor, &winmla::ModelGetName, + &winmla::ModelSetName, &winmla::ModelGetDomain, &winmla::ModelGetDescription, &winmla::ModelGetVersion, diff --git a/winml/adapter/winml_adapter_c_api.h b/winml/adapter/winml_adapter_c_api.h index ce8f33f00c..d4d5d38e91 100644 --- a/winml/adapter/winml_adapter_c_api.h +++ b/winml/adapter/winml_adapter_c_api.h @@ -102,6 +102,13 @@ struct WinmlAdapterApi { */ OrtStatus*(ORT_API_CALL* ModelGetName)(_In_ const OrtModel* model, _Out_ const char** const name, _Out_ size_t* len)NO_EXCEPTION; + /** + * ModelSetName + * This api set the model name from the OrtModel. + * This is used by the Windows ML Samples Gallery to change the model name for telemetry. + */ + OrtStatus*(ORT_API_CALL* ModelSetName)(_In_ const OrtModel* model, _In_ const char* name)NO_EXCEPTION; + /** * ModelGetDomain * This api gets the model domain from the OrtModel. diff --git a/winml/adapter/winml_adapter_model.cpp b/winml/adapter/winml_adapter_model.cpp index b1578d4bf4..49beae906a 100644 --- a/winml/adapter/winml_adapter_model.cpp +++ b/winml/adapter/winml_adapter_model.cpp @@ -290,6 +290,15 @@ ORT_API_STATUS_IMPL(winmla::ModelGetName, _In_ const OrtModel* model, _Out_ cons API_IMPL_END } +ORT_API_STATUS_IMPL(winmla::ModelSetName, _In_ const OrtModel* model, _In_ const char* const name) { + API_IMPL_BEGIN + auto model_proto = model->UseModelProto(); + ONNX_NAMESPACE::GraphProto& graph = *model_proto->mutable_graph(); + graph.set_name(name); + return nullptr; + API_IMPL_END +} + ORT_API_STATUS_IMPL(winmla::ModelGetDomain, _In_ const OrtModel* model, _Out_ const char** const domain, _Out_ size_t* len) { API_IMPL_BEGIN *domain = model->UseModelInfo()->domain_.c_str(); diff --git a/winml/api/Microsoft.AI.MachineLearning.Experimental.idl b/winml/api/Microsoft.AI.MachineLearning.Experimental.idl index 99475ddc62..3e7a33ebd1 100644 --- a/winml/api/Microsoft.AI.MachineLearning.Experimental.idl +++ b/winml/api/Microsoft.AI.MachineLearning.Experimental.idl @@ -141,6 +141,9 @@ namespace ROOT_NS.AI.MachineLearning.Experimental { //! The JoinModel fuses two models by linking outputs from the first model, to inupts of the second. ROOT_NS.AI.MachineLearning.LearningModel JoinModel(ROOT_NS.AI.MachineLearning.LearningModel other, LearningModelJoinOptions options); + + //! The SetName function changes the model name to the specified string + void SetName(String model_name); } } // namespace Microsoft.AI.MachineLearning.Experimental diff --git a/winml/lib/Api.Experimental/LearningModelExperimental.cpp b/winml/lib/Api.Experimental/LearningModelExperimental.cpp index 81ca2effb8..e6c22bbb39 100644 --- a/winml/lib/Api.Experimental/LearningModelExperimental.cpp +++ b/winml/lib/Api.Experimental/LearningModelExperimental.cpp @@ -29,4 +29,9 @@ void LearningModelExperimental::Save(hstring const& file_name) { modelp->SaveToFile(file_name); } +void LearningModelExperimental::SetName(hstring const& model_name) { + auto modelp = model_.as(); + modelp->SetName(model_name); +} + } diff --git a/winml/lib/Api.Experimental/LearningModelExperimental.h b/winml/lib/Api.Experimental/LearningModelExperimental.h index b9b1e85348..1e43c73f4f 100644 --- a/winml/lib/Api.Experimental/LearningModelExperimental.h +++ b/winml/lib/Api.Experimental/LearningModelExperimental.h @@ -12,6 +12,8 @@ struct LearningModelExperimental : LearningModelExperimentalTUseWinmlAdapterApi(); + RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelSetName(ort_model_.get(), name), + engine_factory_->UseOrtApi()); + info_->SetName(name); + return S_OK; +} + STDMETHODIMP OnnruntimeModel::DetachOrtModel(OrtModel** model) { *model = ort_model_.release(); return S_OK; diff --git a/winml/lib/Api.Ort/OnnxruntimeModel.h b/winml/lib/Api.Ort/OnnxruntimeModel.h index 57bcbb9849..d3f65671da 100644 --- a/winml/lib/Api.Ort/OnnxruntimeModel.h +++ b/winml/lib/Api.Ort/OnnxruntimeModel.h @@ -26,6 +26,8 @@ class ModelInfo : public Microsoft::WRL::RuntimeClass< (const char** out, size_t* len); STDMETHOD(GetName) (const char** out, size_t* len); + STDMETHOD(SetName) + (const char* name); STDMETHOD(GetDomain) (const char** out, size_t* len); STDMETHOD(GetDescription) @@ -68,6 +70,8 @@ class OnnruntimeModel : public Microsoft::WRL::RuntimeClass< STDMETHOD(SaveModel) (_In_ const wchar_t* const file_name, _In_ unsigned size); + STDMETHOD(SetName) + (const char* name); STDMETHOD(DetachOrtModel) (OrtModel** model); diff --git a/winml/lib/Api/LearningModel.cpp b/winml/lib/Api/LearningModel.cpp index 787c2afd62..d468d51469 100644 --- a/winml/lib/Api/LearningModel.cpp +++ b/winml/lib/Api/LearningModel.cpp @@ -279,6 +279,13 @@ LearningModel::OutputFeatures() try { } WINML_CATCH_ALL +void LearningModel::SetName(const hstring& name) try { + auto name_std_str = _winml::Strings::UTF8FromHString(name); + auto name_c_str = name_std_str.c_str(); + WINML_THROW_IF_FAILED(model_->SetName(name_c_str)); +} +WINML_CATCH_ALL + void LearningModel::Close() try { // close the model model_ = nullptr; diff --git a/winml/lib/Api/LearningModel.h b/winml/lib/Api/LearningModel.h index 0a7975a144..5fbcebdd60 100644 --- a/winml/lib/Api/LearningModel.h +++ b/winml/lib/Api/LearningModel.h @@ -59,6 +59,8 @@ struct LearningModel : LearningModelT { wfc::IVectorView OutputFeatures(); + void SetName(const hstring& name); + /* IClosable methods. */ void Close(); diff --git a/winml/lib/Common/inc/iengine.h b/winml/lib/Common/inc/iengine.h index df41d05222..cad1d2be8c 100644 --- a/winml/lib/Common/inc/iengine.h +++ b/winml/lib/Common/inc/iengine.h @@ -66,6 +66,9 @@ IModelInfo : IUnknown { STDMETHOD(GetName) (const char** out, size_t* len) PURE; + STDMETHOD(SetName) + (const char* name) PURE; + STDMETHOD(GetDomain) (const char** out, size_t* len) PURE; @@ -100,6 +103,9 @@ IModel : IUnknown { (_In_ const wchar_t* const file_name, _In_ unsigned size) PURE; + STDMETHOD(SetName) + (const char* name) PURE; + STDMETHOD(AddOperator) (_In_ const char* const op_type, _In_ const char* const op_name, _In_ const char* const op_domain, _In_ const char* const* op_input_names, _In_ const char* const* actual_input_names, size_t num_inputs, diff --git a/winml/test/api/LearningModelSessionAPITest.cpp b/winml/test/api/LearningModelSessionAPITest.cpp index faa3794435..65e44275e1 100644 --- a/winml/test/api/LearningModelSessionAPITest.cpp +++ b/winml/test/api/LearningModelSessionAPITest.cpp @@ -1089,6 +1089,30 @@ static void SetIntraOpThreadSpinning() { WINML_EXPECT_TRUE(allowSpinning); } + static void SetName() { + // load the model with name 'squeezenet_old' + LearningModel model = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", model)); + auto model_name = model.Name(); + auto squeezenet_old = to_hstring("squeezenet_old"); + WINML_EXPECT_EQUAL(model_name, squeezenet_old); + + // ensure the model name can be changed to 'new name' + auto experimental_model = winml_experimental::LearningModelExperimental(model); + auto new_name = to_hstring("new name"); + experimental_model.SetName(new_name); + model_name = model.Name(); + WINML_EXPECT_EQUAL(model_name, new_name); + + // ensure the model protobuf was actually modified + std::wstring path = FileHelpers::GetModulePath() + L"model_name_changed.onnx"; + experimental_model.Save(path); + LearningModel model_name_changed = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model_name_changed.onnx", model_name_changed)); + model_name = model_name_changed.Name(); + WINML_EXPECT_EQUAL(model_name, new_name); + } + const LearningModelSessionAPITestsApi& getapi() { static LearningModelSessionAPITestsApi api = @@ -1123,6 +1147,7 @@ const LearningModelSessionAPITestsApi& getapi() { ModelBuilding_STFT, ModelBuilding_MelSpectrogramOnThreeToneSignal, ModelBuilding_MelWeightMatrix, + SetName }; if (SkipGpuTests()) { diff --git a/winml/test/api/LearningModelSessionAPITest.h b/winml/test/api/LearningModelSessionAPITest.h index c3753e1ca0..0b04214507 100644 --- a/winml/test/api/LearningModelSessionAPITest.h +++ b/winml/test/api/LearningModelSessionAPITest.h @@ -34,6 +34,7 @@ struct LearningModelSessionAPITestsApi { VoidTest ModelBuilding_STFT; VoidTest ModelBuilding_MelSpectrogramOnThreeToneSignal; VoidTest ModelBuilding_MelWeightMatrix; + VoidTest SetName; }; const LearningModelSessionAPITestsApi& getapi(); @@ -69,4 +70,5 @@ WINML_TEST(LearningModelSessionAPITests, ModelBuilding_BlackmanWindow) WINML_TEST(LearningModelSessionAPITests, ModelBuilding_STFT) WINML_TEST(LearningModelSessionAPITests, ModelBuilding_MelSpectrogramOnThreeToneSignal) WINML_TEST(LearningModelSessionAPITests, ModelBuilding_MelWeightMatrix) +WINML_TEST(LearningModelSessionAPITests, SetName) WINML_TEST_CLASS_END()