<深度学习入门与TensorFlow实践> - 笔记 I

举报
黄生 发表于 2022/08/19 08:29:49 2022/08/19
【摘要】 之前学了一个深度学习应用开发,学了一段时间,后来就没学了。确实是"靡不有初,鲜克有终",现在不愿意再继续之前的学。我又找了一本书从头开始,这本书的名字是<深度学习入门与TensorFlow实践>。数(scalar)是一个数字。简直是废话。不过这才刚开始嘛。多个数字有序的放在一起,可以构成向量。比如下图的x:你看左边的是行向量,右边的是列向量。多个数字以二维的形式表示的,可以构成矩阵。比如X:...

之前学了一个深度学习应用开发,学了一段时间,后来就没学了。
确实是"靡不有初,鲜克有终",现在不愿意再继续之前的学。我又找了一本书从头开始,这本书的名字是<深度学习入门与TensorFlow实践>。

数(scalar)是一个数字。
简直是废话。
不过这才刚开始嘛。
多个数字有序的放在一起,可以构成向量。比如下图的x:
image.png

你看左边的是行向量,右边的是列向量。
多个数字以二维的形式表示的,可以构成矩阵。比如X:
image.png
矩阵中的行和列的数量就是矩阵的维度。上面是三行两列,因此维度是3x2
在运算中有一类特殊的矩阵经常用到,那就是单位矩阵(identity matrix)。就是这个方向 \ 的对角线上全是1,其他位置是0。
image.png

如果把多个数字写成大于二维的形式,就可以得到张量。就像下面这样。
image.png
这是一个三维的张量,维度是3x4x2。

TensorFlow里的Tensor就是张量。

如果把维度对应到现实世界,那么我们所处的物质世界明显是一个三维世界。再加上不断流淌的时间,可以视为四维的。我能够理解到的最大维数就是四维了。在一些学习中,好像可以简单抽象的推到为五维、六维…,但是我实在是难以想象那些是什么样子?也许五维是两个平行世界?六维是三个平行世界?…


最常用的矩阵运算是矩阵的转置。转置就像是翻转。就像是一个扑克牌,原来是竖着拿的,把它变成翻面横着拿了。

image.png

矩阵的基本运算就是加减乘除。加减法如果这两个矩阵的维度是一样的,就非常好理解。矩阵也可以和行向量进行加减,要求行向量的列数和矩阵的列数是一样的。

矩阵的乘法,如果两个矩阵的维度一样,也非常好理解,这种叫做逐点相乘(element-wise product)。
还有一种惩罚就是我们在线性代数中的乘法。叫做点乘。点乘是这样的:
image.png

然后是向量和矩阵的范数,不好理解。

还有微积分的导数和求导法则,也不好看。


接下来是概率论的一些基本的概念。
随机变量就是一个取值不确定的变量。
这个在工作生活中应用的实在是太广泛了。比如老板问你这件事情明天能不能搞完?一般情况下,你的回答可能就是一个随机变量。
随机变量可以分为两种类型:连续型和离散型。

随机变量的分布用来描述随机变量出现某种结果的可能性。可以用一些分布函数来表示。

常见的概率分布有几种。这里只看最常见的一种概率分布,就是正态分布也叫高斯分布。

很多情况下,还有一种叫做条件概率。就是我们会关心当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模型用于处理分类问题

线性回归模型可以写作如下的形式:
image.png

其中那一系列的x都是已知,而且比较容易测量到的向量。一系列的w是权重或者叫做系数。b是一个常数,叫做截距或偏差。 ϵ \boldsymbol\epsilon 是误差,代表了没有在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()

image.png

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

image.png

再来看一下数学上对这些数据的表达,
第1个观测点的输入向量 x1=(x11,x12,x13),
第2个观测点的输入向量 x2=(x21,x22,x23)
那么因变量矩阵X表示为:
image.png

因变量向量y表示为:
image.png

前一节已经讲过线性回归模型的数学公式的表达,这里我们先假设给定截距项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

继续线性模型,

有了预测值,和真实值比较一下,就知道预测结果准确不准确?用预测值减去真实值 y ^ y \hat{y}-y ,如果是正数,说明预测值偏高,如果是负数说明偏低。通常使用差的平方来衡量预测误差。

target=ad.values[0][3]
loss=(pred-target)**2
print(loss)
#466.9921

而用残差平方之和,可以用来衡量模型总的预测误差。

image.png

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方便一些。

很自然的,我们要最小化 R S S ( b , w ) RSS(b,w) ,得到这种情况下b和w的估计值。

image.png

R S S ( b , w ) RSS(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)记作 \nabla ,函数RSS(w)关于参数w的梯度,记作 w R S S ( w ) \nabla_wRSS(w) ,简洁的记作 w \nabla_w 。它是RSS(w)关于w的偏导数,即:
image.png

对于这里的简单模型,就有:
image.png

所以w=3时, w \nabla_w =(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()

image.png

这个切线的斜率看上去不是0.35的样子啊,明显要更陡一下。这是因为x轴和y轴的比例不一致而导致的视觉效果,如果轴的比例之后显示是这样的,这样看上去就对了

image.png

这里预测值大于实际值,差值是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()

image.png

当w=0时,预测值小于真实值0.8。很自然的,要让预测值更接近实际值的话,需要让预测值变大。想让预测值变大,很简单的就让w变大,变大多少呢?这里的梯度是一个负值,那就先变大一个负的梯度呗。就是w+(-grad),巧了,也是w-grad。

所以无论w的初始值是在哪边, w = w w R S S ( w ) w=w-\nabla_wRSS(w) 都可以让w朝着RSS变小的方向移动。RSS最小的地方,就是我们寻找的地方,因为在这个地方预测值和真实值的差异最小,也就是说预测值最接近真实值。

image.png

这个算法就是梯度下降法,在更新w的过程中,加入了一个系数 α \alpha ,他是一个比较小的正数,叫做学习步长,这样可以让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()

image.png

好了我们上面说的是最简单的情况,因为为了学习,是一个权重或叫参数w,一个自变量x,并且只有一个观测点(x,y)。
在实际情况中,一般就不仅仅是学习的那么简单的情况。
数据会包含多个自变量,多个权重,很多个观测点。

L ( w ) = L ( w 1 , w 2 , . . . , w p ) L(w)=L(w_1,w_2,...,w_p) 表示包含p个权重或参数的损失函数,它的梯度可以表示为:

image.png

它是由函数 L ( w ) L(w) 对各个参数的偏导数构成的向量。

image.png

上面就是随机梯度下降法Stochastic Gradient Descent SGD)。随机是指每次只使用一个观察点计算梯度,在实现随机梯度下降的过程中,随机抽取观测点来计算梯度并更新参数。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。