UDC-GAC / venom

A Vectorized N:M Format for Unleashing the Power of Sparse Tensor Cores
Apache License 2.0
31 stars 5 forks source link

dense with mask != sparse #5

Open ENXING opened 2 months ago

ENXING commented 2 months ago
#gpt2_pytorch.py

class SrnmSpmm(torch.nn.Module):
    def __init__(self, original: transformers.pytorch_utils.Conv1D):
        super().__init__()
        self.bias = original.bias

        # Convert weights from original module to SrNM
        w, mask, sp_to_dense = NMVectorSparsifier(n, m, v)(original.weight)
        w = w.wrapped_tensor
        self.orig =original.weight.half().to('cuda') 
        self.mask= mask.half().to('cuda')
        self.sp_to_dense = sp_to_dense

        self.values = torch.nn.Parameter(w.values)
        #self.columns = self.register_buffer('columns', w.columns)
        self.columns = w.columns
        self.metadata = w.metadata
        #print(w.metadata)
        self.nrows_sp = w.ncols
        self.ncols_sp = w.nrows
        self.nnz      = w.nnz

    def forward(self, input):

        flattened_input = torch.flatten(input, start_dim=0, end_dim=-2)

        ncols_d  = flattened_input.T.shape[1]
        DM, _    = flattened_input.shape

        output = sparse_dense_mul_dispatch(self.values, self.columns, self.metadata, flattened_input.T, self.nrows_sp, self.ncols_sp,
                                           ncols_d, m, n, v, self.nnz, self.bias)
        print(f"{output.shape=},{self.bias.shape=}, {input.shape=} {self.orig.shape=}, {self.nrows_sp=}, {self.ncols_sp=}, {ncols_d=}, {m=}, {n=}, {v=}, {self.nnz=}")
        output = output.reshape((*input.shape[0:-1], -1))[..., :DM]

        output2 = input@ (self.orig * self.mask)
        output3 = input@ (self.sp_to_dense)
        print(f"{torch.allclose(output2, output)=}") # FALSE 
        print(f"{torch.allclose(output3, output)=}") # FALSE 
        print(f"{torch.allclose(output2, output3])=}") #  FALSE 
        exit(1)

        return output

#grouped_nmv_tensor.py

class NMVectorSparsifier:
    def __init__(self, n, m, tileM):
        self.n = n
        self.m = m
        self.tileM = tileM

    def __call__(self, tensor, grad_fmt=None):
        # uncomment to use magnitude-pruning -> mask, columns
        #mask, columns = nm_vector_mask_sparsify(tensor, sparsifier.n, sparsifier.m, sparsifier.tileM)

        # uncomment to use random pruning (cuSparseLt-like approach) -> mask, columns
        nrows, ncols = tensor.shape
        columns = torch.zeros(nrows//self.tileM, ncols//self.m*4, dtype=torch.int32)
        columns = columns.reshape((-1,4)) + torch.tensor([0,1,2,3], dtype=torch.int32)
        columns = columns.reshape((nrows//self.tileM, ncols//self.m*4))

        mask = torch.zeros(tensor.shape, dtype=tensor.dtype)
        m = torch.cat( (torch.tensor([1,0,1,0]), torch.zeros(self.m-4)), 0 )
        mask = mask.reshape(-1, self.tileM, self.m) + m
        mask = mask.reshape(tensor.shape)

        sp = SrNMTensor(self.n, self.m, self.tileM, tensor, mask, columns, tensor.device)
        to_dense = sp.to_dense()
        sparse_mtx = sten.SparseTensorWrapper.wrapped_from_dense(
            sp,
            tensor,
            grad_fmt,
        )

        return sparse_mtx, mask, to_dense

Hi, The above is to get mask and sparse to dense matrix and learn the code. Here is my finding, original dense matrix with mask is not the same as the sp_to_dense from the method of "SrNMTensor". also the dense with mask multiplication with input is not the same as the sparse multiplication sparse_dense_mul_dispatch. It is weird as I expect they are equal. Look forward to your reply.

Thannks!