blob: 61e69a9832a6da297f6450c22d73c43bcb08efe3 [file] [log] [blame]
import torch
import math
import numpy as np
from typing import Any
def generate_inputs(
shapes: tuple[Any, ...],
sparsity: float,
formats: tuple[str, ...],
dtype: Any = np.float64,
drange: tuple[Any, ...] = (1, 100),
) -> tuple[tuple[torch.Tensor, ...], tuple[torch.Tensor, ...]]:
"""Generates dense and sparse tensor inputs.
Args:
shapes: Shape for each input.
sparsity: Sparsity level for the inputs.
formats: Sparsity format for each input.
dtype: Data type of the generated inputs. Default is np.float64.
drange: Data range of the non-zero values. Default is (1, 100).
Returns:
dense_inputs: all dense tensors.
sparse_inputs: inputs are of the specified sparsity format, such as CSR.
"""
dense_inputs = []
sparse_inputs = []
# Each input has a different seed.
for seed, shape in enumerate(shapes):
dense_inputs.append(generate_tensor(seed, shape, sparsity, dtype, drange))
for idx, dense_input in enumerate(dense_inputs):
if formats[idx] == "dense":
sparse_inputs.append(dense_input)
else:
# TODO: support more sparsity formats.
sparse_inputs.append(dense_input.to_sparse_csr())
return dense_inputs, sparse_inputs
def generate_tensor(
seed: int,
shape: tuple[Any, ...],
sparsity: float,
dtype: Any = np.float64,
drange: tuple[Any, ...] = (1, 100),
) -> torch.Tensor:
"""Generates a tensor given sparsity level, shape and data type.
Args:
seed: Seed value for np.random.
shape: A tuple for the shape of tensor.
sparsity: Sparsity level in the range of [0, 1], viz. 0=dense and 1=all-zeros
dtype: Data type of the generated tensor. Default is np.float64.
drange: Data range of the non-zero values (inclusive). Default is (1, 100).
Returns:
A dense torch tensor with the specified shape, sparsity level and type.
Note: the tensor generated doesn't guarantee each batch will have the same
number of specified elements. Therefore, for batched CSR, torch.cat can be
used to concatenate generated tensors in the specified dimension.
"""
if sparsity < 0.0 or sparsity > 1.0:
raise ValueError("Invalid sparsity level: %f" % sparsity)
np.random.seed(seed)
size = math.prod(shape)
nse = size - int(math.ceil(sparsity * size))
flat_output = np.zeros(size)
indices = np.random.choice(size, nse, replace=False)
values = np.random.uniform(drange[0], drange[1], nse)
flat_output[indices] = values
result = np.reshape(flat_output, shape).astype(dtype)
return torch.from_numpy(result)
def print_matrix_market_format(tensor: torch.Tensor):
"""Prints the matrix market format for a sparse matrix.
Args:
tensor: sparse matrix (real type)
"""
if len(tensor.shape) != 2:
raise ValueError("Unexpected rank : %d (matrices only)" % len(tensor.shape))
if tensor.dtype != torch.float32 and tensor.dtype != torch.float64:
raise ValueError("Unexpected type : %s" % tensor.dtype)
h = tensor.shape[0]
w = tensor.shape[1]
nnz = sum([1 if tensor[i, j] != 0 else 0 for i in range(h) for j in range(w)])
density = (100.0 * nnz) / tensor.numel()
print("%%MatrixMarket matrix coordinate real general")
print("% https://math.nist.gov/MatrixMarket/formats.html")
print("%")
print("%% density = %4.2f%%" % density)
print("%")
print(h, w, nnz)
for i in range(h):
for j in range(w):
if tensor[i, j] != 0:
print(i + 1, j + 1, tensor[i, j].item())
def print_extended_frostt_format(tensor: torch.Tensor):
"""Prints the Extended FROSTT format for a sparse tensor.
Args:
tensor: sparse tensor
"""
a = tensor.numpy()
nnz = sum([1 if x != 0 else 0 for x in np.nditer(a)])
density = (100.0 * nnz) / tensor.numel()
print("# Tensor in Extended FROSTT file format")
print("# http://frostt.io/tensors/file-formats.html")
print("# extended with two metadata lines:")
print("# rank nnz")
print("# dims (one per rank)")
print("#")
print("# density = %4.2f%%" % density)
print("#")
print(len(tensor.shape), nnz)
print(*tensor.shape, sep=" ")
it = np.nditer(a, flags=["multi_index"])
for x in it:
if x != 0:
print(*[i + 1 for i in it.multi_index], sep=" ", end=" ")
print(x)