发散阅读、拓宽思路:PageRank+Tf-Idf+协同过滤+分布式训练+StyleTransfer+Node2vec

刚工作一年,做的内容算是比较单一,基本是NLP相关,当然主流的算法、模型还是基本都了解,偶尔发散的看一些东西,算是留个印象,日积月累,可能以后会用到或者有所启发。

这种情况下,一般看的就没那么细节,留下个大致感觉,后续需要用时深究。

1. PageRank

1.1 PageRank的两个假设

假设1,将各个网页做成一个图模型中(每个网页是其中的一个节点),如果一个页面节点收到到的入链数量越多,这个页面越重要;

假设2,指向某节点A的入链质量(分数)不同,质量(分数)高的页面节点,会传递给A更多的分数。

1.2 重点
1.PageRank计算出的每个网页/节点的分数和用户输入的query没有关系;
2.假设某搜索引擎完全采用PageRank的网页得分来进行排序,那搜索引擎表现如何?对于任意query,返回的结果都相同,返回PageRank得分最高的页面。
3.这种可以通俗理解为与query无关的先验概率结果,而在此基础上考虑query相关的为条件概率结果?

1.3 核心公式

P r ( A ) = ( P r ( B ) L ( B ) + P r ( C ) L ( C ) + P r ( C ) L ( C ) . . . ) ∗ q + 1 − q Pr(A)=(\frac{Pr(B)}{L(B)}+\frac{Pr(C)}{L(C)}+\frac{Pr(C)}{L(C)}...)*q+1-q Pr(A)=(L(B)Pr(B)+L(C)Pr(C)+L(C)Pr(C)...)q+1q
(1)其中 P r ( B ) Pr(B) Pr(B)表示页面B的得分,比如0.7,
(2) L ( B ) L(B) L(B)表示节点的出度(指向外的边的个数),比如节点 B B B指向节点 D D D E E E,那么 L ( B ) L(B) L(B)为2,
(3) q q q叫阻尼系数,主要是为了让某些孤立网页(没有入度的网页)有 1 − q 1-q 1q这样一个基础的分数,你可以理解为 1 − q 1-q 1q为所有网页节点的“底薪”,公式的前一部分是“绩效”,整体为页面A的“工资”。(较为官方的解释为,在任意时刻,用户到达某页面后并继续向后浏览的概率)

对于上述的核心公式还有另外一个版本(至于为啥我还没时间去细致研究,回头有空了看下为啥这么设计,查了些资料, 1 − q 1-q 1q表示到新页面的概率,除以 N N N表示访问具体单个页面的概率?深层次的影响待查,我有空搞了update)
P r ( A ) = ( P r ( B ) L ( B ) + P r ( C L ( C ) + P r ( C ) L ( C ) . . . ) ∗ q + ( 1 − q ) / N Pr(A)=(\frac{Pr(B)}{L(B)}+\frac{Pr(C}{L(C)}+\frac{Pr(C)}{L(C)}...)*q+(1-q)/N Pr(A)=(L(B)Pr(B)+L(C)Pr(C+L(C)Pr(C)...)q+(1q)/N

1.4 如何计算
1.4.1 方式1
将所有网页的 P r Pr Pr值初始化,利用公式不断迭代,最终稳定下来(嘿嘿,收敛性是否一定成立呢,如何证明呢,有空了研究update)
1.4.2 方式2

上述公式矩阵化,利用线性代数方法求解,设
P r = [ P r ( 1 ) P r ( 2 ) P r ( 3 ) . . . P r ( n ) ] \bm{Pr}=\begin{bmatrix}Pr(1) \\Pr(2) \\Pr(3)\\...\\Pr(n)\end{bmatrix} Pr=Pr(1)Pr(2)Pr(3)...Pr(n)
(1)那么公式转化为:
P r = [ 1 − q / N 1 − q / N 1 − q / N . . . 1 − q / N ] + q ∗ [ l ( p 1 , p 1 ) l ( p 1 , p 2 ) l ( p 1 , p 3 ) . . . l ( p 1 , p n ) l ( p 2 , p 1 ) l ( p 2 , p 2 ) l ( p 2 , p 3 ) . . . l ( p 2 , p n ) l ( p 3 , p 1 ) l ( p 3 , p 2 ) l ( p 3 , p 3 ) . . . l ( p 3 , p n ) . . . l ( p n , p 1 ) l ( p n , p 2 ) l ( p n , p 3 ) . . . l ( p n , p n ) ] ∗ P r \bm{Pr}=\begin{bmatrix}1-q/N \\1-q/N \\1-q/N\\...\\1-q/N\end{bmatrix}+q*\begin{bmatrix}l(p_1,p_1)&l(p_1,p_2)&l(p_1,p_3)&...&l(p_1,p_n) \\l(p_2,p_1)&l(p_2,p_2)&l(p_2,p_3)&...&l(p_2,p_n) \\l(p_3,p_1)&l(p_3,p_2)&l(p_3,p_3)&...&l(p_3,p_n) \\...\\l(p_n,p_1)&l(p_n,p_2)&l(p_n,p_3)&...&l(p_n,p_n) \end{bmatrix}*\bm{Pr} Pr=1q/N1q/N1q/N...1q/N+ql(p1,p1)l(p2,p1)l(p3,p1)...l(pn,p1)l(p1,p2)l(p2,p2)l(p3,p2)l(pn,p2)l(p1,p3)l(p2,p3)l(p3,p3)l(pn,p3)............l(p1,pn)l(p2,pn)l(p3,pn)l(pn,pn)Pr
至于那个 l ( p i , p j ) l(p_i,p_j) l(pi,pj)就是上文中的 L ( B ) 、 L ( C ) L(B)、L(C) L(B)L(C)之类的,简单想想画一画就理解了。
(2)然后就是解方程
线性代数幂法求解,emmm,有点忘了,想细看的去搜一下就可以得到答案,不纠结这个了。

整体上还有更细节解读方式,资料见https://www.changhai.org/articles/technology/misc/google_math.php。

总而言之:这种方式得到的各个页面的分数与用户的搜索无关,就是一个【静态】分数,衡量的是这个页面的火热度,而衡量搜索词与页面关系的原始方式用的是Tf-idf(BM25是改进版)。

2. TF-idf

细节就不重复了,要学会借鉴别人的成果https://my.oschina.net/stanleysun/blog/1617727

TF-idf简单来说,举个例子:
搜索query中的词,如果在某个页面出现的很多,那么这query和此页面就很可能相关,此为TF
但是有一些不重要的词,比如“的”,“哪”这种,在每个页面都出现了,那么意味着这种词对于各个页面来说没有区分度,根据这些词计算的TF值即使很高,也没有啥意义。那么怎么判定一个词的区分度呢,如果某个词/元素只集中在某些页面,而且越集中,说明区分度越高,此为IDF

延伸:可以利用TF-idf的思想做特征选择,比如某个分类任务,有几百万、千万的特征,你可以统计特征在所有样本的频次取top级别(比如50w)作为你选用的特征,但是这里很可能就会有垃圾特征,与上述的“的”,“哪”这种类似;怎么办呢,可以利用idf的思想,如果某个特征在每个类别样本都出现,那么这个特征可能就是没啥区分度的,如果集中在某几个类别,说明区分度好…

TF-idf原本是用来衡量搜索词与页面的相关性的,但是思想可以用的场景不止于此,所以还是我在bert那一博客提到的,注意这些前人成果的剑意精髓,具体的招式反而次要。

3. 协同过滤

套路有很多,本质上核心的就是矩阵分解,举个例子, m m m个用户,对 n n n个商品的评分,形成了一个大矩阵 R m ∗ n R_{m*n} Rmn,一般是一个稀疏矩阵,将矩阵分解为
R m ∗ n ≈ U m ∗ k ∗ R k ∗ k ∗ I k ∗ n R_{m*n} \approx U_{m*k}*R_{k*k}*I_{k*n} RmnUmkRkkIkn或者 R m ∗ n ≈ U m ∗ k ∗ I k ∗ n R_{m*n} \approx U_{m*k}*I_{k*n} RmnUmkIkn,那么 U m ∗ k U_{m*k} Umk可以看做是每个用户的向量描述, I k ∗ n I_{k*n} Ikn可以看做是每个商品的向量描述。至于怎么分解,大致两种方式,一种是数学角度比如SVD改进之类,一种是初始化后梯度下降这种。

有了向量描述,计算用户或者商品的相似度、聚类、推荐什么的都可以操作了。

不管怎么说,本质上是对矩阵 R m ∗ n R_{m*n} Rmn的处理,信息量是有限的,可以认为这些向量描述是购买行为/评分行为graph的一种embedding。

实际中应该会引入更多的信息,上述得到的向量描述只能算是用户/商品在这一种行为角度下的特征vector,信息单一。

4. 模型的分布式训练

https://www.zhihu.com/question/53851014这个文章说的很清楚,不赘述。
简单理解:

  • 数据并行,可以理解为用 n n n个worker并行跑 n n n个batch;
    同步更新:n个节点从parameter server取到参数矩阵 w w w,输入一个batch训练数据计算梯度以后回传到parameter server,对多个节点回传的梯度进行平均(也是额外计算开销),然后更新参数矩阵 w w w,然后各个节点从这里获取新的参数 w 1 w_1 w1,如此循环;如果需要等待所有节点回传,某个worker计算很慢,会出现等待的情况(当然可以设置一个阈值,太久了就不等了),这就是简单的同步更新例子,实际肯定不是我说的那么简单。
    异步更新:每个节点从parameter server取到参数矩阵 w w w,输入一个batch训练数据计算梯度以后回传到parameter server,不等待其他节点数据,parameter server更新参数矩阵 w w w,计算完成的worker向parameter server取得最新的参数,这种方式存在梯度/参数过时的情况。
  • 模型并行,矩阵计算分块处理。

实际情况肯定有各种优化,比如模型并行和数据并行一起用、同步和异步的处理。

5. 图像风格迁移三部曲

https://zhuanlan.zhihu.com/p/40322927 具体看这位同学的。我主要说点背后的思想和自己的感悟。

5.1 固定风格固定内容的普通风格迁移

A Neural Algorithm of Artistic Style
最早的风格迁移,最慢的,最经典的。

首先,图片本质上是一个矩阵,比如维度为 256 ∗ 256 ∗ 3 256*256*3 2562563 256 ∗ 256 256*256 256256表示图片的大小、像素点个数,3表示3通道RGB。

给定风格图片 s 1 s_1 s1,给定内容图片 c 1 c_1 c1,随机初始化结果图片 r 1 r_1 r1,计算 s 1 s_1 s1 r 1 r_1 r1的风格损失函数 l o s s s loss_s losss,计算 c 1 c_1 c1 r 1 r_1 r1的内容损失函数 l o s s c loss_c lossc,然后加权相加,loss最小化,优化图片 r 1 r_1 r1的参数,就ok了。

问题核心就在构建风格损失函数 l o s s s loss_s losss和内容损失函数 l o s s c loss_c lossc
拿一个预训练好的特征提取网络比如vgg16,分别把 c 1 c_1 c1 r 1 r_1 r1输入,得到中间层特征feature map,利用中间的feature map加工得到两种loss。

举个例子

步骤1:当我们输入 c 1 c_1 c1 进入vgg16,取中间某4层的输出,假设 c 1 c_1 c1 的尺寸是 [1, 3, 512, 512](四个维度分别代表 batch, channels, height, width),那么它返回的四个中间层的尺寸就是这样的,
c 1 v g g f 1 c_{1}^{vgg_{f1}} c1vggf1: [1, 64, 512, 512]
c 1 v g g f 2 c_{1}^{vgg_{f2}} c1vggf2: [1, 128, 256, 256]
c 1 v g g f 3 c_{1}^{vgg_{f3}} c1vggf3: [1, 256, 128, 128]
c 1 v g g f 4 c_{1}^{vgg_{f4}} c1vggf4: [1, 512, 64, 64]

步骤2:输入 r 1 r_1 r1 进入vgg16得到
r 1 v g g f 1 r_{1}^{vgg_{f1}} r1vggf1: [1, 64, 512, 512]
r 1 v g g f 2 r_{1}^{vgg_{f2}} r1vggf2: [1, 128, 256, 256]
r 1 v g g f 3 r_{1}^{vgg_{f3}} r1vggf3: [1, 256, 128, 128]
r 1 v g g f 4 r_{1}^{vgg_{f4}} r1vggf4: [1, 512, 64, 64]

步骤3:将 c 1 v g g f i c_{1}^{vgg_{fi}} c1vggfi r 1 v g g f i r_{1}^{vgg_{fi}} r1vggfi i = 1 、 2 、 3 、 4 i=1、2、3、4 i=1234)矩阵对应取均方误差MSE,得到内容损失函数 l o s s c loss_c lossc,这个好理解,说白了,特征矩阵feature map越相近,内容上越接近

步骤4:输入 s 1 s_1 s1 进入vgg16得到
s 1 v g g f 1 s_{1}^{vgg_{f1}} s1vggf1: [1, 64, 512, 512]
s 1 v g g f 2 s_{1}^{vgg_{f2}} s1vggf2: [1, 128, 256, 256]
s 1 v g g f 3 s_{1}^{vgg_{f3}} s1vggf3: [1, 256, 128, 128]
s 1 v g g f 4 s_{1}^{vgg_{f4}} s1vggf4: [1, 512, 64, 64]

步骤5:对 r 1 v g g f i r_{1}^{vgg_{fi}} r1vggfi i = 1 、 2 、 3 、 4 i=1、2、3、4 i=1234)计算gram矩阵
r 1 v g g f 1 r_{1}^{vgg_{f1}} r1vggf1: [1, 64, 512, 512] -> r 1 g r a m f 1 r_{1}^{gram_{f1}} r1gramf1: [1, 64, 64]
r 1 v g g f 2 r_{1}^{vgg_{f2}} r1vggf2: [1, 128, 256, 256] -> r 1 g r a m f 2 r_{1}^{gram_{f2}} r1gramf2: [1, 128, 128]
r 1 v g g f 3 r_{1}^{vgg_{f3}} r1vggf3: [1, 256, 128, 128] -> r 1 g r a m f 3 r_{1}^{gram_{f3}} r1gramf3: [1, 256, 256]
r 1 v g g f 4 r_{1}^{vgg_{f4}} r1vggf4: [1, 512, 64, 64] -> r 1 g r a m f 3 r_{1}^{gram_{f3}} r1gramf3: [1, 512, 512]
怎么计算的呢,比如对 r 1 v g g f 1 r_{1}^{vgg_{f1}} r1vggf1,有64个feature map,大小都为[512, 512],两两做矩阵"点乘"(类似向量的点乘)得到一个数值,整体就得到一个[64, 64]大小的矩阵(当然每个元素除以512*512归一化?)。

步骤6:同理可以得到 s 1 v g g f i s_{1}^{vgg_{fi}} s1vggfi i = 1 、 2 、 3 、 4 i=1、2、3、4 i=1234)的gram矩阵,对 r 1 r_{1} r1 s 1 s_{1} s1的gram矩阵做MSE,得到风格损失函数 l o s s s loss_s losss,也就是说,gram矩阵越相近,风格上越接近。这个怎么理解,我也不很确定,Gram计算的实际上是两两特征之间的相关性,哪两个特征是同时出现的,哪两个是此消彼长的等等。

5.2 固定风格任意内容的快速风格迁移
Perceptual Losses for Real-Time Style Transfer and Super-Resolution

思路:假设存在这么一个模型 m o d e l 1 model_1 model1对应风格图片 s 1 s_1 s1,可以输入内容图片 c 1 c_1 c1 c 2 c_2 c2、…,得到结果图片 r 1 r_1 r1 r 2 r_2 r2、…;初始化 m o d e l 1 model_1 model1的参数,然后依据结果图片 r i ( i = 1 , 2 , . . . ) r_i(i=1,2,...) ri(i=1,2,...)计算两种损失函数来优化 m o d e l 1 model_1 model1的参数。

模型网络结构:三层卷积层(降维) -> 5个 ResidualBlock 堆叠 -> 三层卷积层(转置卷积,升维)

论文中提到了一个 TV Loss,为了平滑图像:将图像水平和垂直平移一个像素,与原图相减,然后计算绝对值的和。优化模型时用的是上述两种loss加上TV Loss。

整体来说:就是一个模型对应一种风格,模型接受内容图片,输出风格迁移的图片。

5.3 任意风格任意内容的极速风格迁移

Meta Networks for Neural Style Transfer

基于上述5.2一个模型对应一种风格,而模型本身就是一堆参数,那么能不能建立一种网络,每次输入一个风格图像,输出一组参数(风格模型),说白了,建立风格图像与风格迁移模型的映射关系呢。

细节就不说了,比较多,比如均值、标准差代替gram矩阵,比如分组全连接代替全连接…上面的链接有细节。

核心思想:每次输入一个风格图片 s 1 s_1 s1,进入 M e t a N MetaN MetaN网络得到一组参数,把这个参数填入风格转换网络 N 1 N_1 N1,得到的 N 1 N_1 N1就是拥有风格 s 1 s_1 s1的转化模型,在 N 1 N_1 N1中输入任意的内容图片,都可以得到 s 1 s_1 s1风格下的新图片。

5.4 个人感受

图片的风格迁移其实借鉴了图片领域的一些经典结构,比如vgg提取feature map、利用卷积-ResidualBlock-转置卷积转化图像,那么语言上的风格迁移有没有好办法呢…

有人说,图像处理的好处是连续性,那些像素值,随便加减以后无非是颜色变化,而对于自然语言来说,某个字embedding以后的向量你加减一些数,可能完全没法字典里的一个字对应,连续 vs 离散?

这方面没怎么尝试过,希望大佬们搞点东西让我等渣渣学习下。

6. Word2vec -> Node2vec

这个具体细节没啥可说的,贴一个我之前看的知乎https://zhuanlan.zhihu.com/p/58281139。

Node2vec不过是在图里面游走生成节点序列,然后按照Word2vec的形式对Node进行了embedding,这不新鲜。

重要的是对事物的编码提供了另外一种角度

举个例子,拿用户搜索qq音乐里的歌为例,我可以对每一个歌本身的歌词、简介做一下语义、情感、主题上的embedding,这是基于自然语言语义的;还可以根据不同用户先后搜索行为,将不同的歌生成一个“歌”网络,利用上述Node2vec得到每首歌在用户行为逻辑下的embedding。

7. 最后

差点没坚持下去半途而废了,总归还是写完了。

最近老是想着成为暴发户哈哈,这,心态不好。

饭要一口口吃,技术要一点点长进,经验是慢慢积累,钱是会逐渐挣得多。

量变引起质变,积累与坚持,这是规律,是天道。

所以,坚持学习和努力,注重生活品质、身心健康。

说出来你可能不信,我要报钢琴课去学习了,ByeBye,下次见!

你可能感兴趣的:(机器学习)