动手学深度学习1- pytorch初学
pytorch 初学
Tensors
Tensors 与numpy 中的ndarrays很像,pytorch可以支持GPU操作
from __future__ import print_function
import torch
创建空的tensor
x = torch.empty(5,3) # 5行3列的空的tensors
print(x)
tensor([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
创建随机的一个随机数矩阵
x = torch.rand(5,3)
print(x)
tensor([[0.5109, 0.1927, 0.5499],
[0.8677, 0.8713, 0.9610],
[0.9356, 0.0391, 0.3159],
[0.0266, 0.7895, 0.6610],
[0.7188, 0.1331, 0.2180]])
创建0元素的矩阵
x = torch.zeros(5,3)
print(x)
tensor([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
直接从已经数据创建tensor
x= torch.tensor([5,5,3])
print(x)
tensor([5, 5, 3])
创建新的矩阵
x = x.new_ones(5,3,dtype=torch.double)
print(x)
# 根据现有的张量创建张量。 这些方法将重用输入张量的属性,例如, dtype,除非设置新的值进行覆盖
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]], dtype=torch.float64)
x = torch.randn_like(x,dtype=torch.float)
print(x)
# 更新了x的dtype,保留了原始的x的size
tensor([[ 0.8914, 1.5704, -0.1844],
[ 0.7747, -0.6860, -0.5596],
[ 0.1804, -0.2909, -1.3262],
[-1.3021, -0.4132, -2.7060],
[ 0.8989, -0.7269, 1.3862]])
print(x.size())
torch.Size([5, 3])
计算操作
加法操作
y = torch.rand(5,3)
print(x+y)
tensor([[ 1.6333, 2.1744, 0.4975],
[ 1.5430, -0.5863, -0.1416],
[ 0.6954, 0.6694, -0.4113],
[-0.9279, -0.1156, -1.8519],
[ 1.5791, 0.1524, 2.1037]])
print(torch.add(x,y))
tensor([[ 1.6333, 2.1744, 0.4975],
[ 1.5430, -0.5863, -0.1416],
[ 0.6954, 0.6694, -0.4113],
[-0.9279, -0.1156, -1.8519],
[ 1.5791, 0.1524, 2.1037]])
result = torch.empty(5,3)
torch.add(x,y,out=result)
print(result)
tensor([[ 1.6333, 2.1744, 0.4975],
[ 1.5430, -0.5863, -0.1416],
[ 0.6954, 0.6694, -0.4113],
[-0.9279, -0.1156, -1.8519],
[ 1.5791, 0.1524, 2.1037]])
# 加法操作,inplace 操作,替换y值,类似于y+=x
y.add_(x)
print(y)
tensor([[ 1.6333, 2.1744, 0.4975],
[ 1.5430, -0.5863, -0.1416],
[ 0.6954, 0.6694, -0.4113],
[-0.9279, -0.1156, -1.8519],
[ 1.5791, 0.1524, 2.1037]])
转化形状
x = torch.randn(4,4)
y= x.view(16)
z=x.view(-1,8) # the size -1 是根据其他维度进行计算出来的
print(x.size(),y.size(),z.size())
torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])
torch.numel(x) # return the number of the input tensor
16
tensor 与numpy 的转化
import numpy as np
a = np.array([1,2,3])
t = torch.as_tensor(a)
print(t)
tensor([1, 2, 3])
a = torch.ones(5)
print(a)
tensor([1., 1., 1., 1., 1.])
b = a.numpy() # 类似于a和b,a 变了,b也跟着变,类似于numpy 中的view的操作
print(b)
[1. 1. 1. 1. 1.]
a.add_(1)
print(a)
print(b)
tensor([2., 2., 2., 2., 2.])
[2. 2. 2. 2. 2.]
id(a),id(b)
(4487109080, 4807132064)
数据在GPU上的操作
# 以下代码只有在PyTorch GPU版本上才会执行,配的mac没有GPU,所以没有显示结果
if torch.cuda.is_available():
device = torch.device("cuda") # GPU
y = torch.ones_like(x, device=device) # 直接创建一个在GPU上的Tensor
x = x.to(device) # 等价于 .to("cuda")
z = x + y
print(z)
print(z.to("cpu", torch.double)) # to()还可以同时更改数据类型
自动梯度求导
深度学习中通常需要对函数求梯度(gradient),pytorch提供的autograd包能够根据输入和前向传播过程自动构建计算图,并执行方向传播过程,后续将主要介绍autograd包实现自动求梯度的有关操作
自动求导的概念
上节介绍的Tensor是这个包的核心类,如果将其属性 .required_grad 设置为True,将开始追踪(track)在其上的所有操作(可以利用链式法则进行梯度传播了)。计算完成后,可以调用.backward() 来完成所有的梯度计算。此Tensor的梯度将累积到.grad属性中。
需要注意的是,如果调用y.backward()时,如果y是标量,则不需要为backward() 传入任何参数。其余情况,需要传入一个与y相同shape的Tensor。
如果不想被继续追踪,可以调用.detach()将其追踪记录中分离出来,这样就可以防止将来的计算被追踪,这样梯度就传不过去了。此外还可以用with torch.no_grad() 将不想被追踪的操作代码块包裹起来,这样的方法在评估模型的时候常用,因为在评估模型时,不需要计算已经训练出的参数的的梯度。
Function 类
Function是另外一个很重要的类,Tensor和Function相互结合就可以构建一个记录有整个计算过程的有向无环图(DAG)????
每个Tensor都有一个.grad_fn属性,该属性即创建Tensor的Function,就是说该Tensor是不是通过某些运算得到的,如果是,grad_fn返还一个与这些运算相关的对象,否则是None。
Tensor实例
# 创建一个Tensor并设置requires_grad=True
x= torch.ones(2,2,requires_grad=True)
print(x)
print(x.grad_fn)# 返回结果为None,x是直接创建的,则说明该Tensor不是通过运算得到
tensor([[1., 1.],
[1., 1.]], requires_grad=True)
None
y =x+2
print(y)
print(y.grad_fn) ## AddBackward0,y是通过一个假发操作创建的
'''
想x这样直接通过创建的称为叶子节点,叶子节点对应grad_fn 是None
'''
print(x.is_leaf,y.is_leaf)
tensor([[3., 3.],
[3., 3.]], grad_fn=<AddBackward0>)
<AddBackward0 object at 0x11eb55cc0>
True False
复杂运算
z = y*y*3
out = z.mean()
print(z,out)
tensor([[27., 27.],
[27., 27.]], grad_fn=<MulBackward0>) tensor(27., grad_fn=<MeanBackward1>)
"""
可以通过.requires_grad_()来用in_place的方式改变requires_grad的属性
"""
a= torch.randn(2,2) # 缺失的情况下默认requires_grad=False
a =(a*3)/(a-1)
print(a.requires_grad) # False
a.requires_grad_(True)
print(a.requires_grad) # True
b = (a*a).sum()
print(b.grad_fn)
False
True
<SumBackward0 object at 0x11eb65780>
梯度
'''
因为out是一个标量,所以调用backward()时不需要指定求导变量:
'''
out.backward() # 等价于out.backward(torch.tensor(1.))
我们看下out关于x的梯度
\]
print(x.grad)
tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])
\]
\]
数学上的意义
数学上,如果有一个函数值和自变量都为向量的函数 y=f(x)
y=f(x), 那么 y关于x 的梯度就是一个雅可比矩阵(Jacobian matrix):
\]
而torch.autograd这个包就是用来计算一些雅克比矩阵的乘积的,例如如果v是一个标量函数的L = g(y)的梯度:
\]
那么根据链式法则,可以得到:L关于x的雅克比矩阵就是
\]
注意:grad在反向传播过程中是累加的(accumulated),这意味着运行反向传播,梯度都会累加到前一次的梯度,所以一般在反正传播之前需要把梯度清零
# 再来反向传播一次,注意grad是累加的
out2 = x.sum()
out2.backward()
print(x.grad)
out3 = x.sum()
x.grad.data.zero_() # 梯度清零,将梯度的数据变成0
out3.backward()
print(x.grad)
tensor([[5.5000, 5.5000],
[5.5000, 5.5000]])
tensor([[1., 1.],
[1., 1.]])
现在需要解释一个问题:
为什么在y.backward()时,如果y是标量,责不需要为backward()传入任何参数;否则需要传入一个与y同形的Tensor?
- 首先为了避免向量(甚至更高维张量)对张量求导,而转换成标量对张量求导;
- 不允许张量对张量求导,只允许标量与张量求导,求导的结果是和自变量同形的张量。这个地方说的就是不能让函数对函数求导(估计是一个意思吧)
x = torch.tensor([1.0,2.0,3.0,4.0],requires_grad=True)
y = 2*x
z= y.view(2,2)
print(z)
tensor([[2., 4.],
[6., 8.]], grad_fn=<ViewBackward>)
现在的y不是一个标量,所以在调用backward()时需要传入一个和y同形的权重向量进行加权就和得到一个标量。
v = torch.tensor([[1.0,1.0],[0.01,0.01]],dtype=torch.float)
z.backward(v) # 此时v就是与y同形的权重向量
print(x.grad) # x.grad是和x同形的张量
tensor([2.0000, 2.0000, 0.0200, 0.0200])
中断梯度追踪
x = torch.tensor(1.0,requires_grad=True)
y1 = x**2
with torch.no_grad():
y2 = x**3
y3 = y1+y2
print(x.requires_grad)
print(y1,y1.requires_grad) # 平方
print(y2,y2.requires_grad) # 标量,在with torch.no_grad未被追踪
print(y3,y3.requires_grad) # 求和
print(y2,y2.is_leaf) # 标量没有计算公式,y2也称为称为叶子节点,叶子节点对应grad_fn 是None
True
tensor(1., grad_fn=<PowBackward0>) True
tensor(1.) False
tensor(2., grad_fn=<AddBackward0>) True
tensor(1.) True
y3.backward()
print(x.grad)
tensor(2.)
y3 = y1+y2 =x2+ y3,当x=1 时,dy3/dx应该是5,但是y2的定义被torch.no_grad()包裹的,
所以与y2相关的梯度是不会被回传的,只有与y1有关的梯度才会回传,即x**2对x的梯度
修改tensor的数字,不被autograd记录(即不会影响方向传播),可以对tensor.data 进行操作
x = torch.ones(1,requires_grad=True)
print(x.data) # 也是一个tensor
print(x.data.requires_grad) # 但是已经是独立于计算图之外
y = 2*x
x.data *=100 # 只改变了data属性值,不会记录在计算图,因此不会影响梯度传播
y.backward()
print(x)
print(x.grad)
tensor([1.])
False
tensor([100.], requires_grad=True)
tensor([2.])
动手学深度学习1- pytorch初学的更多相关文章
- 小白学习之pytorch框架(2)-动手学深度学习(begin-random.shuffle()、torch.index_select()、nn.Module、nn.Sequential())
在这向大家推荐一本书-花书-动手学深度学习pytorch版,原书用的深度学习框架是MXNet,这个框架经过Gluon重新再封装,使用风格非常接近pytorch,但是由于pytorch越来越火,个人又比 ...
- 对比《动手学深度学习》 PDF代码+《神经网络与深度学习 》PDF
随着AlphaGo与李世石大战的落幕,人工智能成为话题焦点.AlphaGo背后的工作原理"深度学习"也跳入大众的视野.什么是深度学习,什么是神经网络,为何一段程序在精密的围棋大赛中 ...
- 【动手学深度学习】Jupyter notebook中 import mxnet出错
问题描述 打开d2l-zh目录,使用jupyter notebook打开文件运行,import mxnet 出现无法导入mxnet模块的问题, 但是命令行运行是可以导入mxnet模块的. 原因: 激活 ...
- 动手学深度学习9-多层感知机pytorch
多层感知机 隐藏层 激活函数 小结 多层感知机 之前已经介绍过了线性回归和softmax回归在内的单层神经网络,然后深度学习主要学习多层模型,后续将以多层感知机(multilayer percetro ...
- 动手学深度学习14- pytorch Dropout 实现与原理
方法 从零开始实现 定义模型参数 网络 评估函数 优化方法 定义损失函数 数据提取与训练评估 pytorch简洁实现 小结 针对深度学习中的过拟合问题,通常使用丢弃法(dropout),丢弃法有很多的 ...
- 动手学深度学习6-认识Fashion_MNIST图像数据集
获取数据集 读取小批量样本 小结 本节将使用torchvision包,它是服务于pytorch深度学习框架的,主要用来构建计算机视觉模型. torchvision主要由以下几个部分构成: torchv ...
- 《动手学深度学习》系列笔记—— 1.2 Softmax回归与分类模型
目录 softmax的基本概念 交叉熵损失函数 模型训练和预测 获取Fashion-MNIST训练集和读取数据 get dataset softmax从零开始的实现 获取训练集数据和测试集数据 模型参 ...
- 动手学深度学习4-线性回归的pytorch简洁实现
导入同样导入之前的包或者模块 生成数据集 通过pytorch读取数据 定义模型 初始化模型 定义损失函数 定义优化算法 训练模型 小结 本节利用pytorch中的模块,生成一个更加简洁的代码来实现同样 ...
- 动手学深度学习11- 多层感知机pytorch简洁实现
多层感知机的简洁实现 定义模型 读取数据并训练数据 损失函数 定义优化算法 小结 多层感知机的简洁实现 import torch from torch import nn from torch.nn ...
随机推荐
- NaN不等于NaN
目录 原因 表达式计算 类型转换 总结 不知道这个小知识点用得多不多,曾经在书上看到过,所以有一些印象,前段时间顺手写出类似如下的代码 var result; if (parseInt('abc')= ...
- 调用SqlCommand或SqlDataAdapter的Dispose方法,是否会关闭绑定的SqlConnection?(转载)
1. Does SqlCommand.Dispose close the connection? 问 Can I use this approach efficiently? using(SqlCom ...
- Winform 美化
首先,我们先来实现主界面的扁平化 此处分为两个步骤,第一步是更改winform自带的MainForm窗体属性,第二步是添加窗体事件. 将主窗体FormBorderStyle更改为None,这样就得到了 ...
- Python - 标准库概况 - 第二十一天
Python 标准库概览 操作系统接口 os模块提供了不少与操作系统相关联的函数. 建议使用 "import os" 风格而非 "from os import *&quo ...
- 2019年ASP.NET Core学习路线
- [先决条件] + C# + Entity Framework + ASP.NET Core + SQL 基础知识 - [通用开发技能] + 学习 GIT, 在 GitHub 中创建开源项目 + 掌 ...
- spring事务的三种配置应用实例
0.项目结构 具体代码见:https://github.com/xkzhangsan/spring-transaction-practice.git,包括创建表sql在内. 1.编程式事务使用Data ...
- MQ选型对比ActiveMQ,RabbitMQ,RocketMQ,Kafka 消息队列框架选哪个?
最近研究消息队列,发现好几个框架,搜罗一下进行对比,说一下选型说明: 1)中小型软件公司,建议选RabbitMQ.一方面,erlang语言天生具备高并发的特性,而且他的管理界面用起来十分方便.不考虑r ...
- iOS处理含中文的请求链接
NSString *urlStr = @""; // 将中文URL进行转码 urlStr = [urlStr stringByAddingPercentEscapesUsingEn ...
- [b0014] HDFS 常用JAVA 操作实战
目的: 学习用java进行的常用hdfs操作 参考: [b0002] Hadoop HDFS cmd常用命令练手 环境: hadoop2.6.4 win7 下的eclipse环境调试已经配置好,参考前 ...
- redo log 重做日志
--------------------------------------------------2015-02-10---------------------------------------- ...