В RAPIDS 22.06 появилась новая поддержка массивных графов и расширена поддержка алгоритмов Multi-Node Multi-GPU.
Мы рады объявить о выпуске RAPIDS 22.06. Независимо от того, работаете ли вы в среде с одним или несколькими графическими процессорами, этот выпуск предлагает вам новые функции и дополнительные способы ускорения ваших рабочих нагрузок в области обработки данных.
Основные обновления версии RAPIDS 22.06 включают:
- Выпуск новой библиотеки RAPIDS Graph-as-a-Service
- Добавление алгоритмов Multi-Node Multi-GPU (MNMG) во многие библиотеки, включая cuML и cuGraph.
- Поддержка интерактивной отладки и профилирования использования памяти с помощью RMM.
Также были внесены большие обновления в библиотеки cuSpatial и cuCIM, и команда RAPIDS продолжает вносить множество скрытых изменений для оптимизации кода и настраивает нас на успех, поскольку мы продолжаем расширять функциональные возможности RAPIDS.
Выпуск Graph-as-a-Service
Существует множество случаев, когда совместная обработка графа и аналитика на одном и том же графическом процессоре могут быть проблематичными, особенно по мере того, как размер графа увеличивается и используется все больше ограниченного пространства памяти графического процессора. Например, рассмотрите возможность обучения графовой нейронной сети с использованием DGL или PyG, где граф состоит из десятков или сотен миллиардов ребер и требует для обработки 32 или более графических процессоров. Совместное использование графических процессоров и процессов обучения может привести к конфликту ресурсов. Бывают также ситуации, когда имеется один граф и несколько распределенных аналитических клиентов. Рассмотрим хранилище данных, где график представляет исторические данные, размещенные на тысяче графических процессоров, и набор аналитиков, каждый из которых исследует разные части графика, но аналитику достаточно одного рабочего стола с одним графическим процессором. Graph-as-a-Service или GaaS — это наше решение проблемы.
RAPIDS GaaS — это облегченная оболочка для RAPIDS cuGraph, которая обеспечивает доступ к графическим функциям через RPC API. Это позволяет выполнять обработку графиков на отдельном оборудовании от анализа. GaaS использует cuGraph, cuDF и другие библиотеки на сервере для выполнения подготовки и анализа графических данных на серверных графических процессорах. Несколько клиентов могут подключаться к серверу, предоставляя различным пользователям и процессам возможность доступа к большим графическим данным, что иначе было бы невозможно с использованием ресурсов клиента.
Поддержка масштабирования
При работе с огромными объемами данных нередко не хватает места на одном графическом процессоре. Мы продолжаем расширять поддержку рабочих нагрузок Multi-Node Multi-GPU (MNMG) в библиотеках RAPIDS.
Логистическая регрессия MNMG в cuML
В этом выпуске cuML добавляет экспериментальную поддержку многоузловой логистической регрессии на основе Dask-GLM и поддержку массива Dask CuPy. В этом первом выпуске основное внимание уделяется добавлению поддержки обработки данных, намного превышающих размер одного графического процессора.
Добавить необходимые компоненты в среду RAPIDS можно, выполнив следующие команды:
mamba install -c conda-forge sckit-learn pip install "sparse>=0.7.0" "multipledispatch>=0.4.9" --no-deps pip install "git+https://github.com/dask/dask-glm@main" --force-reinstall --no-deps
Затем код имеет знакомый, основанный на Scikit, API обычной логистической регрессии:
from dask.distributed import Client, wait from dask_cuda import LocalCUDACluster cluster = LocalCUDACluster(threads_per_worker=1) client = Client(cluster) n_total_partitions = len(list(client.has_what().keys())) from cuml.dask.extended.linear_model.logistic_regression import LogisticRegression from cuml.dask.datasets import make_classification distX, distY = make_classification(1000000, 10, n_parts = n_total_partitions) logreg = LogisticRegression(fit_intercept=True, max_iter=50) logreg.fit(distX, distY)
В будущих версиях будут удалены необязательные шаги компонентов и основное внимание будет уделено оптимизации потребления памяти и времени выполнения.
Больше алгоритмов Multi Node Multi GPU в cuGraph
В RAPIDS 22.04 команда cuGraph выпустила первую реализацию Property Graph, позволяющую моделировать разнообразные сети и отслеживать метаданные и зависимости между узлами. В выпуске 22.06 вы теперь можете использовать Property Graph в архитектурах MNMG, поддерживая вариант использования, моделирующий большие графовые сети. В приведенном ниже фрагменте кода показано, как создать граф свойств, добавить и выбрать вершины и ребра, а также извлечь подграф с помощью cuGraph.
pG = cugraph.experimental.PropertyGraph() pG.add_vertex_data(customers_df, type_name = "customers", vertex_col_name="Cust_ID") pG.add_edge_data(purchases_df, type_name="purchases", vertex_col_names=("Cust_ID", "Store_num")) selection = pG.select_vertices(f"{pG.type_col_name==}=='stores'") selection += pG.select_edges(f"{pG.type_col_name}=='merch_xfers'") G = pG.extract_subgraph(selection=selection, edge_weight_property="Amount")
И поддержка MNMG в cuGraph на этом не заканчивается — вы также можете использовать как алгоритм центральности собственного вектора, так и алгоритм подсчета треугольников для данных, расположенных на нескольких графических процессорах.
Полная поддержка Dask DataFrames в cuXfilter
Экосистема RAPIDS продолжает расширять поддержку и интеграцию с Dask, позволяя легко масштабироваться между ядрами и машинами при работе с большими наборами данных. Начиная с RAPIDS 22.06, cuXfilter более легко интегрируется с Dask, что позволяет вам использовать dask_cudf.DataFrame
в качестве прямой замены cudf.DataFrame
в ваших больших визуализациях cuXfilter.
Рисунок 1. Показывает визуализацию cuXfilter графика с 300 миллионами узлов и 10 миллионами ребер. dask_cudf.DataFrame
будет работать для более крупных и сложных графиков и диаграмм рассеяния.
Также было внесено множество обновлений в блокноты с примерами cuXfilter, поэтому, если вы хотите изучить возможности библиотеки и опробовать новую dask_cudf
совместимость, загляните в эти блокноты и попробуйте сами!
Повышение эффективности (и как за этим следить!)
Во всех библиотеках RAPIDS мы продолжаем ускорять работу вашего кода, и теперь можно интерактивно профилировать ваш код, чтобы лучше понять, как используется память.
Эффективные сложные выражения DataFrame с помощью cudf.DataFrame.eval
Если вы когда-либо оценивали сложные выражения в больших пандах DataFrames, возможно, вы использовали DataFrame.eval
для ускорения этих вычислений. Теперь вы также можете воспользоваться этими преимуществами с помощью cuDF. cudf.DataFrame.eval
никогда не выделяет память для промежуточных звеньев, что делает его быстрее и эффективнее, чем наивная альтернатива. Например, df.eval('a+b+c')
никогда не создает столбец df['a']+df['b']
, который получился бы в результате записи df['a']+df['b']+df['c']
. Для сложных выражений прирост производительности может быть значительным, а сокращение использования памяти может иметь решающее значение в рабочих процессах с ограниченными ресурсами.
Интерактивная отладка и профилирование с помощью RAPIDS Memory Manager
Распределение памяти в RAPIDS выполняется менеджером памяти RAPIDS (RMM). В выпуске RMM 22.06 пользователи теперь могут запускать функцию обратного вызова, когда библиотеки RAPIDS выделяют или освобождают память для интерактивной отладки, профилирования и множества других вариантов использования.
Это поддерживается с помощью нового класса, называемого ресурсом памяти обратного вызова, и может использоваться с любым другим ресурсом памяти и парой функций обратного вызова, которые запускаются при выделении или освобождении памяти графического процессора. Ресурс памяти обратного вызова может быть создан на C++ или Python и назначен в качестве ресурса памяти текущего устройства. Обратите внимание, что накладные расходы функций обратного вызова allocate/deallocate значительны и должны использоваться только для отладки использования памяти или когда производительность не имеет решающего значения.
Функция allocate принимает размер и возвращает указатель на выделенную память. Функция освобождения принимает указатель и размер и возвращает None (или void в C++).
Ниже мы покажем, как обратный вызов может использовать модуль ведения журнала Python:
import rmm import logging # Log at INFO level logging.basicConfig( format='%(levelname)s:%(message)s',level=logging.INFO) # Using a CudaMemoryResource as the backing MR, # define allocation and deallocation functions that # print the amount of memory being (de)allocated. base_mr = rmm.mr.CudaMemoryResource() def allocate(size): logging.info(f"Allocating {size} bytes") return base_mr.allocate(size) def deallocate(ptr, size): logging.info(f"Deallocating {size} bytes") base_mr.deallocate(ptr, size) # Create a CallbackMemoryResource and set it to be # the default memory resource used by RMM: mr = rmm.mr.CallbackMemoryResource(allocate, deallocate) rmm.mr.set_current_device_resource(mr)
После установки текущего ресурса устройства все операции выделения (освобождения) памяти RAPIDS будут вызывать обратные вызовы. Например, создание cuDF DataFrame покажет, сколько памяти выделено:
>>> import cudf >>> s = cudf.Series([0, 1, 2]) INFO:Allocating 24 bytes >>> del s INFO:Deallocating 24 bytes
Новые функции в библиотеках
В этом выпуске было много новых дополнений к библиотекам RAPIDS, и ниже мы выделяем некоторые из cuDF, cuSpatial и cuCIM.
cuDF
Мы продолжаем расширять функциональность DataFrame. В этом выпуске вы теперь можете использовать метод DataFrame.applymap
для применения поэлементной функции к DataFrame. Метод сопоставляет скалярный элемент DataFrame с другим скалярным элементом DataFrame и может обрабатывать пустые значения внутри DataFrame, как показано в примере ниже:
>>> df = cudf.DataFrame({"a":[0.01, None, 1, 10], "b":[0.12, 1.2, 12.3, None]}) >>> df a b 0 0.01 0.12 1 <NA> 1.2 2 1.0 12.3 3 10.0 <NA> >>> df.applymap(lambda x: 42 if x is cudf.NA else x-1) >>> df a b 0 -0.99 -0.88 1 42.00 0.20 2 0.00 11.30 3 9.00 42.00
cuSpatial
Огромные объемы данных о местоположении записываются каждую секунду с широкого спектра датчиков, в том числе с мобильных телефонов, транспортных средств и камер. Традиционно обработка этих полных наборов данных была невозможна из-за их размера и вычислительной сложности, необходимой для преобразования данных.
Библиотека cuSpatial предоставляет набор функций для ускорения общих операций, необходимых для обработки и понимания данных серии географической информации (ГИС) с датчиков. А в RAPIDS 22.06 cuSpatial представляет новую функцию под названием pairwise_linestring_distance
для вычисления кратчайших расстояний между линиями.
На рис. 2 показано, что производительность pairwise_linestring_distance
снижается по мере усложнения строк.
Мы сравнили производительность pairwise_linestring_distance
в cuSpatial с эквивалентной функцией в Shapely на двух реалистичных наборах данных: Транспортный набор данных Калифорнии и TrajAir, набор данных траекторий авиации общего назначения. Как показано в таблице 1, мы увидели значительное ускорение в обоих наборах данных по сравнению с использованием Shapely на ЦП для этих различных наборов данных.
cuCIM
В cuCIM, библиотеке для ускоренной обработки n-мерных изображений и ввода/вывода изображений, в этом выпуске также были добавлены некоторые интересные новые функции.
Во-первых, в версии cuCIM добавлены две новые функции для извлечения пятен и нормализации слайдов цифровой патологии, окрашенных гематоксилином и эозином: cucim.core.operations.color.stain_extraction_pca
и cicim.core.operations.color.normalize_colors_pca
.
Существует также новая функция cicim.skimage.segmentation.clear_border
, которую можно использовать для удаления любых меток, касающихся границы изображения/объема. В следующем коде мы используем эту функцию clear_border
для удаления меток на границе изображения. Полученные изображения показаны на рисунке 3.
import cupy as cp import matplotlib.pyplot as plt import numpy as np from cucim.skimage import (color, data, measure, segmentation) # generate synthetic data (binary blobs) blobs = data.binary_blobs(1024, n_dim=2, blob_size_fraction=0.04, volume_fraction=0.35, seed=5) # Assign unique labels to each blob labels = measure.label(blobs) # discard any blobs that are touching the border labels2 = segmentation.clear_border(labels) # assign randomized RGB colors to each label labels2_rgb = color.label2rgb(labels2) # Determine the area in pixels of each label properties = measure.regionprops_table(labels2, properties=['area']) areas = properties['area'] print(f"areas = {areas}") # Visualize the result with Matplotlib fig, axes = plt.subplots(2, 2, figsize=(8, 8)) fontdict = dict(fontweight='bold', fontsize=16) axes[0][0].imshow(cp.asnumpy(blobs), cmap=plt.cm.gray) axes[0][0].set_title("synthetic blobs", fontdict=fontdict) axes[0][1].imshow(cp.asnumpy(labels), cmap=plt.cm.gray) axes[0][1].set_title("labeled blobs", fontdict=fontdict) axes[1][0].imshow(cp.asnumpy(labels2), cmap=plt.cm.gray) axes[1][0].set_title("trimmed blobs", fontdict=fontdict) axes[1][1].imshow(cp.asnumpy(labels2_rgb)) axes[1][1].set_title("trimmed blobs (RGB)", fontdict=fontdict) for ax in axes.ravel(): ax.set_axis_off() plt.tight_layout() plt.show()
Кроме того, некоторые из существующих функций cuCIM были обновлены для повышения производительности. В частности, обнаружение границ с помощью cucim.skimage.feature.canny должно быть в 3–4 раза быстрее, чем в предыдущем выпуске. Двоичные и полутоновые морфологические операции теперь могут выполняться намного быстрее для больших размеров.
Заключение
Помимо обсуждаемых здесь обновлений, мы работаем над дополнительными улучшениями, чтобы предоставить вам обновленные версии библиотек, новейшие версии зависимых библиотек, улучшить взаимодействие с пользователем и повысить функциональность и надежность всех библиотек RAPIDS. Обязательно ознакомьтесь со всеми подробностями в примечаниях к выпуску.
Мы с нетерпением ждем ваших сообщений о том, как вы используете эти новые возможности RAPIDS. Как всегда, свяжитесь с нами на GitHub, подпишитесь на нас в Twitter и ознакомьтесь с нашей документацией и ресурсами для начала работы.