深度学习PyTorch(一)pytorch基础&神经网络
科学计算库 numpy,数据分析库 pandas,可视化绘图工具Matplotlib国内:百度的 apollo,duos 技术底层就是图像识别和语音识别技术,讯飞的的语音识别技术用的是深度学习人工智能四小龙:旷视 图森 商汤 依图这几个企业里面面部识别,语音识别也用的深度学习机器学习:图片–feature extracting-encoding-classification-分类结果...
文章目录
科学计算库 numpy,数据分析库 pandas,可视化绘图工具Matplotlib
国内:百度的 apollo,duos 技术底层就是图像识别和语音识别技术,
讯飞的的语音识别技术用的是深度学习
人工智能四小龙:旷视 图森 商汤 依图
这几个企业里面面部识别,语音识别也用的深度学习
机器学习:图片–feature extracting-encoding-classification-分类结果
深度学习:所有的函数都从数据中自动学习
应用:语音识别 图像识别 人脸识别 机器翻译 自动驾驶
人脸识别 黑白图片上色 机器翻译 alphago下围棋 目标检测 自动驾驶
符号为编程:tensorflow
命令为编程:pytorch
目前神经网络框架分为静态图和动态图两种。
PyTorch基础
Tensor
pytorch 与numpy之间的转换
import numpy as np
numpy_tensor=np.random.randn(10,20) 10*20的矩阵
pytorch_tensor=torch.from_numpy(numpy_tensor) 从numpy转化成torch
或者 pytorch_tensor=torch.Tensor(numpy_tensor) 从numpy转化成torch
new_numpy_tensor=pytorch_tensor.numpy(pytorch_tensor) 从torch转化成numpy
GPU tensor和CPU tensor之间的转换
推荐:
x=torch.randn(3,4) cpu的定义,3*4的矩阵
x_gpu=x.cuda(0) 把张量放到第1块GPU上
x_gpu=x.cuda(1) 把张量放到第2块GPU上
x_gpu=x.cuda() 把张量放到默认GPU上
x_gpu=x_gpu.cpu() 把在gpu的张量放到cpu上
x_array=x_gpu.cpu.numpy() 如果要把gpu的张量转化成numpy,要先把gpu的张量转化成cpu的张量
或者定义cuda数据类型
dtype = torch.cuda.FloatTensor # ???? GPU ? ????
gpu_tensor = torch.randn(10, 20).type(dtype)
Tensor的操作分为两种,一种是数学运算,一种是torch的高级操作。
数学运算
x=torch.ones(3,4) 3*4的矩阵,且数字都为1
y=torch.ones(3,4)
z=torch.ones(4,3)
k=x+3 在x的每个数字上+3
k=torch.add(x,3) 同上
x_sum=x+y 两个矩阵的加法
x_sum=torch.add(x,y)
x_mm=torch.mm(x,z) 两个矩阵相乘
x_mm=torch.matmul(x,z) 两个矩阵相乘
高级操作
x=torch.randn(4,3) 定义正态分布的随机的4*3矩阵
x.size()大小
x.shape
x.type() 数据类型
x.dim() 维度
将其转化为整形
x = x.long()
或者 x = x.type(torch.LongTensor)
x.view(3,4) 矩阵的重新排列
x.view(12)
x = x.view(-1, 4) -1表示任意的大小,4表示第二维变成5
torch.unsqueeze(x,dim=1) 给x维的第二维度增加一维
x=x.unsqueeze(1)
x.shape
squeeze是减维度,无论是降第一维度还是第二维度,都需要主要的是该维度上的数值大小必须等于1,否则无任务效果
unsqueeze增加维度时,没有等于1的限制。
pytorch中大多数的操作都支持inplace操作,也就是可以直接对tensor进行操作而不需要另外开辟内存空间。
直接对原始对象进行修改。
一般都是再操作的符号后面加_
比如
x = torch.ones(3, 3)
print(x.shape)
# unsqueeze 进行 inplace
x.unsqueeze_(0)
print(x.shape)
# transpose 进行 inplace
x.transpose_(1, 0) 转置
print(x.shape)
max_index,max_value=torch_max(x,dim=1) [行操作]沿着行取最大值
max_index,max_value=x.max(1)
torch.max(a,0) 返回每一列中最大值的那个元素,且返回索引(返回最大元素在这一列的行索引)
torch.max(a,1) 返回每一行中最大值的那个元素,且返回其索引(返回最大元素在这一行的列索引)
torch.max()[0], 只返回最大值的每个数
troch.max()[1], 只返回最大值的每个索引
torch.max()[1].data 只返回variable中的数据部分(去掉Variable containing:)
torch.max()[1].data.numpy() 把数据转化成numpy ndarry
torch.max()[1].data.numpy().squeeze() 把数据条目中维度为1 的删除掉
torch.max(tensor1,tensor2) element-wise 比较tensor1 和tensor2 中的元素,返回较大的那个值
sum_tensor=torch.sum(x,dim=1) [行操作]沿着行求和
sum_tensor=x.sum(1)
练习:
创建一个float64,大小是3*2,随机初始化的tensor,将其转化成numpy的ndarray,输出其数据类型。
x=torch.randn(3,2)
x=x.type(torch.DoubleTensor)
x_array=x.numpy()
print(x_array.dtype)
Variable
为了构建神经网络,只使用Tensor不够,。
本质上Variable的操作与运算和Tensor是相同的。
唯一的区别是Variable有三个属性。
.data
表示访问这个Variable中的tensor
.grad
表示取得其中的梯度(相当于导数)
.grad_fn
表示如何得到这个Variable
from torch.autograd import Variable
x=Variable(torch.ones(2,2),requires_grad=True) 是否进行梯度下降,是则True
y=Variable(torch.ones(2,2),requires_grad=True)
z=torch.sum(x+y) 在x+y后得到的矩阵,再把其中每个数值做求和工作
print(z,data)
z.backward() 对x,y分别求梯度
print(x.grad)
print(y.grad)
结果:
8
[torch.FloatTensor of size 1]
Variable containing:
1 1
1 1
[torch.FloatTensor of size 2*2]
自动求导AutoGrad
有更加广泛地应用,比如多次求导,对矩阵和向量的自动求导等等
from torch.autograd import Variable
x=Variable(torch.floatTensor([2]),requires_grad=True)
y=(x+2)**2
y.backward()
print(x.grad)
结果:
Variable containing:
8
[torch.FloatTensor of size 1]
复杂情况的自动求导
torch.ones_like(input, dtype=None, layout=None, device=None, requires_grad=False) → Tensor
返回一个填充了标量值1的张量,其大小与之相同 input。torch.ones_like(input)相当于 。
torch.ones(input.size(), dtype=input.dtype, layout=input.layout, device=input.device)
from torch.autograd import Variable
m=Variable(torch.FloatTensor([[2,3]]),requires_grad=True)#构建一个1*2的矩阵 [2 3]
n=torch.zeros(1,2) #[0 0]
n[0,0]=m[0,0]**2
n[0,1]=m[0,1]**3
n.backward(torch.ones_like(n))#将(w0,w1)取成(1,1)
print(m.grad)#4 27
多次自动求导
from torch.autograd import Variable
x=Variable(torch.FloatTensor([3]),requires_grad=True)
y=x*2+x**2+3
print(y)
y.backward(retain_graph=True)#保留计算图
print(x.grad)#8
y.backward()#再对原先的y做一次求导
print(x.grad)#第一次的梯度和第二次的梯度加起来。8+8=16
练习:
from torch.autograd import Variable
x=Variable(torch.FloatTensor([2,3]),requires_grad=True)
k=Variable(torch.zeros(2))
k[0]=x[0]**2+3*x[1]
k[1]=x[1]**2+2*x[0]
print(k)
j=torch.zeros(2,2)
k.backward(torch.FloatTensor([1,0]),retain_graph=True)
j[0]=x.grad.data
x.grad.data.zero_()#归零之前求的梯度
k.backward(torch.FloatTensor([0,1]))
j[1]=x.grad.data
print(j)
结果:
Variable containing:
13
13
[torch.FloatTensor of size 2]
4 3
2 6
[torch.FloatTensor of size 2x2]
神经网络
监督学习:
非监督学习:
强化学习:
线性模型
梯度下降
调参就是调学习率。
输入数据->定义参数和模型->定义损失函数->反向传播,得到梯度->更新模型参数
示例:
import torch
import numpy as np
from torch.autograd import Variable
import matplotlib.pyplot as plt
torch.manual_seed(2017)#为CPU设置随机种子,输出<torch._C.Generator at 0x112959630>
#读入数据x和y
x_train=np.array([[3.3], [4.4], [5.5], [6.71], [6.93], [4.168],
[9.779], [6.182], [7.59], [2.167], [7.042],
[10.791], [5.313], [7.997], [3.1]], dtype=np.float32)
y_train = np.array([[1.7], [2.76], [2.09], [3.19], [1.694], [1.573],
[3.366], [2.596], [2.53], [1.221], [2.827],
[3.465], [1.65], [2.904], [1.3]], dtype=np.float32)
#画出图像
%matplotlib inline#%matplotlib具体作用是当你调用matplotlib.pyplot的绘图函数plot()进行绘图的时候,
## 或者生成一个figure画布的时候,可以直接在你的python console里面生成图像。
plt.plot(x_train,y_train,'bo')
#转化成Tensor
x_train=torch.from_numpy(x_train)
y_train=torch.from_numpy(y_train)
#定义参数w和b
w =Variable(torch.randn(1),requires_grad=True)#随机初始化
b=Variable(torch.zeros(1),requires_grad=True)#使用0进行初始化
#构建线性回归模型
x_train=Variable(x_train)
y_train=Variable(y_train)
def line_mode(x):
return w*x+b
#试着看更新前的模型的输出是什么
#y_=line_mode(x_train)
#plt.plot(x_train.data.numpy(),y_train.data.numpy(),'bo',lable='real')
#plt.plot(x_train.data.numpy().y_.data.numpy(),'ro',lable='estimated')
#plt.legend()#加图例
def get_loss(y_,y):
return torch.mean(y_-y)**2
#试着看更新前的loss是什么
#loss=get_loss(y_,y_train)
#print(loss)
for e in range(10):#10次更新
y_=line_mode(x_train)
loss=get_loss(y_,y_train)
w.grad.data=0#归零梯度
b.grad.data=0#归零梯度
loss.backward()
w.data=w.data-1e-2*w.grad.data#1e-2是学习率,更新w
b.data=b.data-1e-2*b.grad.data#更新b
print('epoch:{},loss:{}'.format(e.loss.data[0]))
#plt.plot(x_train.data.numpy(),y_train.data.numpy(),'bo',lable='real')
#plt.plot(x_train.data.numpy().y_.data.numpy(),'ro',lable='estimated')
#plt.legend()#加图例
多项式回归模型:
函数是个三次的多项式
np.stack()函数解释
import torch
import numpy as np
from torch.autograd import Variable
import matplotlib.pyplot as plt
w_target=np.array([0.5,3,2.5])
b_target=np.array([0.9])
f_des='y={:.2f}+{:.2f}*x+{:.2f}*x^2+{:.2f}*x^3'.format(b_target[0],w_target[0],w_target[1],w_target[2])#打印出函数的式子
print(f_des)#y = 0.90 + 0.50 * x + 3.00 * x^2 + 2.40 * x^3
#画出这个函数的曲线
x_sample=np.arange(-3,3.1,0.1)
y_sample=b_target[0]+w_target[0]*x_sample+w_target[1]*x_sample**2+w_target[2]*x_sample**3
plt.plot(x_sample,y_sample,label='real curve')
plt.legend()
plt.show()
#构建数据x和y
#x是一个如下矩阵[x,x^2,x^3]
#y是函数的结果
x_train=np.stack([x_sample**i for i in range(1,4)],axis=1)#在行方面加一行
x_train=torch.from_numpy(x_train).float()#转成float tensor
y_train=torch.from_numpy(y_sample).float().unsqueeze(1)
#定义参数和模型
w=Variable(torch.randn(3,1),requires_need=True)
b=Variable(torch.zeros(1),requires_need=True)
#将x_train和y_train转化为Variable
x_train=Variable(x_train)
y_train=Variable(y_train)
def multi_line(x):
return torch.mm(x,w)+b
def get_loss(y_,y):
return torch.mean(y_,y)**2
#画出更新前的模型
#y_pred=multi_line(x_train)
#plt.plot(x_train.data.numpy()[:,0],y_pred.data.numpy(),color='r',lable='fitting curve')
#plt.plot(x_train.data.numpy()[:,0],y_sample,color='b',lable='real curve')
#plt.legend()
#plt.show()
for e in range(100):#进行100次更新
y_pred=multi_line(x_train)
loss=get_loss(y_pred,y_train)
w.grad.data.zero_()
b.grad.data.zero_()
loss.backward()
w.data=w.data-1e-3*w.grad.data
b.data=b.data-1e-3*b.grad.data
if (e+1)%20==0:
print('epoch:{},Loss:{}'.format(e,loss.data[0]))
Logistic回归
预测
sigmoid函数
Loss函数
loss越小越好
PyTorch实现
y
∧
=
σ
(
w
1
x
+
w
2
y
+
b
)
\mathop y\limits^ \wedge = \sigma ({w_1}x + {w_2}y+ b)
y∧=σ(w1x+w2y+b)
loss=
定义sigmoid函数
def sigmoid(x):
return 1/(1+np.exp(-x))
或者直接调用
import torch.nn.functional as F
F.sigmoid()
定义logistic回归模型
w=Variavle(torch.randn([2,1]),requires_need=True)
b=Variavle(torch.zeros(1),requires_need=True)
def logistic_regression(x):
return F.sigmoid(torch.mm(x,w)+b)
def binary_loss(y_pred,y):
logits=(y*y_pred.clamp(1e-12).log()+(1-y)*(1-y_pred).clamp(1e-12).log()).mean()
return -logits
y_pred=logistic_regression(x_data)
loss=binary_loss(y_pred,y_data)
#自动求导并更新参数
loss.backward()
w.data=w.data-1e-1*w.grad.data
b.data=b.data-1e-1*b.grad.data
pytorch还有其他修正参数的方法。使用Optimizer更新
torch.optim
Parameter是Variable的一个子类,默认需要求梯度,而且能自动注册到PyTorch中 。
#使用torch.optim更新参数
from torch import nn
w=nn.Paramerer(torch.randn(2,1))
b=nn.Paramerer(torch.zeros(1))
def logistic_regression(x):
return F.sigmoid(torch.mm(x,w)+b)
optimizer=torch.optim.SGD([w,b],lr=1.)#随机梯度下降
for e in range(1000):
y_pred=logistic_regression(x_data)
loss=binary_loss(y_pred,y_data)
#更新参数
optimizer.zero_grad()#使用优化器将梯度归0
loss.backward()
optimizer.step()#使用优化器来更新参数
更多的loss:
nn.BCEWithLogitsLoss()是表示二分类法。
完整的Logistic回归模型实现
str.split(“o”)[0]得到的是第一个o之前的内容
str.split(“o”)[1]得到的是第一个o和第二个o之间的内容
str.split(“o”)[3]得到的是第三个o后和第四个o前之间的内容
str.split("[")[0]得到的是第一个 [ 之前的内容
filter()函数解释
y的由来?
首先理论上是这个样子的。
w0x0+w1x1+b=f(x)
f(x)最开始就设置为1, x1就是我们画图的y值。0是两个类别的分界处
所以: w0x0+w1x1+b=0 => y = (-b-w0*x)/w1
import torch
from torch.autograd import Variable
import numpy as np
import matplotlib.pyplot as plt
from torch import nn
import time
#%matplotlib inline
#设置随机种子,如果不加上这个函数的话,打印出来的随机数每次都不一样。
torch.manual_seed(2017)
with open('./data.txt','r') as f:#Linux系统
data_list=[i.split('\n')[0].split(',') for i in f.readlines()]#从\n前开始划分,以,为分隔符
data=[(float(i[0]),float(i[1]),float(i[3])) for i in data_list]
#标准化
x0_max=max([i[0] for i in data])
x1_max=max([i[1] for i in data])
data=[(i[0]/x0_max,i[1]/x0_max,i[2]) for i in data]
#画图
x0=list[filter(lambda x:x[-1]==0.0,data)]#第一类,最后一个元素为0
x1=list[filter(lambda x:x[-1]==1.0,data)]#第二类,最后一个元素为1
plot_x0=[i[0] for i in x0]
plot_y0=[i[1] for i in x0]
plot_x1=[i[0] for i in x1]
plot_y1=[i[1] for i in x1]
plt.plot(plot_x0,plot_y0,'ro',lable='x_0')#第一类
plt.plot(plot_x1,plot_y1,'bo',lable='x_1')#第二类
plt.legend(loc='best')#自动选择最不碍事的地返回放图例
plt.show()
#转化成NumPy,在转化成Tensor
np_data=np.array(data,dtype='float32')#转化成numpy array
x_data=torch.from_numpy(np.data[:,0:2])#转化成Tensor,大小为[100,2]
y_data=torch.from_numpy(np.data[:,-1]).unsqueeze(1)#转化成Tensor,大小为[100,1]
#定义sigmoid函数
def sigmoid(x):
return 1/(1+torch.exp(-x))
#画出sigmoid的图像
plot_x=np.arange(-10,10.01,0.01)
plot_y=sigmoid(plot_x)
plt.plot(plot_x,plot_y,'r')
plt.show()
#转化为Variable
x_data=Variable(x_data)
y_data=Variable(y_data)
#参数与模型
"""
w=Variable(torch.randn(2,1),requires_need=True)
b=Variable(torch.zeros(1),requires_need=True)
"""
w=nn.Parameter(torch.randn(2,1))#用Parameter默认可自动更新参数
b=nn.Parameter(torch.zero(1))
def logistic_regression(x):
return sigmoid(torch.mm(w,x)+b)
#画出参数更新前的结果
w0=w[0].data[0]
w1=w[1].data[0]
b0=b.data[0]
plt_x=np.arange(0.2,1,0.01 )
plt_y=-(b0-w0*plot_x)/w1
plt.plot(plot_x,plot_y,'b',lable='cutting line')
plt.plot(plot_x0,plot_y0,'ro',label='x_0')
plt.plot(plot_x1,plot_y1,'bo',lable='x_1')
plt.legend(loc='best')
plt.show()
def binary_loss(y_pred,y):
logits=(y*y_pred.clamp(1e-12).log()+(1-y)*(1-y_pred).clamp(1e-12).log()).mean()
return -logits
"""
y_pred=logistic_regression(x_data)
loss=binary_loss(y_pred,y_data)
print(loss)#0.6412
loss.backward()
w.data=w.data-0.1*w.grad.data
b.data=b.data-0.1*b.grad.data
y_pred=logistic_regression(x_data)
loss=binary_loss(y_pred,y_data)
print(loss)#0.6407
"""
#用torch.optim更新参数
optimizer=torch.optim.SGD([w,b],lr=1.)
start=time.time()#返回当前时间的时间戳(1970纪元后经过的浮点秒数)。
#进行1000次更新
for e in range(1000):
#前向传播
y_pred=logistic_regression(x_data)
loss=binary_loss(y_pred,y_data)
#反向传播
optimizer.zero_grad()#使用优化器将梯度归零
loss.backward()
optimizer.step()#使用优化器来更新参数
#计算正确率
mask=y_pred.ge(0.5).float()
acc=(mask==y_data).sum().data[0]/y_data.shape[0]
if (e+1)%200==0:
print('epoch:{},Loss:{:.5f},Acc:{:.5f}'.format(e+1,loss.data[0],acc))
during=time.time()-start
print()
print('During time:{:3f}s'.format(during))
#画出更新后的结果
w0=w[0].data[0]
w1=w[1].data[0]
b0=b.data[0]
plt_x=np.arange(0.2,1,0.01 )
plt_y=-(b0-w0*plot_x)/w1
plt.plot(plot_x,plot_y,'b',lable='cutting line')
plt.plot(plot_x0,plot_y0,'ro',label='x_0')
plt.plot(plot_x1,plot_y1,'bo',lable='x_1')
plt.legend(loc='best')
plt.show()
或者使用自带的loss
criterion=nn.BCEWithgLogitsLoss()#将sigmoid和loss写在一层,有更快的速度、更好的稳定性
w=nn.Parameter(torch.randn(2,1))#用Parameter默认可自动更新参数
b=nn.Parameter(torch.zero(1))
def logistic_reg(x):
return torch.mm(x,w)+b
optimizer=torch.optim.SGD([w,b],lr=1.)
y_pred=logistic_reg(x_data)
loss=criterion(y_pred,y_data)
print(loss)
start=time.time()#返回当前时间的时间戳(1970纪元后经过的浮点秒数)。
#进行1000次更新
for e in range(1000):
#前向传播
y_pred=logistic_reg(x_data)
loss=criterion(y_pred,y_data)
#反向传播
optimizer.zero_grad()#使用优化器将梯度归零
loss.backward()
optimizer.step()#使用优化器来更新参数
#计算正确率
mask=y_pred.ge(0.5).float()
acc=(mask==y_data).sum().data[0]/y_data.shape[0]
if (e+1)%200==0:
print('epoch:{},Loss:{:.5f},Acc:{:.5f}'.format(e+1,loss.data[0],acc))
during=time.time()-start
print()
print('During time:{:3f}s'.format(during))
多层神经网络
激活函数(最右侧是Pytorch中调用)
激活函数的作用:
Pytorch实现
tanh
(
x
)
=
2
σ
(
2
x
)
−
1
\tanh (x) = 2\sigma (2x) - 1
tanh(x)=2σ(2x)−1
R
e
L
U
(
x
)
=
max
(
0
,
x
)
{\mathop{\rm Re}\nolimits} LU(x) = \max (0,x)
ReLU(x)=max(0,x)
现在神经网络90%情况都是使用这个激活函数,简单而有效。
加快梯度下降法的收敛速度,计算简单。
from torch import nn
import torch,nn.funtional as F
这是常规的定义方法
#定义两层神经网络的参数
w1=nn.Parameter(torch.randn(2,4)*0.01)#隐藏层神经元个数2
b1=nn.Parameter(torch.zeros(4))
w2=nn.Parameter(torch.randn(4,1)*0.01)
b2=nn.Parameter(torch.zeros(1))
#定义模型
def two_network(x):
x1=torch.mm(x,w1)+b1
x1=F.tanh(x1)#pytorch自带的tanh激活函数
x2=torch.mm(x1,w2)+b2
return x2
optimizer=torch.optim.SGD([w1,w2,b1,b2],lr=1.)
criterion=nn.BCEWithLogitsLoss()
for e in range(10000):
out=two_network(Variable(x))
loss=criterion(out,Variable(y))
optimizer.zero_grad()
loss.backward()
optimizer.step()
if(e+1)%1000==0:
print('epoch:{},loss:{}'.format(e+1,loss.data[0]))
完整的代码实现:
np.r_
中的r是row(行)的缩写,是按行叠加两个矩阵的意思,也可以说是按列连接两个矩阵,就是把两矩阵上下相加,要求列数相等,类似于pandas中的concat()。
np.c_
中的c是column(列)的缩写,是按列叠加两个矩阵的意思,也可以说是按行连接两个矩阵,就是把两矩阵左右相加,要求行数相等,类似于pandas中的merge()。
np.r_和np.c_详解
import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c = np.c_[a,b]
print(np.r_[a,b])#行
print(np.c_[a,b])#列
a = np.array([[1, 2, 3],[4,5,6]])
b = np.array([[0, 0, 0],[1,1,1]])
print("-------------------a------------------")
print(a)
print("-------------------b------------------")
print(b)
print("-------------------np.r_[a,b]--------------------")
print(np.r_[a,b])#行拼接
print("--------------------np.c_[a,b]-------------------")
print(np.c_[a,b])#列拼接
结果 :
[1 2 3 4 5 6]
[[1 4]
[2 5]
[3 6]]
-------------------a------------------
[[1 2 3]
[4 5 6]]
-------------------b------------------
[[0 0 0]
[1 1 1]]
-------------------np.r_[a,b]--------------------
[[1 2 3]
[4 5 6]
[0 0 0]
[1 1 1]]
--------------------np.c_[a,b]-------------------
[[1 2 3 0 0 0]
[4 5 6 1 1 1]]
import torch
import numpy as np
from torch import nn
from torch.autograd import Variable
import torch.nn.functional as F
import matplotlib.pyplot as plt
%matplotilb inline
def plot_decision_boundry(model,x,y):
#set min and max values and give it some padding
x_min,x_max=x[:,0].min()-1,x[:,0].max()+1
y_min,y_max=x[:,1].min()-1,x[:,1].max()+1
h=0.01
#网格点,距离为h
xx,yy=np.meshgrid(np.arange(x_min,x_max,h),np.arange(y_min,y_max,h))
#ravel():扁平化,如果没有必要,不会产生源数据的副本,np.c_按列叠加
#Predict the function value for the whole grid
z=model(np.c_[xx.ravel(),yy.ravel()])
z=z.reshape(xx.shape)
#Plot the contour and training examples绘制轮廓和训练样例
# xx和yy表示x轴方向的二维数据,yy表示y轴的二维方向的数据,Z表示颜色对应的标签值, cmap表示颜色板
plt.contourf(xx,yy,z,cmap=plt.cm.Spectral)
plt.ylable('x2')
plt.xlable('x1')
#散点图,c=颜色,s=大小
#cmap = plt.cm.Spectral实现的功能是给label为1的点一种颜色,给label为0的点另一种颜色。
plt.scatter(x[:,0],y[:,1],c=y.reshape(-1),s=40,cmp=plt.cm.Spectral)
np.random.seed(1)
m=400#样本数量
N=int(m/2)#每一类的点的个数,200
D=2#维数
x=np.zeros((m,D))
y=np.zeros((m,1),dtype='unit8')# label 向量,0为红色,1为蓝色
a=4
for j in range(2):
ix=range(N*j,N*(j+1))
t=np.linespace(j*3.12,(j+1)*3.12,N)+np.random.randn(N)*0.2#theta
r=a*np.sin(4*t)+np.random.randn(N)*0.2
x[ix]=np.c_[r*np.sin(t),r*np.cos(t)]
y[ix]=j
plt.scatter(x[:,0],y[:,1],c=y.reshape(-1),s=40,cmp=nn.sm.Spectral)
"""
尝试用logistic回归来解决
"""
x=torch.from_numpy(x).float()
y=torch.from_numpy(y).float()
w=nn.Parameter(torch.randn(2,1))
b=nn.Parameter(torch.zeros(1))
def logistic_regression(x):
return torch.mm(x,w)+b
optimizer=torch.optim.SGD([w,b],lr=1e-1)
criterion=nn.BCEWithLogitsLoss()
for e in range(100):
out=logistic_regression(Variable(x))
loss=criterion(out,Variable(y))
optimizer.zero_grad()
loss.backward()
optimizer.step()
if(e+1)%20==0:
print('epoch:{}.loss:{}'.format(e+1,loss.data[0]))
def plot_logistic(x):
x=Variable(torch.from_numpy(x))
out=F.sigmoid(logistic_regression(x))
out=(out>0.5)*1
return out.data.numpy()
plot_decision_boundry(lambda x:plot_logistic(x),x.numpy(),y.numpy())
plt.title('logistic regression')
"""
定义两层神经网络的参数
"""
w1=nn.Parameter(torch.randn(2,4)*0.01)#隐藏神经元2个
b1=nn.Parameter(torch.zero(4))
w2=nn.Parameter(torch.randn(4,1)*0.01)#隐藏神经元2个
b2=nn.Parameter(torch.zero(1))
def two_networks(x):
x1=torch.mm(x,w1)+b1
x1=F.Tanh(x1)
x2=torch(x1,w2)+b2
return x2
optimizer=torch.optim.SGD([w1,w2,b1,b2],lr=1)
criterion=nn.BCEWithLogitsLoss()
for e in range(1000):
out=two_networks(Variable(x))
loss=criterion(out,Variable(y))
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (e+1)%200==0:
print('epoch:{},loss:{}'.format(e+1,loss.data[0]))
def plot_network2(x):
x=Variable(torch.from_numpy(x))
x1=torch.mm(x,w1)+b1
x1=F.tanh(x1)
x2=torch.mm(x1,w2)+b2
out=F.sigmoid(x2)
out=(out>0.5)*1
return out.data.numpy()
plot_decision_boundry(lambda x:plot_logistic(x),x.numpy(),y.numpy())
plt.title('2 layer network')
"""
nn.Sequential可以定义序列化的模型,比如上面的两层网络,
可以按照顺序进行定义
只能按照顺序执行
"""
#Sequential
seq_net=nn.Sequential(
nn.linear(2,4),#pytorch中的线性层,wx+b
nn.Tanh(),
nn.linear(4,1))
#序列模块可以通过索引访问每一层
seq_net[0] #第一层
#打印出第一层的权重
w0=seq.net[0].weight
print(w0)
#通过parameter可以取得模型的参数
param=seq_net.parameters()
#定义优化器
optim=torch.optim.SGD(param,lr=1.)
for e in range(1000):
out=seq_net(Variable(x))
loss=criterion(out,Variable(y))
optim.zero_grad()
loss.backward()
optim.step()
if (e+1)%200==0:
print('epoch:{},loss:{}'.format(e+1,loss.data[0]))
def plot_seq(x):
out=(seq_net(Variable(torch.from_numpy(x).float())))
out=(out>0.5)*1
return out.data.numpy()
plot_decision_boundary(lambda x: plot_seq(x), x.numpy(), y.numpy())
plt.title('sequential')
"""
nn.Module
在后面还有具体解释
"""
class module_net(nn.Module):
def __init__(self):
super(module_net,self)__init__():
#定义模型
self.layer1=nn.Linear(2,4)
self.layer2=nn.Tanh()
self.layer3=nn.Linear(4,1)
#任意定义网络顺序
def forward(self,x):
x=self.layer1(x)
x=self.layer2(x)
x=self.layer3(x)
return x
如何保存模型
两种方式:
1.将模型结构和参数都保存在一起
#将参数和模型保存在一起
torch.save(seq_net,'save_seq_net.pth')
torch.save
里面有两个参数,第一个是要保留的模型,第二个是保存的路径。
读取模型的方式
#读取保存的模型
seq_net=torch.load('save_seq_net.pth')
print(seq_net[0].weight)
结果:
seq_net1
Sequential(
(0): Linear(in_features=2, out_features=4)
(1): Tanh()
(2): Linear(in_features=4, out_features=1))
Parameter containing:
-0.5532 -1.9916
0.0446 7.9446
10.3188 -12.9290
10.0688 11.7754
[torch.FloatTensor of size 4x2]
2.只将参数保存下来
#保存模型参数
torch.save(seq_net.state_dict(),'save_seq_net_params.pth')
读取参数时需要重新定义一次模型
seq_net2=nn.Sequential(x)(
nn.Linear(2,4),
nn.Tanh(),
nn.Linear(4,1))
seq_net2.load_state_dict(torch.load('save_seq_net_params.pth'))
print(seq.net2[0].weight)
结果:
seq_net2
Sequential(
(0): Linear(in_features=2, out_features=4)
(1): Tanh()
(2): Linear(in_features=4, out_features=1))
Parameter containing:
-0.5532 -1.9916
0.0446 7.9446
10.3188 -12.9290
10.0688 11.7754
[torch.FloatTensor of size 4x2]
推荐第二种,第二种可移植性更强。
nn.Module
class module_net(nn.module):
def __init__(self,num_input,num_hidden,num_output):
super(module_net,self).__init__()
self.layer1=nn.Linear(num_input,num_hidden)
self.layer2=nn.Tanh()
self.layer3=nn.Linear(num_hidden,num_output)
def fordward(self,x):
x=self.layer1(x)
x=self.layer2(x)
x=self.layer3(x)
return x
mo_net=module_net(2,4,1)
#访问模型中的某层可以直接通过名字
#第一层
l1=mo_net.layer1
print(l1)#Linear(in_features=2, out_features=4)
#打印第一层的权重
print(l1.weight)
#结果:
#Parameter containing:
#0.1492 0.4150
#0.3403 -0.4084
#-0.3114 -0.0584
#0.5668 0.2063
#[torch.FloatTensor of size 4x2]
#定义优化器
optim=torch.optim.SGD(mo_net.parameters(),lr=1.)
for e in range(1000):
out=mo_net(Variable(x))
loss=criterion(out,Variable(y))
optim.zero_grad()
loss.backward()
optim.step()
if (e+1)%200==0:
print('epoch:{},loss:{}'.format(e+1,loss.data[0]))
#保存模型
torch.save(mo_net.state_dict,'save_mo_net_params.pth')
练习:
定义一个5层甚至更深的模型,增加训练次数,改变学习率
net=nn.Squential(
nn.Linear(2,10),
nn.Tanh(),
nn.Linear(10,10),
nn.Tanh(),
nn.Linear(10,10),
nn.Tanh(),
nn.Linear(10,1)
)
#定义优化器
optim=torch.optim.SGD(mo_net.parameters(),lr=0.1)
for e in range(2000):
out=mo_net(Variable(x))
loss=criterion(out,Variable(y))
optim.zero_grad()
loss.backward()
optim.step()
if (e+1)%200==0:
print('epoch:{},loss:{}'.format(e+1,loss.data[0]))
#保存模型
torch.save(mo_net.state_dict,'save_mo_net_params.pth')
多分类问题&深层神经网络
c
r
o
s
s
_
e
n
t
r
o
p
y
(
p
,
q
)
=
E
p
[
−
log
q
]
cross\_entropy(p,q) = {E_p}[ - \log q]
cross_entropy(p,q)=Ep[−logq]
mnist输入:
选一张图片
28*28 pixels=784 像素点
图片都是由像素点构成,计算机读取像素点作为一个矩阵。
DataLoader(dataset, batch_size=1, shuffle=False, sampler=None,
num_workers=0, collate_fn=default_collate, pin_memory=False,
drop_last=False)
dataset:加载的数据集(Dataset对象)
batch_size:batch size 批量大小
shuffle::是否将数据打乱
sampler: 样本抽样,后续会详细介绍
num_workers:使用多进程加载的进程数,0代表不使用多进程
collate_fn: 如何将多个样本数据拼接成一个batch,一般使用默认的拼接方式即可
pin_memory:是否将数据保存在pin memory区,pin memory中的数据转到GPU会快一些
drop_last:dataset中的数据个数可能不是batch_size的整数倍,drop_last为True会将多出来不足一个batch的数据丢弃
#定义数据集
#使用pytorch自带的DataLoader定义一个数据迭代器
train_data=DataLoader(train_set,batch_size=64,shuffle=True)
test_data=DataLoader(test_set,batch_size=128,shuffle=False)
#定义模型
#使用Sequential定义4层神经网络
net=nn.Sequential(
nn.Linear(784,400),
nn.ReLU(),
nn.Linear(400, 200),
nn.ReLU(),
nn.Linear(200,100),
nn.ReLU(),
nn.Linear(100,10),
)
#定义loss函数和优化器
criterion=nn.CrossEntropyLoss()
optimizer=torch.optim.SGD(net.parameters(),lr=1e-1)#使用随机梯度下降,学习率0.1
#训练过程
for e in range(20):
for im,lable in train_data:
im=Varaible(im)
label=Variable(label)
#前向传播
out=net(im)
loss=criterion(out,label)
#反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
完整代码:
import numpy as np
import torch
from torchvision.datasets import mnist#导入pytorch内置的mnist数据
import matplotlib.pyplot as plt
from torch import nn
from torch.autograd import Varaible
from torch.utils.data import DataLoader
#使用内置函数下载mnist数据集
train_set=mnist.MNIST('./data',train=True,download=True)
test_set=mnist.MNIST('./data',train=False,download=True)
#看其中数据是什么样子
a_data,a_label=train_set[0]#a_data是数字图片,a_label是相应的数字标签
a_data=np.array(a_data,dtype='float32')
print(a_data.shape)#(28,28)
print(a_data)
#对于神经网络 ,第一层的输入是28*28=784,得到的数据需要使用reshape将它们拉平到一个一维向量
def data_tf(x):
x=np.array(x,dtype(float32))/255
x=(x-0.5)/0.5#标准化
x=x.reshape((-1,))#拉平,reshape(-1),都是竖着的一列
x=torch.from_numpy(x)
return x
a,a_label=train_set[0]
print(a.shape)#torch.Size([784])
print(a_label)#数字标签
#重新载入数据集,申明定义的数据变换
train_set=mnist.MNIST('./data',train=True,transform=data_tf,download=True)
test_set=mnist.MNIST('./data',train=False,transform=data_tf,download=True)
#定义数据集
#使用pytorch自带的DataLoader定义一个数据迭代器
train_data=DataLoader(train_set,batch_size=64,shuffle=True)
test_data=DataLoader(test_set,batch_size=128,shuffle=False)
#打印出一个批次的数据大小
a,a_label=next(iter(train_data))
print(a.shape)#torch.Size([64,784])
print(a_label.shape)#torch.Size([64])
print(a_label)
#torch.Size([64, 784])
#tensor([8, 5, 8, 0, 1, 6, 8, 6, 4, 1, 9, 9, 7, 6, 5, 9, 6, 3, 1, 9, 0, 1, 8, 6,
# 8, 4, 2, 2, 4, 1, 2, 0, 1, 9, 7, 1, 8, 2, 0, 3, 2, 6, 7, 6, 4, 0, 9, 5,
# 2, 6, 4, 5, 3, 2, 7, 0, 2, 0, 1, 9, 3, 6, 0, 6])
#定义模型
#使用Sequential定义4层神经网络
net=nn.Sequential(
nn.Linear(784,400),
nn.ReLU(),
nn.Linear(400, 200),
nn.ReLU(),
nn.Linear(200,100),
nn.ReLU(),
nn.Linear(100,10),
)
#定义loss函数和优化器
criterion=nn.CrossEntropyLoss()
optimizer=torch.optim.SGD(net.parameters(),lr=1e-1)#使用随机梯度下降,学习率0.1
#训练过程
losses=[]
acces=[]
eval_losses=[]
eval_acces=[]
for e in range(20):
train_loss = 0
train_acc = 0
net.train()
for im,lable in train_data:
im=Varaible(im)
label=Variable(label)
#前向传播
out=net(im)
loss=criterion(out,label)
#反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
#记录误差
train_loss+=loss.data[0]#每次是和64个真实标签的loss
#计算分类的准确性
_,pred=out.max(1)#矩阵中最大的数
num_correct=(pred==label).sum().data[0]
acc=num_correct/im.shape[0]#在torch中,64*784,每列64。实际784*64,每行64
train_acc+=acc
losses.append(train_loss/len(train_data))#平均每个batch_size的loss
acces.append(train_acc/len(train_data))
#在测试集上检验效果
eval_loss=0
eval_acc=0
net.eval()#将模型改为预测模式
for im,label in test_data:
im=Variable(im)
label=Variable(label)
#前向传播
out=net(im)
loss=criterion(out,label)
#记录误差
eval_loss+=loss.data[0]
#记录准确率
_,pred=out.max(1)
num_correct=(pred==label).sum().data[0]
acc=num_correct/im.shape[0]
eval_acc+=acc
eval_losses.append(eval_loss/len(test_data))
eval_acces.append(eval_acc / len(test_data))
print('epoch:{},Train Loss:{:.6f},Train Acc:{:.6f},Eval Loss:{:.6f},Eval Acc:{:.6f}'
.format(e,train_loss/len(train_data),train_acc/len(train_data),
eval_loss / len(test_data),eval_acc / len(test_data)))
#画出loss曲线和准确率曲线
#%matplotlib inline
plt.title('train loss')
plt.plot(np.arange(len(losses)),losses)
plt.title('train acc')
plt.plot(np.arange(len(acces)),acces)
plt.title('eval loss')
plt.plot(np.arange(len(eval_losses)),eval_losses)
plt.title('eval acc')
plt.plot(np.arange(len(eval_acces)),eval_acces)
反向传播算法
图解:
优化算法
除了梯度下降法之外,还有很多基于梯度下降法的改进算法:
局部最优解:局部最小点、鞍点。
"""
numpy.linspace(start, stop[, num=50[, endpoint=True[, retstep=False[, dtype=None]]]]])
返回在指定范围内的均匀间隔的数字(组成的数组),也即返回一个等差数列
start - 起始点,
stop - 结束点
num - 元素个数,默认为50,
endpoint - 是否包含stop数值,默认为True,包含stop值;若为False,则不包含stop值
retstep - 返回值形式,默认为False,返回等差数列组,若为True,则返回结果(array([`samples`, `step`])),
dtype - 返回结果的数据类型,默认无,若无,则参考输入数据类型。
plt.semilogx()和plt.semilogy()
用于绘制折线图,两个函数的 x 轴、y 轴分别是指数型的。
支持 plot 函数的所有参数,分别有一个重要参数:
basex: x 轴的底,需要大于 1
basey: y 轴的底,需要大于 1
"""
x_axis = np.linspace(0, 5, len(losses1), endpoint=True)
plt.semilogy(x_axis, losses1, label='batch_size=1')
plt.legend(loc='best')
随机梯度下降
batch size越小,梯度具有较高的随机性,从而震荡激烈。
batch size太大,对内存需要更高 ,同时不利于网络跳出局部极小点。
学习率太大会使得损失函数不断回跳,从而无法让损失函数较好降低,所以一般使用较小的学习率。
# 将速度初始化为和参数形状相同的张量
vs = []
for param in net.parameters():
vs.append(torch.zeros_like(param.data))
optimzier = torch.optim.SGD(net.parameters(), 1e-2)
动量法梯度下降
加完动量之后的loss下降的程度更低,
可以将动量理解成一种惯性作用,所以每次更新的幅度都会比不加动量的情况更多。
optimizer = torch.optim.SGD(net.parameters(), lr=1e-2, momentum=0.9) # 加动量
Adagrad
自适应
optimizer = torch.optim.Adagrad(net.parameters(), lr=1e-2)
RMSRrop
不同的alpha会使得loss在下降过程中的震荡程度不同。
optimizer = torch.optim.RMSprop(net.parameters(), lr=1e-3, alpha=0.9)
Adadelta
没有学习率
optimizer = torch.optim.Adadelta(net.parameters(), rho=0.9)
Adam
结合了动量法和RMSProp的优化算法
optimizer = torch.optim.Adam(net.parameters(), lr=1e-3)
参数初始化
一、使用NumPy来初始化
如果模型中的某一层需要被手动地修改:
import numpy as np
import torch
from torch import nn
#定义一个Sequential模型
net1=nn.Sequential(
nn.Linear(30.40),
nn.ReLU(),
nn.Linear(40,50),
nn.ReLU(),
nn.Linear(50,10)
)
#访问第一层的参数
w1=net1[0].weight
b1=net1[0].bias
print(w1.shape)#40*30
#定义一个Tensor直接对其进行替换
net1[0].weight.data=torch.from_numpy(np.random.uniform(3,5,size=(40,30)))#最小值为3,最大值为5
print(net1[0].weight)
模型中相同类型的层都需要初始化成相同的方式:
用循环去访问:
for layer in net1:
if isinstance(layer,nn.Linear):#判断是否为线性层,判断两个类型是否相同推荐使用 isinstance()。
param_shape=layer.weight.shape
layer.weight.data=torch.from_numpy(np.random.normal(0,0.5,size=param_shape))
#定义为均值为0,方差为0.5的正态分布
二、使用Module进行参数初始化
如果相对其中某个层进行初始化,类似上面进行初始化即可。
但是,如果用循环方式访问,需要用两个属性:children和modules
import numpy as np
import torch
from torch import nn
class sim_net(nn.Module):
def __init__(self):
super(sim_net,self).__init__()
self.l1=nn.Sequential(
nn.Linear(30,40),
nn.ReLU()
)
self.l1[0].weight.data=torch.randn(40,30)#直接对某一层初始化
self.l2=nn.Sequential(
nn.Linear(40,50),
nn.ReLU()
)
self.l3 = nn.Sequential(
nn.Linear(50, 10),
nn.ReLU()
)
def forward(self,x):
x=self.l1(x)
x=self.l2(x)
x=self.l3(x)
return x
net2=sim_net()
#访问children
for i in net2.children():
print(i)
"""
Sequential(
(0): Linear(in_features=30, out_features=40)
(1): ReLU()
)
Sequential(
(0): Linear(in_features=40, out_features=50)
(1): ReLU()
)
Sequential(
(0): Linear(in_features=50, out_features=10)
(1): ReLU()
)
"""
#访问module
for i in net2.modules():
print(i)
"""
sim_net(
(l1): Sequential(
(0): Linear(in_features=30, out_features=40)
(1): ReLU()
)
(l2): Sequential(
(0): Linear(in_features=40, out_features=50)
(1): ReLU()
)
(l3): Sequential(
(0): Linear(in_features=50, out_features=10)
(1): ReLU()
)
)
Sequential(
(0): Linear(in_features=30, out_features=40)
(1): ReLU()
)
Linear(in_features=30, out_features=40)
ReLU()
Sequential(
(0): Linear(in_features=40, out_features=50)
(1): ReLU()
)
Linear(in_features=40, out_features=50)
ReLU()
Sequential(
(0): Linear(in_features=50, out_features=10)
(1): ReLU()
)
Linear(in_features=50, out_features=10)
ReLU()
"""
children只会访问到模型定义的第一层。上述在模型中定义了三个Sequential,所以只会访问到三个Sequential.
而modules访问的是每一层
for layer in net2.modules():
if isinstance(layer, nn.Linear):
param_shape = layer.weight.shape
layer.weight.data = torch.from_numpy(np.random.normal(0, 0.5,size=param_shape))
三、对Tensor进行操作初始化torch.nn.init
from torch.nn import init
print(net1[0].weight)#40*30
init.xavier_uniform(net1[0].weight)
print(net1[0].weight)
更多推荐
所有评论(0)