Home
%3CLINGO-SUB%20id%3D%22lingo-sub-765366%22%20slang%3D%22en-US%22%3EDeploying%20Azure%20Machine%20Learning%20service%20models%20for%20inference%20with%20Azure%20Functions%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-765366%22%20slang%3D%22en-US%22%3E%3CP%3EThis%20article%20shows%20how%20to%20deploy%20an%20Azure%20Machine%20Learning%20service%20(AML)%20generated%20model%20to%20an%20Azure%20Function.%20Right%20now%2C%20AML%20supports%20a%20variety%20of%20choices%20to%20deploy%20models%20for%20inferencing%20%E2%80%93%20GPUs%2C%20FPGA%2C%20IoT%20Edge%2C%20custom%20Docker%20images.%20%26nbsp%3BCustomers%20have%20provided%20feedback%20to%20support%20%E2%80%93%20an%20event-driven%20serverless%20compute%20platform%20that%20can%20also%20solve%20complex%20orchestration%20problems%20%E2%80%93%20as%20a%20model%20deployment%20endpoint%20within%20%3CA%20href%3D%22https%3A%2F%2Fazure.microsoft.com%2Fservices%2Fmachine-learning-service%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3EAzure%20Machine%20Learning%20service%3C%2FA%3E%2C%20and%20our%20AI%20platform%20engineering%20team%20is%20looking%20into%20this%20feedback%20to%20make%20it%20a%20seamless%20experience.%3C%2FP%3E%0A%3CP%3EIn%20the%20meantime%2C%20this%20blog%20post%20will%20walk%20you%20through%20the%20set%20of%20steps%20to%20manually%20download%20the%20model%20file%20and%20package%20it%20as%20part%20of%20Azure%20Functions%20for%20inferencing%20.%20This%20article%20uses%20Python%20code%20to%20build%20an%20E2E%20ML%20model%20and%20Azure%20functions.%20The%20data%20and%20model%20are%20from%20the%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2FMachineLearningNotebooks%2Ftree%2Fmaster%2Fhow-to-use-azureml%2Fautomated-machine-learning%2Fforecasting-energy-demand%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3EForecast%20Energy%20Demand%20tutorial%3C%2FA%3E%3C%2FP%3E%0A%3CH1%20id%3D%22toc-hId-1989935302%22%20id%3D%22toc-hId-1989935302%22%3EWhy%20customers%20want%20Azure%20Functions%20integrated%20with%20Azure%20ML%20Service%3F%3C%2FH1%3E%0A%3COL%3E%0A%3CLI%3EThere%20is%20no%20need%20to%20have%20pre-provisioned%20resources%20such%20as%20clusters%3C%2FLI%3E%0A%3CLI%3ELeverage%20event%20driven%20programming%20with%20several%20built-in%20triggers%20%E2%80%93%20for%20example%2C%20when%20the%20payload%20is%20uploaded%20to%20Storage%2C%20automatically%20trigger%20the%20Azure%20Function%20to%20score%20the%20payload%20using%20the%20AML%20model.%3C%2FLI%3E%0A%3CLI%3EThere%20is%20no%20need%20to%20remember%20URLs%20or%20IP%20addresses%20to%20make%20POST%20requests.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CH1%20id%3D%22toc-hId--562221659%22%20id%3D%22toc-hId--562221659%22%3EThings%20to%20keep%20in%20mind%3C%2FH1%3E%0A%3COL%3E%0A%3CLI%3EWhen%20using%20Azure%20Functions%20without%20the%20consumption%20plan%2C%20there%20may%20be%20impact%20due%20to%20%E2%80%98cold%20start%E2%80%99%20scenarios.%20This%20%3CA%20href%3D%22https%3A%2F%2Fblogs.msdn.microsoft.com%2Fappserviceteam%2F2018%2F02%2F07%2Funderstanding-serverless-cold-start%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3Eblog%3C%2FA%3Eexplains%20this%20behavior.%3C%2FLI%3E%0A%3CLI%3EMachine%20learning%20models%20may%20be%20large%20and%20include%20several%20library%20dependencies.%20When%20inferencing%20(scoring)%2C%20the%20machine%20learning%20model%20must%20be%20deserialized%20and%20then%20applied%20against%20the%20payload%20which%20may%20lead%20to%20higher%20performance%20latencies%20when%20coupled%20with%20%E2%80%98cold%20start%E2%80%99%20scenarios.%3C%2FLI%3E%0A%3CLI%3EAt%20this%20time%2C%20Azure%20Functions%20only%20supports%20python%20dependencies%20that%20can%20be%20installed%20via%20pip%20install.%20If%20the%20model%20has%20other%20complex%20dependencies%2C%20then%20this%20may%20not%20be%20viable.%3C%2FLI%3E%0A%3CLI%3EAzure%20Functions%20%3CA%20href%3D%22https%3A%2F%2Fazure.microsoft.com%2Fblog%2Fazure-functions-gets-better-for-python-and-javascript-developers%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3Epython%20support%20recently%20went%20GA%3C%2FA%3E.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CH1%20id%3D%22toc-hId-1180588676%22%20id%3D%22toc-hId-1180588676%22%3EImplementation%3C%2FH1%3E%0A%3CP%3EHere%20are%20the%20set%20of%20steps%20%3A%3C%2FP%3E%0A%3COL%3E%0A%3CLI%3EPicking%20the%20model%20file%20that%20needs%20to%20be%20hosted%20in%20Azure%20Functions%3C%2FLI%3E%0A%3CLI%3EBuilding%20the%20Azure%20Functions%20scaffolding%2C%20testing%20and%20deploying%20to%20Azure.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CH2%20id%3D%22toc-hId--1568081790%22%20id%3D%22toc-hId--1568081790%22%3E%26nbsp%3B%3C%2FH2%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CH2%20id%3D%22toc-hId-174728545%22%20id%3D%22toc-hId-174728545%22%3EStep%201%3A%20Picking%20a%20model%3C%2FH2%3E%0A%3CP%3EPicking%20the%20right%20model%20with%20the%20right%20features%20and%20setting%20up%20the%20correct%20parameters%20takes%20a%20lot%20of%20time%20and%20effort.%20Fortunately%2C%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fmachine-learning%2Fservice%2Fconcept-automated-ml%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3EAzure%20Automated%20ML%3C%2FA%3Emakes%20this%20easy.%3C%2FP%3E%0A%3CP%3ETo%20try%20this%2C%20I%20am%20using%20the%20model%20that%20was%20built%20using%20automated%20ML%20and%20is%20part%20of%20the%20Forecasting%20Energy%20Demand%20tutorial%20at%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2FMachineLearningNotebooks%2Ftree%2Fmaster%2Fhow-to-use-azureml%2Fautomated-machine-learning%2Fforecasting-energy-demand%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3Ehttps%3A%2F%2Fgithub.com%2FAzure%2FMachineLearningNotebooks%2Ftree%2Fmaster%2Fhow-to-use-azureml%2Fautomated-machine-learning%2Fforecasting-energy-demand%3C%2FA%3E.%3C%2FP%3E%0A%3CP%3EAfter%20completing%20the%20training%20of%20the%20model%2C%20automated%20ML%20provides%20the%20right%20%E2%80%98fitted%20model%E2%80%99.%3C%2FP%3E%0A%3CP%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20style%3D%22width%3A%20580px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F123884iA6ECDEB242063282%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20alt%3D%22Figure%201.png%22%20title%3D%22Figure%201.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3EAdd%20these%20commands%20to%20download%20the%20pickle%20file%20from%20the%20notebook.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%3Eimport%20pickle%0Apickle.dump(fitted_model%2C%20open(%20%22forecastmodel.p%22%2C%20%22wb%22%20))%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EAnd%20now%20in%20the%20folder%2C%20I%20can%20see%20this%20pickle%20file%3A%3C%2FP%3E%0A%3CP%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20style%3D%22width%3A%20999px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F123894iF03852B32E2B0B3C%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20alt%3D%22Figure%202.png%22%20title%3D%22Figure%202.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3EThis%20file%20can%20now%20be%20downloaded%20to%20the%20local%20dev%20machine%20where%20the%20next%20set%20of%20steps%20will%20be%20carried%20out.%3C%2FP%3E%0A%3CP%3EThe%20local%20dev%20machine%20has%20%3CA%20href%3D%22https%3A%2F%2Fdocs.docker.com%2Fdocker-for-mac%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noopener%20noreferrer%20noopener%20noreferrer%22%3Edocker%3C%2FA%3E%2C%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fazure-functions%2Ffunctions-run-local%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3EAzure%20Functions%20developer%20tools%3C%2FA%3E(npm%20install%20-g%20azure-functions-core-tools)%2C%20and%20installed%20in%20it.%3C%2FP%3E%0A%3CH2%20id%3D%22toc-hId-1917538880%22%20id%3D%22toc-hId-1917538880%22%3EStep%202%3A%20Building%20the%20Azure%20Functions%20scaffolding%20and%20testing%3C%2FH2%3E%0A%3CP%3EIf%20you%20follow%20this%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fazure-functions%2Ffunctions-create-first-function-python%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3Earticle%3C%2FA%3E%2C%20this%20explains%20how%20to%20develop%20an%20Azure%20function%20using%20Python.%3C%2FP%3E%0A%3CP%3EIn%20my%20dev%20machine%2C%20I%20have%20a%20folder%20%E2%80%98blog%E2%80%99%20where%20requirements.txt%20contains%20the%20various%20python%20packages%20required%20by%20the%20Function%20App.%3C%2FP%3E%0A%3CP%3E%3CSTRONG%3Erequirements.txt%3C%2FSTRONG%3E%3C%2FP%3E%0A%3CPRE%3Eazure-functions%3D%3D1.0.0b3%0Aazure-functions-worker%3D%3D1.0.0b3%0Agrpcio%3D%3D1.14.2%0Agrpcio-tools%3D%3D1.14.2%0Aprotobuf%3D%3D3.6.1%0Asix%3D%3D1.12.0%0Anumpy%0Aazureml-sdk%0Asklearn%3C%2FPRE%3E%0A%3CP%3EInside%20this%20folder%2C%20I%20have%20a%20folder%20%E2%80%98HttpTrigger%E2%80%99%20and%20have%20created%20the%20following%20files%3A%3C%2FP%3E%0A%3CUL%3E%0A%3CLI%3Emain.py%3C%2FLI%3E%0A%3CLI%3Efunction.json%3C%2FLI%3E%0A%3C%2FUL%3E%0A%3CP%3E%3CSTRONG%3Emain.py%3C%2FSTRONG%3E%3C%2FP%3E%0A%3CPRE%3Eimport%20azure.functions%20as%20func%0Aimport%20logging%0Aimport%20pickle%0Aimport%20sys%0Aimport%20os%0Aimport%20pathlib%0Aimport%20numpy%20as%20np%0Aimport%20azureml.train.automl%0Aimport%20pandas%20as%20pd%0A%0A%0Adef%20main(req%3A%20func.HttpRequest)%20-%26gt%3B%20func.HttpResponse%3A%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%20logging.info('Python%20HTTP%20trigger%20function%20processed%20a%20request.')%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%20clientId%20%3D%20req.params.get('clientId')%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%20logging.info('**********Processing********')%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%20if%20not%20clientId%3A%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20try%3A%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20req_body%20%3D%20req.get_json()%0A%26nbsp%3B%20%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3Bexcept%20ValueError%3A%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20pass%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20else%3A%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20clientId%20%3D%20req_body.get('clientId')%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%23%20load%20the%20model%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%20f%20%3D%20open(pathlib.Path(__file__).parent%2F'forecastmodel.pkl'%2C%20'rb')%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%20model%20%3D%20pickle.load(f)%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%20if%20clientId%3A%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20logging.info(clientId)%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20data%20%3D%20%7B'timeStamp'%3A%5B'2017-02-01%2002%3A00%3A00'%2C'2017-02-01%2003%3A00%3A00'%5D%2C'precip'%3A%5B0.0%2C0.0%5D%2C'temp'%3A%5B33.61%2C32.30%5D%7D%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20test%20%3D%20pd.DataFrame(data%2Ccolumns%3D%5B'timeStamp'%2C%20'precip'%2C%20'temp'%5D)%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20logging.info(test.timeStamp%20%2B%20'%20'%20%2B%20str(test.precip)%20%2B%20'%20'%20%2B%20str(test.temp))%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20y_pred%20%3D%20model.predict(test)%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20logging.info(y_pred)%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20return%20func.HttpResponse(str(y_pred))%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%20else%3A%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20return%20func.HttpResponse(%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%22Please%20pass%20the%20correct%20parameters%20on%20query%20strint%20or%20in%20the%20request%20body%22%2C%26nbsp%3B%26nbsp%3B%26nbsp%3Bstatus_code%3D400%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20)%0A%3C%2FPRE%3E%0A%3CP%3EThe%20code%20uses%20%E2%80%982017-02-01%E2%80%99%20since%20the%20demand%20forecast%20tutorial%20includes%20the%20dataset%20from%20that%20year.%3C%2FP%3E%0A%3CP%3E%3CSTRONG%3Efunction.json%3C%2FSTRONG%3E%3C%2FP%3E%0A%3CPRE%3E%7B%0A%26nbsp%3B%20%22scriptFile%22%3A%20%22main.py%22%2C%0A%26nbsp%3B%20%22bindings%22%3A%20%5B%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%7B%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%22authLevel%22%3A%20%22anonymous%22%2C%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%22type%22%3A%20%22httpTrigger%22%2C%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%22direction%22%3A%20%22in%22%2C%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%22name%22%3A%20%22req%22%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%7D%2C%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%7B%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%22type%22%3A%20%22http%22%2C%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%22direction%22%3A%20%22out%22%2C%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%22name%22%3A%20%22%24return%22%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%7D%0A%26nbsp%3B%20%5D%0A%7D%0A%0A%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%3CSTRONG%3ETesting%20the%20function%20locally%3C%2FSTRONG%3E%3C%2FP%3E%0A%3CP%3EYou%E2%80%99ll%20need%20to%20set%20up%20the%20virtual%20python%20environment.%20For%20instructions%2C%20see%20this%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fazure-functions%2Ffunctions-create-first-function-python%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3Earticle%3C%2FA%3E.%3C%2FP%3E%0A%3CPRE%3Epython3.6%20-m%20venv%20.functionenv%0Asource%20.functionenv%2Fbin%2Factivate%3C%2FPRE%3E%0A%3CP%3EAnd%20then%20install%20the%20required%20packages%3A%3C%2FP%3E%0A%3CPRE%3E%26nbsp%3Bpip%20install%20-r%20requirements.txt%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EFrom%20the%20%E2%80%98blog%E2%80%99%20folder%2C%20launch%20the%20Azure%20Functions%20local%20runtime%20to%20start%20locally%3A%3C%2FP%3E%0A%3CPRE%3Efunc%20host%20start%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EThe%20Azure%20Function%20should%20start%20locally%20and%20provide%20the%20complete%20URL%20of%20the%20HttpTrigger%20API.%26nbsp%3B%20You%20should%20see%20similar%20output%20to%20what%20appears%20below.%3C%2FP%3E%0A%3CP%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20style%3D%22width%3A%20999px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F123895iCA94DF94050D2B30%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20alt%3D%22Figure%203.png%22%20title%3D%22Figure%203.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3ETo%20test%20the%20function%2C%20from%20another%20shell%20do%20a%20curl%20command%20and%20you%20should%20get%20the%20output%20which%20is%20a%20prediction.%3C%2FP%3E%0A%3CP%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20style%3D%22width%3A%20999px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F123896iBEC78585C2BD013E%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20alt%3D%22Figure%204.png%22%20title%3D%22Figure%204.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3EThe%20output%20is%20the%20array%20%5B4600.9586368%26nbsp%3B%204642.14414377%5D%20which%20is%20the%20demand%20prediction%20for%20the%20parameters%20passed%20in%20from%20%E2%80%98main.py%E2%80%99%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%3Edata%20%3D%20%7B'timeStamp'%3A%5B'2017-02-01%2002%3A00%3A00'%2C'2017-02-01%2003%3A00%3A00'%5D%2C'precip'%3A%5B0.0%2C0.0%5D%2C'temp'%3A%5B33.61%2C32.30%5D%7D%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3ESo%20the%20complete%20details%20are%20as%20follows%3A%3C%2FP%3E%0A%3CTABLE%3E%0A%3CTBODY%3E%0A%3CTR%3E%0A%3CTD%20width%3D%22156%22%3E%0A%3CP%3Etimestamp%3C%2FP%3E%0A%3C%2FTD%3E%0A%3CTD%20width%3D%22156%22%3E%0A%3CP%3EPrecip%3C%2FP%3E%0A%3C%2FTD%3E%0A%3CTD%20width%3D%22156%22%3E%0A%3CP%3ETemp%3C%2FP%3E%0A%3C%2FTD%3E%0A%3CTD%20width%3D%22156%22%3E%0A%3CP%3EDemand%3C%2FP%3E%0A%3C%2FTD%3E%0A%3C%2FTR%3E%0A%3CTR%3E%0A%3CTD%20width%3D%22156%22%3E%0A%3CP%3E2017-02-01%2002%3A00%3A00%3C%2FP%3E%0A%3C%2FTD%3E%0A%3CTD%20width%3D%22156%22%3E%0A%3CP%3E0.0%3C%2FP%3E%0A%3C%2FTD%3E%0A%3CTD%20width%3D%22156%22%3E%0A%3CP%3E33.61%3C%2FP%3E%0A%3C%2FTD%3E%0A%3CTD%20width%3D%22156%22%3E%0A%3CP%3E4600.9586368%26nbsp%3B%3C%2FP%3E%0A%3C%2FTD%3E%0A%3C%2FTR%3E%0A%3CTR%3E%0A%3CTD%20width%3D%22156%22%3E%0A%3CP%3E2017-02-01%2003%3A00%3A00%3C%2FP%3E%0A%3C%2FTD%3E%0A%3CTD%20width%3D%22156%22%3E%0A%3CP%3E0.0%3C%2FP%3E%0A%3C%2FTD%3E%0A%3CTD%20width%3D%22156%22%3E%0A%3CP%3E32.30%3C%2FP%3E%0A%3C%2FTD%3E%0A%3CTD%20width%3D%22156%22%3E%0A%3CP%3E4642.14414377%3C%2FP%3E%0A%3C%2FTD%3E%0A%3C%2FTR%3E%0A%3C%2FTBODY%3E%0A%3C%2FTABLE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EYou%20can%20modify%20main.py%20and%20get%20new%20prediction%20values.%3C%2FP%3E%0A%3CP%3EThe%20shell%20where%20the%20function%20was%20started%20will%20also%20show%20the%20logging%20and%20other%20details%3C%2FP%3E%0A%3CP%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20style%3D%22width%3A%20999px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F123897i9257EDFB15EB1D6D%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20alt%3D%22Figure%205.png%22%20title%3D%22Figure%205.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3BYou%20can%20deploy%20this%20as%20an%20Azure%20Functions%20using%20the%20instructions%20from%20this%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fazure-functions%2Ffunctions-create-first-function-python%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3Etutorial%3C%2FA%3E.%20Remember%20to%20use%20%E2%80%98--build-native-deps%E2%80%99%20parameter%20and%20now%20a%20docker%20image%20will%20be%20created%20and%20operationalized%20within%20Azure%20Functions.%3C%2FP%3E%0A%3CP%3EI%20created%20an%20app%20service%20plan%20and%20a%20function%20app%20name%20within%20it%3C%2FP%3E%0A%3CPRE%3Eaz%20appservice%20plan%20create%20--resource-group%20%26lt%3Brg%20name%26gt%3B%20%20--name%20%26lt%3Bname%26gt%3B%20--subscription%20%26lt%3Bsubscription%20id%26gt%3B%20--is-linux%0Aaz%20functionapp%20create%20--resource-group%20%26lt%3B%26gt%3B%20--os-type%20Linux%20--plan%20%26lt%3Bplan%20name%26gt%3B%20--runtime%20python%20--name%20%26lt%3Bfunction%20app%20name%26gt%3B%20--storage-account%20%26lt%3Bstorage%20account%20name%26gt%3B%20--subscription%20%26lt%3Bsubscripton%20id%26gt%3B%0Afunc%20azure%20functionapp%20publish%20%26lt%3Bfunction%20app%20name%26gt%3B%20--build-native-deps%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EAt%20this%20point%2C%20you%20have%20taken%20the%20Demand%20Forecasting%20model%20and%20operationalized%20it%20as%20part%20of%20Azure%20Functions%2C%20thus%20taking%20a%20Serverless%20pattern%20approach%20for%20inferencing%20of%20the%20model.%3C%2FP%3E%0A%3CP%3EIn%20a%20subsequent%20blog%2C%20we%20will%20show%20how%20to%20use%20this%20custom%20docker%20image%20within%20Azure%20Machine%20Learning%20and%20the%20advantages%20of%20leveraging%20the%20AML%20registry%20and%20using%20MLOps%20for%20operationalizing%20the%20code.%3C%2FP%3E%0A%3CH1%20id%3D%22toc-hId--438104576%22%20id%3D%22toc-hId--438104576%22%3EUseful%20Links%3C%2FH1%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CUL%3E%0A%3CLI%3E%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fazure-functions%2Ffunctions-create-function-linux-custom-image%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3Ehttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fazure-functions%2Ffunctions-create-function-linux-custom-image%3C%2FA%3E%3C%2FLI%3E%0A%3CLI%3E%3CA%20href%3D%22https%3A%2F%2Fhub.docker.com%2F_%2Fmicrosoft-azure-functions-base%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noopener%20noreferrer%20noopener%20noreferrer%22%3Ehttps%3A%2F%2Fhub.docker.com%2F_%2Fmicrosoft-azure-functions-base%3C%2FA%3E%3C%2FLI%3E%0A%3CLI%3E%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-python-worker%2Fissues%2F340%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3Ehttps%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-python-worker%2Fissues%2F340%3C%2FA%3E--%26gt%3B%20use%20the%20latest%20core%20tools%20to%20get%20past%20this%20issue.%3C%2FLI%3E%0A%3CLI%3E%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fcontainer-registry%2Fcontainer-registry-get-started-docker-cli%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3Ehttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fcontainer-registry%2Fcontainer-registry-get-started-docker-cli%3C%2FA%3E%3C%2FLI%3E%0A%3CLI%3E%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FMicrosoft%2FLightGBM%2Fissues%2F1369%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3Ehttps%3A%2F%2Fgithub.com%2FMicrosoft%2FLightGBM%2Fissues%2F1369%3C%2FA%3E%3C%2FLI%3E%0A%3C%2FUL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-TEASER%20id%3D%22lingo-teaser-765366%22%20slang%3D%22en-US%22%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%3CSTRONG%3EDeploying%20Azure%20Machine%20Learning%20service%20models%20for%20inference%20with%20Azure%20Functions%3C%2FSTRONG%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20style%3D%22width%3A%20999px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F123904iF95067FC1B60422E%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20alt%3D%22Figure%200.png%22%20title%3D%22Figure%200.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CH1%20id%3D%22toc-hId-1304705759%22%3EWhy%20customers%20want%20Azure%20Functions%20integrated%20with%20Azure%20ML%20Service%3F%3C%2FH1%3E%0A%3COL%3E%0A%3CLI%3EThere%20is%20no%20need%20to%20have%20pre-provisioned%20resources%20such%20as%20clusters%3C%2FLI%3E%0A%3CLI%3ELeverage%20event%20driven%20programming%20with%20several%20built-in%20triggers%20%E2%80%93%20for%20example%2C%20when%20the%20payload%20is%20uploaded%20to%20Storage%2C%20automatically%20trigger%20the%20Azure%20Function%20to%20score%20the%20payload%20using%20the%20AML%20model.%3C%2FLI%3E%0A%3CLI%3EThere%20is%20no%20need%20to%20remember%20URLs%20or%20IP%20addresses%20to%20make%20POST%20requests.%3C%2FLI%3E%0A%3C%2FOL%3E%3C%2FLINGO-TEASER%3E%3CLINGO-LABS%20id%3D%22lingo-labs-765366%22%20slang%3D%22en-US%22%3E%3CLINGO-LABEL%3Eazure%20ml%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3EAzureAI%3C%2FLINGO-LABEL%3E%3C%2FLINGO-LABS%3E
Microsoft

This article shows how to deploy an Azure Machine Learning service (AML) generated model to an Azure Function. Right now, AML supports a variety of choices to deploy models for inferencing – GPUs, FPGA, IoT Edge, custom Docker images.  Customers have provided feedback to support – an event-driven serverless compute platform that can also solve complex orchestration problems – as a model deployment endpoint within Azure Machine Learning service, and our AI platform engineering team is looking into this feedback to make it a seamless experience.

In the meantime, this blog post will walk you through the set of steps to manually download the model file and package it as part of Azure Functions for inferencing . This article uses Python code to build an E2E ML model and Azure functions. The data and model are from the Forecast Energy Demand tutorial

Why customers want Azure Functions integrated with Azure ML Service?

  1. There is no need to have pre-provisioned resources such as clusters
  2. Leverage event driven programming with several built-in triggers – for example, when the payload is uploaded to Storage, automatically trigger the Azure Function to score the payload using the AML model.
  3. There is no need to remember URLs or IP addresses to make POST requests.

Things to keep in mind

  1. When using Azure Functions without the consumption plan, there may be impact due to ‘cold start’ scenarios. This blog explains this behavior.
  2. Machine learning models may be large and include several library dependencies. When inferencing (scoring), the machine learning model must be deserialized and then applied against the payload which may lead to higher performance latencies when coupled with ‘cold start’ scenarios.
  3. At this time, Azure Functions only supports python dependencies that can be installed via pip install. If the model has other complex dependencies, then this may not be viable.
  4. Azure Functions python support recently went GA.

Implementation

Here are the set of steps :

  1. Picking the model file that needs to be hosted in Azure Functions
  2. Building the Azure Functions scaffolding, testing and deploying to Azure.

 

 

Step 1: Picking a model

Picking the right model with the right features and setting up the correct parameters takes a lot of time and effort. Fortunately, Azure Automated ML makes this easy.

To try this, I am using the model that was built using automated ML and is part of the Forecasting Energy Demand tutorial at https://github.com/Azure/MachineLearningNotebooks/tree/master/how-to-use-azureml/automated-machine-l....

After completing the training of the model, automated ML provides the right ‘fitted model’.

Figure 1.png

Add these commands to download the pickle file from the notebook.

 

import pickle
pickle.dump(fitted_model, open( "forecastmodel.p", "wb" ))

 

And now in the folder, I can see this pickle file:

Figure 2.png

This file can now be downloaded to the local dev machine where the next set of steps will be carried out.

The local dev machine has docker, Azure Functions developer tools (npm install -g azure-functions-core-tools), and installed in it.

Step 2: Building the Azure Functions scaffolding and testing

If you follow this article, this explains how to develop an Azure function using Python.

In my dev machine, I have a folder ‘blog’ where requirements.txt contains the various python packages required by the Function App.

requirements.txt

azure-functions==1.0.0b3
azure-functions-worker==1.0.0b3
grpcio==1.14.2
grpcio-tools==1.14.2
protobuf==3.6.1
six==1.12.0
numpy
azureml-sdk
sklearn

Inside this folder, I have a folder ‘HttpTrigger’ and have created the following files:

  • main.py
  • function.json

main.py

import azure.functions as func
import logging
import pickle
import sys
import os
import pathlib
import numpy as np
import azureml.train.automl
import pandas as pd


def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')
    clientId = req.params.get('clientId')
    logging.info('**********Processing********')
    if not clientId:
        try:
            req_body = req.get_json()
        except ValueError:
            pass
        else:
            clientId = req_body.get('clientId')
    # load the model
    f = open(pathlib.Path(__file__).parent/'forecastmodel.pkl', 'rb')
    model = pickle.load(f)
    if clientId:
        logging.info(clientId)
        data = {'timeStamp':['2017-02-01 02:00:00','2017-02-01 03:00:00'],'precip':[0.0,0.0],'temp':[33.61,32.30]}
        test = pd.DataFrame(data,columns=['timeStamp', 'precip', 'temp'])
        logging.info(test.timeStamp + ' ' + str(test.precip) + ' ' + str(test.temp))
        y_pred = model.predict(test)
        logging.info(y_pred)
        return func.HttpResponse(str(y_pred))
    else:
        return func.HttpResponse(
             "Please pass the correct parameters on query strint or in the request body",   status_code=400
            )

The code uses ‘2017-02-01’ since the demand forecast tutorial includes the dataset from that year.

function.json

{
  "scriptFile": "main.py",
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
  ]
}

 

Testing the function locally

You’ll need to set up the virtual python environment. For instructions, see this article .

python3.6 -m venv .functionenv
source .functionenv/bin/activate

And then install the required packages:

 pip install -r requirements.txt

 

From the ‘blog’ folder, launch the Azure Functions local runtime to start locally:

func host start

 

The Azure Function should start locally and provide the complete URL of the HttpTrigger API.  You should see similar output to what appears below.

Figure 3.png

To test the function, from another shell do a curl command and you should get the output which is a prediction.

Figure 4.png

The output is the array [4600.9586368  4642.14414377] which is the demand prediction for the parameters passed in from ‘main.py’

 

data = {'timeStamp':['2017-02-01 02:00:00','2017-02-01 03:00:00'],'precip':[0.0,0.0],'temp':[33.61,32.30]}

 

 

So the complete details are as follows:

timestamp

Precip

Temp

Demand

2017-02-01 02:00:00

0.0

33.61

4600.9586368 

2017-02-01 03:00:00

0.0

32.30

4642.14414377

 

You can modify main.py and get new prediction values.

The shell where the function was started will also show the logging and other details

Figure 5.png

 

 You can deploy this as an Azure Functions using the instructions from this tutorial. Remember to use ‘--build-native-deps’ parameter and now a docker image will be created and operationalized within Azure Functions.

I created an app service plan and a function app name within it

az appservice plan create --resource-group <rg name>  --name <name> --subscription <subscription id> --is-linux
az functionapp create --resource-group <> --os-type Linux --plan <plan name> --runtime python --name <function app name> --storage-account <storage account name> --subscription <subscripton id>
func azure functionapp publish <function app name> --build-native-deps

 

At this point, you have taken the Demand Forecasting model and operationalized it as part of Azure Functions, thus taking a Serverless pattern approach for inferencing of the model.

In a subsequent blog, we will show how to use this custom docker image within Azure Machine Learning and the advantages of leveraging the AML registry and using MLOps for operationalizing the code.

Useful Links