本文 GitHub https://github.com/Jack-Cherish/PythonPark 已收錄,有技術乾貨文章,整理的學習資料,一線大廠面試經驗分享等,歡迎 Star 和 完善。
一、前言
2020 年,魔幻開局。
全球疫情、美國暴亂、印度蝗災,天災人禍接踵不斷。
學生們沒想到,一個寒假,竟然可以放到暑假。
"社畜們"也沒想到,遠程辦公,竟然如此酸爽。
時間,不知不覺中,已經來到了 7 月。
恍然發現,2020 年已經悄然過去了一半。
秋天還沒到,互聯網公司的秋招提前批已悄然來襲。
秋招在即,你準備好了嗎?
無論是學生黨要找實習、找工作,還是工作黨要跳槽、要轉崗。
秋招,都是一個必須把握的機會。
想要找個好工作,都要準備哪些?
回憶自己的秋招,在此分享一些面試經驗。
二、經驗總結
想要找個好工作,都要準備些什麼?
最好地瞭解一個工作崗位需求的方法,就是看 JD(job description)。
比如騰訊的一個視覺算法崗位,這樣寫着:
根據 JD 上的描述,可以有針對性地做一些準備。
其他崗位,也是如此,需要準備什麼,一目瞭然。
本文就以我當初秋招找實習、找工作爲例,分享一下我的算法面經。
我選擇崗位的標準是,找各個公司最適合我的崗位,有就投,沒有就 pass,因此我投遞的崗位有些多樣,主要投遞的崗位:算法工程師、機器學習/深度學習工程師、數據挖掘工程師。
參加過的面試形式有:電話面、視頻面、現場面。
對了,找工作期間,如果你的電話來電有房產中介之類的標識,也要接起來,不要直接掛斷,因爲這沒準就是你面試官的副業(尷尬臉)。
1、認真思考
對於學生,剛開始參加面試,往往不夠自信。例如我第一次參加遠程電話面試的時候,面對面試官的問題,我的第一反應是這個問題在哪看過,網上是怎麼說的,甚至是在哪能找到答案。
當時的我忽略了思考這個問題本身,總想着從何處能找到所謂的正確答案。
這就是準備不充分、不自信、緊張共同造成的結果。
其實,如果認真地思考問題本身,答案並不難想到。
往往掛斷電話後,自己認真思考一番,然後悔恨不已:哇,剛纔怎麼沒有想到!
所以一句話:面對面試官的問題,一定要自己認真思考問題本身,自信一些,大膽說出自己的想法,如果碰到有耐心的面試官,他會一步一步引導你。
2、做好準備
充足的準備很重要,“佛系”隨緣面試不可取。
我們需要根據崗位需求,着重準備以下幾點:自我介紹、數據結構、簡歷項目、崗位需求。
- 自我介紹:這個是最好準備的東西了,根據自己的實際經歷,組織好語言即可。面試官一般剛開始會讓你做一個簡短的自我介紹,以便他快速瀏覽一下你的簡歷。
- 數據結構:數據結構很重要,屬於必過的一關。至少要刷一遍劍指 offer,或者刷一遍 leetcode 的 top100 題目。面試讓寫一道編程題,這都是常規操作。
- 簡歷項目:面試官問的一些問題往往都是針對項目經歷問的,我當初的簡歷上寫了基於嵌入式平臺的目標檢測系統,那麼面試官就會問 YOLO、SSD 的算法原理。YOLO v2 v3 v4 做出了哪些改進?針對自己簡歷上寫的項目,好好想一想可能會問哪些問題。自問自答走一波。
- 崗位需求:這個就需要我們針對崗位要求進行準備了,比如對於深度學習崗位,會問下神經網絡基礎,卷積核是怎麼計算的?卷積層、全連階層都有什麼作用?你會用哪些深度學習框架,可以簡述下使用流程嗎?你認爲深度學習和傳統機器學習本質上有什麼不同?對於這些問題,我們都可以提前準備,面試前一個小時,好好過一遍,會有意想不到的收穫的。
3、時刻準備
有些公司的面試電話說不定什麼時候就打進來了,可能投遞簡歷半個月了,你都忘記了。
本以爲是直接約個面試時間,結果上來直接面試。
當然此時,你可以說下自己現在不方便,可不可以另約時間。
但是心裏總會有疑慮:哇,這樣做,另約時間,到時他會不會忘了?面試晚了,會不會崗位就招滿了?諸如此類的想法。
其實,大多數的時候是沒有問題的,不必有這些想法。當然,爲了完全避免這些憂慮,時刻做好面試準備,保持電話時刻暢通是很有必要的。
4、儘量內推
內推很重要,如果沒有內推,那麼需要走簡歷篩選流程,就是 HR 從簡歷池把你的簡歷撈出來,如果沒有撈出來,也就是沒有相中你的簡歷,很可能你連面試機會都沒有。
但是如果有內推,就會好很多。而且內推可以走提前批,大廠都有這些流程,意思就是不用等後面的統一筆試,直接面試。從哪找內推呢?
- 通過師兄、師姐;
- 招聘網站,例如針對校招的「牛客網」,還有針對校招和社招的「BOSS 直聘」等;
- 社交 APP,比如「脈脈」、「領英」等;
- 通過 QQ 羣,比如一些春招內推羣、秋招內推羣;
- 通過學校的 BBS,對於外校不能訪問的 BBS ,例如「北郵人」,可以找同學借帳號,或者通過鏡像站進入;
- 還有就是公衆號了,現在很多公衆號都在做內推方面的內容。
5、不要着急
這一點我感覺也很重要,別上來就投 BAT 大廠的崗位,先拿非理想公司的崗位,試試水,感受一下面試的氛圍。
不過話說回來,其實可能一些初創公司面試反而會更難,因爲 BAT 這些大廠出題都是有跡可循,而一些初創公司說不定考你什麼,並且可能崗位要求比大廠還高。
學會總結經驗,學會在一次次面試中成長。
6、博客、Github沒那麼重要
好的技術博客,牛的 Github 項目,不一定有加分。
這個完全是看試官怎麼看,面試官感覺好,就有用。如果面試官感覺沒用,那就作用不大。
儘管用處不是很多,但是以技術博客的形式記錄自己的所學,也有助於後續的回顧。
此外,有個好的技術博客或者 Github 項目,會有一些人主動聯繫你,幫你內推。不過,後續的面試情況還是要看你自己的發揮。
7、運氣也很重要
面試也很看運氣,與其說是運氣,不如說是面試技巧。
這個東西挺玄學的,不過它確實存在,比如面試時,問的題目剛好是自己都會的,那麼恭喜,這輪面試你就輕鬆過去了。
不能否認運氣的存在,但也不能全靠運氣,要自身實力過硬纔行。
三、問題彙總
接下來,就總結一下,我在當初面試時,被問到的一些常見問題。
問題總共可分爲七類:數學題、計算機基礎、數據結構、機器學習相關、深度學習相關、項目相關、業務場景。
項目相關的問題,根據每個人的項目經歷而不同,這個需要自行準備了,根據實際情況闡述。
本文主要記錄另外六類問題。
1、數學題
面試的時候偶爾會被問道數學題,這裏也值得準備一下,特別是算法崗。
面試的題型完全看面試官的風格,比如問問泰勒展開、偏導啥的,還有一些五花八門的小智力題。
不過這類考點,考得並不多,十場面試,可能就碰到一場問數學題的。
2、計算機基礎
計算機基礎屬於常考內容。一般都會問一些 linux 基礎,比如常用 linux 指令,平時經常用 linux 的話,這個問題不大。
如果沒有這方面基礎的,就需要提前學一學了。
此外,還會問一下關於你熟悉的計算機語言的基礎知識,比如我說我更熟悉 python ,那麼面試官可能就會問一些關於 python 基礎的問題。
常考問題如下:
1) 進程和線程的區別?
答:進程擁有一個完整的虛擬地址空間,不依賴於線程而獨立存在;反之,線程是進程的一部分,沒有自己的地址空間,與進程內的其他線程一起共享分配給該進程的所有資源。
比如:開個 QQ,開了一個進程;開了迅雷,開了一個進程。在 QQ 的這個進程裏,傳輸文字開一個線程、傳輸語音開了一個線程、彈出對話框又開了一個線程。所以運行某個軟件,相當於開了一個進程。在這個軟件運行的過程裏(在這個進程裏),多個工作支撐的完成 QQ 的運行,那麼這“多個工作”分別有一個線程。所以一個進程管着多個線程。通俗的講:“進程是爹媽,管着衆多的線程兒子”。
2) 爲什麼說 python 的線程是僞線程?
答:在 python 的原始解釋器 CPython 中存在着 GIL(Global Interpreter Lock,全局解釋器鎖),因此在解釋執行 python 代碼時,會產生互斥鎖來限制線程對共享資源的訪問,直到解釋器遇到 I/O 操作或者操作次數達到一定數目時纔會釋放 GIL 。
所以,雖然 CPython 的線程庫直接封裝了系統的原生線程,但 CPython 整體作爲一個進程,同一時間只會有一個線程在跑,其他線程則處於等待狀態。這就造成了即使在多核 CPU 中,多線程也只是做着分時切換而已。
3) python 的 append 和 extend 有什麼區別?
答:extend() 接受一個列表參數,把參數列表的元素添加到列表的尾部,append() 接受一個對象參數,把對象添加到列表的尾部。
例如:
a = [1,2]
b = [1,2,3]
a.append(b)
print(a)
輸出結果爲:
[1, 2, [1, 2, 3]]
而:
a = [1,2]
b = [1,2,3]
a.extend(b)
print(a)
輸出結果爲:
[1, 2, 1, 2, 3]
4) linux 下創建定時任務使用什麼指令?
答:可以使用 crontab 命令。
5) 數據庫 Mysql 和 MongoDB 的區別?
答:Mysql 是關係型數據庫,MongoDB 是文檔型數據庫。MongoDB 佔用空間大,典型的用空間換時間原則的類型。Mysql 相對成熟,MongoDB 較爲年輕。
6) 你知道的加解密算法有哪些?
答:AES(對稱加密)、RSA(非對稱加密)、MD5(Hash算法)等。
3、數據結構
個人感覺數據結構最重要,面試五花八門什麼題都有,但是唯一統一的,就是數據結構基礎。
不考數據結構的情況也有,但這種情況少之又少。
數據結構的考法,也各有不同。有的讓說思路,有的讓在線寫代碼。
所以,複習的方法應該是:審題->思考->表達->碼字。
首先,認真審題,審題很重要。然後組織語言,把自己所想表達清楚。
別小看這一步,一些公司面試都是讓先說解題思路,再寫代碼,甚至是隻需要說思路。
我這有一份當初刷題的記錄,劍指 Offer 系列的刷題筆記,解題思路+代碼都有:
已分門別類整理好,有需要的自取。
地址:https://cuijiahua.com/blog/2018/02/basis_67.html
下面對一些常見題型進行彙總,這些也是我當初面試時,真實被問到的題目以及相關擴展題。
鏈表:
1) 找出單鏈表的倒數第K個元素(僅允許遍歷一遍鏈表)
答:使用指針追趕的方法,定義一個 fast 指針和一個 slow 指針,fast 指針先走 K 步,然後 fast 和slow 同時繼續走。當 fast 指針走到鏈表尾部時,slow 指向的位置就是倒數第 K 個元素。
注意:要考慮鏈表長度應該大於 K 。參考:劍指Offer(十四):鏈表中倒數第k個結點
2) 找出單鏈表的中間元素(僅允許遍歷一遍鏈表)
答:使用指針追趕的方法,定義一個 fast 指針和一個 slow 指針,兩個指針同時走,fast 指針每次走兩步,slow 指針每次走一步。當 fast 指針到鏈表尾部時,slow 指針指向的就是鏈表的中間元素。
3) 判斷單鏈表是否有環?
答:使用指針追趕的方法,定義一個 fast 指針和一個 slow 指針,兩個指針同時走,fast 指針每次走兩步,slow 指針每次走一步。如果有環,則兩者會相遇;如果沒有環,fast 指針會遇到 NULL 退出。
4) 已知單鏈表有環,如何知道環的長度?
答:使用指針追趕的方法,定義一個 fast 指針和一個 slow 指針,兩個指針同時走,fast 指針每次走兩步,slow 指針每次走一步,找到碰撞點。然後使用 slow 指針,從該碰撞點開始遍歷,繞着走一起圈,再次回到該點,所走過的結點數就是環的長度。
5) 如何找到環的入口結點?
答:先使用題 4 的方法,計算出環的長度。然後重新從頭結點開始遍歷,定義定義一個 fast 指針和一個 slow 指針,fast 指針先走 l(環的長度)步,然後兩個指針以相同的速度在鏈表上向前移動,直到它們再次相遇,那麼這個相遇點即爲環的入口結點。
6) 判斷兩個無環單鏈表是否相交?
答:一旦兩個鏈表相交,那麼兩個鏈表從相交節點開始到尾節點一定都是相同的節點。所以,如果他們相交的話,那麼他們最後的一個節點一定是相同的,因此分別遍歷到兩個鏈表的尾部,然後判斷他們是否相同。
7) 如何知道兩個單鏈表(可能有環)是否相交?
答:根據兩個鏈表是否有環來分別處理,若相交這個環屬於兩個鏈表共有
(1)如果兩個鏈表都沒有環,如題 6 所示方法。
(2)一個有環,一個沒環,肯定不相交。
(3)兩個都有環。在 A 鏈表上,使用指針追趕的方法,找到兩個指針碰撞點,之後判斷碰撞點是否在 B 鏈表上。如果在,則相交。
8) 尋找兩個相交鏈表的第一個公共結點。
答:我們也可以先讓把長的鏈表的頭砍掉,讓兩個鏈表長度相同,這樣,同時遍歷也能找到公共結點。此時,時間複雜度 O(m+n),空間複雜度爲 O(MAX(m,n)) 。
9) 反轉鏈表。
答:我們使用三個指針,分別指向當前遍歷到的結點、它的前一個結點以及後一個結點。在遍歷的時候,交換當前結點的尾結點和前一個結點的。
數組:
1) 給定一個數組(非遞減排序),同時給定一個目標數字,找出這個數字在該數組中第一次出現的位置,如果不存在,返回-1。例如[1,3,5,5,5,5,8,9,13,15],輸入5,返回2,輸入8,返回6,輸入18,返回-1。
答:使用二分查找法即可。
# -*-coding:utf-8 -*-
def BinarySearch(input_list, end, value):
if end == 0 or value < input_list[0] or value > input_list[-1]:
return -1
left = 0
right = end - 1
while left <= right:
middle = left + (right - left) // 2
if input_list[middle] >= value:
right = middle - 1
else:
left = middle + 1
return left if left < end else -1
if __name__ == '__main__':
input_list = [1,3,5,5,5,5,8,9,13,15]
target = 5
print(BinarySearch(input_list, len(input_list), target))
運行結果如下圖所示:
2) 給定一個數組,裏面有很多數字(亂序),找出其中最大的 4 個數字。
答:最簡單的辦法就是先排序再找出最大的四數,這種方法時間複雜度過高。一個更好的方法是使用堆排序,即維護一個存儲最大的4個數的最小堆。
解析:這的思想和代碼可以參考《劍指Offer(二十九):最小的K個數》,這裏僅僅做了一個變形。
3) 給定一個整數的數組 nums,返回相加爲 target 的兩個數字的索引值。假設每次輸入都只有一個答案,並且不會使用同一個元素兩次。
答:如果這個數組是已經排序的,可以使用頭指針和尾指針,我們可以定義一個頭指針 left,一個尾指針 right 。left 指針指向元素值+ right 指針指向元素值的和爲 sum,用 sum 和 target 比較。如果sum > target,說明和大了,那麼 right 右指針左移一位,然後重新判斷。反之,如果 sum < target,說明和小了,那麼 left 左指針右移以爲,然後會從新判斷。直到找到 sum=target 的情況。如果沒有排序,可以使用使用哈希表,也就是散列表。
解析:如果沒有排序,這道題就是Leetcode中的一道題。代碼可以參考《Two Sum》。
4) 給定一個字符串,找到最長無重複子字符串。
答:定義兩個變量 longest 和 left ,longest 用於存儲最長子字符串的長度,left 存儲無重複子串左邊的起始位置。然後創建一個哈希表,遍歷整個字符串,如果字符串沒有在哈希表中出現,說明沒有遇到過該字符,則此時計算最長無重複子串,當哈希表中的值小於 left,說明 left 位置更新了,需要重新計算最長無重複子串。每次在哈希表中將當前字符串對應的賦值加 1 。
解析:Leetcode中的一道題。代碼可以參考《Longest Substring Without Repeating Characters》。
二叉樹:
1) 給定任意一棵二叉樹,假設每個結點之間的距離相等,現從任意葉結點,點燃這顆二叉樹,假設結點到結點間的燃燒時間均爲 1s,問需要多久能燒完整顆二叉樹。
答:二叉樹燃燒,需要向父結點遍歷。此外,因爲是燃燒整顆二叉樹,所以結點間應該是擴散式的同時燃燒。因此思路是找到點燃的葉結點到另一個結點的最大距離。
其他:
1) 不使用現成的開根號庫函數,如何實現開平方根的操作?
答:可以使用二分查找法或者牛頓法。
# -*-coding:utf-8 -*-
def sqrt_binary_search(target):
left = 0
right = target
mid = (left + right) / 2
while abs(mid*mid-target) > 0.000001:
if mid*mid == target:
return mid
elif mid*mid > target:
right = mid
else:
left = mid
mid = (left + right) / 2
return mid
def sqrt_newton(target):
k = target
while abs(k*k-target) > 0.000001:
k = 0.5*(k+target/k)
return k
if __name__ == '__main__':
print("二分查找法:",sqrt_binary_search(64))
print("牛頓法:",sqrt_newton(64))
運行結果如下圖所示:
2) 一個自然序列,從0開始,去掉凡是出現8和9的數,請問去掉後的序列中的第2018個數是多少?
答:這道題只要理解題意就好了,怎奈我當時緊張,感覺答的不好,其實事後仔細一想還是蠻簡單的。例如去掉後的序列爲:0,1,2,3,4,5,6,7,10,11,12,13,14,15,16,17,20,21,22,23,24,25,26,27,30,31,32,33,34,35,36,37···。通過數字規律,會發現,其實這個就是10進制轉8進制,第9個數是10,第17個數是20,第25個數是30。那麼,第2018個數是多少?用除八取餘法,得3742。而第2018個數,應該是3742-1=3741。
3) EXCEL中,列序是有規律的。A,B,C···,Z,接着是AA,AB,···,AZ,再接着是BA,BB,···,BZ。這樣一直循環下去,等到有三位的時候就是從AAA開始。請問,第2018個數對應的序列號是多少?
答:這道題還是進制轉換問題,是10進制轉26進制。比如第27個數:27除以26爲1餘1,那麼結果就是AA,第53個數:53除以26爲2餘1,那麼結果就是BA。同理,第2018個數:使用除26取餘法,得到最終結果爲BYP。
4、機器學習
1) 什麼是歸一化,歸一化的作用是什麼?
答:歸一化是將數據變爲(0,1)之間的小數,主要是爲了數據處理方便,把數據映射到0~1範圍之內處理,處理起來可以更加便捷快速。歸一化的作用是把有量綱表達式變爲無量綱表達式,歸一化是一種簡化計算的方式,即將有量綱的表達式,經過變化,化爲無量綱的表達式,成爲純量。同時,提高迭代求解的收斂速度,提高迭代求解的精度。
相應擴展:
深度學習中的歸一化應該怎麼理解?
答:神經網絡學習過程的本質是爲了學習數據分佈,一旦訓練數據與測試數據的分佈不同,那麼網絡的泛化能力也大大降低;另一方面,一旦每批訓練數據的分佈各不相同,那麼網絡就要在每次迭代都去學習適應不同的分佈,這樣會大大降低網絡的訓練速度,這也正是爲什麼我們需要對數據進行歸一化處理的原因。對於深度網絡的訓練是一個複雜的過程,只要網絡的前面幾層發生微小的改變,那麼後面幾層就會被累積放大下去。一旦網絡某一層的輸入數據的分佈發生改變,那麼這一層網絡就需要去適應學習這個新的數據分佈,所以如果訓練過程中,訓練數據的分佈一直在發生變化,那麼將會影響網絡的訓練速度。因此,我們一般會對輸入數據進行"白化"除理,使得它的均值是0,方差是1。
2) 標準化是什麼?
答:數據的標準化是將數據按比例縮放,使之落入一個小的特定區間。由於信用指標體系的各個指標度量單位是不同的,爲了能夠將指標參與評價計算,需要對指標進行規範化處理,通過函數變化將其數值映射到某個數值區間。
相應擴展:
常見的數據歸一化方法有哪些?
答:min-max標準化、z-score標準化等。
對於數據標準化/歸一化的詳細內容,可以參見:
https://blog.csdn.net/pipisorry/article/details/52247379
3) 你最熟悉的機器學習算法是什麼?可以講解下SVM原理嗎?
答:省略若干字。
解析:這部分內容可以參考我的文章《機器學習實戰教程(八):支持向量機原理篇之手撕線性SVM》,我當時面試的時候是先說的線性可分的情況,然後再引入核函數。
4) 在推導公式的時候,要向量化,這是什麼意思?
答:其實就是將多組數據,放到一個矩陣裏,進行矩陣運算。因爲如果是一條一條遍歷計算參數,需要用到for循環,這樣很浪費時間。python的第三方庫提供了很好的矩陣計算支持,我們完全可以把多組數據放到一個矩陣裏,這樣可以實現多組數據同時計算。這個向量化推導,就是根據一條數據計算公式推導出矩陣運算公式,這樣可以方便我們寫代碼。
5) 在邏輯迴歸中,我們使用的是sigmoid函數,知道sigmoid函數吧?
答:知道。
繼續問:那麼tanh函數和它有什麼區別呢?
答:它們的值域不同,sigmoid函數將輸出映射到0~1的範圍內,而tanh函數將輸出映射到-1~1的範圍內。同時,它們過零點的值也不同,sigmoid函數的過零點的值爲0.5,tanh函數過零點的值爲0。當我們更偏向於當激活函數的輸入是0時,輸出也是0的函數時候,就需要使用tanh函數,而非sigmoid函數。
6) SVM和Logistic的區別?
答:(1)SVM不是概率輸出,Logistic Regression是概率輸出。也就是說,當一個新樣本來了,SVM只會告訴你它的分類,而Logistic Regression會告訴你它屬於某類的概率!(2)異常點的魯棒性問題。當訓練樣本中存在異常點時,由於Logistic Regression的lost function中有每一個點的貢獻,所以某種程度上“削弱了”異常點的貢獻。而SVM只需要考慮支持向量,此時支持向量本來就不是很多的情況下,幾個異常點就很有可能極大影響SVM的表現。(3)目標函數不同。Logistic Regression使用cross entropy loss,互熵損失。而SVM使用hinge loss,鉸鏈損失。(4)實際問題中,如果數據量非常大,特徵維度很高,使用SVM搞不定時,還是用Logistic Regression吧,速度更快一些。
7) 常見的損失函數有哪些?
- 鉸鏈損失(Hinge Loss):主要用於支持向量機(SVM) 中;
- 互熵損失 (Cross Entropy Loss,Softmax Loss ):用於Logistic 迴歸與Softmax 分類中;
- 平方損失(Square Loss):主要是最小二乘法(OLS)中;
- 指數損失(Exponential Loss) :主要用於Adaboost 集成學習算法中;
- 其他損失(如0-1損失,絕對值損失)。
參考鏈接:https://blog.csdn.net/u010976453/article/details/78488279
8) GBDT和XGBOOST的區別有哪些?
- 傳統GBDT以CART作爲基分類器,xgboost還支持線性分類器,這個時候xgboost相當於帶L1和L2正則化項的邏輯斯蒂迴歸(分類問題)或者線性迴歸(迴歸問題)。
- 傳統GBDT在優化時只用到一階導數信息,xgboost則對代價函數進行了二階泰勒展開,同時用到了一階和二階導數。順便提一下,xgboost工具支持自定義代價函數,只要函數可一階和二階求導。
- xgboost在代價函數里加入了正則項,用於控制模型的複雜度。正則項裏包含了樹的葉子節點個數、每個葉子節點上輸出的score的L2模的平方和。從Bias-variance tradeoff角度來講,正則項降低了模型的variance,使學習出來的模型更加簡單,防止過擬合,這也是xgboost優於傳統GBDT的一個特性。
- Shrinkage(縮減),相當於學習速率(xgboost中的eta)。xgboost在進行完一次迭代後,會將葉子節點的權重乘上該係數,主要是爲了削弱每棵樹的影響,讓後面有更大的學習空間。實際應用中,一般把eta設置得小一點,然後迭代次數設置得大一點。(補充:傳統GBDT的實現也有學習速率)
- 列抽樣(column subsampling)。xgboost借鑑了隨機森林的做法,支持列抽樣,不僅能降低過擬合,還能減少計算,這也是xgboost異於傳統gbdt的一個特性。
- 對缺失值的處理。對於特徵的值有缺失的樣本,xgboost可以自動學習出它的分裂方向。
- xgboost工具支持並行。boosting不是一種串行的結構嗎?怎麼並行的?注意xgboost的並行不是tree粒度的並行,xgboost也是一次迭代完才能進行下一次迭代的(第t次迭代的代價函數裏包含了前面t-1次迭代的預測值)。xgboost的並行是在特徵粒度上的。我們知道,決策樹的學習最耗時的一個步驟就是對特徵的值進行排序(因爲要確定最佳分割點),xgboost在訓練之前,預先對數據進行了排序,然後保存爲block結構,後面的迭代中重複地使用這個結構,大大減小計算量。這個block結構也使得並行成爲了可能,在進行節點的分裂時,需要計算每個特徵的增益,最終選增益最大的那個特徵去做分裂,那麼各個特徵的增益計算就可以開多線程進行。
- 可並行的近似直方圖算法。樹節點在進行分裂時,我們需要計算每個特徵的每個分割點對應的增益,即用貪心法枚舉所有可能的分割點。當數據無法一次載入內存或者在分佈式情況下,貪心算法效率就會變得很低,所以xgboost還提出了一種可並行的近似直方圖算法,用於高效地生成候選的分割點。
參考自:https://www.zhihu.com/question/41354392
5、深度學習
目標檢測算法相關:
1) 簡述下 YOLO 算法原理?
答:Yolo算法採用一個單獨的CNN模型實現end-to-end的目標檢測,模型參考自GoogleNet,YOLO的CNN網絡將輸入的圖片分割成SxS的網絡,然後每個單元格負責去檢測那些中心點落在該格子內的目標。每個單元格會預測B個邊界框(bounding box)以及邊界框的置信度(confidence score)。所謂置信度其實包含兩個方面,一是這個邊界框含有目標的可能性大小,二是這個邊界框的準確度,邊界框的準確度可以用預測框與實際框(ground truth)的IOU(intersection over union,交併比)來表徵。邊界框的大小與位置可以用4個值來表徵:(x,y,w,h),其中(x,y)是邊界框的中心座標,而(w,h)是邊界框的寬與高。還有一點要注意,中心座標的預測值(x,y)是相對於每個單元格左上角座標點的偏移值,並且單位是相對於單元格大小的,而(w,h)預測值是相對於整個圖片的寬與高的比例。這樣,每個邊界框的預測值實際上包含5個元素:(x,y,w,h,c),其中前4個表徵邊界框的大小與位置,而最後一個值是置信度。每個單元格需要預測 (B*5+C) 個值。如果將輸入圖片劃分爲 S*S 網格,那麼最終預測值爲 S*S*(B*5+C) 大小的張量。對於PASCAL VOC數據,其共有20個類別,如果使用 S=7,B=2 ,那麼最終的預測結果就是 7*7*30大小的張量。
2) 相對於YOLO,YOLO v2有哪些改進?
- 首先,將dropout層去掉,在每個卷積層添加了Batch Normalization,mAP提高了2%;
- 其次,使用高分辨率分類器,將輸入分辨率數據有224*224變爲448*448,mAP提高了4%;
- 第三,引入anchor boxes來預測bounding boxes,去掉網絡中的全連接層。準確率只有小幅度的下降,而召回率則提升了7%,說明可以通過進一步的工作來加強準確率,的確有改進空間;
- 第四,使用維度聚類,本文使用K-means聚類方法訓練bounding boxes,可以自行找到更好的boxes寬高維度;同時使用直接位置預測(Direct lacation prediction),將定位預測值歸一化,使參數更容易得到學習,模型更加穩定。作者使用Dimension Clusters和Direct location prediction這兩項anchor boxes改進方法,mAP獲得了5%的提升。
- 第五,增加細粒度特徵(Fine-Grained Feature),是模型獲得多尺度的適應性,簡單添加了一個轉移層( passthrough layer),這一層要把淺層特徵圖(分辨率爲26 * 26,是底層分辨率4倍)連接到深層特徵圖。這樣做相當於做了一次特徵融合,有利於檢測小目標。
- 最後,多尺度訓練(Multi-Scale Training),方法就是幾次迭代之後就會微調網絡,每過10次訓練(10 epoch),就會隨機選擇新的圖片尺寸。YOLO網絡使用的降採樣參數爲32,那麼就使用32的倍數進行尺度池化{320,352,…,608}。最終最小的尺寸爲320 * 320,最大的尺寸爲608 * 608。接着按照輸入尺寸調整網絡進行訓練。這種機制使得網絡可以更好地預測不同尺寸的圖片,意味着同一個網絡可以進行不同分辨率的檢測任務,在小尺寸圖片上YOLOv2運行更快,在速度和精度上達到了平衡。
3) 深度學習方法與傳統機器學習方法的區別是什麼?
答:機器學習包括深度學習,深度學習是使用卷積層學習特徵,而非像機器學習那樣需要人爲提取特徵,深度學習可以自行學習到更深層次的特徵。機器學習方法的各個公式有數學理論推導支持,深度學習方法就像一個黑匣子,缺少數學理論支持。
4) YOLO的損失函數是什麼?
答:YOLO算法將目標檢測看成迴歸問題,採用的是均方差損失函數。公式如下圖所示:
6、業務場景
種這題目也是常出題目,會給定你一個場景來提問。
1) 如果給了你很多數據,這些數據已經標註好,即已經做好分類,現在讓你訓練出一個模型,用於區分新來的數據屬於哪一類,你需要怎麼做呢?可以說下詳細的流程嗎?
答:首先這是一個分類問題,首先應該想到的是可以嘗試使用常用的分類算法,例如樸素貝葉斯、決策樹或者SVM。拿到數據之後,做的第一件事就是特徵工程。然後將數據分類兩部分,一部分用於訓練,另一部分用於測試,即分爲訓練集和測試集,不混用。其實,使用什麼分類算法倒是其次,重要在於選好特徵,對於給定的特徵,需要做一些過濾,比如一些干擾數據,如果對於結果影響很大,可以嘗試捨棄這些數據。除此之外,看看是否需要對數據進行歸一化處理,將數據無量綱化。然後對已經處理好的特徵,送入分類算法中,讓其學習。最後,可以通過查看測試集的預測準確度,對一些算法必要參數進行優化調試。
解析:我當時差不多就是這麼回答的,只要有的說,讓面試官認爲你做過相關工作即可。
2) 如果給你1億個數據,讓你找出其中第 1000 大的數據,你會怎麼做?我們先不考慮多進程和多線程,也不考慮數據庫,如何在算法方面給出思路呢?
答:可以使用堆排序,創建一個存儲1000個數據的小根堆。先將1億個數據的前1000個數據放入這個小根堆中,然後繼續遍歷,對於新插入的數據,需要與小根堆的最小值進行比較,如果待插入的數據比這個最小值還小,那麼不插入,如果比這個最小值大,那麼就插入該數,並重新調整小根堆,隨後繼續使用此方法遍歷整個數據。遍歷一次數據後,就得到了前1000大的數據,然後輸出小根堆的最小值,即根值,即可得到第1000大的數據。
PS:還有一種思路,有就是利用 MapReduce,實際工作中,非常常用的工具。
四、總結
- 本文總結的題目,都是我當初剛參加工作面試遇到的一些常規題目,例如 YOLO 系列算法,現在已經出了 YOLO v3、YOLO v4 ,有新算法就得看,需要跟進最新的進展。
- 臨陣磨槍,不快也光。面試前,看一看自己的筆記,沒準面試的時候正好碰到。
-
好好準備,祝在座的各位,人人都是 offer 收割機。