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提示: 你须要有庞大的神经网络支撑,否则效果很差。
相关文章
相关标签/搜索