Data Parallelism با پارامترهای متمرکز
بهجای نگهداری نسخهٔ کامل Parameterها روی تمام GPUها، میتوان Parameterها را بیرون از Workerهای محاسباتی، مثلاً روی CPU یا روی یک یا چند Parameter Server، نگه داشت. Workerها Mini-batchهای خود را پردازش میکنند، Gradient میسازند و برای Update به محل مرکزی میفرستند؛ سپس Parameterهای جدید را دریافت میکنند.
شکل 19-15. Data Parallelism با پارامترهای متمرکز
برخلاف Mirrored Strategy که Updateهای Synchronous دارد، معماری متمرکز میتواند Synchronous یا Asynchronous باشد.
بهروزرسانی همگام و ناهمگام
در Synchronous Update، Aggregator منتظر Gradient تمام Replicaها میماند، میانگین را محاسبه میکند و سپس Optimizer Parameterها را Update میکند. این روش سازگار و پایدار است، اما سرعت کل Step را کندترین Worker تعیین میکند. یک راه کاهش انتظار، استفاده از Spare Replica است؛ برای مثال از ۲۰ Replica فقط Gradient سریعترین ۱۸ Replica در هر Step جمع شود.
در Asynchronous Update هر Replica بهمحض آمادهشدن Gradient آن را روی Parameterها اعمال میکند و منتظر دیگران نمیماند. Throughput بالاتر و فشار همزمان روی Network کمتر است، اما Gradient ممکن است بر اساس Weightهای قدیمی محاسبه شده باشد. چنین Gradientهایی Stale Gradient نام دارند و میتوانند Convergence را کند، نوسانی یا حتی Divergent کنند.
شکل 19-16. بهروزرسانی همگام و ناهمگام
برای کاهش اثر Staleness میتوان Learning Rate را کم کرد، Gradientهای خیلی قدیمی را حذف یا ضعیف کرد، Batch Size را تغییر داد یا چند Epoch اول را با یک Replica بهعنوان Warmup انجام داد. نتایج پژوهشی ذکرشده در کتاب نشان میدهد Synchronous Training با چند Spare Replica در بسیاری از Workloadها هم سریعتر هم پایدارتر بوده است.
اشباع پهنای باند و محدودیت Scale
در Data Parallelism، Parameterها و Gradientها باید پیوسته میان Workerها یا Parameter Serverها منتقل شوند. از نقطهای به بعد، افزودن GPU دیگر Speedup ایجاد نمیکند چون Communication از Compute گرانتر میشود. مدلهای Dense بزرگ بیشترین فشار را ایجاد میکنند، در حالی که مدلهای Sparse بهدلیل Gradientهای کمتراکم بهتر Scale میشوند.
برای کاهش Communication، معماریهایی مانند PipeDream Model Parallelism و Data Parallelism را بهشکل Pipeline ترکیب میکنند. مدل به Stageهای متوالی تقسیم میشود و هر Stage Mini-batchها و Gradientها را از Queue دریافت و به Stage بعد یا قبل ارسال میکند.
شکل 19-17. اشباع پهنای باند و محدودیت Scale
در Pipeline نیز Stale Weight مشکل ایجاد میکند؛ PipeDream با تکنیکی مانند Weight Stashing Weightهای استفادهشده در Forward را نگه میدارد تا Backward همان Mini-batch با همان نسخه انجام شود. کتاب همچنین به Pathways اشاره میکند؛ سامانهای برای Scheduling و Model Parallelism خودکار که در مقیاس هزاران TPU به Utilization بسیار بالا رسیده است.
برای کاهش Bandwidth میتوان از Float16 یا bfloat16 استفاده کرد، GPUهای کمتر ولی قویتر و با Interconnect بهتر انتخاب کرد، و در معماری Parameter Server، Parameterها را بین چند Server Shard کرد.
Distribution Strategies API در TensorFlow
TensorFlow پیچیدگی توزیع Training را پشت API یکپارچهٔ tf.distribute پنهان میکند. برای Train روی چند GPU یک Machine، معمولاً MirroredStrategy بهترین نقطهٔ شروع است. Model و Compile داخل strategy.scope() ساخته میشوند و سپس fit() همانند حالت عادی فراخوانی میشود.
strategy = tf.distribute.MirroredStrategy()
with strategy.scope():
model = tf.keras.Sequential([...])
model.compile([...])
batch_size = 100
model.fit(X_train, y_train, epochs=10,
validation_data=(X_valid, y_valid),
batch_size=batch_size)
Keras Batch را بین Replicaها تقسیم میکند و Variableها به MirroredVariable تبدیل میشوند. بهتر است Batch Size بر تعداد Replicaها بخشپذیر باشد. Prediction نیز میتواند روی Replicaها توزیع شود. اگر Model ذخیره شود، بهصورت Model معمولی ذخیره میشود؛ برای Load و اجرای توزیعشده باید load_model() داخل Scope همان Strategy انجام شود.
with strategy.scope():
model = tf.keras.models.load_model("my_mirrored_model")
میتوان فقط GPUهای مشخص را به MirroredStrategy داد. برای AllReduce، NCCL معمولاً انتخاب سریع است، ولی بسته به Hardware گزینههای Hierarchical Copy یا Reduction to One Device نیز قابل آزمودناند. برای Data Parallelism با Parameterهای مرکزی میتوان از CentralStorageStrategy استفاده کرد.
Training روی TensorFlow Cluster
یک TensorFlow Cluster مجموعهای از Processهای TensorFlow است که معمولاً روی Machineهای مختلف اجرا میشوند و با Network ارتباط دارند. هر Process یک Task است و نقش آن میتواند worker، chief، ps یا evaluator باشد. Worker محاسبه انجام میدهد؛ Chief علاوه بر محاسبه، کارهایی مانند ذخیره Checkpoint و Log را انجام میدهد؛ Parameter Server Variableها را نگه میدارد؛ Evaluator مسئول ارزیابی است.
شکل 19-18. Training روی TensorFlow Cluster
cluster_spec = {
"worker": [
"machine-a.example.com:2222",
"machine-b.example.com:2222"
],
"ps": ["machine-a.example.com:2221"]
}
Firewall باید ارتباط لازم میان Taskها را روی Portهای انتخابشده اجازه دهد. هر Process باید علاوه بر Cluster Spec بداند خودش کدام Task است. TensorFlow معمولاً این اطلاعات را از Environment Variable به نام TF_CONFIG میخواند.
import json, os
os.environ["TF_CONFIG"] = json.dumps({
"cluster": cluster_spec,
"task": {"type": "worker", "index": 0}
})
MultiWorkerMirroredStrategy و Strategyهای Cluster
برای Data Parallelism همگام روی چند Server، MultiWorkerMirroredStrategy Replicaها را میان Workerها Mirror میکند و Gradientها با Collective Operationها Aggregate میشوند. همان Code اصلی Keras باقی میماند؛ تفاوت مهم این است که Dataset و Batch Size باید با تعداد Workerها و Replicaها سازگار طراحی شوند و تمام Workerها اسکریپت Training را اجرا کنند.
برای معماری Parameter Server از ParameterServerStrategy استفاده میشود. این روش به Coordinator نیاز دارد تا Dataset و Functionهای Train را میان Workerها Schedule کند. برای TPUها نیز TPUStrategy وجود دارد. انتخاب Strategy به Hardware، Network، اندازهٔ Model و نیاز به Sync یا Async بستگی دارد.
Training در مقیاس بزرگ روی Vertex AI
Vertex AI میتواند Script Training را روی Machineهای مدیریتشده اجرا کند. یک Custom Job تعریف میشود که Script، Container، Machine Type و Accelerator را مشخص میکند. Cloud منابع را Provision میکند، Logها را جمع میکند و Model نهایی را در مسیر تعیینشده نگه میدارد. Environment Variableهای AIP_* مسیرهای استاندارد Artifact، Checkpoint و Log را در اختیار Script قرار میدهند.
برای اجرای توزیعشده میتوان Replica Count و تعداد GPU هر Worker را مشخص کرد:
mnist_model2 = custom_training_job.run(
machine_type="n1-standard-4",
replica_count=2,
accelerator_type="NVIDIA_TESLA_K80",
accelerator_count=2,
)
پس از پایان، Model برگشتی مانند Modelهای دیگر Vertex AI قابل Deploy روی Endpoint یا قابل استفاده در Batch Prediction است. در صورت خطا، Logهای Job در Console و Cloud Logging قابل مشاهدهاند. TensorBoard نیز میتواند مستقیماً Logهای روی GCS را بخواند.
تنظیم Hyperparameter در Vertex AI
برای تعداد زیاد Hyperparameter، اجرای دستی چند Job بهینه نیست. سرویس Hyperparameter Tuning در Vertex AI از Bayesian Optimization برای انتخاب Trialهای بعدی استفاده میکند. Script Training باید Hyperparameterها را از Command Line دریافت کند.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--n_hidden", type=int, default=2)
parser.add_argument("--n_neurons", type=int, default=256)
parser.add_argument("--learning_rate", type=float, default=1e-2)
parser.add_argument("--optimizer", default="adam")
args = parser.parse_args()
هر اجرای Script با یک مجموعه Parameter یک Trial و مجموعه Trialها یک Study است. Script مدل را با Parameterهای دریافتی میسازد و Train میکند، سپس Metric را با Library hypertune به سرویس گزارش میدهد:
import hypertune
hpt_client = hypertune.HyperTune()
hpt_client.report_hyperparameter_tuning_metric(
hyperparameter_metric_tag="accuracy",
metric_value=max(history.history["val_accuracy"]),
global_step=model.optimizer.iterations.numpy(),
)
سپس یک Custom Job بهعنوان Template هر Trial ساخته میشود و Search Space تعریف میگردد. Learning Rate میتواند Log-scale، تعداد Neuron و Layer عدد صحیح و Optimizer یک Parameter دستهای باشد.
from google.cloud.aiplatform import hyperparameter_tuning as hpt
hp_job = aiplatform.HyperparameterTuningJob(
display_name="my_hp_search_job",
custom_job=trial_job,
metric_spec={"accuracy": "maximize"},
parameter_spec={
"learning_rate": hpt.DoubleParameterSpec(min=1e-3, max=10, scale="log"),
"n_neurons": hpt.IntegerParameterSpec(min=1, max=300, scale="linear"),
"n_hidden": hpt.IntegerParameterSpec(min=1, max=10, scale="linear"),
"optimizer": hpt.CategoricalParameterSpec(["sgd", "adam"]),
},
max_trial_count=100,
parallel_trial_count=20,
)
hp_job.run()
افزایش Trialهای موازی زمان Wall-clock را کم میکند، ولی Trialهای همزمان نمیتوانند از نتیجهٔ یکدیگر برای انتخاب Parameter بعدی استفاده کنند؛ بنابراین Parallelism بسیار زیاد ممکن است Efficiency جستوجوی Bayesian را کاهش دهد. پس از پایان میتوان Resultها را خواند، بهترین Trial را انتخاب کرد و SavedModel آن را برای Production استفاده کرد. Vertex AI همچنین AutoML را ارائه میدهد که انتخاب Architecture و Train را تا حد زیادی خودکار میکند.
Keras Tuner در محیط توزیعشده
راه دیگر استفاده از Keras Tuner روی چند Machine است. یک Machine نقش Chief یا Oracle را دارد و Workerها از آن Hyperparameter بعدی را میگیرند، Model را Train میکنند و Metric را گزارش میدهند. سه Environment Variable اصلی عبارتاند از:
KERASTUNER_TUNER_ID: مقدار chief برای Oracle یا شناسهٔ یکتا مانند worker0.
KERASTUNER_ORACLE_IP: IP یا Hostname ماشین Chief.
KERASTUNER_ORACLE_PORT: Port TCP که Oracle روی آن گوش میدهد.
همین روش را میتوان روی Machineهای Vertex AI نیز اجرا کرد؛ کافی است Script Training متغیرهای Environment را برای نقش هر Machine تنظیم کند.
تمرینهای فصل ۱۹
- توضیح دهید SavedModel چه اطلاعاتی دارد و چگونه محتوای آن را بررسی میکنید.
- موارد مناسب استفاده از TF Serving، قابلیتهای اصلی و روشهای استقرار آن را بیان کنید.
- راه استقرار یک Model روی چند Instance از TF Serving را بررسی کنید.
- مشخص کنید چه زمانی gRPC نسبت به REST برای Query کردن TF Serving مناسبتر است.
- روشهای TFLite برای کاهش اندازهٔ Model روی Mobile و Embedded Device را توضیح دهید.
- Quantization-Aware Training چیست و چه زمانی به آن نیاز داریم؟
- Model Parallelism و Data Parallelism را مقایسه کنید و دلیل رایجبودن Data Parallelism را توضیح دهید.
- Strategyهای قابل استفاده برای Train روی چند Server را بررسی و معیار انتخاب آنها را بیان کنید.
- یک Model را Train و در TF Serving یا Vertex AI Deploy کنید، Client REST یا gRPC بنویسید، نسخهٔ جدید را Deploy و سپس Rollback کنید.
- یک Model را روی چند GPU با MirroredStrategy و سپس CentralStorageStrategy Train و زمانها را مقایسه کنید.
- یک Model را با Keras Tuner یا Hyperparameter Tuning سرویس Vertex AI Fine-tune کنید.
سخن پایانی کتاب
نویسنده در پایان از خواننده تشکر میکند و تأکید دارد که بهترین راه ادامهٔ مسیر، تمرین مداوم است: حل Exerciseها، کار با Notebookها، حضور در Communityهای یادگیری ماشین، مطالعهٔ Paperها و داشتن یک Project واقعی. حوزهٔ ML با سرعت زیادی تغییر میکند، بنابراین دنبالکردن منابع فنی و ساخت تدریجی یک محصول واقعی کمک میکند دانش نظری به مهارت عملی تبدیل شود.
توصیهٔ پایانی این است که بهجای تلاش برای ساخت یک سامانهٔ عظیم از همان ابتدا، Project را مرحلهبهمرحله توسعه دهید. صبر و استمرار در نهایت به ساخت چیزی مانند Robot، Chatbot یا هر کاربرد مفید دیگری منجر میشود. امید نهایی نویسنده این است که دانش این کتاب به ساخت یک کاربرد ارزشمند یادگیری ماشین که برای دیگران نیز سودمند باشد منتهی شود.