import torch from torchvision import datasets, transforms import torch.nn as nn import torch.optim as optim import numpy as np
data
In [3]:
train_data=datasets.MNIST(root='data/mnist', train=True, transform=transforms.ToTensor(), download=True) test_data=datasets.MNIST(root='data/mnist', train=False, transform=transforms.ToTensor(), download=True)
Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz Failed to download (trying next): HTTP Error 403: Forbidden Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz to data/mnist\MNIST\raw\train-images-idx3-ubyte.gz
100%|██████████| 9.91M/9.91M [00:23<00:00, 428kB/s]
Extracting data/mnist\MNIST\raw\train-images-idx3-ubyte.gz to data/mnist\MNIST\raw Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz Failed to download (trying next): HTTP Error 403: Forbidden Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-labels-idx1-ubyte.gz Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-labels-idx1-ubyte.gz to data/mnist\MNIST\raw\train-labels-idx1-ubyte.gz
100%|██████████| 28.9k/28.9k [00:00<00:00, 65.1kB/s]
Extracting data/mnist\MNIST\raw\train-labels-idx1-ubyte.gz to data/mnist\MNIST\raw Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz Failed to download (trying next): HTTP Error 403: Forbidden Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz to data/mnist\MNIST\raw\t10k-images-idx3-ubyte.gz
100%|██████████| 1.65M/1.65M [00:07<00:00, 208kB/s]
Extracting data/mnist\MNIST\raw\t10k-images-idx3-ubyte.gz to data/mnist\MNIST\raw Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz Failed to download (trying next): HTTP Error 403: Forbidden Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz to data/mnist\MNIST\raw\t10k-labels-idx1-ubyte.gz
100%|██████████| 4.54k/4.54k [00:00<?, ?B/s]
Extracting data/mnist\MNIST\raw\t10k-labels-idx1-ubyte.gz to data/mnist\MNIST\raw
张量的获取与存储
In [4]:
arr=np.array([[1,2,3],[4,5,6]]) t=torch.tensor(arr) t
Out[4]:
tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.int32)
In [5]:
a=torch.zeros(3,3,3) a
Out[5]:
tensor([[[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]], [[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]], [[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]]])
In [6]:
d=torch.full([2,3],5) d
Out[6]:
tensor([[5, 5, 5], [5, 5, 5]])
In [7]:
points=torch.full([3,3],6) points
Out[7]:
tensor([[6, 6, 6], [6, 6, 6], [6, 6, 6]])
In [9]:
torch.save(points,"data/points.t")
In [10]:
new_p=torch.load("data/points.t") new_p
C:\Users\tanhaowen\AppData\Local\Temp\ipykernel_19060\1017535897.py:1: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature. new_p=torch.load("data/points.t")
Out[10]:
tensor([[6, 6, 6], [6, 6, 6], [6, 6, 6]])
In [17]:
with open("data/points.t","rb") as f: new_points=torch.load(f) new_points
C:\Users\tanhaowen\AppData\Local\Temp\ipykernel_19060\424723661.py:2: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature. new_points=torch.load(f)
Out[17]:
tensor([[6, 6, 6], [6, 6, 6], [6, 6, 6]])
通用存储格式
In [12]:
import h5py
In [13]:
points=torch.ones(3,3) f=h5py.File("data/points.hdf5","w") dset=f.create_dataset("abs",data=points.numpy()) f.close()
In [16]:
f=h5py.File("data/points.hdf5","r") dset=f["abs"] last_points=torch.from_numpy(dset[:]) f.close() last_points
Out[16]:
tensor([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]])
张量的基本操作
两种拼接方法cat()和stack()。cat不会扩张张量
的维度,而stack()会扩张张量的维度
In [19]:
a=torch.ones(4,5) a
Out[19]:
tensor([[1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.]])
In [23]:
cal_a1=torch.cat([a,a],dim=0) cal_a1
Out[23]:
tensor([[1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.]])
In [24]:
cal_a2=torch.cat([a,a],dim=1) cal_a2
Out[24]:
tensor([[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]])
In [26]:
a=torch.normal(0,1,(3,4)) b=torch.normal(0,1,(3,4)) a
Out[26]:
tensor([[-1.7911, 0.6957, -1.2896, 1.6791], [ 0.7843, -1.2995, 0.0932, -0.0388], [ 0.2603, -0.1247, -0.2939, -0.9207]])
In [30]:
cat_ab1=torch.stack([a,a],dim=0) cat_ab1
Out[30]:
tensor([[[-1.7911, 0.6957, -1.2896, 1.6791], [ 0.7843, -1.2995, 0.0932, -0.0388], [ 0.2603, -0.1247, -0.2939, -0.9207]], [[-1.7911, 0.6957, -1.2896, 1.6791], [ 0.7843, -1.2995, 0.0932, -0.0388], [ 0.2603, -0.1247, -0.2939, -0.9207]]])
In [31]:
cat_ab2=torch.stack([a,a],dim=2) cat_ab2
Out[31]:
tensor([[[-1.7911, -1.7911], [ 0.6957, 0.6957], [-1.2896, -1.2896], [ 1.6791, 1.6791]], [[ 0.7843, 0.7843], [-1.2995, -1.2995], [ 0.0932, 0.0932], [-0.0388, -0.0388]], [[ 0.2603, 0.2603], [-0.1247, -0.1247], [-0.2939, -0.2939], [-0.9207, -0.9207]]])
张量的切分
torch.chunk(input, chunks, dim=0)
按照指定的维度进行平均切分
In [33]:
a=torch.ones((3,7)) chunked_a=torch.chunk(a,3,1) chunked_a
Out[33]:
(tensor([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]]), tensor([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]]), tensor([[1.], [1.], [1.]]))
torch.split(tensor, splitsize_orsections, dim=0)
可以指定切分的长度
In [5]:
a=torch.ones([3,7]) splited_a1=torch.split(a,4,1) splited_a1
Out[5]:
(tensor([[1., 1., 1., 1.], [1., 1., 1., 1.], [1., 1., 1., 1.]]), tensor([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]]))
In [6]:
splited_a2=torch.split(a,[2,4,1],1) splited_a2
Out[6]:
(tensor([[1., 1.], [1., 1.], [1., 1.]]), tensor([[1., 1., 1., 1.], [1., 1., 1., 1.], [1., 1., 1., 1.]]), tensor([[1.], [1.], [1.]]))
张量的索引
torch.index select(input, dim, index,out=None)在按照index序号,在指定的维度上索引
In [7]:
points=torch.tensor([[4.0,1.0],[5.0,3.0],[2.0,1.0]]) idx=torch.tensor([0,2]) res=torch.index_select(points,0,idx) res
Out[7]:
tensor([[4., 1.], [2., 1.]])
使用范围直接索引
In [8]:
points=torch.tensor([[4.0,1.0],[5.0,3.0],[2.0,1.0]]) points
Out[8]:
tensor([[4., 1.], [5., 3.], [2., 1.]])
In [9]:
points[1:]# 输出第一行之后的所百行,别不不做外理
Out[9]:
tensor([[5., 3.], [2., 1.]])
In [10]:
points[1:,:]#出第一行之局的所有行,选取全部列
Out[10]:
tensor([[5., 3.], [2., 1.]])
In [11]:
points[1:,0]#出第一行之局的所有行,选取第一列
Out[11]:
tensor([5., 2.])
In [12]:
points[None]#可以升维
Out[12]:
tensor([[[4., 1.], [5., 3.], [2., 1.]]])
In [15]:
points.unsqueeze(0)
Out[15]:
tensor([[[4., 1.], [5., 3.], [2., 1.]]])
torch.masked select(input, mask, out=None)通过mask中为true的元素进行索引。通常这个方法是用来筛选数据。返回一维张量,
In [17]:
points=torch.tensor([[4.0,1.0],[5.0,3.0],[2.0,1.0]]) mask=points.ge(3) res=torch.masked_select(points,mask) res
Out[17]:
tensor([4., 5., 3.])
张量的变换
In [20]:
# torch.reshape(input,shasp)改变张量的形状。新张量与旧张量共享内存 points=torch.tensor([[4.0,1.0],[5.0,3.0],[2.0,1.0]]) new_points=torch.reshape(points,[2,3]) new_points
Out[20]:
tensor([[4., 1., 5.], [3., 2., 1.]])
In [21]:
# torch.transpose(input,dim0,dim1)交换张量的两个维度,交换也是共享内存. points=torch.tensor([[4.0,1.0],[5.0,3.0],[2.0,1.0]]) new_points=torch.transpose(points,0,1) new_points
Out[21]:
tensor([[4., 5., 2.], [1., 3., 1.]])
In [22]:
# torch.t(input)针对二维张量的转置而创建的,等价于torch.transpose(input, 0,1) points=torch.tensor([[4.0,1.0],[5.0,3.0],[2.0,1.0]]) new_points=torch.t(points) new_points
Out[22]:
tensor([[4., 5., 2.], [1., 3., 1.]])
torch.squeeze(input, dim=None, out=None)压缩张量中长度为1的维度
In [23]:
points=torch.squeeze(points) new_points=torch.squeeze(points) new_points.size()
Out[23]:
torch.Size([3, 2])
torch.unsqueeze(input, dim, out=None)依据dim扩展维度。扩展的长度为1
In [24]:
points = torch.ones(1,2,1,5) new_points=torch.unsqueeze(points,-1) new_points.size()
Out[24]:
torch.Size([1, 2, 1, 5, 1])
张量的元素类型
In [27]:
double_points=torch.ones(10,2,dtype=torch.double) short_points=torch.tensor([[1,2],[3,4]],dtype=torch.short)
查看元素类型
In [28]:
short_points.dtype
Out[28]:
torch.int16
转换元素类型
In [32]:
double_points=torch.zeros(10,2).double() short_points=torch.ones(10,2).short() double_points=torch.zeros(10,2).to(torch.double) short_points=torch.ones(10,2).to(dtype=torch.short)
不同元素类型运算
In [33]:
points_64=torch.rand(5,dtype=torch.double) points_short=points_64.to(torch.short) points_64 *points_short
Out[33]:
tensor([0., 0., 0., 0., 0.], dtype=torch.float64)
张量的命名
In [34]:
img_t=torch.rand(3,5,5) weights=torch.tensor([0.2126,0.7152,0.0722])
使用GPU计算
创建时指定设备
In [8]:
points_gpu=torch.tensor([[4.0,1.0],[5.0,3.0],[2.0,1.0]],device="cuda")
移动到指定设备
In [6]:
points=torch.tensor([[4.0,1.0],[5.0,3.0],[2.0,1.0]]) points_gpu=points.to(device='cuda') points_gpu=points.to(device='cuda:0')
回传到CPU
In [9]:
points_cpu=points_gpu.to(device="cpu") #有更简略的写达如下,但是我觉得用to/).更规范一点,而to/ # 可支持其他地的操作 points_gpu=points.cuda() points_gpu=points.cuda(0) points_cpu=points_gpu.cpu() # 什么都不写默认GPU
张量的底层设计
通过步长和偏移来实现
storage方法访问内存
In [12]:
points=torch.tensor([[4.0,1.0],[5.0,3.0],[2.0,1.0]]) points.storage()
Out[12]:
4.0 1.0 5.0 3.0 2.0 1.0 [torch.storage.TypedStorage(dtype=torch.float32, device=cpu) of size 6]
In [13]:
points_storage=points.storage() points_storage[0]
Out[13]:
4.0
In [14]:
points_storage[0]=2.0 points
Out[14]:
tensor([[2., 1.], [5., 3.], [2., 1.]])
关于带下划线的操作
In [2]:
a=torch.ones(3,2) a
Out[2]:
tensor([[1., 1.], [1., 1.], [1., 1.]])
In [4]:
b=a.zero_() b
Out[4]:
tensor([[0., 0.], [0., 0.], [0., 0.]])
In [5]:
a
Out[5]:
tensor([[0., 0.], [0., 0.], [0., 0.]])
In [14]:
points=torch.tensor([[4.0,1.0,3.0,2.0,],[5.0,3.0,7.0,8.0],[2.0,1.0,9.0,5.0],[3.0,8.0,4.0,5.0]]) second_points=points[1:,1:] second_points
Out[14]:
tensor([[3., 7., 8.], [1., 9., 5.], [8., 4., 5.]])
In [15]:
points.storage_offset()
Out[15]:
0
In [16]:
second_points.storage_offset()# 取到第一个数的偏移量
Out[16]:
5
In [17]:
points.stride()# 步长和和下一个元素的距离
Out[17]:
(4, 1)
In [19]:
second_points.stride()
Out[19]:
(4, 1)
In [20]:
second_points[0,0]=0 second_points
Out[20]:
tensor([[0., 7., 8.], [1., 9., 5.], [8., 4., 5.]])
In [21]:
points#second_points不是一个独立的变量
Out[21]:
tensor([[4., 1., 3., 2.], [5., 0., 7., 8.], [2., 1., 9., 5.], [3., 8., 4., 5.]])
转制后发生了什么
In [22]:
points=torch.tensor([[4.0,1.0],[5.0,3.0],[2.0,1.0]]) points
Out[22]:
tensor([[4., 1.], [5., 3.], [2., 1.]])
In [23]:
points_t=points.t() points_t
Out[23]:
tensor([[4., 5., 2.], [1., 3., 1.]])
验证两个tensor是否用的一个储存区
In [27]:
id(points.storage())==id(points_t.storage()) points.stride()
Out[27]:
(2, 1)
In [28]:
points_t.stride()
Out[28]:
(1, 2)
In [30]:
points[0][0]=100 points_t # 转制只是那个步长和偏移量变了,还是同一个存储区。
Out[30]:
tensor([[100., 5., 2.], [ 1., 3., 1.]])
points_t算得上是一个连续增量张量
关于连续张量
In [31]:
# 有些操作只对连续张亮起作用如果我们不对这些连续张亮实施这些操作就会报错 points_t_conut=points_t.contiguous() points_t_conut# 可以看到tensor的表示没有发生变化
Out[31]:
tensor([[100., 5., 2.], [ 1., 3., 1.]])
In [34]:
points_t_conut.stride()# 可以看到步长信息已经变了
Out[34]:
(3, 1)
In [33]:
points_t_conut.storage()# 你也可以看到存储器区已经发生了变化
Out[33]:
100.0 5.0 2.0 1.0 3.0 1.0 [torch.storage.TypedStorage(dtype=torch.float32, device=cpu) of size 6]
In [ ]:
发表回复