cumo 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +590 -152
- data/CHANGELOG.md +29 -0
- data/README.md +140 -0
- data/bench/cumo_probe.rb +1 -1
- data/cumo.gemspec +1 -1
- data/ext/cumo/cuda/cudnn.c +18 -0
- data/ext/cumo/cuda/cudnn_impl.cpp +60 -14
- data/ext/cumo/cuda/driver.c +11 -9
- data/ext/cumo/cuda/runtime.c +56 -0
- data/ext/cumo/cumo.c +4 -0
- data/ext/cumo/extconf.rb +2 -0
- data/ext/cumo/include/cumo/bit_reduce_kernel.h +6 -6
- data/ext/cumo/include/cumo/cuda/cudnn.h +40 -0
- data/ext/cumo/include/cumo/cuda/runtime.h +2 -0
- data/ext/cumo/include/cumo/intern.h +9 -0
- data/ext/cumo/include/cumo/narray.h +1 -0
- data/ext/cumo/include/cumo/reduce_kernel.h +32 -28
- data/ext/cumo/include/cumo/row_kernel.h +170 -0
- data/ext/cumo/include/cumo/row_method.h +48 -0
- data/ext/cumo/include/cumo/template_kernel.h +26 -0
- data/ext/cumo/include/cumo/types/bf16_def.h +82 -0
- data/ext/cumo/include/cumo/types/bf16_def_kernel.h +28 -0
- data/ext/cumo/include/cumo/types/bf16_macro.h +186 -0
- data/ext/cumo/include/cumo/types/bf16_macro_kernel.h +213 -0
- data/ext/cumo/include/cumo/types/bfloat.h +22 -0
- data/ext/cumo/include/cumo/types/bfloat_kernel.h +16 -0
- data/ext/cumo/include/cumo/types/bit.h +2 -0
- data/ext/cumo/include/cumo/types/bit_kernel.h +2 -0
- data/ext/cumo/include/cumo/types/complex_macro.h +2 -0
- data/ext/cumo/include/cumo/types/complex_macro_kernel.h +2 -0
- data/ext/cumo/include/cumo/types/float_def.h +8 -0
- data/ext/cumo/include/cumo/types/float_def_kernel.h +8 -0
- data/ext/cumo/include/cumo/types/float_macro.h +19 -17
- data/ext/cumo/include/cumo/types/float_macro_kernel.h +19 -19
- data/ext/cumo/include/cumo/types/half_macro.h +15 -17
- data/ext/cumo/include/cumo/types/half_macro_kernel.h +15 -0
- data/ext/cumo/include/cumo/types/robj_macro.h +2 -0
- data/ext/cumo/include/cumo/types/xint_macro.h +2 -6
- data/ext/cumo/include/cumo/types/xint_macro_kernel.h +2 -0
- data/ext/cumo/include/cumo.h +2 -2
- data/ext/cumo/narray/gen/def/bfloat.rb +56 -0
- data/ext/cumo/narray/gen/def/bit.rb +11 -1
- data/ext/cumo/narray/gen/def/dcomplex.rb +11 -1
- data/ext/cumo/narray/gen/def/dfloat.rb +10 -1
- data/ext/cumo/narray/gen/def/hfloat.rb +10 -1
- data/ext/cumo/narray/gen/def/int16.rb +11 -1
- data/ext/cumo/narray/gen/def/int32.rb +11 -1
- data/ext/cumo/narray/gen/def/int64.rb +11 -1
- data/ext/cumo/narray/gen/def/int8.rb +11 -1
- data/ext/cumo/narray/gen/def/robject.rb +11 -1
- data/ext/cumo/narray/gen/def/scomplex.rb +11 -1
- data/ext/cumo/narray/gen/def/sfloat.rb +10 -1
- data/ext/cumo/narray/gen/def/uint16.rb +11 -1
- data/ext/cumo/narray/gen/def/uint32.rb +11 -1
- data/ext/cumo/narray/gen/def/uint64.rb +11 -1
- data/ext/cumo/narray/gen/def/uint8.rb +11 -1
- data/ext/cumo/narray/gen/narray_def.rb +0 -5
- data/ext/cumo/narray/gen/spec.rb +11 -14
- data/ext/cumo/narray/gen/tmpl/accum_arg.c +1 -1
- data/ext/cumo/narray/gen/tmpl/accum_binary_kernel.cu +9 -9
- data/ext/cumo/narray/gen/tmpl/accum_index.c +1 -1
- data/ext/cumo/narray/gen/tmpl/batch_norm.c +3 -3
- data/ext/cumo/narray/gen/tmpl/batch_norm_backward.c +3 -3
- data/ext/cumo/narray/gen/tmpl/complex_accum_kernel.cu +15 -5
- data/ext/cumo/narray/gen/tmpl/conv.c +88 -121
- data/ext/cumo/narray/gen/tmpl/conv_grad_w.c +89 -81
- data/ext/cumo/narray/gen/tmpl/conv_transpose.c +88 -121
- data/ext/cumo/narray/gen/tmpl/cum.c +8 -7
- data/ext/cumo/narray/gen/tmpl/cum_kernel.cu +7 -6
- data/ext/cumo/narray/gen/tmpl/fixed_batch_norm.c +3 -3
- data/ext/cumo/narray/gen/tmpl/float_accum_kernel.cu +22 -10
- data/ext/cumo/narray/gen/tmpl/gemm.c +11 -35
- data/ext/cumo/narray/gen/tmpl/layer_norm.c +91 -0
- data/ext/cumo/narray/gen/tmpl/layer_norm_kernel.cu +54 -0
- data/ext/cumo/narray/gen/tmpl/lib.c +1 -0
- data/ext/cumo/narray/gen/tmpl/lib_kernel.cu +1 -0
- data/ext/cumo/narray/gen/tmpl/median.c +1 -1
- data/ext/cumo/narray/gen/tmpl/poly.c +0 -3
- data/ext/cumo/narray/gen/tmpl/poly_kernel.cu +1 -1
- data/ext/cumo/narray/gen/tmpl/pooling_backward.c +2 -1
- data/ext/cumo/narray/gen/tmpl/pooling_forward.c +2 -1
- data/ext/cumo/narray/gen/tmpl/rand.c +9 -9
- data/ext/cumo/narray/gen/tmpl/rand_kernel.cu +9 -9
- data/ext/cumo/narray/gen/tmpl/rand_norm.c +4 -4
- data/ext/cumo/narray/gen/tmpl/rand_norm_kernel.cu +7 -7
- data/ext/cumo/narray/gen/tmpl/real_accum_kernel.cu +6 -6
- data/ext/cumo/narray/gen/tmpl/softmax.c +56 -0
- data/ext/cumo/narray/gen/tmpl/softmax_kernel.cu +157 -0
- data/ext/cumo/narray/gen/tmpl/sort.c +9 -32
- data/ext/cumo/narray/gen/tmpl/sort_index.c +16 -95
- data/ext/cumo/narray/gen/tmpl/store_array.c +12 -9
- data/ext/cumo/narray/gen/tmpl_bit/mask.c +11 -11
- data/ext/cumo/narray/gen/tmpl_bit/store_array.c +5 -9
- data/ext/cumo/narray/gen/tmpl_bit/where.c +50 -11
- data/ext/cumo/narray/gen/tmpl_bit/where2.c +11 -12
- data/ext/cumo/narray/gen/tmpl_bit/where_kernel.cu +1 -2
- data/ext/cumo/narray/index.c +2 -1
- data/ext/cumo/narray/math.c +2 -0
- data/ext/cumo/narray/narray.c +27 -1
- data/ext/cumo/narray/ndloop.c +73 -4
- data/ext/cumo/narray/sort_kernel.cu +61 -41
- data/ext/cumo/narray/struct.c +3 -0
- data/lib/cumo/cuda/cudnn.rb +1 -1
- data/lib/cumo/narray/extra.rb +2 -2
- data/test/bfloat_test.rb +238 -0
- data/test/cuda/memory_pool_test.rb +8 -7
- data/test/cuda/runtime_test.rb +25 -0
- data/test/cudnn_test.rb +108 -24
- data/test/extra_test.rb +1 -1
- data/test/fused_test.rb +311 -0
- data/test/math_test.rb +77 -2
- data/test/narray_alt_coverage_test.rb +1 -0
- data/test/narray_test.rb +70 -10
- data/test/test_helper.rb +1 -0
- metadata +20 -4
- data/ext/cumo/narray/gen/tmpl/qsort.c +0 -205
data/ext/cumo/narray/gen/spec.rb
CHANGED
|
@@ -59,7 +59,7 @@ if (is_float || is_complex) && !is_object
|
|
|
59
59
|
def_id "gemm"
|
|
60
60
|
end
|
|
61
61
|
# cudnn
|
|
62
|
-
if is_float && !is_complex && !is_object
|
|
62
|
+
if is_float && !is_complex && !is_object && !cudnn_dtype.empty?
|
|
63
63
|
def_id "conv"
|
|
64
64
|
def_id "conv_transpose"
|
|
65
65
|
def_id "conv_grad_w"
|
|
@@ -128,6 +128,7 @@ def_method "store" do
|
|
|
128
128
|
store_from "SComplex", "cumo_scomplex", "m_from_scomplex"
|
|
129
129
|
end
|
|
130
130
|
store_from "HFloat", "cumo_half", "m_from_half"
|
|
131
|
+
store_from "BFloat", "cumo_bfloat", "m_from_bfloat"
|
|
131
132
|
store_from "DFloat", "double", "m_from_real"
|
|
132
133
|
store_from "SFloat", "float", "m_from_real"
|
|
133
134
|
store_from "Int64", "int64_t", "m_from_int64"
|
|
@@ -367,7 +368,7 @@ if (is_float || is_complex) && !is_object
|
|
|
367
368
|
end
|
|
368
369
|
|
|
369
370
|
# cudnn
|
|
370
|
-
if is_float && !is_complex && !is_object
|
|
371
|
+
if is_float && !is_complex && !is_object && !cudnn_dtype.empty?
|
|
371
372
|
def_method "conv"
|
|
372
373
|
def_method "conv_transpose" # conv_backward_data
|
|
373
374
|
def_method "conv_grad_w" # conv_backward_filter
|
|
@@ -378,6 +379,12 @@ if is_float && !is_complex && !is_object
|
|
|
378
379
|
def_method "pooling_backward"
|
|
379
380
|
end
|
|
380
381
|
|
|
382
|
+
# fused
|
|
383
|
+
if is_float && !is_complex && !is_object
|
|
384
|
+
def_method "layer_norm"
|
|
385
|
+
def_method "softmax"
|
|
386
|
+
end
|
|
387
|
+
|
|
381
388
|
# rmsdev
|
|
382
389
|
# prod
|
|
383
390
|
|
|
@@ -400,19 +407,7 @@ end
|
|
|
400
407
|
def_method "poly"
|
|
401
408
|
|
|
402
409
|
if is_comparable && !is_object
|
|
403
|
-
if is_float
|
|
404
|
-
qsort type_name, "dtype", "*(dtype*)", "_prnan"
|
|
405
|
-
qsort type_name, "dtype", "*(dtype*)", "_ignan"
|
|
406
|
-
else
|
|
407
|
-
qsort type_name, "dtype", "*(dtype*)"
|
|
408
|
-
end
|
|
409
410
|
def_method "sort"
|
|
410
|
-
if is_float
|
|
411
|
-
qsort type_name + "_index", "dtype*", "**(dtype**)", "_prnan"
|
|
412
|
-
qsort type_name + "_index", "dtype*", "**(dtype**)", "_ignan"
|
|
413
|
-
else
|
|
414
|
-
qsort type_name + "_index", "dtype*", "**(dtype**)"
|
|
415
|
-
end
|
|
416
411
|
def_method "sort_index"
|
|
417
412
|
def_method "median"
|
|
418
413
|
end
|
|
@@ -461,6 +456,8 @@ def_module do
|
|
|
461
456
|
math "hypot", 2
|
|
462
457
|
math "erf"
|
|
463
458
|
math "erfc"
|
|
459
|
+
math "gelu"
|
|
460
|
+
math "gelu_tanh"
|
|
464
461
|
math "log1p"
|
|
465
462
|
math "expm1"
|
|
466
463
|
math "ldexp", 2
|
|
@@ -38,7 +38,7 @@ static void
|
|
|
38
38
|
<%=name%>. Returns an index of the <%=name[3..5]%>imum value along the axis. See also `<%=name[3..5]%>_index`.
|
|
39
39
|
<% if is_float %>
|
|
40
40
|
@overload <%=name%>(axis:nil, nan:false)
|
|
41
|
-
@param [TrueClass] nan If true, apply NaN-aware algorithm (return NaN
|
|
41
|
+
@param [TrueClass] nan If true, apply NaN-aware algorithm (return NaN position if exist).
|
|
42
42
|
<% else %>
|
|
43
43
|
@overload <%=name%>(axis:nil)
|
|
44
44
|
<% end %>
|
|
@@ -14,19 +14,19 @@
|
|
|
14
14
|
|
|
15
15
|
// The product is never an array of its own: MapIn takes one element of each
|
|
16
16
|
// operand, which is what a zip reduction hands it. The accumulator stays dtype
|
|
17
|
-
// rather than widening, as the host loop it replaces did, except for
|
|
18
|
-
//
|
|
17
|
+
// rather than widening, as the host loop it replaces did, except for the
|
|
18
|
+
// types that set an accumulator of their own.
|
|
19
19
|
struct <%="cumo_#{type_name}_#{name}#{nan}_impl"%> {
|
|
20
|
-
<%
|
|
21
|
-
__device__
|
|
22
|
-
__device__
|
|
20
|
+
<% unless acc_type.empty? %>
|
|
21
|
+
__device__ <%=acc_type%> Identity(int64_t /*index*/) { return <%=acc_zero%>; }
|
|
22
|
+
__device__ <%=acc_type%> MapIn(dtype x, dtype y, int64_t /*index*/) {
|
|
23
23
|
<% if nan == '_nan' %>
|
|
24
|
-
if (!not_nan(x) || !not_nan(y)) { return
|
|
24
|
+
if (!not_nan(x) || !not_nan(y)) { return <%=acc_zero%>; }
|
|
25
25
|
<% end %>
|
|
26
|
-
return
|
|
26
|
+
return <%=to_acc%>(x) * <%=to_acc%>(y);
|
|
27
27
|
}
|
|
28
|
-
__device__ void Reduce(
|
|
29
|
-
__device__ dtype MapOut(
|
|
28
|
+
__device__ void Reduce(<%=acc_type%> next, <%=acc_type%>& accum) { accum = next + accum; }
|
|
29
|
+
__device__ dtype MapOut(<%=acc_type%> accum) { return <%=from_acc%>(accum); }
|
|
30
30
|
<% else %>
|
|
31
31
|
__device__ dtype Identity(int64_t /*index*/) { return m_zero; }
|
|
32
32
|
__device__ dtype MapIn(dtype x, dtype y, int64_t /*index*/) {
|
|
@@ -39,7 +39,7 @@ static void
|
|
|
39
39
|
<%=name%>. Return an index of result.
|
|
40
40
|
<% if is_float %>
|
|
41
41
|
@overload <%=name%>(axis:nil, nan:false)
|
|
42
|
-
@param [TrueClass] nan If true, apply NaN-aware algorithm (return NaN
|
|
42
|
+
@param [TrueClass] nan If true, apply NaN-aware algorithm (return NaN position if exist).
|
|
43
43
|
<% else %>
|
|
44
44
|
@overload <%=name%>(axis:nil)
|
|
45
45
|
<% end %>
|
|
@@ -148,18 +148,18 @@ static VALUE
|
|
|
148
148
|
}
|
|
149
149
|
y_ptr = cumo_na_get_offset_pointer_for_write(y);
|
|
150
150
|
|
|
151
|
+
mode = cumo_cuda_cudnn_GetBatchNormMode(axis_ndim, int_axis);
|
|
152
|
+
handle = cumo_cuda_cudnn_handle();
|
|
153
|
+
|
|
151
154
|
status = cumo_cuda_cudnn_CreateTensorDescriptor(&x_desc, x_cont, cudnn_dtype);
|
|
152
155
|
if (status != CUDNN_STATUS_SUCCESS) goto BATCH_NORM_ERROR;
|
|
153
156
|
|
|
154
|
-
mode = cumo_cuda_cudnn_GetBatchNormMode(axis_ndim, int_axis);
|
|
155
157
|
status = cumo_cuda_cudnn_CreateBNTensorDescriptor(&bn_desc, x_desc, mode);
|
|
156
158
|
if (status != CUDNN_STATUS_SUCCESS) goto BATCH_NORM_ERROR;
|
|
157
159
|
// cuDNN derives the parameter descriptor as float for a half x and as x's
|
|
158
160
|
// own type otherwise, and the checks above hold every parameter to exactly
|
|
159
161
|
// that class, so none of them needs a cast.
|
|
160
162
|
|
|
161
|
-
handle = cumo_cuda_cudnn_handle();
|
|
162
|
-
|
|
163
163
|
status = cudnnBatchNormalizationForwardTraining(
|
|
164
164
|
handle,
|
|
165
165
|
mode,
|
|
@@ -133,18 +133,18 @@ static VALUE
|
|
|
133
133
|
}
|
|
134
134
|
gbeta_ptr = cumo_na_get_offset_pointer_for_write(gbeta);
|
|
135
135
|
|
|
136
|
+
mode = cumo_cuda_cudnn_GetBatchNormMode(axis_ndim, int_axis);
|
|
137
|
+
handle = cumo_cuda_cudnn_handle();
|
|
138
|
+
|
|
136
139
|
status = cumo_cuda_cudnn_CreateTensorDescriptor(&x_desc, x_cont, cudnn_dtype);
|
|
137
140
|
if (status != CUDNN_STATUS_SUCCESS) goto BATCH_NORM_BACKWARD_ERROR;
|
|
138
141
|
|
|
139
|
-
mode = cumo_cuda_cudnn_GetBatchNormMode(axis_ndim, int_axis);
|
|
140
142
|
status = cumo_cuda_cudnn_CreateBNTensorDescriptor(&bn_desc, x_desc, mode);
|
|
141
143
|
if (status != CUDNN_STATUS_SUCCESS) goto BATCH_NORM_BACKWARD_ERROR;
|
|
142
144
|
// cuDNN derives the parameter descriptor as float for a half x and as x's
|
|
143
145
|
// own type otherwise, and the checks above hold every parameter to exactly
|
|
144
146
|
// that class, so none of them needs a cast.
|
|
145
147
|
|
|
146
|
-
handle = cumo_cuda_cudnn_handle();
|
|
147
|
-
|
|
148
148
|
status = cudnnBatchNormalizationBackward(
|
|
149
149
|
handle,
|
|
150
150
|
mode,
|
|
@@ -43,11 +43,21 @@ struct cumo_<%=type_name%>_moments_impl {
|
|
|
43
43
|
}
|
|
44
44
|
};
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
// An infinity has no deviation from a mean that is itself infinite, so a row
|
|
47
|
+
// holding one has a variance of NaN wherever the infinity falls in the tree.
|
|
48
|
+
// It sits below the accumulator so that the forms that cannot use it, as the
|
|
49
|
+
// real layer_norm cannot, do not pay for it.
|
|
50
|
+
struct cumo_<%=type_name%>_spread_impl : cumo_<%=type_name%>_moments_impl {
|
|
51
|
+
__device__ Moments MapIn(dtype in, int64_t /*index*/) {
|
|
52
|
+
return {1, in, c_isinf(in) ? (rtype)NAN : (rtype)0};
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
struct cumo_<%=type_name%>_var_impl : cumo_<%=type_name%>_spread_impl {
|
|
47
57
|
__device__ rtype MapOut(Moments accum) { return accum.m2 / (accum.n - 1); }
|
|
48
58
|
};
|
|
49
59
|
|
|
50
|
-
struct cumo_<%=type_name%>_stddev_impl : cumo_<%=type_name%>
|
|
60
|
+
struct cumo_<%=type_name%>_stddev_impl : cumo_<%=type_name%>_spread_impl {
|
|
51
61
|
__device__ rtype MapOut(Moments accum) { return r_sqrt(accum.m2 / (accum.n - 1)); }
|
|
52
62
|
};
|
|
53
63
|
|
|
@@ -87,10 +97,10 @@ struct cumo_<%=type_name%>_prod_nan_impl {
|
|
|
87
97
|
__device__ <%=dtype%> MapOut(<%=dtype%> accum) { return accum; }
|
|
88
98
|
};
|
|
89
99
|
|
|
90
|
-
struct cumo_<%=type_name%>_moments_nan_impl : cumo_<%=type_name%>
|
|
91
|
-
__device__ Moments MapIn(dtype in, int64_t
|
|
100
|
+
struct cumo_<%=type_name%>_moments_nan_impl : cumo_<%=type_name%>_spread_impl {
|
|
101
|
+
__device__ Moments MapIn(dtype in, int64_t index) {
|
|
92
102
|
if (!not_nan(in)) { return {0, m_zero, 0}; }
|
|
93
|
-
return
|
|
103
|
+
return cumo_<%=type_name%>_spread_impl::MapIn(in, index);
|
|
94
104
|
}
|
|
95
105
|
};
|
|
96
106
|
|
|
@@ -1,17 +1,79 @@
|
|
|
1
1
|
#ifdef CUDNN_FOUND
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
// Everything here holds a descriptor or the workspace, and the two allocations
|
|
5
|
+
// below raise on their own when the device is full.
|
|
6
|
+
static VALUE
|
|
7
|
+
<%=c_iter%>_run(VALUE v)
|
|
8
|
+
{
|
|
9
|
+
cumo_cuda_cudnn_conv_run_t *r = (cumo_cuda_cudnn_conv_run_t*)v;
|
|
10
|
+
cudnnDataType_t cudnn_dtype = <%= cudnn_dtype %>;
|
|
11
|
+
<%=cudnn_scalar_t%> alpha = 1;
|
|
12
|
+
<%=cudnn_scalar_t%> beta = 0;
|
|
13
|
+
cudnnConvolutionFwdAlgoPerf_t perf_result;
|
|
14
|
+
size_t workspace_size;
|
|
15
|
+
|
|
16
|
+
r->status = cumo_cuda_cudnn_CreateTensorDescriptor(&r->held.x_desc, r->x_cont, cudnn_dtype);
|
|
17
|
+
if (r->status != CUDNN_STATUS_SUCCESS) return Qnil;
|
|
18
|
+
r->status = cumo_cuda_cudnn_CreateTensorDescriptor(&r->held.y_desc, r->y, cudnn_dtype);
|
|
19
|
+
if (r->status != CUDNN_STATUS_SUCCESS) return Qnil;
|
|
20
|
+
r->status = cumo_cuda_cudnn_CreateFilterDescriptor(&r->held.w_desc, r->w_cont, cudnn_dtype);
|
|
21
|
+
if (r->status != CUDNN_STATUS_SUCCESS) return Qnil;
|
|
22
|
+
r->status = cumo_cuda_cudnn_CreateConvolutionDescriptor(&r->held.conv_desc, r->ndim, r->int_stride, r->int_pad, <%=cudnn_compute_dtype%>, <%=cudnn_math_type%>);
|
|
23
|
+
if (r->status != CUDNN_STATUS_SUCCESS) return Qnil;
|
|
24
|
+
|
|
25
|
+
// auto tune
|
|
26
|
+
r->status = cumo_cuda_cudnn_FindConvolutionForwardAlgorithm(
|
|
27
|
+
&perf_result,
|
|
28
|
+
r->handle,
|
|
29
|
+
r->held.x_desc,
|
|
30
|
+
r->x_cont,
|
|
31
|
+
r->held.w_desc,
|
|
32
|
+
r->w_cont,
|
|
33
|
+
r->held.conv_desc,
|
|
34
|
+
r->held.y_desc,
|
|
35
|
+
r->y,
|
|
36
|
+
cumo_cuda_cudnn_max_workspace_size(),
|
|
37
|
+
r->int_stride,
|
|
38
|
+
r->int_pad,
|
|
39
|
+
r->ndim,
|
|
40
|
+
cudnn_dtype);
|
|
41
|
+
if (r->status != CUDNN_STATUS_SUCCESS) return Qnil;
|
|
42
|
+
// The descriptor asked for a math type; use the one the search settled on.
|
|
43
|
+
r->status = cudnnSetConvolutionMathType(r->held.conv_desc, perf_result.mathType);
|
|
44
|
+
if (r->status != CUDNN_STATUS_SUCCESS) return Qnil;
|
|
45
|
+
|
|
46
|
+
// The search may look at algorithms needing up to max_workspace_size,
|
|
47
|
+
// but only the one it picked has to be paid for.
|
|
48
|
+
workspace_size = perf_result.memory;
|
|
49
|
+
if (workspace_size > 0) r->held.workspace = cumo_cuda_runtime_malloc(workspace_size);
|
|
50
|
+
r->status = cudnnConvolutionForward(
|
|
51
|
+
r->handle,
|
|
52
|
+
(void*)&alpha,
|
|
53
|
+
r->held.x_desc,
|
|
54
|
+
(void*)r->x_cont_ptr,
|
|
55
|
+
r->held.w_desc,
|
|
56
|
+
(void*)r->w_cont_ptr,
|
|
57
|
+
r->held.conv_desc,
|
|
58
|
+
perf_result.algo,
|
|
59
|
+
(void*)r->held.workspace,
|
|
60
|
+
workspace_size,
|
|
61
|
+
(void*)&beta,
|
|
62
|
+
r->held.y_desc,
|
|
63
|
+
(void*)r->y_ptr);
|
|
64
|
+
if (r->status != CUDNN_STATUS_SUCCESS) return Qnil;
|
|
65
|
+
|
|
66
|
+
r->status = cumo_cuda_cudnn_AddBias(r, cudnn_dtype, &alpha);
|
|
67
|
+
return Qnil;
|
|
68
|
+
}
|
|
69
|
+
|
|
4
70
|
// cover_all=true is not supported with CUDNN
|
|
5
71
|
// dilation > 1 is not supported yet
|
|
6
72
|
// x.conv(w, b: nil, stride: 1, pad: 0, y: nil)
|
|
7
73
|
static VALUE
|
|
8
74
|
<%=c_func(-1)%>(int argc, VALUE argv[], VALUE self)
|
|
9
75
|
{
|
|
10
|
-
|
|
11
|
-
cudnnStatus_t status = 0;
|
|
12
|
-
cudnnHandle_t handle = 0;
|
|
13
|
-
<%=cudnn_scalar_t%> alpha = 1;
|
|
14
|
-
<%=cudnn_scalar_t%> beta = 0;
|
|
76
|
+
cumo_cuda_cudnn_conv_run_t r;
|
|
15
77
|
|
|
16
78
|
VALUE x=self, w, b, stride, pad, y;
|
|
17
79
|
VALUE kw_hash = Qnil;
|
|
@@ -24,22 +86,10 @@ static VALUE
|
|
|
24
86
|
size_t out_channels, batch_size;
|
|
25
87
|
|
|
26
88
|
VALUE x_cont, w_cont;
|
|
27
|
-
cudnnTensorDescriptor_t x_desc = 0;
|
|
28
|
-
cudnnTensorDescriptor_t y_desc = 0;
|
|
29
|
-
cudnnTensorDescriptor_t b_desc = 0;
|
|
30
|
-
cudnnFilterDescriptor_t w_desc = 0;
|
|
31
|
-
cudnnConvolutionDescriptor_t conv_desc = 0;
|
|
32
|
-
char *x_cont_ptr, *w_cont_ptr, *y_ptr;
|
|
33
|
-
|
|
34
|
-
cudnnConvolutionFwdAlgoPerf_t perf_result;
|
|
35
|
-
cudnnConvolutionFwdAlgo_t algo;
|
|
36
|
-
size_t max_workspace_size = cumo_cuda_cudnn_max_workspace_size();
|
|
37
|
-
size_t workspace_size;
|
|
38
|
-
char* workspace = 0;
|
|
39
|
-
|
|
40
89
|
int int_stride[CUMO_NA_MAX_DIMENSION];
|
|
41
90
|
int int_pad[CUMO_NA_MAX_DIMENSION];
|
|
42
91
|
|
|
92
|
+
memset(&r, 0, sizeof(r));
|
|
43
93
|
rb_scan_args(argc, argv, "1:", &w, &kw_hash);
|
|
44
94
|
rb_get_kwargs(kw_hash, kw_table, 0, 4, opts);
|
|
45
95
|
stride = cumo_option_value(opts[0], Qnil);
|
|
@@ -91,112 +141,29 @@ static VALUE
|
|
|
91
141
|
x_cont = cumo_na_as_contiguous_array(x);
|
|
92
142
|
w_cont = cumo_na_as_contiguous_array(w);
|
|
93
143
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
handle = cumo_cuda_cudnn_handle();
|
|
108
|
-
|
|
109
|
-
// auto tune
|
|
110
|
-
status = cumo_cuda_cudnn_FindConvolutionForwardAlgorithm(
|
|
111
|
-
&perf_result,
|
|
112
|
-
handle,
|
|
113
|
-
x_desc,
|
|
114
|
-
x_cont,
|
|
115
|
-
w_desc,
|
|
116
|
-
w_cont,
|
|
117
|
-
conv_desc,
|
|
118
|
-
y_desc,
|
|
119
|
-
y,
|
|
120
|
-
max_workspace_size,
|
|
121
|
-
int_stride,
|
|
122
|
-
int_pad,
|
|
123
|
-
ndim,
|
|
124
|
-
cudnn_dtype);
|
|
125
|
-
if (status != CUDNN_STATUS_SUCCESS) goto CONV_ERROR;
|
|
126
|
-
// The descriptor asked for a math type; use the one the search settled on.
|
|
127
|
-
status = cudnnSetConvolutionMathType(conv_desc, perf_result.mathType);
|
|
128
|
-
if (status != CUDNN_STATUS_SUCCESS) goto CONV_ERROR;
|
|
129
|
-
|
|
130
|
-
algo = perf_result.algo;
|
|
131
|
-
workspace_size = perf_result.memory;
|
|
132
|
-
|
|
133
|
-
// The search may look at algorithms needing up to max_workspace_size,
|
|
134
|
-
// but only the one it picked has to be paid for.
|
|
135
|
-
if (workspace_size > 0) workspace = cumo_cuda_runtime_malloc(workspace_size);
|
|
136
|
-
status = cudnnConvolutionForward(
|
|
137
|
-
handle,
|
|
138
|
-
(void*)&alpha,
|
|
139
|
-
x_desc,
|
|
140
|
-
(void*)x_cont_ptr,
|
|
141
|
-
w_desc,
|
|
142
|
-
(void*)w_cont_ptr,
|
|
143
|
-
conv_desc,
|
|
144
|
-
algo,
|
|
145
|
-
(void*)workspace,
|
|
146
|
-
workspace_size,
|
|
147
|
-
(void*)&beta,
|
|
148
|
-
y_desc,
|
|
149
|
-
(void*)y_ptr);
|
|
150
|
-
if (status != CUDNN_STATUS_SUCCESS) goto CONV_ERROR;
|
|
151
|
-
|
|
144
|
+
r.x_cont = x_cont;
|
|
145
|
+
r.w_cont = w_cont;
|
|
146
|
+
r.y = y;
|
|
147
|
+
r.x_cont_ptr = cumo_na_get_offset_pointer_for_read(x_cont);
|
|
148
|
+
r.w_cont_ptr = cumo_na_get_offset_pointer_for_read(w_cont);
|
|
149
|
+
r.y_ptr = cumo_na_get_offset_pointer_for_write(y);
|
|
150
|
+
r.ndim = ndim;
|
|
151
|
+
r.int_stride = int_stride;
|
|
152
|
+
r.int_pad = int_pad;
|
|
153
|
+
|
|
154
|
+
// Taking the bias runs Ruby, which can raise, so it is settled before the
|
|
155
|
+
// ensure below has anything to give back.
|
|
152
156
|
if (b != Qnil) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
cumo_narray_t *nb, *nb_cont;
|
|
157
|
-
size_t *b_shape;
|
|
158
|
-
int b_ndim;
|
|
159
|
-
|
|
160
|
-
CUMO_CHECK_NARRAY_TYPE(b, cT);
|
|
161
|
-
CumoGetNArray(b, nb);
|
|
162
|
-
new_shape[0] = 1;
|
|
163
|
-
new_shape[1] = nb->size;
|
|
164
|
-
for (size_t i = 0; i < ndim; ++i) {
|
|
165
|
-
new_shape[i + 2] = 1;
|
|
166
|
-
}
|
|
167
|
-
b_cont = cumo_na_as_contiguous_array(b);
|
|
168
|
-
b_cont_ptr = cumo_na_get_offset_pointer_for_read(b_cont);
|
|
169
|
-
CumoGetNArray(b_cont, nb_cont);
|
|
170
|
-
b_shape = nb_cont->shape;
|
|
171
|
-
b_ndim = nb_cont->ndim;
|
|
172
|
-
// reshape b
|
|
173
|
-
nb_cont->ndim = ndim + 2;
|
|
174
|
-
nb_cont->shape = new_shape;
|
|
175
|
-
status = cumo_cuda_cudnn_CreateTensorDescriptor(&b_desc, b_cont, cudnn_dtype);
|
|
176
|
-
// restore b.shape
|
|
177
|
-
nb_cont->ndim = b_ndim;
|
|
178
|
-
nb_cont->shape = b_shape;
|
|
179
|
-
if (status != CUDNN_STATUS_SUCCESS) goto CONV_ERROR;
|
|
180
|
-
|
|
181
|
-
status = cudnnAddTensor(
|
|
182
|
-
handle,
|
|
183
|
-
(void*)&alpha,
|
|
184
|
-
b_desc,
|
|
185
|
-
(void*)b_cont_ptr,
|
|
186
|
-
(void*)&alpha,
|
|
187
|
-
y_desc,
|
|
188
|
-
(void*)y_ptr);
|
|
189
|
-
if (status != CUDNN_STATUS_SUCCESS) goto CONV_ERROR;
|
|
157
|
+
cumo_cuda_cudnn_check_input(b, cT, 1, &out_channels);
|
|
158
|
+
r.b_cont = cumo_na_as_contiguous_array(b);
|
|
159
|
+
r.b_cont_ptr = cumo_na_get_offset_pointer_for_read(r.b_cont);
|
|
190
160
|
}
|
|
161
|
+
r.handle = cumo_cuda_cudnn_handle();
|
|
191
162
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if (w_desc) cudnnDestroyFilterDescriptor(w_desc);
|
|
197
|
-
if (conv_desc) cudnnDestroyConvolutionDescriptor(conv_desc);
|
|
198
|
-
if (workspace) cumo_cuda_runtime_free(workspace);
|
|
199
|
-
cumo_cuda_cudnn_check_status(status);
|
|
163
|
+
rb_ensure(<%=c_iter%>_run, (VALUE)&r, cumo_cuda_cudnn_release_conv_held, (VALUE)&r.held);
|
|
164
|
+
RB_GC_GUARD(r.b_cont);
|
|
165
|
+
cumo_cuda_cudnn_check_status(r.status);
|
|
166
|
+
cumo_cuda_runtime_check_status(r.held.wait_status);
|
|
200
167
|
|
|
201
168
|
return y;
|
|
202
169
|
}
|
|
@@ -11,16 +11,85 @@ cumo_cuda_cudnn_get_sizet_ary(size_t *sizet_ary, VALUE ary, size_t ndim)
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
typedef struct {
|
|
15
|
+
cumo_cuda_cudnn_conv_held_t held;
|
|
16
|
+
cudnnHandle_t handle;
|
|
17
|
+
VALUE x_cont, gy_cont, gw;
|
|
18
|
+
char *x_cont_ptr, *gy_cont_ptr, *gw_ptr;
|
|
19
|
+
size_t ndim;
|
|
20
|
+
int *int_stride, *int_pad;
|
|
21
|
+
cudnnStatus_t status;
|
|
22
|
+
} <%=c_iter%>_run_t;
|
|
23
|
+
|
|
24
|
+
// Everything here holds a descriptor or the workspace, and the two allocations
|
|
25
|
+
// below raise on their own when the device is full.
|
|
16
26
|
static VALUE
|
|
17
|
-
<%=
|
|
27
|
+
<%=c_iter%>_run(VALUE v)
|
|
18
28
|
{
|
|
29
|
+
<%=c_iter%>_run_t *r = (<%=c_iter%>_run_t*)v;
|
|
19
30
|
cudnnDataType_t cudnn_dtype = <%= cudnn_dtype %>;
|
|
20
|
-
cudnnStatus_t status = 0;
|
|
21
|
-
cudnnHandle_t handle = 0;
|
|
22
31
|
<%=cudnn_scalar_t%> one = 1;
|
|
23
32
|
<%=cudnn_scalar_t%> zero = 0;
|
|
33
|
+
cudnnConvolutionBwdFilterAlgoPerf_t perf_result;
|
|
34
|
+
size_t workspace_size;
|
|
35
|
+
|
|
36
|
+
r->status = cumo_cuda_cudnn_CreateTensorDescriptor(&r->held.x_desc, r->x_cont, cudnn_dtype);
|
|
37
|
+
if (r->status != CUDNN_STATUS_SUCCESS) return Qnil;
|
|
38
|
+
r->status = cumo_cuda_cudnn_CreateTensorDescriptor(&r->held.y_desc, r->gy_cont, cudnn_dtype);
|
|
39
|
+
if (r->status != CUDNN_STATUS_SUCCESS) return Qnil;
|
|
40
|
+
r->status = cumo_cuda_cudnn_CreateFilterDescriptor(&r->held.w_desc, r->gw, cudnn_dtype);
|
|
41
|
+
if (r->status != CUDNN_STATUS_SUCCESS) return Qnil;
|
|
42
|
+
r->status = cumo_cuda_cudnn_CreateConvolutionDescriptor(&r->held.conv_desc, r->ndim, r->int_stride, r->int_pad, <%=cudnn_compute_dtype%>, <%=cudnn_math_type%>);
|
|
43
|
+
if (r->status != CUDNN_STATUS_SUCCESS) return Qnil;
|
|
44
|
+
|
|
45
|
+
// auto tune
|
|
46
|
+
r->status = cumo_cuda_cudnn_FindConvolutionBackwardFilterAlgorithm(
|
|
47
|
+
&perf_result,
|
|
48
|
+
r->handle,
|
|
49
|
+
r->held.x_desc,
|
|
50
|
+
r->x_cont,
|
|
51
|
+
r->held.y_desc,
|
|
52
|
+
r->gy_cont,
|
|
53
|
+
r->held.conv_desc,
|
|
54
|
+
r->held.w_desc,
|
|
55
|
+
r->gw,
|
|
56
|
+
cumo_cuda_cudnn_max_workspace_size(),
|
|
57
|
+
r->int_stride,
|
|
58
|
+
r->int_pad,
|
|
59
|
+
r->ndim,
|
|
60
|
+
cudnn_dtype);
|
|
61
|
+
if (r->status != CUDNN_STATUS_SUCCESS) return Qnil;
|
|
62
|
+
// The descriptor asked for a math type; use the one the search settled on.
|
|
63
|
+
r->status = cudnnSetConvolutionMathType(r->held.conv_desc, perf_result.mathType);
|
|
64
|
+
if (r->status != CUDNN_STATUS_SUCCESS) return Qnil;
|
|
65
|
+
|
|
66
|
+
// The search may look at algorithms needing up to max_workspace_size,
|
|
67
|
+
// but only the one it picked has to be paid for.
|
|
68
|
+
workspace_size = perf_result.memory;
|
|
69
|
+
if (workspace_size > 0) r->held.workspace = cumo_cuda_runtime_malloc(workspace_size);
|
|
70
|
+
r->status = cudnnConvolutionBackwardFilter(
|
|
71
|
+
r->handle,
|
|
72
|
+
(void*)&one,
|
|
73
|
+
r->held.x_desc,
|
|
74
|
+
(void*)r->x_cont_ptr,
|
|
75
|
+
r->held.y_desc,
|
|
76
|
+
(void*)r->gy_cont_ptr,
|
|
77
|
+
r->held.conv_desc,
|
|
78
|
+
perf_result.algo,
|
|
79
|
+
(void*)r->held.workspace,
|
|
80
|
+
workspace_size,
|
|
81
|
+
(void*)&zero,
|
|
82
|
+
r->held.w_desc,
|
|
83
|
+
(void*)r->gw_ptr);
|
|
84
|
+
return Qnil;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// cover_all=true is not supported with CUDNN
|
|
88
|
+
// gw = x.conv_grad_w(gy, w_shape, stride: 1, pad: 0, gw: nil)
|
|
89
|
+
static VALUE
|
|
90
|
+
<%=c_func(-1)%>(int argc, VALUE argv[], VALUE self)
|
|
91
|
+
{
|
|
92
|
+
<%=c_iter%>_run_t r;
|
|
24
93
|
|
|
25
94
|
VALUE x=self, gy, w_shape, stride, pad, gw;
|
|
26
95
|
VALUE kw_hash = Qnil;
|
|
@@ -31,22 +100,12 @@ static VALUE
|
|
|
31
100
|
cumo_narray_t *nx, *ngy;
|
|
32
101
|
|
|
33
102
|
VALUE x_cont, gy_cont;
|
|
34
|
-
cudnnTensorDescriptor_t x_desc = 0;
|
|
35
|
-
cudnnTensorDescriptor_t gy_desc = 0;
|
|
36
|
-
cudnnConvolutionDescriptor_t conv_desc = 0;
|
|
37
|
-
cudnnFilterDescriptor_t gw_desc = 0;
|
|
38
|
-
char *x_cont_ptr, *gy_cont_ptr, *gw_ptr;
|
|
39
|
-
|
|
40
|
-
cudnnConvolutionBwdFilterAlgoPerf_t perf_result;
|
|
41
|
-
cudnnConvolutionBwdFilterAlgo_t algo;
|
|
42
|
-
size_t max_workspace_size = cumo_cuda_cudnn_max_workspace_size();
|
|
43
|
-
size_t workspace_size;
|
|
44
|
-
char* workspace = 0;
|
|
45
103
|
|
|
46
104
|
size_t sizet_w_shape[CUMO_NA_MAX_DIMENSION];
|
|
47
105
|
int int_stride[CUMO_NA_MAX_DIMENSION];
|
|
48
106
|
int int_pad[CUMO_NA_MAX_DIMENSION];
|
|
49
107
|
|
|
108
|
+
memset(&r, 0, sizeof(r));
|
|
50
109
|
rb_scan_args(argc, argv, "2:", &gy, &w_shape, &kw_hash);
|
|
51
110
|
rb_get_kwargs(kw_hash, kw_table, 0, 3, opts);
|
|
52
111
|
stride = cumo_option_value(opts[0], Qnil);
|
|
@@ -102,71 +161,20 @@ static VALUE
|
|
|
102
161
|
x_cont = cumo_na_as_contiguous_array(x);
|
|
103
162
|
gy_cont = cumo_na_as_contiguous_array(gy);
|
|
104
163
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
// auto tune
|
|
121
|
-
status = cumo_cuda_cudnn_FindConvolutionBackwardFilterAlgorithm(
|
|
122
|
-
&perf_result,
|
|
123
|
-
handle,
|
|
124
|
-
x_desc,
|
|
125
|
-
x_cont,
|
|
126
|
-
gy_desc,
|
|
127
|
-
gy_cont,
|
|
128
|
-
conv_desc,
|
|
129
|
-
gw_desc,
|
|
130
|
-
gw,
|
|
131
|
-
max_workspace_size,
|
|
132
|
-
int_stride,
|
|
133
|
-
int_pad,
|
|
134
|
-
ndim,
|
|
135
|
-
cudnn_dtype);
|
|
136
|
-
if (status != CUDNN_STATUS_SUCCESS) goto CONV_GRAD_W_ERROR;
|
|
137
|
-
// The descriptor asked for a math type; use the one the search settled on.
|
|
138
|
-
status = cudnnSetConvolutionMathType(conv_desc, perf_result.mathType);
|
|
139
|
-
if (status != CUDNN_STATUS_SUCCESS) goto CONV_GRAD_W_ERROR;
|
|
140
|
-
|
|
141
|
-
algo = perf_result.algo;
|
|
142
|
-
workspace_size = perf_result.memory;
|
|
143
|
-
|
|
144
|
-
// The search may look at algorithms needing up to max_workspace_size,
|
|
145
|
-
// but only the one it picked has to be paid for.
|
|
146
|
-
if (workspace_size > 0) workspace = cumo_cuda_runtime_malloc(workspace_size);
|
|
147
|
-
status = cudnnConvolutionBackwardFilter(
|
|
148
|
-
handle,
|
|
149
|
-
(void*)&one,
|
|
150
|
-
x_desc,
|
|
151
|
-
(void*)x_cont_ptr,
|
|
152
|
-
gy_desc,
|
|
153
|
-
(void*)gy_cont_ptr,
|
|
154
|
-
conv_desc,
|
|
155
|
-
algo,
|
|
156
|
-
(void*)workspace,
|
|
157
|
-
workspace_size,
|
|
158
|
-
(void*)&zero,
|
|
159
|
-
gw_desc,
|
|
160
|
-
(void*)gw_ptr);
|
|
161
|
-
if (status != CUDNN_STATUS_SUCCESS) goto CONV_GRAD_W_ERROR;
|
|
162
|
-
|
|
163
|
-
CONV_GRAD_W_ERROR:
|
|
164
|
-
if (x_desc) cudnnDestroyTensorDescriptor(x_desc);
|
|
165
|
-
if (gy_desc) cudnnDestroyTensorDescriptor(gy_desc);
|
|
166
|
-
if (gw_desc) cudnnDestroyFilterDescriptor(gw_desc);
|
|
167
|
-
if (conv_desc) cudnnDestroyConvolutionDescriptor(conv_desc);
|
|
168
|
-
if (workspace) cumo_cuda_runtime_free(workspace);
|
|
169
|
-
cumo_cuda_cudnn_check_status(status);
|
|
164
|
+
r.x_cont = x_cont;
|
|
165
|
+
r.gy_cont = gy_cont;
|
|
166
|
+
r.gw = gw;
|
|
167
|
+
r.x_cont_ptr = cumo_na_get_offset_pointer_for_read(x_cont);
|
|
168
|
+
r.gy_cont_ptr = cumo_na_get_offset_pointer_for_read(gy_cont);
|
|
169
|
+
r.gw_ptr = cumo_na_get_offset_pointer_for_write(gw);
|
|
170
|
+
r.ndim = ndim;
|
|
171
|
+
r.int_stride = int_stride;
|
|
172
|
+
r.int_pad = int_pad;
|
|
173
|
+
r.handle = cumo_cuda_cudnn_handle();
|
|
174
|
+
|
|
175
|
+
rb_ensure(<%=c_iter%>_run, (VALUE)&r, cumo_cuda_cudnn_release_conv_held, (VALUE)&r.held);
|
|
176
|
+
cumo_cuda_cudnn_check_status(r.status);
|
|
177
|
+
cumo_cuda_runtime_check_status(r.held.wait_status);
|
|
170
178
|
|
|
171
179
|
return gw;
|
|
172
180
|
}
|