| 130 | bool AlwaysComputeWhenAllOutputsEmpty() const override { return false; } |
| 131 | |
| 132 | void Compute(user_op::KernelComputeContext* ctx, user_op::OpKernelState* state, |
| 133 | const user_op::OpKernelCache* cache) const override { |
| 134 | const auto* target = ctx->Tensor4ArgNameAndIndex("target", 0); |
| 135 | const auto* out_grad = ctx->Tensor4ArgNameAndIndex("out_grad", 0); |
| 136 | auto* in_grad = ctx->Tensor4ArgNameAndIndex("in_grad", 0); |
| 137 | |
| 138 | const int64_t N = target->shape_view().elem_cnt(); |
| 139 | const int64_t C = in_grad->shape_view().At(in_grad->shape_view().NumAxes() - 1); |
| 140 | CHECK_LE(N, std::numeric_limits<int32_t>::max()) |
| 141 | << "Expected batch size not exceed int32 numeric limits"; |
| 142 | |
| 143 | K class_start = 0; |
| 144 | if (cache) { |
| 145 | const auto* spec_cache = dynamic_cast<const NLLKernelCache*>(cache); |
| 146 | CHECK_NOTNULL(spec_cache); |
| 147 | CHECK_EQ(spec_cache->num_classes(), C) << ctx->op_name() << ": expected num_classes " << C |
| 148 | << ", got " << spec_cache->num_classes(); |
| 149 | class_start = spec_cache->class_start(); |
| 150 | } |
| 151 | |
| 152 | const K ignore_index = static_cast<K>(ctx->Attr<int64_t>("ignore_index")); |
| 153 | |
| 154 | const T* weight_dptr = nullptr; |
| 155 | if (ctx->has_input("weight", 0)) { |
| 156 | weight_dptr = CHECK_NOTNULL(ctx->Tensor4ArgNameAndIndex("weight", 0))->dptr<T>(); |
| 157 | } |
| 158 | |
| 159 | NLLKernelUtil<device_type, T, K>::Backward( |
| 160 | ctx->stream(), static_cast<int32_t>(N), static_cast<K>(C), class_start, ignore_index, |
| 161 | out_grad->dptr<T>(), target->dptr<K>(), weight_dptr, in_grad->mut_dptr<T>()); |
| 162 | } |
| 163 | }; |
| 164 | |
| 165 | #define REGISTER_NLL_KERNELS(device, dtype, ltype) \ |
nothing calls this directly
no test coverage detected