-
Notifications
You must be signed in to change notification settings - Fork 5
/
cudnnFilter.go
219 lines (192 loc) · 6.5 KB
/
cudnnFilter.go
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
package gocudnn
/*
#include <cudnn.h>
*/
import "C"
import (
"fmt"
"runtime"
"github.com/dereklstinson/cutil"
)
//FilterD is the struct holding discriptor information for cudnnFilterDescriptor_t
type FilterD struct {
descriptor C.cudnnFilterDescriptor_t
gogc bool
dims C.int
}
const filterdescriptorallndtest = true
func (f *FilterD) String() string {
dtype, frmt, dims, err := f.Get()
if err != nil {
return fmt.Sprintf("FilterDescriptor{error in pulling values")
}
return fmt.Sprintf("FilterDescriptor{\n%v,\n%v,\nShape : %v,\n}\n", frmt, dtype, dims)
}
/*
//TensorD returns the tensor descripter of FilterD. //Kind of a hack
func (f *FilterD) TensorD() *TensorD {
return f.tensorD
}
*/
//CreateFilterDescriptor creates a filter distriptor
func CreateFilterDescriptor() (*FilterD, error) {
flt := new(FilterD)
err := Status(C.cudnnCreateFilterDescriptor(&flt.descriptor)).error("CreateFilterDescriptor()")
if setfinalizer || flt.gogc {
runtime.SetFinalizer(flt, destroyfilterdescriptor)
}
return flt, err
}
//Set sets the filter descriptor
//Like with TensorD the shape put in will be not like cudnn. cudnn will always take the shape NCHW and switch the dims
// and change the tensor stride in order to change the format. gocudnn will change the dims to a format that cudnn likes.
//if the format is nhwc.
//
// Basic 4D filter
//
// The Basic NCHW shape is shape[0] = # of output feature maps
// shape[1] = # of input feature maps
// shape[2] = height of each filter
// shape[3] = width of each input filter
//
// The Basic NHWC shape is shape[0] = # of output feature maps
// shape[1] = height of each filter
// shape[2] = width of each input filter
// shape[3] = # of input feature maps
//
// Basic ND filter
//
// The Basic NCHW shape is shape[0] = # of output feature maps
// shape[1] = # of input feature maps
// shape[.] = feature dims
// shape[N-1] = feature dims
//
// The Basic NHWC shape is shape[0] = # of output feature maps
// shape[.] = feature dims
// shape[N-1] = # of input feature maps
func (f *FilterD) Set(dtype DataType, format TensorFormat, shape []int32) error {
cshape := int32Tocint(shape)
f.dims = (C.int)(len(shape))
fflg := format
switch format {
case fflg.NHWC():
cshapecopy := int32Tocint(shape)
cshape[1] = cshapecopy[len(cshape)-1]
for i := 2; i < len(cshape); i++ {
cshape[i] = cshapecopy[i-1]
}
}
return Status(C.cudnnSetFilterNdDescriptor(f.descriptor, dtype.c(), format.c(), f.dims, &cshape[0])).error(" (f *FilterD) Set")
}
//Get returns a copy of the ConvolutionD
func (f *FilterD) Get() (dtype DataType, frmt TensorFormat, shape []int32, err error) {
if f.dims == 0 {
f.dims = C.CUDNN_DIM_MAX
shape = make([]int32, f.dims)
var actual C.int
err = Status(C.cudnnGetFilterNdDescriptor(f.descriptor, f.dims, dtype.cptr(), frmt.cptr(), &actual, (*C.int)(&shape[0]))).error(" (f *FilterD) Get()")
flg := frmt
f.dims = actual
shape = shape[:f.dims]
switch frmt {
case flg.NHWC():
shapecpy := make([]int32, len(shape))
copy(shapecpy, shape)
shape[len(shape)-1] = shapecpy[1]
for i := 2; i < len(shape); i++ {
shape[i-1] = shapecpy[i]
}
}
return dtype, frmt, shape, err
}
var holder C.int
shape = make([]int32, f.dims)
err = Status(C.cudnnGetFilterNdDescriptor(f.descriptor, f.dims, dtype.cptr(), frmt.cptr(), &holder, (*C.int)(&shape[0]))).error(" (f *FilterD) Get()")
flg := frmt
shape = shape[:f.dims]
switch frmt {
case flg.NHWC():
shapecpy := make([]int32, len(shape))
copy(shapecpy, shape)
shape[len(shape)-1] = shapecpy[1]
for i := 2; i < len(shape); i++ {
shape[i-1] = shapecpy[i]
}
}
return dtype, frmt, shape, err
}
//GetSizeInBytes returns the size in bytes for the filter
func (f *FilterD) GetSizeInBytes() (uint, error) {
dtype, _, shape, err := f.Get()
if err != nil {
return 0, err
}
return FindSizeTfromVol(shape, dtype), nil
}
//Destroy Destroys Filter Descriptor if GC is not set. if GC is set then it won't do anything
func (f *FilterD) Destroy() error {
if f.gogc || setfinalizer {
return nil
}
return destroyfilterdescriptor(f)
}
func destroyfilterdescriptor(f *FilterD) error {
err := Status(C.cudnnDestroyFilterDescriptor(f.descriptor)).error(" destroyfilterdescriptor(f *FilterD)")
if err != nil {
return err
}
f = nil
return nil
}
//ReorderFilterBias -reorders the filter and bias values. It can be used to enhance
//the inference time by separating the reordering operation from convolution.
//
//For example, convolutions in a neural network of multiple layers can require
//reordering of kernels at every layer, which can take up a significant fraction
//of the total inference time. Using this function, the reordering can be done one
//time on the filter and bias data followed by the convolution operations at the multiple
//layers, thereby enhancing the inference time.
func (f *FilterD) ReorderFilterBias(h *Handle,
r Reorder,
filtersrc, reorderfilterdest cutil.Mem,
reorderbias bool,
biassrc, reorderbiasdest cutil.Mem) error {
var robias C.int
if reorderbias {
robias = 1
}
if h.w != nil {
return h.w.Work(func() error {
return Status(C.cudnnReorderFilterAndBias(h.x, f.descriptor,
r.c(), filtersrc.Ptr(), reorderfilterdest.Ptr(),
robias, biassrc.Ptr(), reorderbiasdest.Ptr())).error("(f *FilterD) ReorderFilterBias")
})
}
return Status(C.cudnnReorderFilterAndBias(h.x, f.descriptor,
r.c(), filtersrc.Ptr(), reorderfilterdest.Ptr(),
robias, biassrc.Ptr(), reorderbiasdest.Ptr())).error("(f *FilterD) ReorderFilterBias")
}
/*
//Set4DEx sets the filter up like nd but using a 4d
func (f *FilterD) Set4D(dtype DataType, format TensorFormat, shape []int32) error {
l := len(shape)
f.flags = t4d
f.dims = (C.int)(len(shape))
if l != 4 {
return errors.New("length of shape needs to be 4")
}
cshape := int32Tocint(shape)
if filterdescriptorallndtest{
return Status(C.cudnnSetFilterNdDescriptor(f.descriptor, dtype.c(), format.c(), f.dims, &cshape[0])).error("(*FilterD)SetND")
}
return Status(C.cudnnSetFilter4dDescriptor(f.descriptor, dtype.c(), format.c(), cshape[0], cshape[1], cshape[2], cshape[3])).error("(*FilterD)Set4DEx")
}
*/
/*
//Set4D sets the filter like normal
func (f *FilterD) Set4D(dtype DataType, format TensorFormat, k, c, h, w int32) error {
f.flags = t4d
f.dims = (C.int)(2)
return Status(C.cudnnSetFilter4dDescriptor(f.descriptor, dtype.c(), format.c(), (C.int)(k), (C.int)(c), (C.int)(h), (C.int)(w))).error("(*FilterD)Set4DEx")
}
*/