         cudnnStatus_t err = CUDNN_STATUS_SUCCESS;
         callCudnnIfNoErr(err, cudnnSetStream, *handle, *context.getCudaStream());
 
-        cudnnCTCLossDescriptor_t  ctcLossDesc;
-        cudnnTensorDescriptor_t probsDesc = nullptr;
-        cudnnTensorDescriptor_t gradsDesc = nullptr;
-        callCudnnIfNoErr(err, cudnnCreateCTCLossDescriptor, &ctcLossDesc);
-        callCudnnIfNoErr(err, cudnnSetCTCLossDescriptorEx, ctcLossDesc, CUDNN_DATA_FLOAT, CUDNN_LOSS_NORMALIZATION_SOFTMAX, CUDNN_PROPAGATE_NAN);
-        callCudnnIfNoErr(err, cudnnCreateTensorDescriptor, &probsDesc);
-        callCudnnIfNoErr(err, cudnnSetTensorNdDescriptor, probsDesc, cudnnDataType(probs.dataType()), probs.rankOf() , dims, strides);
-        if(!grads.isEmpty()){
+        CTCLossDesc  ctcLossDesc;
+        CudnnTensor probsDesc, gradsDesc(false);
+        bool calcGrads = !grads.isEmpty();
+        ctcLossDesc.set( err, CUDNN_DATA_FLOAT, CUDNN_LOSS_NORMALIZATION_SOFTMAX, CUDNN_PROPAGATE_NAN);
+        probsDesc.set( err, cudnnDataType(probs.dataType()), probs.rankOf() , dims, strides);
+
+        if(calcGrads){
+            gradsDesc.create();
             const int gradStrides[] = {(int)grads.strideAt(0), (int)grads.strideAt(1), (int)grads.strideAt(2)};
-            callCudnnIfNoErr(err, cudnnCreateTensorDescriptor, &gradsDesc);
-            callCudnnIfNoErr(err, cudnnSetTensorNdDescriptor, gradsDesc, cudnnDataType(grads.dataType()), grads.rankOf() , dims, gradStrides);
+            gradsDesc.set( err, cudnnDataType(grads.dataType()), grads.rankOf() , dims, gradStrides);
         }
 
         size_t tempWorkSpaceSize=0;

        NDArray::registerSpecialUse({&ctcLosses, &grads}, {&probs});

        cudaFree(tempWorkSpace);
        callCudnnIfNoErr(err, cudnnDestroyTensorDescriptor,probsDesc);
        if(gradsDesc) callCudnnIfNoErr(err, cudnnDestroyTensorDescriptor,gradsDesc);
        callCudnnIfNoErr(err, cudnnDestroyCTCLossDescriptor,ctcLossDesc);
        return err;
     }


            bufferInHost<int32_t>(probInputLengthes),
            ctcLosses.specialBuffer(),
            gradsDesc,
            calcGrads ? grads.specialBuffer() :nullptr,
            CUDNN_CTC_LOSS_ALGO_DETERMINISTIC,
            ctcLossDesc,
            tempWorkSpace,
