目錄
1.1 SGD(Stochastic Gradient Descent)
1.2 BGD(Batch Gradient Descent)
1.3 MBGD(Mini-Batch Gradient Descent)
1.5 Adagrad(Adaptive gradient algorithm)
1.8 Adam(Adaptive Moment Estimation)
3.LSTM裏面爲什麼有些激活函數用sigmoid,有些用tanh?
6. 給出二叉樹的前序遍歷(preorder)和中序遍歷(inorder),重建該二叉樹:
part 1.
1. 介紹一下幾種優化器
在機器學習與深度學習中,主要應用於梯度下降。如,傳統的優化器主要結合數據集,通過變化單次循環所採用的數據量的大小對梯度下降進行控制;非傳統的優化器則進一步集合數據集的特點和模型的訓練時間,以不同的形式變化梯度下降的學習率。
常見的優化器有SGD、BGD、MBGD、Momentum、Adagrad、RMSprop、Adam。
梯度下降的原理:
其中, 爲學習率, 爲更新前的參數, 爲更新後的參數, 爲當前參數的導數。
1.1 SGD(Stochastic Gradient Descent)
SGD隨機梯度下降參數更新原則:單條數據就可對參數進行一次更新。
優點:參數更新速度快。
缺點:由於每次參數更新時採用的數據量小,造成梯度更新時震盪幅度大,但大多數情況是向着梯度減小的方向。
for n in n_epochs:
for data in train_dataset:
#對參數進行一次更新
1.2 BGD(Batch Gradient Descent)
BGD批量梯度下降參數更新原則:所有數據都參與梯度的每一次更新(一個batch中每個參數需要更新的梯度取均值作爲更新值)。
優點:由於每次參數更新時採用的數據量大,所以梯度更新時比較平滑。
缺點:由於參數更新時需要的數據量大,造成參數更新速度慢。
for n in n_epochs:
for data in train_dataset:
#計算每個參數所有梯度的均值作爲一次更新的梯度,對參數進行一次更新
1.3 MBGD(Mini-Batch Gradient Descent)
MBGD小批量梯度參數更新原則:只有所有數據的一部分進行參數的更新。
優點:相比於SGD,由於參與梯度更新的數據量大,所以梯度更新時相對平滑;相比於BGD,參與梯度更新的數據量小,參數更新速度更快一些。
缺點:沒有考慮到數據集的稀疏度和模型的訓練時間對參數更新的影響。
n=0
while n <= n_epochs:
for minibatch_traindataset in train_dataset:
if n <= n_epochs:
n+=1
for i in minibatch_traindataset:
#計算每個參數更新的梯度的均值作爲一次更新的梯度進行參數更新
else:break
1.4 Momentum
Momentum解決的問題是:SGD梯度下降時的震盪問題。
Momentum參數更新原則:通過引入 ,加速SGD,並且抑制震盪。(MBGD是通過小批量數據來平滑梯度更新,方法不同而已)
更新公式:
超參數設定值: 一般取 0.9 左右。
優點:通過加入 ,使得梯度方向不變的維度上速度變快,梯度方向改變的維度上更新速度變慢,這樣就可以加快收斂並減小震盪。
缺點:梯度方向不變時,參數更新速度會越來越快,但是在梯度方向改變時,梯度更新速度不能及時減小導致適應性差。
1.5 Adagrad(Adaptive gradient algorithm)
Adagrad解決的問題:解決不能根據參數重要性而對不同參數進行不同程度更新問題。
Adagrad參數更新原則:對低頻的參數做較大的更新,對高頻的參數做較小的更新。
更新公式:
其中,g爲t時刻 的梯度; , 是個對角矩陣, 元素就是t時刻參數 的梯度平方和。
如果是普通的SGD,那麼 在每一時刻的梯度更新公式爲:
,超參數 選取0.01 。
優點:減少了學習率的手動調節。
缺點:分母會不斷積累,導致學習率會收縮並最終變得很小。
1.6 Adadelta
Adadelta解決的問題:解決Adagrad分母不斷積累,導致學習率收縮變得非常小的問題。
Adadelta參數更新原則:和Adagrad相比,就是分母的 換成了過去的梯度平方的衰減平均值,指數衰減平均值。
這個分母相當於梯度的均方根(root mean squared,RMS),在數據統計分析中,將所有值平方求和,求其均值,再開平方,就得到均方根值,所以可以用RMS簡寫:
其中,E的計算公式如下, t時刻的依賴於前一時刻的平均和當前的梯度:
此外,還將學習率 換成了 ,這樣甚至都不需要提前設定學習率,更新公式爲:
,超參數 一般設定爲0.9 。
優點:減少了學習率的手動調節。
1.7 RMSprop
RMSprop解決的問題:RMSProp和Adadelta 都是爲了解決Adagrad學習率急劇下降問題。
參數更新原則:RMSprop與Adadelta第一種形式相同:使用的是指數加權平均,旨在消除梯度下降中的擺動,與Momentum的效果一樣,某一維度的導數比較大,則指數加權平均就大,某一維度的導數比較小,則其指數加權平均就小,這樣就保證了各維度導數都在一個量級,進而減少了擺動,允許使用一個較大的學習率 。
更新公式:
1.8 Adam(Adaptive Moment Estimation)
Adam解決的問題:這個算法是另一種計算每個參數的自適應學習率的方法。
Adam參數更新原則:相當於RMSprop + Momentum。除了像Adadelt 和RMSprop一樣存儲了過去梯度的平方 的指數衰減平均值,也像Momentum一樣保持了過去梯度 的指數衰減平均值:
梯度更新公式:
2. LSTM裏面有哪些門,爲什麼用這些門?
- 遺忘門:將細胞狀態中的信息選擇性遺忘。
- 輸入門:將新的信息選擇性的記錄到細胞狀態中。
- 輸出門:當前細胞的信息保存到隱層中。
3.LSTM裏面爲什麼有些激活函數用sigmoid,有些用tanh?
- sigmoid用在LSTM的三個門裏,作用在前一個狀態和輸出上,主要功能是讓神經元對過去輸入和前一個狀態的信息選擇性輸入,它的輸出範圍是(0,1),0是丟棄,1是保留;
- tanh是用在後一個狀態和輸出上,是對數據的處理。它的輸出範圍是(-1,1),功能是對哪些輸出信息放大,對哪些輸出信息縮小。
4. Bert中的位置向量作用是什麼?有哪些生成方式?
1.位置向量的作用是表示每個單詞token 距離目標單詞的遠近,每個token 的位置向量表示形式可以是one-hot形式,將它們合起來就是一個隨機矩陣;也可以說隨機id形式。
2.論文中Bert的位置向量是通過餘弦函數生成,位置向量的維度和word embedding維度相同都是512維,其中位置向量的前一半通過正弦生成,後一半(後面256的長度)是通過餘弦生成的。
part 2.
1. 淺copy和深copy的概念
在Python中對象的賦值其實就是對象的引用。當創建一個對象,並把它賦值給另外一個對象時,Python並沒有拷貝這個對象,只是拷貝了這個對象的引用。
淺copy:拷貝了最外圍的對象本身,內部的元素只是拷貝了一個引用;也就是把對象複製一遍,但是對象中引用的其他對象並不複製。比如,對於嵌套數組的淺拷貝,僅僅是拷貝外圍數組元素對象,內部數組對象並不拷貝,僅拷貝引用。
深copy:外圍和內部元素都進行拷貝對象本身,而不是引用。
# ---拷貝---
alist=[1, 2, 3, ['a', 'b']]
b=alist
print( b)
[1, 2, 3, ['a', 'b']]
alist.append(5)
print (alist)
print(b)
[1, 2, 3, ['a', 'b'], 5]
[1, 2, 3, ['a', 'b'], 5]
#---淺拷貝---沒有拷貝子對象,所以原始數據改變,子對象會改變
# 總的來說就是,淺拷貝之後,僅僅子對象與原始數據有關係
import copy
alist=[1, 2, 3, ['a', 'b'], 5]
c=copy.copy(alist)
alist.append(5)
print(alist,c)
#輸出
[1, 2, 3, ['a', 'b'], 5]
[1, 2, 3, ['a', 'b']]
alist[3].append('ccc')
print(alist,c)
#輸出
[1, 2, 3, ['a', 'b', 'cccc'], 5]
[1, 2, 3, ['a', 'b', 'cccc']] 裏面的子對象被改變了
# ---深拷貝---包含對象裏面自對象的拷貝,所以原始對象的改變並不會造成深拷貝里面任何子元素的改變
# 總的來說就是,深拷貝之後,與原始數據已經沒有關係了
[1, 2, 3, ['a', 'b'], 5]
d=copy.deepcopy(alist)
alist.append(5)
print(alist,d)
#輸出
[1, 2, 3, ['a', 'b'], 5]
[1, 2, 3, ['a', 'b']]始終沒有改變
alist[3].append('ccc')
print(alist,d)
#輸出:
[1, 2, 3, ['a', 'b', 'ccccc'], 5]
[1, 2, 3, ['a', 'b']] 始終沒有改變
2. Python中的self關鍵字
在Python中規定,函數的第一個參數是實例對象本身,並且約定俗成,把其名字寫成self。作用類似於Java中的this關鍵字,表達當前類的對象,可以調用當前類的屬性和方法。
3. Python中類的繼承
面向對象編程的一個主要功能是繼承。繼承指的是,它可以使用現有類的所有功能,並在無需重寫編寫現有類的情況下對這些功能進行擴展。
通過繼承創建的類稱爲子類或派生類,被繼承的類稱爲基類或者父類,繼承的過程就是從一般到特殊的過程。在某些面嚮對象語言中,一個子類可以繼承多個基類,但一般情況下一個子類只能有一個基類。
繼承的實現方式有兩種:實現繼承和接口繼承:
- 實現繼承指的是使用基類的屬性和方法而無需額外編碼的能力。
- 接口繼承指的是僅使用屬性和方法的名稱,但是子類必須提供實現的能力(子類重構父類方法)。
4. 完全二叉樹的概念
二叉樹:樹中每個節點最多有兩個子節點
二叉搜索樹:對於樹中任何節點,如果其左子節點不爲空,那麼該節點的value值永遠>=其左子節點;如果其右子節點不爲空,那麼該節點值永遠<=其右子節點值。
滿二叉樹:樹中除了葉子節點外,每個節點有2個子節點。
完全二叉樹:在滿足滿二叉樹的性質後,最後一層的葉子節點均需在最左邊
完美二叉樹:滿足完全二叉樹的性質,樹的葉子節點均在最後一層。
5. 單鏈表與順序表的區別
順序表和鏈表是非常基本的數據結構,它們被統稱爲線性表,順序表和鏈表是線性表的不同存儲結構。
順序表的特點是:
- 長度固定,必須在分配內存之前固定數組的長度;
- 存儲空間連續,即允許元素的隨機訪問;
- 存儲密度大,內存中存儲的全部是數據元素;、
- 要訪問特定元素,可以使用索引訪問;
- 要想在順序表插入或刪除一個元素,都涉及到之後所有元素的移動。
而單鏈表是隻包含指向下一個節點的指針,只能單向遍歷,它的特點是:
- 長度不固定,可以任意增刪;
- 存儲空間不連續,數據元素之間使用指針相連,每個數據元素只能訪問周圍的一個元素(區別於雙鏈表);
- 存儲密度小,因爲每個數據元素,都需要額外存儲一個指向下一個元素的指針;
- 要訪問特定元素,只能從鏈表頭開始,遍歷到該元素(順序表只用索引查找即可)
- 在特定元素之後插入或刪除元素,不需要移動其他元素。
6. 給出二叉樹的前序遍歷(preorder)和中序遍歷(inorder),重建該二叉樹:
思路:使用遞歸,遞歸的出口就是inorder爲空;首先從preorder中找到根節點,然後在inorder中找到根節點的索引index;在 inorder中,index之前的左子樹的節點,後面就是右子樹的節點
class Solution:
def buildTree(self,preorder,inorder):
if not inorder:return None
root=TreeNode(preorder.pop(0))
index=inorder.index(root.val)
root.left=self.buildTree(preorder,inorder[:index])
root.right=self.buildTree(preorder,inorder[index+1:])
return root
7.反轉一個鏈表,並返回頭結點
class Solution:
def reverseList(self, head):
if not head or not head.next:return None
prev=None
cur=head
while cur:
tmp=cur.next
cur.next=prev
prev=cur
cur=tmp
return prev