أفضل الممارسات وأنماط التصميم لبناء مسارات عمل التعلم الآلي باستخدام Amazon SageMaker Pipelines | خدمات ويب أمازون

أفضل الممارسات وأنماط التصميم لبناء مسارات عمل التعلم الآلي باستخدام Amazon SageMaker Pipelines | خدمات ويب أمازون

خطوط أنابيب Amazon SageMaker هي خدمة AWS مُدارة بالكامل لبناء وتنظيم سير عمل التعلم الآلي (ML). توفر SageMaker Pipelines لمطوري تطبيقات تعلم الآلة القدرة على تنسيق خطوات مختلفة لسير عمل تعلم الآلة، بما في ذلك تحميل البيانات، وتحويل البيانات، والتدريب، والضبط، والنشر. يمكنك استخدام SageMaker Pipelines لتنسيق وظائف ML في SageMaker و التكامل مع النظام البيئي الأكبر لـ AWS كما يسمح لك باستخدام الموارد مثل AWS لامدا وظائف، أمازون EMR وظائف، وأكثر من ذلك. يمكّنك هذا من إنشاء مسار مخصص وقابل للتكرار لتلبية متطلبات محددة في سير عمل تعلم الآلة لديك.

في هذا المنشور، نقدم بعض أفضل الممارسات لتعظيم قيمة خطوط أنابيب SageMaker وجعل تجربة التطوير سلسة. نناقش أيضًا بعض سيناريوهات وأنماط التصميم الشائعة عند إنشاء خطوط أنابيب SageMaker ونقدم أمثلة لمعالجتها.

أفضل الممارسات لخطوط أنابيب SageMaker

في هذا القسم، نناقش بعض أفضل الممارسات التي يمكن اتباعها أثناء تصميم سير العمل باستخدام خطوط أنابيب SageMaker. يمكن أن يؤدي اعتمادها إلى تحسين عملية التطوير وتبسيط الإدارة التشغيلية لخطوط أنابيب SageMaker.

استخدم جلسة خط الأنابيب للتحميل البطيء لخط الأنابيب

جلسة خط الأنابيب يتيح التهيئة البطيئة لموارد خط الأنابيب (لا تبدأ المهام حتى وقت تشغيل خط الأنابيب). ال PipelineSession السياق يرث جلسة سيج ميكر وتنفيذ طرق مناسبة للتفاعل مع كيانات وموارد SageMaker الأخرى، مثل وظائف التدريب ونقاط النهاية ومجموعات بيانات الإدخال في خدمة تخزين أمازون البسيطة (أمازون S3)، وما إلى ذلك. عند تحديد خطوط أنابيب SageMaker، يجب عليك استخدام PipelineSession خلال جلسة SageMaker العادية:

from sagemaker.workflow.pipeline_context import PipelineSession
from sagemaker.sklearn.processing import SKLearnProcessor
role = sagemaker.get_execution_role()
pipeline_session = PipelineSession()
sklearn_processor = SKLearnProcessor( framework_version=’0.20.0’, instance_type=’ml.m5.xlarge’, instance_count=1, base_job_name="sklearn-abalone-process", role=role, sagemaker_session=pipeline_session,
)

قم بتشغيل خطوط الأنابيب في الوضع المحلي لإجراء تكرارات سريعة وفعالة من حيث التكلفة أثناء التطوير

يمكنك تشغيل ملف خط الأنابيب في الوضع المحلي يستخدم ال LocalPipelineSession سياق. في هذا الوضع، يتم تشغيل المسار والوظائف محليًا باستخدام الموارد الموجودة على الجهاز المحلي، بدلاً من موارد SageMaker المُدارة. يوفر الوضع المحلي طريقة فعالة من حيث التكلفة للتكرار على رمز خط الأنابيب مع مجموعة فرعية أصغر من البيانات. بعد اختبار خط الأنابيب محليًا، يمكن توسيع نطاقه للتشغيل باستخدام جلسة خط الأنابيب سياق الكلام.

from sagemaker.sklearn.processing import SKLearnProcessor
from sagemaker.workflow.pipeline_context import LocalPipelineSession
local_pipeline_session = LocalPipelineSession()
role = sagemaker.get_execution_role()
sklearn_processor = SKLearnProcessor( framework_version=’0.20.0’, instance_type=’ml.m5.xlarge, instance_count=1, base_job_name="sklearn-abalone-process", role=role, sagemaker_session=local_pipeline_session,
)

إدارة مسار SageMaker من خلال الإصدار

يعد إصدار العناصر وتعريفات خطوط الأنابيب متطلبًا شائعًا في دورة حياة التطوير. يمكنك إنشاء إصدارات متعددة من خط الأنابيب عن طريق تسمية كائنات خط الأنابيب ببادئة أو لاحقة فريدة، وأكثرها شيوعًا هو الطابع الزمني، كما هو موضح في التعليمة البرمجية التالية:

from sagemaker.workflow.pipeline_context import PipelineSession
import time current_time = time.strftime("%Y-%m-%d-%H-%M-%S", time.gmtime())
pipeline_name = "pipeline_" + current_time
pipeline_session = PipelineSession()
pipeline = Pipeline( name=pipeline_name, steps=[step_process, step_train, step_eval, step_cond], sagemaker_session=pipeline_session,
)

تنظيم وتتبع عمليات تشغيل خط أنابيب SageMaker من خلال التكامل مع تجارب SageMaker

يمكن دمج خطوط أنابيب SageMaker بسهولة مع تجارب SageMaker للتنظيم و تتبع تشغيل خط الأنابيب. يتم تحقيق ذلك عن طريق تحديد تكوين تجربة خط الأنابيب في وقت إنشاء أ كائن خط الأنابيب. باستخدام كائن التكوين هذا، يمكنك تحديد اسم التجربة واسم التجربة. يتم تنظيم تفاصيل تشغيل خط أنابيب SageMaker ضمن التجربة والتجربة المحددة. إذا لم تحدد اسم التجربة بشكل صريح، فسيتم استخدام اسم المسار لاسم التجربة. وبالمثل، إذا لم تحدد اسمًا تجريبيًا بشكل صريح، فسيتم استخدام معرف تشغيل المسار لاسم المجموعة التجريبية أو التشغيل. انظر الكود التالي:

Pipeline( name="MyPipeline", parameters=[...], pipeline_experiment_config=PipelineExperimentConfig( experiment_name = ExecutionVariables.PIPELINE_NAME, trial_name = ExecutionVariables.PIPELINE_EXECUTION_ID ), steps=[...]
)

قم بتشغيل مسارات SageMaker بشكل آمن داخل VPC خاص

لتأمين أحمال عمل تعلم الآلة، من أفضل الممارسات نشر المهام التي تنظمها SageMaker Pipelines في تكوين شبكة آمن داخل VPC خاص وشبكات فرعية خاصة ومجموعات أمان. لضمان استخدام هذه البيئة الآمنة وفرضه، يمكنك تنفيذ ما يلي إدارة الهوية والوصول AWS (IAM) سياسة دور تنفيذ SageMaker (وهذا هو الدور الذي يلعبه خط الأنابيب أثناء تشغيله). يمكنك أيضًا إضافة السياسة لتشغيل المهام المُنسقة بواسطة SageMaker Pipelines في وضع عزل الشبكة.

# IAM Policy to enforce execution within a private VPC { "Action": [ "sagemaker:CreateProcessingJob", "sagemaker:CreateTrainingJob", "sagemaker:CreateModel" ], "Resource": "*", "Effect": "Deny", "Condition": { "Null": { "sagemaker:VpcSubnets": "true" } }
} # IAM Policy to enforce execution in network isolation mode
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Deny", "Action": [ "sagemaker:Create*" ], "Resource": "*", "Condition": { "StringNotEqualsIfExists": { "sagemaker:NetworkIsolation": "true" } } } ]
}

للحصول على مثال لتنفيذ المسار مع وجود ضوابط الأمان هذه، راجع تنسيق الوظائف وتسجيل النماذج والنشر المستمر مع Amazon SageMaker في بيئة آمنة.

مراقبة تكلفة تشغيل خطوط الأنابيب باستخدام العلامات

يعد استخدام خطوط أنابيب SageMaker بحد ذاته مجانيًا؛ أنت تدفع مقابل موارد الحوسبة والتخزين التي تقوم بتدويرها كجزء من خطوات التدفق الفردية مثل المعالجة والتدريب والاستدلال الدفعي. لتجميع التكاليف لكل تشغيل خط الأنابيب، يمكنك تضمين علامات في كل خطوة من خطوات خط الأنابيب التي تؤدي إلى إنشاء مورد. يمكن بعد ذلك الرجوع إلى هذه العلامات في مستكشف التكلفة لتصفية إجمالي تكلفة تشغيل المسار وتجميعها، كما هو موضح في المثال التالي:

sklearn_processor = SKLearnProcessor( framework_version=’0.20.0’, instance_type=’ml.m5.xlarge, instance_count=1, base_job_name="sklearn-abalone-process", role=role, tags=[{'Key':'pipeline-cost-tag', 'Value':'<<tag_parameter>>'}]
) step_process = ProcessingStep( name="AbaloneProcess", processor=sklearn_processor, ...
)

من مستكشف التكلفة، يمكنك الآن تصفية التكلفة حسب العلامة:

response = client.get_cost_and_usage( TimePeriod={ 'Start': '2023-07-01', 'End': '2023-07-15' }, Metrics=['BLENDED_COST','USAGE_QUANTITY','UNBLENDED_COST'], Granularity='MONTHLY', Filter={ 'Dimensions': { 'Key':'USAGE_TYPE', 'Values': [ ‘SageMaker:Pipeline’ ] }, 'Tags': { 'Key': 'keyName', 'Values': [ 'keyValue', ] } }
)

أنماط التصميم لبعض السيناريوهات الشائعة

في هذا القسم، نناقش أنماط التصميم لبعض حالات الاستخدام الشائعة مع SageMaker Pipelines.

قم بتشغيل وظيفة Python خفيفة الوزن باستخدام خطوة Lambda

وظائف بايثون موجودة في كل مكان في سير عمل تعلم الآلة؛ يتم استخدامها في المعالجة المسبقة والمعالجة اللاحقة والتقييم والمزيد. Lambda هي خدمة حوسبة بدون خادم تتيح لك تشغيل التعليمات البرمجية دون توفير الخوادم أو إدارتها. باستخدام Lambda، يمكنك تشغيل التعليمات البرمجية بلغتك المفضلة والتي تتضمن Python. يمكنك استخدام هذا لتشغيل كود Python المخصص كجزء من خط الأنابيب الخاص بك. خطوة لامدا يمكّنك من تشغيل وظائف Lambda كجزء من مسار SageMaker الخاص بك. ابدأ بالكود التالي:

%%writefile lambdafunc.py import json def lambda_handler(event, context): str1 = event["str1"] str2 = event["str2"] str3 = str1 + str2 return { "str3": str3 }

قم بإنشاء وظيفة Lambda باستخدام ملف مساعد Lambda الخاص بـ SageMaker Python SDK:

from sagemaker.lambda_helper import Lambda def create_lambda(function_name, script, handler): response = Lambda( function_name=function_name, execution_role_arn=role, script= script, handler=handler, timeout=600, memory_size=10240, ).upsert() function_arn = response['FunctionArn'] return function_arn fn_arn = create_Lambda("func", "lambdafunc.py", handler = "lambdafunc.lambda_handler")

استدعاء خطوة لامدا:

from sagemaker.lambda_helper import Lambda
from sagemaker.workflow.lambda_step import ( LambdaStep, LambdaOutput, LambdaOutputTypeEnum
) str3 = LambdaOutput(output_name="str3", output_type=LambdaOutputTypeEnum.String) # Lambda Step
step_lambda1 = LambdaStep( name="LambdaStep1", lambda_func=Lambda( function_arn=fn_arn ), inputs={ "str1": "Hello", "str2": " World" }, outputs=[str3],
)

تمرير البيانات بين الخطوات

البيانات المدخلة لخطوة المسار هي إما موقع بيانات يمكن الوصول إليه أو بيانات تم إنشاؤها بواسطة إحدى الخطوات السابقة في المسار. يمكنك تقديم هذه المعلومات ك ProcessingInput معامل. دعونا نلقي نظرة على بعض السيناريوهات لكيفية استخدام ProcessingInput.

السيناريو 1: تمرير الإخراج (أنواع البيانات البدائية) لخطوة Lambda إلى خطوة المعالجة

تشير أنواع البيانات البدائية إلى أنواع البيانات العددية مثل السلسلة والعدد الصحيح والمنطقية والعائمة.

يحدد مقتطف التعليمات البرمجية التالي دالة Lambda التي تقوم بإرجاع قاموس المتغيرات مع أنواع البيانات الأولية. سيُرجع رمز دالة Lambda الخاص بك JSON لأزواج قيمة المفتاح عند استدعائها من خطوة Lambda داخل مسار SageMaker.

def handler(event, context): ... return { "output1": "string_value", "output2": 1, "output3": True, "output4": 2.0, }

في تعريف خط الأنابيب، يمكنك بعد ذلك تحديد معلمات خط أنابيب SageMaker التي تنتمي إلى نوع بيانات محدد وتعيين المتغير إلى مخرجات وظيفة Lambda:

from sagemaker.workflow.lambda_step import ( LambdaStep, LambdaOutput, LambdaOutputTypeEnum
)
from sagemaker.workflow.pipeline_context import PipelineSession
from sagemaker.sklearn.processing import SKLearnProcessor role = sagemaker.get_execution_role()
pipeline_session = PipelineSession() # 1. Define the output params of the Lambda Step str_outputParam = LambdaOutput(output_name="output1", output_type=LambdaOutputTypeEnum.String)
int_outputParam = LambdaOutput(output_name"output2", output_type=LambdaOutputTypeEnum.Integer)
bool_outputParam = LambdaOutput(output_name"output3", output_type=LambdaOutputTypeEnum.Boolean)
float_outputParam = LambdaOutput(output_name"output4", output_type=LambdaOutputTypeEnum.Float) # 2. Lambda step invoking the lambda function and returns the Output step_lambda = LambdaStep( name="MyLambdaStep", lambda_func=Lambda( function_arn="arn:aws:lambda:us-west-2:123456789012:function:sagemaker_test_lambda", session=PipelineSession(), ), inputs={"arg1": "foo", "arg2": "foo1"}, outputs=[ str_outputParam, int_outputParam, bool_outputParam, float_outputParam ],
) # 3. Extract the output of the Lambda str_outputParam = step_lambda.properties.Outputs["output1"] # 4. Use it in a subsequent step. For ex. Processing step sklearn_processor = SKLearnProcessor( framework_version="0.23-1", instance_type="ml.m5.xlarge", instance_count=1, sagemaker_session=pipeline_session, role=role
) processor_args = sklearn_processor.run( code="code/preprocess.py", #python script to run arguments=["--input-args", str_outputParam]
) step_process = ProcessingStep( name="processstep1", step_args=processor_args,
)

السيناريو 2: تمرير الإخراج (أنواع البيانات غير البدائية) لخطوة Lambda إلى خطوة المعالجة

تشير أنواع البيانات غير البدائية إلى أنواع البيانات غير العددية (على سبيل المثال، NamedTuple). قد يكون لديك سيناريو عندما يتعين عليك إرجاع نوع بيانات غير بدائي من دالة Lambda. للقيام بذلك، عليك تحويل نوع البيانات غير البدائية إلى سلسلة:

# Lambda function code returning a non primitive data type from collections import namedtuple def lambda_handler(event, context): Outputs = namedtuple("Outputs", "sample_output") named_tuple = Outputs( [ {'output1': 1, 'output2': 2}, {'output3': 'foo', 'output4': 'foo1'} ] )
return{ "named_tuple_string": str(named_tuple)
}

#Pipeline step that uses the Lambda output as a “Parameter Input” output_ref = step_lambda.properties.Outputs["named_tuple_string"]

ثم يمكنك استخدام هذه السلسلة كمدخل لخطوة لاحقة في المسار. لاستخدام الصف المسمى في الكود، استخدم eval() لتحليل تعبير بايثون في السلسلة:

# Decipher the string in your processing logic code import argparse
from collections import namedtuple Outputs = namedtuple("Outputs", "sample_output") if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--named_tuple_string", type=str, required=True) args = parser.parse_args() #use eval to obtain the named tuple from the string named_tuple = eval(args.named_tuple_string)

السيناريو 3: تمرير إخراج الخطوة من خلال ملف خاصية

يمكنك أيضًا تخزين مخرجات خطوة المعالجة في ملف ملف الملكية JSON للاستهلاك المصب في ConditionStep أو آخر ProcessingStep. يمكنك استخدام ال وظيفة JSONGet للاستعلام أ ملف الملكية. انظر الكود التالي:

# 1. Define a Processor with a ProcessingOutput
sklearn_processor = SKLearnProcessor( framework_version="0.23-1", instance_type="ml.m5.xlarge", instance_count=1, base_job_name="sklearn-abalone-preprocess", sagemaker_session=session, role=sagemaker.get_execution_role(),
) step_args = sklearn_processor.run( outputs=[ ProcessingOutput( output_name="hyperparam", source="/opt/ml/processing/evaluation" ), ], code="./local/preprocess.py", arguments=["--input-data", "s3://my-input"],
) # 2. Define a PropertyFile where the output_name matches that with the one used in the Processor

hyperparam_report = PropertyFile( name="AbaloneHyperparamReport", output_name="hyperparam", path="hyperparam.json",
)

لنفترض أن محتويات ملف الخاصية كانت كما يلي:

{ "hyperparam": { "eta": { "value": 0.6 } }
}

في هذه الحالة، يمكن الاستعلام عنها عن قيمة محددة واستخدامها في الخطوات اللاحقة باستخدام الدالة JsonGet:

# 3. Query the property file
eta = JsonGet( step_name=step_process.name, property_file=hyperparam_report, json_path="hyperparam.eta.value",
)

معلمة متغير في تعريف خط الأنابيب

غالبًا ما يكون تحديد معلمات المتغيرات بحيث يمكن استخدامها في وقت التشغيل أمرًا مرغوبًا فيه - على سبيل المثال، لإنشاء معرف URI S3. يمكنك تحديد معلمات سلسلة بحيث يتم تقييمها في وقت التشغيل باستخدام التابع Join وظيفة. يوضح مقتطف التعليمات البرمجية التالي كيفية تعريف المتغير باستخدام Join الوظيفة واستخدمها لتعيين موقع الإخراج في خطوة المعالجة:

# define the variable to store the s3 URI
s3_location = Join( on="/", values=[ "s3:/", ParameterString( name="MyBucket", default_value="" ), "training", ExecutionVariables.PIPELINE_EXECUTION_ID ]
) # define the processing step
sklearn_processor = SKLearnProcessor( framework_version="1.2-1", instance_type="ml.m5.xlarge", instance_count=processing_instance_count, base_job_name=f"{base_job_prefix}/sklearn-abalone-preprocess", sagemaker_session=pipeline_session, role=role,
) # use the s3uri as the output location in processing step
processor_run_args = sklearn_processor.run( outputs=[ ProcessingOutput( output_name="train", source="/opt/ml/processing/train", destination=s3_location, ), ], code="code/preprocess.py"
) step_process = ProcessingStep( name="PreprocessingJob”, step_args=processor_run_args,
)

قم بتشغيل التعليمات البرمجية المتوازية على كائن قابل للتكرار

تقوم بعض مسارات عمل تعلم الآلة بتشغيل التعليمات البرمجية في حلقات متوازية عبر مجموعة ثابتة من العناصر (an متوقعة). يمكن أن يكون إما نفس الكود الذي يتم تشغيله على بيانات مختلفة أو جزء مختلف من الكود الذي يجب تشغيله لكل عنصر. على سبيل المثال، إذا كان لديك عدد كبير جدًا من الصفوف في ملف وتريد تسريع وقت المعالجة، فيمكنك الاعتماد على النمط السابق. إذا كنت تريد إجراء تحويلات مختلفة على مجموعات فرعية محددة في البيانات، فقد يتعين عليك تشغيل جزء مختلف من التعليمات البرمجية لكل مجموعة فرعية في البيانات. يوضح السيناريوهين التاليين كيف يمكنك تصميم مسارات SageMaker لهذا الغرض.

السيناريو 1: تنفيذ منطق المعالجة على أجزاء مختلفة من البيانات

يمكنك تشغيل مهمة معالجة بمثيلات متعددة (عن طريق الإعداد instance_count بقيمة أكبر من 1). يؤدي ذلك إلى توزيع بيانات الإدخال من Amazon S3 على جميع مثيلات المعالجة. يمكنك بعد ذلك استخدام برنامج نصي (process.py) للعمل على جزء معين من البيانات بناءً على رقم المثيل والعنصر المقابل في قائمة العناصر. يمكن كتابة منطق البرمجة فيprocess.py بحيث يتم تشغيل وحدة نمطية مختلفة أو جزء من التعليمات البرمجية اعتمادًا على قائمة العناصر التي تعالجها. يحدد المثال التالي المعالج الذي يمكن استخدامه في ProcessingStep:

sklearn_processor = FrameworkProcessor( estimator_cls=sagemaker.sklearn.estimator.SKLearn, framework_version="0.23-1", instance_type='ml.m5.4xlarge', instance_count=4, #number of parallel executions / instances base_job_name="parallel-step", sagemaker_session=session, role=role,
) step_args = sklearn_processor.run( code='process.py', arguments=[ "--items", list_of_items, #data structure containing a list of items inputs=[ ProcessingInput(source="s3://sagemaker-us-east-1-xxxxxxxxxxxx/abalone/abalone-dataset.csv", destination="/opt/ml/processing/input" ) ], ]
)

السيناريو 2: تشغيل سلسلة من الخطوات

عندما يكون لديك سلسلة من الخطوات التي تحتاج إلى تشغيلها بالتوازي، يمكنك تحديد كل تسلسل كمسار مستقل لـ SageMaker. ويمكن بعد ذلك تشغيل خطوط أنابيب SageMaker هذه من وظيفة Lambda التي تعد جزءًا من ملف LambdaStep في خط الأنابيب الأم. يوضح الجزء التالي من التعليمات البرمجية السيناريو الذي يتم فيه تشغيل مسارين مختلفين لخط أنابيب SageMaker:

import boto3
def lambda_handler(event, context): items = [1, 2] #sagemaker client sm_client = boto3.client("sagemaker") #name of the pipeline that needs to be triggered. #if there are multiple, you can fetch available pipelines using boto3 api #and trigger the appropriate one based on your logic. pipeline_name = 'child-pipeline-1' #trigger pipeline for every item response_ppl = sm_client.start_pipeline_execution( PipelineName=pipeline_name, PipelineExecutionDisplayName=pipeline_name+'-item-%d' %(s), ) pipeline_name = 'child-pipeline-2' response_ppl = sm_client.start_pipeline_execution( PipelineName=pipeline_name, PipelineExecutionDisplayName=pipeline_name+'-item-%d' %(s), )
return

وفي الختام

في هذا المنشور، ناقشنا بعض أفضل الممارسات للاستخدام والصيانة الفعالة لخطوط أنابيب SageMaker. لقد قدمنا ​​أيضًا أنماطًا معينة يمكنك اعتمادها أثناء تصميم مسارات العمل باستخدام SageMaker Pipelines، سواء كنت تقوم بتأليف مسارات جديدة أو تقوم بترحيل مسارات عمل ML من أدوات التنسيق الأخرى. لبدء استخدام SageMaker Pipelines لتنسيق سير عمل ML، راجع عينات التعليمات البرمجية على جيثب و خطوط أنابيب بناء نموذج Amazon SageMaker.


حول المؤلف

أفضل الممارسات وأنماط التصميم لبناء مسارات عمل التعلم الآلي باستخدام Amazon SageMaker Pipelines | أمازون ويب سيرفيسز PlatoBlockchain Data Intelligence. البحث العمودي. منظمة العفو الدولية.بيناك بانيغراهي يعمل مع العملاء لبناء حلول تعتمد على التعلم الآلي لحل مشكلات العمل الإستراتيجية على AWS. عندما لا يكون منشغلًا بالتعلم الآلي، يمكن العثور عليه وهو يقوم بنزهة أو يقرأ كتابًا أو يشاهد الألعاب الرياضية.

أفضل الممارسات وأنماط التصميم لبناء مسارات عمل التعلم الآلي باستخدام Amazon SageMaker Pipelines | أمازون ويب سيرفيسز PlatoBlockchain Data Intelligence. البحث العمودي. منظمة العفو الدولية.ميناكشيسوندارام ثاندافارايان يعمل لدى AWS كأخصائي AI / ML. لديه شغف بتصميم وإنشاء وتعزيز تجارب البيانات والتحليلات التي تركز على الإنسان. تركز Meena على تطوير أنظمة مستدامة توفر مزايا تنافسية قابلة للقياس للعملاء الاستراتيجيين لـ AWS. مينا هو موصل ، ومفكر تصميم ، ويسعى جاهدًا لدفع الأعمال إلى طرق جديدة للعمل من خلال الابتكار ، والاحتضان ، والدمقرطة.

الطابع الزمني:

اكثر من التعلم الآلي من AWS