深度学习面经-推荐算法系列

一、简介

搜广推算法在各大互联网公司中承担着重要的流量转化的作用,其中推荐算法作为一个重要分支,它旨在为用户提供个性化的推荐内容,以提高用户体验和满足他们的需求。推荐算法的应用范围非常广泛,包括电子商务、社交媒体、音乐和视频流媒体、新闻推荐等各个领域。以下是一些可能出现在推荐算法系列面试中的主题和问题,面经请关注专栏:小白机器学习面试指南。持续更新中。

二、面经及参考回答

1、你了解的常见的召回策略,算法有哪些?

参考回答:召回算法用于从大规模数据集中快速筛选出一组候选项,以供后续的排序和推荐处理。常见的召回有下面几种:

基于内容的召回:基于物品的内容召回:使用物品的属性和特征,如文本、标签或图像,来计算物品之间的相似度,以推荐相似的物品。

基于用户的内容召回:分析用户的历史行为和个人资料,以确定他们对内容的兴趣,并为其推荐相关内容。

协同过滤召回:基于用户的协同过滤:根据用户与其他用户的相似性,为目标用户推荐与相似用户喜欢的物品。基于物品的协同过滤:根据物品之间的相似性,为用户推荐与他们以前喜欢的物品相似的物品。

矩阵分解:矩阵分解方法,如奇异值分解(SVD)和交替最小二乘(ALS),用于将用户-物品交互矩阵分解为潜在因子矩阵,以捕捉用户和物品之间的潜在关系。这些方法通常用于协同过滤。

基于流行度的召回:流行度召回方法会根据物品的全局流行度为用户推荐物品。这意味着用户将看到最热门的物品,无论他们的兴趣如何。

基于规则的召回:基于规则的召回使用预定义的规则来选择候选物品。这些规则可以是手动制定的,也可以通过机器学习方法自动学习得出。在业务迭代初期,一般会使用这种召回方法;

深度学习召回:使用深度学习模型(如神经网络)进行召回,这些模型可以从用户历史数据中学习用户和物品之间的复杂关系,以生成召回结果。

多通道召回:使用多个不同的召回算法,并将它们的结果合并或加权,以提高推荐的多样性和准确性。

2、协同过滤存在什么问题?

参考回答:泛化能力弱。即协同过滤无法将两个物品相似的信息推广到其他物品的相似性上。导致的问题是热门物品具有很强的头部效应,容易跟大量物品产生相似,而尾部物品由于特征向量稀疏,导致很少被推荐。协同过滤的特点就是完全没有利用到物品本身或者是用户自身的属性,仅仅利用了用户与物品的交互信息就可以实现推荐,比较简单高效,但这也是它的一个短板所在,由于无法有效的引入用户年龄,性别,商品描述,商品分类,当前时间,地点等一系列用户特征、物品特征和上下文特征,这就造成了有效信息的遗漏,不能充分利用其它特征数据。

3、协同过滤有哪些可以改进的?

参考回答:加一些参数权重对热门物品,以及活跃用户进行一些惩罚。或者利用矩阵分解,使用更稠密的隐向量表示用户和物品,挖掘用户和物品的隐含兴趣和隐含特征。

4、什么时候使用UserCF,什么时候使用ItemCF?为什么?

参考回答:UserCF:由于是基于用户相似度进行推荐,所以具备更强的社交特性,这样的特点非常适于用户少,物品多,时效性较强的场合,比如新闻推荐场景,因为新闻本身兴趣点分散,相比用户对不同新闻的兴趣偏好,新闻的及时性,热点性往往更加重要,所以正好适用于发现热点,跟踪热点的趋势。对于用户较少,要求时效性较强的场合,就可以考虑UserCF。ItemCF:这个更适用于兴趣变化较为稳定的应用,更接近于个性化的推荐,适合用户兴趣固定持久,物品更新速度不是太快的场合,比如推荐艺术品,音乐,电影。

5、什么是faiss,它的原理是什么?

参考回答:faiss是FaceBook的AI团队开源的一套用于做稠密向量聚类和相似性搜索的软件库,它包含在任意大小向量上的搜索算法,也支持评估和参数调节。Faiss包含多种相似度检索方法,通过L2(欧氏距离)和点积确定,同时也支持余弦相似度来计算向量距离。它主要是通过向量压缩进行计算,而不是通过使用原型向量进行比较,这种方法虽然降低精度,但是可以极大缩小存储空间以及检索速度,可以达到近似检索。faiss本质是: 使用PCA、K-means、PQ等算法对数据进行操作,对数据进行分群,每一个群都有一个Index,根据要查找数据的与每个Index距离大小,定位要查找的那个群,也就是缩小了数据查找范围,进而加速。

6、还了解其他向量检索的方法吗?

参考回答:其他向量检索的方式 Kd - tree;kd - tree的构建方式是根据我们输入的多维embedding。每次分裂的时候,会选择方差最大的一列,然后选择这一列的中位数去划分结点,直到每一个结点都有一个向量,这样kd-tree就构建完成了。kdtree的查找:向量的查找也是每次从根节点出发,开始对比,比如这个结点是按照第三列某一个数划分的,就比较这个向量这个位置的数和这个结点的数的大小,从而判定是往左走还是往右走,最终会落到一个结点上,但是这样找不一定是最近的,如果还有更近的,就会回溯到上一个分裂点,看另一个结点的距离。

7、双塔的user侧特征和item侧的特征可以做交叉吗?

参考回答:可以的, 最简单的方式是取用户特征和物品特征的点积,这可以被看作是一种线性交叉方式。这个点积可以被加入到模型的最后输出或中间层。特征交叉可以更好地捕捉用户和物品之间的关系,从而提高推荐系统的效果。如何进行交叉需要根据具体问题和数据来设计和优化。

8、相似度的度量方法有哪些?

参考回答:Jaccard相关系数: 两个用户u和v所交互商品的交集的数量占这两个用户交互商品并集的数量的比例,称为两个集合的杰卡德相似系数,余弦相似度,在此基础上引入皮尔逊相关系数。余弦相似度没有考虑到不同用户平均打分偏差的问题,最直观的理解就是某一个用户的品味很高,对任何商品打分都很低,这样计算出来的余弦相似度就有差异,引入偏置a,b分别为a的平均打分情况,b的平均打分情况,每一个参数都减去这个平均值,然后再来计算。

9、矩阵分解的原理,具体是怎么分解的?

参考回答:矩阵分解算法将 m×n 维的共享矩阵 R 分解成 m×k 维的用户矩阵 U 和 k×n 维的物品矩阵 V 相乘的形式。其中m是用户数量,n是物品数量,k是隐向量维度,也就是隐含特征个数, k的大小决定了隐向量表达能力的强弱,k越大,表达信息就越强,理解起来就是把用户的兴趣和物品的分类划分的越具体。

矩阵分解的求解: 常用的做法就是特征值分解(EVD),奇异值分解(SVD)。但是特征值分解它要求分解的矩阵是方阵,在推荐系统中,显然用户-物品矩阵不满足这个要求,而传统的SVD分解,会要求原始矩阵是稠密的,而我们这里的这种矩阵一般情况下是非常稀疏的,如果想用奇异值分解,就必须对缺失的元素进行填充,而一旦补全,空间复杂度就会非常高,且补的不一定对。 然后就是SVD分解计算复杂度非常高,而我们的用户-物品矩阵非常大, 所以基本上无法使用。

Funk SVD:所以具体对SVD进行一些改变,用一种叫Funk SVD来进行求解。只针对矩阵中有用户评分的信息进行分解。Funk-SVD的思想很简单,把求解上面两个矩阵的参数问题转换成一个最优化问题,可以通过训练集里面的观察值利用最小化来学习用户矩阵和物品矩阵。FunkSVD的做法:因为我们已经有了用

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

小白机器学习面试指南 文章被收录于专栏

林小白的机器学习指南,从本人面试的机器学习算法岗位出发,对机器学习“八股文”做详细的介绍、推导;

全部评论
求一个搜索算法系列的
1 回复 分享
发布于 2023-10-13 16:54 北京

相关推荐

笔试通过后约的面试,之前实习经历不是开发相关的,面试时也没怎么问过往实习。对c++17和20之后特性了解多吗?用过哪些智能指针,说说各自使用场景。share_ptr底层实现。(答了什么场景下会创建shared_ptr的control block),描述enable_shared_from_this的工作原理Stl常见容器有哪些?底层用什么实现的?C++编译过程(预处理编译汇编链接),动态链接静态链接有了解吗?有什么区别?内存对齐目的?回答现场给的结构体的sizeof内存泄漏有遇到过吗说一下?你是如何解决的?new和malloc区别?malloc会用哪两种系统调用,有什么区别?(mmap和brk)操作系统的线程进程协程区别?强制类型转换有哪几种?空类大小,为什么?描述下空基类优化禁止某种不需要调用的函数怎么实现编译期间就可以进行检查?(用=delete)你知道哪些实际场景例子吗?比如thread的复制构造函数高数学了哪些?(因为投量化所以简历扯了下高中拿过数物菜鸡省奖)说一下罗尔,拉格朗日,柯西中值定理?柯西中值定理的证明。答构造一个辅助函数然后用罗尔定理证明,具体构造啥样的辅助函数忘了Linux熟练吗?常用命令哪些?查看当前性能的命令?(htop,netstat)Python装饰器用过吗?有哪些使用场景(胡答了下用于记录日志和计算函数运行时间)Python还问了些其他的但记不起来了给百来行的cpp程序,说哪个位置有误(充当下人工编译器)以及可改进优化之处手撕力扣mid
查看18道真题和解析
点赞 评论 收藏
分享
04-02 21:12
已编辑
门头沟学院 C++
1. 读写锁如何实现?2. 如何实现线程池?线程池里放了多个任务后,这些任务怎么分配到各线程的?3.哈希表的原理是什么?4.怎么实现对一个树结构进行广度优先遍历?5.栈内存和堆内存的区别?栈为什么分配速度快?它具体怎么分配?6.当使用new创建一个新的数组,它指针是虚拟地址还是物理地址?什么时候回真正映射到物理内存?7.https加密原理是怎么样的?8.如果有个假冒服务器,它也可以跟你握手吗?1. 读写锁是一种并发控制机制,允许多个线程同时读取共享资源,但写操作需要独占访问;初始化一个互斥锁(用于保护共享转态),初始化一个条件变量(用于阻塞等待的线程);读锁:如果没有写线程正在访问,允许读线程进入;写锁:如果没有读线程或写线程正在访问,允许写线程进入;解锁:读线程解锁时,介绍读取计数;写线程解锁时,通知等待的线程;2. 线程池,通过三个类实现,(1)线程类,用于控制线程的启动和停止,以及维护一个指向事件循环的指针;(2)程池类:用于管理线程,包括初始化线程数量,已经放置一个任务队列,每来一个事件就放到队列里,如果有空闲线程就唤醒去执行;(3)任务函数的接口类,写一个基类,自己通过子类来自定义函数;线程池收到任务后,会把任务放到共享的任务队列里面,每个线程会在循环里去拿任务,拿到任务时要加锁互斥,谁先拿到就执行。另外还可以考虑给任务添加优先级3. 通过哈希函数将将键值映射到数组索引,再用数组存储键值对。举例:像C++中的unorder_map,使用链地址法解决冲突,在哈希冲突时把多个元素放到同一个桶里链表中。当存储的元素跟数组大小的比值超过一定阈值,会进行自动扩容;4.  广度优先遍历就是对每一层进行遍历,用队列实现;先把根节点入队,出队时访问,然后把它的子节点按顺序入队,一直到队列为空;5. 栈由操作系统自动分配回收,存储函数的现参、局部变量、返回地址等;堆是通过new/delete或者malloc/free由程序自己分配释放,能分配更大的内存,但可能会出现内存碎片等问题;操作系统在底层对栈提供支持,会分配专门的寄存器存放栈的地址,另外它的入栈出栈操作也十分简单,并且由专门的指令执行,所以下来会很快;堆的操作是由C/C++函数库提供,在分配内存的时候需要一定的算法寻找合适大小的内存。并且获取堆的内容需要两次访问,第一次访问指针,第二次根据指针保存的地址访问内存,因此堆比较慢。6. 并不是物理内存,而是虚拟地址,后面需要通过页表和MMU(内存管理单元)来映射到物理内存;操作系统采用懒加载策略,只有在程序访问这块内存时,才会将虚拟内存页映射到物理内存。也就是说,程序触发缺页中断时,操作系统才会分配物理内存并更新页表来完成映射。7. 客户端会发送一个Client random + TLS版本号 + 支持的密码套件列表的信息给服务端,服务器回应一个Server random + 自己的数字证书;客户端通过证书认证机构(CA)来验证证书是否合法,确认服务器身份后,用服务器的公钥加密一个pre-master发回给服务器;服务器用私钥解密得到该数;后面的就使用这个生成的会话秘钥client random + Server random + pre-master进行对称加密传输;8. 如果是一个假冒服务器,它的证书没有权威CA的签名,或者证书域名不匹配,客户端会提示不信任,阻止连接。CA:是证书颁发机构,负责签发;证书:由CA颁发的电子文件,包含公钥、身份信息和CA的签名等;
点赞 评论 收藏
分享
评论
10
132
分享

创作者周榜

更多
牛客网
牛客企业服务