<深度学习入门与TensorFlow实践> - 笔记 I
之前学了一个深度学习应用开发,学了一段时间,后来就没学了。
确实是"靡不有初,鲜克有终",现在不愿意再继续之前的学。我又找了一本书从头开始,这本书的名字是<深度学习入门与TensorFlow实践>。
数(scalar)
是一个数字。
简直是废话。
不过这才刚开始嘛。
多个数字有序的放在一起,可以构成向量
。比如下图的x:
你看左边的是行向量,右边的是列向量。
多个数字以二维的形式表示的,可以构成矩阵
。比如X:
矩阵中的行和列的数量就是矩阵的维度。上面是三行两列,因此维度是3x2
在运算中有一类特殊的矩阵经常用到,那就是单位矩阵
(identity matrix)。就是这个方向 \ 的对角线上全是1,其他位置是0。
如果把多个数字写成大于二维的形式,就可以得到张量
。就像下面这样。
这是一个三维的张量,维度是3x4x2。
TensorFlow里的Tensor
就是张量。
如果把维度对应到现实世界,那么我们所处的物质世界明显是一个三维世界。再加上不断流淌的时间,可以视为四维的。我能够理解到的最大维数就是四维了。在一些学习中,好像可以简单抽象的推到为五维、六维…,但是我实在是难以想象那些是什么样子?也许五维是两个平行世界?六维是三个平行世界?…
最常用的矩阵运算是矩阵的转置。转置就像是翻转。就像是一个扑克牌,原来是竖着拿的,把它变成翻面横着拿了。
矩阵的基本运算就是加减乘除。加减法如果这两个矩阵的维度是一样的,就非常好理解。矩阵也可以和行向量进行加减,要求行向量的列数和矩阵的列数是一样的。
矩阵的乘法,如果两个矩阵的维度一样,也非常好理解,这种叫做逐点相乘
(element-wise product)。
还有一种惩罚就是我们在线性代数中的乘法。叫做点乘
。点乘是这样的:
然后是向量和矩阵的范数,不好理解。
还有微积分的导数和求导法则,也不好看。
接下来是概率论的一些基本的概念。
随机变量
就是一个取值不确定的变量。
这个在工作生活中应用的实在是太广泛了。比如老板问你这件事情明天能不能搞完?一般情况下,你的回答可能就是一个随机变量。
随机变量可以分为两种类型:连续型和离散型。
随机变量的分布
用来描述随机变量出现某种结果的可能性。可以用一些分布函数来表示。
常见的概率分布有几种。这里只看最常见的一种概率分布,就是正态分布
也叫高斯分布。
很多情况下,还有一种叫做条件概率
。就是我们会关心当A事件发生时,B事件发生的概率。在生活中也是经常有场景的,比如当小孩长时间的磨磨唧唧的做事的时候,你发火的概率。
Anaconda
,用于管理和隔离环境env
。因为在实际中我们经常会需要用到不同的版本的python,甚至于特定版本的python模块包。这种情况下就非常好用,可以让这些环境共存。Anaconda帮你管理了。命令是conda
,具体使用和功能参数就不说了。
Jupyter Notebook
是WEB应用,可方便的创建、运行和分享python代码。conda install jupyter notebook就可以安装。安装好启动后就自动打开网页,就可以使用了。ctl-c按2次可以退出。有命令模式和编辑模式。有代码框和标记框(markdown cell
)。
然后就是Python的介绍。包括常见的数据类型,基本算术运算,比较和布尔运算,如何载入额外的模块和包。
基本数据结构有列表、元组、字典和集合。控制结构,内建函数和自定义函数。
然后介绍numpy库,他可以实现快速的算数运算,特别是矩阵运算,运算内部是通过C语言实现的,所以比较快。他包含两种基本数据类型:数组(array)
和矩阵(matrix)
。
然后介绍基于numpy库的pandas库,可以用于数据分析,数据清理和数据准备。他的数据结构主要有两种:序列(series)
和数据表(dataframe)
。
画图工具mathplotlib是在Python中最流行的,可以很方便的实现数据的图形化展示。使用前要载入mathplotlib的pyplot
。
其实这些知识在华为云的AI gallery里面都有相应的入门教程。
接下来就是讲线性模型了。线性模型相对比较简单,但是他是学习比较复杂的深度学习模型的一个基础,而且线性模型本身也具有广泛的用途。
这里讲了线性模型中的线性回归模型和logistic模型。线性回归模型用于处理回归问题
。logistic模型用于处理分类问题
。
线性回归模型可以写作如下的形式:
其中那一系列的x
都是已知,而且比较容易测量到的向量。一系列的w
是权重或者叫做系数。b
是一个常数,叫做截距或偏差。
是误差,代表了没有在x里体现但对y有影响的信息。
这其中一系列的w和b都是未知数,就是模型参数
。
下面是一个简单的例子来介绍线性回归模型。
数据是在多个市场的3个不同渠道的广告投入以及商品销量。
这个模型的意义也就很明白了,那就是找出在这3个不同渠道广告投入与最终的商品销量之间的关系。
先把数据可视化:
%config InlineBackend.figure_format='retina'
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
ad = pd.read_csv('./Ad.csv')
ad.head()
plt.scatter('TV','sales',data=ad,label='TV',marker='D')
plt.scatter('radio','sales',data=ad,marker='o',label='radio')
plt.scatter('newspaper','sales',data=ad,marker='s',label='newspaper')
plt.legend(loc='lower right')
plt.xlabel('Advertising Budgets',fontsize=16)
plt.ylabel('Sales',fontsize=16)
plt.show
再来看一下数学上对这些数据的表达,
第1个观测点的输入向量 x1=(x11,x12,x13),
第2个观测点的输入向量 x2=(x21,x22,x23)
那么因变量矩阵X表示为:
因变量向量y表示为:
前一节已经讲过线性回归模型的数学公式的表达,这里我们先假设给定截距项b和自变量权重w,至于误差这里不管,那么我们就可以写出预测函数了。
def linear_mode(input,weight,b):
prediction=np.sum(input*weight)+b
return prediction
b=10
w=np.array([0.1,0.1,0.1])
input_0=ad.values[0][0:3]
print('第一个观测点的自变量向量:'+str(input_0))
pred=linear_mode(input_0,w,b)
print('第一个观测点的预测值:'+str(pred))
第一个观测点的自变量向量:[230.1 37.8 69.2]
第一个观测点的预测值:43.71
继续线性模型,
有了预测值,和真实值比较一下,就知道预测结果准确不准确?用预测值减去真实值 ,如果是正数,说明预测值偏高,如果是负数说明偏低。通常使用差的平方来衡量预测误差。
target=ad.values[0][3]
loss=(pred-target)**2
print(loss)
#466.9921
而用残差平方之和,可以用来衡量模型总的预测误差。
rss=0
for i in range(len(ad)):
input=ad.values[i][0:3]
pred=linear_mode(input,w,b)
target=ad.values[i][3]
rss+=(pred-target)**2/2/len(ad)
print(rss)
#143.69051025000013
这里乘以常数1/2,说是为了稍后估计b和w方便一些。
很自然的,我们要最小化 ,得到这种情况下b和w的估计值。
也叫做目标函数或者损失函数,它值叫做预测误差或者模型误差。求它的最小值的方法有很多,最常见的方法是求偏导数
,然后令这些偏导数等于零,解方程得到b和w的估计值。但是这个方法只适合少数结构比较简单的模型(比如线性回归模型),不能求解深度学习这类复杂模型的参数。
所以下面介绍的是深度学习中常用的优化算法:梯度下降法
。其中有三个不同的变体:随机梯度下降法、全数据梯度下降法、和批量随机梯度下降法。
继续线性回归模型,这里先说随机梯度下降法
。
先考虑一个简单的模型,没有截距,只有一个自变量:
y=xw
当观测点为(x=0.5,y=0.8),w=3时,残差平方和是
x,y=0.5,0.8
w=3
rss=(y-x*w)**2/2
print(rss)
#0.24499999999999997
梯度
(gradient)记作
,函数RSS(w)关于参数w的梯度,记作
,简洁的记作
。它是RSS(w)关于w的偏导数,即:
对于这里的简单模型,就有:
所以w=3时,
=(0.5x3-0.8)x0.5=0.35
梯度就是w=3处的切线的斜率,这里梯度是正。如下图
pred=x*w
grad=(pred-y)*x
print('w=3时,预测值:'+str(pred))
print('w=3时,残差平方和:'+str(round(rss,ndigits=3)))
print('w=3时,RSS(w)的梯度:'+str(grad))
#w=3时,预测值:1.5
#w=3时,残差平方和:0.245
#w=3时,RSS(w)的梯度:0.35
w_vec=np.linspace(-1,4,100)
rss_vec=[]
for w_tmp in w_vec:
rss_tmp=(y-x*w_tmp)**2/2
rss_vec.append(rss_tmp)
plt.plot(w_vec,rss_vec)
plt.scatter(w,rss,s=100,c='y',marker='o')
plt.plot(np.linspace(2.5,3.5,50),\
np.linspace(2.5,3.5,50)*0.35-0.805,\
'--',linewidth=2.0)
plt.xlabel('w',fontsize=16)
plt.ylabel('RSS',fontsize=16)
#ax=plt.gca()
#ax.set_aspect(1)
plt.show()
这个切线的斜率看上去不是0.35的样子啊,明显要更陡一下。这是因为x轴和y轴的比例不一致而导致的视觉效果,如果轴的比例之后显示是这样的,这样看上去就对了
这里预测值大于实际值,差值是0.7,很自然的,要让预测值更接近实际值的话,需要让预测值变小。想让预测值变小,很简单的就让w变小,变小多少呢?这里的梯度是一个正值,那就先变小一个梯度呗。也就是w-grad。
来看一下梯度为负的情况。当w=0时,
x,y=0.5,0.8
w=0
pred=x*w
rss=(pred-y)**2/2
grad=(pred-y)*x
print('w=0时,预测值:'+str(pred))
print('w=0时,残差平方和:'+str(round(rss,ndigits=3)))
print('w=0时,RSS(w)的梯度:'+str(grad))
#w=0时,预测值:0.0
#w=0时,残差平方和:0.32
#w=0时,RSS(w)的梯度:-0.4
plt.plot(w_vec,rss_vec)
plt.scatter(w,rss,s=100,c='y',marker='o')
plt.plot(np.linspace(-0.5,0.5,50),\
np.linspace(-0.5,0.5,50)*(-0.4)+0.32,\
'--',linewidth=2.0)
plt.xlabel('w',fontsize=16)
plt.ylabel('RSS',fontsize=16)
#ax=plt.gca()
#ax.set_aspect(1)
plt.show()
当w=0时,预测值小于真实值0.8。很自然的,要让预测值更接近实际值的话,需要让预测值变大。想让预测值变大,很简单的就让w变大,变大多少呢?这里的梯度是一个负值,那就先变大一个负的梯度呗。就是w+(-grad),巧了,也是w-grad。
所以无论w的初始值是在哪边, 都可以让w朝着RSS变小的方向移动。RSS最小的地方,就是我们寻找的地方,因为在这个地方预测值和真实值的差异最小,也就是说预测值最接近真实值。
这个算法就是梯度下降法,在更新w的过程中,加入了一个系数
,他是一个比较小的正数,叫做学习步长
,这样可以让w更新的速度变慢一些,使得w更容易收敛。
继续线性回归模型,前面说了如何更新模型参数w,让预测值接近于真实值。现在我们来尝试迭代多次,看看效果。
从w=0开始
#w初始值给0
x,y=0.5,0.8
w=0;lr=0.5 #lr学习率=0.5
pred=x*w
loss=((pred-y)**2)/2
grad=(pred-y)*x
print('自变量:'+str(x))
print('因变量:'+str(y))
print('初始权重:'+str(w))
print('预测值:'+str(pred))
print('差值:'+str(round(loss,ndigits=3)))
print('梯度:'+str(grad))
自变量:0.5
因变量:0.8
初始权重:0
预测值:0.0
差值:0.32
梯度:-0.4
然后更新w的值,做第一次迭代:
#第一次迭代
w=w-lr*grad
pred=x*w
loss=((pred-y)**2)/2
grad=(pred-y)*x
print('自变量:'+str(x))
print('因变量:'+str(y))
print('权重:'+str(w))
print('预测值:'+str(pred))
print('差值:'+str(round(loss,ndigits=3)))
print('梯度:'+str(round(grad,ndigits=3)))
自变量:0.5
因变量:0.8
权重:0.2
预测值:0.1
差值:0.245
梯度:-0.35
可以看到预测值和真实值的差值在变小(0.32 > 0.245),也就是在向着不断的收敛的方向。
接着看梯度下降,用循环来实现。
#循环迭代20次
x,y=0.5,0.8
w=0;lr=0.5 #lr学习率=0.5
w_record=[]
loss_record=[]
for iter in range(20):
pred=x*w
loss=((pred-y)**2)/2
w_record.append(w)
loss_record.append(loss)
delta=pred-y
w=w-lr*(delta*x)
if (iter%5==0 or iter==19):
print('iter: %2d; w: %0.2f; Loss: %0.3f'%(iter,w,loss))
w_record.append(w)
loss_record.append((x*w-y)**2/2)
iter: 0; w: 0.20; Loss: 0.320
iter: 5; w: 0.88; Loss: 0.084
iter: 10; w: 1.23; Loss: 0.022
iter: 15; w: 1.41; Loss: 0.006
iter: 19; w: 1.49; Loss: 0.002
把这循环的过程中的变化可视化出来:
#模型参数w 和 残差平方和RSS 随迭代的变化曲线
w_vec=np.linspace(-1,4,100)
rss_vec=[]
for w_tmp in w_vec:
rss_tmp=(y-x*w_tmp)**2/2
rss_vec.append(rss_tmp)
plt.plot(w_vec,rss_vec)
plt.scatter(0,0.32,s=100,c='y',marker='o')
for i in range(len(w_record)-1):
plt.arrow(w_record[i],loss_record[i],\
w_record[i+1]-w_record[i],\
loss_record[i+1]-loss_record[i],width=0.01,\
color='y',head_width=0.05)
plt.xlabel('w',fontsize=16)
plt.ylabel('RSS',fontsize=16)
plt.show()
好了我们上面说的是最简单的情况,因为为了学习,是一个权重或叫参数w,一个自变量x,并且只有一个观测点(x,y)。
在实际情况中,一般就不仅仅是学习的那么简单的情况。
数据会包含多个自变量,多个权重,很多个观测点。
用 表示包含p个权重或参数的损失函数,它的梯度可以表示为:
它是由函数 对各个参数的偏导数构成的向量。
上面就是随机梯度下降法
(Stochastic Gradient Descent
SGD)。随机是指每次只使用一个观察点计算梯度,在实现随机梯度下降的过程中,随机抽取观测点来计算梯度并更新参数。
- 点赞
- 收藏
- 关注作者
评论(0)