| 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) |