oppo哲库-音频算法工程师面经

面试内容要求保密,所以除编码题不会涉及具体内容,整体面试体验不是很好,大部分原因是我菜。从交流过程中发现他们想要的是可以做底层开发的人,偏向工业落地,希望应聘者既可以做理论研究,同时也要能进行工业化部署,而不是像我这种浮于表面研究而不考虑落地的研究生(身边大多数人的毛病,只看效果,不考虑实施,学界和工业界的割裂)。
先说好的地方,本人提前半小时上线(个人习惯),面试官提前十五分钟上线,好评。面试开始是自我介绍,其后聊我提到的论文,中间有讨论,面试官提出了很多见解,有思想的碰撞,真心话,受益匪浅,对自己课题研究有了新的思考。
然后不好的地方,从其举止上感受到不被尊重,坐姿有些懒散,脸上无表情,说话声音时大时小,而且多数时候否定我的观点而不举证,让人有一种被训话的感觉,当然可能是工作很忙,加班之类的比较累导致精神状态不好。
最后聊不下去了出了道编程题:
# 用python实现一个二维卷积,其中输入和输出均为四维tensor  y=x*h
# x: [batch, channel_in, height, width]
# h: [channel_in, channel_out, k_height, k_width]
# y: [batch, channel_out, height, width]
我开始以为是写个小算法,但看到题之后愣了一下,然后问面试官是否是要求我使用python在不依赖第三方库的情况下实现二维卷积,得到了肯定答复。
我笑了一下,告诉面试官这题我不会做(其实有思路,但不能熟练的写出来,也不能保证正确,尤其是特征通道处理部分没有看过详解)。面试官说难道不尝试一下吗?我以能力有限为由拒绝了。
反问环节就项目内容和公司发展问了两个问题,面试官耐心的做了解答,而且给了一些建议,很受用。

当天晚上有事,第二天对这次笔试做了复盘,并且做了反思。
首先是对编码题进行了尝试,写了一个半小时,才写出来,没有用实例测试,代码如下,希望可以得到大佬指导。采用将高维矩阵展开成一维相乘的形式,输入通道方面的处理使用的是取平均的方法,这个地方需要看看原理。代码比较冗长,因为很多功能list实现起来很麻烦,如果能用numpy的话可以精简很多。代码风格有些混乱,将就。
其次,自己对这次面试的处理并不好,最后心态发生了变化,发现对方岗位与自己不适合之后想立即结束面试,并且拒绝做编程题目,这是面试时不应该出现的,至少应该与面试官沟通编码思路,并表示无法在有限时间完成编码,希望朋友们引以为戒。
import random
from typing import List


class conv2d(object):
    def __init__(self, in_channals: int, out_channals: int, kernel_size: int, stride: int = 1, dialtion: int = 0):
        # 没实现padding,这个比较简单
        self.in_channals = in_channals
        self.out_channals = out_channals
        self.kernel_size = kernel_size
        self.stride = stride
        self.dialtion = dialtion
        self.kernel_ = (self.dialtion + 1) * self.kernel_size - self.dialtion
        self.kernel = [[self._make_kernel() for k in range(in_channals)] for l in range(out_channals)]  # 核大小是[out_channals, in_channals, kernel_size, kernel_size]

    def _make_kernel(self):
        kernel = []
        for j in range(self.kernel_size):
            rows = []
            for i in range(self.kernel_size):
                rows.append(random.random())
                if i < self.kernel_size-1 and self.dialtion != 0:
                    zeros = [0 for l in range(self.dialtion)]
                    rows += zeros
            kernel.append(rows)
            if j < self.kernel_size-1 and self.dialtion != 0:
                for k in range(self.dialtion):
                    zeros = [0 for k in range(self.kernel_)]
                    kernel.append(zeros)
        return kernel

    def _make_kernel_mat(self, i, j, feature_map_size):
        kernel_mat = []
        for col_ in range((feature_map_size - self.kernel_)//self.stride+1):
            kernel_head = [0 for _ in range(col_*feature_map_size)]
            for row_ in range((feature_map_size - self.kernel_)//self.stride+1):
                kernel = kernel_head[:]
                for kernel_row in self.kernel[i][j]:
                    kernel += [0 for _ in range(row_*self.stride)] + kernel_row + [0 for _ in range(feature_map_size - row_*self.stride - self.kernel_)]
                kernel += [0 for _ in range(feature_map_size**2 - len(kernel))]
                kernel_mat.append(kernel)
        return kernel_mat


    def _matrix_mul(self, feature_maps, kernel_mats):
        result = []
        in_dim = len(feature_maps)
        for i in range(in_dim):
            feature_map = []
            for maps in feature_maps[i]:
                feature_map += maps
            for idx_, kernel in enumerate(kernel_mats[i]):
                res_ = 0
                for a, b in zip(feature_map, kernel):
                    res_ += (a*b)
                if i == 0:
                    result.append(res_)
                else:
                    result[idx_] += res_
        for i in range(len(result)):
            result[i] /= in_dim
        out_dim = int(len(result) ** 0.5)
        result = [result[:out_dim], result[out_dim:]]
        return result

    def forward(self, inputs: List[List[List[List[int]]]]):
        # 没有写维度检验
        batch_size = len(inputs)
        in_channel = len(inputs[0])
        feature_map_size = [len(inputs[0][0]), len(inputs[0][0][0])]

        # 写了要求特征图是方形,是为了方便写原理,可以随意,需要修改循环的中止条件
        assert self.in_channals == in_channel, 'in_channals must be equal'
        assert feature_map_size[0] == feature_map_size[1] and feature_map_size[0] >= self.kernel_, 'feature_map size must larger than (dialtion * kernel_size - dialtion)'
        kernel_mats = [[self._make_kernel_mat(i, j, feature_map_size[0]) for j in range(self.in_channals)] for i in range(self.out_channals)]
        outputs = []
        for i in range(batch_size):
            output = []
            for j in range(self.out_channals):
                output.append(self._matrix_mul(inputs[i], kernel_mats[j]))
            outputs.append(output)
        return outputs


net = conv2d(in_channals=1, out_channals=1, kernel_size=3, dialtion=0)
inputs = [[[[random.random() for _ in range(4)] for _ in range(4)] for _ in range(1)] for _ in range(3)]
outputs = net.forward(inputs)

#OPPO##面经##校招##算法工程师#
全部评论
上周我也面了zeku,全程被吊打😂😂
1 回复 分享
发布于 2021-07-26 11:45
前天哲库一面,我擦,问了好多C语言底层,堆栈、操作系统线程并发。感觉不熟悉C是很难面过去。我以为凉了结果今天收到二面通知。非常开心
1 回复 分享
发布于 2022-04-14 14:02
很好的面经
点赞 回复 分享
发布于 2021-07-24 22:43
想问楼主哲库面试结果什么时候通知呀?我也是上周面的,难。。。
点赞 回复 分享
发布于 2021-07-26 17:19
全完实现2d卷积啊 代码量这么大还考。。
点赞 回复 分享
发布于 2021-08-04 16:51
想问一下lz最终去哪了hhh
点赞 回复 分享
发布于 2021-09-30 15:24

相关推荐

今天 17:51
南昌大学 Java
点赞 评论 收藏
分享
有个问题,现在大家都在劝退客户端,客户端岗位也很稀缺,那为什么不去呢,就算干一两年被裁了也可以社招进去吧,人不是同样很少,社招岗位也户会急招人的吧😋😋😋
Runquicky:在前三年客户端还好,主要是因为大厂都在扩张状态。这两年已经不建议了,大厂都只剩维护的需求了,没新功能,自然也没那么多需求。新人进去一两年被裁会怎样很难说了。
点赞 评论 收藏
分享
20 43 评论
分享
牛客网
牛客企业服务