TensorStore برای ذخیره سازی آرایه با کارایی بالا و مقیاس پذیر


بسیاری از برنامه های کاربردی هیجان انگیز معاصر علوم کامپیوتر و یادگیری ماشین (ML) مجموعه داده های چند بعدی را دستکاری می کنند که یک سیستم مختصات بزرگ را در بر می گیرد، به عنوان مثال، مدل سازی آب و هوا از اندازه گیری های جوی روی یک شبکه فضایی یا پیش بینی های تصویربرداری پزشکی از مقادیر شدت تصویر چند کاناله در یک 2 بعدی. یا اسکن سه بعدی در این تنظیمات، حتی یک مجموعه داده واحد ممکن است به ترابایت یا پتابایت ذخیره داده نیاز داشته باشد. کار با چنین مجموعه‌های داده نیز چالش برانگیز است زیرا کاربران ممکن است داده‌ها را در فواصل نامنظم و مقیاس‌های متفاوت بخوانند و بنویسند، و اغلب علاقه‌مند به انجام تحلیل‌ها با استفاده از ماشین‌های متعددی هستند که به صورت موازی کار می‌کنند.

امروز ما TensorStore را معرفی می کنیم، یک کتابخانه نرم افزاری منبع باز C++ و Python که برای ذخیره سازی و دستکاری اطلاعات طراحی شده است. n-داده های ابعادی که:

  • یک API یکنواخت برای خواندن و نوشتن فرمت های آرایه های متعدد از جمله zarr و N5 ارائه می دهد.
  • به طور بومی از چندین سیستم ذخیره سازی، از جمله Google Cloud Storage، سیستم های فایل محلی و شبکه، سرورهای HTTP و ذخیره سازی در حافظه پشتیبانی می کند.
  • پشتیبانی از حافظه پنهان خواندن/نوشتن و تراکنش ها، با ضمانت های اتمی قوی، ایزوله، ثبات و دوام (ACID).
  • از دسترسی ایمن و کارآمد از چندین فرآیند و ماشین از طریق همزمانی خوش بینانه پشتیبانی می کند.
  • یک API ناهمزمان را ارائه می دهد تا دسترسی با توان بالا را حتی به ذخیره سازی راه دور با تأخیر بالا امکان پذیر کند.
  • عملیات نمایه سازی پیشرفته و کاملاً قابل ترکیب و نماهای مجازی را ارائه می دهد.

TensorStore قبلاً برای حل چالش‌های مهندسی کلیدی در محاسبات علمی (مثلاً مدیریت و پردازش مجموعه‌های داده بزرگ در علوم اعصاب، مانند داده‌های میکروسکوپ الکترونی سه بعدی در مقیاس پتا و ویدیوهای “4 بعدی” از فعالیت عصبی) استفاده شده است. TensorStore همچنین در ایجاد مدل‌های یادگیری ماشینی در مقیاس بزرگ مانند PaLM با پرداختن به مشکل مدیریت پارامترهای مدل (نقاط بازرسی) در طول آموزش توزیع‌شده استفاده شده است.

API آشنا برای دسترسی و دستکاری داده ها
TensorStore یک API ساده پایتون برای بارگذاری و دستکاری داده های آرایه بزرگ ارائه می دهد. در مثال زیر، یک شی TensorStore ایجاد می کنیم که یک تصویر 56 تریلیون وکسل 3 بعدی از مغز مگس را نشان می دهد و به یک پچ کوچک 100×100 از داده ها به عنوان یک آرایه NumPy دسترسی داریم:

>>> import tensorstore as ts
>>> import numpy as np

# Create a TensorStore object to work with fly brain data.
>>> dataset = ts.open({
...     'driver':
...         'neuroglancer_precomputed',
...     'kvstore':
...         'gs://neuroglancer-janelia-flyem-hemibrain/v1.1/segmentation/',
... }).result()

# Create a 3-d view (remove singleton 'channel' dimension):
>>> dataset_3d = dataset[ts.d['channel'][0]]
>>> dataset_3d.domain
{ "x": [0, 34432), "y": [0, 39552), "z": [0, 41408) }

# Convert a 100x100x1 slice of the data to a numpy ndarray
>>> slice = np.array(dataset_3d[15000:15100, 15000:15100, 20000])

مهمتر از همه، تا زمانی که قطعه 100×100 خاص درخواست نشود، هیچ داده واقعی در حافظه قابل دسترسی یا ذخیره نمی شود. از این رو، مجموعه داده‌های زیربنایی خودسرانه بزرگ را می‌توان بدون نیاز به ذخیره کل مجموعه داده در حافظه، بارگیری و دستکاری کرد، با استفاده از نحو نمایه‌سازی و دستکاری که تا حد زیادی با عملیات استاندارد NumPy یکسان است. TensorStore همچنین پشتیبانی گسترده‌ای از ویژگی‌های نمایه‌سازی پیشرفته، از جمله تبدیل، تراز، پخش، و نماهای مجازی (تبدیل نوع داده، نمونه‌برداری پایین، آرایه‌های تولید شده به‌صورت تنبلی در لحظه) ارائه می‌کند.

مثال زیر نشان می‌دهد که چگونه TensorStore می‌تواند برای ایجاد یک آرایه zarr استفاده شود، و چگونه API ناهمزمان آن، توان عملیاتی بالاتری را فعال می‌کند:

>>> import tensorstore as ts
>>> import numpy as np

>>> # Create a zarr array on the local filesystem
>>> dataset = ts.open({
...     'driver': 'zarr',
...     'kvstore': 'file:///tmp/my_dataset/',
... },
... dtype=ts.uint32,
... chunk_layout=ts.ChunkLayout(chunk_shape=[256, 256, 1]),
... create=True,
... shape=[5000, 6000, 7000]).result()

>>> # Create two numpy arrays with example data to write.
>>> a = np.arange(100*200*300, dtype=np.uint32).reshape((100, 200, 300))
>>> b = np.arange(200*300*400, dtype=np.uint32).reshape((200, 300, 400))

>>> # Initiate two asynchronous writes, to be performed concurrently.
>>> future_a = dataset[1000:1100, 2000:2200, 3000:3300].write(a)
>>> future_b = dataset[3000:3200, 4000:4300, 5000:5400].write(b)

>>> # Wait for the asynchronous writes to complete
>>> future_a.result()
>>> future_b.result()

مقیاس بندی ایمن و عملکردی
پردازش و تجزیه و تحلیل مجموعه داده های عددی بزرگ به منابع محاسباتی قابل توجهی نیاز دارد. این امر معمولاً از طریق موازی سازی در میان هسته های متعدد CPU یا شتاب دهنده که در بسیاری از ماشین ها پخش شده اند به دست می آید. بنابراین یک هدف اساسی TensorStore فعال کردن پردازش موازی مجموعه داده‌های فردی است که هم ایمن باشد (یعنی از فساد یا تناقضات ناشی از الگوهای دسترسی موازی جلوگیری می‌کند) و هم کارایی بالا (یعنی خواندن و نوشتن در TensorStore در طول محاسبه یک گلوگاه نیست). . در واقع، در آزمایشی در مراکز داده گوگل، با افزایش تعداد CPU ها، مقیاس تقریباً خطی عملکرد خواندن و نوشتن را دریافتیم:

عملکرد خواندن و نوشتن برای مجموعه داده TensorStore در قالب zarr موجود در Google Cloud Storage (GCS) که به طور همزمان با استفاده از تعداد متغیری از وظایف محاسباتی تک هسته‌ای در مراکز داده Google قابل دسترسی است. هر دو مقیاس عملکرد خواندن و نوشتن تقریباً خطی با تعداد وظایف محاسباتی هستند.

عملکرد با پیاده سازی عملیات اصلی در C++، استفاده گسترده از چند رشته ای برای عملیاتی مانند رمزگذاری/رمزگشایی و I/O شبکه، و تقسیم مجموعه داده های بزرگ به واحدهای بسیار کوچکتر از طریق تقسیم بندی به منظور امکان خواندن و نوشتن کارآمد زیر مجموعه های کل مجموعه داده به دست می آید. TensorStore همچنین قابلیت تنظیم حافظه پنهان (که تعاملات سیستم ذخیره سازی کندتر را برای داده هایی که اغلب به آنها دسترسی دارند کاهش می دهد) و یک API ناهمزمان را فراهم می کند که عملیات خواندن یا نوشتن را در پس زمینه ادامه می دهد در حالی که یک برنامه کارهای دیگر را تکمیل می کند.

ایمنی عملیات موازی زمانی که بسیاری از ماشین‌ها به یک مجموعه داده دسترسی دارند، از طریق استفاده از همزمانی خوش‌بینانه به دست می‌آید، که سازگاری با لایه‌های ذخیره‌سازی زیربنایی متنوع (از جمله پلت‌فرم‌های ذخیره‌سازی ابری، مانند GCS، و همچنین سیستم‌های فایل محلی) را بدون تأثیر قابل‌توجهی بر عملکرد حفظ می‌کند. TensorStore همچنین تضمین های قوی ACID را برای تمام عملیات های فردی که در یک زمان اجرا اجرا می شوند ارائه می دهد.

برای اینکه محاسبات توزیع شده با TensorStore با بسیاری از گردش‌های کاری پردازش داده‌های موجود سازگار باشد، TensorStore را با کتابخانه‌های محاسباتی موازی مانند Apache Beam (کد مثال) و Dask (کد مثال) ادغام کرده‌ایم.

مورد استفاده: مدل‌های زبان
یکی از پیشرفت‌های هیجان‌انگیز اخیر در ML، ظهور مدل‌های زبانی پیشرفته‌تر مانند PaLM است. این شبکه های عصبی حاوی صدها میلیارد پارامتر هستند و قابلیت های شگفت انگیزی را در درک و تولید زبان طبیعی از خود نشان می دهند. این مدل ها همچنین محدودیت های زیرساخت محاسباتی را افزایش می دهند. به طور خاص، آموزش یک مدل زبان مانند PaLM به هزاران TPU نیاز دارد که به طور موازی کار کنند.

یکی از چالش‌هایی که در طول این فرآیند آموزشی مطرح می‌شود، خواندن و نوشتن موثر پارامترهای مدل است. آموزش در بسیاری از ماشین‌های مجزا توزیع می‌شود، اما پارامترها باید به طور منظم در یک شی واحد (“نقطه بازرسی”) در یک سیستم ذخیره‌سازی دائمی ذخیره شوند بدون اینکه روند کلی آموزش کاهش یابد. مشاغل آموزشی فردی همچنین باید بتوانند فقط مجموعه خاصی از پارامترهای مورد نظر خود را بخوانند تا از سرباری که برای بارگیری کل مجموعه پارامترهای مدل (که می تواند صدها گیگابایت باشد) اجتناب شود.

قبلاً از TensorStore برای رسیدگی به این چالش ها استفاده شده است. این برای مدیریت نقاط بازرسی مرتبط با مدل‌های مقیاس بزرگ (“چند پاد”) آموزش دیده با JAX (نمونه کد) استفاده شده است و با چارچوب‌هایی مانند T5X (نمونه کد) و Pathways ادغام شده است. موازی سازی مدل برای پارتیشن بندی مجموعه کامل پارامترها، که می تواند بیش از یک ترابایت حافظه را در صدها TPU اشغال کند، استفاده می شود. چک پوینت ها در قالب zarr با استفاده از TensorStore ذخیره می شوند، با یک ساختار تکه ای انتخاب شده که اجازه می دهد پارتیشن برای هر TPU به طور مستقل به صورت موازی خوانده و نوشته شود.

هنگام ذخیره یک چک پوینت، هر پارامتر مدل با استفاده از TensorStore در قالب zarr با استفاده از یک شبکه تکه ای نوشته می شود که شبکه مورد استفاده برای پارتیشن بندی پارامتر را روی TPU ها بیشتر تقسیم می کند. ماشین های میزبان به طور موازی تکه های zarr را برای هر یک از پارتیشن های اختصاص داده شده به TPU های متصل به آن میزبان می نویسند. با استفاده از API ناهمزمان TensorStore، آموزش ادامه می‌یابد حتی زمانی که داده‌ها هنوز در ذخیره‌سازی دائمی نوشته می‌شوند. هنگام شروع مجدد از یک چک پوینت، هر میزبان فقط تکه هایی را می خواند که پارتیشن های اختصاص داده شده به آن میزبان را تشکیل می دهند.

مورد استفاده: نقشه برداری مغز سه بعدی
هدف زمینه کانکتومیک با وضوح سیناپس ترسیم سیم کشی مغز حیوانات و انسان در سطح دقیق اتصالات سیناپسی فردی است. این امر مستلزم تصویربرداری از مغز با وضوح بسیار بالا (نانومتر) در میدان‌های دید تا میلی‌متر یا بیشتر است که مجموعه‌ای از داده‌هایی را به دست می‌دهد که می‌توانند در اندازه پتابایت باشند. در آینده این مجموعه داده ها ممکن است تا اگزابایت ها گسترش یابد، زیرا دانشمندان نقشه برداری از کل مغز موش یا پستانداران را در نظر دارند. با این حال، حتی مجموعه داده های فعلی چالش های مهمی را در رابطه با ذخیره سازی، دستکاری و پردازش ایجاد می کنند. به طور خاص، حتی یک نمونه مغز ممکن است به میلیون ها گیگابایت با یک سیستم مختصات (فضای پیکسل) صدها هزار پیکسل در هر بعد نیاز داشته باشد.

ما از TensorStore برای حل چالش‌های محاسباتی مرتبط با مجموعه داده‌های اتصال در مقیاس بزرگ استفاده کرده‌ایم. به طور خاص، TensorStore برخی از بزرگترین و گسترده‌ترین مجموعه داده‌های کانکتومیک را با Google Cloud Storage به عنوان سیستم ذخیره‌سازی اشیاء زیربنایی مدیریت کرده است. به عنوان مثال، آن را بر روی مجموعه داده “h01” قشر انسان اعمال شده است، که یک تصویر سه بعدی با وضوح نانومتری از بافت مغز انسان است. داده های تصویربرداری خام 1.4 پتابایت است (تقریباً 500000 * 350000 * 5000 پیکسل بزرگ، و بیشتر با محتوای اضافی مانند بخش بندی های سه بعدی و حاشیه نویسی که در همان سیستم مختصات قرار دارند مرتبط است. داده های خام به تکه های تک تک تک تک تکه های بزرگ 1218x18x و 1216x تقسیم می شوند. در قالب “Neuroglancer precomputed” ذخیره شده است، که برای مشاهده تعاملی مبتنی بر وب بهینه شده است و می توان آن را به راحتی از TensorStore دستکاری کرد.

شروع شدن
برای شروع استفاده از TensorStore Python API، می توانید بسته tensortore PyPI را با استفاده از:

pip install tensorstore

برای جزئیات استفاده به آموزش ها و مستندات API مراجعه کنید. برای سایر گزینه های نصب و استفاده از C++ API، به دستورالعمل های نصب مراجعه کنید.

سپاسگزاریها
با تشکر از تیم بلیکلی، ویرن جین، یاش کاتاریا، یان-متیس لاکمن، میکال یانوشفسکی، پیتر لی، آدام رابرتز، برین ویلیامز و هکتور یی از Google Research، و دیویس بنت، استوارت برگ، اریک پرلمن، استیون پلازا و خوان Nunez-Iglesias از جامعه علمی گسترده تر برای بازخورد ارزشمند در مورد طراحی، آزمایش اولیه و اشکال زدایی.