#include #include "Layer.h" namespace tk { namespace dnn { LSTM::LSTM( Network *net, int hiddensize, bool returnSeq, std::string fname_weights) : Layer(net) { this->returnSeq = returnSeq; int batchSize = input_dim.n; int inputSize = input_dim.c; seqLen = input_dim.w; stateSize = hiddensize; // init Tensor Descriptors std::vector x_vec(seqLen); std::vector y_vec(seqLen); int dimA[3]; int strideA[3]; for (int i = 0; i < seqLen; i++) { checkCUDNN(cudnnCreateTensorDescriptor(&x_vec[i])); checkCUDNN(cudnnCreateTensorDescriptor(&y_vec[i])); dimA[0] = batchSize; dimA[1] = inputSize; dimA[2] = 1; dimA[0] = batchSize; dimA[1] = inputSize; strideA[0] = dimA[2] * dimA[1]; strideA[1] = dimA[2]; strideA[2] = 1; checkCUDNN(cudnnSetTensorNdDescriptor(x_vec[i], net->dataType, 3, dimA, strideA)); dimA[0] = batchSize; dimA[1] = stateSize; dimA[2] = 1; strideA[0] = dimA[2] * dimA[1]; strideA[1] = dimA[2]; strideA[2] = 1; checkCUDNN(cudnnSetTensorNdDescriptor(y_vec[i], net->dataType, 3, dimA, strideA)); } // apply tensordesc x_desc_vec_ = x_vec; y_desc_vec_ = y_vec; // set the state tensors dimA[0] = numLayers; dimA[1] = batchSize; dimA[2] = stateSize; strideA[0] = dimA[2] * dimA[1]; strideA[1] = dimA[2]; strideA[2] = 1; checkCUDNN(cudnnCreateTensorDescriptor(&hx_desc_)); checkCUDNN(cudnnCreateTensorDescriptor(&cx_desc_)); checkCUDNN(cudnnCreateTensorDescriptor(&hy_desc_)); checkCUDNN(cudnnCreateTensorDescriptor(&cy_desc_)); checkCUDNN(cudnnSetTensorNdDescriptor(hx_desc_, net->dataType, 3, dimA, strideA)); checkCUDNN(cudnnSetTensorNdDescriptor(cx_desc_, net->dataType, 3, dimA, strideA)); checkCUDNN(cudnnSetTensorNdDescriptor(hy_desc_, net->dataType, 3, dimA, strideA)); checkCUDNN(cudnnSetTensorNdDescriptor(cy_desc_, net->dataType, 3, dimA, strideA)); // allocate dnnType *hx_ptr, *cx_ptr, *hy_ptr, *cy_ptr; stateDataDim = dimA[0]*dimA[1]*dimA[2]; checkCuda( cudaMalloc(&hx_ptr, stateDataDim*sizeof(dnnType)) ); checkCuda( cudaMalloc(&cx_ptr, stateDataDim*sizeof(dnnType)) ); checkCuda( cudaMalloc(&hy_ptr, stateDataDim*sizeof(dnnType)) ); checkCuda( cudaMalloc(&cy_ptr, stateDataDim*sizeof(dnnType)) ); // Create Dropout descriptors // TODO: ??? IS IT NECESSARY ??? float dropoutprob = 0.1f; // random val ???? checkCUDNN(cudnnCreateDropoutDescriptor(&dropoutDesc)); checkCUDNN(cudnnDropoutGetStatesSize(net->cudnnHandle, &dropout_byte_)); dropout_size_ = dropout_byte_ / sizeof(dnnType); checkCuda( cudaMalloc(&dropout_states_, dropout_byte_) ); uint64_t seed_ = 17 + rand() % 4096; // NOLINT(runtime/threadsafe_fn) checkCUDNN(cudnnSetDropoutDescriptor(dropoutDesc, net->cudnnHandle, dropoutprob, dropout_states_, dropout_byte_, seed_)); // RNN descriptors checkCUDNN(cudnnCreateRNNDescriptor(&rnnDesc)); #if CUDNN_MAJOR > 7 checkCUDNN(cudnnSetRNNDescriptor_v6(net->cudnnHandle,rnnDesc, stateSize, numLayers, dropoutDesc, cudnnRNNInputMode_t::CUDNN_LINEAR_INPUT, //(bidirectional ? cudnnDirectionMode_t::CUDNN_BIDIRECTIONAL : cudnnDirectionMode_t::CUDNN_UNIDIRECTIONAL), cudnnDirectionMode_t::CUDNN_UNIDIRECTIONAL, cudnnRNNMode_t::CUDNN_LSTM, cudnnRNNAlgo_t::CUDNN_RNN_ALGO_STANDARD, net->dataType)); #else checkCUDNN(cudnnSetRNNDescriptor(net->cudnnHandle,rnnDesc, stateSize, numLayers, dropoutDesc, cudnnRNNInputMode_t::CUDNN_LINEAR_INPUT, //(bidirectional ? cudnnDirectionMode_t::CUDNN_BIDIRECTIONAL : cudnnDirectionMode_t::CUDNN_UNIDIRECTIONAL), cudnnDirectionMode_t::CUDNN_UNIDIRECTIONAL, cudnnRNNMode_t::CUDNN_LSTM, cudnnRNNAlgo_t::CUDNN_RNN_ALGO_STANDARD, net->dataType)); #endif // Get temp space sizes checkCUDNN(cudnnGetRNNWorkspaceSize(net->cudnnHandle, rnnDesc, seqLen, x_desc_vec_.data(), &workspace_byte_)); workspace_size_ = workspace_byte_ / sizeof(dnnType); checkCuda( cudaMalloc(&work_space_, workspace_byte_) ); // Check that number of params are correct size_t cudnn_param_size; checkCUDNN(cudnnGetRNNParamsSize(net->cudnnHandle, rnnDesc,x_desc_vec_[0], &cudnn_param_size, net->dataType)); int cudnn_params = cudnn_param_size/sizeof(dnnType); //std::cout<<"LSTM params size: "<dataType, net->tensorFormat, 3, dim_w)); // load params std::cout<<"Reading weights: PARAMS="<cudnnHandle, rnnDesc, i, x_desc_vec_[0], w_desc_, 0, j, m_desc, (void**)&p)); std::cout << "ptr: " << ((int64_t)(p - NULL))/sizeof(dnnType)<<"\n"; cudnnDataType_t t; cudnnTensorFormat_t f; int ndim = 5; int dims[5] = {0, 0, 0, 0, 0}; checkCUDNN(cudnnGetFilterNdDescriptor(m_desc, ndim, &t, &f, &ndim, &dims[0])); std::cout << "(layer, linlayer): " << i << " " << j << "\n"; int tot = 1; for (int i = 0; i < ndim; ++i) { std::cout << dims[i] << " "; tot *= dims[i]; } std::cout<<"\t-> "<cublasHandle, srcData, srcF, dim.c, dim.h*dim.w*dim.l); // build srcB as reversed srcF for(int i=0; icudnnHandle, rnnDesc, seqLen, // number of time steps (nT) x_desc_vec_.data(), // input array of desc (nT*nC_in) srcF, // input pointer hx_desc_, // initial hidden state desc hx_ptr, // initial hidden state pointer cx_desc_, // initial cell state desc cx_ptr, // initial cell state pointer w_desc_, // weights desc wf_ptr, // weights pointer y_desc_vec_.data(), // output desc (nT*nC_out) dstF, // output pointer hy_desc_, // final hidden state desc hy_ptr, // final hidden state pointer cy_desc_, // final cell state desc cy_ptr, // final cell state pointer work_space_, // workspace pointer workspace_byte_)); // workspace size } // backward { // reset states checkCuda( cudaMemset(hx_ptr, 0, stateDataDim*sizeof(float)) ); checkCuda( cudaMemset(cx_ptr, 0, stateDataDim*sizeof(float)) ); checkCUDNN(cudnnRNNForwardInference(net->cudnnHandle, rnnDesc, seqLen, // number of time steps (nT) x_desc_vec_.data(), // input array of desc (nT*nC_in) srcB, // input pointer hx_desc_, // initial hidden state desc hx_ptr, // initial hidden state pointer cx_desc_, // initial cell state desc cx_ptr, // initial cell state pointer w_desc_, // weights desc wb_ptr, // weights pointer y_desc_vec_.data(), // output desc (nT*nC_out) dstB_NR, // output pointer hy_desc_, // final hidden state desc hy_ptr, // final hidden state pointer cy_desc_, // final cell state desc cy_ptr, // final cell state pointer work_space_, // workspace pointer workspace_byte_)); // workspace size } // reverse order of dstB for(int i=0; icublasHandle, dstF, dstData, one_output_dim.h* one_output_dim.w*one_output_dim.l, one_output_dim.c); // backward transpose matrixTranspose(net->cublasHandle, dstB, dstData + one_output_dim.tot(), one_output_dim.h* one_output_dim.w*one_output_dim.l, one_output_dim.c); } else { // copy last of forward checkCuda( cudaMemcpy(dstData, dstF + one_output_dim.tot() - one_output_dim.c, one_output_dim.c*sizeof(dnnType), cudaMemcpyDeviceToDevice)); // copy first of backward checkCuda( cudaMemcpy(dstData + one_output_dim.c, dstB, one_output_dim.c*sizeof(dnnType), cudaMemcpyDeviceToDevice)); } dim = output_dim; return dstData; } }}