深度学习初步

本博客目标

  1. 创建一个全连接神经网络
  2. 应用神经元去解决回归和分类问题
  3. 用随机梯度下降去训练神经元,并用dropout, batch normalization等方法提升性能。

线性神经元

  1. 单个输入

在这里插入图片描述
x为输入,w为权重;b即bias,用于修正output的独立于input的项
2. 多个输入
在这里插入图片描述

用keras.Sequential创建模型

from tensorflow import keras
from tensorflow.keras import layers

# Create a network with 1 linear unit
model = keras.Sequential([
    layers.Dense(units=1, input_shape=[3])
])
参数说明
units神经元的输出维度
input_shape输入数据的特征数,是一个list,方便[height, width, channels]这类复杂数据的输入

tensor数组

tensor是TensorFlow下的数组,类似于Numpy中的array,用于深度学习。在keras中用来表示weights。

import tensorflow as tf

layers

layers是keras中非常普通的结构,用来完成数据的转换。层的连接方式不同,如CNN,RNN,就会产生不同的效果。

dense layer:一层输入都相同的神经元
在这里插入图片描述

激活函数Activation Function

Relu

在这里插入图片描述
以下两种写法相同,激活函数可以独立作为一层

model = keras.Sequential([
    layers.Dense(units=32,activation="relu",input_shape=[8]),
    layers.Dense(units=32,activation="relu"),
    layers.Dense(units=1)
])
### YOUR CODE HERE: rewrite this to use activation layers
model = keras.Sequential([
    layers.Dense(32, input_shape=[8]),
    layers.Activation("relu"),
    layers.Dense(units=32),
    layers.Activation("relu"),
    layers.Dense(1),
])

在这里插入图片描述

建立Sequential 模型

Sequential中的layers按照层的叠加顺序写,最后一层是输出层,之前的都为隐藏层,input_shape作为第一层的参数。
第一次建立后,网络中的weigths都是随机的。

from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    # the hidden ReLU layers
    layers.Dense(units=4, activation='relu', input_shape=[2]),
    layers.Dense(units=3, activation='relu'),
    # the linear output layer 
    layers.Dense(units=1),
])

损失函数

loss function:用于评价结果的好坏

优化方法

optimizer:调整weigths以最小化损失函数的算法。
深度学习的优化算法,几乎都基于随机梯度下降的迭代算法,步骤一般如下:

  1. 在训练集中采样并训练神经网络
  2. 通过损失函数度量模型预测和真实值的差距
  3. 朝损失函数减小的方向调整weights

note:放入模型前,要先进行归一化

名称解释
batch_size每次迭代的训练集样本数量
iteration每次放batch_size个样本,把全部样本放进网络需要多少次,不满一个batch_size的就不用了。
epoch把全部样本训练过一次为一个epoch
learning rate调整weigths改变的速度
Adam随机梯度下降的自适应算法

optimizer和loss可通过Keras API 微调

model.compile(
    optimizer="adam",
    loss="mae",
)

PS:

SGDM:
θ t = θ t − 1 − η m t m t = β 1 m t − 1 + ( 1 − β 1 ) g t − 1 \theta_t=\theta_{t-1}-\eta m_t\\m_t=\beta_1m_{t-1}+(1-\beta_1)g_{t-1} θt=θt1ηmtmt=β1mt1+(1β1)gt1
RMSProp:
θ t = θ t − 1 − η v t g t v t = β 2 v t − 1 + ( 1 − β 1 ) g t − 1 2 v 1 = g 0 2 \theta_t=\theta_{t-1}-\frac{\eta}{\sqrt{v_t}} g_t\\ v_t=\beta_2v_{t-1}+(1-\beta_1)g_{t-1}^2\\v_1=g_0^2 θt=θt1vt ηgtvt=β2vt1+(1β1)gt12v1=g02
Adam=SGDM+RMSProp
θ t = θ t − 1 − η v t ^ + ϵ m t ^ m t ^ = m t 1 − β 1 t v t ^ = v t 1 − β 2 t \theta_t=\theta_{t-1}-\frac{\eta}{\sqrt{\hat{v_t}}+\epsilon}\hat{m_t}\\ \hat{m_t}=\frac{m_t}{1-\beta_1^t}\\ \hat{v_t}=\frac{v_t}{1-\beta_2^t} θt=θt1vt^ +ϵηmt^mt^=1β1tmtvt^=1β2tvt

搭建网络

  1. 先对数据进行归一化,确定特征的维数
import pandas as pd
from IPython.display import display

data = pd.read_csv('XXX.csv')

# Create training and validation splits
df_train = data.sample(frac=0.7, random_state=0)
df_valid = data.drop(df_train.index)

# Scale to [0, 1]
max_ = df_train.max(axis=0)
min_ = df_train.min(axis=0)
df_train = (df_train - min_) / (max_ - min_)
df_valid = (df_valid - min_) / (max_ - min_) #极差是根据训练集来的

# Split features and target
X_train = df_train.drop('quality', axis=1)
X_valid = df_valid.drop('quality', axis=1)
y_train = df_train['quality']
y_valid = df_valid['quality']
  1. 按需要搭建一个多层神经网络,设定loss function和optimizer
from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    layers.Dense(512, activation='relu', input_shape=X_train.shape[1]),
    layers.Dense(512, activation='relu'),
    layers.Dense(512, activation='relu'),
    layers.Dense(1),
])

model.compile(
    optimizer='adam',
    loss='mae',
)

  1. 训练数据集(导入训练集,验证集可不导入,设置batch_size,设置epochs)
history = model.fit(
    X_train, y_train,    #导入训练集的数据
    validation_data=(X_valid, y_valid),    #导入验证集的数据,可不写
    batch_size=256,   #设置每次随机梯度下降的样本采样量
    epochs=10,
)

fit方法记录了整个训练过程的loss,可将其转化为pandas DataFrame 格式后进行可视化

import pandas as pd

# convert the training history to a dataframe
history_df = pd.DataFrame(history.history)
# use Pandas native plot method
history_df['loss'].plot();

在这里插入图片描述

若loss呈现出仍在下降的趋势,需要增加训练的epochs,如果已经下降到一个平缓的位置,则增加epochs用处不大。

对于learning rate和batch_size需要考虑的三个问题:

  • 模型训练需要话多长时间
  • 学习曲线的波动怎么样
  • loss能减少到什么程度

batch_size越小,学习曲线波动越大——数据量小相对噪音就会比较大
learning rate越小,更新得慢,意味着收敛需要更长的时间,大的学习率可以加快速度,但过大会导致整个模型不收敛。

learning curve

在这里插入图片描述

所有数据里面都会包含一些noise( ϵ \epsilon ϵ)。对于training loss不论学习到的是noise还是signal,learning curve最终都会下降。但是validation loss 只会在模型学习到比较多的signal时下降,模型学习到的噪音信息不能正确泛化应用到新数据上。学习到的噪音信息越多,learning curve和validation loss的差距越大。

however,学习更多数据的同时,必然也会学习到更多的噪音,我们需要make a trade。只要validation loss在继续减小,增加epochs学习新的数据,虽然这个过程增加了噪音,但是可以接受的,但是过了转折点以后,trade-off就不好啦。

这种trade-off其实处理的是欠拟合和过拟合的问题。
在这里插入图片描述

阶段主导原因
1偏差主导,主要是欠拟合
2转折点,噪声主导
3方差主导(就是过拟合了)
验证集解释处理
偏差大就是模型欠拟合造成的一般是训练初期,继续训练,或者换一个强学习器
方差大方差是模型训练刻画扰动的,相同规模但内容不同的数据集,所带来的模型性能的变化
过拟合,模型太复杂,把一点点改变都学进去了,模型复杂度太高,就出现方差大的表现(过拟合和方差大差不多一个意思,过拟合说的更形象)
早停止、正则化、加大样本等等,第一还是从数据找原因

模型复杂度越高,方差越大,偏差越小

getting more signal while reducing noise.

对于神经网络,模型的能力与神经元的数模和连接方式有关。模型欠拟合,就需要增加模型的拟合能力:

  1. wider:增加每层的神经元 → \rightarrow 增加线性关系
  2. deeper:增加神经元层数 → \rightarrow 增加非线性关系

early stoping

目的:

  1. 在validation loss 不再降低时,及时停止训练
  2. 将网络的权重weights重置成validation loss最低时的状态
  3. 同时epochs要足够大,避免没有训练充分就停止出现欠拟合。

通过callback函数(可通过链接,或者自定义),去平衡validation loss上升的原因——overfitting and random batch variance 。


from tensorflow.keras.callbacks import EarlyStopping

early_stopping = EarlyStopping(
    min_delta=0.001, # minimium amount of change to count as an improvement
    patience=20, # how many epochs to wait before stopping
    restore_best_weights=True,
)

在20epochs(patience=20)中 validation loss若没有0.001(min_delta=0.001)的下降,则停止训练,并保留目前为止最优参数(restore_best_weights=True)。


history = model.fit(
    X_train, y_train,
    validation_data=(X_valid, y_valid),
    batch_size=256,
    epochs=500,
    callbacks=[early_stopping], # put your callbacks in a list
    verbose=0,  # turn off training log,默认是开着
)

history_df = pd.DataFrame(history.history)
history_df.loc[:, ['loss', 'val_loss']].plot();
print("Minimum validation loss: {}".format(history_df['val_loss'].min()))

如果如下图,两条曲线的gap很小,validation loss 也没有增加,可能还欠拟合,需要增加模型复杂度继续训练

在这里插入图片描述

PS:按照某个类别特征划分训练集测试集

from sklearn.model_selection import GroupShuffleSplit
# We'll do a "grouped" split to keep all of an artist's songs in one
# split or the other. This is to help prevent signal leakage.
def group_split(X, y, group, train_size=0.75):
    splitter = GroupShuffleSplit(train_size=train_size)
    train, test = next(splitter.split(X, y, groups=group))
    return (X.iloc[train], X.iloc[test], y.iloc[train], y.iloc[test])

X_train, X_valid, y_train, y_valid = group_split(X, y, artists)

special layers

Dropout

过拟合是因为学习得太符合训练集了——神经网络的这种weights组合把训练集的噪音都学得很好。dropout的想法就是要打破这种组合:
在每个epochs随机去掉每层中一定比例的神经元——加大神经网络学习训练集中noise的难度,进而去探索泛化能力更强,鲁棒性更好的weigths组合。

在这里插入图片描述

You could also think about dropout as creating a kind of ensemble of networks. The predictions will no longer be made by one big network, but instead by a committee of smaller networks. Individuals in the committee tend to make different kinds of mistakes, but be right at the same time, making the committee as a whole better than any individual. (If you’re familiar with random forests as an ensemble of decision trees, it’s the same idea.)

Adding Dropout

  1. 使用Dropout需要在每层适当增加神经元
    将layers.Dropout放在要应用dropout的layers前面
keras.Sequential([
    # ...
    layers.Dropout(rate=0.3), # apply 30% dropout to the next layer
    layers.Dense(1024),
    # ...
])

Batch Normalization

在这里插入图片描述

目的:可用于纠正训练慢和不稳定。(每一层的信息利用更充分而不是最后集中在某些值)
结果:对隐藏层的输入也进行标准化,更有效地利用激活函数进行非线性化的过程.(更有效地传递信息)。

添加神经网络的时候, 先有数据 X, 再添加全连接层, 全连接层的计算结果会经过激励函数成为下一层的输入。Batch Normalization (BN) 就被添加在每一个全连接和激励函数之间

  1. 标准化工序:将全连接层的输出的batch用均值和方差标准化
    使数据大部分集中在激活函数的敏感区域,信息保留更完善
    在验证集和测试时,均值和方差要固定
  2. 反标准化工序:用scale和shift两个参数(可被神经网络学习),对batch进行再调整
    若BN操作无效,学习到的scale和shift会抵消抵消一些BN效果

Adding BN

layers.Dense(16),
layers.BatchNormalization(),
layers.Activation('relu'),

layers.BatchNormalization()如果作为第一层,相当于sklearn里的StandardScaler操作

神经网络做分类

和回归问题最大的区别是,损失函数和模型输出不同。

指标式子
accuracy c o r r e c t _ n u m b e r t o t a l \frac{correct\_number}{total} totalcorrect_number标签类别的比例大致相同

上述指标不能直接作为损失函数loss function(SGD需要损失函数光滑)

损失函数解释式子
Cross-entropy概率意义上的距离度量 H ( p , q ) = − ∑ i = 1 n p ( x i ) log ⁡ ( q ( x i ) ) H(p,q)=-\sum_{i=1}^np(x_i)\log (q(x_i)) H(p,q)=i=1np(xi)log(q(xi)),这里 l o s s = − 1 m ∑ j = 1 m ∑ i = 1 n y i j log ⁡ y i j log ⁡ y i j ^ loss=-\frac{1}{m}\sum_{j=1}^m \sum_{i=1}^n y_{ij} \log y_{ij}\log \hat{y_{ij}} loss=m1j=1mi=1nyijlogyijlogyij^,n为类别数,m为batch_size

(
PS: D K L ( p ∣ ∣ q ) = − H ( p ( x ) ) + [ − ∑ i = 1 n p ( x i ) log ⁡ ( q ( x i ) ) ] , D_{KL}(p||q)=-H(p(x))+[-\sum_{i=1}^np(x_i)\log (q(x_i))], DKL(pq)=H(p(x))+[i=1np(xi)log(q(xi))],这里的KL散度为 D K L ( y ∣ ∣ y ^ ) D_{KL}(y||\hat{y}) DKL(yy^).

首先,给目标分配神经网络可学习的数值型类别标签。

构建分类的神经网络

sigmoid 函数

可将神经层输出转化到0~1之间的概率,需要确定一个阈值

在最后一层,应该使用sigmod激活函数去产生类别概率。

from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    layers.Dense(4, activation='relu', input_shape=[33]),
    layers.Dense(4, activation='relu'),    
    layers.Dense(1, activation='sigmoid'),
])

同时,compile方法也需要变换

model.compile(
    optimizer='adam',
    loss='binary_crossentropy',
    metrics=['binary_accuracy'],
)

early stopping和fit方法不变

early_stopping = keras.callbacks.EarlyStopping(
    patience=10,
    min_delta=0.001,
    restore_best_weights=True,
)

history = model.fit(
    X_train, y_train,
    validation_data=(X_valid, y_valid),
    batch_size=512,
    epochs=1000,
    callbacks=[early_stopping],
    verbose=0, # hide the output because we have so many epochs
)

最后画出学习曲线和正确率变换曲线:

history_df = pd.DataFrame(history.history)
# Start the plot at epoch 5
history_df.loc[5:, ['loss', 'val_loss']].plot()
history_df.loc[5:, ['binary_accuracy', 'val_binary_accuracy']].plot()

print(("Best Validation Loss: {:0.4f}" +\
      "\nBest Validation Accuracy: {:0.4f}")\
      .format(history_df['val_loss'].min(), 
              history_df['val_binary_accuracy'].max()))

(simpleImpute,onehotencoder(handle_unknown),make_pipeline

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值