分类 软件 下的文章

最新版的网易云音乐(1.2.1)使用到了deepin自己编写的qcef,该组建的功能是为第三方软件提供内嵌chrome浏览器的支持。由于是deepin自己写的,dnf里面还没有形成相应的包,所以需要自己编译。

安装了qt库之后,使用cmake开始编译,遇到了这么一个问题:

fatal error: QtGui/private/qguiapplication_p.h not found
#include <QtGui/private/qguiapplication_p.h>
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

安装了qt5的devel包也没用。后来发现private headers被放在了这么一个奇怪的包里:qt5-qtbase-private-devel

安装完这个包,编译继续,正常完成,网易云音乐可以使用。

此外,ubuntu包里的libs就可以删除了,因为可以通过在系统里用dnf手动杆状需要的依赖库。 数据文件可以通过ar x命令解压,然后在里面的data.tar.gz里。

在国内逛了老半天,都tm是那几篇博客,讲的方法我从f26试到f28,没有一次是成功的(生气)。 然后到国外逛,在Reddit上看到了有不少人在对这个进行讨论。有人直接用nvidia的.run文件安装驱动,然后上bumblebee管理,也有人用rpmfusion里的驱动,也有人用Negativo17的nvidia驱动源。为啥我只给最后一个方式添加链接呢?因为这就是本篇的主角。 至少在我华硕+HM175的笔记本上,使用原生驱动加bumblebee在配置正确的情况下是会直接让电脑死机的,也不知为啥,看到Negativo17这个名字的时候,总有种熟悉感,而且直觉告诉我用了这个一定会配置好。。。

直接上操作了:

  1. 为了让电脑首先正常地启动,修改/etc/sysconfig/grub中的GRUB_CMDLINE_LINUX变量,如果有与modeset相关的一律删掉,改为rd.driver.blacklist=nouveau用以在开机时不加载会让电脑卡死的nouveau驱动。 在此顺便提一下:nomodeset将不会加载任何驱动,直接使用llvmpipe以兼容方式实现最基本的图形输出;nouveau.modeset=0将会加载但不使用nouveau驱动,若是cpu有核显的话会加载并使用对应的核显驱动。
  2. 添加软件源
    sudo dnf config-manager --add-repo=https://negativo17.org/repos/fedora-nvidia.repo
  3. 安装驱动 基本驱动对应的是nvidia-driver,需要使用CUDA的话还需要安装nvidia-driver-cudacuda-devel;需要看X Server Settings的安装nvidia-settings。 GPU开发者全家桶:
    sudo dnf install nvidia-driver nvidia-driver-cuda cuda-devel nvidia-settings

    根据作者描述,如果是游戏玩家的话,可能还需要32位的图形库nvidia-driver-libs.i686

装完就完事了。直接能用。

然后根据作者描述有以下两种情景: 1)使用nvidia的官方闭源驱动:在该场景下能最大程度地发挥GPU的性能,但是所有应用将运行在nvidia GPU上,因而无法关闭; 2)使用nouveau开源驱动:对于GPU的使用可能不是十分充分,但是可以选择是否将应用运行在nvidia GPU上,因而可以从某种程度上节省电能,即在该模式下,允许nvidia GPU休眠。 也就是说,使用Negativo17的驱动源,在目前的Fedora上是无法兼顾性能与能耗的。

(有人在Reddit论坛上提到,nvidia官方的run文件不受linux发行版的包管理器管理,会修改许多文件,可能与其他软件造成冲突;自身的卸载指令也无法完全生效,总之就是卸不干净。。。反正据他们推荐,在好还是用包管理器提供的显卡驱动)

LLVM连同组件一起编译

对LLVM有初步了解的话,会发现LLVM可以被描述为编译器的“中后端”。也就是说,LLVM本身不是一个完整的编译器,需要与编译器前端等组件配合使用才能完成完整的编译过程。作为可选组件形式与LLVM一同发布的配件就有配置的讲究了。 根据CMakeList文件对组件的配置,加上网上其他人对于编译过程的总结,对组件及其位置罗列如下:

文件名 对应组件 对应位置
llvm-.src.tar.gz LLVM本体 ./
cfe-.src.tar.gz Clang ./tools/clang
compiler-rt-.src.tar.gz Compiler-RT ./projects/compiler-rt
libcxx-.src.tar.gz libcxx ./projects/libcxx
libcxxabi-.src.tar.gz libcxxabi ./projects/libcxxabi
libunwind-.src.tar.gz libunwind ./projects/libunwind
lld-.src.tar.gz LLVM连接器 ./tools/lld
lldb-.src.tar.gz LLVM调试器 ./tools/lldb
openmp-.src.tar.gz OpenMP支持 ./projects/openmp
polly-.src.tar.gz (暂时不懂) ./tools/polly
clang-tools-extra-.src.tar.gz Clang附加工具 ./tools/clang/tools/extra
test-suite-.src.tar.gz 测试程序(相当大) ./projects/test-suite

编译时遇到错误:r7 cannot be used in asm here

https://tls.mbed.org/kb/development/arm-thumb-error-r7-cannot-be-used-in-asm-here

根据上述网站叙述,该问题在于gcc对于arm处理器中寄存器的使用方式与arm自身对编译过程的优化中产生了冲突。arm优化的函数在汇编中显式地使用了编号为r7的寄存器,而在不经优化的情况下,r7被gcc用作帧指针寄存器,不允许被显示地用作其他用途,从而报错。

在解决这个问题时,发现另一个问题:理论情况来说,发布的稳定版的软件源码在编译时会默认设置为发布版本Release,在该模式下,编译器将会对目标软件进行大幅优化以加快运行速度(比如常见的开启-O2-O3选项),删除不必要的调试信息从而缩小软件大小。而LLVM却将其默认设置为了调试版本Debug,在该模式下,将保留较多的源代码信息,能够在出错时较好地帮助开发人员进行调试,也会相比发布版本有着更加接近原代码的二进制逻辑过程,而这也正是上面在直接编译LLVM时遇到错误的原因。

因而解决方法十分清晰了:将CMake中决定编译版本的参数设置为Release即可。

cd /path/to/llvm/src
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release

然后再加上其他需要的参数配置完以后,使用make进行编译即可。

若是只想解决该问题并编译调试版本的话,在编译器参数中加上-fomit-frame-pointer选项即可。

https://devtalk.nvidia.com/default/topic/1049681/nsight-visual-studio-edition/nvidia-nsight-visual-studio-edition-2019-1-with-cuda-9-2/

  1. C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.2\extras\visual_studio_integration\MSBuildExtensions下的文件复制到C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Microsoft\VC\v160\BuildCustomizations

  2. 编辑C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.2\include\crt\host_config.h的133-135行,强行添加对新版本VC++的支持。把133行的1913改成1921,要是不怕出事可以直接注释掉整个if。我的个人修改方法:在修改133行的同时,139行插入
#elif _MSC_VER == 1921

#pragma message("support for Microsoft Visual Studio 2019 is unofficial!")

用于验证修改是否有效。

有一点要注意的是,CUDA若是安装在默认的X:\Program Files目录下的话,修改其中的文件通常需要管理员权限。而我使用的gedit会很神奇地在没有权限的时候(即以普通用户权限保存文件),不知道自动在哪创建一个同名副本保存,并且还会每次贴心地读取副本。。。我一直以为是哪里缓存的问题,直到重启电脑发现文件变回原样才想起来。。。所以说在权限问题上尽量要清晰,不要偷懒或者马虎。

改编自 https://blog.csdn.net/Vipbinn/article/details/82978003 ->来源追踪:https://blog.csdn.net/chengshuhao1991/article/details/78545723

在通过TensorFlow中文社区TensorFly对TensorFlow框架进行了解的时候,对于入门的第一个例子进行了逐行的学习,对于数据的生成、表示,以及各个函数的作用有了一定的认识。其中reduce_mean()函数的定义和作用让我觉得很有意思,但又无法确认对其的理解,在网络上浏览了一些博客,发现有不少与我的理解是相同的,因此记录下来。

使用任意具有代码补全功能的IDE,在完成导入工作(即import tensorflow as tf)后,输入tf.reduce_,会得到大量reduce开头的函数补全提示,其中就包含reduce_mean()

文档中列出的所有操作为: reduce_all(...) 逻辑与 reduce_any(...) 逻辑或 reduce_euclidean_norm(...) 欧几里得范数(Euclidean norm of elements)->\sqrt{\sigma_{i=1}^{n} x_{i}^{2}} reduce_logsumexp(...) 如同名字,先取指数幂,求和后取对数 -> \log_{10} \sigma_{i=1}^{n} e^{x} reduce_max(...) 最大值 reduce_mean(...) 平均值 reduce_min(...) 最小值 reduce_prod(...) 乘积 reduce_std(...) 标准差 reduce_sum(...) 求和 reduce_variance(...) 方差

其中关于reduce_mean(),官方给出的解释如下:

tf.math.reduce_mean(
    input_tensor,
    axis=None,
    keepdims=None,
    name=None,
    reduction_indices=None,
    keep_dims=None
)

Reduces input_tensor along the dimensions given in axis. Unless keepdims is true, the rank of the tensor is reduced by 1 for each entry in axis. If keepdims is true, the reduced dimensions are retained with length 1.

If axis is None, all dimensions are reduced, and a tensor with a single element is returned.

其中,axis参数指定了计算过程中需要“降维”的维度,若是不传值的话,默认对全部维度采取降维操作,返回的是一个单独的值(维度为0),否则将按照指定的维度执行降维操作。而keepdims参数则用于申明要求在操作过程中不降低维度,由于各类reduce操作均属于聚合操作,因而该参数的实际含义为在计算完成后,为其保留一对方括号(即一个维度)。

咕果的开发团队把之前版本的参数名keep_dims改为了keepdims,所以如果使用的是比较老的版本的话,可能需要考虑改一下函数名= =(还算良心地没有直接去除对老参数名的支持)

在文档给出的例子中,使用输入张量

x = tf.constant(
  [[1., 1.],
   [2., 2.]]
)

对于两个常用参数(axis, keepdims)的测试,结果分别如下: 不传值的情况下:

>>> op = tf.reduce_mean(x)
>>> sess.run(op)
1.5

指定axis的情况下:

>>> op = tf.reduce_mean(x, axis = 0)
>>> sess.run(op)
array([1.5, 1.5], dtype=float32)

>>> op = tf.reduce_mean(x, axis = [1])
>>> sess.run(op)
array([1., 2.], dtype=float32)

>>> op = tf.reduce_mean(x, axis = [0, 1])
>>> sess.run(op)
1.5

指定keepdims=True,即保留维度的情况下:

>>> op = tf.reduce_mean(x, keepdims = True)
>>> sess.run(op)
array([[1.5]], dtype=float32)

>>> op = tf.reduce_mean(x, axis = [1], keepdims = True)
>>> sess.run(op)
array([[1.],
       [2.]], dtype=float32)

由此,两个常用参数与函数本身的作用就能够比较清晰地展示出来了。

那么,回到标题:既然都是聚合函数,为什么要在函数名前加一个reduce_前缀呢? 根据上文的描述,答案应该是比较清晰了:在进行了这些聚合操作之后,TensorFlow会默认将结果作为数据返回,也就是说,不论你的axis参数填了没,填了什么,在输入张量的至少某一个维度,一定会进行聚合操作,而聚合操作之后,数据合而为一,降低了输入张量的维度。而在英语中,reduce作为动词,有着减少,缩小(尺寸、数量、价格等)的意思,在此可以引申为在维度数量上的缩小。这样理解之后,看着函数名,对于其记忆和功能的推测就轻松多了。