深度学习/联邦学习随笔一
PyTorch基础知识
Tensor(张量)
PyTorch里面处理的最基本的操作对象就是Tensor,Tensor是张量的英文,表示的是一个多维的矩阵,比如零维就是一个点、一维就是向量、二维就是一般的矩阵、多维就是相当于一个多维的数组,这和numpy是对应的,且PyTorch的是Tensor可以和numpy的ndarray相互转换,唯一不同的是PyTorch可以在GPU上运行,而numpy的ndarray只能在CPU上运行
我们可以通过下面这样的方式来定义一个三行两列给定元素的矩阵,并且显示出矩阵的元素和大小:
import torch
a = torch. Tensor([[2,3],[4,8],[7,9]])
print('a is: { }',format(a))
print('a size is {}',format(a.size())) # a.size() = 3,2
需要注意的是torch . Tensor默认的是torch. FloatTensor数据类型,也可以定义我们想要的数据类型,就像下面这样:
b = torch. LongTensor([[2,3],[4,8],[7,9]])
print('b is : {}',format(b))
当然也可以创建一个全是0的空Tensor或者取一个正态分布作为随机初始值:
c=torch. zeros((3, 2))
print(' zero tensor:{}',format(c))
d = torch. randn((3, 2))
print('normal randon is : {}',format(d))
我们也可以像numpy一样通过索引的方式取得其中的元素,同时也可以改变它的值,比如将a的第一行第二列改变为100。
a[0, 1] = 100
print('changed a is: {}' ,format(a))
除此之外,还可以在Tensor与numpy.ndarray,之间相互转换:
numpy_b = b.numpy()
print('conver to numpy is \n {}' ,format(numpy_b))
e = np.array([[2,3],[4, 5]])
torch_e = torch.from_numpy(e)
print ('from numpy to torch Tensor is {}' ,format (torch_e))
f_torch_e = torch_e.float()
print('change data type to float tensor:{}',format(f_torch_e))
Variable(变量)
接着要讲的一个概念就是Variable,也就是变量,这个在numpy里面就没有了,是神经网络计算图里特有的一个概念,就是Variable 提供了自动求导的功能,神经网络在做运算的时候需要先构造一个计算图谱,然后在里面进行前向传播和反向传播。
Vrible和Tener本质上没有区别,不过Variable 会被放入一个计算图中,然后进行前向传播,反向传播,自动求导。
首先Vriable是在torch..autograd.Variable中, 要将个tensor变成Variable也非常简单,比如想让一个torch a 变成variable 只需要Variable(a)就可以了。Vriable有三个比较重要的属性:data,grad和grad_fn。通过data可以取出Variable里面的tensor值,
grad_fn表示的是得到这个variable的操作,如通过加减还是乘除得到。grad是这个variable的反向传播梯度,下面通过一个例子说明:
from torch.autograd import Variable
# Create Variable
x = Variable(torch.Tensor([1]),requires_grad=True)
w = Variable(torch. Tensor([2]),requires_grad=True)
b = Variable(torch.Tensor([31]),requires_grad=True)
# Build a computational graph.
#y=2*x+3
y=w*x+b
# Compute gradients
y.backward() # same as y .backward(torch.FloatTensor([1]))1 # Print out the gradients.
'''这-行代码就是所谓的自动求导,这其实等价于y.backward(torch. Floatenso(1)),只不过对于标量求导里面的参数就可以不写了,
自动求导不需要你再去明确地写明哪个函数对哪个函数求导,直接通过这行代码就能对所有的需要梯度的变量进行求导,
得到它们的梯度,然后通过x.grad可以得到x的梯度。'''
print (x.grad)
print (w.grad)
print (b.grad)
上面是标量的求导,同时也可以做矩阵求导,比如:
x = torch.randn(3)
x = Variable(x, requires_grad=True)
y=x*2
print(y)
y. backward(torch. FloatTensor([1, 0.1, 0.01]))
print (x. grad)
相当于给出了一个三维向量去做运算,这时候得到的结果y就是一个向量。对这个向量求导就不能直接写成y.backward(),这样程序是会报错的。这个时候需要传人参数声明比如y backward(torch. FloatTensor(1, 1, 1)),这样得到的结果就是它们每个分量的梯度,或者可以传人y. backward(torch.FloatTeng(1,0.1, 0.01))这样得到的梯度就是它们原本的梯度分别乘上1,0.1和0.01
(Dataset)数据集
在处理任何机器学习问题之前都需要数据读取,并进行项处理。PyTorch 提供了很多工具使得数据的读取和预处理变得很容易。
torch.utils.data.Dataset是代表这一数据的抽象类, 你可以自己定义你的数据类继承和重写这个抽象类,非常简单,只需要定义_1en_和_getitem_这两个函数:
from torch.utils.data import Dataset
class myDataset(Dataset):
def inti_(self,csv_file, txt_file, root_dir, other_file):
self.csv_data = pd.read_csv(csv_file)
with open(txt_file, 'r') as f:
data_list = f.readlines()
self.txt_data = data_list
self.root_dir = root_dir
def _len_ (self):
return len(self.csv_data)
def _getitem_ (self, idx):
data = (self.csv_data[idx],self.txt_data[idx])
return data
通过上面的方式,可以定义我们需要的数据类,可以通过迭代的方式来取得每一数据,但是这样很难实现取batch, shufle或者是多线程去读取数据,所以PyTorch提供了一个简单的办法来做这个事情, 通过torch. utils.data . DataLoader来定个新的迭代器,如下:
from torch.utils.data.dataloader import default_collate
dataiter = DataLoader(myDataset,batch_size=32,shuffle=True,collate_fn=default_collate)
里面的参数都特别清楚,只有collate fn 是表示如何取样本的,我们可以定义自己的函数来准确地实现想要的功能,默认的函数在一般情况下都是可以使用的。
nn.Module(模组)
在PyTorch里面编写神经网络,所有的层结构和损失函数都来自于torch.nn, 所有的模型构建都是从这个基类nn. Module继承的,于是有了下面这个模板:
from torch import nn
class net_name (nn.Module) :
def _init_ (self, other_arguments) :
super(net_name, self)._init_()
self.conv1 = nn.Conv2d(3, 6, 5)
# other network layer
def forward(self, x):
x = self.conv1(x)
return x
这样就建立了一个计算图,并且这个结构可以复用多次,每次调用就相当于用该计算图定义的相同参数做一次前向传播,这得益于PyTorch的自动求导功能,所以我们不需要自己编写反向传播,而所有的网络层都是由nn这个包得到的,比如线性层nn.Linear
定义完模型之后,我们需要通过nn这个包来定义损失函数。常见的损失定义都已经定义在了nn中,比如均方误差、多分类的交叉摘,以及二分类的交叉摘,等等,调用这些已经定义好的损失函数如下:
critertion = nn.CrooBntropyloso()
loss = critertion(output,target)
这样就能来得我们的输出和真实目标之间的损失函数了
torch.optim(优化)
在机器学习或者深度学习中,我们需要通过修改参数使得损失函数最小化(或最大化),优化算法就是一种调整模型参数更新的策略。
优化算法分为两大类。
1)一阶优化算法
这种算法使用各个参数的梯度值来更新参数,最常用的一阶优化算法是梯度下降,所谓的梯度就是导数的多变量表达式,函数的梯度形成了一个向量场,同时也是一个方向,这个方向上方向导数最大,且等于梯度。梯度下降的功能是通过寻找最小值,控制方差,更新模型参数,最终使模型收敛,网络的参数更新公式是:
其中,η是学习率, 是函数的梯度
2)二阶优化算法
二阶优化算法使用了二阶导数(也叫做Hessian方法)来最小化或最大化损失函数,主要基于牛顿法,但是由于二阶导数的计算成本很高,所以这种方法并没有广泛使|用。torch.optim是一个实现各种优化算法的包,大多数常见的算法都能够直接通过这个包来调用,比如随机梯度下降,以及添加动量的随机梯度下降,自适应学习率等。在调用的时候将需要优化的参数传入,这些参数都必须是Variable。然后传人一此基本的设定,比如学习率和动量等。
下面举一个例子:
optimizer= torch.optim.SGD(model.parameters(),lr=0.01,momentum=0.9)
这样我们就将模型的参数作为需要更新的参数传人优化器,设定学习率是0.01,动量是0.9的随机梯度下降,在优化之前需要先将梯度归零,即optimizer . zeros().然后通过loss . backward()反向传播,自动求导得到每个参数的梯度,最后只需要optimizer. step()就可以通过梯度做一步 参数更新。
模型的保存和加载
在PyTorch里面使用torch.save来保存模型的结构和参数,有两种保存方式:
(1)保存整个模型的结构信息和参数信息,保存的对象是模型model;
(2)保存模型的参数,保存的对象是模型的状态model.state_ dict()。
可以这样保存,save 的第一个参数是保存对象,第二个参数是保存路径及名称:
torch. save (model, '. /model. pth')
torch. save (model.state dict(),, ./model_ state .pth')
加载模型有两种方式对应于保存模型的方式:
(1 )加载完整的模型结构和参数信息,使用load model - torch. load( 'model.pth'),在网络较大的时候加载的时间比较长,同时存储空间也比较大;
(2)加载模型参数信息,需要先导人模型的结构,然后通过model .load state_die (torch. load('model_ state.pth')) 来导人。