|
11 | 11 | #include "infini_train/include/common/cuda/kernel_helper.cuh" |
12 | 12 | #include "infini_train/include/dispatcher.h" |
13 | 13 | #include "infini_train/include/tensor.h" |
| 14 | +#include "infini_train/src/core/runtime/cuda/cuda_dispatch.h" |
14 | 15 |
|
15 | 16 | namespace infini_train::kernels::cuda { |
16 | 17 |
|
@@ -76,40 +77,56 @@ std::shared_ptr<Tensor> LinearForward(const std::shared_ptr<Tensor> &input, cons |
76 | 77 | output->Fill(0.0); |
77 | 78 | } |
78 | 79 |
|
79 | | - // TODO(zbl): use cublasSgemv if possible for convenience and simplicity |
80 | | - // |
81 | | - // - if a is transposed: |
82 | | - // weight is [out_features, in_features] here |
83 | | - // output = input * weight.T --> output.T = weight * input.T |
84 | | - // C = output.T[out_features, bs] |
85 | | - // A = weight.T[in_features, out_features] |
86 | | - // B = input.T[in_features, bs] |
87 | | - // |
88 | | - // - if a is not transposed: |
89 | | - // output = input * weight --> output.T = weight.T * input.T |
90 | | - // C = output.T[out_features, bs] |
91 | | - // A = weight.T[out_features, in_features] |
92 | | - // B = input.T[in_features, bs] |
93 | | - GemmParams p; |
94 | | - p.trans_a = transpose ? CUBLAS_OP_T : CUBLAS_OP_N; |
95 | | - p.trans_b = CUBLAS_OP_N; |
96 | | - p.m = static_cast<int>(out_features); |
97 | | - p.n = static_cast<int>(bs); |
98 | | - p.k = static_cast<int>(in_features); |
99 | | - p.A = weight->DataPtr(); |
100 | | - p.lda = static_cast<int>(transpose ? in_features : out_features); |
101 | | - p.B = input->DataPtr(); |
102 | | - p.ldb = static_cast<int>(in_features); |
103 | | - p.C = output->DataPtr(); |
104 | | - p.ldc = static_cast<int>(out_features); |
105 | | - p.alpha = 1.0f; |
106 | | - p.beta = 1.0f; // bias already written into output; beta=1 accumulates |
107 | | - p.batch_count = 1; |
108 | | - p.input_dtype = dtype; |
109 | | - p.output_dtype = dtype; |
110 | | - p.blas_handle = GetCublasHandle(device); |
111 | | - |
112 | | - GemmCuda(p); |
| 80 | + // When bs==1 and fp32, use cublasSgemv (more efficient than GEMM for matrix-vector). |
| 81 | + // cublasSgemv does not support bf16, so bf16 falls through to GemmCuda. |
| 82 | + if (bs == 1 && dtype == DataType::kFLOAT32) { |
| 83 | + SgemvParams p; |
| 84 | + p.trans = transpose ? CUBLAS_OP_T : CUBLAS_OP_N; |
| 85 | + p.m = static_cast<int>(transpose ? in_features : out_features); |
| 86 | + p.n = static_cast<int>(transpose ? out_features : in_features); |
| 87 | + p.A = static_cast<const float *>(weight->DataPtr()); |
| 88 | + p.lda = static_cast<int>(transpose ? in_features : out_features); |
| 89 | + p.x = static_cast<const float *>(input->DataPtr()); |
| 90 | + p.y = static_cast<float *>(output->DataPtr()); |
| 91 | + p.alpha = 1.0f; |
| 92 | + p.beta = 1.0f; // output already initialized with bias or zero above |
| 93 | + p.blas_handle = GetCublasHandle(device); |
| 94 | + SgemvCuda(p); |
| 95 | + } else { |
| 96 | + // cuBLAS is colmun-major |
| 97 | + // - if a is transposed: |
| 98 | + // weight is [out_features, in_features] here |
| 99 | + // output = input * weight.T --> output.T = weight * input.T |
| 100 | + // C = output.T[out_features, bs] |
| 101 | + // A = weight.T[in_features, out_features] |
| 102 | + // B = input.T[in_features, bs] |
| 103 | + // |
| 104 | + // - if a is not transposed: |
| 105 | + // output = input * weight --> output.T = weight.T * input.T |
| 106 | + // C = output.T[out_features, bs] |
| 107 | + // A = weight.T[out_features, in_features] |
| 108 | + // B = input.T[in_features, bs] |
| 109 | + GemmParams p; |
| 110 | + p.trans_a = transpose ? CUBLAS_OP_T : CUBLAS_OP_N; |
| 111 | + p.trans_b = CUBLAS_OP_N; |
| 112 | + p.m = static_cast<int>(out_features); |
| 113 | + p.n = static_cast<int>(bs); |
| 114 | + p.k = static_cast<int>(in_features); |
| 115 | + p.A = weight->DataPtr(); |
| 116 | + p.lda = static_cast<int>(transpose ? in_features : out_features); |
| 117 | + p.B = input->DataPtr(); |
| 118 | + p.ldb = static_cast<int>(in_features); |
| 119 | + p.C = output->DataPtr(); |
| 120 | + p.ldc = static_cast<int>(out_features); |
| 121 | + p.alpha = 1.0f; |
| 122 | + p.beta = 1.0f; // bias already written into output; beta=1 accumulates |
| 123 | + p.batch_count = 1; |
| 124 | + p.input_dtype = dtype; |
| 125 | + p.output_dtype = dtype; |
| 126 | + p.blas_handle = GetCublasHandle(device); |
| 127 | + |
| 128 | + GemmCuda(p); |
| 129 | + } |
113 | 130 |
|
114 | 131 | return output; |
115 | 132 | } |
@@ -152,40 +169,56 @@ std::shared_ptr<Tensor> LinearBackwardInput(const std::shared_ptr<Tensor> &weigh |
152 | 169 | // No Fill(0) needed: cuBLAS beta=0.0f fully overwrites output. |
153 | 170 | auto grad_input = std::make_shared<Tensor>(input_dims, output_dtype, grad_output->GetDevice()); |
154 | 171 |
|
155 | | - // TODO(zbl): use cublasSgemv if possible |
156 | | - // - if transpose: |
157 | | - // weight is [out_features, in_features] here |
158 | | - // d_input = d_output * weight --> d_input.T = weight.T * d_output.T |
159 | | - // C = d_input.T[in_features, bs] |
160 | | - // A = weight.T[in_features, out_features] |
161 | | - // B = d_output.T[out_features, bs] |
162 | | - // |
163 | | - // - if not transpose: |
164 | | - // weight is [in_features, out_features] here |
165 | | - // d_input = d_output * weight.T --> d_input.T = weight * d_output.T |
166 | | - // C = d_input.T[in_features, bs] |
167 | | - // A = weight.T[out_features, in_features] |
168 | | - // B = d_output.T[out_features, bs] |
169 | | - GemmParams p; |
170 | | - p.trans_a = transpose ? CUBLAS_OP_N : CUBLAS_OP_T; |
171 | | - p.trans_b = CUBLAS_OP_N; |
172 | | - p.m = static_cast<int>(in_features); |
173 | | - p.n = static_cast<int>(bs); |
174 | | - p.k = static_cast<int>(out_features); |
175 | | - p.A = weight->DataPtr(); |
176 | | - p.lda = static_cast<int>(transpose ? in_features : out_features); |
177 | | - p.B = grad_output_promoted->DataPtr(); |
178 | | - p.ldb = static_cast<int>(out_features); |
179 | | - p.C = grad_input->DataPtr(); |
180 | | - p.ldc = static_cast<int>(in_features); |
181 | | - p.alpha = 1.0f; |
182 | | - p.beta = 0.0f; |
183 | | - p.batch_count = 1; |
184 | | - p.input_dtype = compute_dtype; |
185 | | - p.output_dtype = output_dtype; |
186 | | - p.blas_handle = GetCublasHandle(grad_output->GetDevice()); |
187 | | - |
188 | | - GemmCuda(p); |
| 172 | + // When bs==1 and fp32, use cublasSgemv (more efficient than GEMM for matrix-vector). |
| 173 | + // cublasSgemv does not support bf16, so bf16 falls through to GemmCuda. |
| 174 | + if (bs == 1 && compute_dtype == DataType::kFLOAT32) { |
| 175 | + SgemvParams p; |
| 176 | + p.trans = transpose ? CUBLAS_OP_N : CUBLAS_OP_T; |
| 177 | + p.m = static_cast<int>(transpose ? in_features : out_features); |
| 178 | + p.n = static_cast<int>(transpose ? out_features : in_features); |
| 179 | + p.A = static_cast<const float *>(weight->DataPtr()); |
| 180 | + p.lda = static_cast<int>(transpose ? in_features : out_features); |
| 181 | + p.x = static_cast<const float *>(grad_output_promoted->DataPtr()); |
| 182 | + p.y = static_cast<float *>(grad_input->DataPtr()); |
| 183 | + p.alpha = 1.0f; |
| 184 | + p.beta = 0.0f; |
| 185 | + p.blas_handle = GetCublasHandle(grad_output->GetDevice()); |
| 186 | + SgemvCuda(p); |
| 187 | + } else { |
| 188 | + // - if transpose: |
| 189 | + // weight is [out_features, in_features] here |
| 190 | + // d_input = d_output * weight --> d_input.T = weight.T * d_output.T |
| 191 | + // C = d_input.T[in_features, bs] |
| 192 | + // A = weight.T[in_features, out_features] |
| 193 | + // B = d_output.T[out_features, bs] |
| 194 | + // |
| 195 | + // - if not transpose: |
| 196 | + // weight is [in_features, out_features] here |
| 197 | + // d_input = d_output * weight.T --> d_input.T = weight * d_output.T |
| 198 | + // C = d_input.T[in_features, bs] |
| 199 | + // A = weight.T[out_features, in_features] |
| 200 | + // B = d_output.T[out_features, bs] |
| 201 | + GemmParams p; |
| 202 | + p.trans_a = transpose ? CUBLAS_OP_N : CUBLAS_OP_T; |
| 203 | + p.trans_b = CUBLAS_OP_N; |
| 204 | + p.m = static_cast<int>(in_features); |
| 205 | + p.n = static_cast<int>(bs); |
| 206 | + p.k = static_cast<int>(out_features); |
| 207 | + p.A = weight->DataPtr(); |
| 208 | + p.lda = static_cast<int>(transpose ? in_features : out_features); |
| 209 | + p.B = grad_output_promoted->DataPtr(); |
| 210 | + p.ldb = static_cast<int>(out_features); |
| 211 | + p.C = grad_input->DataPtr(); |
| 212 | + p.ldc = static_cast<int>(in_features); |
| 213 | + p.alpha = 1.0f; |
| 214 | + p.beta = 0.0f; |
| 215 | + p.batch_count = 1; |
| 216 | + p.input_dtype = compute_dtype; |
| 217 | + p.output_dtype = output_dtype; |
| 218 | + p.blas_handle = GetCublasHandle(grad_output->GetDevice()); |
| 219 | + |
| 220 | + GemmCuda(p); |
| 221 | + } |
189 | 222 |
|
190 | 223 | return grad_input; |
191 | 224 | } |
|
0 commit comments