美团推荐算法工程师面试题8道

1、各种优化器使用的经验

    梯度下降:在一个方向上更新和调整模型的参数,来最小化损失函数。

    随机梯度下降(Stochastic gradient descent,SGD)对每个训练样本进行参数更新,每次执行都进行一次更新,且执行速度更快。

    为了避免SGD和标准梯度下降中存在的问题,一个改进方法为小批量梯度下降(Mini Batch Gradient Descent),因为对每个批次中的n个训练样本,这种方法只执行一次更新。

    使用小批量梯度下降的优点是:

    1) 可以减少参数更新的波动,最终得到效果更好和更稳定的收敛。

    2) 还可以使用最新的深层学习库中通用的矩阵优化方法,使计算小批量数据的梯度更加高效。

    3) 通常来说,小批量样本的大小范围是从50到256,可以根据实际问题而有所不同。

    4) 在训练神经网络时,通常都会选择小批量梯度下降算法。

    SGD方法中的高方差振荡使得网络很难稳定收敛,所以有研究者提出了一种称为动量(Momentum)的技术,通过优化相关方向的训练和弱化无关方向的振荡,来加速SGD训练。

    Nesterov梯度加速法,通过使网络更新与误差函数的斜率相适应,并依次加速SGD,也可根据每个参数的重要性来调整和更新对应参数,以执行更大或更小的更新幅度。

    AdaDelta方法是AdaGrad的延伸方法,它倾向于解决其学习率衰减的问题。Adadelta不是累积所有之前的平方梯度,而是将累积之前梯度的窗口限制到某个固定大小w。

    Adam算法即自适应时刻估计方法(Adaptive Moment Estimation),能计算每个参数的自适应学习率。这个方法不仅存储了AdaDelta先前平方梯度的指数衰减平均值,而且保持了先前梯度M(t)的指数衰减平均值,这一点与动量类似。

    Adagrad方法是通过参数来调整合适的学习率η,对稀疏参数进行大幅更新和对频繁参数进行小幅更新。因此,Adagrad方法非常适合处理稀疏数据。

2、python 垃圾处理机制

    在Python中,主要通过引用计数进行垃圾回收;通过 “标记-清除” 解决容器对象可能产生的循环引用问题;通过 “分代回收” 以空间换时间的方法提高垃圾回收效率。也就是说,python采用的是引用计数机制为主,标记-清除和分代收集(隔代回收)两种机制为辅的策略。

3、yield 关键字作用

    yield是一个类似 return 的关键字,只是这个函数返回的是个生成器,可以节省巨大的时间、空间开销。

4、python 多继承,两个父类有同名方法怎么办?

    super(Classname, self).methodname() 或 super(Classname, cls).methodname() 调用"下一个"父类中的方法

    1.假设类A继承B, C, D: class A(B, C, D), B/C/D都有一个show()方法

    a.调用B的show()方法:

    super().show()

    super(A, self).show()

    b.调用C的show()方法:

    super(B,self).show()

    c.调用D的show()方法:

    super(C,self).show()

    2.如果在B类中需要调用C类中的show()方法, 也是一样的

class B:
    def show(self):
        super(B, self).show()

5、python 多线程/多进程/协程

类型

优点

缺点

适用

多进程Process(multiprocessing)

可以利用CPU多核并行运算

占用资源最多可启动数目比线程少

CPU密集型计算

多线程Thread(threading)

相比进程更轻量占用资源少

相比进程,多线程只能并发执行,不能利用多CPU(GIL)相比协程启动数目有限制,占用内存资源有线程切换开销

IO密集型计算、同时运行的任务要求不多

多协程Coroutine(asyncio)

内存开销最少,启动协程数量最多

支持库的限制代码实现复杂

IO密集型计算、同时运行的较多任务

6、乐观锁/悲观锁 

    参考:乐观锁与悲观锁的区别 - 知乎

    悲观锁

    总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁

    乐观锁

    总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。

    两种锁的使用场景

    乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。

    悲观锁一般适用于多写的场景下。

    两种锁的实现方式

    乐观锁常见的两种实现方式

    乐观锁一般会使用版本号机制或CAS算法实现。

    悲观锁的实现方式是加锁,加锁既可以是对代码块加锁(如Java的synchronized关键字),也可以是对数据加锁(如MySQL中的排它锁)。

7、coding: 合并两个有序链表

    方法一:递归

    分两种情况:空链表和非空链表

    当其中一个为空链表时,可以直接返回另一个链表

    当两个链表都为非空链表时,可以使用下面方法进行递归

代码如下:

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        if l1 is None:
            return l2
        elif l2 is None:
            return l1
        elif l1.val < l2.val:
            l1.next = self.mergeTwoLists(l1.next,l2)
            return l1
        else:
            l2.next = self.mergeTwoLists(l1,l2.next)
            return l2

    时间复杂度:O(m+n)

    空间复杂度:O(m+n)

    方法二:迭代

    首先要设定一个哨兵节点,可以在最后比较容易地返回合并后的链表。

维护一个 pre 指针,根据 l1和 l2 的大小不断更新 prev 的next 指针。

    代码如下:

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        Newhead = ListNode(-1)
        pre = Newhead
        while l1 and l2:
            if l1.val < l2.val:
                pre.next = l1
                l1 = l1.next
            else:
                pre.next = l2
                l2 = l2.next
            pre = pre.next
        if l1 is None:
            pre.next = l2
        else:
            pre.next = l1
        return Newhead.next

    时间复杂度:O(m+n)

    空间复杂度:O(1)

8、讲下CNN发展史

    1 LeNet:

    广为流传LeNet诞生于1998年,网络结构比较完整,包括卷积层、pooling层、全连接层,这些都是现代CNN网络的基本组件。被认为是CNN的开端。

    2 AlexNet:

    2012年Geoffrey和他学生Alex在ImageNet的竞赛中,刷新了image classification的记录,一举奠定了deep learning 在计算机视觉中的地位。这次竞赛中Alex所用的结构就被称为作为AlexNet。

    对比LeNet,AlexNet加入了:

    (1)非线性激活函数:ReLU;

    (2)防止过拟合的方法:Dropout,Data augmentation。同时,使用多个GPU,LRN归一化层。其主要的优势有:网络扩大(5个卷积层+3个全连接层+1个softmax层);解决过拟合问题(dropout,data augmentation,LRN);多GPU加速计算。

    3 VGG-Net:

    VGG-Net来自 Andrew Zisserman 教授的组 (Oxford),在2014年的 ILSVRC localization and classification 两个问题上分别取得了第一名和第二名,其不同于AlexNet的地方是:VGG-Net使用更多的层,通常有16-19层,而AlexNet只有8层。同时,VGG-Net的所有 convolutional layer 使用同样大小的 convolutional filter,大小为 3 x 3。

    4 GoogLeNet:

    提出的Inception结构是主要的创新点,这是(Network In Network)的结构,即原来的结点也是一个网络。其使用使得之后整个网络结构的宽度和深度都可扩大,能够带来2-3倍的性能提升。

    5 Resnet

    ResNet提出了一种减轻网络训练负担的残差学习框架,这种网络比以前使用过的网络本质上层次更深。其明确地将这层作为输入层相关的学习残差函数,而不是学习未知的函数。在ImageNet数据集用152 层(据说层数已经超过1000==)——比VGG网络深8倍的深度来评估残差网络,但它仍具有较低的复杂度。在2015年大规模视觉识别挑战赛分类任务中赢得了第一。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七月在线

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值