大挪耗

pytorch张量的基本操作

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 [ ]:


已发布

分类

可以收藏大挪耗一下。下载麻烦点城通网盘,站长保证下载速度,不会限速的,放心点就是了;分卷,安卓下载为txt:程序下载为url,不会下载参考不会下载。如果你想让本站活的久一点,请直接捐助

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注