1+ from contextlib import contextmanager
12import torch
23import torch .nn .functional as F
34import triton
5+ import torch .nn as nn
46
57import ops .ninetoothed .torch
68import ops .triton .torch
9+ import ntops .torch
10+
11+ class Conv2d (nn .Module ):
12+ conv2d = None
13+
14+ def __init__ (self , other ):
15+ super ().__init__ ()
16+
17+ self .__dict__ = other .__dict__
18+
19+ def forward (self , input ):
20+ def _pair (x ):
21+ return x if isinstance (x , (tuple , list )) else (x , x )
22+
23+ stride = _pair (self .stride )
24+ padding = _pair (self .padding )
25+ dilation = _pair (self .dilation )
26+
27+ return type (self ).conv2d (
28+ input ,
29+ self .weight ,
30+ self .bias ,
31+ stride = stride ,
32+ padding = padding ,
33+ dilation = dilation ,
34+ groups = self .groups ,
35+ )
36+
37+ @contextmanager
38+ def conv2d_backend (backend_name ):
39+ _prev_impl = Conv2d .conv2d
40+ if backend_name == "ninetoothed" :
41+ impl = ntops .torch .conv2d
42+ elif backend_name == "torch" :
43+ impl = F .conv2d
44+ else :
45+ raise ValueError (f"unknown backend: `{ backend_name } `" )
46+
47+ Conv2d .conv2d = impl
48+
49+ try :
50+ yield
51+ finally :
52+ Conv2d .conv2d = _prev_impl
753
854if __name__ == "__main__" :
955 torch .manual_seed (0 )
1056
11- n , c , h , w = 4 , 3 , 224 , 224
12- k , _ , r , s = 8 , c , 3 , 3
57+ n , c , h , w = 2 , 3 , 112 , 112
58+ k , _ , r , s = 4 , c , 3 , 3
1359 dtype = torch .float16
1460 device = "cuda"
1561
16- input = torch .randn (n , c , h , w , dtype = dtype , device = device )
17- filter = torch .randn (k , c , r , s , dtype = dtype , device = device )
18-
19- ninetoothed_output = ops .ninetoothed .torch .conv2d (input , filter )
20- torch_output = F .conv2d (input , filter )
21- triton_output = ops .triton .torch .conv2d (input , filter )
62+ input = torch .randn ((n , c , h , w ), dtype = dtype , device = device )
63+ weight = torch .randn ((k , c , r , s ), dtype = dtype , device = device )
64+ bias = torch .randn ((k ,), dtype = dtype , device = device )
65+ stride = 3
66+ dilation = 1
67+
68+ ninetoothed_output = ops .ninetoothed .torch .conv2d (
69+ input , weight , bias = bias , stride = stride , dilation = dilation
70+ )
71+ reference_output = F .conv2d (
72+ input , weight , bias = bias , stride = stride , dilation = dilation
73+ )
2274
75+
2376 print (ninetoothed_output )
24- print (torch_output )
25- print ( triton_output )
77+ print (reference_output )
78+
2679
27- if torch .allclose (ninetoothed_output , torch_output , atol = 0.01 , rtol = 0.01 ):
80+ if torch .allclose (ninetoothed_output , reference_output , atol = 0.01 , rtol = 0.01 ):
2881 print ("✅ NineToothed and PyTorch match." )
2982 else :
3083 print ("❌ NineToothed and PyTorch differ." )
31- if torch .allclose (ninetoothed_output , triton_output , atol = 0 , rtol = 0 ):
32- print ("✅ NineToothed and Triton match." )
33- else :
34- print ("❌ NineToothed and Triton differ." )
35-
36- @triton .testing .perf_report (
37- triton .testing .Benchmark (
38- x_names = ["n" ],
39- x_vals = [2 ** i for i in range (1 , 11 )],
40- x_log = True ,
41- line_arg = "provider" ,
42- line_vals = ["ninetoothed" , "torch" , "triton" ],
43- line_names = ["NineToothed" , "PyTorch" , "Triton" ],
44- styles = [("blue" , "-" ), ("green" , "-" ), ("orange" , "-" )],
45- ylabel = "ms" ,
46- plot_name = "conv2d-performance" ,
47- args = {},
48- )
49- )
50- def benchmark (n , provider ):
51- _ , c , h , w = n , 512 , 14 , 14
52- k , _ , r , s = 512 , c , 3 , 3
53-
54- input = torch .randn ((n , c , h , w ), dtype = dtype , device = device )
55- filter = torch .randn ((k , c , r , s ), dtype = dtype , device = device )
56-
57- ninetoothed_output = ops .ninetoothed .torch .conv2d (input , filter )
58- torch_output = F .conv2d (input , filter )
59- triton_output = ops .triton .torch .conv2d (input , filter )
60-
61- assert torch .allclose (ninetoothed_output , torch_output , atol = 0.01 , rtol = 0.01 )
62- assert torch .allclose (ninetoothed_output , triton_output , atol = 0 , rtol = 0 )
63-
64- if provider == "ninetoothed" :
65- ms = triton .testing .do_bench (
66- lambda : ops .ninetoothed .torch .conv2d (input , filter )
67- )
68- elif provider == "torch" :
69- ms = triton .testing .do_bench (lambda : F .conv2d (input , filter ))
70- elif provider == "triton" :
71- ms = triton .testing .do_bench (lambda : ops .triton .torch .conv2d (input , filter ))
72-
73- return ms
74-
75- benchmark .run (show_plots = True , print_data = True , save_path = "." )
84+
0 commit comments