0%

参考书:[Introduction to Linear Algebra]

概念汇总

这一节内容真实非常奇妙啊,简直是线代精华,用线代可以描述世间万物。空间、基、坐标表示、线性变换这四个术语息息相关,这里来阐述其关系。

  • 空间

    这个很好理解,从小我们就知道:点,线,面,体。这就对应着0维、1维、2维、3维空间,我们所处的就是三维空间。(PS:三体中的二向箔,莫非就是说明了宇宙是数字化出来的,歌者实则为编程人员,其甩出的二向箔,就是对宇宙(矩阵表示)的一部分进行了三维到二维的一个线性变化: linear transformation? interesting…)

  • 既然我们有了空间的概念,那么我们如何表示这个空间呢?基(basis)就此出现了,可以理解为:空间的基础,即空间的任何一个位置,我们都可以用基的线性组合来表示。比如在我们三维空间里面,一个standard basis就是b1(1,0,0) b2(0,1,0) b3(0,0,1),任何一个位置v我们都可以用v = α*b1 + β*b2 + Γ*b3来表示。需要注意的是,我们对基的选择是非常自由的,如我们将列向量作为基写成矩阵ANxN,R(A)=N,那么这些列向量就可以作为这个N维空间的基。

  • 坐标表示

    我们平时所画的那个三维坐标轴x,y,z笛卡尔坐标系。常用3个数字来表述一个位置,如p1=(12,34,56)。这实则用完整的语言表述是:p1点,在基b1(1,0,0) b2(0,1,0) b3(0,0,1)所表示的三维空间下的坐标为(12,34,56),用矩阵的表述语言如坐标与基同一空间下相同的点,在不同的基下其坐标表示会不一样。

  • 线性变换 (Linear Transformation)

    线性变换的定义就不再赘述了,1P405提出:任何从V=Rn到W=Rm的线性变换,都对应着其矩阵表达。(V是n维输入空间,W是m维输出空间。)

思考问题:
从V=Rn到W=Rm的线性变换的矩阵表达A是唯一的吗?

answer: 不是唯一的,变换肯定是在空间中进行的,而无关于基的选择。基的选择会确定该变换矩阵表达A。

解释:我们用顺时针旋转90度来举例子,V=R2到W=R2,那么,不管我们怎么选择V=(v1,v2)与W=(w1,w2),顺时针旋转90始终表示顺时针旋转。只是我们对基的选择,会决定该变换的矩阵表达A。
决定变换矩阵A的三要素

  • 基变换矩阵

    这个其实相当于特殊的线性变换,即Basisin -> Basisout的identitic transformation。说人话就是,我们只变换一下空间的基的表示而已。我们以1p412举例。
    basisTransformation1
    basisTransformation2
    basisTransformation3

  • 如何选择好的基,使得该变换T在这组input basis与output basis下的矩阵表示比较简单?

    待续…

K近邻算法 简介

这一部分就不赘述了,挺基本的。

为啥需要KD-Tree

KD-Tree是存储训练数据的一种结构,因为K近邻算法没有显示的学习过程,所以每次对目标点进行分类的时候,都需要借助已知的训练数据。而类似感知机这种具有显示的学习过程的算法,会根据训练数据,得出一个模型sign(<w,x>+B),后续预测直接用训练好的模型进行预测就行了。

因为这个特性,所以如果不采取特殊的数据结构对数据进行存储,那么每一次分类目标点的时候,都要遍历所有的训练数据,时间不可控。对此,KD-Tree就出来了,其实KD-Tree听名字就是一棵树,可以参考二分查找的过程。

什么是KD-Tree

这里先给出一颗KD-Tree的例子,后续再对KD-tree的Construction与Searching进行论述。KD-Tree
每一个节点对应着一个划分(就是一个大饼被刀切了),如图所示,根节点(30,40)对应了整个输入空间(整个饼),根节点将整个输入控件分为了两类,分别是x<30, x>30,由其两个分支表示。(解释为啥是x,这与选择的特征有关,看图根节点左边是选的x,所以对比x)。这样不断往下划分,最终得到了整个输入空间的划分(左边),对应的数据结构如右边所示。

闲话:其实通过上面描述应该就知道KD-Tree存储的什么东西了,它将数据的信息(具体特征的数值大小)表示在了结构上。其与排序二叉树十分类似嘛。

KD-Tree’s Construction

  • 数据描述:(5,25) (10, 12) (30, 40) (35, 45) (50, 30) (70, 70),输入空间为整个二维平面。即每个样本点,有两个特征,我们假定为(x, y)。我们先展示整个构造过程,再解释构造细节。
  1. 随机选择一点(30, 40),作为根节点,x<30的(5,25) (10, 12)位于根节点左子树上。大于的就位于右子树。

  2. 在左子树中,随机选择一点作为左子树的根节点,这里选择了(5, 25)。然后y<25的位于其左子树,y>25的位于右子树

  3. 这样不断迭代,最终形成了树的模样。

  4. 根据构造出来的树画图:根据判别条件画垂直的线。如根节点,根据x来判别的,那么就在这一点上,垂直与x轴,将其代表的划分(根节点是整个输入空间嘛),一分为二。

由上可知,整个过程中存在着3个问题尚未解决:我们在划分时应该选取哪个维度?划分时我们应该选择哪一个值来划分?什么时候停止划分?

  • 应该选择哪一个维度?

    一般是交叉维度来进行选择,如有n个维度,那么依次选择(1, 2, 3…n, 1, 2…n…)这样子。上述例子中就是交叉选择(x,y,x,y…)来进行的

  • 维度确定了我们应该选择哪一个点当作划分点?

    这个其实理论上来说当然是选择搜索路径最短的那个点,但是这好像不是很容易达到。《统计学习方法》中采用的方法是采用中位数当作划分点,这样可以保证整个树是平衡的。如上述第一步骤中,x的中位数是(30, 40) (以左边为基准的话)。那么根节点就是(30, 40)。

  • 我们什么时候停止划分?

    这是我们自己设定阈值,我们知道,每一个点对应一个划分区域,那么我们可设定 threshold = 10,表示如果这个划分区域中,

    1
    2
    if num(point_In_Split) < threshold
    End Spliting.

KD-Tree’s Searching

这个我懒得描述了,看李航老师《统计学习方法》上就有。需要更正的一点是(我觉得其算法3.3漏了一个判别步骤),算法3.3的(1)中,强调的是“直到子节点为叶节点为止”,但是有可能搜索结束后发现结束的那个节点并不是叶节点,如(50,30),那么就要在(50, 30)下添加一个空节点,然后以该空节点作为"包含目标点x的叶节点"

1. 奇异值分解:A=UΣV^T, 其中,U是AA^T的特征向量,Σ^2是AA^T的特征值,V是A^TA的特征向量,目的即将图片weights x heights分解为矩阵表达,这样存储时仅仅存储矩阵表达即可,从而达到压缩的效果。代码如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import numpy as np
from PIL import Image


if __name__ == "__main__":
# psuedo Code
# 1. 加载图片成width x height的数组A
# 2. 计算A^TA,算出其lambda^2, lambda是SIGMA, 对应特征向量是V1,V2;再根据(1):解AA^T的eigen vector作为U;(2)或者解AV/SIGMA得出U。
# 3. 从大到小排列SIGMA以及对应U,V得出分解内容。
# 4. 分析结论

# 1. 得出矩阵A_TA
Img = Image.open('./test.jpg')
Img_array = np.array(Img)
A = Img_array[:,:,0]
A_T = A.transpose()
A_TA = np.dot(A_T, A)

# 2. 计算出对应特征值及对应特征向量,并排好序(in order of importance)
eigenvalues,eigenVectors = np.linalg.eig(A_TA)
tmp = np.column_stack((eigenvalues, eigenVectors))
tmp = tmp[np.argsort(-(tmp[:,0]))]
singularValues, singularVectorsV = np.nan_to_num(np.power(tmp[:, 0], 0.5)), tmp[:, 1:]

# 用AV/SIGMA = U 计算U
singularVectorsU = np.dot(A, singularVectorsV)/singularValues

# 设置阈值为99%
threshold = 0.99
SigmaSum = np.sum(singularValues)
tmp = singularValues[0]
i = 1
while(tmp/SigmaSum <= threshold):
tmp += singularValues[i]
i += 1

reConstructImgArray = np.dot(
np.dot(singularVectorsU[:, 0:i+1], np.diag(singularValues[0:i+1])),
np.transpose(singularVectorsV[:, 0:i+1]))

reConstructImg = Image.fromarray(reConstructImgArray)
reConstructImg.show()
# 结果为i=1257, 即压缩为了1257*(1980+2640), 原图是1980*2640, 这样压缩保留了99%的信息
print("good luck")

2. 左为重构,右为原图

SVD_Sample_Pic

3. 结果说明

> 原图大小是 198026403(带color channel),现经过SVD压缩为了(1257(1980+2640)3)(代码中为了简单表明过程,只计算了一个color channel上的)。上述例子表明,在保存图片信息99%的情况下,压缩率为90%。

参考书目章节

  1. Introduction to linear algebra: P239, The Factorization A = QR
  2. Iterative Methods for Sparse Linear systems: P11, Gram-schmidt

    一:Gram-Schmidt

    Interesting: gilbert strang said:”i don’t know what schmidt did in this greatful process”
    在很多工作中,我们需要用到一组向量空间的正交基来简化计算(如简化求解Ax=b的最小二乘解的过程)。Gram-Schmidt就是正交化一种经典方法,掌握了投影后,gram-schmidt就很好理解了。

prerequisite: A的column space’s projection matrix is A对应投影矩阵公式

1. 首先以二维为例

(x1, x2)是线性无关的列向量,现需找出orthonormal的(q1, q2)来表示(x1,x2)的列空间。第一步:q1=x1/norm2(x1)。问题是如何依据x2找到q2使<q1, q2> = 0二维Gram_Schmidt

如图所示,x2q1上的投影p=<q1, x2>q1,而我们需要的部分是e(error) = x2-p(# 注为啥叫error在投影那一章节有记录)。从而令q2 = e/norm2(e)用人话来说就是,第n维的目标向量(qn)是第n维的已知向量(xn)依次减去其在q1 -> qn-1上的投影,最后单位化。

2. 三维图示

三维Gram_Schmidt

由此可推到出Gram_Schmidt的公式:
Gram_Schmidt公式

3. Pseudo Code of Gram-Schmidt

Gram_Schmidt_Algorithm

二:A=QR与Gram-Schmidt的关系

实际上这也是A=QR的第一种推理方式,即从Gram-Schmidt的推理过程得出A=QR。现假设我们已经通过Gram-Schmidt得到了前j个q(q1,q2...qj),这样我们就可以得到分解xj,即将xj分解至每一个正交基上。用矩阵的语言进行表达,即X=QR,X=[x1, x2...,xr],Q=[q1,q2,...,qr]。如下图所示A=QR矩阵表示

三:从行列空间规律得出A=QR

这是A=QR的第二种推理方式,C(A)是independent的,在Gram-Schmidt中,我们的目的是找出orthonormal的Q,从目的而言,Q与A的列向量代表的向量空间肯定是一样的,即C(A) = C(Q),根据线代的基础知识我们知道,肯定存在一个矩阵R,使得A=QR(A与Q的列向量空间相同)。若A is Square,那么A and Q both are invertiable。从而R=Q^(-1)A,又Q is orthonormal,so Q^(-1) = Q^T,so R = Q^TA,这样就求出了R,如下图所示。

A=QR矩阵表示方法二

四:A=QR的应用

gilbert Strang教授在书上说过:"the matrix factorization is of most importance in linear algebra",A=QR作为一种矩阵分解,可以把线性独立的矩阵,分解成QR,Q是orthonormal,R又是upper triangle,特别是orthonormal给计算提供了很好的性质,目前接触到的就是在least square solution中的投影矩阵部分,的那一块直接为单位矩阵了,大大节约了计算时间成本。

作业描述:新竹清华大学,周志远老师的并行计算课程,作业一

  1. 环境配置

    slurm平台搭建成功的基础上,(使用sinfo查看,应该如下图所示),包含2台机器(虚拟机ubuntu16.04 64位),一台master, 既作为control节点,又作为computing节点,配置为2核cpu。一台slaver,只作为computing节点,配置为一核cpu。
    sinfo配置成功图片

  2. 配置共享nfs文件服务器

    这是根据报错来的,我在master节点独立目录下运行任务时报错如下图所示,显示在slaver节点上找不到这个目录,于是采用share memory的方式,根据这篇nfs配置对nfs进行配置。
    nfs未配置
    我的配置是将物理主机的/mnt/nfs_share作为共享目录,然后将虚拟机(master and slaver)的/mnt/nfs_clientshare作为挂载目录

    1
    2
    3
    # 需要注意的一条命令,在nfs client上对nfs server上目录进行挂载
    sudo mount 192.168.1.103:/mnt/nfs_share /mnt/nfs_clientshare
    # 注意,最后面没有 '/',不然好像会挂在失败(未提示错误但是就是显示不出文件)
  3. 修改slaver状态

    我这默认salver’s state=down, 需要手动设置其状态为idle,然后再使用sinfo查看节点状态
    scontrol: update NodeName=slave1 State=down

  4. hello.c进行测试

    用master主机在共享目录下下载测试文件,运行如下

    1
    2
    3
    # mpicc编译
    mpicc hello.c -o hello
    srun -n 3 hello

    结果如下图所示,但是按道理来说应该是0 of 2, 1 of 2, 2 of 2啊,为啥是3个 0 of 1 呢,奇怪
    nfs配置成功后运行srun

机器配置(注:我是基于zxh的博客,以及官方文档针对ubuntu进行配置的)

两台ubuntu的虚拟机,一台作为master(2核心),一台作为slave(1核心)

  • 配置过程
  1. 配置etc/hosts文件, 以及配置静态ip(默认是dhcp动态的,这样重启或者到了一个新的网络环境下局域网内部ip会自适应,这样每次都要调整很麻烦,所以此处设置为静态的)
    注意修改master node的etc/hostname文件,最好保持与你的用户名一致,不然后续可能会出现”slurmctld: error: this host (xx) not valid controller (master or (null))”错误
    设置静态ip的时候需注意网关的设置,一般是192.168.1.1(路由器的地址嘛,关于网关的知识可以自行了解一下)
  2. 关闭防火墙(ubuntu’s SELinux默认是关闭的)
    1
    ufw disable (注:ufw,即uncomplicated firewall)
  3. 配置ntp (network Time protocol) 时间同步服务
    ntp简介,使用timedatectl可以查看时间同步状态,默认我这里时ntp synchronized: yes已经开启的
  1. 配置安装munge

    munge是为了授权才安装的,确保所有节点上的munge.key是相同的,并且在启动slurm之前要确保守护进程munged处于运行状态

    1
    sudo apt-get install munge

    这里直接用apt安装,默认就配置好了munge的owner以及grouper,如果要手动配置的话要注意, munge daemon process的启用者要与munge’ owner一致。
    安装完毕后将host节点中/etc/munge/munge.txt拷贝到其他节点的/etc/munge里面去(首先都安装上ssh)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # host machine
    scp /etc/munge/munge.key slave1@192.168.1.105:/tmp # 将host machine节点上的munge.key复制到ip为192.168.1.105的slave1节点的tmp目录(这个目录有权限)
    # 然后在slave节点上移动munge.txt到/etc/munge目录下,注意更改复制过来后key文件的owner与grouper为munge
    sudo chown munge:munge munge.key

    # Start the daemon automatically at boot:
    sudo systemctl enable munge #(开机自启)
    # Start the daemon now:
    sudo systemctl start munge
    # Stop the daemon:
    sudo systemctl stop munge

    ps -aux | grep munge查看

    * 注意:一定要在slurm daemon开启之前start munge daemon

  2. 下载配置 slurm

    4.1 ubuntu,现在下载页面下载slurm源码,编译后根据这篇博客配置slurm.conf文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 安装依赖
    apt-get install hwloc libhwloc-dev libmunge-dev libmunge2 munge mariadb-server libmysqlclient-dev(slave节点不需要最后两个sql)
    # 解压,在目录进行编译
    ./configure
    sudo make
    sudo make install
    # 编译完成后进入 slurm-xxxx/etc
    cp slurm.conf.example slurm.conf, 然后根据上述博客进行配置,配置完成后将slurm.conf拷贝到集群所有节点上面
    scp slurm.conf slave1@192.168.1.105:/tmp
    # 在slave1节点将slurm.conf文件拷贝进入安装目录
    cp /tmp/slurm.conf /home/slave1/slurmxxxx/etc

    4.2 此处根据zxh配置Maria DB以及配置slurm

    1
    2
    3
    4
    5
    6
    sudo apt-get install mariadb-servert
    # 注意,在ubuntu下安装mariadb,但是操作的时候是操作的mysql
    sudo systemctl start mysql
    systemctl enable mysql
    mysql_secure_installation
    # 将配置好的slurm.conf copy至/usr/local/etc/中去

4.3
主节点运行:

1
2
3
slurmctld -c
slurmd -c
注意:-c时后台运行,在第一次运行时可以使用-D参数,显式运行以观察运行情况

slave节点运行:
1
slurmd -c

False Log

  • 我在master运行sudo slurmctld -c启动时报错找不到/usr/local/etc/slurm.conf文件

    将编译目录下/etc/slurm.conf复制进去即可

  • 使用sinfo时报错:slurm_load_partitions: unable to contact slurm controller (connect failure)

    这个就是slurmctld没有正常启动…

  • “slurmd: fatal: mkdir(/var/spool/slurm/d): No such file or directory”

    创建slurm中部分配置的目录,/var/spool/slurm/ctld 和 /var/spool/slurm/d

    1
    2
    3
    # 注意更改spool以及其子目录文件的所有者及权限(如果需要的话)
    mkdir -p /var/spool/slurm/ctld
    mkdir -p /var/spool/slurm/d
  • master成功启动slurmctld 与 slurmd,但是从节点启动slurmd启动时报错:invalid user for slurmUser xxx, ignored(此时master与slave的slurm.conf完全一样)

    更改salve节点/etc/slurm-llnl/slurm.conf文件的slurmUser的值为slave的用户即可

  • slave节点:slurmd:error:couldn’t find the specified plugin name for select/cons_tres lokking at all files

    这个我也找不到问题所在了,定位在 slave节点上的/usr/local/lib下面居然没有找到与slurm相关的文件!,奇了怪了,算了,现在已经凌晨了,其他centos配个环境怎么这么简单,一路都没有错误,ubuntu错误为什么这么多呢,这个问题也是连日志都没有,我把master上面的相关文件copy至slave节点还是没有,那我直接把slave节点删除了!就用一个master同时充当controller与computer算了。就这样,
    第二天早上我tm发现,在salve节点上居然没有make install… 所以在/usr/local/lib中找不到相关文件…

安装经验总结

  • git上文件的状态

    这很重要,要求git使用者必须知道你local repository中文件的状态,可以通过git status命令查看。其中,可以从两方面来看到文件状态

    1. 从git的角度来考虑

    从git角度考量文件,只有两种状态:untracked与tracked,untracked可以理解为git没有存放该文件的信息,一般是新建文件后文件的状态。tracked是git已经知道了文件的信息了。

    2. 从文件本身角度来考虑

    从文件本身来说其有unmodified、modified、staged三种状态,意思顾名思义即可,知道了文件当前的状态,使用git命令对其进行状态进行修改,从而达到操控local repository的目的。

    3. 问题探讨(将文件从staging area中移除,但是仍让其保存在working tree中)

    应用场景:这通常是在项目开发中。随项目产生的那些.o文件等等不需要存在repositiry中,但是要在本地端存在

    1
    $ git rm --cached README

    解决办法即添加参数 —cached

    4. 镜像问题探讨(如何让文件只在于repository中而不存在于本地local working tree中,以免浪费本地资源)

    应用场景:相当于作为图片服务器
    解决办法:目前好没有看到,之后再看吧。

Lei的第一篇博客

  • 自我介绍

    我,秃头披风侠,计算机,UCAS,参上。
    7.10日导师发邮件给我让我暑期开始钻研linear algebra的基础知识还有相关研究论文,that may be hard, but that’s useful!, 之前对于学习我都没有记录的好习惯,直接就在书上做笔记了,最近看到很多大牛都有自己的博客,
    而且在研读新书时碰到的问题也要自己汇总,于是昨日我开始有针对性的去了解博客的相关知识。

  • 博客搭建过程

    首先我了解了git的相关内容,这一部分主要是阅读git官网那本书progit
    这本书很详细地介绍了git地发展与使用,看到第二章就足够应付日常git使用了:不包括branch等等,仅包括简单的本地仓库管理与远端提交等等。
    关于github博客的搭建以及hexo的配置(就3个命令其实:hexo new; hexo g; hexo d)我是参照了这篇知乎文章
    在此表示感谢,当然还需要搭配的是markdown的相关语法,以及丰富完善git知识,hexo知识。注意以上只是工具,切不可忘记真正目的:parallel Computing!
    此上,以及不定期分析研读书籍时碰到的问题。