       theta.setZero();
       gradient.setZero();
 
-      Vector<T> bottom_theta;
       Matrix<T> xin_trans = xin.transpose();
       Vector<T> temp(xin.rows());
 

      dim3 dimGridTrans(std::ceil((T)(xin.cols() - 1) / (BLOCK_SIZE)));

      for (int i = 0; i < iterations; i++) {
        bottom_theta = theta.bottomRows(theta.rows() - 1);
        CUDA_CALL(cudaMalloc(&d_bottom_theta, xin.cols() * sizeof(T)));
        CUDA_CALL(cudaMemcpy(d_bottom_theta, &bottom_theta(0), xin.cols() * sizeof(T),
          cudaMemcpyHostToDevice));
        CUDA_CALL(cudaDeviceSynchronize());

        CudaGlobalKernel<<<dimGrid, dimBlock, BLOCK_SIZE * sizeof(T)>>>(d_xin, d_bottom_theta, d_result, xin.rows(), bottom_theta.rows());

        preMultiply<<<dimGrid,dimBlock>>>(d_result, d_y, d_temp, theta(0));

        CUDA_CALL(cudaDeviceSynchronize());
        CudaGlobalKernel<<<dimGridTrans, dimBlockTrans, BLOCK_SIZE * sizeof(T)>>>(d_xin_trans, d_temp, d_end, bottom_theta.rows(), xin.rows());

        CUDA_CALL(cudaMemcpy(&h_end(0), d_end, xin.cols() * sizeof(T), cudaMemcpyDeviceToHost));

        gradient.bottomRows(gradient.rows() - 1) = h_end;


        CUDA_CALL(cudaMalloc(&d_theta, theta.size() * sizeof(T)));
        CUDA_CALL(cudaMemcpy(d_theta, &theta(0), theta.size() * sizeof(T),
          cudaMemcpyHostToDevice));

        reduce<<< dimGrid, dimBlock, BLOCK_SIZE * sizeof(T)>>>(d_theta, d_sum, theta.size());

        CUDA_CALL(cudaMemcpy(&h_sum, d_sum, sizeof(T), cudaMemcpyDeviceToHost));

      CUDA_CALL(cudaMalloc(&d_sum, sizeof(T)));
      CUDA_CALL(cudaMemset(d_end, 0, sizeof(T)));

      T * d_gradient;

      dim3 dimBlock(BLOCK_SIZE);
