我发现每次生完病之后,自己总会迷茫一段时间,可能因为打乱了自己的所有计划。以至于现在啥也不想干,但是又比较慌,所以自己得给自己找点事干,要不然估计又快要怀疑人生了。

话不多说了,之前挺好奇TensorFlow是如何实现自动微分的,因为我之前看过的darknet和caffe反向传播过程均是利用矩阵形式的反向传播公式,要是想自定义loss层,必须给定loss关于输出层的偏导数$\delta$(关于这个代表啥,这里不详细解释了),但是像TensorFlow和Pytorch实现了自动微分,你只需要给定loss公式即可,不需要自己求导,感觉还是挺神奇的。上午看了看Hands-on Machine Learning with Scikit-Learn & Tensorflow这本书,对其中的原理大概有了个理解。下面就把所有内容抄在下面,然后做点笔记。

这个附录解释了 TensorFlow 的自动微分功能是如何工作的,以及它与其他解决方案的对比。

假定你定义了函数$f(x, y) = x^2y + y + 2$,需要得到它的偏导数$\frac{\partial f}{\partial x}$ 和$\frac{\partial f}{\partial y}$,以用于梯度下降或者其他优化算法。你的可选方案有手动微分法,符号微分法,数值微分法,前向自动微分,和反向自动微分。TensorFlow 实现的反向自动微分法。我们来看看每种方案。

首先,在抄袭之前,说明一下在图中使用方框代表变量或常量(不同颜色进行区分),而使用椭圆框表示操作。我之前之所以不太像画反向传播图,就是搞不清楚什么该画什么不该画,如何画。感觉这个教程图画的很好,可以借鉴一下。

阅读全文 »

这篇文章记录一些不常出现的问题,因为每个单独开一篇文章,篇幅太短,不值得。

回收站无法清空

1
sudo rm -rf ~/.local/share/Trash/*

Ubuntu系统魔法键

alt+ PrtSc + B

阅读全文 »

指数加权移动平均(Exponential Weighted Moving Average),简写为EMA。最近不知道干点啥,没有目标,所以想着先打好机器学习的基础吧,所以就简单的总结了一下基于梯度的一些优化算法,但是在看到Adadelta算法的时候,碰到了指数加权移动平均,感觉要理解这个算法,必须要理解EMA,所以在网上就抄袭了以下的内容。

为了理解下面的内容,我们先介绍一下什么是指数(妈呀这也能忘,今天高考完了,我这水平去参加高考,估计连二本都够呛了吧,23333~)。

指数是幂运算$aⁿ(a≠0)$中的一个参数,$a$为底数,$n$为指数,指数位于底数的右上角,幂运算表示指数个底数相乘。当$n$是一个正整数,$aⁿ$表示$n$个$a$连乘。当$n=0$时,$aⁿ=1$。

EMA 简介

演化

阅读全文 »

信号和槽机制是 QT 的核心机制,要精通 QT 编程就必须对信号和槽有所了解。信号和槽是一种高级接口,应用于对象之间的通信,它是 QT 的核心特性,也是 QT 区别于其它工具包的重要地方。信号和槽是 QT 自行定义的一种通信机制,它独立于标准的 C/C++ 语言,因此要正确的处理信号和槽,必须借助一个称为 moc(Meta Object Compiler)的 QT 工具,该工具是一个 C++ 预处理程序,它为高层次的事件处理自动生成所需要的附加代码。

在我们所熟知的很多 GUI 工具包中,窗口小部件 (widget) 都有一个回调函数用于响应它们能触发的每个动作,这个回调函数通常是一个指向某个函数的指针。但是,在 QT 中信号和槽取代了这些凌乱的函数指针,使得我们编写这些通信程序更为简洁明了。信号和槽能携带任意数量和任意类型的参数,他们是类型完全安全的,不会像回调函数那样产生 core dumps。

所有从 QObject 或其子类 ( 例如 Qwidget) 派生的类都能够包含信号和槽。当对象改变其状态时,信号就由该对象发射 (emit) 出去,这就是对象所要做的全部事情,它不知道另一端是谁在接收这个信号。这就是真正的信息封装,它确保对象被当作一个真正的软件组件来使用。槽用于接收信号,但它们是普通的对象成员函数。一个槽并不知道是否有任何信号与自己相连接。而且,对象并不了解具体的通信机制。

你可以将很多信号与单个的槽进行连接,也可以将单个的信号与很多的槽进行连接,甚至于将一个信号与另外一个信号相连接也是可能的,这时无论第一个信号什么时候发射系统都将立刻发射第二个信号。总之,信号与槽构造了一个强大的部件编程机制。

信号

阅读全文 »

虽然之前也面向github跑了很多代码,但是通常仅仅改改输入输出,没有深入了解过。上学期才深入了解了卷积神经网络以及反向传播,前段时间又简单的总结了常见的激活函数。接下来准备总结总结机器学习中常用的损失函数以及优化方法。然后好好看看NumpyDL这个库。不仅仅要理论跟得上,实践也要跟的上啊。好了,废话不多说了。

交叉熵

为了方便理解交叉熵的本质,我将从以此介(chao)绍(xi)信息熵、条件熵、相对熵、交叉熵。

另外,因为该笔记参考了很多教程,我尽可能的已经统一了符号,但是有些地方改的比较麻烦,我就不改了,而且一眼就能看出来什么意思。例如$\sum_{x}p(x)logp(x)$和$-\sum_{j=1}^{n}p(x_j)logp(x_j)$代表同一个意思。

信息熵

阅读全文 »

本科的时候虽然都学过这些东西,但是自己从来没有总结过这些东西,大多数时候都是抱着应付考试的态度学习的(逃~)。而且之前思考问题从来都不是以数学公式为主,不会找知识之间的关系,没有在较高维度上对这些问题进行联系与思考。最近学习老是陷入递归复习法无法自拔。算了,先简单的总结一下吧,之后面试之前可以详细的总结一波。

机器学习中的任务大多数可以分为分类问题或者回归问题。

  • 输入变量与输出变量均为连续变量的预测问题是回归问题
  • 输出变量为有限个离散变量的预测问题为分类问题
  • 输入变量与输出变量均为变量序列的预测问题为标注问题

举个例子:

  • 预测明天的气温是多少度,这是一个回归任务;
  • 预测明天是阴、晴还是雨,就是一个分类任务。
阅读全文 »

*

若两个tensor的维度相同,*符号表示对应元素相乘。例如:

1
2
3
4
5
a = torch.Tensor([[1, 2, 3], [1, 2, 3]]).view(-1, 2)
b = torch.Tensor([[3, 2, 1], [3, 2, 1]]).view(-1, 2)
print('a:',a)
print('b:',b)
print('a*b:',a*b)

运行结果

1
2
3
4
5
6
7
8
9
a: tensor([[1., 2.],
[3., 1.],
[2., 3.]])
b: tensor([[3., 2.],
[1., 3.],
[2., 1.]])
a*b: tensor([[3., 4.],
[3., 3.],
[4., 3.]])

若两个tensor的维度不相同,则将某一个tensor扩展(复制)成相同的维度,然后*表示对应位置相乘。例如:

1
2
3
4
5
a = torch.Tensor([[1, 2, 3], [1, 2, 3]]).view(-1, 2)
b = torch.Tensor([[3, 2, 1]]).view(3, -1)
print('a:',a)
print('b:',b)
print('a*b:',a*b)

运行结果:

1
2
3
4
5
6
7
8
9
a: tensor([[1., 2.],
[3., 1.],
[2., 3.]])
b: tensor([[3.],
[2.],
[1.]])
a*b: tensor([[3., 6.],
[6., 2.],
[2., 3.]])

阅读全文 »

Python的参数传递机制具有值传递(int、float等值数据类型)和引用传递(以字典、列表等非值对象数据类型为代表)两种基本机制以及方便的关键字传递特性(直接使用函数的形参名指定实参的传递目标,如函数定义为def f(a,b,c),那么在调用时可以采用f(b=1,c=2,a=3)的指定形参目标的传递方式,而不必拘泥于c语言之类的形参和实参按位置对应)

多值参数

包裹方式

除此之外,python中还允许包裹方式的参数传递,这未不确定参数个数和参数类型的函数调用提供了基础:

1
def f(*a,**b)

包裹参数传递的实现是在定义函数时在形参前面加上*或***所对应的形参(如上面的a)会被解释为一个元组(tuple,而**所对应的形参(如上面的b)会被解释为一个字典。具体调用时参数的传递见下面的代码:

1
2
3
4
5
6
def f(*a,**b):
print(a)
print(b)
a=3
b=4
f(a,b,m=1,n=2)

阅读全文 »

csc_matrix

例如:

1
2
3
4
5
6
>>> import numpy as np
>>> from scipy.sparse import csc_matrix
>>> csc_matrix((3, 4), dtype=np.int8).toarray()
array([[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]], dtype=int8)

再比如:

1
2
3
4
5
6
7
>>> row = np.array([0, 2, 2, 0, 1, 2])
>>> col = np.array([0, 0, 1, 2, 2, 2])
>>> data = np.array([1, 2, 3, 4, 5, 6])
>>> csc_matrix((data, (row, col)), shape=(3, 3)).toarray()
array([[1, 0, 4],
[0, 0, 5],
[2, 3, 6]])

data是存储的数据,矩阵以列来存储,很多人学习完了线性代数,甚至不知道矩阵一般是以列还是以行来存储。从向量Vector的角度来看,矩阵都应该以列方式来存储,以列来理解和存储更符合实际需要,我们常用的行向量$x = [1,2,3,5]$,在运算时都要进行一个转置$x^T$。实际上Numpy中矩阵也是使用csc_matrix存储。

那么,在上面例子中,csc_matrix表示以列的形式存储矩阵,观察可知datarowcol的维度相同,既然data为存储的数据,那么可以联想到row[i]col[i]表示data[i]数据在矩阵的位置,例如row[1]=2col[1]=0表示矩阵的第3行第1列存储data[1]=2

阅读全文 »

矩阵乘法

  • 结合律:$A(BC)=(AB)C$
  • 分配率:$A(B+C)=AB+AC$(左结合率)
    $(B+C)A=BA+CA$(右结合律)
  • $(\lambda A)B=\lambda(AB)=A(\lambda B)$

对角矩阵乘法

设$D$和$U$为对角矩阵,$A$为普通方阵。这些矩阵的维度相同,则有以下规则:

  • $DA$,即矩阵$ A$ 左乘一个对角矩阵$ D$,是分别用 $D$ 的对角线元素分别作用于矩阵 $A$ 的每一行;
  • $AD$,即矩阵$ A$ 右乘一个对角矩阵 $D$,是分别将$ D$ 的对角线元素分别作用于矩阵$ A$ 的每一列。
  • $DU$,即对角矩阵之间的矩阵乘法运算,对角线元素相乘,仍为对角矩阵,自然此时满足乘法的交换律。即$UD=DU$
阅读全文 »