AI => DeepLearning+Metrics(Ng)

前言

看Andrew Ng視頻,總結的學習心得。
雖然本篇文章可能不是那麼細緻入微,甚至可能有了解誤差。
可是,我喜歡用更直白的方式去理解知識。git

數據劃分

傳統機器學習數據的劃分

傳統機器學習通常都是小規模數據(幾萬條)網絡

那麼能夠  訓練集:驗證集:測試集 = 6:2:2

如果大規模深度學習通常都是大規模數據(幾百萬條)app

訓練集: 驗證機:測試集 = 9:0.5:0.5

劃分 驗證集 能夠過早的爲咱們預測 指標和精度框架

誤差 與 方差

高誤差: 訓練集和測試集 loss 都比較高 (比人預測的loss高不少) (欠擬合)
高方差: 訓練集Loss低, 測試集 Loss高。 因此訓練集和測試集 loss相差太大, 也成爲(過擬合)dom

防止過擬合的幾種方法

損失函數 (懲罰項係數) 正則化(regularization)

可分兩種 (L1正則化懲罰 和 L2正則化懲罰)下面只以 L2爲例,L2用的也是比較多的)
正則化係數公式:機器學習

loss = ...
new_loss = loss + (λ/2m) * w^2
w = w - learning_rate * 梯度

上面公式的單調變換解釋:函數

求梯度的時候 λ越大, new_loss越大, 求得的梯度越大(正比)
w 減去的值就越大。   w變得就越小。
w 越小, 必定程度上特徵就衰減了許多。  就有效的放置了過擬合哦

對應API(有兩種方式):學習

L1 = keras.regularizers.l2(0.01)   # TF2 看成 keras 的 Layers定義來使用
L1 = tf.nn.l2_loss(w_b)            # 看到裏面傳遞 w和b了吧, 這種是偏手動方式實現的API

若是你想使用手撕實現,下面有個例子(僞代碼):測試

for
    with tf.GradientTape() as tape:
        ...
        loss_reg = [tf.nn.l2_loss(w_b) for w_b in model.trainable_variables] # [w1,b1,w2,b2]
        print(tf.reduce_sum(loss_reg))        # tf.Tensor(2.98585, shape=(), dtype=float32) # 就是這個形狀
        loss = loss + loss_reg

另外一種正則化方式(regularization) -- DropOut

"隨機"剪枝, 略, TF框架一步到位

還有一種防止過擬合的方式(數據加強)

防止過擬合的另外一種方式,就是須要的大量的數據來支撐,那麼數據就那麼點,怎麼辦?優化

數據加強( 其原理就是增大樣本數量,小幅度翻轉等) 某種程度上,就是增長了樣本。

最後一種防止過擬合的方法 (earlystopping )

earlystopping (tf.keras.callback模塊中,有這個 callback函數,註釋部分有解釋)

callbacks = [
    keras.callbacks.TensorBoard(logdir),
    keras.callbacks.ModelCheckpoint(output_model_file, save_best_only=True),
    # 在這裏
    keras.callbacks.EarlyStopping(patience=5, min_delta=1e-3)
    # 驗證集,每次都會提高,若是提高不動了,小於這個min_delta閾值,則會耐性等待5次。
    # 5次事後,要是還提高這麼點。就提早結束。
]

數據預處理

標準化 和 歸一化能起到什麼做用:

作了標準化 和 歸一化 能夠 讓函數收斂的 更快速(梯度降低的快)
參考 (圓形降低的快, 和 橢圓降低的慢)

其次,在神經網絡中,BN層還有額外的效果。每層網絡的不一樣參數,可能會致使"數據分佈"散亂、變形
所以,BN能夠有效 防止數據分佈變形。 (其實說白了也是"加速函數收斂" ,加速NN訓練)

注意點

訓練集 和 測試集的樣本特徵 ("要麼都作處理,要麼都不作處理")(就是相同待遇的意思。。。)
專業點叫作 :"保證訓練集 和 測試集 相同分佈"

數據 隨機分佈有什麼影響(Andrew ng解釋)?

假如訓練集的數據分佈 訓練的目標是正中靶心。
而預測時,假如你的預測集數據分佈 和 訓練集數據分佈的不一樣。
那麼極可能會 預測集 預測的時候(是另外一個靶心)。
因此你訓練的再好,到預測集的靶子上 也是脫靶。。。
因此 訓練集 和 測試集 的 相同分佈很重要

數據預處理大致分2類:

1. 中心化處理
2. 縮放處理

zero-centered (中心化處理)

平移 --- 減去固定值

scale (縮放處理)

歸一化:除以 最大值-最小值
標準化:除以 標準差

下面的操做都是經過 中心化處理+縮放處理 聯合組成的

normalization(歸一化) sklearn那裏也提到過

目標:

將數據收斂到 [0,1]

公式

x - min(x)          # 中心化
------------------
max(x) - min(x)            # 縮放處理

StandardScaler(標準化)

目標:

將數據轉化爲標準 正態分佈(均值爲0,方差爲1)

公式:

x - 平均值
-----------------
    標準差

標準化 和 歸一化 選哪一個???

視覺圖片: 歸一化
其餘: 標準化較好

數據集不足怎麼辦?

我本身也遇到過這樣的問題。
我以前作一個QA聊天機器人時。 數據是百度知道的爬的。
可是(用過的應該清楚。 百度知道有不少用戶的垃圾回答,是用戶刷分的。)
問了解決這一問題。個人解決思路是:經過Pandas, 篩選答案長度至最小。
可是這樣。就可能篩選除了 大量大量的 原生數據
再加上,把(原數據中 "有問無答" 的問答對)過濾扔掉。
那麼弄下來的源數據,幾乎沒剩多少了。。(我記得我當時弄了400W+問答對)
篩選到最後(問答長度 15個漢字, 篩選掉空回答)(只剩下 幾萬條了。。。)
後來,我急中生智。在網上找了一些 中文語料庫(我用的青雲中文語料庫)
把它融合到 我本身的 語料庫中。。。

可是訓練後的結果, 全是人家 青雲語料庫的 問答內容。。。
後來也沒去繼續深究了。。。

後來正好看到 Ng。提到這一問題,記錄一下相應的應對措施!

訓練集:青雲語料+ 1/2 本身的語料
測試集: 1/4 本身的語料
驗證集:1/4 本身的語料

隨機初始化權重

隨機初始化認知

爲何不是初始化爲0???

由於神經網絡中, W初始化爲0的話, 會致使反向傳播後, 全部神經元會訓練同一個網絡。一點效果沒有

爲何不初始化很大的值或者很小的值???

這是分狀況來定的。
好比你用的 tanh 或者 sigmoid函數
由腦海中的圖像可知(求導 或 斜率) ,當 初始值過大,或者太小。
都會可能致使,y直接落在 sigmoid的  頂部和底部(就是斜率水平,近乎爲0)
落在了水平的梯度。這樣的梯度,猴年馬月也降不下去啊。。。。。
若是落在了 傾斜陡峭的梯度。 那麼梯度降低的必定很快啦。

若是作了BatchNormalization,那麼可以使用 高斯 x 0.01

正態分佈 * 拉低值

np.random.randn(2,2)  * 0.01            # 2,2是形狀, 這個0.01 能夠本身調節。 總之,小一點 最好, 但不要過小

若是使用了Relu激活函數,對應 初始化方法

np.random.randn(shapex, shapey) *  np.sqrt( 2/shapex )    # 係數爲2

若是使用了Tanh激活函數,對應 初始化方法(NG推薦, 也叫 Xavier)

np.random.randn(shapex, shapey) *  np.sqrt( 1/shapex ) # 係數爲1

激活函數

激活函數認知

學習Andrew Ng課更深入瞭解了激活函數。

神經網絡中,爲何咱們須要激活函數,甚至須要非線性激活函數?

首先挑明,咱們使用神經網絡的目的,就是想訓練出更多,更豐富的特徵。
    因此。 一直用線性激活函數,或者不用激活函數。會使得你整個網絡訓練到頭,仍是線性的。就沒意思了。
    它學不到豐富的特徵的。

由於神經網絡多層是須要拿前一層的結果做爲下一層的 x,因此有了以下公式:
    w3 (w2 (w1x+b) +b) +b
展開後, 
    w3 * w2 * w1 * x + ......   
    很明顯它依然是線性的。  
    因此,不管你用多少層 神經網絡。  到最後它依然是線性的。。。。
    這樣倒不如 一層網絡也不用。
    直接上個 邏輯迴歸模型,效果估計也是同樣的。。。。。。

固然有一些場合也須要使用 線性激活函數,好比 房價預測。身高預測。(這些都是線性迴歸模型)

這些狀況,就可使用 線性激活函數了。

可是不妨想想, 就像上面 身高預測這些。是線性迴歸,而且 y預測都是正數值。
某種程度上,其實咱們也可使用 relu激活函數, (由於 relu的右半側(就是大於0的部分) 也是線性的哦)

咱們NN隱層就大多數都使用非線性激活函數。

隱層: relu 或者 leakly relu 或者 tanh
輸出層: sigmoid  或者 softmax 或者 tanh  等等

sigmoid

公式

1  
---------
1 + e**(-x)

每一個out: (0, 1)  

二分類out之和爲 1

對應API:

1. tf.sigmoid(y)
2. 或函數參數 xxxxx (activations='sigmoid')
3. tf.keras.activations.sigmoid()

softmax

e**x
---------------------------------
e**(x1) + e**(x2) + ... + e**(xn)

每一個out: (0,1)

多分類 out之和爲 1

對應API:

1. tf.nn.softmax()
2. 函數參數 xxxxx (activations='softmax')
3. tf.keras.activations.softmax()

softmax特色:

輸出的是什麼形狀的張量,輸出的就是什麼形狀的張量
也是有線性決策邊界(線性 多 分類器)

tanh

coshx

e**x - e**(-x)
-------------
      2

sinhx

e**x + e**(-x)
--------------
      2

tanhx

e**x - e**(-x)
-------------
e**x + e**(-x)
      
每一個out: (0,1) * 2 -1  ===>  (-1,1)

LSTM

對應API:

1. tf.tanh(y)
2. 函數參數 xxxxx (activations='tanh')
3. tf.keras.activations.tanh()

relu

公式:

y = 0 if x < 0 else x    # 大於0,梯度爲1

對應API

1. tf.nn.relu()
2. 或函數參數 xxxxx (activations='relu')
3. tf.keras.activations.relu()

leaky_relu: (小擴展)
    y = kx if x < 0 else x    
    tf.nn.leaky_relu()

損失函數

MSE (均方偏差)

公式

Σ( (y-y_predict)**2 )
--------------------
     n

對應API

公式實現: 
    tf.reduce_mean( tf.square( y-y_predict ) )
tf.API:   
    tf.reduce_mean( tf.loss.MSE(y, y_predict) )

CrossEntropy (交叉熵)

熵公式: -Σ(plogp)
交叉熵公式:-( Σplogq ) p爲真實值One-hot, q爲預測值

p: [1,0,0]
q: [0.9, 0,0.1]
H = -( 1*log0.9 + 0*log0 + 0*log0.1) = -log0.9 = -ln0.9 ≈ 0.1053....
tf的 tf.math.log至關於 ln

交叉熵API:

交叉熵越小(y與y-predict差距越小,預測較準確)
交叉熵越大(y與y_predict差距越大,交叉相乘累加後值大,說明預測錯位了。。。因此交叉起來變大了)

tf.API: (方式1:直接是函數調用)
    loss = tf.losses.categorical_crossentropy([1,0,0], [0.9, 0, 0.1],from_logits=True)  # 第一個參數y, 第二個參數 y_predict
    loss = tf.reduce_mean(loss)

tf.API: (方式2:用類的call調用 , 此次以 二分類交叉熵爲例)
    loss = tf.losses.BinaryCrossentropy(from_logits=True)( [1], [0.1] )  # 結果爲2.+  。 由於 真實值是1類, 而預測值機率是0.1過小了。因此確定預測錯了。
    loss = tf.reduce_mean(loss)
    
說明:categorical_crossentropy( ) # 第一個參數必須 one_hot, (第二個參數按理來講須要作 softmax,可是你傳了 from_logigs=True,就沒必要softmax了)

梯度

SGD(Stochastic Gradent Descent):

解釋 各類梯度降低的區別:
Mini-Batch Gradent Descent:

指定每次 mini-batch個 來作梯度降低 (就是每次指定多少個樣本 來作GD的意思)
這種介於  1-所有樣本之間的。 是最優的

Batch gradent descent:

mini-batch 爲所有樣本

Stochastic gradent descent:

mini-batch 爲 1個樣本
缺點: 每次 1個樣本作SGD, 那麼就失去了 向量化(矩陣乘代替循環)的 加速快感。。。。。

減去梯度,表明朝着梯度方向走

w新 = w當前 - learning_rate * 梯度

使用方式:

model.compile(..... ,optimizer=keras.optimizers.SGD(learning_rate=0.01))

再記錄其餘優化器以前, 先補一個 指數加權平均 的知識

公式:

y = β * X以前 + (1-β)* X當前

圖形曲線表現:

β越小:(小到0.5) :曲線越抖動頻繁(鋸齒 越厲害)(0.5左右已經,嚴重上下跳動了)
β越大:(大至1.0) :曲線越光滑(無鋸齒)
因此 β: 越大越好 
(涉及到一個技術--誤差修正, 若是你不修正。 可能訓練會稍微慢一些。無傷大雅)

Momentum(動量)

公式大概:

dw' =  β * dw-1 + ( 1-β ) * dw        # 用 dw-1 掰彎 dw
db' =  β * db-1 + ( 1-β ) * db        # 用 db-1 掰彎 db

公式理解:

在原來的梯度基礎上, 用 上一次的梯度方向, 把當前將要計算的梯度掰彎

RMSProp

model.compile(..... ,optimizer=keras.optimizers.RMSprop(learning_rate=0.01, momentum=0.9))

Adam(強烈推薦)

TF-API: 默認原參數

model.compile(..... ,optimizer=keras.optimizers.Adam(
        learning_rate=0.001,
        beta_1=0.9,           # 學習率衰減參數
        beta_2=0.999,
        epsilon=1e-7,
    ),
)

其實這個API參數,咱們只稍微調整一下 learning _ rate 便可,其餘不用怎麼。

學習率衰減

其實大多數 優化器內都有 學習率衰減參數,例如:

SGD(decay)
Adam(beta_1)

固然你也能夠本身實現(按照樣本已訓練的批次,動態衰減)

learning rate = learning rate * 1/(epoch輪數 * 衰減率 + 1)

其實還有更多 可調節參數,就像Adam中的 那麼多參數似。固然我壓根也沒想本身實現衰減。。

可知 decay越小, 學習率衰減的越慢, 當衰減率爲0時。  學習率壓根就不衰減
而 decay越大, 學習率衰減的越快, 當衰減率爲1時。  那衰減的就太誇張了~~

遷移學習 (我想到一個詞:移花接木)

應用場景

假如已經有現成的 狗類 識別的 神經網絡模型
那麼假如你如今想要 作一個 貓類的 識別

你徹底能夠把 狗識別 網絡模型拿過來
而後把最後 輸出層 扔掉,本身加一個新輸出層(固然中間你也能夠加一些新的NN層)
而後 旁敲側擊,只在最後一層提供輸入,只對 新的輸出層(或者你額外加的NN)層訓練。

應用條件

當你遷移後的數據有特別特別多的時候, 那麼你徹底能夠把 搬過來的 模型參數 從頭至尾訓練一遍。

就像你 狗模型, 前面的網絡學到了不少  毛,特徵。 (這貓也有嘛,因此正好能夠用得上)
而後你 在狗模型的基礎上 ,訓練貓模型 (我不太瞭解貓~~~, 好比說能夠新學到貓的鬍鬚之類的新特徵)
總結來講:  新模型 = NN層(狗)參數 + NN層(貓)參數 + 輸出層(貓)參數

固然, 若是你遷移支持的數據,只有不多,根本不夠強大的神經網絡訓練

那麼,你就能夠直接把,搬過來的模型參數固定住, 直接只在 最後輸出層,提供輸入,進行訓練
總結來講:  新模型 = NN層(狗)參數 + 輸出層(貓)參數

遷移學習的主要目的思想:

當你 有不多的小數據集A, 可是你想訓練成一個 NN 來 達到目的。
可想而知,少許數據集A 還不夠 NN 塞牙縫的。。。

因此,你須要找一些其餘相似的數據集B(量多的,好收集的)
而後這些大量數據集B,足以 馳騁於 NN , 獲得一個模型。(而且帶着 訓練好的參數)

數據集A說: "
    大哥,你訓練好的網絡借我用用唄。
    你用了那麼多數據,訓練出的特徵必定有我想要的。
    我把整個模型拿過來,只改一下最後一層的輸入。而後只訓練最後一層的參數。
    其餘層的參數都用你的。
"。
數據集B大哥說: "能夠"

遷移學習API (Tensorflow2.0)

舒適提示: TF20的Keras Layers 是能夠 用切片語法 選取具體網絡層的,舉個例子:

# from tensorflow import keras
# cut_resnet = keras.applications.DenseNet121(  # 使用現有ResNet模型
#     include_top=False,  # 不要最後一層,而是使用咱們本身定義的全鏈接層
#     pooling='avg',
#     weights='imagenet',  # 初始化權重(從imagenet訓練好模型參數來初始化)
# )
# for layer in cut_resnet.layers[0:-3]:  # 部分可訓練(fine-tune分割)
#     trainable=False             # 0 到 倒數第三層,參數不可訓練
# 
# new_model = keras.models.Sequential()
# new_model.add(cut_resnet)
# new_model.add(其餘層)

遷移學習 適用場景

  1. 統一使用領域(要麼文本遷移要文本, 要門圖像遷移到圖像。)
  2. 假如 A 遷移到 B (那麼 A的樣本最好遠大於 B的樣本)
  3. 假如 A 遷移到 B (最好A的許多特徵信息,B正好能夠用獲得。好比 貓狗,都有毛髮,鬍鬚,四條腿)

多任務學習(瞭解,用的少)

直接感觀:我認爲就像(類的繼承 , 或者封裝爲一個函數, 這樣的概念。。)

你想訓練 預測 各類各樣類別的圖片。
你能夠首先 用一個任務 訓練一下 共有特徵 的 NN。
而後其餘任務 用這個 訓練好的 共有的特徵的 NN。
Ng提示: 你須要有龐大的神經網絡支撐,否則效果很差。
相關文章
相關標籤/搜索