1.1 人工智能与传统机器学习
学习心得:
传统机器学习(ML):需要专业的主题专家人工提取特征,并通过一个编写良好的算法来破译给定的特征,从而判断这幅图像中的内容。
输入-->人工提取特征-->特征-->具有浅层结构的分类器-->输出
当存在欺骗性的图片出现时可能会失效,我们需要创建能够精细分类多种类型的人为规则数量可能是指数级的,,因此传统方法在非常受限的环境中很有效。
我们可以将同样的思路扩展到任何领域比如:文本或结构化数据,在过去如果想通过编程解决现实世界的任务,那么必须理解关于输入数据的所有内容,并且需要编写尽可能多的规则来覆盖每个场景,不仅乏味,而且不能保证所有的新场景都会遵循上述规则。
然而,通过人工神经网络,神经网络提供了特征提取和决策分类的模块,几乎不需要手工提取特征,只需要标记数据(如:哪些是人,哪些不是人)和神经网络架构,这样就消除了传统技术(如何创造规则)带来的负担
输入-->特征学习+分类器(端到端选择)-->输出
但是在这里,我们需要提供大量样本,如:大量人和不含人的图片输入给模型,以便它学习特征
1.2 人工神经网络的构建模块
可以将人工神经网络看作一个数学函数,输入一个或者多个张量(权重),输出一个或者多个张量(权重)连接这些输入和输出的运算排列称为神经网络的架构,我们可以根据手头任务定制。
输入层:自变量的输入。
隐藏(中间)层:连接输入和输出层,并对输入数据进行转换,此外隐藏层包含节点, 用于将输入值修改为更高/更低维度的值,可以通过修改中间层节点的激活函数实现更复杂的表示。
输出层:输入变量后产生期望的值,树输出层节点数量取决于手头任务,及试图预测的是连续还是分类变量,若是连续的则输出层只有一个节点,若是n个分类则输出层就有n个节点。
激活函数:
深度学习指的是具有更多隐藏层
1.3 前向传播
在开始前使用随机权重初始化
-
计算隐藏层的值
-
进行非线性激活
sigmoid = 1/(1 + e^-x)
ReLU = x if x > 0 else 0
tanh = (e^x - e-x)/(ex + e^-x) -
估算输出层的值
-
计算与期望值对应的损失值
计算连续变量的损失一般用MSE(均方误差的平方可以保证正误差和负误差不相互抵消)
np.mean(np.square(pred - y))计算分类变量的损失一般用二元交叉熵损失(当只有两个类别的时候)
-np.mean((y*np.log(p))+(1-y)*np.log(1-p))
一般多分类用分类交叉熵
(图)
数据集的最终损失是所有单个损失的平均值。
补:平均绝对误差
np.mean(np.abs(pred - y))
# 在预测输出小于1的时候,使用均方误差可以大大降低损失量
np.mean(np.square(pred - y))
前向传播(Numpy)
def feed_forward(inputs, outputs, weights):
pre_hidden = np.dot(inputs,weights[0])+ weights[1]
hidden = 1/(1+np.exp(-pre_hidden))
pred_out = np.dot(hidden, weights[2]) + weights[3]
mean_squared_error = np.mean(np.square(pred_out - outputs))
return mean_squared_error
1.4 反向传播
通过更新权重来减小误差的过程称为梯度下降
Numpy实现每次对一个参数少量更新,实现梯度下降
from copy import deepcopy
import numpy as np
import matplotlib.pyplot as plt
# 更新权重
def update_weights(inputs, outputs, weights, lr):
original_weights = deepcopy(weights)
updated_weights = deepcopy(weights)
original_loss = feed_forward(inputs, outputs, original_weights)
# 先计算一次损失
for i, layer in enumerate(original_weights):
for index, weight in np.ndenumerate(layer):
temp_weights = deepcopy(weights)
temp_weights[i][index] += 0.0001
# 每次将权重和偏置的一个增加很小的量
_loss_plus = feed_forward(inputs, outputs, temp_weights)
# 再计算一次损失
grad = (_loss_plus - original_loss)/(0.0001)
# 计算梯度(参数值改变引起的损失的改变)
updated_weights[i][index] -= grad*lr
# 更新参数,使用学习率慢慢建立信任
return updated_weights, original_loss
# 输入输出
x = np.array([[1,1]])
y = np.array([[0]])
# 参数随机初始化
W = [
np.array([[-0.0053, 0.3793],
[-0.5820, -0.5204],
[-0.2723, 0.1896]], dtype=np.float32).T,
np.array([-0.0140, 0.5607, -0.0628], dtype=np.float32),
np.array([[ 0.1528, -0.1745, -0.1135]], dtype=np.float32).T,
np.array([-0.5516], dtype=np.float32)
]
# 绘图
losses = []
for epoch in range(100):
W, loss = update_weights(x,y,W,0.01)
losses.append(loss)
plt.plot(losses)
plt.title('Loss over increasing number of epochs')
批大小:当有成千上万的数据的时候,如果一起输入到网络计算损失收益不是很高,因此使用批大小进行模型训练
1.5 链式法则的反向传播
利用偏导数就可以仅仅通过利用前向传播计算出的损失来更新参数。
1.6 学习率的影响
当学习率很小的时候,权值向最优值的移动比较慢。
当学习率稍大的时候,权值先是震荡,然后快速向最优值收敛。
当学习率很大的时候,权值会达到一个很大的值,无法达到最优值。
(权值小于最优值的时候梯度为负,反之梯度为正)
一般来说学习率越小越好(0.0001-0.01)