### 深度学习概述
#### 什么是深度学习?
**人工智能机器学习、深度学习的关系](https://images.gitee.com/uploads/images/2021/1004/144611_893ccfa9_9672955.png "01.png")
**“深度”**是指一系列连续的表示层。数据模型中包含多少层,称为模型的**深度**。这些分层几乎总是通过**神经网络**的模型来学习得到的。
**深度网络**可以看作下图的多级信息蒸馏操作:信息穿过连续的过滤器,其纯度越来越高,对识别任务的帮助越来越大。
**深度学习核心思想:卷积神经网络和反向传播 。**
**权重**(每层的参数):学习是指为神经网络的所有层找到一组权重值,使得该网络能够将每个示例输入与其目标正确地一一对应。
**损失函数**(categorical_crossentropy,目标函数):输入的是网络预测值与真实目标值,然后计算一个距离值,衡量该网络在这个示例上的效果好坏。
**反向传播**(优化器):深度学习的核心算法。利用距离值作为反馈信号来对权重值进行微调,以降低当前示例的损失值。
![输入图片说明](https://images.gitee.com/uploads/images/2021/1004/144632_caa305c5_9672955.png "机器学习.png")
**从机器学习到深度学习:**
**机器学习:**
**概率建模:朴素贝叶斯算法(分类器);logistic回归(分类算法);**
**核方法**(一组分类算法):**SVM**(支持向量机,通过将两种不同类别的数据点之间找到良好的决策边界,以该边界将训练数据划分为两个空间/类别,来解决分类问题。先将数据映射到一个新的高维表示,再间隔最大化(尽量让超平面/或线与每个类别最近的数据点之间的距离最大化)。
**核函数:**在新空间中计算点对之间的距离(SVM一般不计算点的坐标)。
核函数是人为选取的,SVM中只有分割超平面是学习得到的。
**缺点:**SVM是比较浅层的方法,很难扩展到大型数据集,在图像分类等感知问题上效果也不好。)
**决策树、随机森林算法、梯度提升机。**
但是,以上全是机器学习时代的辣鸡(小声bb),直到深度学习时代的到来,深度卷积神经网络的出现,渐渐取而代之。
**深度学习:**优点:特征工程自动化!!!(以前的浅层学习是依次连续学习(贪婪学习),收益会随着层数的增加而迅速降低,但是深度学习可以在同一时间共同学习所有表示层,且主动调节适应,无需人为干预)。
在kaggle竞赛,梯度提升机用于处理结构化数据的问题(**XGBoost库**),深度学习则用于图像分类等感知问题(**Keras库**)。
**深度网络**可以看作下图的多级信息蒸馏操作:信息穿过连续的过滤器,其纯度越来越高,对识别任务的帮助越来越大。
深度学习,实际上来说就是一种模仿人脑的学习,它是起源于人工神经网络的研究.它含多隐层的[多层感知器](https://baike.baidu.com/item/多层感知器)就是一种深度学习结构。深度学习通过组合低层特征形成更加抽象的高层表示属性类别或特征,以发现数据的分布式特征表示。
深度学习(DL, Deep Learning)是[机器学习](https://baike.baidu.com/item/机器学习/217599)(ML, Machine Learning)领域中一个新的研究方向,它被引入机器学习使其更接近于最初的目标——[人工智能](https://baike.baidu.com/item/人工智能/9180)(AI, Artificial Intelligence)。 [1]
深度学习是学习[样本数据](https://baike.baidu.com/item/样本数据/12726279)的内在规律和表示层次,这些学习过程中获得的信息对诸如文字,[图像](https://baike.baidu.com/item/图像/773234)和声音等数据的解释有很大的帮助。它的最终目标是让机器能够像人一样具有分析学习能力,能够识别文字、图像和声音等数据。 深度学习是一个复杂的机器学习算法,在语音和图像识别方面取得的效果,远远超过先前相关技术。 [1]
深度学习在[搜索技术](https://baike.baidu.com/item/搜索技术/1447197),[数据挖掘](https://baike.baidu.com/item/数据挖掘/216477),机器学习,[机器翻译](https://baike.baidu.com/item/机器翻译/411793),[自然语言处理](https://baike.baidu.com/item/自然语言处理/365730),[多媒体学习](https://baike.baidu.com/item/多媒体学习/10528812),语音,推荐和个性化技术,以及其他相关领域都取得了很多成果。深度学习使机器模仿视听和思考等人类的活动,解决了很多复杂的模式识别难题,使得人工智能相关技术取得了很大进步。
1. ##### 推动机器学习发展的三大因素: 硬件, 数据, 算法
1.1 高速, 大规模集成电路的发展. GPU并行运算的发展
1.2 大量的数据产生, 每天都会产生海量的数据资源.
1.3 丰富的软件支持包.
2. ##### 机器学习, 深度学习和人工智能
人工智能是[计算机](https://baike.baidu.com/item/计算机)科学的一个分支,它企图了解智能的实质,并生产出一种新的能以[人类智能](https://baike.baidu.com/item/人类智能/2287229)相似的方式做出反应的智能机器,该领域的研究包括机器人、语言识别、图像识别、自然语言处理和[专家系统](https://baike.baidu.com/item/专家系统/267819)等。人工智能从诞生以来,理论和技术日益成熟,应用领域也不断扩大,可以设想,未来人工智能带来的科技产品,将会是人类[智慧](https://baike.baidu.com/item/智慧/129438)的“容器”。人工智能可以对人的意识、思维的信息过程的模拟。人工智能不是人的智能,但能像人那样思考、也可能超过人的智能。
深度学习源于人工神经网络的研究,它被引入机器学习使其更接近于最初的目标——[人工智能](https://baike.baidu.com/item/人工智能/9180)(AI, Artificial Intelligence)。
机器学习是一门多领域交叉学科,涉及概率论、统计学、[逼近论](https://baike.baidu.com/item/逼近论/967006)、[凸分析](https://baike.baidu.com/item/凸分析)、[算法复杂度](https://baike.baidu.com/item/算法复杂度)理论等多门学科。专门研究计算机怎样模拟或实现人类的[学习行为](https://baike.baidu.com/item/学习行为/5482132),以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。
3. ##### 深度学习的框架
深度学习在研究初期, 科研人员需要编写大量重复性代码. 一方面, 大量代码的编写增加了入门的门槛, 同时增加了代码出错的风险, 科研人员需要花费大量的精力用于代码的维护工作. 另一方面, 由于编程规范不统一, 以及编程语言的多样性, 使得学术交流较为困难, 严重阻止的深度学习的发展. 因此, 为了避免重复"造轮子"的尴尬局面,同时提高工作效率. 一些研究人员开始着力开发编写深度学习框架.
深度学习的发展,以及广泛使用, 得益于深度学习框架的易用性.
目前业界使用比较普遍的深度学习框架有:
1. TensorFlow: TensorFlow 是一个开源的、基于 Python 的机器学习框架,它由 Google 开发,并在图形分类、音频处理、推荐系统和自然语言处理等场景下有着丰富的应用,是目前最热门的机器学习框架。TensorFlow™ 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。它灵活的架构让你可以在多种平台上展开计算,例如台式计算机中的一个或多个CPU(或GPU),服务器,移动设备等等。TensorFlow 最初由Google大脑小组(隶属于Google机器智能研究机构)的研究员和工程师们开发出来,用于机器学习和深度神经网络方面的研究,但这个系统的通用性使其也可广泛用于其他计算领域。
Tensorflow是谷歌公司在**2015年9月**开源的一个深度学习框架
2.Pytorch:201年1月,由[Facebook](https://baike.baidu.com/item/Facebook/7449587)[人工智能](https://baike.baidu.com/item/人工智能/9180)研究院(FAIR)基于Torch推出了PyTorch。它是一个基于Python的可续计算包,提供两个高级功能:1、具有强大的GPU加速的张量计算(如NumPy)。2、包含自动求导系统的深度神经网络。其优点是 入门简单, 框架简介高效, 一直在维护和开发
3. Keras: Keras是一个高层神经网络API,Keras由纯Python编写而成并基[Tensorflow](https://github.com/tensorflow/tensorflow)、[Theano](https://github.com/Theano/Theano)以及[CNTK](https://github.com/Microsoft/cntk)后端。Keras 为支持快速实验而生,能够把你的idea迅速转换为结果。
4. Caffe: Convolutional Architecture for fast feature embedding, 由加州大学伯克利分校的贾扬清开发,使用C++编写, 是一个清晰且高效的开源深度学习框架, 目前由伯克利视觉学习中心进行维护. 只提供C++接口, 并没有提供Python接口.
Caffe的流行,源于ImageNet比赛中, 使用的网络都是caffe写的, 想要参加比赛就必须掌握Caffe的网络模型接口, 目前caffe2的已经开源 .
5. 百度飞桨:飞桨(PaddlePaddle)以百度多年的深度学习技术研究和业务应用为基础,集深度学习核心训练和推理框架、基础模型库、端到端开发套件、丰富的工具组件于一体。是中国首个自主研发、功能完备、开源开放的产业级深度学习平台. 其官方四大领先技术包括: 开发便捷的深度学习框架, 超大规模深度学习模型训练技术; 多端多平台部署的高性能推理引擎, 以及产业级的开源模型库. 具有丰富的硬件支持, 以及多家国内落地应用产业.
f(x)=ax+bf(x)=ax+b
深度学习的框架 数据集 模型, 训练 , 推理
x |
y |
1 |
2 |
2 |
4 |
3 |
6 |
4 |
? |
前三行可以成为训练集, 第四行为测试集
很容易的,我们可以猜到最后的yy值应该是44, 但是我们在怎么让机器去预测最后的yy值呢? 换句话说,如果我们能够找到一个直线方程,能够最大限度的穿过给定的x, y点也可以. (这里为了简化计算, 假设已经知道直线方程过原点,也就是说bb 等于0)
“斜率”参数(w,也叫作权重或系数)被保存在coef_属性中,而偏移或截距(b)被保存在intercept_属性中:
线性模型利用输入特征的线性函数(linear function)进行预测。
普通最小二乘法(ordinary least squares,OLS),是回归问题最简单也最经典的线性方法。线性回归寻找参数 w 和 b,使得对训练集的预测值与真实的回归目标值 y之间的均方误差最小。均方误差(mean squared error)是预测值与真实值之差的平方和除 以样本数。线性回归没有参数,这是一个优点,但也因此无法控制模型的复杂度。
岭回归的预测公式与普通最小二乘法相同。但在岭回归中,对系数(w)的选择不仅要在训练数据上得到好的预测结果,而且还要拟合附加约束。我们还希望系数尽量小。、w 的所有元素都应接近于 0。直观上来看,这意味着每个特征对输出的影响应尽可能小(即斜率很小),同时仍给出很好的预测结果。这种约束是正则化(regularization)。正则化是指对模型做显式约束以避免过拟合。岭回归使用的是L2正则化。岭回归在 linear_model.Ridge 中实现。对扩展的波士顿房价数据集进行岭回归预测(图1)
图一:不同alpha值的岭回归与线性回归的系数比较
图二:不同 alpha 值的 lasso 回归与岭回归的系数比较
除了 Ridge,还有一种正则化的线性回归是 Lasso。与岭回归相同,使用 lasso 也是约束系数使其接近于 0,但用到的方法不同,叫作 L1 正则化。L1 正则化的结果是,使用 lasso 时某些系数刚好为 0。这说明某些特征被模型完全忽略。这可以看作是一种自动化的特征选择。某些系数刚好为 0,这样模型更容易解释,也可以呈现模型最重要的特征。
常见的两种线性分类算法是 Logistic 回归(logistic regression)和线性支持向量机(linear support vector machine,线性 SVM),前者在 linear_model.LogisticRegression 中实现,后者在 svm.LinearSVC(SVC 代表支持向量分类器)中实现。
下面给出一个方法:
定义损失函数 loss=(y^−y)2=(a⋅x+b−y)2loss=(y^−y)2=(a⋅x+b−y)2, 可以看出,只要找到了正确的a值,就可以得到一个较小的loss函数值.
首先,我们采用穷举的方式查找最小的损失函数
本例题的目标就是找到一个组合适的x,bx,b使得上式中的lossloss最小
import numpy as np
from matplotlib import pyplot as plt
data_x = [1, 2, 3]
data_y = [2, 4, 6]
loss_list = list()
a_list = list()
def forward(x):
return a * x
def lossFunction(x, y):
y_pred = forward(x)
loss = (y_pred - y) ** 2
return loss
def predict(x,a_):
return a_*x
if __name__ == '__main__':
for a in np.arange(0, 4, 0.1):
sum_loss = 0
for i in range(3):
sum_loss += lossFunction(data_x[i], data_y[i])
loss_list.append(sum_loss / 3)
a_list.append(a)
plt.figure()
plt.plot(a_list, loss_list)
# plt.title("")
plt.xlabel('a')
plt.ylabel('loss')
# plt.show()
min_value = min(loss_list)
index_lossMin = loss_list.index(min_value)
print(index_lossMin)
proper_a = a_list[index_lossMin]
print(proper_a)
print("Please input the desired x:")
desired_x = input()
print(f"The predict output for the linear model is {predict(float(desired_x),proper_a)}")
下面给出采用sklearn的方法来实现线性回归的效果
import numpy as np
from matplotlib import pyplot as plt
from sklearn import linear_model
import pandas as pd
lrm = linear_model.LinearRegression()
x_data = np.array([1,2,3])
y_data = np.array([2,4,6])
z_data = np.zeros([3,2])
m_data = np.zeros([3,2])
z_data[:,0] = x_data
z_data[:,1] = y_data
m_data[:,0] = x_data
m_data[:,1] = x_data
lrm.fit(m_data,z_data)
print(lrm.predict([[4,4]]))
练习题:
'''
给定训练集为 x=1, y=6.8
x=2, y=9.8
x=3, y=13.2
x=4, y=16.2
测试集 x=5, y=? '''
import numpy as np
from matplotlib import pyplot as plt
x_data = [1,2,3,4]
y_data = [6.8,9.8,13.2,16.2]
loss_list = list()
def forward(a,x,b):
return a*x+b
def lossFunction(a,x,y,b):
y_pred = forward(a,x,b)
loss = (y_pred - y)**2
return loss
a_list = list()
b_list = list()
if __name__ == '__main__':
for a in np.arange(0,6,0.1):
for b in np.arange(0,6,0.1):
sum_loss = 0
for i in range(4):
sum_loss += lossFunction(a, x_data[i], y_data[i],b)
loss_list.append(sum_loss/4)
a_list.append(a)
b_list.append(b)
plt.plot(a_list,loss_list)
plt.xlabel('a')
plt.ylabel('loss')
print(min(loss_list))
loss_min_index = loss_list.index(min(loss_list))
print(loss_min_index)
a_wanted = a_list[loss_min_index]
b_wanted = b_list[loss_min_index]
print(f'a_wanted = {a_wanted}, b_wanted ={b_wanted}')
# plt.show()
# a_wanted = a_list[loss_list.index(min(loss_list))]
# print(forward(a_wanted, 4))
print(forward(a_wanted, 5, b_wanted))
通过下面的代码可以直观的看出,当取得不同bb的时候,得到的直线的样子。
def LinearFunction(x,a=3.2,b=3.4):
return a*x+b
def LinearFunction2(x,a=3.2,b=3.5):
return a*x+b
x_data = [1,2,3,4]
y_data = [6.8, 9.8, 13.2, 16.2]
z_data = [6,12,18,24]
n_data = np.arange(5)
m_data = np.zeros([5,1])
l_data = np.zeros([5,1])
for i in range(5):
m_data[i] = LinearFunction(n_data[i])
l_data[i] = LinearFunction2(n_data[i])
plt.scatter(x_data,y_data)
plt.plot(n_data,m_data,'r')
plt.plot(n_data,l_data,'g')
plt.show()
上面的实例中存在一个问题,那就是我们是采用穷举的方式进行a值的预测,这样就要求a的最佳值最好我们所选取的范围内,否则只能得到一个局部最优值,但是这个值是不是全局最优值就不知道了. 也就是说,上面的例子中, 如果我们选取的(0,4)的范围不对,是(3,6), 那么我们得到的预测结果就不是最优的了.
那么,有没有什么方法可以避免这个问题,可以让程序自己找到一个最小的Loss呢?
局部最小值与全局最小值, 我们可以认为上面的方法很有可能找到一个局部最小值. 画图说明局部最小值的问题
接下来,我们采用梯度的方法进行网络的改写
import numpy as np
from matplotlib import pyplot as plt
data_x = [1, 2, 3]
data_y = [2, 4, 6]
loss_list = list()
a_list = list()
alpha = 0.01
def forward(x):
return a * x
def lossFunction(x, y):
y_pred = forward(x)
loss = (y_pred - y) ** 2
return loss
def predict(x, a_):
return a_ * x
def gradient(a, x, y):
a = a - alpha * 2 * (a * x - y) * x
return a
if __name__ == '__main__':
a = 0
for epoch in range(1000):
# for a in np.arange(0, 4, 0.1):
sum_loss = 0
for i in range(3):
sum_loss += lossFunction(data_x[i], data_y[i])
a = gradient(a, data_x[i], data_y[i])
loss_list.append(sum_loss / 3)
a_list.append(a)
plt.subplot(211)
plt.plot(a_list)
plt.subplot(212)
plt.plot(loss_list)
plt.show()
plt.figure()
plt.plot(a_list, loss_list)
plt.xlabel('a')
plt.ylabel('loss')
plt.show()
min_value = min(loss_list)
index_lossMin = loss_list.index(min_value)
print(index_lossMin)
proper_a = a_list[index_lossMin]
print(proper_a)
print("Please input the desired x:")
desired_x = input()
print(f"The predict output for the linear model is {predict(float(desired_x), proper_a)}")
import time
import numpy as np
from matplotlib import pyplot as plt
import random
x_data = [1,2,3]
y_data = [2,4,6]
loss_list = list()
a_b_list = list()
def forward(a, x):
return a*x
def lossFunction(a,x,y):
y_pred = forward(a,x)
loss = (y - y_pred)**2
return loss
alpha = 0.1
def gradient(x, a, y):
a = a - alpha*2*x*(x*a -y)
return a
a_list = list()
b_list = list()
if __name__ == '__main__':
a = random.randint(0, 10)
for epoch in range(100):
sum_loss = 0
for i in range(3):
sum_loss += lossFunction(a, x_data[i], y_data[i])
a = gradient(x_data[i], a, y_data[i])
loss_list.append(sum_loss/3)
a_list.append(a)
b_list.append(epoch)
print(f'epoch = {epoch}, a = {a}, loss = {sum_loss/3}')
time.sleep(0.5)
# time.sleep(0.5)
# plt.plot(a_list, loss_list)
plt.plot(b_list, loss_list)
plt.show()
优点、缺点和参数 线性模型的主要参数是正则化参数,在回归模型中叫作alpha,在LinearSVC和LogisticRegression中叫作C。alpha值较大或C值较小,说明模型比较简单。特别是对于回归模型而言,调节这些参数非常重要。通常在对数尺度上对C和alpha进行搜索。此外还需要确定的是用L1正则化还是L2正则化。如果假定只有几个特征是真正重要的,那么应该用L1正则化,否则应默认使用L2正则化。如果模型的可解释性很重要的话,使用L1也会有帮助。由于L1只用到几个特征,所以更容易解释哪些特征对模型是重要的,以及这些特征的作用。 线性模型的训练速度非常快,预测速度也很快。这种模型可以推广到非常大的数据集,对稀疏数据也很有效。如果数据包含数十万甚至上百万个样本,可能需要研究如何使用LogisticRegression和Ridge 模型的 solver='sag' 选项,在处理大型数据时,这一选项比默认值要更快。其他选项还有SGDClassifier类和SGDRegressor类,它们对以上的线性模型实现了可扩展性更强的版本。 线性模型的另一个优点在于,利用我们之前见过的用于回归和分类的公式,理解如何进行预测是相对比较容易的。不幸的是,往往并不完全清楚系数为什么是这样的。如果数据集中包含高度相关的特征,这一问题尤为突出。在这种情况下,可能很难对系数做出解释。 如果特征数量大于样本数量,线性模型的表现通常都很好。它也常用于非常大的数据集,只是因为训练其他模型并不可行。但在更低维的空间中,其他模型的泛化性能可能更好。
知识点回顾:链式传播法则
y=f(g(x))y=f(g(x)) 则有 dydx=∂f∂g∂g∂xdydx=∂f∂g∂g∂x
在pytorch中,tensor的数据类型中,一方面包含有数据的数值,还有一个数据包含有数据的梯度。 如下例子
import torch
a = torch.tensor([2, 3], requires_grad=True, dtype=torch.float)
b = torch.tensor([6, 4], requires_grad=True, dtype=torch.float)
Q = 3 * a ** 3 - b ** 2
extern_gradient = torch.tensor([1, 1])
Q.backward(gradient=extern_gradient)
print(a.grad)
print(b.grad)
我们定义Q=3a3−b2Q=3a3−b2, 则可以计算出 ∂Q∂a=9a2∂Q∂a=9a2 且 ∂Q∂b=−2b∂Q∂b=−2b, 然后我们将a,ba,b的值带入就可以计算出对应的梯度值。
import torch
x = torch.tensor(3, dtype=torch.float32, requires_grad=True)
y = torch.tensor(4, dtype=torch.float32, requires_grad=True)
b = torch.tensor(5, dtype=torch.float32, requires_grad=True)
z = x*y + b
"Z = xy"
print(z)
z.backward()
print(z.requires_grad, x.grad, y.grad, b.grad)
在pytorch中,可以通过backward()自动的反向计算梯度,对应的数据类型应该是torch中的tenser. 在上一个例子中,我们需要计算的是对应变量aa的梯度,因此,我们对上一个例子进行修改。首先,引入pytorch的包, import torch.
定义数据类型为 a= torch.Tensor([7.0]) 且声明 a. requires_grad=True
from matplotlib import pyplot as plt
import torch
data_x = [1, 2, 3]
data_y = [2, 4, 6]
loss_list = list()
a_list = list()
alpha = 0.01
def forward(x):
return a * x
def lossFunction(x, y):
y_pred = forward(x)
loss = (y_pred - y) ** 2
return loss
if __name__ == '__main__':
a = torch.Tensor([7.0])
a.requires_grad = True
for epoch in range(1000):
# for a in np.arange(0, 4, 0.1):
sum_loss = 0
for i in range(3):
sum_loss += lossFunction(data_x[i], data_y[i])
l = lossFunction(data_x[i],data_y[i])
l.backward()
a.data = a.data - alpha*a.grad
a.grad = None
a_list.append(a.data)
# a = gradient(a, data_x[i], data_y[i])
loss_list.append(sum_loss / 3)
print(a_list)
plt.subplot(211)
plt.plot(a_list)
plt.subplot(212)
plt.plot(loss_list)
plt.show()
11
利用pytorch实现线性回归
本节课我们将采用pytorch标准模块来实现上面的例子。
优化器参考文档https://pytorch.org/docs/stable/optim.html
计算流程如下所示:
for input, target in dataset:
output = model(input)
loss = loss_fn(output, target)
optimizer.zero_grad()
loss.backward()
optimizer.step()
同时之前的例子可以改写为:
import torch
from matplotlib import pyplot as plt
x_data = torch.tensor([[1], [2], [3]], dtype=torch.float)
y_data = torch.tensor([[2], [4], [6]], dtype=torch.float)
class LinearExample(torch.nn.Module):
def __init__(self):
super(LinearExample, self).__init__()
self.linear = torch.nn.Linear(1, 1)
def forward(self, x):
y_pred = self.linear(x)
return y_pred
model = LinearExample()
criterion = torch.nn.MSELoss(reduction='sum')
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
epoch_list = list()
a_list = list()
if __name__ == '__main__':
for epoch in range(100):
y_hat = model(x_data)
loss = criterion(y_hat, y_data)
a_list.append(model.linear.weight.item())
epoch_list.append(epoch)
optimizer.zero_grad()
loss.backward()
optimizer.step()
plt.plot(epoch_list, a_list)
plt.show()
12逻辑斯特回归问题:用于处理二分类问题-->二分类表示输出或者是0, 或者是1, 输出只有两种选择。
逻辑回归(Logistic regression 或logit regression),即逻辑模型(英语:Logit model,也译作“评定模型”、“分类评定模型”)是离散选择法模型之一,属于多重变量分析范畴,是社会学、生物统计学、临床、数量心理学、计量经济学、市场营销等统计实证分析的常用方法。虽然叫做回归其实是个分类模型。逻辑回归实际上是用sigmoid函数将线性回归进行了归一化,把输出值压缩到0-1之间,这个值代表的是发生的概率。 对这张图一定不陌生,它在神经网络中作为常用的激活函数,将输出值控制在0-1之间。他就是Sigmoid函数!当然它也被称为Logistic函数,这就是逻辑斯蒂回归算法的由来。还有一点要注意的是,虽然名字叫做逻辑斯蒂回归,但他解决的其实是分类问题。其实原理很简单,对于二分类任务来说,大于0就是正类,小于0就是负类。
损失函数采用交叉熵
import time
import matplotlib.pyplot as plt
import numpy as np
import torch
import torch.nn.functional as F
x_data = torch.tensor([[1],[2],[3]],dtype=torch.float32)
y_data = torch.tensor([[0],[0],[1]],dtype=torch.float32)
class Model(torch.nn.Module):
def __init__(self):
super(Model, self).__init__()
self.linear = torch.nn.Linear(1,1)
def forward(self,x):
y_pred = self.linear(x)
return torch.sigmoid(y_pred)
model = Model()
criterion = torch.nn.BCELoss(size_average=False)
optim = torch.optim.SGD(model.parameters(),lr=0.01)
for epoch in range(1000):
y_pred = model(x_data)
loss = criterion(y_pred,y_data)
print(epoch, loss.item())
# time.sleep(0.1)
optim.zero_grad()
loss.backward()
optim.step()
x = np.linspace(0,10,200)
x_t = torch.tensor(x,dtype=torch.float32).view((200,1))
y_t = model(x_t)
y = y_t.data.numpy()
plt.plot(x,y)
plt.show()
网络的层数越多,学习能力越强。那么,我们不就可以一直增加网络的层数了吗?答案是否定的,一方面,由于网络层数越多,那么学习能力越强,但是也会把系统中的噪声也学习出来。在真是的环境中,系统的噪声在不同的环境下可能会有差异的。这就要求网络要有一定的泛化能力。
分类预测问题: 保险行业预测问题
数据类型一般选择为float32, 这是因为1, 在中低端显卡中,多支持的是32位的浮点运算。在高端显卡中才支持64为的浮点运算。 2 在神经网络的计算过程中,32位浮点数足够使用
下面的例子显示一个糖尿病例子的预测问题:
import numpy as np
from matplotlib import pyplot as plt
import torch
data_xy = np.loadtxt('/home/chasing/Documents/pytorchbooklit/diabetes.csv.gz', delimiter=',', dtype=np.float32)
x_data = torch.from_numpy(data_xy[:,:-1])
y_data = torch.from_numpy(data_xy[:,-1]).reshape(-1,1)
class LinearExample(torch.nn.Module):
def __init__(self):
super(LinearExample, self).__init__()
self.linear1 = torch.nn.Linear(8,6)
self.linear2 = torch.nn.Linear(6,4)
self.linear3 = torch.nn.Linear(4,1)
# self.linear4 = torch.nn.Linear(2,1)
self.sigmoid = torch.nn.Sigmoid()
self.relu = torch.nn.ReLU()
def forward(self,x):
x = self.relu(self.linear1(x))
x = self.relu(self.linear2(x))
x = self.linear3(x)
# x = self.linear4(x)
return self.relu(x)
# return self.sigmoid(x)
model = LinearExample()
criterion = torch.nn.BCELoss(reduction='mean')
optimizer = torch.optim.SGD(model.parameters(),lr=1e-2)
loss_list = list()
if __name__ == '__main__':
for epoch in range(300):
y_pred = model(x_data)
loss = criterion(y_pred, y_data)
loss_list.append(loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
plt.plot(loss_list)
plt.show()
在深度学习中,由于问题的复杂性,我们往往会使用较深层数的网络进行训练,相信很多炼丹的朋友都对调参的困难有所体会,尤其是对深层神经网络的训练调参更是困难且复杂。在这个过程中,我们需要去尝试不同的学习率、初始化参数方法(例如Xavier初始化)等方式来帮助我们的模型加速收敛。深度神经网络之所以如此难训练,其中一个重要原因就是网络中层与层之间存在高度的关联性与耦合性。下图是一个多层的神经网络,层与层之间采用全连接的方式进行连接。
我们规定左侧为神经网络的底层,右侧为神经网络的上层。那么网络中层与层之间的关联性会导致如下的状况:随着训练的进行,网络中的参数也随着梯度下降在不停更新。一方面,当底层网络中参数发生微弱变化时,由于每一层中的线性变换与非线性激活映射,这些微弱变化随着网络层数的加深而被放大(类似蝴蝶效应);另一方面,参数的变化导致每一层的输入分布会发生改变,进而上层的网络需要不停地去适应这些分布变化,使得我们的模型训练变得困难。上述这一现象叫做Internal Covariate Shift。
采用一个batch会提升并行计算能力,提升计算的速度。采用一组数据会避免陷入鞍点(局部最优), 本历程中,我们采用dataset构造数据集。
from torch.utils.data import DataLoader
from torch.utils.data import Dataset
import numpy as np
import torch
from matplotlib import pyplot as plt
class LinearExample(torch.nn.Module):
def __init__(self):
super(LinearExample, self).__init__()
self.linear1 = torch.nn.Linear(8,6)
self.linear2 = torch.nn.Linear(6,4)
self.linear3 = torch.nn.Linear(4,1)
# self.linear4 = torch.nn.Linear(2,1)
self.sigmoid = torch.nn.Sigmoid()
self.relu = torch.nn.ReLU()
def forward(self,x):
x = self.relu(self.linear1(x))
x = self.relu(self.linear2(x))
x = self.linear3(x)
# x = self.linear4(x)
return self.relu(x)
# return self.sigmoid(x)
class DiabetesDatset(Dataset):
def __init__(self):
data_xy = np.loadtxt('/home/chasing/Documents/pytorchbooklit/diabetes.csv.gz', delimiter=',', dtype=np.float32)
self.len = data_xy.shape[0]
self.data_x = torch.from_numpy(data_xy[:,:-1])
self.data_y = torch.from_numpy(data_xy[:,-1]).reshape(-1,1)
def __getitem__(self, index):
return self.data_x[index], self.data_y[index]
def __len__(self):
return self.len
model = LinearExample()
dataset = DiabetesDatset()
train_loader = DataLoader(dataset=dataset, batch_size=32, shuffle=True, num_workers=2)
criterion = torch.nn.BCELoss(size_average=True)
optimizer = torch.optim.SGD(model.parameters(), lr=1e-2)
loss_list = list()
if __name__ == '__main__':
for epoch in range(100):
for i, data in enumerate(train_loader, 0):
inputs, labels = data
y_pred = model(inputs)
loss = criterion(y_pred, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
loss_list.append(loss)
plt.plot(loss_list)
plt.show()
13
采用softmax函数进行
P(y=i)=ezi∑kj=0ezjj=0,1,2,3...i...kP(y=i)=ezi∑j=0kezjj=0,1,2,3...i...k
保证了求和后为1, 且每个值都是正数, exex是一个单调增函数
同时计算损失的时候,之前的BCE已经不再适用(该问题是针对的二分类问题), 所以引入一种新的损失计算方法 CrossEntropyLoss(), 计算表达式为
−ylogy^−ylogy^
import torch
criterion = torch.nn.CrossEntropyLoss()
y = torch.LongTensor([2, 0, 1])
y1 = torch.tensor([[0.1,0.2,0.9],
[1.1,0.1,0.2],
[0.2,2.1,0.1]])
y2 = torch.tensor([[0.8,0.2,0.3],
[0.2,0.3,0.5],
[0.2,0.2,0.5]])
loss1 = criterion(y1, y)
loss2 = criterion(y2, y)
print(f'loss1= {loss1}, loss2={loss2}')
手写数字识别例题:
import torch
from matplotlib import pyplot as plt
from torchvision import datasets
from torch.utils.data import DataLoader
from torchvision import transforms
import torch.optim as optim
import numpy as np
batch_size = 64
batch_size_test = 100
data_transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))])
minist_tainloader = datasets.MNIST(root='./', train=True, download=True, transform=data_transform)
minist_testloader = datasets.MNIST(root='./', train=False, download=True, transform=data_transform)
trainloader = DataLoader(minist_tainloader, batch_size=batch_size, shuffle=True)
testloader = DataLoader(minist_testloader, batch_size=batch_size_test, shuffle=False)
class Model(torch.nn.Module):
def __init__(self):
super(Model, self).__init__()
self.linear1 = torch.nn.Linear(784, 512)
self.linear2 = torch.nn.Linear(512, 256)
self.linear3 = torch.nn.Linear(256, 128)
self.linear4 = torch.nn.Linear(128, 64)
self.linear5 = torch.nn.Linear(64, 10)
self.relu = torch.nn.ReLU()
def forward(self, x):
x = x.view(-1, 784)
x = self.relu(self.linear1(x))
x = self.relu(self.linear2(x))
x = self.relu(self.linear3(x))
x = self.relu(self.linear4(x))
return self.linear5(x)
model = Model()
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=1e-2, momentum=0.5)
loss_list = list()
def test_accuracy():
correct = 0
with torch.no_grad():
for data in testloader:
images, labels = data
pred = model(images)
total_num = 0
correct = 0
for i in range(batch_size_test):
labels_np = labels.numpy().tolist()
pred_np = pred.numpy().tolist()
total_num += 1
if labels_np[i] == pred_np[i].index(max(pred_np[i])):
correct += 1
print(f'Accuracy = {correct/total_num}, i = {i}')
if __name__ == '__main__':
for epoch in range(10):
for i, data in enumerate(trainloader, 0):
inputs, label = data
outputs = model(inputs)
optimizer.zero_grad()
loss = criterion(outputs, label)
loss_list.append(loss)
loss.backward()
optimizer.step()
print(f'[{epoch}]: loss = {loss}')
plt.plot(loss_list)
plt.show()
test_accuracy()
通过PIL识别图像
import numpy as np
from PIL import Image
a = Image.open('test.jpg')
c = a.convert('L')
c.show()
# print(c)
im = np.array(a)
im_gray = np.array(c)
print(im_gray.shape)
print(im_gray)
print(im.shape)
# print(im)
b = np.array([[[1,2,3],[2,3,3],[3,4,5]],[[2,1,2],[3,4,5],[4,5,6]]])
# print(b.shape)
# a.show()
# print(a)
14
卷积神经网络
首先需要完成卷积网络的维度的推断
import torch
width, height = 28, 28
in_channle = 1
batch_size = 1
inputs = torch.randn(batch_size, in_channle,
width, height)
print(inputs.shape)
conv_lay1 = torch.nn.Conv2d(in_channels=1,
out_channels=10,
kernel_size=5)
output1 = conv_lay1(inputs)
print(output1.shape)
maxpool_lay = torch.nn.MaxPool2d(kernel_size=2)
output2 = maxpool_lay(output1)
print(output2.shape)
conv_lay2 = torch.nn.Conv2d(in_channels=10,
out_channels=20,
kernel_size=5)
output3 = conv_lay2(output2)
print(output3.shape)
output4 = maxpool_lay(output3)
print(output4.shape)
output5 = output4.view(1, -1)
linear_lay = torch.nn.Linear(320, 10)
output6 = linear_lay(output5)
print(output6.shape)
下面将手写数字识别的程序修改成带有卷积操作的深度神经网络结构
import torch
from matplotlib import pyplot as plt
from torchvision import datasets
from torch.utils.data import DataLoader
from torchvision import transforms
import torch.optim as optim
import numpy as np
batch_size = 64
data_transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))])
minist_tainloader = datasets.MNIST(root='./', train=True, download=True, transform=data_transform)
minist_testloader = datasets.MNIST(root='./', train=False, download=True, transform=data_transform)
trainloader = DataLoader(minist_tainloader, batch_size=batch_size, shuffle=True)
testloader = DataLoader(minist_testloader, batch_size=batch_size, shuffle=False)
class Model(torch.nn.Module):
def __init__(self):
super(Model, self).__init__()
self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5)
self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5)
self.pooling = torch.nn.MaxPool2d(kernel_size=2)
self.linear = torch.nn.Linear(320, 10)
self.relu = torch.nn.ReLU()
def forward(self, x):
batch_size = x.size(0)
x = self.relu(self.pooling(self.conv1(x)))
x = self.relu(self.pooling(self.conv2(x)))
x = x.view(batch_size, -1)
x = self.linear(x)
return x
model = Model()
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=1e-2, momentum=0.5)
loss_list = list()
def test_accuracy():
correct = 0
with torch.no_grad():
for data in testloader:
images, labels = data
pred = model(images)
total_num = 0
correct = 0
for i in range(batch_size):
labels_np = labels.numpy().tolist()
pred_np = pred.numpy().tolist()
total_num += 1
if labels_np[i] == pred_np[i].index(max(pred_np[i])):
correct += 1
print(f'Accuracy = {correct / total_num}')
if __name__ == '__main__':
for epoch in range(3):
for i, data in enumerate(trainloader, 0):
inputs, label = data
outputs = model(inputs)
optimizer.zero_grad()
loss = criterion(outputs, label)
loss_list.append(loss)
loss.backward()
optimizer.step()
print(f'[{epoch}]: loss = {loss}')
plt.plot(loss_list)
plt.show()
test_accuracy()
RNN 循环神经网络
主要用于处理序灌问题(输入数据之间存在一定的相关性)
下面给出一个学习实例, 主要完成的输入数据为"hello" -->"ohlol"
import torch
batch_size = 1
seq_len = 5
input_size = 4
hidden_size = 4
num_layer = 1
idx2char = ['e', 'h', 'l', 'o']
x_data = [1, 0, 2, 2, 3]
y_data = [3, 1, 2, 3, 2]
one_hot_lookup = [[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]]
x_one_hot = [one_hot_lookup[x] for x in x_data]
inputs = torch.Tensor(x_one_hot).view(seq_len, batch_size, input_size)
labels = torch.LongTensor(y_data)
class NLPModel(torch.nn.Module):
def __init__(self):
super(NLPModel, self).__init__()
self.rnn = torch.nn.RNN(input_size=input_size, hidden_size=hidden_size,
num_layers=num_layer)
def forward(self, x):
hidden = torch.zeros(num_layer, batch_size, hidden_size)
out, _ = self.rnn(x, hidden)
return out.view(-1, hidden_size)
model = NLPModel()
criterion = torch.nn.CrossEntropyLoss()
optim = torch.optim.Adam(model.parameters(), lr=0.05)
for epoch in range(35):
outputs = model(inputs)
loss = criterion(outputs, labels)
optim.zero_grad()
loss.backward()
optim.step()
_, idex = outputs.max(dim= 1)
idx = idex.data.numpy()
print('Predicted:', ''.join([idx2char[x] for x in idx]), end='')
print(f'\t epoch={epoch}, loss={loss.item()}')