Improve Q8_0 and Q4_0, Add Q4_1 and Q5_1
Use FP32 to do the calculations while dequantizing to improve existing Q8_0 quants and to avoid double dtype conversion. Add Q4_1 and Q5_1 dequant kernels
This commit is contained in:
+48
-12
@@ -17,13 +17,18 @@ def dequantize_tensor(tensor, dtype=torch.float16):
|
||||
return data.to(dtype)
|
||||
elif qtype in dequantize_functions:
|
||||
# this is the main pytorch op
|
||||
return dequantize(data, qtype, oshape).to(dtype)
|
||||
if False and dtype == torch.bfloat16: # disabled, lower quality
|
||||
# dequant directly in native BF16
|
||||
return dequantize(data, qtype, oshape, dtype)
|
||||
else:
|
||||
# dequant in fp32, convert to target
|
||||
return dequantize(data, qtype, oshape, dtype=torch.float32).to(dtype)
|
||||
else:
|
||||
# this is incredibly slow
|
||||
new = gguf.quants.dequantize(data.cpu().numpy(), qtype)
|
||||
return torch.from_numpy(new).to(data.device, dtype=dtype)
|
||||
|
||||
def dequantize(data, qtype, oshape):
|
||||
def dequantize(data, qtype, oshape, dtype=None):
|
||||
"""
|
||||
Dequantize tensor back to usable shape/dtype
|
||||
"""
|
||||
@@ -36,7 +41,7 @@ def dequantize(data, qtype, oshape):
|
||||
|
||||
n_blocks = rows.numel() // type_size
|
||||
blocks = rows.reshape((n_blocks, type_size))
|
||||
blocks = dequantize_blocks(blocks, block_size, type_size)
|
||||
blocks = dequantize_blocks(blocks, block_size, type_size, dtype)
|
||||
return blocks.reshape(oshape)
|
||||
|
||||
def to_uint32(x):
|
||||
@@ -44,19 +49,36 @@ def to_uint32(x):
|
||||
x = x.view(torch.uint8).to(torch.int32)
|
||||
return (x[:, 0] | x[:, 1] << 8 | x[:, 2] << 16 | x[:, 3] << 24).unsqueeze(1)
|
||||
|
||||
def dequantize_blocks_Q8_0(blocks, block_size, type_size):
|
||||
d = blocks[:, :2].view(torch.float16)
|
||||
x = blocks[:, 2:].view(torch.int8).to(torch.float16)
|
||||
return (x * d)
|
||||
def dequantize_blocks_Q8_0(blocks, block_size, type_size, dtype=None):
|
||||
d = blocks[:, :2].view(torch.float16).to(dtype)
|
||||
x = blocks[:, 2:].view(torch.int8)
|
||||
return (d * x)
|
||||
|
||||
def dequantize_blocks_Q5_0(blocks, block_size, type_size):
|
||||
def dequantize_blocks_Q5_1(blocks, block_size, type_size, dtype=None):
|
||||
n_blocks = blocks.shape[0]
|
||||
|
||||
d = blocks[:, :2]
|
||||
d = blocks[:, :2].view(torch.float16).to(dtype)
|
||||
m = blocks[:, 2:4].view(torch.float16).to(dtype)
|
||||
qh = blocks[:, 4:8]
|
||||
qs = blocks[:, 8: ]
|
||||
|
||||
qh = to_uint32(qh)
|
||||
|
||||
qh = qh.reshape((n_blocks, 1)) >> torch.arange(32, device=d.device, dtype=torch.int32).reshape(1, 32)
|
||||
ql = qs.reshape((n_blocks, -1, 1, block_size // 2)) >> torch.tensor([0, 4], device=d.device, dtype=torch.uint8).reshape(1, 1, 2, 1)
|
||||
qh = (qh & 1).to(torch.uint8)
|
||||
ql = (ql & 0x0F).reshape((n_blocks, -1))
|
||||
|
||||
qs = (ql | (qh << 4))
|
||||
return (d * qs) + m
|
||||
|
||||
def dequantize_blocks_Q5_0(blocks, block_size, type_size, dtype=None):
|
||||
n_blocks = blocks.shape[0]
|
||||
|
||||
d = blocks[:, :2].view(torch.float16).to(dtype)
|
||||
qh = blocks[:, 2:6]
|
||||
qs = blocks[:, 6: ]
|
||||
|
||||
d = d.view(torch.float16).to(torch.float32)
|
||||
qh = to_uint32(qh)
|
||||
|
||||
qh = qh.reshape(n_blocks, 1) >> torch.arange(32, device=d.device, dtype=torch.int32).reshape(1, 32)
|
||||
@@ -68,10 +90,22 @@ def dequantize_blocks_Q5_0(blocks, block_size, type_size):
|
||||
qs = (ql | (qh << 4)).to(torch.int8) - 16
|
||||
return (d * qs)
|
||||
|
||||
def dequantize_blocks_Q4_0(blocks, block_size, type_size):
|
||||
def dequantize_blocks_Q4_1(blocks, block_size, type_size, dtype=None):
|
||||
n_blocks = blocks.shape[0]
|
||||
|
||||
d = blocks[:, :2].view(torch.float16)
|
||||
d = blocks[:, :2].view(torch.float16).to(dtype)
|
||||
m = blocks[:, 2:4].view(torch.float16).to(dtype)
|
||||
qs = blocks[:, 4: ]
|
||||
|
||||
qs = qs.reshape((n_blocks, -1, 1, block_size // 2)) >> torch.tensor([0, 4], device=d.device, dtype=torch.uint8).reshape(1, 1, 2, 1)
|
||||
qs = (qs & 0x0F).reshape(n_blocks, -1)
|
||||
|
||||
return (d * qs) + m
|
||||
|
||||
def dequantize_blocks_Q4_0(blocks, block_size, type_size, dtype=None):
|
||||
n_blocks = blocks.shape[0]
|
||||
|
||||
d = blocks[:, :2].view(torch.float16).to(dtype)
|
||||
qs = blocks[:, 2:]
|
||||
|
||||
qs = qs.reshape((n_blocks, -1, 1, block_size // 2)) >> torch.tensor([0, 4], device=d.device, dtype=torch.uint8).reshape((1, 1, 2, 1))
|
||||
@@ -80,6 +114,8 @@ def dequantize_blocks_Q4_0(blocks, block_size, type_size):
|
||||
|
||||
dequantize_functions = {
|
||||
gguf.GGMLQuantizationType.Q8_0: dequantize_blocks_Q8_0,
|
||||
gguf.GGMLQuantizationType.Q5_1: dequantize_blocks_Q5_1,
|
||||
gguf.GGMLQuantizationType.Q5_0: dequantize_blocks_Q5_0,
|
||||
gguf.GGMLQuantizationType.Q4_1: dequantize_blocks_Q4_1,
|
||||
gguf.GGMLQuantizationType.Q4_0: dequantize_blocks_Q4_0,
|
||||
}
|
||||
|
||||
@@ -72,7 +72,8 @@ class GGMLOps(comfy.ops.disable_weight_init):
|
||||
self.parameters_manual_cast = torch.float32
|
||||
|
||||
def forward(self, x):
|
||||
weight, bias = self.get_weights(x.dtype)
|
||||
x = torch.nn.functional.linear(x, weight, bias)
|
||||
del weight, bias
|
||||
with torch.no_grad():
|
||||
weight, bias = self.get_weights(x.dtype)
|
||||
x = torch.nn.functional.linear(x, weight, bias)
|
||||
del weight, bias
|
||||
return x
|
||||
|
||||
Reference in New Issue
Block a user