刚工作一年,做的内容算是比较单一,基本是NLP相关,当然主流的算法、模型还是基本都了解,偶尔发散的看一些东西,算是留个印象,日积月累,可能以后会用到或者有所启发。
这种情况下,一般看的就没那么细节,留下个大致感觉,后续需要用时深究。
1. PageRank
1.1 PageRank的两个假设
假设1,将各个网页做成一个图模型中(每个网页是其中的一个节点),如果一个页面节点收到到的入链数量越多,这个页面越重要;
假设2,指向某节点A的入链质量(分数)不同,质量(分数)高的页面节点,会传递给A更多的分数。
1.2 重点:
1.PageRank计算出的每个网页/节点的分数和用户输入的query没有关系;
2.假设某搜索引擎完全采用PageRank的网页得分来进行排序,那搜索引擎表现如何?对于任意query,返回的结果都相同,返回PageRank得分最高的页面。
3.这种可以通俗理解为与query无关的先验概率结果,而在此基础上考虑query相关的为条件概率结果?
1.3 核心公式:
Pr(A)=(Pr(B)L(B)+Pr(C)L(C)+Pr(C)L(C)...)∗q+1−qPr(A)=(\frac{Pr(B)}{L(B)}+\frac{Pr(C)}{L(C)}+\frac{Pr(C)}{L(C)}...)*q+1-qPr(A)=(L(B)Pr(B)+L(C)Pr(C)+L(C)Pr(C)...)∗q+1−q
(1)其中Pr(B)Pr(B)Pr(B)表示页面B的得分,比如0.7,
(2)L(B)L(B)L(B)表示节点的出度(指向外的边的个数),比如节点BBB指向节点DDD和EEE,那么L(B)L(B)L(B)为2,
(3)qqq叫阻尼系数,主要是为了让某些孤立网页(没有入度的网页)有1−q1-q1−q这样一个基础的分数,你可以理解为1−q1-q1−q为所有网页节点的“底薪”,公式的前一部分是“绩效”,整体为页面A的“工资”。(较为官方的解释为,在任意时刻,用户到达某页面后并继续向后浏览的概率)
对于上述的核心公式还有另外一个版本(至于为啥我还没时间去细致研究,回头有空了看下为啥这么设计,查了些资料,1−q1-q1−q表示到新页面的概率,除以NNN表示访问具体单个页面的概率?深层次的影响待查,我有空搞了update)
Pr(A)=(Pr(B)L(B)+Pr(CL(C)+Pr(C)L(C)...)∗q+(1−q)/NPr(A)=(\frac{Pr(B)}{L(B)}+\frac{Pr(C}{L(C)}+\frac{Pr(C)}{L(C)}...)*q+(1-q)/NPr(A)=(L(B)Pr(B)+L(C)Pr(C+L(C)Pr(C)...)∗q+(1−q)/N
1.4 如何计算:
1.4.1 方式1
将所有网页的PrPrPr值初始化,利用公式不断迭代,最终稳定下来(嘿嘿,收敛性是否一定成立呢,如何证明呢,有空了研究update)
1.4.2 方式2
上述公式矩阵化,利用线性代数方法求解,设
Pr=[Pr(1)Pr(2)Pr(3)...Pr(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)那么公式转化为:
Pr=[1−q/N1−q/N1−q/N...1−q/N]+q∗[l(p1,p1)l(p1,p2)l(p1,p3)...l(p1,pn)l(p2,p1)l(p2,p2)l(p2,p3)...l(p2,pn)l(p3,p1)l(p3,p2)l(p3,p3)...l(p3,pn)...l(pn,p1)l(pn,p2)l(pn,p3)...l(pn,pn)]∗Pr\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=⎣⎢⎢⎢⎢⎡1−q/N1−q/N1−q/N...1−q/N⎦⎥⎥⎥⎥⎤+q∗⎣⎢⎢⎢⎢⎡l(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(pi,pj)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. 协同过滤
套路有很多,本质上核心的就是矩阵分解,举个例子,mmm个用户,对nnn个商品的评分,形成了一个大矩阵Rm∗nR_{m*n}Rm∗n,一般是一个稀疏矩阵,将矩阵分解为
Rm∗n≈Um∗k∗Rk∗k∗Ik∗nR_{m*n} \approx U_{m*k}*R_{k*k}*I_{k*n}Rm∗n≈Um∗k∗Rk∗k∗Ik∗n或者Rm∗n≈Um∗k∗Ik∗nR_{m*n} \approx U_{m*k}*I_{k*n}Rm∗n≈Um∗k∗Ik∗n,那么Um∗kU_{m*k}Um∗k可以看做是每个用户的向量描述,Ik∗nI_{k*n}Ik∗n可以看做是每个商品的向量描述。至于怎么分解,大致两种方式,一种是数学角度比如SVD改进之类,一种是初始化后梯度下降这种。
有了向量描述,计算用户或者商品的相似度、聚类、推荐什么的都可以操作了。
不管怎么说,本质上是对矩阵Rm∗nR_{m*n}Rm∗n的处理,信息量是有限的,可以认为这些向量描述是购买行为/评分行为graph的一种embedding。
实际中应该会引入更多的信息,上述得到的向量描述只能算是用户/商品在这一种行为角度下的特征vector,信息单一。
4. 模型的分布式训练
https://www.zhihu.com/question/53851014这个文章说的很清楚,不赘述。
简单理解:
- 数据并行,可以理解为用nnn个worker并行跑nnn个batch;
同步更新:n个节点从parameter server取到参数矩阵www,输入一个batch训练数据计算梯度以后回传到parameter server,对多个节点回传的梯度进行平均(也是额外计算开销),然后更新参数矩阵www,然后各个节点从这里获取新的参数w1w_1w1,如此循环;如果需要等待所有节点回传,某个worker计算很慢,会出现等待的情况(当然可以设置一个阈值,太久了就不等了),这就是简单的同步更新例子,实际肯定不是我说的那么简单。
异步更新:每个节点从parameter server取到参数矩阵www,输入一个batch训练数据计算梯度以后回传到parameter server,不等待其他节点数据,parameter server更新参数矩阵www,计算完成的worker向parameter server取得最新的参数,这种方式存在梯度/参数过时的情况。 - 模型并行,矩阵计算分块处理。
实际情况肯定有各种优化,比如模型并行和数据并行一起用、同步和异步的处理。
5. 图像风格迁移三部曲
https://zhuanlan.zhihu.com/p/40322927 具体看这位同学的。我主要说点背后的思想和自己的感悟。
5.1 固定风格固定内容的普通风格迁移
A Neural Algorithm of Artistic Style
最早的风格迁移,最慢的,最经典的。
首先,图片本质上是一个矩阵,比如维度为256∗256∗3256*256*3256∗256∗3,256∗256256*256256∗256表示图片的大小、像素点个数,3表示3通道RGB。
给定风格图片s1s_1s1,给定内容图片c1c_1c1,随机初始化结果图片r1r_1r1,计算s1s_1s1与r1r_1r1的风格损失函数losssloss_slosss,计算c1c_1c1与r1r_1r1的内容损失函数losscloss_clossc,然后加权相加,loss最小化,优化图片r1r_1r1的参数,就ok了。
问题核心就在构建风格损失函数losssloss_slosss和内容损失函数losscloss_clossc:
拿一个预训练好的特征提取网络比如vgg16,分别把c1c_1c1与r1r_1r1输入,得到中间层特征feature map,利用中间的feature map加工得到两种loss。
举个例子
步骤1:当我们输入c1c_1c1 进入vgg16,取中间某4层的输出,假设 c1c_1c1 的尺寸是 [1, 3, 512, 512](四个维度分别代表 batch, channels, height, width),那么它返回的四个中间层的尺寸就是这样的,
c1vggf1c_{1}^{vgg_{f1}}c1vggf1: [1, 64, 512, 512]
c1vggf2c_{1}^{vgg_{f2}}c1vggf2: [1, 128, 256, 256]
c1vggf3c_{1}^{vgg_{f3}}c1vggf3: [1, 256, 128, 128]
c1vggf4c_{1}^{vgg_{f4}}c1vggf4: [1, 512, 64, 64]
步骤2:输入r1r_1r1 进入vgg16得到
r1vggf1r_{1}^{vgg_{f1}}r1vggf1: [1, 64, 512, 512]
r1vggf2r_{1}^{vgg_{f2}}r1vggf2: [1, 128, 256, 256]
r1vggf3r_{1}^{vgg_{f3}}r1vggf3: [1, 256, 128, 128]
r1vggf4r_{1}^{vgg_{f4}}r1vggf4: [1, 512, 64, 64]
步骤3:将c1vggfic_{1}^{vgg_{fi}}c1vggfi与r1vggfir_{1}^{vgg_{fi}}r1vggfi(i=1、2、3、4i=1、2、3、4i=1、2、3、4)矩阵对应取均方误差MSE,得到内容损失函数losscloss_clossc,这个好理解,说白了,特征矩阵feature map越相近,内容上越接近。
步骤4:输入s1s_1s1 进入vgg16得到
s1vggf1s_{1}^{vgg_{f1}}s1vggf1: [1, 64, 512, 512]
s1vggf2s_{1}^{vgg_{f2}}s1vggf2: [1, 128, 256, 256]
s1vggf3s_{1}^{vgg_{f3}}s1vggf3: [1, 256, 128, 128]
s1vggf4s_{1}^{vgg_{f4}}s1vggf4: [1, 512, 64, 64]
步骤5:对r1vggfir_{1}^{vgg_{fi}}r1vggfi(i=1、2、3、4i=1、2、3、4i=1、2、3、4)计算gram矩阵
r1vggf1r_{1}^{vgg_{f1}}r1vggf1: [1, 64, 512, 512] -> r1gramf1r_{1}^{gram_{f1}}r1gramf1: [1, 64, 64]
r1vggf2r_{1}^{vgg_{f2}}r1vggf2: [1, 128, 256, 256] -> r1gramf2r_{1}^{gram_{f2}}r1gramf2: [1, 128, 128]
r1vggf3r_{1}^{vgg_{f3}}r1vggf3: [1, 256, 128, 128] -> r1gramf3r_{1}^{gram_{f3}}r1gramf3: [1, 256, 256]
r1vggf4r_{1}^{vgg_{f4}}r1vggf4: [1, 512, 64, 64] -> r1gramf3r_{1}^{gram_{f3}}r1gramf3: [1, 512, 512]
怎么计算的呢,比如对r1vggf1r_{1}^{vgg_{f1}}r1vggf1,有64个feature map,大小都为[512, 512],两两做矩阵"点乘"(类似向量的点乘)得到一个数值,整体就得到一个[64, 64]大小的矩阵(当然每个元素除以512*512归一化?)。
步骤6:同理可以得到s1vggfis_{1}^{vgg_{fi}}s1vggfi(i=1、2、3、4i=1、2、3、4i=1、2、3、4)的gram矩阵,对r1r_{1}r1和s1s_{1}s1的gram矩阵做MSE,得到风格损失函数losssloss_slosss,也就是说,gram矩阵越相近,风格上越接近。这个怎么理解,我也不很确定,Gram计算的实际上是两两特征之间的相关性,哪两个特征是同时出现的,哪两个是此消彼长的等等。
5.2 固定风格任意内容的快速风格迁移
Perceptual Losses for Real-Time Style Transfer and Super-Resolution
思路:假设存在这么一个模型model1model_1model1对应风格图片s1s_1s1,可以输入内容图片c1c_1c1、c2c_2c2、…,得到结果图片r1r_1r1、r2r_2r2、…;初始化model1model_1model1的参数,然后依据结果图片ri(i=1,2,...)r_i(i=1,2,...)ri(i=1,2,...)计算两种损失函数来优化model1model_1model1的参数。
模型网络结构:三层卷积层(降维) -> 5个 ResidualBlock 堆叠 -> 三层卷积层(转置卷积,升维)
论文中提到了一个 TV Loss,为了平滑图像:将图像水平和垂直平移一个像素,与原图相减,然后计算绝对值的和。优化模型时用的是上述两种loss加上TV Loss。
整体来说:就是一个模型对应一种风格,模型接受内容图片,输出风格迁移的图片。
5.3 任意风格任意内容的极速风格迁移
Meta Networks for Neural Style Transfer
基于上述5.2一个模型对应一种风格,而模型本身就是一堆参数,那么能不能建立一种网络,每次输入一个风格图像,输出一组参数(风格模型),说白了,建立风格图像与风格迁移模型的映射关系呢。
细节就不说了,比较多,比如均值、标准差代替gram矩阵,比如分组全连接代替全连接…上面的链接有细节。
核心思想:每次输入一个风格图片s1s_1s1,进入MetaNMetaNMetaN网络得到一组参数,把这个参数填入风格转换网络N1N_1N1,得到的N1N_1N1就是拥有风格s1s_1s1的转化模型,在N1N_1N1中输入任意的内容图片,都可以得到s1s_1s1风格下的新图片。
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,下次见!