配置环境填坑小记

方法永远比困难多

Posted on January 21, 2019


计算机科学除了有丰富的理论内涵,也是一门锻炼工程能力的实践科学,填坑力 就成为了解决问题的能力中一个重要的方面。 类似医院里的实习医师、法庭内外的年轻律师、中学里的青年教师,ta们的能力同样是在不断的实践摸索中成长的。要学会投入工作, 加入自己的思考,不断填坑又爬坑逐渐掌握无可替代的经验和能力。计算机的专家也是在坐得住地debug中、不断参与比赛、解决项目中, 成长为能写出bug-free clean and elegant的代码。理论和实践,都值得投入学习取得进步。

CUDA和显卡驱动以及pytorch版本的对应关系

参考文章

安装多版本CUDA时

  • 历史版本 cuda https://developer.nvidia.com/cuda-toolkit-archive cudnn https://developer.nvidia.com/rdp/cudnn-archive
  • 多版本 https://blog.csdn.net/Tesion_001/article/details/89737044
  • 检查nvcc https://stackoverflow.com/questions/53422407/different-cuda-versions-shown-by-nvcc-and-nvidia-smi
  • nvcc --version和nvidia-smi显示的cuda版本不一致。务必以nvcc的为准。安装cuda时遵循指南,并且检查必要的环境要求

Linux更改用户环境变量和所有用户环境变量

  • 创建用户 https://www.cnblogs.com/sunyllove/p/9772053.html
  • 修改用户环境 https://blog.csdn.net/weixin_38361347/article/details/93392842
  • 具体修改CUDA环境 https://blog.csdn.net/Tesion_001/article/details/89737044
  • 关于沿用root配置的环境 usermod -g root devonn

安装CUDA

去官网,会生成所需版本的安装命令,如:

wget http://developer.download.nvidia.com/compute/cuda/10.1/Prod/local_installers/cuda_10.1.243_418.87.00_linux.run

sudo sh cuda_10.1.243_418.87.00_linux.run

附1:CUDA对应的NVIDIA驱动版本对照表
https://blog.csdn.net/zhw864680355/article/details/90411288

附2:看看别人的填坑记 https://blog.csdn.net/QLULIBIN/article/details/78714596

注1:配置环境一般考虑较新的稳定版,而不是追求最新。版本还可以再更新,而不要现在去冒着driver、toolkit、platform兼容上的风险。

安装版本检查

pip安装一般会自动检查,只可以安装和系统适配的whl(Wheel,是Python软件包的一种二进制分发格式)。 但希望pip install xx.whl时,一般可以根据名称检查是否适配。下载合适的whl文件。
python -m pip debug --verbose
可以检查环境版本。
xxx-cp310-cp310-manylinux_2_28_x86_64.whl
名称指示了适配的环境版本。

TensorFlow安装

通常和CUDA版本安装一起考虑。

  • tensorflow for windows

    https://www.cnblogs.com/xianhan/p/9084815.html

    https://www.cnblogs.com/guoyaohua/p/9265268.html

    https://blog.csdn.net/gyp2448565528/article/details/79451212

PyTorch奇怪的报错

RuntimeError: cuDNN error: CUDNN_STATUS_NOT_SUPPORTED. This error may appear if you passed in a non-contiguous input.
  • 原因:版本不匹配
  • 解决方法: 使用torch.backends.cudnn.enabled = False

anaconda

  • 安装与配置 https://www.jb51.net/article/137772.htm
  • jupyter快捷键 https://blog.csdn.net/HeatDeath/article/details/78030902
  • jupyter魔法命令 https://blog.csdn.net/HeatDeath/article/details/78030902
  • jupyter启动默认设置 https://blog.csdn.net/m0_37723350/article/details/89141276
  • 如果想从指定目录打开 命令时jupyter notebook + 路径即可
  • 如何翻墙访问云端的jupyter端口 把远端端口映射到本地,浏览器可以本地打开:ssh -L 8008:localhost:8888 用户名@IP 就可以本地8008端口打开云端jupyter notebook.
  • https://www.jianshu.com/p/013a95576cf6
  • nvidia断电驱动崩溃

    • 驱动卸载重装 https://blog.csdn.net/Netooo/article/details/84888755
    • 记得chmod赋予run文件执行的权限

    关于调试

    • |tee log.txt 可以将终端内容输出记录到文本
    • Compare IDE中 Select for Compare & Compare with Selected

    关于GCC (redhat系)

    • 有许多模型算子,对部署的GCC版本有要求。比如某些DCNv2,需要gcc 5以上
    •           # 使用scl软解集
                yum install centos-release-scl scl-utils -y
                yum install devtoolset-4-gcc.x86_64 devtoolset-4-gcc-c++.x86_64 devtoolset-4-gcc-gdb-plugin.x86_64 -y
                scl enable devtoolset-4 bash
            
    • 以上方式可以在当前用户下,创建一个gcc 5.3的环境。而不影响root环境,也不影响当前用户其他环境。只是替换了编译器。
    • 通过gcc -v查看前后改变
    • 若出现动态库缺失或者版本不够,参见libstdc++.so.6*

    关于OpenCV

    • PIP3依赖有:opencv-python-headless, opencv-python, opencv-contrib-python
    • 这三者在完整性上是递增的,常用的opencv-python,如果你的环境报错缺少libSM,这是图形界面的库, 如果你的环境不需要,可以把opencv-python的依赖改成opencv-python-headless。如果要用一些有专利 收费的算法,则使用opencv-contrib-python.
    • Of course there is opencv-contrib-python-headless
    •             python中安装OpenCV提供四种依赖包
      
                  1,如果只需要主要模块
                  pip install opencv-python
      
                  2,如果需要更全的模块
                  pip install opencv-contrib-python
      
                  3,如果资源较少,不需要任何GUI功能
                  pip install opencv-python-headless
      
                  4,如果资源较少,不需要任何GUI功能,包含contrib模块
                  pip install opencv-contrib-python-headless
            
                有些仓库,比如MMCV需要opencv-python,可以采取如下方式:
                '''
                  export DEBIAN_FRONTEND=noninteractive
                  apt-get -y install tzdata
                  apt-get update
                  apt-get install ffmpeg libsm6 libxext6  -y
                  pip3 install opencv-python
                '''
                再就是opencv如果不是在ffmpeg之后构建的,可能会有视频数据I/O方面的问题。
                '''
                apt update
                apt install -y ffmpeg
                pip uninstall -y opencv
                pip install opencv-python-headless (or apt install -y python3-opencv)
                '''
                最后可以打印python3 -c "import cv2; print(cv2.getBuildInformation())"|grep FFMPEG看是不是yes
            

    nvidia-smi显存被占用,却没显示进程

    • 使用fuser命令
    • fuser用于显示哪些进程正在使用给定的文件、文件系统或unix套接字
    • sudo fuser -v /dev/nvidia*
    • 记住最好加sudo,因为有些进程是只有系统管理员可见的。 查看占用指定显卡的进程id之后,kill掉就好了。
    • kill -9 PID

    远程终端标准输出的恢复

    如果使用tmuxscreen、supervisor,它们有进程托管的功能可以很好的恢复。但关闭普通的远程终端,如何恢复标准输出呢?
  • tty/pts详解
  • 先ps ef找到进程号PID,这时也能看到TTY(与进程关联的终端),STAT是检查的状态R运行,S睡眠,l空闲。
  • 首先找到进程号,然后获取进程的标准输出。linux一切到可以看作文件,/proc/pid/fd/1 就是pid进程的标准输出。
  • Maybe these schema can clarify the situation. This is the usual setting:
          Terminal  (/dev/ttyX or /dev/pts/x)
                                    device
                                       |
                        (screen)<--[]---o-\----->(stdin)
                                                \ \
    (hardware console or                         \ `----(stdout) Process2
     virtual console or terminal                  `---->(stdin)
     emulators like xterm, …)
      
    And there is no way to plug some new Process3 like this:
          Terminal
                                  device
                                     |
                 (screen)<---o---[]-o-\---->(stdin)
                           | /              \ \
                           | |               \ `---(stdout) Process2
                           | |                `--->(stdin)
                           | |
                           \ `---------------------(stdout) Process3
                            `--------------------->(stdin)
      
    What screen (and others) does is allocating some pseudo terminal device (like xterm does) and redirect it to one or more "real" terminals (physical, virtual, or emulated):
          Terminal                   pseudo
                 devices              ,--> Terminal (/dev/pts/x)
                    |         _______/      device
    Terminal <--[]--> |screen | <--[]--o-\--->(stdin)
    Terminal <--[]--> |_______|                 \ `--(stdout) Process2
                                                        `-->(stdin)
      
    Using screen -x you can attach one more terminal, xterm, whatever (say Terminal 3) to the screen session.
    So no, you can't communicate directly through stdin/stdout with processes attached to a different terminal. You can only do so through the process that is controlling this terminal if it happens to be a pseudo terminal, and if this process was concieved to do so (like screen is). https://unix.stackexchange.com/questions/17838/how-can-i-switch-between-ttys-without-using-screen
  • 所以最好是使用tmux:
    The simple answer is that if you want to reconnect to a terminal from a different place, use screen or tmux.
  • 磁盘推出

    • 磁盘没有被推出,因为一个或多个程序可能正在使用它。
    •           df -lh 查看硬盘编号,如/dev/disk2s1
      
                lsof /Volumes/Seagate/
      
                打开活动监视器 Activity Monitor,找到 QuickLook,强制退出
                如果 lsof /Volumes/Seagate/ 没有输出的话,加上 sudo 再执行 sudo lsof /Volumes/Seagate/,
                估计会发现是 mds 和 mds_store 在后台搞鬼, 这两个是 SpotLight 的进程,强退之!
            
    • lsof : lists openfiles 列出打开文件。 注:在Unix中一切(包括网络套接口)都是文件。

    跳板机掉线

    • 检查机器是否设置永不休眠
    •       Mac os 在设置关闭显示器不休眠中有两个状态分别为“电池”与“电源适配器”
            Step1:系统编好设置 — 节能——电池,勾选“当显示器关闭时,防止电脑自动进入睡眠”,取消“如果可能,使硬盘自动进入睡眠”。
            Step1:系统编好设置 — 节能——电源适配器,勾选“当显示器关闭时,防止电脑自动进入睡眠”,取消“如果可能,使硬盘自动进入睡眠”。
            
    • 检查客户端是否设置保持活动状态

    Shell下不能使用Tab补全命令

      这是因为/etc/passwd中该用户的默认shell不是/bin/bash
    • 修改方式 1. chsh命令
    • 修改方式 2. sudo vim /etc/passwd
    • /home/hdw:/bin/bash
    • 修改方式 3. usermod - s /bin/bash 用户名
    • -s 修改用户登入后所使用的shell。

    服务器禁止内核自动更新

          内核默认会自动更新,更新到某些版本可能和显卡驱动不适配。
          所以最好是禁止自动更新:
          https://blog.csdn.net/weixin_43064339/article/details/88370372
          如果已经发生内核变动、更新,显卡显示不出来,可以稍微补救下:
          https://www.jianshu.com/p/3cedce05a481
          如果是没死机的情况显卡出现问题,nvidia也提供了自检命令:
          https://blog.csdn.net/u012759006/article/details/103629003
          不过这个还没正式用过,不晓得有帮助不
    
          宕机查看下 /var/log/kern.log
          也可以看看last -F 宕机当天的用户登录情况
      

    Linux crontab 定期执行程序

          crontab [ -u user ] { -l | -r | -e }
          -e : 执行文字编辑器来设定时程表
          -r : 删除目前的时程表
          -l : 列出目前的时程表
    
          注:定时执行top命令需要 -b
          http://blog.itpub.net/25311408/viewspace-686412
      

    Chrome连接问题

        Chrome您的连接不是私密连接
        解决:就是在当前页面用键盘输入  thisisunsafe  ,不是在地址栏输入,就直接敲键盘就行了,页面即会自动刷新进入网页。
        thisisunsafe 这个命令,说明你已经了解并确认这是个不安全的网站,你仍要访问就给你访问了。
      

    根据安全要求升级软件包

        sudo apt update
        apt list --upgradable
        sudo apt-get install --only-upgrade package1 package2 ...
        或
        sudo apt upgrade package1 package2 ...
      

    man apt查看手册

        apt-get 是在基于 Debain 的机器(如Ubuntu)中进行包/应用程序管理的命令。
    
        更新和升级选项之间存在细微差别。
    
        ・sudo apt-get update # 获取最新资源包
        是更新源列表的命令,如果您修改源列表或者想要进行同步刷新或添加新的ppa源,那么您应该执行上面的命令。
    
        ・sudo apt-get upgrade # 更新本机已安装的软件包
        命令将尝试下载在apt服务器上具有更新的所有软件包,然后尝试按下“y”时安装它们。这就像系统升级到新包。
    
        ・sudo apt-get dist-upgrade # 本机系统软件更新
        dist-upgrade命令也算更新所有软件包,但是当 upgrade 更新时,如果依赖关系无法解决时可能会报错或者停止,但是 dist-upgrade 命令可以自动解决依赖关系
    
        但是 dist-update 有一定的危险性,因为可能会更新很大您不希望更新的软件,导致原理的一些需要依赖旧包的软件无法运行。
        所以,使用 apt-get dist-upgrade 时,请慎重使用,一般是 apt-get update && apt-get upgrade 可以保证系统的完整性。
      
        apt-get是某些linux发行版使用的一个“包管理器”(还有别的发行版使用yum等,以及brew等其他平台上的包管理器,工作原理类似)。
    包管理器的作用是从 源(Source)服务器那里下载最新的软件包列表 (PS:软件源服务器地址可以在/etc/apt/sources.list里面看到。),然后在你需要安装某个软件包(apt-get install)的时候从列表里面查询这个软件包的版本信息、系统要求、翻译、依赖项(该软件正常运行必须安装的其它软件)并且添加到同时安装的列表里面,再查询所有安装列表里面的软件包的.deb文件下载地址,最后批量下载,自动分析安装顺序然后安装完成。
    但是这个软件包列表是不会被自动下载的,需要用户使用apt-get update更新。这样,apt-get才能知道每个软件包的最新信息,从而正确地下载最新版本的软件。
    至于apt-get upgrade,则是对已经安装的软件包本身进行更新的过程。由于确定要更新的软件包需要对本地安装的版本和列表的版本进行比较,所以要在update以后运行这一条。
    apt-get dist-upgrade会识别出当依赖关系改变的情形并作出处理(所以通常这个会被认为是有点风险的升级),而apt-get upgrade对此情形不处理。
    例如软件包 a 原先依赖 b c d,但是在源里面可能已经升级了,现在是 a 依赖 b c e。这种情况下,dist-upgrade 会删除 d 安装 e,并把 a 软件包升级,而 upgrade 会认为依赖关系改变而拒绝升级 a 软件包。
      
        请改用 apt 命令
    
        apt-get 是一个传统的低级命令,可以做很多事情。它适合由其他工具或系统管理员在脚本中使用。
        apt 命令是一个简化版本,面向普通的临时用户。它比 apt-get 做得更好、更简单。
        apt 命令被设计为对用户更加友好的 apt-get 替代方案,来自AWS建议
      

    关于显卡的温度监控

        指定显卡重启:
        nvidia-smi --gpu-reset -i 0
        如果没能正常重启,有可能是烧坏了。
        nvidia-smi窗口直接就有显示温度,下面的命令进行温度持续监控。
        nvidia-smi --query-gpu=temperature.gpu -i 7 --format=csv >> xxx.log
      

    关于youtube视频下载器

    做CV,经常会到youtube收集数据集。有时会有一些downloader的库找不到视频,其实是被禁了。这时不用被block,果断换一个库尝试。 而且几个库可以换着尝试,它们都在不断维护、更新,上一次落伍的库可能下一次更新在前面了。
        比如:
        https://github.com/AliaksandrSiarohin/video-preprocessing的issue:
    
    def download(video_id, args):
        video_path = os.path.join(args.video_folder, video_id + ".mp4")
        subprocess.call([args.youtube, '-f', "''best/mp4''", '--write-auto-sub', '--write-sub',
                         '--sub-lang', 'en', '--skip-unavailable-fragments',
                         "https://www.youtube.com/watch?v=" + video_id, "--output",
                         video_path], stdout=DEVNULL, stderr=DEVNULL)
        return video_path
    
    替换为(youtube-dl替换为yt-dlp或pytube)
    def download(ytb_id, args, proxy=None):
        """
        ytb_id: youtube_id
        save_folder: save video folder
        proxy: proxy url, defalut None
        """
        video_path = os.path.join(args.video_folder, ytb_id + ".mp4")
        if proxy is not None:
            proxy_cmd = "--proxy {}".format(proxy)
        else:
            proxy_cmd = ""
        if not os.path.exists(video_path):
            down_video = " ".join([
                "yt-dlp",
                proxy_cmd,
                '-f', "'bestvideo[ext=mp4]+bestaudio[ext=m4a]/bestvideo+bestaudio'",
                '--skip-unavailable-fragments',
                '--merge-output-format', 'mp4',
                "https://www.youtube.com/watch?v=" + ytb_id, "--output",
                video_path, "--external-downloader", "aria2c",
                "--external-downloader-args", '"-x 16 -k 1M"'
            ])
            print(down_video)
            status = os.system(down_video)
            if status != 0:
                print(f"video not found: {ytb_id}")
        return video_path
    
        yt-dlp参数:
        yt-dlp -f [下载ID] [代理配置] [视频链接] [合并语句] [外部下载器选择] [下载器参数]
    -f [id] #选择下载内容,注意和 -F 区分。例子中使用137+140,如果你只下载720p则填写22就好,后面的合并语句可不填写。
    --proxy #代理配置 见前文
    --merge-output-format [合并输出格式] #例子中选择mp4作为输出格式
    --external-downloader [下载器名称] #下载器选择 例子中选择aria2c
    --downloader-args [下载器名称]:"[下载器配置]" #下载器配置语句 例子中 x 16 代表16线程下载 -k 1M 代表块大小为1M 但youtube不支持分块故此句可忽略