python
一.python入门
1. 基础运算
if __name__ == '__main__':
print("第一个解释器")
print(1-2)
print(3*2)
print(3**2)
lkl={'aini':520}
print(lkl['aini'])
hu=True
if hu:
print("刘坤龙")
else:
print("坤龙")
for i in [1,2,3]:
print(i)
a = [1,2,3,4,5]
print(a)
print(a[0:3])
a[4]=99
print(a)
def lkl():
print("好难啊")
lkl()
def lkl1(object):
print(object+"好难啊"+"!")
lkl1("计算机")’
2.类运行
class lkl:
def __init__(self,name,age):
self.name=name
self.age=age
print("这个是初始函数!!")
def lkl1(self):
print("我叫"+self.name)
def lkl2(self):
print("年纪是"+self.age)
lkl=lkl("刘坤龙","21")
lkl.lkl1();
lkl.lkl2();
#### 注意:使用类时要在终端输入 python test.py
#### 使用类时里面不管是数字还是汉字都要带引号
3. NumPy数组
import numpy as np#numpy属于外界包 需要向外界导入,此时的需要
#此时将numpy作为np导入
x=np.array([1.0,2.0,3.0])
print(x)
y=np.array([4.0,5.0,6.0])
print(x+y)
x1=np.array([[1,2],[3,4]])
print(x1)
print(x1.shape,x1.dtype)
#shape表示矩阵的形状,矩阵的元素类型有dtype查看
print(x1*10)
x1=x1.flatten()
print(x1)
#flatten是将此以一维数组输出
4.matplotlib
import numpy as np
import matplotlib.pyplot as plt
x=np.arange(0,6,0.1)#以0.1为单位,生成0到6的数据
y=np.sin(x)
plt.plot(x,y)#将x,y的数据传给plt.plot方法
plt.show()
4.1 绘制图像
import numpy as np
import matplotlib.pyplot as plt
x=np.arange(0,6,0.1)#以0.1为单位,生成0到6的数据
y=np.sin(x)
plt.plot(x,y,label="sin")#将x,y的数据传给plt.plot方法
n=np.cos(x)
plt.plot(x,n,linestyle="--",label="cos")#用虚线绘制
plt.title('sin & cos')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()
4.2 图片
import matplotlib.pyplot as plt
from matplotlib.image import imread
#img=imread('E:\python学习\py.png')#读入图片
img=imread('E:/python学习/py.png')#两种都可以
plt.imshow(img)
plt.show()
二.感知机
1. 理解
- 感知机接收多个输入信号,输出一个信号
- 输入信号都有各自固有的权重w,权重发挥控制各个信号的重要性作用,权重越大,重要性越高
2. 逻辑电路
- 与门:仅在两个输入均为1时输出1,其他为0.(3011)
- 与非门:仅当两个输入为1时输出0,其他为1.(3110)
- 或门:只要有一个输入为1,输出就为1.(3110)
- 异或门:仅当x1或x2中一方为1时,才会输出1.(2120)
三.神经网络
1.激活函数(必须使用非线性函数)
- sigmoid函数(exp(-x)表示e的-x次方)
- 用该函数进行信号的转换,转换后传送给下一个神经元
h ( x ) = 1 1 + e x p ( − x ) h(x)=\frac{1}{1+exp(-x)} h(x)=1+exp(−x)1
- sigmoid函数实现
import numpy as np
def sigmoid(x):
return 1/(1+np.exp(-x))
x=np.array([-0.1,1.0,2.0])
print(sigmoid(x))
2.跳跃函数
import numpy as np
x=np.array([-1.0,1.0,2.0])
print(x)
y=x>0
y1=y.astype(np.int)#转换数据类型
print(y)
print(y1)
import numpy as np
import matplotlib.pylab as plt
def st_fu(x):
return np.array(x>0,dtype=np.int)
x = np.arange(-5.0,5.0,0.1)#在-5.0到5.0之间以0.1为单位生数组
y = st_fu(x)
plt.plot(x,y)
plt.ylim(-0.1,1.1)#指定y的范围
plt.show()
3.ReLU函数
h ( x ) = { x ( x > 0 ) 0 ( x ≤ 0 ) h(x)=\begin{cases}x(x>0)\\0(x\le0)\end{cases} h(x)={x(x>0)0(x≤0)
- 函数实现
import matplotlib.pylab as plt
import numpy as np
def relu(x):
return np.maximum(x,0)
4.神经网络内积
import numpy as np
x=np.array([1,2])
print(x.shape)
y=np.array([[1,3,5],[2,4,6]])
print(y)
print(y.shape)
w=np.dot(x,y)#内积
print(w)
5.小结1
- 回归问题可以使用恒等函数identity_function() {感觉没啥用,原样输出}
- 二元分类问题可以使用sigmoid函数
- 多元分类问题可以使用softmax函数
5.softmax函数
- 该函数会出现溢出的现象,由于进行指数函数,数会很大
- softmax函数的输出是0.0到1.0之间的实数,输出总和为1
y k = e x p ( a k ) ∑ i = 1 n exp ( α i ) y_k=\cfrac{exp(a_k)}{\sum_{i=1}^n{\exp \left(\alpha _i \right)}} yk=∑i=1nexp(αi)exp(ak)
5.1改进softmax函数
y k = C e x p ( a k ) C ∑ i = 1 n exp ( α i ) y_k=\cfrac{Cexp(a_k)}{C\sum_{i=1}^n{\exp \left(\alpha _i \right)}} yk=C∑i=1nexp(αi)Cexp(ak)
y k = e x p ( a k + l o g C ) ∑ i = 1 n exp ( α i + l o g C ) y_k=\cfrac{exp(a_k+logC)}{\sum_{i=1}^n{\exp \left(\alpha _i +logC\right)}} yk=∑i=1nexp(αi+logC)exp(ak+logC)
y k = e x p ( a k + C ′ ) ∑ i = 1 n exp ( α i + C ′ ) y_k=\cfrac{exp(a_k+C')}{\sum_{i=1}^n{\exp \left(\alpha _i +C'\right)}} yk=∑i=1nexp(αi+C′)exp(ak+C′)
- 由于分子分母同时乘上C(为任意数),不改变数值大小
c=np.max(a)
exp_a=np.exp(a-c)#溢出对策
- 为防止溢出,一般使用输入信号的最大值
小结2
- 神经网络中激活函数使用的是平滑变化的sigmoid函数和ReLU函数
- 使用NumPy多维数组,可以高效实现神经网络
- 机器学习大致分回归问题(恒等函数)和分类问题(softmax函数)
四.神经网络学习
1. 数据
- (例如识别数字5)先从图像中提取特征量,在用机器学习技术学习这些特征量的模式。
- 特征量指可以从输入数据(输入图像)中准确提取本质数据(重要数据)的转换器
- 特征量通常为向量的形式(包括SIFT,SURF,HOG等)
- 使用特征量将图像数据转为向量,然后对向量使用机器学习中的SVM,KNN等进行分类
- 神经网络的学习通过某个指标表示现在的状态
- 神经中的所有指标称为损失函数(一般用均方误差和交叉熵误差)
2.均方误差
- 公式
E = 1 2 ∑ k ( y k − t k ) 2 E=\frac{1}{2}\sum_k{(y_k-t_k)^2} E=21k∑(yk−tk)2
- yk表示神经网络的输出,tk表示监督数据,k表示数据的维数
- 代码实现
import numpy as np
def mean_sq_err(y,t):
return 0.5*np.sum((y-t)**2)
t=[0,0,1,0,0,0,0,0,0,0]
y=[0.1,0.05,0.6,0.0,0.05,0.1,0.0,0.1,0.0,0.0]
print(mean_sq_err(np.array(y),np.array(t)))
y=[0.1,0.05,0.1,0.0,0.05,0.1,0.0,0.6,0.0,0.0]
print(mean_sq_err(np.array(y),np.array(t)))
3.交叉熵误差
- 公式
E = − ∑ k t k l o g y k E=-\sum_k{t_klogy_k} E=−k∑tklogyk
- yk表示网络神经的输出,tk是正确解标签
- tk中只有正确解标签的索引是1,其他均是0
- 代码实现
import numpy as np
def cro_ent_err(y,t):
delta=1e-7
return -np.sum(t*np.log(y+delta))
t=[0,0,1,0,0,0,0,0,0,0]
y=[0.1,0.05,0.6,0.0,0.05,0.1,0.0,0.1,0.0,0.0]
print(cro_ent_err(np.array(y),np.array(t)))
y=[0.1,0.05,0.1,0.0,0.05,0.1,0.0,0.6,0.0,0.0]
print(cro_ent_err(np.array(y),np.array(t)))
4. mini-batch
-
之前是针对单个函数的损失函数,要对所有的训练数据的损失函数的总和,以交叉熵误差为例
-
E = − 1 N ∑ n ∑ k t n k l o g y n k E=-\frac{1}{N}\sum_n\sum_kt_{nk}logy_{nk} E=−N1n∑k∑tnklogynk
-
Tnk表示第n个数据的第k个元素的值
-
Ynk是神经网络的输出,Tnk是监督数据
-
神经网络的学习就是从训练数据中选出一批数据(称为mini-batch,小批量),再对每个小批量进行学习
5.mini-batch版交叉熵误差实现
- 实现一个同时处理单个数据和多个数据两种情况的函数
def cro_ent_err(y,t):
if y.ndim==1:
t=reshape(1,t.size)
y=reshape(1,y.size)
batch_size=y.shape[0]
return -np.sum(np.log(y[np.arange(batch_size),t]+1e-7))/batch_size
6数值微分
- 导数
d f ( x ) d x = lim h − > 0 f ( x + h ) − f ( x ) h \frac{df(x)}{dx}=\lim_{h->0}\frac{f(x+h)-f(x)}{h} dxdf(x)=h−>0limhf(x+h)−f(x)
-
import numpy as np def nnum_dif(f,x): h=1e-4#表示10的-4次方,大概是0.0001 return (f(x+h)-f(x))/h def func_1(x): return 0.01*x**2+0.1*x print(nnum_dif(func_1,5)) print(nnum_dif(func_1,10))
-
偏导数
f ( x 0 , x 1 ) = x 0 2 + x 1 2 f(x_0,x_1)=x_0^2+x_1^2 f(x0,x1)=x02+x12
import numpy as np#此时x0=3,x1=4
def nnum_dif(f,x):
h=1e-4
return (f(x+h)-f(x))/h
def func_tmp1(x0):
return x0*x0+4.0**2
print(nnum_dif(func_tmp1,3.0))
- 梯度
import numpy as np
def num_grad(f,x):
h=1e-4
grad=np.zeros_like(x)#生成和x形状相同的数组
for idx in range(x.size):
tmp_val=x[idx]
# f(x+h)的计算
x[idx]=tmp_val+h
fxh1 = f(x)
# f(x-h)的计算
x[idx] = tmp_val - h
fxh2 = f(x)
grad[idx]=(fxh1-fxh2)/(2*h)
x[idx]=tmp_val#还原值
return grad
def func_2(x):
return x[0]**2+x[1]**2#或者return np.sum(x**2)
print(num_grad(func_2,np.array([3.0,4.0])))
#输出是[6. 8.]在输出NumPy数组时,数组会改成易读模式
- 梯度指示的方向时各点处的函数值减少最多的方向
- 神经网络必须在学习时找到最优参数(权重和偏置),最优参数指损失函数取最小值的参数
- 用梯度来找函数最小值(或尽可能小)就是梯度法
- 代码表示梯度下降法
import numpy as np
def num_grad(f,x):
h=1e-4
grad=np.zeros_like(x)#生成和x形状相同的数组
for idx in range(x.size):
tmp_val=x[idx]
# f(x+h)的计算
x[idx]=tmp_val+h
fxh1 = f(x)
# f(x-h)的计算
x[idx] = tmp_val - h
fxh2 = f(x)
grad[idx]=(fxh1-fxh2)/(2*h)
x[idx]=tmp_val#还原值
return grad
def grad_des(f,init_x,lr=0.01,step_num=100):#f是要优化的参数
x=init_x#init_x是初始值,lr是学习率,step_num是梯度重复次数
for i in range(step_num):
grad=num_grad(f,x)
x-=lr*grad
return x
def func_2(x):
return x[0]**2+x[1]**2
init_x=np.array([-3.0,4.0])
print(grad_des(func_2,init_x=init_x,lr=0.1,step_num=100))
- 学习率过大会发散一个很大的值,太小会没怎么更新就结束了
- 神经网络里面的梯度是指损失函数关于权重参数的梯度
五. 误差反向传播法
1.神经网络学习的全貌图
- 神经网络中有合适的权重和偏置,调整权重和偏置以便于拟合训练数据的过程称为学习。分以下四步
- 从训练数据中随机选择一部分数据。
- 计算损失函数关于各个权重参数的梯度,(误差反向传播法)
- 将权重参数沿梯度方向进行微小的更新。
- 重复步骤1 步骤2,步骤3
六.与学习相关技巧
- 神经网络学习的目的是为了找到使损失函数的值尽可能小的参数。即寻找最优化参数的问题。
1. SGD随机梯度下降法
w ← w − η δ L δ W 需 要 更 新 的 权 重 参 数 记 为 W , 损 失 函 数 关 于 W 的 梯 度 记 为 δ L δ W η 表 示 学 习 率 w\gets w-\eta\frac{\delta L}{\delta W} \\需要更新的权重参数记为W,损失函数关于W的梯度记为\frac{\delta L}{\delta W} \\ \eta表示学习率 w←w−ηδWδL需要更新的权重参数记为W,损失函数关于W的梯度记为δWδLη表示学习率
class SGD:
def __init__(self,lr=0.01):
self.lr=lr #lr表示学习率,这个会保存为实例变量
def update(self,params,grads): #params['w1'],grads['w1']分别保存了权重参数和他们梯度
for key in params.keys():
params[key]-=self.lr*grads[key]
- 缺点:如果函数的形状非均匀,比如呈延伸状,搜索路径会很低效。
- 原因:梯度方向没有指向最小值方向
2.Momentum
-
参照小球在碗中的滚动的物理规则进行移动
-
w ← α w − η δ L δ W W ← W + v w\gets \alpha w-\eta\frac{\delta L}{\delta W} \\ W\gets W+v w←αw−ηδWδLW←W+v
-
出现新的变量v,对应物理上的速度
class Momentum: """Momentum SGD""" def __init__(self, lr=0.01, momentum=0.9): self.lr = lr self.momentum = momentum self.v = None def update(self, params, grads): if self.v is None: self.v = {} for key, val in params.items(): self.v[key] = np.zeros_like(val) for key in params.keys(): self.v[key] = self.momentum*self.v[key] - self.lr*grads[key] params[key] += self.v[key]
3.AdaGrad
-
为参数的每个元素适当的调整更新步伐
-
该会为参数的每个元素适当的调整学习率,与此同时进行学习。
-
h ← h + δ L δ W ⊙ δ L δ W ⊙ 表 示 对 应 矩 阵 运 算 的 乘 法 W ← W − η 1 h δ L δ W h\gets h+\frac{\delta L}{\delta W}\odot\frac{\delta L}{\delta W} \\ \odot 表示对应矩阵运算的乘法 \\ W\gets W-\eta\frac{1}{\sqrt h}\frac{\delta L}{\delta W} h←h+δWδL⊙δWδL⊙表示对应矩阵运算的乘法W←W−ηh1δWδL
-
h保存了以前梯度值的平方和
-
class AdaGrad: """AdaGrad""" def __init__(self, lr=0.01): self.lr = lr self.h = None def update(self, params, grads): if self.h is None: self.h = {} for key, val in params.items(): self.h[key] = np.zeros_like(val) for key in params.keys(): self.h[key] += grads[key] * grads[key] params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)
-
在更新参数时,通过乘以1/根号h,就可以调整学习的尺度。
-
参数的元素中变动较大(被大幅更新)的元素的学习率将变小。
-
可以按参照的元素进行学习率衰减,使变动大的参数的学习率逐渐减少
4.Adam
- 2015年提出,将Momentum和AdaGrad结合,实现了参数空间的高效搜索。
- 也进行了超参数的“偏置校正”
5.初始值-激活函数
Xavier初始值-----sigmoid,tanh
He初始值-----ReLU
- 书上说很重要,权重初始值非常重要。
6.Batch Normalization
思路:调整各层的激活值分布使其拥有适当的广度。为此,要向神经网络中插入对数据分布进行正规化的层。
- 可以使学习快速进行(可以增大学习率)
- 不那么依赖初始值(对于初始值不那么神经质)
- 抑制过拟合(降低Dropout等的必要性)
- 过拟合:指的使只能拟合训练数据,但不能很好的拟合不包含在训练数据中的其他数据的状态。
原因:
- 模型拥有大量参数,表现力强。
- 训练数据小
- 机器学习目标:就是提高泛化能力,即便是没有包含在训练数据里的未关测数据,也希望模型可以进行正确的识别。
- 权值衰减:用来被使用的一种抑制过拟合的方法,通过对大的权重进行惩罚,来抑制过拟合。
+权重的L2范数
- Dropout(网络模型复杂,权值衰减不行):在学习过程中随机删除神经元的方法。
- 超参数:指的是各层的神经元个数,batch大小,参数更新时的学习率或权值衰减等
- 超参数的验证:如果没有设置合适的值,模型的性能就会很差。
七.卷积神经网络
1.卷积层
- 填充:在进行卷积处理时,有时要向输入数据的周围填入固定的数据。
- 步幅:应用滤波器的位置间隔称为步幅。
2.池化层
- 池化是缩小高,长方向上的空间的运算。
- 除了Max池化(从目标区域中取出最大值)之外,还有Average池化(计算目标区域的平均值)等。
- 特点:1.没有学习的参数。2.通道数不发生变化。3.对微小的位置变化具有鲁棒性(健壮)
3.四维数组
import numpy as np
x=np.random.rand(10,1,4,4)#随机生成数据
#生成10个高为4,长为4,通道数为1的数据
print(x.shape)
print(x[0])
4.基于im2col的展开
-
使用im2col函数可以高效实现卷积层和池化层
-
对3维的输入数据应用im2col后,数据转化为2维矩阵。(展开以适合滤波器)
-
使用im2col展开数据后,之后就只需将卷积层的滤波器(权重)纵向展开为1列,并计算2个矩阵的乘积即可。
5.池化层实现
- 展开输入数据
- 求各行的最大值
- 转换为合适的输出大小
6.具有代表的CNN
- LeNet
- 与现有cnn不同,激活函数不同,采用的sigmoid函数,现有的是ReLU函数。
- 采用子采样(subsampling)缩小中间数据大小,现有的Max池化
- AlexNet
- 叠有很多个卷积层和池化层,最后由全连接层输出结果。
- 激活函数用ReLU
- 使用进行局部正规化的LRN(Local Response Normalization)层
- 使用Dropout(抑制过拟合)
八.深度学习
1.进行手写数字识别的深度CNN
- 基于3*3的小型滤波器的卷积层。
- 激活函数是ReLU
- 全连接层的后面使用Dropout层。
- 基于Adam的最优化
- 使用He初始值作为权重初始值
2.VGG
- VGG是由卷积层和池化层构成的基础的CNN。
- 特点在于将有权重的层(卷积层或全连接层)叠加至16层(或者19层),具有深度(根据深度也被称为VGG16或者VGG19)
- 基于3*3的小型滤波器的卷积层的运算是连续进行的。
3.GoogLeNet
- 特点:横向纵向上面都有深度。横向有“宽度”,称为“Inception结构”。
- 该结构使用了多个大小不同的滤波器(和池化),最后合并看结果。
- GoogLeNet特征就是将这个Inception结构用作一个构件(构成元素)。
- 很多地方使用了1*1的滤波器的卷积器,通过在通道方向上减小大小,有助于减少参数和实现高速化处理。
4.ResNet
- 微软团队,特点:具有更深的结构。
- 太深也不好,会影响学习不能正常进行,导致性能不佳,所以导入“快捷结构(捷径,小路)”
- 快捷结构横跨(跳过)输入数据的卷积层,将输入x合计到输出。
- 通过以2个卷积层为间隔跳跃式的来连接加深层。
- AlexNet中conv是对应卷积层,pool对应池化层,fc对应全连接层,norm对应正规化层。
5.基于GPU的高速化
- GPU适合计算大规模的汇总好的数据。
- 通过基于im2col以大型矩阵的乘积的方式汇总计算,更适合GPU发挥。
6.分布式学习
- Google的TensorFlow,微软的CNTK在开发中高度重视分布式学习。
7.图像分割
- FCN(Fully Convolutional Network)“全部由卷积层构成的网络”,通过一次forward处理,对所有像素进行分类。
- FCN的特征:在于最后导入了扩大空间大小的处理,基于这个处理,使变小的中间数据可以一下子扩大到和输入图像一样的大小。
- FCN最后的扩大处理是基于双线性插值法的扩大(双线性插值扩大),通过卷积(逆卷积运算)来实现的。
8.图像标题生成
- NIC(Neural Image Caption)由深层的CNN和处理自然语言的RNN(Recurrent Neural Network)构成
- RNN是循环连接的网络,经常被用于自然语言,时间序列数据等连续性的数据上。
- NIC基于CNN从图片中提取特征,并将这个特征传给RNN。
9.深度学习应用
- 图像风格变换:在学习过程中使网络的中间数据近似内容的中间数据。(风格矩阵)
- 图像的生成:基于DCGAN(Deep Convolutional Generative Adversarial Network),从零生成的图片。
- DCGAN:使用深度学习,技术要点是使用Generator(生成者)和Discriminator(识别者)这两个神经网络。
- 自动驾驶:基于CNN的神经网络SegNet,输入头像进行分割(像素水平分割)