File size: 5,967 Bytes
fd8c8b9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
#!/usr/bin/env python3
"""
Verification script to demonstrate all implemented functionality.
Run this to see layers.py and packing.py in action!
"""
import torch
import torch.nn as nn
from bitlinear import BitLinear, MultiTernaryLinear, convert_linear_to_bitlinear
from bitlinear.packing import (
pack_ternary_base3,
unpack_ternary_base3,
estimate_memory_savings,
)
def demo_bitlinear():
"""Demonstrate BitLinear layer."""
print("=" * 70)
print("1. BitLinear Layer Demo")
print("=" * 70)
# Create layer
layer = BitLinear(512, 256, bias=True)
print(f"β Created BitLinear(512 β 256)")
print(f" - W_ternary shape: {layer.W_ternary.shape}")
print(f" - Gamma shape: {layer.gamma.shape}")
print(f" - Unique weight values: {sorted(layer.W_ternary.unique().tolist())}")
# Forward pass
x = torch.randn(16, 512)
y = layer(x)
print(f"\nβ Forward pass: {x.shape} β {y.shape}")
# Convert from Linear
linear = nn.Linear(512, 256)
bitlinear = BitLinear.from_linear(linear)
print(f"β Converted nn.Linear to BitLinear")
print()
def demo_multi_ternary():
"""Demonstrate MultiTernaryLinear layer."""
print("=" * 70)
print("2. MultiTernaryLinear Layer Demo")
print("=" * 70)
# Test different k values
for k in [1, 2, 4]:
layer = MultiTernaryLinear(256, 128, k=k, bias=True)
print(f"β MultiTernaryLinear(256 β 128, k={k})")
print(f" - W_ternary shape: {layer.W_ternary.shape}")
print(f" - Gammas shape: {layer.gammas.shape}")
# Compare approximation quality
print("\nβ Approximation quality test:")
linear = nn.Linear(128, 128)
x = torch.randn(8, 128)
dense_out = linear(x)
errors = []
for k in [1, 2, 4]:
multi = MultiTernaryLinear.from_linear(linear, k=k)
ternary_out = multi(x)
error = torch.norm(dense_out - ternary_out).item()
errors.append(error)
print(f" - k={k}: reconstruction error = {error:.4f}")
print(f" - Error decreases with k: {errors[0] > errors[1] > errors[2]}")
print()
def demo_model_conversion():
"""Demonstrate model conversion utility."""
print("=" * 70)
print("3. Model Conversion Utility Demo")
print("=" * 70)
# Create a simple model
class SimpleModel(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(128, 256)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(256, 128)
self.fc3 = nn.Linear(128, 10)
def forward(self, x):
x = self.relu(self.fc1(x))
x = self.relu(self.fc2(x))
return self.fc3(x)
model = SimpleModel()
# Count Linear layers
linear_count = sum(1 for m in model.modules() if isinstance(m, nn.Linear))
print(f"β Original model: {linear_count} Linear layers")
# Convert to BitLinear
model_converted = convert_linear_to_bitlinear(model, inplace=False)
bitlinear_count = sum(1 for m in model_converted.modules() if isinstance(m, BitLinear))
print(f"β Converted model: {bitlinear_count} BitLinear layers")
# Test forward pass
x = torch.randn(4, 128)
y = model_converted(x)
print(f"β Forward pass works: {x.shape} β {y.shape}")
print()
def demo_packing():
"""Demonstrate base-3 packing."""
print("=" * 70)
print("4. Base-3 Packing Demo")
print("=" * 70)
# Create ternary weights
W = torch.tensor([
[-1, 0, 1, -1, 0],
[1, 1, -1, 0, 1],
[0, -1, 1, 1, -1],
], dtype=torch.float32)
print(f"β Original ternary weights shape: {W.shape}")
print(f" - Float32 memory: {W.numel() * 4} bytes")
# Pack
packed, original_shape = pack_ternary_base3(W)
print(f"\nβ Packed into uint8 tensor")
print(f" - Packed shape: {packed.shape}")
print(f" - Packed memory: {packed.numel()} bytes")
print(f" - Compression: {W.numel() * 4 / packed.numel():.2f}x")
# Unpack
W_unpacked = unpack_ternary_base3(packed, original_shape)
print(f"\nβ Unpacked back to ternary")
print(f" - Unpacked shape: {W_unpacked.shape}")
print(f" - Perfect round-trip: {torch.allclose(W, W_unpacked)}")
print()
def demo_memory_estimation():
"""Demonstrate memory savings estimation."""
print("=" * 70)
print("5. Memory Savings Estimation")
print("=" * 70)
configs = [
(768, 3072, 1, "Single Transformer FFN layer"),
(768, 3072, 12, "BERT-base (12 layers)"),
(1024, 4096, 24, "BERT-large (24 layers)"),
]
for in_dim, out_dim, num_layers, description in configs:
stats = estimate_memory_savings(in_dim, out_dim, num_layers)
print(f"\nβ {description}")
print(f" Configuration: {in_dim} β {out_dim} Γ {num_layers} layers")
print(f" Float32 memory: {stats['float32_bytes'] / 1e6:.2f} MB")
print(f" Packed memory: {stats['packed_bytes'] / 1e6:.2f} MB")
print(f" Savings: {stats['savings_bytes'] / 1e6:.2f} MB")
print(f" Compression: {stats['compression_ratio']:.2f}x")
print()
def main():
"""Run all demos."""
print("\n" + "=" * 70)
print(" BitLinear Implementation Verification")
print(" All functionality implemented and working!")
print("=" * 70)
print()
demo_bitlinear()
demo_multi_ternary()
demo_model_conversion()
demo_packing()
demo_memory_estimation()
print("=" * 70)
print(" β All implementations verified!")
print(" β Ready for C++/CUDA optimization")
print("=" * 70)
print()
if __name__ == "__main__":
main()
|