Repository navigation
Expand file tree
/
Copy pathspeed_test.py
More file actions
147 lines (103 loc) · 4.33 KB
/
Copy pathspeed_test.py
File metadata and controls
147 lines (103 loc) · 4.33 KB
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
import argparse
import torch
import torch.optim as optim
import time
import datasets
from network import Network, Baseline, SparseNetwork, BlockNetwork
import block_network
from typing import Union
from functions import Timer, HiddenPrints
def benchmark_sparse(net:SparseNetwork, data:datasets.Dataset):
""" Note: this will only benchmark on the CPU. """
timer = Timer()
num_correct = 0
num_total = 0
for x, y in data.test:
# Time the actual runtime
with timer.time():
y_hat = net(x)
# Untimed, verify that the prediction is accurate
num_correct += torch.sum(y == y_hat).item()
num_total += int(x.size(0))
time_taken = timer.total / len(data.test.dataset)
acc = num_correct / num_total * 100
return time_taken, acc
def benchmark_dense(net:Network, data:datasets.Dataset):
""" Note: this will benchmark using whatever device you pass in net as. """
net.eval()
timer = Timer()
num_correct = 0
num_total = 0
for x, y in data.test:
y = y.to(net.device)
# Time the actual runtime
with timer.time():
# Note that transfering x to the device is necessary, so it's timed
x = x.to(net.device)
y_hat = net(x)
# Make sure we're timing the asynchronous CUDA calls here
try: torch.cuda.synchronize()
except: pass # If CUDA is not supported, we don't care.
# Untimed, verify that the prediction is accurate
num_correct += torch.sum(y == y_hat).item()
num_total += int(x.size(0))
time_taken = timer.total / len(data.test.dataset)
acc = num_correct / num_total * 100
return time_taken, acc
def benchmark(net:Union[Network, BlockNetwork, SparseNetwork], dataset:datasets.Dataset, batch_size:int):
is_dense = isinstance(net, Network) or isinstance(net, BlockNetwork)
with torch.no_grad():
# Warm up the network (yes pytorch needs this to happen)
if is_dense:
for i in range(5):
net(dataset.train.dataset[0][0][None, ...].to(net.device).repeat(batch_size, 1, 1, 1))
# Don't leak into the benchmark time
try: torch.cuda.synchronize()
except: pass # If CUDA is not supported, we don't care.
runtime, accuracy = benchmark_dense(net, dataset) if is_dense else benchmark_sparse(net, dataset)
runtime *= 1000*1000 # s -> us
print(f'{runtime:6.1f} us / sample, {accuracy:6.2f}% Test Accuracy.')
if __name__ == '__main__':
batch_size = 64
dataset = datasets.MNIST(batch_size=batch_size)
tests = [
('CUDA Random Weights', 'weights/random_init.pth', 'cuda'),
('CUDA Pruned Weights', 'weights/pruned_iterative.pth', 'cuda'),
('CUDA Block Pruned Weights', 'weights/pruned_block_iterative.pth', 'cuda'),
(' CPU Random Weights', 'weights/random_init.pth', 'cpu'),
(' CPU Pruned Weights', 'weights/pruned_iterative.pth', 'cpu'),
(' CPU Block Pruned Weights', 'weights/pruned_block_iterative.pth', 'cpu'),
# (' CUDA Block Size = 2', 'weights/pruned_block2_iterative.pth' , 'cuda'),
# (' CUDA Block Size = 4', 'weights/pruned_block4_iterative.pth' , 'cuda'),
# (' CUDA Block Size = 8', 'weights/pruned_block8_iterative.pth' , 'cuda'),
# ('CUDA Block Size = 16', 'weights/pruned_block16_iterative.pth', 'cuda'),
# ('CUDA Block Size = 32', 'weights/pruned_block32_iterative.pth', 'cuda'),
]
print()
print(f'Benchmarking with batch_size={batch_size} and {len(dataset.test.dataset)} samples.')
print()
blocknets = []
for name, weights_path, device in tests:
with HiddenPrints(stderr=True):
net = Baseline(dataset.shape, dataset.num_classes)
net.load_weights(weights_path)
net.to(device)
print(f' ---- {name} ----')
print('Vanilla Pytorch: ', end='')
benchmark(net, dataset, batch_size)
print(' Block Network: ', end='')
block_network.BLOCK_SIZE = int(name.split(' ')[-1])
blocknet = net.blockify()
benchmark(blocknet, dataset, batch_size)
print(' Scipy Sparse: ', end='')
if device == 'cpu':
sparsenet = net.sparsify()
benchmark(sparsenet, dataset, batch_size)
else:
print(' N/A')
print()
# For whatever reason, when python garbage collects a blocknet it crashes.
# Because I don't want to debug a double free / segfault (in fucking python like wtf),
# which is likely internal to pytorch, I'm just going to make sure that blocknets never
# go out of scope and put them in this list. Fight me.
blocknets.append(blocknet)