导航:如果你同在搭建QRNN时遇到问题,不妨从问题1
按顺序阅读
如果搭建其他项目中遇到[WinError 126]问题,可尝试直接跳转问题2
,希望能带去一些启发。
最近在做时间序列处理,需要用到Quasi-Recurrent Neural Networks(QRNN),源码地址。但遇到了各种各样的问题,其中最主要的是标题中的问题[WinError 126]
。
鉴于当前论坛中关于[WinError 126]的相关问题较少且回答较为单一,写下了第一篇博客。
先前配置:torch==1.8.1
, cuda==11.1
。直接运行,往往会出现以下错误:
RuntimeError: Legacy autograd function with non-static forward method is deprecated. Please use new-style autograd function with static forward method.
原因:pytorch版本高于1.3会出现该问题。当前版本要求forward过程是静态的,所以需要将原代码进行修改。解决方法有两个:
一、修改代码(推荐)
简单的自定义Function函数较为简单(例如常见的梯度反转,仅包含forward和backward两个函数),网上的例子也有很多。但QRNN源码中的forget_mult.py
下,类GPUForgetMult
中包含了自定义的编译函数compiler(self)
。对于我这种没有系统学过类的人,改变量近乎不可能,调了多半天还是报错,放弃了。(其实后来发现,根本原因还是[WinError 126],其实改成功了hh)
二、torch降级
其实根本没有“降级”一说,就是将高版本torch卸掉再装。由于高版本的cuda又和低版本的torch不匹配,加之各种冲突报错,后来干脆重新搭了个新环境。所以,如果你对python的“类”比较熟悉,同时也在用QRNN源码,建议按照“Legacy autograd function”的官方指引,将forward修改为静态的即可,不建议为了跑一个QRNN,把原环境都推倒重建。
重新搭建了环境,当前配置为:torch==1.4.0
,cuda==10.1
,同时安装所需的cupy
和pynvrtc
库。
然后,就来到了标题中的问题:
File "C:/XXX/pytorch-qrnn-master/torchqrnn/forget_mult.py", line 199, in <module>
resulta = ForgetMult()(forget, a, last_h, use_cuda=True)
File "D:\Anaconda3\envs\XXX\lib\site-packages\torch\nn\modules\module.py", line 532, in __call__
result = self.forward(*input, **kwargs)
File "C:/XXX/pytorch-qrnn-master/torchqrnn/forget_mult.py", line 178, in forward
return GPUForgetMult()(f, x, hidden_init) if use_cuda else CPUForgetMult()(f, x, hidden_init)
File "C:/XXX/pytorch-qrnn-master/torchqrnn/forget_mult.py", line 119, in forward
self.compile()
File "C:/XXX/pytorch-qrnn-master/torchqrnn/forget_mult.py", line 101, in compile
program = Program(kernel, 'recurrent_forget_mult.cu')
File "D:\Anaconda3\envs\XXX\lib\site-packages\pynvrtc\compiler.py", line 49, in __init__
self._interface = NVRTCInterface(lib_name)
File "D:\Anaconda3\envs\XXX\lib\site-packages\pynvrtc\interface.py", line 87, in __init__
self._load_nvrtc_lib(lib_path)
File "D:\Anaconda3\envs\XXX\lib\site-packages\pynvrtc\interface.py", line 110, in _load_nvrtc_lib
self._lib = cdll.LoadLibrary(name)
File "D:\Anaconda3\envs\XXX\lib\ctypes\__init__.py", line 426, in LoadLibrary
return self._dlltype(name)
File "D:\Anaconda3\envs\XXX\lib\ctypes\__init__.py", line 348, in __init__
self._handle = _dlopen(self._name, mode)
OSError: [WinError 126] 找不到指定的模块。
“Win”的模块是指.dll文件,即找不到某个.dll文件。但请注意:这个“找不到”分两种情况:1. 真的没有该.dll
文件 2. 存在该.dll
文件,但没有被正确找到。
一开始以为是情况1(即真的缺某个文件),但又论坛中类似的帖子不一样,报错没有告诉你具体缺哪个.dll,于是各种盲目重装C++运行库,还是于事无补。
注意到报错中可能和pynvrtc
库有关,就去github上的pynvrtc-issue中挨个找相关问题,终于先后找到了两个有联系的回答:回答1和回答2。
结论:层层寻找,在pynvrtc
库中interface.py
文件下的NVRTCInterface
类中,将第96行附近的:
if system() == 'Windows':
def_lib_name = 'nvrtc64_92.dll'
修改为:(对应你的cuda版本号,我是10.1,所以是_101_0)
if system() == 'Windows':
def_lib_name = 'nvrtc64_101_0.dll' # 对应你的cuda版本号
同时,需检查你的环境目录X:\XXX\Anaconda3\envs\环境名\Library\bin
中有该nvrtc64_101_0.dll
文件,名称需与以上代码块中刚刚修改的语句完全一致。如果没有,自行百度下载对应cuda版本的nvrtc64.dll
文件即可。
至此,最大的问题终于解决了。距离运行forget_mult.py
就只剩下一些小问题,简单列出一个:
此时若直接运行forget_mult.py
,大概率会出现如下错误:
AttributeError: 'bytes' object has no attribute 'encode'
AttributeError: 'Program' object has no attribute '_program'
溯源具体报错,推测出现了重复编码(.encode()
)的问题。定位GPUForgetMult
类下的compile(self)
函数(方法),将103行附近的:
program = Program(kernel.encode(), 'recurrent_forget_mult.cu'.encode())
两个变量的.encode()
后缀删去,即改为:
program = Program(kernel, 'recurrent_forget_mult.cu')
即可解决。
剩下便是些小细节,例如输出维度等等,便不再一一列举。
当出现”[WinError 126] 找不到指定的模块“的错误时,基本可以断定和.dll
文件有关。具体可能有两种情况:
1. 指定位置中确实没有该.dll
文件。
2. 该.dll
文件存在,但没有被正确定位和调用(本例)
还有,就是出了问题之后不能只会把报错的最后一行粘贴到百度或者Google上,要静下心来逐行查看出错提示,往往能推断出出错位置,再结合论坛和自身经验完成debug。
(第一篇blog,希望后面有机会多多记录,帮到更多的人吧)