torch.sparse
Создано: 26 апр. 2017 | Последнее обновление: 12 мая 2026
Предупреждение
API PyTorch для разреженных тензоров находится в стадии бета-тестирования и в ближайшем будущем может измениться. Мы будем рады запросам на новые функции, сообщениям об ошибках и общим предложениям в виде задач на GitHub.
Зачем и когда использовать разреженность
По умолчанию PyTorch хранит элементы torch.Tensor последовательно в физической памяти. Это позволяет эффективно реализовывать различные алгоритмы обработки массивов, которым нужен быстрый доступ к элементам.
Некоторые пользователи могут решить представлять такие данные, как матрицы смежности графов, прореженные веса или облака точек, с помощью тензоров, большинство элементов которых равны нулю. Мы понимаем, что это важные сценарии применения, и стремимся обеспечить оптимизацию производительности для них с помощью форматов разреженного хранения.
За прошедшие годы были разработаны различные форматы разреженного хранения, такие как COO, CSR/CSC, полуструктурированный формат, LIL и другие. Хотя точные схемы хранения различаются, все они сжимают данные за счёт эффективного представления элементов, равных нулю. Несжатые значения мы называем заданными, в отличие от незаданных сжатых элементов.
Сжимая повторяющиеся нули, форматы разреженного хранения позволяют экономить память и вычислительные ресурсы на различных CPU и GPU. Это может существенно повысить производительность, особенно при высокой степени разреженности или строго структурированной разреженности. Таким образом, форматы разреженного хранения можно рассматривать как способ оптимизации производительности.
Как и многие другие способы оптимизации производительности, форматы разреженного хранения не всегда дают преимущество. При проверке разреженных форматов в своём сценарии использования вы можете обнаружить, что время выполнения увеличилось, а не уменьшилось.
Если вы теоретически ожидали значительного прироста производительности, но вместо этого измерили её снижение, пожалуйста, создайте задачу на GitHub. Это поможет нам расставить приоритеты при реализации эффективных ядер и более широких оптимизаций производительности.
Мы упрощаем проверку различных схем разреженности и преобразование между ними, не навязывая мнение о том, какая из них лучше подходит для вашего приложения.
Обзор функциональности
Мы стремимся упростить создание разреженного тензора из заданного плотного тензора, предоставляя функции преобразования для каждой схемы хранения.
В следующем примере мы преобразуем двумерный тензор с плотной схемой хранения по умолчанию (strided) в двумерный тензор со схемой хранения COO. В этом случае сохраняются только значения и индексы ненулевых элементов.
>>> a = torch.tensor([[0, 2.], [3, 0]])
>>> a.to_sparse()
tensor(indices=tensor([[0, 1],
[1, 0]]),
values=tensor([2., 3.]),
size=(2, 2), nnz=2, layout=torch.sparse_coo)
В настоящее время PyTorch поддерживает COO, CSR, CSC, BSR и BSC.
У нас также есть прототип реализации поддержки полуструктурированной разреженности. Дополнительные сведения см. в справочной документации.
Обратите внимание, что мы предоставляем несколько обобщённых вариантов этих форматов.
Пакетная обработка: для оптимальной производительности таким устройствам, как GPU, необходима пакетная обработка, поэтому мы поддерживаем пакетные измерения.
Сейчас мы предлагаем очень простой вариант пакетной обработки, в котором каждый компонент самого разреженного формата обрабатывается пакетно. При этом для каждой записи пакета требуется одинаковое число заданных элементов. В этом примере мы создаём трёхмерный (пакетный) тензор CSR из трёхмерного плотного тензора.
>>> t = torch.tensor([[[1., 0], [2., 3.]], [[4., 0], [5., 6.]]])
>>> t.dim()
3
>>> t.to_sparse_csr()
tensor(crow_indices=tensor([[0, 1, 3],
[0, 1, 3]]),
col_indices=tensor([[0, 0, 1],
[0, 0, 1]]),
values=tensor([[1., 2., 3.],
[4., 5., 6.]]), size=(2, 2, 2), nnz=3,
layout=torch.sparse_csr)
Плотные измерения: с другой стороны, некоторые данные, например эмбеддинги графов, лучше представлять в виде разреженных наборов векторов, а не скаляров.
В этом примере мы создаём трёхмерный гибридный тензор COO с двумя разреженными и одним плотным измерением из трёхмерного тензора со схемой хранения strided. Если вся строка в трёхмерном тензоре со схемой хранения strided состоит из нулей, она не сохраняется. Однако если хотя бы одно значение в строке ненулевое, сохраняется вся строка. Это уменьшает количество индексов, поскольку для каждой строки нужен один индекс, а не отдельный индекс для каждого элемента. Но при этом увеличивается объём памяти, занимаемый значениями. Можно пропустить только строки, полностью состоящие из нулей: наличие хотя бы одного ненулевого значения приводит к сохранению всей строки.
>>> t = torch.tensor([[[0., 0], [1., 2.]], [[0., 0], [3., 4.]]])
>>> t.to_sparse(sparse_dim=2)
tensor(indices=tensor([[0, 1],
[1, 1]]),
values=tensor([[1., 2.],
[3., 4.]]),
size=(2, 2, 2), nnz=2, layout=torch.sparse_coo)
Обзор операторов
В целом операции над тензорами с форматами разреженного хранения работают так же, как операции над тензорами с форматом хранения strided (или другими форматами). Особенности хранения, то есть физическое расположение данных, влияют на производительность операции, но не должны влиять на её семантику.
Мы активно расширяем набор поддерживаемых операторов для разреженных тензоров. Пока пользователям не следует ожидать такого же уровня поддержки, как для плотных тензоров. Список операторов приведён в документации по операторам.
>>> b = torch.tensor([[0, 0, 1, 2, 3, 0], [4, 5, 0, 6, 0, 0]])
>>> b_s = b.to_sparse_csr()
>>> b_s.cos()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: unsupported tensor layout: SparseCsr
>>> b_s.sin()
tensor(crow_indices=tensor([0, 3, 6]),
col_indices=tensor([2, 3, 4, 0, 1, 3]),
values=tensor([ 0.8415, 0.9093, 0.1411, -0.7568, -0.9589, -0.2794]),
size=(2, 6), nnz=6, layout=torch.sparse_csr)
Как показано в примере выше, мы не поддерживаем унарные операторы, не сохраняющие нули, например cos. Результат унарной операции, не сохраняющей нули, не сможет в той же степени, что и входные данные, использовать преимущества форматов разреженного хранения, что потенциально может привести к катастрофическому увеличению объёма памяти. Вместо этого мы полагаемся на то, что пользователь сначала явно преобразует тензор в плотный, а затем выполнит операцию.
>>> b_s.to_dense().cos()
tensor([[ 1.0000, -0.4161],
[-0.9900, 1.0000]])
Мы знаем, что некоторые пользователи хотят игнорировать сжатые нули при таких операциях, как cos, вместо того чтобы сохранять точную семантику операции. В этом случае можно воспользоваться torch.masked и его MaskedTensor, который также основан на форматах разреженного хранения и соответствующих ядрах.
Также обратите внимание, что пока пользователь не может выбрать схему хранения выходных данных. Например, сложение разреженного тензора с обычным тензором со схемой хранения strided даёт тензор со схемой хранения strided. Некоторые пользователи могут предпочесть, чтобы результат оставался разреженным, поскольку они знают, что он всё ещё будет достаточно разреженным.
>>> a + b.to_sparse()
tensor([[0., 3.],
[3., 0.]])
Мы признаём, что доступ к ядрам, способным эффективно создавать выходные данные с различными схемами хранения, может быть очень полезен. Следующая операция может значительно выиграть от получения данных с определённой схемой хранения. Мы работаем над API для управления схемой хранения результата и понимаем, что эта важная функция позволит планировать более оптимальный путь выполнения для любой заданной модели.
Полуструктурированные разреженные тензоры
Предупреждение
Полуструктурированные разреженные тензоры пока являются экспериментальной функцией и могут измениться. Пожалуйста, создайте задачу, если обнаружите ошибку или захотите поделиться отзывом.
Полуструктурированная разреженность — это схема хранения разреженных данных, впервые представленная в архитектуре NVIDIA Ampere. Её также называют мелкозернистой структурированной разреженностью или структурированной разреженностью 2:4.
При использовании этой схемы хранения среди каждых 2n элементов сохраняются n элементов, а значение n определяется шириной типа данных тензора (dtype). Чаще всего используется тип данных float16, для которого n=2, отсюда и название «структурированная разреженность 2:4».
Более подробное объяснение полуструктурированной разреженности приведено в этой публикации в блоге NVIDIA.
В PyTorch полуструктурированная разреженность реализована с помощью подкласса Tensor. Создав подкласс, мы можем переопределить __torch_dispatch__, чтобы использовать более быстрые разреженные ядра при умножении матриц. Мы также можем хранить тензор в сжатом виде внутри подкласса, чтобы уменьшить накладные расходы на память.
В сжатом виде разреженный тензор хранится с сохранением только заданных элементов и некоторых метаданных, кодирующих маску.
Примечание
Заданные элементы и маска метаданных полуструктурированного разреженного тензора хранятся вместе в одном плоском сжатом тензоре. Они объединяются, образуя непрерывный участок памяти.
сжатый тензор = [ заданные элементы исходного тензора | маска метаданных ]
Для исходного тензора размера (r, c) мы ожидаем, что первые m * k // 2 элементов будут сохранёнными элементами, а оставшаяся часть тензора будет содержать метаданные.
Чтобы пользователю было проще просматривать заданные элементы и маску, можно использовать .indices() и .values() для доступа к маске и заданным элементам соответственно.
-
.values()возвращает заданные элементы в тензоре размера(r, c//2)с тем же типом данных, что и у плотной матрицы. -
.indices()возвращает маску метаданных в тензоре размера(r, c//2 )с типом элементовtorch.int16, если dtype — torch.float16 или torch.bfloat16, и типом элементовtorch.int32, если dtype — torch.int8.
Для разреженных тензоров 2:4 накладные расходы на метаданные незначительны — всего 2 бита на заданный элемент.
Примечание
Важно отметить, что torch.float32 поддерживается только для разреженности 1:2. Поэтому для него не действует та же формула, что приведена выше.
Ниже мы разберём, как вычислить коэффициент сжатия (размер плотного тензора / размер разреженного тензора) для разреженного тензора 2:4.
Пусть (r, c) = tensor.shape и e = bitwidth(tensor.dtype), тогда e = 16 для torch.float16 и torch.bfloat16, а также e = 8 для torch.int8.
Используя эти вычисления, мы можем определить общий объём памяти для исходного плотного и нового разреженного представления.
Это даёт простую формулу коэффициента сжатия, который зависит только от разрядности типа данных тензора.
Согласно этой формуле, коэффициент сжатия составляет 56,25% для torch.float16 или torch.bfloat16 и 62,5% для torch.int8.
Создание полуструктурированных разреженных тензоров
Преобразовать плотный тензор в полуструктурированный разреженный тензор можно просто с помощью функции torch.to_sparse_semi_structured.
Обратите внимание, что мы поддерживаем только тензоры CUDA, поскольку аппаратная поддержка полуструктурированной разреженности ограничена GPU NVIDIA.
Для полуструктурированной разреженности поддерживаются следующие типы данных. Обратите внимание, что для каждого типа данных действуют собственные ограничения на форму и коэффициент сжатия.
Тип данных PyTorch | Ограничения на форму | Коэффициент сжатия | Шаблон разреженности |
|---|---|---|---|
| Тензор должен быть двумерным, а значения (r, c) должны быть положительными числами, кратными 64 | 9/16 | 2:4 |
| Тензор должен быть двумерным, а значения (r, c) должны быть положительными числами, кратными 64 | 9/16 | 2:4 |
| Тензор должен быть двумерным, а значения (r, c) должны быть положительными числами, кратными 128 | 10/16 | 2:4 |
Чтобы создать полуструктурированный разреженный тензор, сначала создайте обычный плотный тензор, соответствующий формату разреженности 2:4 (или полуструктурированному формату). Для этого мы повторяем небольшой фрагмент размером 1x4, создавая плотный тензор float16 размером 16x16. Затем можно вызвать функцию to_sparse_semi_structured, чтобы сжать его и ускорить инференс.
>>> from torch.sparse import to_sparse_semi_structured
>>> A = torch.Tensor([0, 0, 1, 1]).tile((128, 32)).half().cuda()
tensor([[0., 0., 1., ..., 0., 1., 1.],
[0., 0., 1., ..., 0., 1., 1.],
[0., 0., 1., ..., 0., 1., 1.],
...,
[0., 0., 1., ..., 0., 1., 1.],
[0., 0., 1., ..., 0., 1., 1.],
[0., 0., 1., ..., 0., 1., 1.]], device='cuda:0', dtype=torch.float16)
>>> A_sparse = to_sparse_semi_structured(A)
SparseSemiStructuredTensor(shape=torch.Size([128, 128]), transposed=False, values=tensor([[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
...,
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.]], device='cuda:0', dtype=torch.float16), metadata=tensor([[-4370, -4370, -4370, ..., -4370, -4370, -4370],
[-4370, -4370, -4370, ..., -4370, -4370, -4370],
[-4370, -4370, -4370, ..., -4370, -4370, -4370],
...,
[-4370, -4370, -4370, ..., -4370, -4370, -4370],
[-4370, -4370, -4370, ..., -4370, -4370, -4370],
[-4370, -4370, -4370, ..., -4370, -4370, -4370]], device='cuda:0',
dtype=torch.int16))
Операции с полуструктурированными разреженными тензорами
В настоящее время для полуструктурированных разреженных тензоров поддерживаются следующие операции:
- torch.addmm(bias, dense, sparse.t())
- torch.mm(dense, sparse)
- torch.mm(sparse, dense)
- aten.linear.default(dense, sparse, bias)
- aten.t.default(sparse)
- aten.t.detach(sparse)
Чтобы использовать эти операции, просто передайте результат to_sparse_semi_structured(tensor) вместо использования tensor, когда в вашем тензоре уже есть нули в полуструктурированном разреженном формате, например:
>>> a = torch.Tensor([0, 0, 1, 1]).tile((64, 16)).half().cuda() >>> b = torch.rand(64, 64).half().cuda() >>> c = torch.mm(a, b) >>> a_sparse = to_sparse_semi_structured(a) >>> torch.allclose(c, torch.mm(a_sparse, b)) True
Ускорение nn.Linear с помощью полуструктурированной разреженности
Если веса уже имеют полуструктурированную разреженность, можно ускорить линейные слои модели всего несколькими строками кода:
>>> input = torch.rand(64, 64).half().cuda() >>> mask = torch.Tensor([0, 0, 1, 1]).tile((64, 16)).cuda().bool() >>> linear = nn.Linear(64, 64).half().cuda() >>> linear.weight = nn.Parameter(to_sparse_semi_structured(linear.weight.masked_fill(~mask, 0)))
-
torch.sparse.semi_structured.to_sparse_semi_structured(original_tensor, transposed=False, alg_id=0)[исходный код] -
Эта функция преобразует плотный тензор в полуструктурированный разреженный тензор. Она возвращает SparseSemiStructuredTensor — подкласс torch.Tensor.
Эта функция проверяет, что у плотного тензора правильные тип данных, размер, размерность и устройство. В настоящее время мы поддерживаем полуструктурированные разреженные тензоры только для двумерных тензоров CUDA. Кроме того, размер вашего тензора должен быть положительным числом, кратным минимальному размеру разреженного блока, указанному в
_DTYPE_TO_SHAPE_CONSTRAINTSдля каждого типа данных (float32, float16, bfloat16, int8).- Параметры:
-
- original_tensor (Tensor) – плотный тензор для преобразования
- transposed (bool, optional) – устаревший аргумент, который будет удалён в одном из следующих выпусков. Не используйте его.
-
alg_id (int, optional) – идентификатор алгоритма для умножения матриц cuSPARSELt. По умолчанию равен 0. Его можно получить с помощью
torch._cslt_sparse_mm_search.
- Возвращает:
-
Разреженный полуструктурированный тензор, созданный из заданного original_tensor
- Тип возвращаемого значения:
-
SparseSemiStructuredTensor
- Исключения:
-
None –
Пример
>>> A = torch.Tensor([0, 0, 1, 1]).tile((128, 32)).half().cuda() tensor([[0., 0., 1., ..., 0., 1., 1.], [0., 0., 1., ..., 0., 1., 1.], [0., 0., 1., ..., 0., 1., 1.], ..., [0., 0., 1., ..., 0., 1., 1.], [0., 0., 1., ..., 0., 1., 1.], [0., 0., 1., ..., 0., 1., 1.]], device='cuda:0', dtype=torch.float16) >>> A_sparse = to_sparse_semi_structured(A) SparseSemiStructuredTensor(shape=torch.Size([128, 128])) >>> A_sparse.values() tensor([[1., 1., 1., ..., 1., 1., 1.], [1., 1., 1., ..., 1., 1., 1.], [1., 1., 1., ..., 1., 1., 1.], ..., [1., 1., 1., ..., 1., 1., 1.], [1., 1., 1., ..., 1., 1., 1.], [1., 1., 1., ..., 1., 1., 1.]], device='cuda:0', dtype=torch.float16), >>> A_sparse.indices() tensor([[-4370, -4370, -4370, ..., -4370, -4370, -4370], [-4370, -4370, -4370, ..., -4370, -4370, -4370], [-4370, -4370, -4370, ..., -4370, -4370, -4370], ..., [-4370, -4370, -4370, ..., -4370, -4370, -4370], [-4370, -4370, -4370, ..., -4370, -4370, -4370], [-4370, -4370, -4370, ..., -4370, -4370, -4370]], device='cuda:0', dtype=torch.int16))
SparseSemiStructuredTensorCUSPARSELT
| Бэкенд cuSPARSELt ожидает, что заданные элементы и метаданные будут храниться в одном тензоре: packed = [ заданные элементы исходного тензора | метаданные ]. Для исходного тензора размера (m, k) мы ожидаем, что первые m * k // 2 элементов будут сохранёнными элементами. Остальная часть тензора содержит метаданные. |
SparseSemiStructuredTensorCUTLASS
| Этот класс реализует полуструктурированную разреженность для бэкенда CUTLASS. |
Разреженные тензоры COO
PyTorch реализует так называемый координатный формат, или формат COO, как один из форматов хранения разреженных тензоров. В формате COO заданные элементы хранятся в виде кортежей индексов элементов и соответствующих значений. В частности,
- индексы заданных элементов собираются в тензор
indicesразмера(ndim, nse)с типом элементовtorch.int64, - соответствующие значения собираются в тензор
valuesразмера(nse,)с произвольным целочисленным типом или типом с плавающей точкой,
где ndim — размерность тензора, а nse — количество заданных элементов.
Примечание
Объём памяти, занимаемый разреженным тензором COO, составляет не менее (ndim * 8 + <size of element type in bytes>) * nse байт (не считая постоянных накладных расходов на хранение других данных тензора).
Объём памяти, занимаемый тензором со схемой хранения strided, составляет не менее product(<tensor shape>) * <size of element type in bytes>.
Например, тензор размером 10 000 x 10 000 со 100 000 ненулевых 32-разрядных чисел с плавающей точкой занимает не менее (2 * 8 + 4) * 100 000 = 2 000 000 байт при использовании схемы хранения COO и 10 000 * 10 000 * 4 = 400 000 000 байт при использовании стандартной схемы хранения strided. Обратите внимание: формат хранения COO позволяет сэкономить память в 200 раз.
Создание
Разреженный тензор COO можно создать, передав два тензора индексов и значений, а также размер разреженного тензора (если его нельзя определить по тензорам индексов и значений) функции torch.sparse_coo_tensor().
Предположим, мы хотим определить разреженный тензор со значением 3 в позиции (0, 2), значением 4 в позиции (1, 0) и значением 5 в позиции (1, 2). Предполагается, что незаданные элементы имеют одно и то же значение заполнения, которое по умолчанию равно нулю. Тогда мы напишем:
>>> i = [[0, 1, 1], [2, 0, 2]]
>>> v = [3, 4, 5]
>>> s = torch.sparse_coo_tensor(i, v, (2, 3))
>>> s
tensor(indices=tensor([[0, 1, 1],
[2, 0, 2]]),
values=tensor([3, 4, 5]),
size=(2, 3), nnz=3, layout=torch.sparse_coo)
>>> s.to_dense()
tensor([[0, 0, 3],
[4, 0, 5]])
Обратите внимание, что входной i — это НЕ список кортежей индексов. Если вы хотите задать индексы таким образом, перед передачей конструктору разреженного тензора транспонируйте их:
>>> i = [[0, 2], [1, 0], [1, 2]]
>>> v = [3, 4, 5 ]
>>> s = torch.sparse_coo_tensor(list(zip(*i)), v, (2, 3))
>>> # Or another equivalent formulation to get s
>>> s = torch.sparse_coo_tensor(torch.tensor(i).t(), v, (2, 3))
>>> torch.sparse_coo_tensor(i.t(), v, torch.Size([2,3])).to_dense()
tensor([[0, 0, 3],
[4, 0, 5]])
Пустой разреженный тензор COO можно создать, указав только его размер:
>>> torch.sparse_coo_tensor(size=(2, 3))
tensor(indices=tensor([], size=(2, 0)),
values=tensor([], size=(0,)),
size=(2, 3), nnz=0, layout=torch.sparse_coo)
Гибридные разреженные тензоры COO
PyTorch расширяет концепцию разреженных тензоров со скалярными значениями на разреженные тензоры со значениями в виде (непрерывно расположенных) тензоров. Такие тензоры называются гибридными.
Гибридный тензор COO в PyTorch расширяет разреженный тензор COO, позволяя тензору values быть многомерным. Таким образом, мы получаем:
- индексы заданных элементов собираются в тензор
indicesразмера(sparse_dims, nse)с типом элементовtorch.int64, - соответствующие значения (в виде тензоров) собираются в тензор
valuesразмера(nse, dense_dims)с произвольным целочисленным типом или типом с плавающей точкой.
Примечание
Для обозначения N-мерного разреженного гибридного тензора мы используем запись «тензор размерности (M + K)», где M и K — количество разреженных и плотных измерений соответственно, причём выполняется равенство M + K == N.
Предположим, мы хотим создать тензор размерности (2 + 1) со значением [3, 4] в позиции (0, 2), значением [5, 6] в позиции (1, 0) и значением [7, 8] в позиции (1, 2). Мы напишем:
>>> i = [[0, 1, 1],
[2, 0, 2]]
>>> v = [[3, 4], [5, 6], [7, 8]]
>>> s = torch.sparse_coo_tensor(i, v, (2, 3, 2))
>>> s
tensor(indices=tensor([[0, 1, 1],
[2, 0, 2]]),
values=tensor([[3, 4],
[5, 6],
[7, 8]]),
size=(2, 3, 2), nnz=3, layout=torch.sparse_coo)
>>> s.to_dense()
tensor([[[0, 0],
[0, 0],
[3, 4]],
[[5, 6],
[0, 0],
[7, 8]]])
В общем случае, если s — разреженный тензор COO и M = s.sparse_dim(), K = s.dense_dim(), выполняются следующие инварианты:
-
M + K == len(s.shape) == s.ndim— размерность тензора равна сумме количества разреженных и плотных измерений; -
s.indices().shape == (M, nse)— разреженные индексы хранятся явно; -
s.values().shape == (nse,) + s.shape[M : M + K]— значения гибридного тензора представляют собой K-мерные тензоры; -
s.values().layout == torch.strided— значения хранятся в виде тензоров со схемой хранения strided.
Примечание
Плотные измерения всегда следуют за разреженными, то есть смешивание плотных и разреженных измерений не поддерживается.
Примечание
Чтобы убедиться, что у созданного разреженного тензора согласованы индексы, значения и размер, проверки инвариантов можно включить при создании каждого тензора с помощью именованного аргумента check_invariants=True или глобально, используя экземпляр контекстного менеджера torch.sparse.check_sparse_tensor_invariants. По умолчанию проверки инвариантов разреженных тензоров отключены.
Несобранные разреженные тензоры COO
Формат разреженных тензоров COO в PyTorch допускает разреженные несобранные тензоры, в индексах которых могут повторяться координаты. В этом случае значением по такому индексу считается сумма всех значений с повторяющимися индексами. Например, можно указать несколько значений — 3 и 4 — для одного индекса 1, что приводит к созданию одномерного несобранного тензора:
>>> i = [[1, 1]]
>>> v = [3, 4]
>>> s=torch.sparse_coo_tensor(i, v, (3,))
>>> s
tensor(indices=tensor([[1, 1]]),
values=tensor( [3, 4]),
size=(3,), nnz=2, layout=torch.sparse_coo)
а при сборке многократные значения элементов суммируются в одно значение:
>>> s.coalesce()
tensor(indices=tensor([[1]]),
values=tensor([7]),
size=(3,), nnz=1, layout=torch.sparse_coo)
В общем случае результат метода torch.Tensor.coalesce() — разреженный тензор со следующими свойствами:
- индексы заданных элементов тензора уникальны;
- индексы отсортированы в лексикографическом порядке;
-
torch.Tensor.is_coalesced()возвращаетTrue.
Примечание
В большинстве случаев вам не нужно беспокоиться о том, собран разреженный тензор или нет, поскольку большинство операций работают одинаково как с собранным, так и с несобранным разреженным тензором.
Однако некоторые операции эффективнее выполняются над несобранными тензорами, а другие — над собранными.
Например, сложение разреженных тензоров COO реализовано простым объединением тензоров индексов и значений:
>>> a = torch.sparse_coo_tensor([[1, 1]], [5, 6], (2,))
>>> b = torch.sparse_coo_tensor([[0, 0]], [7, 8], (2,))
>>> a + b
tensor(indices=tensor([[0, 0, 1, 1]]),
values=tensor([7, 8, 5, 6]),
size=(2,), nnz=4, layout=torch.sparse_coo)
Если вы многократно выполняете операцию, которая может создавать повторяющиеся записи (например, torch.Tensor.add()), следует время от времени собирать разреженные тензоры, чтобы они не становились слишком большими.
С другой стороны, лексикографический порядок индексов может быть полезен при реализации алгоритмов, включающих множество операций выбора элементов, например срезов или произведений матриц.
Работа с разреженными тензорами COO
Рассмотрим следующий пример:
>>> i = [[0, 1, 1],
[2, 0, 2]]
>>> v = [[3, 4], [5, 6], [7, 8]]
>>> s = torch.sparse_coo_tensor(i, v, (2, 3, 2))
Как упоминалось выше, разреженный тензор COO является экземпляром torch.Tensor. Чтобы отличить его от экземпляров Tensor с другими схемами хранения, можно использовать свойства torch.Tensor.is_sparse или torch.Tensor.layout:
>>> isinstance(s, torch.Tensor) True >>> s.is_sparse True >>> s.layout == torch.sparse_coo True
Количество разреженных и плотных измерений можно получить с помощью методов torch.Tensor.sparse_dim() и torch.Tensor.dense_dim() соответственно. Например:
>>> s.sparse_dim(), s.dense_dim() (2, 1)
Если s — разреженный тензор COO, его данные в формате COO можно получить с помощью методов torch.Tensor.indices() и torch.Tensor.values().
Примечание
В настоящее время получить данные в формате COO можно только для собранного экземпляра тензора:
>>> s.indices() RuntimeError: Cannot get indices on an uncoalesced tensor, please call .coalesce() first
Чтобы получить данные в формате COO для несобранного тензора, используйте torch.Tensor._values() и torch.Tensor._indices():
>>> s._indices()
tensor([[0, 1, 1],
[2, 0, 2]])
Предупреждение
Вызов torch.Tensor._values() вернёт отсоединённый тензор. Для отслеживания градиентов следует использовать torch.Tensor.coalesce().values().
Создание нового разреженного тензора COO приводит к получению несобранного тензора:
>>> s.is_coalesced() False
однако можно создать собранную копию разреженного тензора COO с помощью метода torch.Tensor.coalesce():
>>> s2 = s.coalesce()
>>> s2.indices()
tensor([[0, 1, 1],
[2, 0, 2]])
При работе с несобранными разреженными тензорами COO необходимо учитывать аддитивную природу несобранных данных: значения с одинаковыми индексами являются слагаемыми, сумма которых даёт значение соответствующего элемента тензора. Например, умножение несобранного разреженного тензора на скаляр можно реализовать умножением всех несобранных значений на скаляр, поскольку выполняется c * (a + b) == c * a + c * b. Однако нелинейную операцию, например извлечение квадратного корня, нельзя реализовать применением операции к несобранным данным, поскольку в общем случае sqrt(a + b) == sqrt(a) + sqrt(b) не выполняется.
Срезы (с положительным шагом) разреженного тензора COO поддерживаются только для плотных измерений. Индексация поддерживается как для разреженных, так и для плотных измерений:
>>> s[1]
tensor(indices=tensor([[0, 2]]),
values=tensor([[5, 6],
[7, 8]]),
size=(3, 2), nnz=2, layout=torch.sparse_coo)
>>> s[1, 0, 1]
tensor(6)
>>> s[1, 0, 1:]
tensor([6])
В PyTorch нельзя явно задать значение заполнения разреженного тензора; обычно предполагается, что оно равно нулю. Однако некоторые операции могут интерпретировать значение заполнения иначе. Например, torch.sparse.softmax() вычисляет softmax, предполагая, что значение заполнения равно минус бесконечности.
Сжатые разреженные тензоры
Сжатые разреженные тензоры представляют собой класс разреженных тензоров, для которых характерно сжатие индексов определённого измерения с помощью кодирования, позволяющего оптимизировать ядра линейной алгебры для сжатых разреженных тензоров. Это кодирование основано на формате Compressed Sparse Row (CSR), расширенном в разреженных сжатых тензорах PyTorch поддержкой пакетов разреженных тензоров, многомерных значений тензоров и хранением значений разреженных тензоров в плотных блоках.
Примечание
Для обозначения N-мерного гибридного сжатого разреженного тензора мы используем тензор размерности (B + M + K), где B, M и K — числа пакетных, разреженных и плотных измерений соответственно, так что выполняется B + M + K == N. Число разреженных измерений у сжатых разреженных тензоров всегда равно двум: M == 2.
Примечание
Говорят, что тензор индексов compressed_indices использует кодирование CSR, если выполняются следующие инварианты:
-
compressed_indices— это непрерывный тензор с шагами, содержащий целые числа размером 32 или 64 бита -
форма
compressed_indicesимеет вид(*batchsize, compressed_dim_size + 1), гдеcompressed_dim_size— число сжатых измерений (например, строк или столбцов) -
compressed_indices[..., 0] == 0, где...обозначает пакетные индексы -
compressed_indices[..., compressed_dim_size] == nse, гдеnse— число заданных элементов -
0 <= compressed_indices[..., i] - compressed_indices[..., i - 1] <= plain_dim_sizeдляi=1, ..., compressed_dim_size, гдеplain_dim_size— число обычных измерений (ортогональных сжатым измерениям, например столбцов или строк).
Чтобы убедиться в согласованности индексов, значений и размера создаваемого разреженного тензора, проверки инвариантов можно включить при создании каждого тензора с помощью именованного аргумента check_invariants=True или глобально, используя экземпляр контекстного менеджера torch.sparse.check_sparse_tensor_invariants. По умолчанию проверки инвариантов разреженных тензоров отключены.
Примечание
Обобщение сжатых разреженных форматов на N-мерные тензоры может привести к путанице при подсчёте заданных элементов. Если сжатый разреженный тензор содержит пакетные измерения, число заданных элементов соответствует числу таких элементов в каждом пакете. Если сжатый разреженный тензор содержит плотные измерения, элементом считается K-мерный массив. Кроме того, в блочных сжатых разреженных форматах заданным элементом считается двумерный блок. Рассмотрим в качестве примера трёхмерный блочный разреженный тензор с одним пакетным измерением длины b и размером блока p, q. Если в этом тензоре задано n элементов, то фактически в каждом пакете задано n блоков. У этого тензора будет values с формой (b, n, p, q). Такое толкование числа заданных элементов обусловлено тем, что все сжатые разреженные форматы являются результатом сжатия двумерной матрицы. Пакетные измерения рассматриваются как стопка разреженных матриц, а плотные измерения меняют смысл элемента: вместо простого скалярного значения он становится массивом с собственными измерениями.
Разреженный тензор CSR
Главное преимущество формата CSR перед форматом COO — более эффективное использование памяти и значительно более высокая скорость вычислений, таких как умножение разреженной матрицы на вектор с использованием бэкендов MKL и MAGMA.
В простейшем случае двумерный разреженный тензор CSR (0 + 2 + 0) состоит из трёх одномерных тензоров: crow_indices, col_indices и values:
- Тензор
crow_indicesсодержит сжатые индексы строк. Это одномерный тензор размераnrows + 1(число строк плюс 1). Последний элементcrow_indicesравен числу заданных элементов,nse. Этот тензор кодирует индекс вvaluesиcol_indicesв зависимости от того, где начинается заданная строка. Разность каждого последующего числа в тензоре и предыдущего числа обозначает число элементов в соответствующей строке. - Тензор
col_indicesсодержит индексы столбцов каждого элемента. Это одномерный тензор размераnse. - Тензор
valuesсодержит значения элементов тензора CSR. Это одномерный тензор размераnse.
Примечание
Тип элементов тензоров индексов crow_indices и col_indices должен быть torch.int64 (по умолчанию) или torch.int32. Если вы хотите использовать операции с матрицами на базе MKL, используйте torch.int32. Это связано с тем, что PyTorch по умолчанию компонуется с MKL LP64, где для индексации используются 32-битные целые числа.
В общем случае N-мерный разреженный тензор CSR (B + 2 + K) состоит из двух тензоров индексов размерности (B + 1) — crow_indices и col_indices — и тензора values размерности (1 + K), таких что
crow_indices.shape == (*batchsize, nrows + 1)col_indices.shape == (*batchsize, nse)values.shape == (nse, *densesize)
при этом форма разреженного тензора CSR равна (*batchsize, nrows, ncols, *densesize), где len(batchsize) == B и len(densesize) == K.
Примечание
Пакеты разреженных тензоров CSR зависят друг от друга: число заданных элементов должно быть одинаковым во всех пакетах. Это несколько искусственное ограничение позволяет эффективно хранить индексы разных пакетов CSR.
Примечание
Число разреженных и плотных измерений можно получить с помощью методов torch.Tensor.sparse_dim() и torch.Tensor.dense_dim(). Пакетные измерения можно вычислить по форме тензора: batchsize = tensor.shape[:-tensor.sparse_dim() - tensor.dense_dim()].
Примечание
Объём памяти, занимаемый разреженным тензором CSR, составляет не менее (nrows * 8 + (8 + <size of element type in bytes> * prod(densesize)) * nse) * prod(batchsize) байт (не считая постоянных накладных расходов на хранение других данных тензора).
Для тех же примерных данных, что и в примечании во введении к формату разреженных тензоров COO, объём памяти для тензора размером 10 000 x 10 000 со 100 000 ненулевых 32-битных чисел с плавающей точкой составляет не менее (10000 * 8 + (8 + 4 * 1) * 100 000) * 1 = 1 280 000 байт при использовании формата тензора CSR. Обратите внимание, что по сравнению с форматами хранения COO и strided формат CSR позволяет сократить расход памяти соответственно в 1,6 и 310 раз.
Создание тензоров CSR
Разреженные тензоры CSR можно создать напрямую с помощью функции torch.sparse_csr_tensor(). Пользователь должен отдельно передать тензоры индексов строк и столбцов, а также значений; при этом индексы строк должны быть заданы с использованием кодирования сжатия CSR. Аргумент size является необязательным: если он не задан, его значение будет выведено из crow_indices и col_indices.
>>> crow_indices = torch.tensor([0, 2, 4])
>>> col_indices = torch.tensor([0, 1, 0, 1])
>>> values = torch.tensor([1, 2, 3, 4])
>>> csr = torch.sparse_csr_tensor(crow_indices, col_indices, values, dtype=torch.float64)
>>> csr
tensor(crow_indices=tensor([0, 2, 4]),
col_indices=tensor([0, 1, 0, 1]),
values=tensor([1., 2., 3., 4.]), size=(2, 2), nnz=4,
dtype=torch.float64)
>>> csr.to_dense()
tensor([[1., 2.],
[3., 4.]], dtype=torch.float64)
Примечание
Значения разреженных измерений в выведенном size вычисляются по размеру crow_indices и максимальному значению индекса в col_indices. Если число столбцов должно быть больше, чем в выведенном size, необходимо явно указать аргумент size.
Проще всего создать двумерный разреженный тензор CSR из тензора strided или разреженного тензора COO с помощью метода torch.Tensor.to_sparse_csr(). Все нули в тензоре (strided) будут интерпретироваться как отсутствующие значения в разреженном тензоре:
>>> a = torch.tensor([[0, 0, 1, 0], [1, 2, 0, 0], [0, 0, 0, 0]], dtype=torch.float64)
>>> sp = a.to_sparse_csr()
>>> sp
tensor(crow_indices=tensor([0, 1, 3, 3]),
col_indices=tensor([2, 0, 1]),
values=tensor([1., 1., 2.]), size=(3, 4), nnz=3, dtype=torch.float64)
Операции с тензорами CSR
Умножение разреженной матрицы на вектор можно выполнить с помощью метода tensor.matmul(). В настоящее время это единственная математическая операция, поддерживаемая для тензоров CSR.
>>> vec = torch.randn(4, 1, dtype=torch.float64)
>>> sp.matmul(vec)
tensor([[0.9078],
[1.3180],
[0.0000]], dtype=torch.float64)
Разреженный тензор CSC
Формат разреженного тензора CSC (Compressed Sparse Column, сжатый разреженный столбец) реализует формат CSC для хранения двумерных тензоров и дополнен поддержкой пакетов разреженных тензоров CSC и многомерных тензоров в качестве значений.
Примечание
Разреженный тензор CSC по сути является транспонированным разреженным тензором CSR, если при транспонировании меняются местами разреженные измерения.
Как и разреженные тензоры CSR, разреженный тензор CSC состоит из трёх тензоров: ccol_indices, row_indices и values:
- Тензор
ccol_indicesсодержит сжатые индексы столбцов. Это тензор размерности (B + 1) с формой(*batchsize, ncols + 1). Последний элемент равен числу заданных элементов,nse. Этот тензор кодирует индекс вvaluesиrow_indicesв зависимости от того, где начинается заданный столбец. Разность каждого последующего числа в тензоре и предыдущего числа обозначает число элементов в соответствующем столбце. - Тензор
row_indicesсодержит индексы строк каждого элемента. Это тензор размерности (B + 1) с формой(*batchsize, nse). - Тензор
valuesсодержит значения элементов тензора CSC. Это тензор размерности (1 + K) с формой(nse, *densesize).
Создание тензоров CSC
Разреженные тензоры CSC можно создать напрямую с помощью функции torch.sparse_csc_tensor(). Пользователь должен отдельно передать тензоры индексов строк и столбцов, а также значений; при этом индексы столбцов должны быть заданы с использованием кодирования сжатия CSR. Аргумент size является необязательным: если он не задан, его значение будет выведено из тензоров row_indices и ccol_indices.
>>> ccol_indices = torch.tensor([0, 2, 4])
>>> row_indices = torch.tensor([0, 1, 0, 1])
>>> values = torch.tensor([1, 2, 3, 4])
>>> csc = torch.sparse_csc_tensor(ccol_indices, row_indices, values, dtype=torch.float64)
>>> csc
tensor(ccol_indices=tensor([0, 2, 4]),
row_indices=tensor([0, 1, 0, 1]),
values=tensor([1., 2., 3., 4.]), size=(2, 2), nnz=4,
dtype=torch.float64, layout=torch.sparse_csc)
>>> csc.to_dense()
tensor([[1., 3.],
[2., 4.]], dtype=torch.float64)
Примечание
В функции-конструкторе разреженного тензора CSC аргумент сжатыx индексов столбцов расположен перед аргументом индексов строк.
Разреженные двумерные тензоры CSC (0 + 2 + 0) можно создать из любого двумерного тензора с помощью метода torch.Tensor.to_sparse_csc(). Все нули в тензоре (strided) будут интерпретироваться как отсутствующие значения в разреженном тензоре:
>>> a = torch.tensor([[0, 0, 1, 0], [1, 2, 0, 0], [0, 0, 0, 0]], dtype=torch.float64)
>>> sp = a.to_sparse_csc()
>>> sp
tensor(ccol_indices=tensor([0, 1, 2, 3, 3]),
row_indices=tensor([1, 1, 0]),
values=tensor([1., 2., 1.]), size=(3, 4), nnz=3, dtype=torch.float64,
layout=torch.sparse_csc)
Разреженный тензор BSR
Формат разреженного тензора BSR (Block compressed Sparse Row, блочный сжатый разреженный ряд) реализует формат BSR для хранения двумерных тензоров и дополнен поддержкой пакетов разреженных тензоров BSR и блоков многомерных тензоров в качестве значений.
Разреженный тензор BSR состоит из трёх тензоров: crow_indices, col_indices и values:
- Тензор
crow_indicesсодержит сжатые индексы строк. Это тензор размерности (B + 1) с формой(*batchsize, nrowblocks + 1). Последний элемент равен числу заданных блоков,nse. Этот тензор кодирует индекс вvaluesиcol_indicesв зависимости от того, где начинается заданный блок столбцов. Разность каждого последующего числа в тензоре и предыдущего числа обозначает число блоков в соответствующей строке. - Тензор
col_indicesсодержит индексы блоков столбцов каждого элемента. Это тензор размерности (B + 1) с формой(*batchsize, nse). - Тензор
valuesсодержит значения элементов разреженного тензора BSR, сгруппированные в двумерные блоки. Это тензор размерности (1 + 2 + K) с формой(nse, nrowblocks, ncolblocks, *densesize).
Создание тензоров BSR
Разреженные тензоры BSR можно создать напрямую с помощью функции torch.sparse_bsr_tensor(). Пользователь должен отдельно передать тензоры индексов блоков строк и столбцов, а также значений; при этом индексы блоков строк должны быть заданы с использованием кодирования сжатия CSR. Аргумент size является необязательным: если он не задан, его значение будет выведено из тензоров crow_indices и col_indices.
>>> crow_indices = torch.tensor([0, 2, 4])
>>> col_indices = torch.tensor([0, 1, 0, 1])
>>> values = torch.tensor([[[0, 1, 2], [6, 7, 8]],
... [[3, 4, 5], [9, 10, 11]],
... [[12, 13, 14], [18, 19, 20]],
... [[15, 16, 17], [21, 22, 23]]])
>>> bsr = torch.sparse_bsr_tensor(crow_indices, col_indices, values, dtype=torch.float64)
>>> bsr
tensor(crow_indices=tensor([0, 2, 4]),
col_indices=tensor([0, 1, 0, 1]),
values=tensor([[[ 0., 1., 2.],
[ 6., 7., 8.]],
[[ 3., 4., 5.],
[ 9., 10., 11.]],
[[12., 13., 14.],
[18., 19., 20.]],
[[15., 16., 17.],
[21., 22., 23.]]]),
size=(4, 6), nnz=4, dtype=torch.float64, layout=torch.sparse_bsr)
>>> bsr.to_dense()
tensor([[ 0., 1., 2., 3., 4., 5.],
[ 6., 7., 8., 9., 10., 11.],
[12., 13., 14., 15., 16., 17.],
[18., 19., 20., 21., 22., 23.]], dtype=torch.float64)
Разреженные двумерные тензоры BSR (0 + 2 + 0) можно создать из любого двумерного тензора с помощью метода torch.Tensor.to_sparse_bsr(), для которого также необходимо указать размер блока значений:
>>> dense = torch.tensor([[0, 1, 2, 3, 4, 5],
... [6, 7, 8, 9, 10, 11],
... [12, 13, 14, 15, 16, 17],
... [18, 19, 20, 21, 22, 23]])
>>> bsr = dense.to_sparse_bsr(blocksize=(2, 3))
>>> bsr
tensor(crow_indices=tensor([0, 2, 4]),
col_indices=tensor([0, 1, 0, 1]),
values=tensor([[[ 0, 1, 2],
[ 6, 7, 8]],
[[ 3, 4, 5],
[ 9, 10, 11]],
[[12, 13, 14],
[18, 19, 20]],
[[15, 16, 17],
[21, 22, 23]]]), size=(4, 6), nnz=4,
layout=torch.sparse_bsr)
Разреженный тензор BSC
Формат разреженного тензора BSC (Block compressed Sparse Column, блочный сжатый разреженный столбец) реализует формат BSC для хранения двумерных тензоров и дополнен поддержкой пакетов разреженных тензоров BSC и блоков многомерных тензоров в качестве значений.
Разреженный тензор BSC состоит из трёх тензоров: ccol_indices, row_indices и values:
- Тензор
ccol_indicesсодержит сжатые индексы столбцов. Это тензор размерности (B + 1) с формой(*batchsize, ncolblocks + 1). Последний элемент равен числу заданных блоков,nse. Этот тензор кодирует индекс вvaluesиrow_indicesв зависимости от того, где начинается заданный блок строк. Разность каждого последующего числа в тензоре и предыдущего числа обозначает число блоков в соответствующем столбце. - Тензор
row_indicesсодержит индексы блоков строк каждого элемента. Это тензор размерности (B + 1) с формой(*batchsize, nse). - Тензор
valuesсодержит значения элементов разреженного тензора BSC, сгруппированные в двумерные блоки. Это тензор размерности (1 + 2 + K) с формой(nse, nrowblocks, ncolblocks, *densesize).
Создание тензоров BSC
Разреженные тензоры BSC можно создать напрямую с помощью функции torch.sparse_bsc_tensor(). Пользователь должен отдельно передать тензоры индексов блоков строк и столбцов, а также значений; при этом индексы блоков столбцов должны быть заданы с использованием кодирования сжатия CSR. Аргумент size является необязательным: если он не задан, его значение будет выведено из тензоров ccol_indices и row_indices.
>>> ccol_indices = torch.tensor([0, 2, 4])
>>> row_indices = torch.tensor([0, 1, 0, 1])
>>> values = torch.tensor([[[0, 1, 2], [6, 7, 8]],
... [[3, 4, 5], [9, 10, 11]],
... [[12, 13, 14], [18, 19, 20]],
... [[15, 16, 17], [21, 22, 23]]])
>>> bsc = torch.sparse_bsc_tensor(ccol_indices, row_indices, values, dtype=torch.float64)
>>> bsc
tensor(ccol_indices=tensor([0, 2, 4]),
row_indices=tensor([0, 1, 0, 1]),
values=tensor([[[ 0., 1., 2.],
[ 6., 7., 8.]],
[[ 3., 4., 5.],
[ 9., 10., 11.]],
[[12., 13., 14.],
[18., 19., 20.]],
[[15., 16., 17.],
[21., 22., 23.]]]), size=(4, 6), nnz=4,
dtype=torch.float64, layout=torch.sparse_bsc)
Инструменты для работы со сжатыми разреженными тензорами
Все сжатые разреженные тензоры — CSR, CSC, BSR и BSC — концептуально очень похожи: данные их индексов разделены на две части: так называемые сжатые индексы, использующие кодирование CSR, и так называемые обычные индексы, ортогональные сжатым индексам. Благодаря этому для работы с такими тензорами можно использовать общие инструменты с реализациями, параметризованными форматом тензора.
Создание сжатых разреженных тензоров
Разреженные тензоры CSR, CSC, BSR и CSC можно создать с помощью функции torch.sparse_compressed_tensor(), интерфейс которой совпадает с интерфейсами рассмотренных выше функций-конструкторов torch.sparse_csr_tensor(), torch.sparse_csc_tensor(), torch.sparse_bsr_tensor() и torch.sparse_bsc_tensor() соответственно, но требует дополнительного аргумента layout. В следующем примере показано, как создать тензоры CSR и CSC из одних и тех же входных данных, указав соответствующий параметр формата в функции torch.sparse_compressed_tensor():
>>> compressed_indices = torch.tensor([0, 2, 4])
>>> plain_indices = torch.tensor([0, 1, 0, 1])
>>> values = torch.tensor([1, 2, 3, 4])
>>> csr = torch.sparse_compressed_tensor(compressed_indices, plain_indices, values, layout=torch.sparse_csr)
>>> csr
tensor(crow_indices=tensor([0, 2, 4]),
col_indices=tensor([0, 1, 0, 1]),
values=tensor([1, 2, 3, 4]), size=(2, 2), nnz=4,
layout=torch.sparse_csr)
>>> csc = torch.sparse_compressed_tensor(compressed_indices, plain_indices, values, layout=torch.sparse_csc)
>>> csc
tensor(ccol_indices=tensor([0, 2, 4]),
row_indices=tensor([0, 1, 0, 1]),
values=tensor([1, 2, 3, 4]), size=(2, 2), nnz=4,
layout=torch.sparse_csc)
>>> (csr.transpose(0, 1).to_dense() == csc.to_dense()).all()
tensor(True)
Поддерживаемые операции
Операции линейной алгебры
В следующей таблице перечислены поддерживаемые операции линейной алгебры над разреженными матрицами, для которых форматы операндов могут различаться. Здесь T[layout] обозначает тензор с заданным форматом. Аналогично, M[layout] обозначает матрицу (двумерный тензор PyTorch), а V[layout] — вектор (одномерный тензор PyTorch). Кроме того, f обозначает скаляр (число с плавающей точкой или нульмерный тензор PyTorch), * — поэлементное умножение, а @ — матричное умножение.
Операция PyTorch | Разреженный градиент? | Сигнатура формата |
|---|---|---|
нет |
| |
нет |
| |
нет |
| |
нет |
| |
нет |
| |
нет |
| |
нет |
| |
нет |
| |
нет |
| |
да |
| |
нет |
| |
нет |
| |
нет |
| |
нет |
| |
нет |
| |
нет |
| |
да |
| |
нет |
| |
нет |
| |
нет |
| |
да |
| |
да |
|
Столбец «Разреженный градиент?» указывает, поддерживает ли операция PyTorch обратное распространение относительно аргумента-разреженной матрицы. Все операции PyTorch, кроме torch.smm(), поддерживают обратное распространение относительно аргументов-матриц со страйдовым форматом.
Примечание
В настоящее время PyTorch не поддерживает матричное умножение с сигнатурой формата M[strided] @ M[sparse_coo]. Однако приложения могут выполнять это умножение, используя соотношение между матрицами D @ S == (S.t() @ D.t()).t().
Методы Tensor и разреженные тензоры
Следующие методы Tensor связаны с разреженными тензорами:
Возвращает | |
Возвращает | |
Возвращает число плотных измерений в разреженном тензоре | |
Возвращает число разреженных измерений в разреженном тензоре | |
Возвращает новый разреженный тензор со значениями из страйдового тензора | |
Возвращает разреженную копию тензора. | |
Преобразует тензор в координатный формат. | |
Преобразует тензор в формат хранения со сжатием по строкам (CSR). | |
Преобразует тензор в формат хранения со сжатием по столбцам (CSC). | |
Преобразует тензор в формат хранения с блочным сжатием по строкам (BSR) с заданным размером блока. | |
Преобразует тензор в формат хранения с блочным сжатием по столбцам (BSC) с заданным размером блока. | |
Создаёт страйдовую копию | |
Возвращает тензор значений разреженного тензора COO. |
Следующие методы предназначены для разреженных тензоров COO:
Возвращает объединённую копию | |
Изменяет размер | |
Удаляет все указанные элементы из разреженного тензора | |
Возвращает | |
Возвращает тензор индексов разреженного тензора COO. |
Следующие методы предназначены для разреженных тензоров CSR и разреженных тензоров BSR:
Возвращает тензор, содержащий сжатые индексы строк тензора | |
Возвращает тензор, содержащий индексы столбцов тензора |
Следующие методы предназначены для разреженных тензоров CSC и разреженных тензоров BSC:
Следующие методы Tensor поддерживают разреженные тензоры COO:
add() add_() addmm() addmm_() any() asin() asin_() arcsin() arcsin_() bmm() clone() deg2rad() deg2rad_() detach() detach_() dim() div() div_() floor_divide() floor_divide_() get_device() index_select() isnan() log1p() log1p_() mm() mul() mul_() mv() narrow_copy() neg() neg_() negative() negative_() numel() rad2deg() rad2deg_() resize_as_() size() pow() sqrt() square() smm() sspaddmm() sub() sub_() t() t_() transpose() transpose_() zero_()
Функции Torch для разреженных тензоров
sparse_coo_tensor
| Создаёт разреженный тензор в координатном формате COO с заданными значениями по указанным |
sparse_csr_tensor
| Создаёт разреженный тензор в формате CSR (сжатие разреженных строк) с заданными значениями по указанным |
sparse_csc_tensor
| Создаёт разреженный тензор в формате CSC (сжатие разреженных столбцов) с заданными значениями по указанным |
sparse_bsr_tensor
| Создаёт разреженный тензор в формате BSR (блочное сжатие разреженных строк) с заданными двумерными блоками по указанным |
sparse_bsc_tensor
| Создаёт разреженный тензор в формате BSC (блочное сжатие разреженных столбцов) с заданными двумерными блоками по указанным |
sparse_compressed_tensor
| Создаёт разреженный тензор в формате сжатого хранения — CSR, CSC, BSR или BSC — с заданными значениями по указанным |
Возвращает сумму элементов каждой строки заданного разреженного тензора. | |
При прямом проходе эта функция выполняет ту же операцию, что и | |
Выполняет умножение плотных матриц | |
Выполняет умножение разреженной матрицы | |
sspaddmm
| Умножает разреженный тензор |
hspmm
| Выполняет умножение разреженной матрицы COO |
smm
| Выполняет умножение разреженной матрицы |
Применяет функцию softmax. | |
Вычисляет решение квадратной системы линейных уравнений с единственным решением. | |
Применяет функцию softmax, а затем логарифм. | |
Создаёт разреженный двумерный тензор, размещая значения из строк |
Другие функции
Следующие функции torch поддерживают разреженные тензоры:
cat() dstack() empty() empty_like() hstack() index_select() is_complex() is_floating_point() is_nonzero() is_same_size() is_signed() is_tensor() lobpcg() mm() native_norm() pca_lowrank() select() stack() svd_lowrank() unsqueeze() vstack() zeros() zeros_like()
Для управления проверкой инвариантов разреженных тензоров см.:
Средство для управления проверкой инвариантов разреженных тензоров. |
О применении разреженных тензоров с функцией gradcheck() см.:
Декоратор функции, расширяющий gradcheck для разреженных тензоров. |
Унарные функции, сохраняющие ноль
Мы стремимся поддерживать все «унарные функции, сохраняющие ноль»: функции от одного аргумента, которые отображают ноль в ноль.
Если вам нужна унарная функция, сохраняющая ноль, которой здесь нет, пожалуйста, создайте запрос на добавление этой функции. Как всегда, перед созданием запроса сначала воспользуйтесь поиском.
В настоящее время следующие операторы поддерживают входные тензоры sparse COO/CSR/CSC/BSR/CSR.
abs() asin() asinh() atan() atanh() ceil() conj_physical() floor() log1p() neg() round() sin() sinh() sign() sgn() signbit() tan() tanh() trunc() expm1() sqrt() angle() isinf() isposinf() isneginf() isnan() erf() erfinv()
© 2026, PyTorch Contributors
PyTorch has a BSD-style license, as found in the LICENSE file.
https://docs.pytorch.org/docs/2.14/sparse.html