格物钛:2021秋招 Python开发岗(偏算法,实习)
视频面。
问题
项目相关。
-
Python中装饰器的本质。
装饰器的本质是一个接收一个方法为参数的方法,在该方法中定义一个包装后的方法,对被装饰方法执行前、后进行额外的处理。
如:
from functools import wraps # define the decorator def f(func): @wraps(func) def g(): print('before') func() print('after') return g @f def func(): print('test') func()
在装饰器
f
中定义了包装后的方法g
,在g
中定义被包装方法func
执行前后的相关处理(输出'before'
和'after'
),在使用@f
对func
进行装饰后,实际运行的输出为:before
test
after -
__new__
和__init__
的执行顺序与区别。__new__
方法用于创建类的对象,是严格意义上的构造函数;__init__
方法用于对__new__
创建的对象进行初始化,如设置对象的属性等。在执行顺序上,先执行
__new__
再执行__init__
。区别方面,
__init__
的第一个参数是self
,而__new__
第一个参数是cls
类型,这也反映了前者对已建立的对象进行属性的设置,后者通过给定的类型进行实例对象的构造。
-
如何重载加法运算符。
重写
__add__
方法。 -
介绍python中的基本数据类型。
int
、float
、str
、dict
、set
、list
、map
、complex
(复数)。 -
深度学习中如何处理过拟合。
从网络结构层次的角度,可以采用残差连接的方式,提供降低模型复杂度的可能;
从正向传播的角度,可以使用
Dropout
的方式,每次丢弃一部分特征,防止参数过分依赖训练数据,增加参数对数据集的泛化能力;从反向传播的角度,可以通过正则化的方式,每一次计算loss时增加一个参数相关的惩罚项,缩放参数值使输出的区间更为稳定合理;
从数据处理的角度,通过进行
shuffle
打乱数据的顺序、对数据进行增广(增加噪音、变换等),避免参数对数据的依赖,提高泛化能力;从训练的角度,可以考虑使用
EarlyStopping
在模型持续优化一定Epoch
后便提前停止训练;
-
PyTorch
中继承torch.utils.data.Dataset
主要需要重写的方法。最重要的是重写
__getitem__(self, index)
方法,用于获取指定位置的数据样本。 -
深度学习中常用的正则化有哪些。
常用的正则化方式一般有两种: 和 正则化,又分别称为 Lasso 回归和 Ridge 回归。
此外,也有相关的正则化层,用于对神经网络层输入的特征进行正则化,如
LayerNorm
、BatchNorm
等。 -
L1正则化与L2正则化的区别。
L1正则化与L2正则化都是在计算损失反向传播的基础上额外增加一个和参数有关的惩罚项
公式:对于已经计算的损失loss以、参数w以及正则项系数 (手动设置),有:
L1对参数取绝对值之和,L2则是平方和。这个差异最形象的解释是,对两个参数的情况下绘制等值线,其最优参数在正则项曲线与损失曲线的交点处(带约束的优化),而L1的正则项曲线严格意义上并不是“曲线”而是一个“菱形”,而L2的曲线则是一个圆形(图片见相关参考),因此:
- L1正则的优化结果容易在坐标轴上与损失曲线相交(部分参数为0的情况),得到使模型更加稀疏(降低了模型的复杂度)的效果,因此在一定程度上也能防止过拟合;
- L2正则的优化结果容易在非坐标轴上与损失曲线相交,使得各个参数均缩放到一个较小的值,这样模型即使输入波动较大其输出也会稳定在一定的、比较合理范围内,从而有更强的抗干扰能力,达到防止过拟合的效果。
参考:
-
一行代码计算 中的奇数平方和。
sum([i**2 for i in range(n) if i % 2 == 1])
-
编程题:合并两个有序序列
- 解法:
- 创建一个新的
list
,遍历两个有序序列并按序将其中的数放到新建的list
中; - 将较短的序列插入到较长的序列中,建议从后往前遍历实现,不容易出现插入下标的问题。
- 创建一个新的
- 讨论:使用方法1时如果一个序列已经处理完了,剩下的一个序列如何处理效率更高:
- 使用
for
或者while
直接遍历复杂度是 ; - 对剩下的序列切片并使用
list.extend
或者+
进行合并,虽然代码层面没有循环了,但是切片操作本身返回的也是一个副本,内部还是有一个 的操作。 - 最优的操作应该是第2种解法。
- 使用
- 解法:
-
参数传递与深浅拷贝
判断如下两个代码的输出并解释:
def f1(l: list): l = [4,5,6] a = [1,2,3] f1(a) print(a)
这里
f1
传入的l
指向的是a
的一个副本,a
内部只包含基本数据类型,在方法中修改的是l
所指向的位置,并不影响a
,输出[1,2,3]
。def f2(l: list): l2 = l.copy() l2[0][1] = 22 a = [[1,2,3], 2] f2(a) print(a)
f2
中传入的也是a
的一个副本,但是由于a
中包含了其他对象,这个副本本身是浅拷贝的,且在函数内部也进行了一次浅拷贝,即l[0]
与l2[0]
都指向a[0]
,所以这里的修改是会影响到a
的,输出[[1,22,3],2]
。
总结
面试涉及到的问题主要包含如下方面:
- Python基础、底层;
- 深度学习基础、优化技巧;
- 算法设计与问题分析;
均需要继续加强知识积累。