手上显卡只有算力3.0,想试用一下pytorch和ctranslate2,预编译版都不支持需要自己编译
经查文档cuda11开始不支持算力3.0,所以只能使用cuda10最后一个版本cuda10.2
10.2在windows下的编译器最高只支持VS2019,对一些c++新版的特性支持不是很好也会导致编译错误
环境:conda + python3.10 + cuda10.2 + cudnn8.7 + VS2019
一、pytorch (v1.13.1)
查阅pytorch的release信息可以发现从2.0开始不支持cuda10,的确经多次尝试都无法编译(可能因为VS2019对c++17的支持太差),所以可编译的最后版本为v1的最后一个版本1.13.1,但是此版本也是需要一些改动的
1. member "xxx" may not be initialized
这是由constexpr关键词引起的编译错误,只能将constexpr改为const
将aten/src/ATen/core/dynamic_type.h和c10/core/SymInt.h这两个头文件中的constexpr替换掉即可
2. CUDASparseDescriptors.cpp报错
这其实是因为windows上的10.2不支持CuSparseXXX的API,原代码疑似判断逻辑有误
在aten/src/ATen/cuda/CUDASparse.h中,既然按注释
// cuSparse Generic API added in CUDA 10.1
// Windows support added in CUDA 11.0
也就是11.0全平台支持,10.1只有非Windows平台支持,那么第7行的
((CUSPARSE_VERSION >= 10300) || (CUSPARSE_VERSION >= 11000 && defined(_WIN32)))
就不对了,于是改成
((CUSPARSE_VERSION >= 11000) || (CUSPARSE_VERSION >= 10300 && !defined(_WIN32)))
其实就是让AT_USE_CUSPARSE_GENERIC_API()的定义变为0,只是按照我觉得对的逻辑改了
改完这两个问题就可以顺利编译pytorch了(好慢啊要编译好几个小时)
二、Ctranslate2 (v3.16.1)
Ctranslate2的changelog里虽然写着从v3.0开始不支持cuda10,但是经过尝试,修改部分文件以后还是可以编译的,v4.0+我也试过但是没法编译(可能也是因为c++17)。另外由于从3.17开始增加了cuda10缺少头文件的bfloat16类型支持,产生许多难以解决的错误,所以可编译的最后版本为3.16.1
1. 不支持cuda10
在CMakeLists.txt第417行的find_package(CUDA 11.0 REQUIRED),将11.0改为10.0
2. include/ctranslate2/utils.h报错
该utils.h文件第32行有个中文系统不支持的字符"│",我试过给编译选项加上/utf-8还是不行,于是只能将引号里的字符改为键盘上的竖杠:"|" (看起来一样其实不是同样的字符),或者像最新版本一样改成"\uFFE8"
3. nvcc error : 'cicc' died with status 0xC0000005 (ACCESS_VIOLATION)
这真的是一个超级大坑,一点都看不出问题在哪里。而且不止编译v3,就算是编译支持cuda10的v2.10+也会遇到这个问题。最后终于发现是因为Ctranslate2强制使用了子模块的thrust头文件,看一下CMakeLists.txt第450行的注释:
# We should ensure that the Thrust include directories appear before
# -I/usr/local/cuda/include for both GCC and NVCC, so that the headers
# are coming from the submodule and not the system.
而出现问题时所使用的头文件跟10.2不兼容导致nvcc运行报错。但是因为项目代码中使用了11.0+的cub头文件,完全用10.2的也会编译不过去,所幸经实验用11.0的可以。因此将third_party/thrust这个子模块重新检出为标签cuda-11.0(或者1.9.9),当然它下面的dependencies/cub子模块也需要检出到对应的版本
4. src/cuda/utils.h报缺少par_nosync相关的错误
这个错误是改完上面一个才会出现的,因为旧版本的thrust头文件没有这个东西。经查看历史版本这边使用par_nosync是从2.13.0开始的,所以我们找到2.12.0版本的utils.h文件内容来替换一下,其实就是把
// Convenience macro to call Thrust functions with a default execution policy.
#define THRUST_CALL(FUN, ...) FUN(thrust::cuda::par_nosync.on(ctranslate2::cuda::get_cuda_stream()), __VA_ARGS__)
改成
// Define a custom execution policy to set the default stream and disable synchronization.
struct thrust_execution_policy : thrust::device_execution_policy<thrust_execution_policy> {
private:
cudaStream_t _stream = get_cuda_stream();
friend __host__ __device__ cudaStream_t get_stream(thrust_execution_policy& policy) {
return policy._stream;
}
friend __host__ __device__ cudaError_t synchronize_stream(thrust_execution_policy&) {
return cudaSuccess;
}
};
// Convenience macro to call Thrust functions with a default execution policy.
#define THRUST_CALL(FUN, ...) FUN(ctranslate2::cuda::thrust_execution_policy(), __VA_ARGS__)
好了经过这些改动CTranslate2也可以顺利编译成功了