前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >pytorch入门

pytorch入门

作者头像
狼啸风云
修改2022-09-04 21:11:06
1.1K0
修改2022-09-04 21:11:06
举报

1、Tensor(张量)

Pytorch里面处理的最基本的操作对象就是Tensor,Tensor是张量的英文,表示的是一个多维的矩阵,比如零维就是一个点,一维就是向量,二维就是一般的矩阵,多维就相当于一个多维的数组,这和numpy是对应的,而且Pytorch的Tensor可以和numpy的ndarray相互转换,唯一不同的是Pytorch可以在GPU上运行,而numpy的ndarray只能在CPU上运行。

我们先介绍一下一些常用的不同数据类型的Tensor,有32位浮点型torch.Float Tensor、64位浮点型torch.DoubleTensor、16位整型torch.Shor tTensor、32位整型 torch.IntTensor和64位整型torch.LongTensor。我们可以通过下面这样的方式来定义一个三行两列给定元素的矩阵,并且显示出矩阵的元素和大小:

a = torch.Tensor([[2, 3],[4, 8],[7, 9]])
print('a is: {}'.format(a))
print('a size is {}'.foramt(a.size()))

需要注意的是 torch.Tensor默认的是torch.FloatTensor数据类型,也可以定义我们想要的数据类型,就像下面这样:

b = torch.LongTensor([[2, 3],[4, 8],[7, 9]])
print('b is : {}'.foramt(b))

当然也可以创建一个全是0的空Tensor或者取一个正太分布作为随机初始值:

c = torch.zeros((3, 2))
print('zero tensor: {}'.foramt())

d = torch.randn((3,2))
print('noraml randon is : {}'.foramt(d))

我们也可以像numpy一样通过索引的方式取得其中的元素,同时也可以改变它的值,比如将a的第一行第二列改变为100。

a[0, 1] = 100
print('changed a is: {}'.format(a))

除此之外,还可以在Tensor与numpy.ndarray之间相互转换:

numpy_b = b.numpy()
print('cover to many is \n {}'.foramt(numpy_b))

e = np.array([[2, 3],[4, 5]])
torch_e = torch.from_numpy(e)
print('from numpy tp torch.Tensor is {}'.format(torch_e))
f_torch_e = torch_e.float()
print('change data type to float tensor: {}'.format(f_torch_e))

通过简单的b.numpy(),就能将b转换为numpy数据类型,同时使用torch.from_numpy()就能将numpy转换为tensor,如果需要更改tensor的数据类型,只需要在换换后的tensor后面加上你需要的类型,比如想将a的类型转换为float,只需a.float()就可以了。如果你的电脑支持GPU加速,还可以将Tensor放到GPU上。首先通过torch.cuda.is_available()判断一下是否支持GPU,如果想把tensor a放到GPU上,只需a.cuda()就能将tensor a放到GPU上了。

if torch.cuda.is_available():
   a_cuda = a.cuda()
   print(a_cuda)

2、Variable(变量)

接着要讲的一个概念就是Variable,也就是变量,这个在numpy里面就meiyou,是神经网络计算图里特有的一个概念,就是Variable提供了自动求导的功能,之前如果了解通过Tensorflow的读者应该清楚神经网络在做员孙的时候需要先构造一个计算图谱,然后在里面运行前向传播和反向传播。Variable和Tensor本质上没有区别,不过Variable会被放入一个计算图中,然后进行前向传播,反向传播,自动求导。首先Variable是在torch.autograd.Variable,要将一个tensor变成Variable也非常简单,比如想让一个tensor a变成Variable,只需要Variable(a)就可以了。Variable有三个比较重要的组成属性:data、grad和grad_fn。通过data可以取出Variable里面重要的tensor数值,grad_fn表示的是得到这个Variable的操作。比如通过加减还是乘除来得到的,最后grad是这个Variable的反向传播梯度,下面通过例子来具体说明一下:

# Create Variable

x = Variable(torch.Tensor([1]), requires_grad=True)
w = Variable(torch.Tensor([2]), requires_grad=True)
b = Variable(torch.Tensor([3]), requires_grad=True)

# Build a computational graph.
y = w * x + b    # y = 2 * x + b

# Compute gradients
y.backward()  #same as y.backward(torch.FloatTensor([1]))
# Print out the gradients.
print(x.grad)    # x.grad = 2
print(w.grad)    # x.grad = 1
print(b.grad)    # x.grad = 1

构建Variable,要注意得传入一个参数requires_grad=True,这个参数表示是否对这个变形求梯度,默认的是False,也就是不对这个变量求梯度,这里我们希望得到这些变量的梯度,所以需要传入这个参数。从上面的代码中,我们注意到了一行y.backward(),这一行代码就是所谓的自动求导这其实等价于y.backward(torch.FloatTensor([1])),只不过对于标量求导里面的参数就可以不写了,自动求导不需要你再去明确哪个函数对哪个函数求导,得到它们的梯度,然后通过x.grad可以得到x的梯度。

x = torch.randn(3)
x = Variable(x, requires_grad=Ture)

y = x * 3
print(y)

y.backward(torch.FloatTensor([1, 0.1, 0.01]))
print(x.grad)

相当于给出了一个三维向量去做运算,这时候得到的结果y就是一个向量,这里对这个向量求导就不能直接写成y.backward(),这样程序就会报错的。这个时候需要传入参数声明,比如y.backward(troch.FloatTensor([1, 1, 1])),这样得到的结果就是它们每个分量的梯度,或者可以传入y.backward(torch.FloatTensor([1, 0.1, 0.01])),这样得到的梯度就是它们原本的梯度分别乘上1, 0.1和0.01。

3、Dataset(数据集)

在处理任何机器学习问题之前都需要数据读取,并进行预处理。Pytorch提供了很多工具使得数据的读取和预处理变得容易。torch.utils.data.Dataset是代表这一数据的抽象类,你可以自己定义你的数据类型继承好重写这个抽象类,非常简单,只需要定义__len__和__getitem__这两个函数:

class myDataset(Dataset):
    def __init__(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.readline()
        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,shuffle或者是多线程去读取数据,所以Pytorch中提供了一个简单的办法来做这个事情,通过torch.utils.data.DataLoader来定义一个新的迭代器,如下:

dataiter = DataLoader(myDataset, batch_size=32, shuffle = Ture, collate_fn = default_collate)

里面的参数都是特别清楚,只有collate_fn是表示如何取样本的,我们可以定义自己的函数来准确地实现想要的功能,默认的函数在一般情况下都是可以使用的。另外在torchvision这个包中还有一个更高级的有关于计算机视觉的数据读取类:ImageFolder,主要功能是处理图片,且要求图片是线面这种存放方式:

root/dog/xxx.png
root/dog/xxy.png
root/dog/xxz.png

root/dog/123.png
root/dog/asd.png
root/dog/zxc.png

之后这样来调用这个类:

dset = ImageFolder(root='root_path', transform=None, loader=default_loader)

其中的root需要是根目录,在这个目录下有几个文件,每个文件夹表示一个类别:transform和target_transfrom是图片增强,之后我们会详细讲:loader是图片读取的办法,因为我们读取的是图片的名字,然后通过loader经图片转换成我们需要的图片类型进入神经网络。

3.1.4、nn.Module(模组)

在Pytorch里面编写神经网络,所有的层结构和损失函数都来自由torch.nn,所有的模型构建都是从这个基类nn.Module继承的,于是有了下面这个模板。

class net_name(nn.Module):
    def __init__(self, other_argument):
        super(net_name, self).___init__()
        self.cov1 = nn.Conv2d(in_channels, cut_channels, kernel_size)
        # other network layer
    
    def forward(self, x):
        x = self.conv1(x)
        return x

这样就就建立了一个计算图,并且这个结构可以复用多次,每次调用就相当于用该计算图定义的相同参数做一次前向传播,这得益于Pytorch的自动求导功能,所以我们不需要自己编写反向传播,而所有的网络层都是由nn这个包得到的,比如线性层nn.Linear,等之后使用的时候我们可以详细地介绍每一种网络对应的结构,以及如何调用。定义完模型之后,我们需要通过nn这个包来定义损失函数。常见的损失函数都已经定义在了nn中,比如均方误差、多分类的定义熵,以及二分类的交叉熵,等等,调用这些已经定义好的损失函数也很简单:

criterion = nn.CrossEntropyLoss()
loss = criterion(output, target)

这样就能求得我们的输出和真实目标之间的损失函数了。

5、troch.optim(优化)

在机器学习或者深度学习中,我们需要通过修改参数使得损失函数最小化(或最大化),优化算法就是一种调整模型参数更新的策略。优化算法分为两大类。

1、一阶优化算法

这种算法使用各个参数的梯度值来更新参数,最常见的一阶优化算法是梯度下降。所谓的梯度就是导数的多变量表达式,函数的梯度形成了一个向量场,同时也是一个方向。这个方向上方向导数最大,且等于梯度。梯度下降的功能是通过寻找最小值,控制方差,更新模型参数,最终使模型收敛,网络的参数更新公式是:

\large \theta = \theta -\eta \times \frac{\partial J(\theta )}{\partial \theta }
\large \theta = \theta -\eta \times \frac{\partial J(\theta )}{\partial \theta }

其中

\large \eta
\large \eta

是学习率,

\large \frac{\partial J(\theta )}{\partial \theta x}
\large \frac{\partial J(\theta )}{\partial \theta x}

是函数的梯度。这是深度学习里面最常见的优化方法。

2、二阶优化算法

二阶优化算法使用了二阶导数(也叫做Hessian方法)来最下化或最大化损失函数,主要基于牛顿法,但是由于二阶导数的计算成本很高,所以这种方法并没有广泛使用。torch.optim是一个实现各种优化算法的包,大多数常见的算法都能够直接通过这个包来调用,比如随机梯度下降,以及添加动量的随机梯度下降,自使用学习率等。在调用的时候将需要优化的参数导入,这些参数都必须是Variable,然后传入一些基本的设定,比如计算率和动量等。

下面举一个例子:

optimizer = torch.optim,SGD(model.parameter(), lr=0.01, momentum=0.9)

这样我们就将模型的参数作为需要更新的参数传入优化器,设定学习率0.01,动量是0.9,的随机梯度下降,在优化之前需要先将梯度归零,即optimizer.zeros(),然后通过loss.backward()反向传播,自动求导得到两个参数的梯度,最后只需要optimizer.step()就可以通过梯度做一步参数更新。

6、模型的保存和加载

在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_dic(torch.load('model_state.pth'))来导入。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年08月29日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、Tensor(张量)
    • 2、Variable(变量)
      • 3、Dataset(数据集)
        • 3.1.4、nn.Module(模组)
          • 5、troch.optim(优化)
            • 6、模型的保存和加载
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档