3 .at@sddlZddlZddlmZddlmZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl Z ddlZddlmZddlmZddlZddlZddlZddlZGdddeZdS)N)yaspin)Spinners)MultiDataModel)Modelc@seZdZd(dd Zd d Zd d ZddZddZddZddZ ddZ ddZ ddZ ddZ ddZd d!Zd)d$d%Zd&d'ZdS)*DeployNFTdcCsddddg|_dgdgddgdgd|_||_||_||_||_| |_| |_||_| |_ ||_ d|_ ||_ t jd d }i|_t|d d 4}tj|}x"|D]}t|d |j|d<qWWdQRX|jdkrd|_d|_n|jt|jjksd|jkrz|jdkrzd|jkrD|jdkr6d|_d|_|jdkn d|_d|_n4|jjdd dd&krld|_d|_n d|_d|_ntdt|jjdt|tkr|g|_d|_nTt|tkr||_d|_n8|dkrtdd}WdQRXdg|_d|_ntd|d'ddkr&td|dn||_|j}t|$}tj|j }dd|j!D}WdQRXd |krd!|krtd"|| dkrt"j#j$|_#n| |_#|dkrt%j&j'|_(n@t|tkr||_(|j)dkrtd#ntd$tt|| dkr|j#j*|_+n| |_+||_,|dkrJ||jkrJ||_-|j||_,n|dkrh||jkrhtd%||_.||_|j/dS)(N tensorflowpytorchmxnetsklearnZtorchZgluon)r r r rF ezsmdeployz data/cost.csvr)moder rTlocal local_gpu.pgz!Please choose an instance type inz, or choose local for local testing. Don't pass in any instance or pass in None if you want to automatically choose an instance type.tmpmodelwzmodel must be a single serialized file (like 'model.pkl') or a list of files ([model.pkl, model2.pkl]). If you are downloading a model in the script or packaging with the container, pass in model = Nonepyz9please provide a valid python script with .py extension. z is invalidcSsg|]}t|tjr|jqS) isinstanceastZ FunctionDefname).0nrrQ/home/ec2-user/SageMaker/easy-amazon-sagemaker-deployments/ezsmdeploy/__init__.py sz#Deploy.__init__..Z load_modelZpredictzplease implement a load_model(modelpath) that returns a loaded model, and predict(inputdata) function that returns a prediction in yourzplease enter a name with lower case letters; we will be using this name for s3 bucket prefixes, model names, ECR repository names etc. that have various restrictionszKenter string for a name or don't pass in a name; type of name passed in is zIf requirements=None, please provide a value for framework; choice should be one of 'tensorflow','pytorch','mxnet','sklearn')rr)0Z frameworklistZframeworkinstallswaitbudgetinstance_count instance_typeimagedockerfilepatheiprefixmonitordeployedautoscaletarget pkg_resourcesresource_filenamecostdictopencsvreaderfloatgpu multimodellistkeyssplit ValueErrortypestrmodelscriptrZparsereadZbody sagemakersessionZSession shortuuidZuuidlowerrislowerZdefault_bucketbucket requirements framework autoscaledeploy)selfr>r?rHrGrrIr.r$rFr+rBr(r)r'r&r%r*r,Zcostpathinfiler4rowsfpfilenamefileZnodeZ functionsrrr!__init__s    $              zDeploy.__init__cCs@i|_|jdkrtjdd}t|ddz}tj|}xh|D]`}t|ddt|d|j|d|j|dt|ddt|df|j|d<q:WWdQRX|j n|jt |jj ks|jdkr&|jdkr|j|j|_ |j dkr$d d d d ddd}|j ||j |_ nd|_ ntdt |jj ddS)Nrzdata/instancetypes.csvr)rrr rrrgQ?gQ?g(\?gp= ף?gp= ף?gp= ף?)zml.eia2.mediumz ml.eia2.largezml.eia2.xlargez ml.eia.mediumz ml.eia.largez ml.eia.xlargez!Please choose an instance type inz$, or choose local for local testing.)rr)rr) instancedictr'r/r0r2r3r4r5r1choose_instance_typer8r9 costperhourr*r;)rKZinstancetypepathrLr4rMZeicostsrrr!process_instance_types8    D     zDeploy.process_instance_typec CsJ|jdkrd|jd}n|jd|jd}|j|j|}tjdd|_d}d}x|t|jj D]j}|j|d}|j|d }|j|d }|j d kr||kr||kr|}|}qb||krb||j krb|}PqbW|dko|j d krt d t |j d t |dn*|dkr2|j d kr2t dt |d||_ |j|j |_dS)Nrzezsmdeploy/model-/z/ezsmdeploy/model-rzdata/instancetypes.csvirr rr z9Could not find an instance that satisfies your budget of z8 per hour and can host your models with a total size of z, Gb. Please choose a higher budget per hour.z3You may be using large models with a total size of z` Gb. Please choose a high memory GPU instance and launch without multiple models (if applicable))r+rget_sizerFr/r0Zinstancetypespathr8rRr9r%r;r=r'r1rT) rKtmppathsizeZchoseninstanceZmincostinstanceZ memperworkerZcostZ costpermemrrr!rSs6   "zDeploy.choose_instance_typecCs|jj||dS)N)sagemakermodel add_model)rKZs3pathZ relativepathrrr!r\AszDeploy.add_modelcCs|js2td|j|jd|jtjtjjd|_ ndt d|jdj |jdj ddd d|jtjtjjd|_ x|jD]}|j |dq|Wd|_dS) Nzmodel-r)rZ model_data image_urirole predictor_clsrVr )rZmodel_data_prefixr]r^r_zserving/F)r7rr modelpathr(rAZget_execution_role predictorZ Predictorr[rjoinr:r\r*)rKpathrrr! create_modelDs   zDeploy.create_modelc Cs|jrPddlm}tdkr,dj|j|j}ndj|j|j|j}|dd|d}nd}|jj|j |j |j d |jd |j |d |_ d |j|_dS) Nr)DataCaptureConfigrz's3://{}/ezsmdeploy/model-{}/datacapturez*s3://{}/{}/ezsmdeploy/model-{}/datacaptureTr )Zenable_captureZsampling_percentageZdestination_s3_urizezsmdeploy-endpoint-F)Zinitial_instance_countr'Zaccelerator_type endpoint_nameZupdate_endpointr$data_capture_config)r,Zsagemaker.model_monitorrfr+formatrFrr[rJr&r'r*r$rbrg)rKrfZtmps3urirhrrr! deploy_modelas*   zDeploy.deploy_modelcCsBtjd}|j|}d}x |jj|dD]}||j}q(W|dS)Ns3g)ZPrefixg@gA)boto3ZresourceZBucketZobjectsfilterrY)rKrFrdrkZ my_bucketZ total_sizeobjrrr!rWs   zDeploy.get_sizecCshd}|jdkrd}n |jd}g|_x>|jD]4}|jj|jjdj||j||jd|d7}q,WdS)Nr rzezsmdeploy/model-z/ezsmdeploy/model-zmodel{}.tar.gz)rdrF key_prefix) r+rar>appendrBZ upload_datarirFr)rKirXrrrr! upload_models   zDeploy.upload_modelc Cs^d}xR|jD]F}d|krd|kr|jjdj||jdddj|jddddtjtjd j|d }|j d j|WdQRXd j|}ntd|kod|kr|j d j|t j |d j|tjtjd j|d }|j d j|WdQRXd j|}tjdj|d}d|kr<|j |ddn |j ||j|d7}qWdS)Nr ztar.gzrkz./downloads/{}rVrrl)rdrFrpz./downloads/{}/*.tar.gzrz./extractedmodel/{}/zextractedmodel/{}/z./downloads/{}/zmodel{}.tar.gzzw:gzr)Zarcname)r>rBZ download_datarir:rctarfiler2globZ extractall makedir_safeshutilcopyaddclose)rKrrrZtarrrr! tar_models4     zDeploy.tar_modelcCstytj|Wn YnXytjj|s4tj|Wn8tk rn}z|jdkr^t|jWYdd}~XnXdS)N) rwrmtreeosrdexistsmakedirsOSErrorerrnoprint)rKZ directoryerrrrr!rvs   zDeploy.makedir_safecCs|jdt|jtkrBtjj|jr6tj|jdq|jdnDt|jt kr~t dd}t dd|j}|j ||j ntddS)Nsrczsrc/requirements.txtz does not exist!rcSs|dS)N r)xrrr!sz,Deploy.handle_requirements..zUpass in a path/to/requirements.txt or a list of requirements ['scikit-learn',...,...])rvr<rGr=r~rdrrwrxr8r2map writelinesrzr;)rKfl1rrr!handle_requirementss     zDeploy.handle_requirementsc Csd}tdd}tj|j|j|dd}WdQRXtjdjjdd}tjd jjdd}d j|||j|_ xtj j d st j d qvWd |_dS)Nz=chmod +x src/build-docker.sh & sudo ./src/build-docker.sh {}zsrc/dockeroutput.txtrT)stdoutshellz9aws sts get-caller-identity --query Account --output textrrzaws configure get regionz/{}.dkr.ecr.{}.amazonaws.com/ezsmdeploy-image-{}z src/done.txtrlzPlease see src/dockeroutput.txt)r2 subprocessPopenrirr~popenr@r:r(rdrtimesleepZ dockeroutput)rKcmdrrZacctZregionrrr! build_dockers " zDeploy.build_dockerc Cstjdj|jd}|d}|ddd}tjd}|jddj||d d d d }|jd j|jddj||d d|jddiddddd}||_ dS)NrA) EndpointNamerZProductionVariantsrZ VariantNamezapplication-autoscalingzendpoint/{}/variant/{}z&sagemaker:variant:DesiredInstanceCountr )ServiceNamespace ResourceIdScalableDimensionZ MinCapacityZ MaxCapacityzscaling-policy-{}ZTargetTrackingScalingZPredefinedMetricTypeZ&SageMakerVariantInvocationsPerInstanceiXF)Z TargetValueZPredefinedMetricSpecificationZScaleOutCooldownZScaleInCooldownZDisableScaleIn)Z PolicyNamerrrZ PolicyTypeZ(TargetTrackingScalingPolicyConfiguration) rmclientZdescribe_endpointrgZregister_scalable_targetriZput_scaling_policyrr.Zscalingresponse)rKZresponseZin1Zin2rrrr!autoscale_endpoints.       zDeploy.autoscale_endpointrc Cst|jr|dkrtd|jrhtjdd}tj|dtjj}t t j ddd}|j |j ttjj|d|j|jrtd d } tj|jd d | WdQRXn*td d } tj|jdd | WdQRXtj|td ddj|||} tj| } xtjjds$tjdqWtjd|j |j ttjj|d|jWdQRXntddS)NzXsince this is a multimodel endpoint, please pass in a target model that you wish to testrzdata/smlocust.pyzsrc/smlocust.pygreenr)colortextz | Starting test with Locustzsrc/locustdata.txtrz model1.tar.gz)rg target_modelzsrc/testdata.pwbzklocust -f src/smlocust.py --no-web -c {} -r {} --run-time {}s --csv=src/locuststats; touch src/testdone.txtzsrc/testdone.txtrlz9 | Done! Please see the src folder for locuststats* filesz-Deploy model to endpoint first before testing)r7r;r-r/r0rwrxdatetimenowrrpointhidewriter=showr2jsondumprgpicklerir~systemrdrrrremove) rKZ input_datarZ usercountZ hatchrateZ timeoutsecspath1startspZoutfilerrrrr!test,sH         z Deploy.testc Cstjj}ttjddd}ytjdWn YnX|j|j|j dgkrt|j t tjj|dn|j t tjj|d|j |j |j|j|j t tjj|d|j |jdkrt tjj|d }|jd n|jt tjj|d }|j|j ||j tj|jd |j|j t tjj|d |j |jdkr|jdkrtjdd|_n&|jdkr|jdkrtjdd|_tj|jd|j|j t tjj|d|j |jrTtjdd}tjdd}tjdd}tj|dtj|dtj|dd|_ntjdd}tjdd}tjdd}tjdd}tjdd}tjdd} tj|d tj|d!tj|d"tj|d#tj|d$tj| d|jr*|jdkr*d|_|j|j t tjj|d%|j |j|j t tjj|d&|j |jdkr|j t tjj|d'|j|j|j t tjj|d(|j |j|j|j t tjj|d)|j|j |j|j|j t tjj|d*|j |jrj|jd7krj|j |j|j t tjj|d-|j n@|jr|jd8kr|j|j t tjj|d.|j |jd9kr|j|j t tjj|d/t |j!d0|j |j"r4|j|j t tjj|d1d2j#|j$|j%|j |j&j't tjj|d3d|_(y6t)j*d4t)j*d t)j*d5t)j*d6t)j*dWn YnX|j+SQRXdS):Nrr)rrzsrc/rz^ | No model was passed. Assuming you are downloading a model in the script or in the containerz | compressed model(s)z7 | uploaded model tarball(s) ; check returned modelpathz# | no additional requirements foundrz | added requirements filezsrc/transformscript.pyz | added source fileTrzdata/DockerfileFzdata/Dockerfile_flaskzsrc/Dockerfilez | added Dockerfilezdata/model_handler.pyzdata/dockerd-entrypoint.pyzdata/build-docker.shzsrc/model_handler.pyzsrc/dockerd-entrypoint.pyzsrc/build-docker.shzdata/nginx.confzdata/predictor.pyz data/servez data/trainz data/wsgi.pyzsrc/nginx.confzsrc/predictor.pyz src/servez src/trainz src/wsgi.pyzZ | Setting Elastic Inference to None since you selected a GPU instancez' | added model_handler and docker utilsz | building docker containerz | built docker containerz& | created model(s). Now deploying on z | deployed modelrrz | set up autoscalingz0 | not setting up autoscaling; deploying locallyz | estimated cost is $z per hourz* | model monitor data capture location is z's3://{}/ezsmdeploy/model-{}/datacaptureu | Done! ✔z src/done.txtZ downloadsZextractedmodel)rr)rr)rr),rrrrrrwr}r{rr>rr=rrsrUrGrvrrxr?r)r7r/r0r*r6r(rrer'rjrIrrTr,rirFrrokr-r~rrb) rKrrZrtextrZpath2Zpath3Zpath4Zpath5Zpath6rrr!rJjs                         &    z Deploy.deploy)NNNFrTNrNNNNr r NF)Nrrr)__name__ __module__ __qualname__rQrUrSr\rerjrWrsr{rvrrrrrJrrrr!rs> &2<# (% =r)rArCrZyaspin.spinnersrrrrtrermrur~rwr/rZsagemaker.multidatamodelrZsagemaker.modelrrr3rrobjectrrrrr!s(