| 18 | // CUDA-side Tensor class for in/out parameter parsing. Can be float32 or bfloat16 |
| 19 | |
| 20 | struct Tensor |
| 21 | { |
| 22 | void* val; |
| 23 | void* d_val; |
| 24 | int dims[4], _dims[4]; |
| 25 | int strides[4]; |
| 26 | bool fp16; |
| 27 | |
| 28 | #if defined(__CUDA__) && !defined(__CUDA_ARCH__) |
| 29 | Tensor() : val(nullptr), d_val(nullptr), fp16(true), dims{ 0, 0, 0, 0 }, _dims{ 0, 0, 0, 0 }, strides{ 0, 0, 0, 0 } {} |
| 30 | #endif |
| 31 | |
| 32 | #ifdef __CUDACC__ |
| 33 | // Helpers to index and read/write a single element |
| 34 | __device__ inline int _nhwcIndex(int n, int h, int w, int c) const { return n * strides[0] + h * strides[1] + w * strides[2] + c * strides[3]; } |
| 35 | __device__ inline int nhwcIndex(int n, int h, int w, int c) const { return (dims[0] == 1 ? 0 : n * strides[0]) + (dims[1] == 1 ? 0 : h * strides[1]) + (dims[2] == 1 ? 0 : w * strides[2]) + (dims[3] == 1 ? 0 : c * strides[3]); } |
| 36 | __device__ inline int nhwcIndexContinuous(int n, int h, int w, int c) const { return ((n * _dims[1] + h) * _dims[2] + w) * _dims[3] + c; } |
| 37 | #ifdef BFLOAT16 |
| 38 | __device__ inline float fetch(unsigned int idx) const { return fp16 ? __bfloat162float(((__nv_bfloat16*)val)[idx]) : ((float*)val)[idx]; } |
| 39 | __device__ inline void store(unsigned int idx, float _val) { if (fp16) ((__nv_bfloat16*)val)[idx] = __float2bfloat16(_val); else ((float*)val)[idx] = _val; } |
| 40 | __device__ inline void store_grad(unsigned int idx, float _val) { if (fp16) ((__nv_bfloat16*)d_val)[idx] = __float2bfloat16(_val); else ((float*)d_val)[idx] = _val; } |
| 41 | #else |
| 42 | __device__ inline float fetch(unsigned int idx) const { return ((float*)val)[idx]; } |
| 43 | __device__ inline void store(unsigned int idx, float _val) { ((float*)val)[idx] = _val; } |
| 44 | __device__ inline void store_grad(unsigned int idx, float _val) { ((float*)d_val)[idx] = _val; } |
| 45 | #endif |
| 46 | |
| 47 | ////////////////////////////////////////////////////////////////////////////////////////// |
| 48 | // Fetch, use broadcasting for tensor dimensions of size 1 |
| 49 | __device__ inline float fetch1(unsigned int x, unsigned int y, unsigned int z) const |
| 50 | { |
| 51 | return fetch(nhwcIndex(z, y, x, 0)); |
| 52 | } |
| 53 | |
| 54 | __device__ inline vec3f fetch3(unsigned int x, unsigned int y, unsigned int z) const |
| 55 | { |
| 56 | return vec3f( |
| 57 | fetch(nhwcIndex(z, y, x, 0)), |
| 58 | fetch(nhwcIndex(z, y, x, 1)), |
| 59 | fetch(nhwcIndex(z, y, x, 2)) |
| 60 | ); |
| 61 | } |
| 62 | |
| 63 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 64 | // Store, no broadcasting here. Assume we output full res gradient and then reduce using torch.sum outside |
| 65 | __device__ inline void store(unsigned int x, unsigned int y, unsigned int z, float _val) |
| 66 | { |
| 67 | store(_nhwcIndex(z, y, x, 0), _val); |
| 68 | } |
| 69 | |
| 70 | __device__ inline void store(unsigned int x, unsigned int y, unsigned int z, vec3f _val) |
| 71 | { |
| 72 | store(_nhwcIndex(z, y, x, 0), _val.x); |
| 73 | store(_nhwcIndex(z, y, x, 1), _val.y); |
| 74 | store(_nhwcIndex(z, y, x, 2), _val.z); |
| 75 | } |
| 76 | |
| 77 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////// |
nothing calls this directly
no outgoing calls
no test coverage detected