计算机图形学:变换矩阵

最近在研究3D建模和新视点合成,在渲染过程中需要选取新视点去合成新图。一般在接口处需要传递一个变换矩阵,用于控制视点的变化。

成像的过程实质上是几个坐标系的转换。首先空间中的一点由世界坐标系转换到 摄像机坐标系 ,然后再将其投影到成像平面 ( 图像物理坐标系 ) ,最后再将成像平面上的数据转换到图像平面 (图像像素坐标系 ) 。

以AdaMPI的代码为例:

# 定义新视角的角度和渲染的帧数
def gen_swing_path(num_frames=90, r_x=0.14, r_y=0., r_z=0.10):
    "Return a list of matrix [4, 4]"
    t = torch.arange(num_frames) / (num_frames - 1)
    poses = torch.eye(4).repeat(num_frames, 1, 1)
    poses[:, 0, 3] = r_x * torch.sin(2. * math.pi * t)
    poses[:, 1, 3] = r_y * torch.cos(2. * math.pi * t)
    poses[:, 2, 3] = r_z * (torch.cos(2. * math.pi * t) - 1.)
    return poses.unbind()

以Synsin代码为例:

# Parameters for the transformation
theta = -0.15
phi = -0.1
tx = 0
ty = 0
tz = 0.1

RT = torch.eye(4).unsqueeze(0)
# Set up rotation(旋转参数)
RT[0,0:3,0:3] = torch.Tensor(quaternion.as_rotation_matrix(quaternion.from_rotation_vector([phi, theta, 0])))
# Set up translation(平移参数)
RT[0,0:3,3] = torch.Tensor([tx, ty, tz])

一开始其实没有明白为什么需要对 r_x=0.14, r_y=0., r_z=0.10 进行处理,处理成4*4的矩阵形式,而不是直接使用,后来查阅资料发现应该是涉及到计算机图形学的变换矩阵的范畴。

计算机图形学中3D的变换是基于转换矩阵( 仿射空间 )进行的。那么为什么是4维的矩阵而不是3维:用第四维度标识向量 or 点。

模型的变换可以认为是空间中一堆点的变换,三维空间中,(x,y,z)可以认为是点,也可以认为是一个向量,因此,人们引入的第4个维度来标识是点还是向量,这个4维空间就叫 仿射空间,,在仿射空间中,(x,y,z,0)标识向量,而(x,y,z,1)表示点。

在图形学中,在做平移,旋转和缩放时,经常会用到矩阵,有缩放矩阵、平移矩阵和旋转矩阵。在三维空间中,变换矩阵都是一个四维矩阵,每一行分别表示x, y, z, w。

1. 缩放矩阵(scale)

上面的公式,左边的第一个操作数(四维矩阵)就是一个缩放矩阵,s1表示x轴的缩放倍数,s2表示y轴的缩放倍数,s3表示z轴的缩放倍数。第二个操作数表示空间中(x, y, z)点, w分量在缩放矩阵中没有用到,我们将其设为1。由右边的结果,可以看出(x, y, z)点经过缩放矩阵变换后,x、y、z分量都各自缩放了s(s1、s2、s3)倍。需要注意的是矩阵的乘法不具有交换律,这里点是用一维列矩阵表示的,作为矩阵乘法的右操作数。如果将其转换到乘法的左边,那么点应该用一维行矩阵表示:

缩放矩阵比较简单,不需要证明,只需要会简单的乘法,就可以看出x,y,z经过缩放矩阵的变换确实被缩放了。

2.平移矩阵(translation)

平移矩阵也称位移矩阵,平移矩阵用到了第四列(w列),这也是为什么三维空间变换矩阵为什么是四维的。平移矩阵也比较容易理解,因为可以通过结果看出想x 、y、z确实各自平移了T步。

3. 旋转矩阵

旋转矩阵,相对难一些,也不是那么容易理解,我们先看最基础的绕x、y、z轴旋转的旋转矩阵。

沿x轴:

沿y轴:

沿z轴:

引入了三角函数,我们无法从结果看出旋转矩阵是否正确,所以我们需要证明。下面我给出沿z轴旋转的变换矩阵证明过程,其他轴同理可证。

image-20210521112417466

假设有如图的点p1,因为绕z轴旋转,点的z值是不变的,我们将其设为0,这样可以将其模拟成二维平面xy中旋转。假设p1绕原点旋转b角度,初始角度为a。整个证明过程如下:

// 经过旋转后向量的长度不变为L(原点到p1和p2的距离相同)
// 由三角函数得到sin(a + b), cos(a + b)的值
cos(a + b) = x2 / L;
sin(a + b) = y2 / L;

// 展开sin(a + b)和cos(a + b)
cos(a) * cos(b) - sin(a) * sin(b) = x2 / L;
sin(a) * cos(b) + cos(a) * sin(b) = y2 / L;

// 用x和y表示cos(a)和sin(a)
x / L * cos(b) - y / L * sin(b) = x2 / L;
y / L * cos(b) + x / L * sin(b) = y2 / L;

// 等式两边同时乘以L
x * cos(b) - y * sin(b) = x2;
y * cos(b) + x * sin(b) = y2;

将x2和y2的结果与上面z轴旋转矩阵结果比较,发现是完全一样的。

按照上面的方法同理可证绕x轴旋转和绕z轴旋转的矩阵。

那么绕任意轴旋转的矩阵呢?learnOpengl_cn官网直接给出了绕任意轴旋转的矩阵,(Rx, Ry, Rz)表示任意轴,θ表示旋转的矩阵。这个矩阵证明比较复杂。

PyTorch3D:面向3D计算机视觉的PyTorch工具箱

PyTorch3D通过PyTorch为3D计算机视觉研究提供高效,可重复使用的组件。目前已基于此开发了:Mesh R-CNN、SynSin等模型。

Facebook开源了一个专门用于3D模型学习的库pytorch3d,说白了就是将3d中一些常用的操作封装起来了。那这个玩意到底有啥用呢?使用这个库又能完成什么事情呢?个人觉得这个库还是蛮有用的,它将一些常用的3D概念整理在一起,并且通过使用这个库可以完成一些基于3D的创作,对于学习入门3D的视觉生成、渲染、甚至是3d的目标检测、3维的姿态评估都大有裨益。

Pytorch3D_上手学习3D的AI模型

Accelerating 3D Deep Learning with PyTorch3D

文档:Welcome to PyTorch3D’s documentation!
项目链接:facebookresearch/pytorch3d
论文:https://arxiv.org/abs/2007.08501

PyTorch3D

主要功能包括:

  • 用于存储和操作 triangle meshes的数据结构
  • 在 triangle meshes上的有效操作(投影变换,图卷积,采样,损失函数)
  • 可微的mesh渲染器

PyTorch3D旨在与深度学习方法稳定集成,以预测和处理3D数据。 因此,PyTorch3D中的所有运算符:

  • 使用PyTorch张量实现
  • 可以处理小批量的异构数据
  • 可以differentiated
  • 可以利用GPU进行加速

深度学习已大大改善了2D图像识别。扩展到3D可能会推动许多新应用的发展,包括自动驾驶汽车,虚拟现实和增强现实,创作3D内容,甚至改善2D识别。然而,尽管兴趣日益浓厚,但3D深度学习仍相对未得到充分开发。我们认为,这种差异是由于3D深度学习所涉及的工程挑战所致,例如有效处理异构数据和将图形操作重构为可微的。

我们通过引入PyTorch3D来应对这些挑战,PyTorch3D是一个用于3D深度学习的模块化,高效且可微的运算符库。它包括一个用于网格和点云的快速,模块化,可微的渲染器,支持按合成进行分析的方法。

与其他可微的渲染器相比,PyTorch3D更具模块化和效率,允许用户更轻松地扩展它,同时还可以优雅地缩放到较大的网格和图像。我们将PyTorch3D运算符和渲染器与其他实现进行了比较,并展示了显著的速度和内存改进。我们还使用PyTorch3D改进了ShapeNet上2D图像的无监督3D网格和点云预测的最新技术。

PyTorch3D是开源的,我们希望它将有助于加速3D深度学习的研究。

实验结果

命令行从 Google Drive下载数据

本文介绍了通过wgetcurl从Google Drive上下载文件的脚本。因为大量的数据集都存放在Google Drive上,而计算任务通常都是在计算服务器上,直接从Google Drive这类云盘下载到服务器上显然是最合适的方式。

分享链接

Google Drive的分享链接格式通常为:

https://drive.google.com/file/d/<fileid>/view

其中这个<fileid>就是对应文件在服务器上的唯一标识符。

例如OfficeHome数据集在Google Drive上的链接即为:

https://drive.google.com/file/d/0B81rNlvomiwed0V1YUxQdC1uOTg/view

其中的<fileid>0B81rNlvomiwed0V1YUxQdC1uOTg,文件名可以自己取。

所以提取到的关键变量为:

filename=’OfficeHomeDataset_10072016.zip’
fileid=’0B81rNlvomiwed0V1YUxQdC1uOTg’

wget 下载指令

针对小文件:

wget –no-check-certificate “https://drive.google.com/uc?export=download&id=${fileid}” -O ${filename}

如果文件大的话,需要对cookie进行处理:

wget –load-cookies /tmp/cookies.txt “https://drive.google.com/uc?export=download&confirm=$(wget –quiet –save-cookies /tmp/cookies.txt –keep-session-cookies –no-check-certificate ‘https://drive.google.com/uc?export=download&id=${fileid}’ -O- | sed -rn ‘s/.confirm=([0-9A-Za-z_]+)./\1\n/p’)&id=${fileid}” -O ${filename} && rm -rf /tmp/cookies.txt

因为Google drive的大文件,无法通过安全查杀

整理成更方便的脚本示例为:

#!/bin/bash

# cd scratch place
cd data/

# Download zip dataset from Google Drive
filename=’OfficeHomeDataset_10072016.zip’
fileid=’0B81rNlvomiwed0V1YUxQdC1uOTg’
wget –load-cookies /tmp/cookies.txt “https://drive.google.com/uc?export=download&confirm=$(wget –quiet –save-cookies /tmp/cookies.txt –keep-session-cookies –no-check-certificate ‘https://drive.google.com/uc?export=download&id=${fileid}’ -O- | sed -rn ‘s/.confirm=([0-9A-Za-z_]+)./\1\n/p’)&id=${fileid}” -O ${filename} && rm -rf /tmp/cookies.txt

# Unzip
unzip -q ${filename}
rm ${filename}
cd

curl 下载指令

小文件 < 40MB:

curl -L -o ${filename} “https://drive.google.com/uc?export=download&id=${fileid}”

大文件 > 40MB:

curl -c ./cookie -s -L “https://drive.google.com/uc?export=download&id=${fileid}” > /dev/null
curl -Lb ./cookie “https://drive.google.com/uc?export=download&confirm=`awk ‘/download/ {print $NF}’ ./cookie`&id=${fileid}” -o ${filename}
rm ./cookie

整理成脚本:

#!/bin/bash

# cd scratch place
cd scratch/

# Download zip dataset from Google Drive
filename=’OfficeHomeDataset_10072016.zip’
fileid=’0B81rNlvomiwed0V1YUxQdC1uOTg’
curl -c ./cookie -s -L “https://drive.google.com/uc?export=download&id=${fileid}” > /dev/null
curl -Lb ./cookie “https://drive.google.com/uc?export=download&confirm=`awk ‘/download/ {print $NF}’ ./cookie`&id=${fileid}” -o ${filename}
rm ./cookie

# Unzip
unzip -q ${filename}
rm ${filename}

# cd out
cd

但是如果连不上外网,那就需要一个梯子的选项,即proxychains4这个命令行代理工具,或者需要通过其他机器进行联网的中转可以参考离线服务器通过PC中转连接公网

对于不能直接联网的机器运行脚本方式为:

proxychains4 sh download_google_drive.sh

参考资源

推荐系统–物品冷启动

物品冷启01:优化目标 & 评价指标

冷启动问题 (cold start) 主要分3类:

  • 用户冷启动。用户冷启动主要解决如何给新用户做个性化推荐的问题。当新用户到来时,我们没有他的行为数据,所以也无法根据他的历史行为预测其兴趣,从而无法借此给他做个性化推荐。
  • 物品冷启动。物品冷启动主要解决如何将新的物品推荐给可能对它感兴趣的用户这一问题。
  • 系统冷启动。 系统冷启动主要解决如何在一个新开发的网站上(还没有用户,也没有用户行为,只有一些物品的信息)设计个性化推荐系统,从而在网站刚发布时就让用户体验到个性化推荐服务这一问题。

物品冷启动指的是如何对新发布的物品做分发。优化物品冷启动在小红书这样的 User-Generated Content (UGC) 平台尤为重要,这是因为新物品数量巨大,内容质量良莠不齐,分发非常困难。而且之气讲到的那些模型对于新发布的物品效果很差,曝光率比较低。

UGC 平台的物品冷启动有三个目标: 1. 精准推荐:克服冷启的困难,把新物品推荐给合适的用户,不引起用户反感。 2. 激励发布:流量向低曝光新物品倾斜,激励发布。 3. 挖掘高潜:通过初期小流量的试探,找到高质量的物品,给与流量倾斜。

UGC 平台的物品冷启动主要考察三种指标: 1. 作者侧指标,包括发布渗透率、人均发布量。 2. 用户侧指标,包括大盘消费指标和新物品消费指标。 3. 内容侧指标,比如高热物品占比。

优化目标

评价指标

物品冷启02:简单的召回通道

物品冷启动 (item cold start) 中的召回。冷启动召回的难点是缺少用户交互,还没学好笔记 ID embedding,导致双塔模型效果不好。而且缺少用户交互会导致 ItemCF 不适用。 这节课介绍两种简单的召回通道: 1. 改造双塔模型,使得它适用于冷启动。 2. 类目召回。

物品冷启03:聚类召回

聚类召回是基于物品内容的召回通道。它假设如果用户喜欢一个物品,那么用户会喜欢内容相似的其他物品。使用聚类召回,需要事先训练一个多模态神经网络,将笔记图文表征为向量,并对向量做聚类,然后建索引。

内容相似度模型:

内容相似度模型的训练:

物品冷启04:Look-Alike 召回

Look-Alike 是一种召回通道,对冷启很有效。

Look-Alike 适用于发布一段时间、但是点击次数不高的物品。物品从发布到热门,主要的透出渠道会经历三个阶段: 1. 类目召回、聚类召回。它们是基于内容的召回通道,适用于刚刚发布的物品。 2. Look-Alike 召回。它适用于有点击,但是点击次数不高的物品。 3. 双塔、ItemCF、Swing 等等。它们是基于用户行为的召回通道,适用于点击次数较高的物品。

物品冷启05:流量调控

流量调控是物品冷启动最重要的一环,直接影响作者发布指标。流量调控的发展通常会经历这几个阶段:

1. 在推荐结果中强插新笔记。 2. 对新笔记做提权(boost)。 3. 通过提权,对新笔记做保量。 4. 差异化保量。

新笔记做提权:

物品冷启06:冷启的AB测试

物品冷启动的AB测试,内容很烧脑,不建议初学者观看。推荐系统常用的AB测试只考察用户侧消费指标,而推荐系统的AB测试还需要额外考察作者侧发布指标。后者远比前者复杂,而且所有已知的实验方案都存在缺陷。

推荐系统–重排

重排01:物品相似性的度量、提升多样性的方法

推荐系统中的多样性。如果多样性做得好,可以显著提升推荐系统的核心业务指标。这节课的内容分两部分: 1. 物品相似性的度量。可以用物品标签或向量表征度量物品的相似性。最好的方法是基于图文内容的向量表征,比如 CLIP 方法。 2. 提升多样性的方法。在推荐的链路上,在粗排和精排的后处理阶段,综合排序模型打分和多样性分数做选择。

为了提升物体的多样性,首先要度量两个物品有多相似。

基于物品属性标签计算相似度:

基于物品向量表征:基于图文内容的向量表征

用下面的方法不好训练,因为需要人工标注,因此一般采用cilp的方法。

提升多样性的方法:

重排02:MMR 多样性算法(Maximal Marginal Relevance)

推荐系统和搜索引擎重排中常用的 Maximal Marginal Relevance (MMR),它根据精排打分和物品相似度,从 n 个物品中选出 k 个价值高、且多样性好的物品。这节课还介绍滑动窗口 (sliding window),它可以与 MMR、DPP 等多样性算法结合,实践中滑动窗口的效果更优。

选择R中MR最高的放入集合S中。

参考文献: Carbonell and Goldstein. The use of MMR, diversity-based reranking for reordering documents and producing summaries. In ACM SIGIR Conference on Research and Development in Information Retrieval, 1998.

重排03:业务规则约束下的多样性算法

推荐系统有很多业务规则,比如不能连续出多篇某种类型的物品、某两种类型的物品笔记间隔多少。这些业务规则应用在重排阶段,可以与 MMR、DPP 等多样性算法相结合。

重排04:DPP 多样性算法

行列式点过程 (determinantal point process, DPP) 是一种经典的机器学习方法,在 1970’s 年代提出,在 2000 年之后有快速的发展。DPP 是目前推荐系统重排多样性公认的最好方法。 DPP 的数学比较复杂,内容主要是超平行体、超平行体的体积、行列式与体积的关系。

参考文献: Chen et al. Fast greedy map inference for determinantal point process to improve recommendation diversity. In NIPS, 2018.

行列式等价于体积,因此用行列式的值来衡量物品的多样性。

DPP及其再推荐系统重排中的应用。求解DPP是比较困难的,需要计算行列式很多次,而计算行列式需要矩阵分解,代价很大。这节课介绍Hulu论文中的算法,可以用较小的代价求解DPP。 参考文献: Chen et al. Fast greedy map inference for determinantal point process to improve recommendation diversity. In NIPS, 2018.

行列式等价于体积,因此用行列式的值来衡量物品的多样性。

求解DPP:

推荐系统–行为序列特征

行为序列01:用户历史行为序列建模

用户最近 n 次(top n)点击、点赞、收藏、转发等行为都是推荐系统中重要的特征,可以帮助召回和排序变得更精准。这节课介绍最简单的方法——对用户行为取简单的平均,作为特征输入召回、排序模型。

多目标排序模型:

这里 用户历史行为序列 就是指用户特征中的last n序列特征。

以用户点击过的last n的物品为例 ,对这n个物品id和其他特征用embedding做嵌入,获得相应的n个向量,对这n个向量取平均得到最终的向量。

这里对Last N个向量只是简单的做一下平均,也有更高级的做法,比如基于attention注意力。后面会提到 Last N 不同的序列建模方法。

行为序列02:DIN模型(注意力机制)

上节课介绍了用户的 LastN 序列特征。这节课介绍 DIN 模型,它是对 LastN 序列建模的一种方法,效果优于简单的平均。DIN 的本质是注意力机制(attention)。DIN 是阿里在 2018 年提出的,有兴趣的话可以阅读下面的参考文献。

什么是候选物体:对于精排模型来说,粗排模型输出的几百个物体就是候选物体。

行为序列03:SIM模型(长序列建模)

SIM 模型,它的主要目的是保留用户的长期兴趣。SIM 的原理是对用户行为序列做快速筛选,缩短序列长度,使得DIN可以用于长序列。

参考文献: Qi et al. Search-based User Interest Modeling with Lifelong Sequential Behavior Data for Click-Through Rate Prediction. In CIKM, 2020.

如何运行 c++ 代码/编译过程

运行cpp文件:

如何运行cpp文件:
方法1、vscode runcode
方法2、使用g++命令简单编译,在终端输入 g++ -o test test.cpp # -L. -l动态库名 (如果需要导入动态库)
方法3、对于复杂的程序,需要编写makefile or 使用cmake ,然后执行 make命令

CMake说明: 一般把CMakeLists.txt文件放在工程目录下,使用时,先创建一个叫build的文件夹(这个并非必须,因为cmake命令指向CMakeLists.txt所在的目录,例如cmake .. 表示CMakeLists.txt在当前目录的上一级目录。cmake后会生成很多编译的中间文件以及makefile文件,所以一般建议新建一个新的目录,专门用来编译),然后执行下列操作:

cd build
cmake ..
make
其中cmake .. 在build里生成Makefile,make根据生成makefile文件,编译程序,make应当在有Makefile的目录下,根据Makefile生成可执行文件。

C++编译过程主要分为,预处理、编译、汇编、链接四个过程。如下图所示:

在这里插入图片描述

第一步:预处理 将源代码的.c 、.cpp 、.h 等文件包含到一个文件中。在这个过程中会使用一些预处理指令要求编译器使用什么样的方式包含这些文件。预处理结束之后对于c语言编译器会生成一个.i 文件。C++会生成.ii文件。

预编译过程主要处理那些源代码中以#开始的预编译指令,主要处理规则如下:

·将所有的#define删除,并且展开所有的宏定义;

·处理所有条件编译指令,如#if,#ifdef等;

·处理#include预编译指令,将被包含的文件插入到该预编译指令的位置。该过程递归进行,及被包含的文件可能还包含其他文件。

·删除所有的注释//和 /**/;

·添加行号和文件标识,如#2 “hello.c” 2,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号信息;

·保留所有的#pragma编译器指令,因为编译器须要使用它们;

第二步:编译 编译过程就是把预处理完的文件进行一系列词法分析,语法分析,语义分析及优化后生成相应的汇编代码文件.

第三步:汇编 汇编器是将汇编代码转变成机器可以执行的命令,每一个汇编语句几乎都对应一条机器指令。汇编相对于编译过程比较简单,根据汇编指令和机器指令的对照表一一翻译即可。

第四步:链接 链接器ld将各个目标文件组装在一起,解决符号依赖,库依赖关系,并生成可执行文件。

动态链接和静态链接

方法库大体上可以分为两类:静态库和动态库(共享库)。

1. windows中静态库是以 .lib 为后缀的文件,动态库是以 .dll 为后缀的文件。

2. linux中静态库是以 .a 为后缀的文件,动态库是以 .so为后缀的文件。

静态链接:

  • 静态库 在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。
  • 静态库可以简单看成是一组目标文件(.o .obj文件)的集合, 将若干个.o文件转换为静态库的过程,称之为打包. Linux下是使用ar工具, Windows下是使用lib.exe。
  • Linux下静态链接库的后缀是.libWindows下静态链接库的后缀是.a

动态链接:

  • 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行时才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新。
  • 在Windows系统下的执行文件格式是PE(Portable Executable)格式,动态库需要一个DllMain函数做出初始化的入口,通常在导出函数的声明时需要有_declspec(dllexport)关键字。 跟exe有个main或者WinMain入口函数一样,DLL也有一个入口函数,就是DllMain。根据编写规范,Windows必须查找并执行DLL里的DllMain函数作为加载DLL的依据,它使得DLL得以保留在内存里。这个函数并不属于导出函数,而是DLL的内部函数。这意味着不能直接在应用工程中引用DllMain函数,DllMain是自动被调用的。
    对于动态链接库,DllMain是一个可选的入口函数。一个动态链接库不一定要有DllMain函数,比如仅仅包含资源信息的DLL是没有DllMain函数的。
  • Linux下gcc编译的执行文件默认是ELF格式,不需要初始化入口,亦不需要函数做特别的声明,编写比较方便。
    无需打包工具,直接使用编译器即可创建动态库。
  • Linux下动态链接库的后缀是.so;Windows下动态链接库的后缀是.dll

区别:

 当程序与静态库链接时,静态库中所包含的所有函数方法都会被copy到最终的可执行文件中去。这就会导致最终生成的可执行代码量相对变多,相当于编译器将代码补充完整了。这种方式会让程序运行起来相对快一些,不过也会有个缺点: 占用磁盘和内存空间,导致可执行exe程序过大。另外,静态库会被添加到和它链接的每个程序中去, 而且这些程序运行时, 都会被加载到内存中,无形中又多消耗了更多的内存空间。

与动态库链接的可执行文件只包含它需要的函数方法的引用表,而不是所有的函数代码,只有在程序执行时, 那些需要的函数代码才会被拷贝到内存中。这样就使可执行文件比较小, 节省磁盘空间,更进一步,操作系统使用虚拟内存,使得一份动态库驻留在内存中被多个程序使用,也同时节约了内存。不过由于运行时要去链接库会花费一定的时间,执行速度相对会慢一些。

       总的来说,静态库是牺牲了空间效率,换取了时间效率,动态库是牺牲了时间效率换取了空间效率,没有好与坏的区别,只看具体需要了。
       另外,一个程序编好后,有时需要做一些修改和优化,如果我们要修改的刚好是库函数的话,在接口不变的前提下,使用动态库的程序只需要将动态库重新编译就可以了,而使用静态库的程序则需要将静态库重新编译好后,将程序再重新编译一遍。

推荐系统–特征交叉

特征交叉用于召回和排序阶段。

特征交叉01:Factorized Machine (FM) 因式分解机

线性模型对输入的特征取加权和,作为对目标的预估。如果先做特征交叉,再用线性模型,通常可以取得更好的效果。如果做二阶特征交叉,那么参数量为O(特征数量平方),计算量大,而且容易造成过拟合因式分解机(Factorized Machine, FM)用低秩矩阵分解的方式降低参数量,加速计算。任何可以用线性模型(比如线性回归、逻辑回归)解决的问题,都可以用 FM 解决。

线性模型的特征xi之间没有交叉,只是简单的加法,没有乘法。

二阶交叉特征:如果d很大,复杂度就太高了,计算代价太大,所以需要一种低复杂度的特征交叉方法,关键在于优化uij这个矩阵。

目前FM已经过时,不再使用该方法

特征交叉02:DCN 深度交叉网络

Deep & Cross Networks (DCN) 译作“深度交叉网络”,用于代替传统的全连接网络。可以用于召回双塔模型、粗排三塔模型、精排模型。DCN 由一个深度网络和一个交叉网络组成,交叉网络的基本组成单元是交叉层 (Cross Layer)。这节课最重点的部分就是交叉层。

交叉层 (Cross Layer)

深度交叉网络

特征交叉03:LHUC (PPNet)

LHUC 这种神经网络结构,只用于精排。LHUC 的起源是语音识别,后来被应用到推荐系统,快手将其称为 PPNet,现在已经在业界广泛落地。 遗漏一个细节:将LHUC用于推荐系统,门控神经网络(2 x sigmoid)的梯度不要传递到用户ID embedding特征,需要对其做 stop gradient。 参考文献: 1. Pawel Swietojanski, Jinyu Li, & Steve Renals. Learning hidden unit contributions for unsupervised acoustic model adaptation. IEEE/ACM Transactions on Audio, Speech, and Language Processing, 2016. 2. 快手落地万亿参数推荐精排模型,2021。

特征交叉04:SENet 和 Bilinear 交叉

1. SENet 是计算机视觉中的一种技术,可以用在推荐系统中对特征做动态加权。

2. 双线性(bilinear)特征交叉可以提升排序模型的表现。有很多种 bilinear 交叉的方法。 3. FiBiNet 是将 SENet 与 Bilinear 模型结合。

Filed间特征交叉

双线性(bilinear)特征交叉:

推荐系统–排序

课件地址:https://github.com/wangshusen/RecommenderSystem

结合小红书的业务场景和内部实践,讲解主流的工业界推荐系统技术。

主要内容:

排序01:多目标模型

第一部分是模型结构。模型把用户特征、物品特征、统计特征、场景特征作为输入,输出对多个指标的预估。 第二部分内容是降采样和校准。在实际的推荐系统中,正负样本的比例严重不平衡,负样本数量远多于正样本,因此需要对负样本做降采样。以点击率为例,对负样本做降采样会导致模型高估点击率,因此需要用公式做校准。

粗排和精排用到的方法都差不多,但精排的模型比较大,因此需要先用粗排模型从几千篇笔记中选择几百篇用于精排。

用户点击以后才会出现点赞、收藏和转发行为:

排序的依据是笔记的点击率、点赞率、收藏率、转发率等多种分数。

多目标模型:

模型输出某个用户对于某篇笔记的预估点赞率、点击率、收藏率以及转发率

训练:类别不平衡。

预估值校准

排序02:多目标排序模型的改进MMoE

Multi-gate Mixture-of-Experts (MMoE) 是一种多目标排序模型。MMoE 用多个独立的塔提取特征,并对多塔提取的特征向量做加权平均,然后送入多头。MMoE 的训练容易出现极化现象(polarize),可以用 dropout 解决。

这里假设神经网络的目标只有点击率和点赞率这两个目标,因此只需要两组权重:p和q

极化现象:softmax函数导致

极化解决方法:

排序03:预估分数的融合

前面通过MMoE获得了点赞、点击、转发率等指标的预估值,得到这些指标之后,需要将它们融合成一个分数。这节课介绍工业界常用的几种融分公式。

用预估的视频时长做排序,用排名来计算得分:

排序04:视频播放建模

视频播放的建模主要有两个目标:视频播放时长、视频完播率。这节课讨论如何在多目标排序模型添加与播放时长、完播率相关的预估任务。

视频越长,完播率越低:

排序05:排序模型的特征

推荐系统中的排序模型需要用户画像、物品画像、统计特征、场景特征。

排序06:粗排的三塔模型

粗排三塔模型,它介于前期融合的双塔模型和后期融合的精排模型之间。用户塔可以很大,因为它只需要做1次推理。物品塔可以比较大,因为物品塔的输出可以缓存在PS。交叉塔必须很小,如果有n个物品,交叉塔需要做n次推理。三塔模型的计算量主要是上层的全连接层。

推荐系统–召回

召回01:基于物品的协同过滤(ItemCF)

Item Based Collaborative Filtering,缩写 ItemCF

ItemCF 的原理:如果用户喜欢物品1,而且物品1与物品2相似,那么用户很可能喜欢物品2。

1. 如何计算两个物品之间的相似度。

2. 如何预估用户对候选物品的兴趣。

3. 如何利用索引在线上快速做召回。

ItemCF的实现

两个物体的受众重合度越高,表示两个物体越相似。

余弦相似度

ItemCF完整流程:

step1:事先做离线计算

step2 线上做召回:

为什么要用索引:

召回02:Swing召回通道

ItemCF :(缺点)

Swing模型:(为用户设置权重)

召回03:基于用户的协同过滤(UserCF)

UserCF 的原理:如果用户1跟用户2相似,而且用户2喜欢某物品,那么用户1很可能喜欢该物品。

关键:1. 如何计算两个用户之间的相似度。 2. 如何预估用户对候选物品的兴趣。 3. 如何利用索引在线上快速做召回。

用户相似度:

如果是热门物体,那么大概率两个用户都会喜欢,因此需要降低热门物体的权重:

UserCF召回的完整流程

step1:离线计算

step2:线上做召回

召回04: 向量召回 ,离散特征处理

one-hot encoding (独热编码) 和 embedding (嵌入)

召回05: 向量召回 ,矩阵补充、最近邻查找

矩阵补充(matrix completion),它是一种向量召回通道。矩阵补充的本质是对用户 ID 和物品 ID 做 embedding,并用两个 embedding 向量的内积预估用户对物品的兴趣。值得注意的是,矩阵补充存在诸多缺点,在实践中效果远不及双塔模型。 做向量召回需要做最近邻查找(nearest neighbor search)。

用绿色的信息做训练,来预测灰色的值,进而为用户做召回

近似最近邻查找:

step1:划分区域

step2:用一个向量表示但各区域,给定一个物体,则返回所在的区域的物体

step3:只需计算该区域所在的相似度。

召回06:双塔模型:矩阵补充的升级版

双塔模型(two-tower)也叫 DSSM,是推荐系统中最重要的召回通道,没有之一。双塔模型有两个塔:用户塔、物品塔。两个塔各输出一个向量,作为用户、物品的表征。两个向量的内积或余弦相似度作为对兴趣的预估。有三种训练双塔模型的方式:pointwise、pairwise、listwise。

双塔模型训练:

pointwise:

pariwise:

listwise:

召回07:双塔模型–正负样本选择

双塔模型(two-tower,也叫 DSSM)正负样本的选取。正样本是有点击的物品。负样本是被召回、排序淘汰的物品,分为简单负样本和困难负样本。

负样本:

简单负样本:Batch内负样本

热门样本成为负样本的概率过大,解决办法:

困难负样本:

召回08:双塔模型的线上服务和模型更新

在开始线上服务之前,需要把物品向量存储到Milvus、Faiss、HnswLib这类向量数据库,供最近邻查找(KNN 或 ANN)。当用户发起推荐请求时,用户塔用用户ID和用户画像现算一个用户向量,作为query,去向量数据库中做最近邻查找。

模型需要定期做更新,分为全量更新(天级别)和增量更新(实时)。全量更新会训练整个模型,包括embedding和全连接层。而增量更新只需要训练embedding层。

模型更新:

全量更新:跟新用户和物体向量

增量更新:每隔几小时实现用户模型更新

为什么需要这个:用户的兴趣可能会随时改变,因此需要随时做用户的更新,且只更新用户embedding参数,其他参数不需要更新。

注意:每天的全量更新是基于昨天的全量更新后的模型进行训练的。

问题:能否只做增量更新,不做全量更新

召回09:双塔模型的改进–自监督学习

改进双塔模型的方法,叫做自监督学习(self-supervised learning),用在双塔模型上可以提升业务指标。这种方法由谷歌在2021年提出,工业界(包括小红书)普遍验证有效。

长尾效应:

参考文献: Tiansheng Yao et al. Self-supervised Learning for Large-scale Item Recommendations. In CIKM, 2021.

自监督学习:

对物品进行不同的特征变换得到的特征向量同类之间尽可能的相同,不同物体之间尽可能不同。

特征变换方法:

1、Random Mask

2、Dropout

3、互补特征

最好的办法 :Random mask(将一组相关联的特征全部mask)

召回10:其他召回通道

地理位置召回包括GeoHash召回和同城召回作者召回包括关注作者、有交互作者、相似作者。缓存召回是储存精排打分高、而且未曝光的笔记。

6个其他召回通道: