Pytorch和Numpy
pytorch中的张量就类似于numpy中的n维数组。但是pytorch可以通过.cuda()方法使用GPU加速计算。这篇文章主要介绍pytorch的一些基本操作。这里也贴一下Pytorch的网站,里面也有torch的函数的参数说明以及例子。
1.首先是导入包。
<code class="language-plaintext hljs">import torch #导入pytorch包
import numpy #导入numpy包</code>
2.torch中常用的创建张量的方法
创建一个未初始化的2×3的矩阵
声明未初始化的矩阵,但使用前不包含确定的已知值。当创建一个未初始化的矩阵时,无论当时分配的内存中有什么值,都会显示为初始值。
<code class="language-plaintext hljs">a = torch.tensor([[1,2,3],[4,5,6]])#创建一个tensor([[1,2,3],[4,5,6]])
print(a.size())#获得张量a的形状,是一个元组
print(a)
x = torch.empty(2, 3)#多次运行可以看到,每次的x都是不一样的,因为未初始化
print(x.size())#获得张量x的形状,是一个元组
print(x)#此时的x未初始化,size与a相同。
y = torch.empty(2,3,out = a)
print(y.size())#获得张量y的形状,是一个元组
print(y)#运用a参数后,此时y和a一样了
empty_like = torch.empty_like(y) #创建一个size和y一样的未初始化张量。
print(empty_like.size())#获得张量empty_like的形状,是一个元组
print(empty_like)</code>
关于torch.empty,torch.empty_like:
<code class="language-plaintext hljs">torch.empty(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False, pin_memory=False) → Tensor
'''
返回一个未初始化的张量,张量大小由参数size定义。
参数说明:
size(int…):是一个用于定义输出的张量的形状的整形序列,也可以是list或者turple。
out(Tensor,可选):要求的值为张量,默认为none。也可以令out为一个具体张量a(a的shape与参数size相同),这样输出的张量就会和a一样。上面的例子可以看出。
dtype(torch.dtype,可选): 要求的值的类型是torch.dtype,默认值是torch.set_default_tensor_type的值。可以通过这个dtype参数来改变输出的张量的数据类型。
layout(torch.layout,可选):torch.layput表示torch.Tensor内存布局的对象。这个参数表示你希望返回的张量的内存布局类型,默认为torch.strided。torch.strided代表密集型张量,是最常见的内存布局;每个strided张量都关联一个torch.Storage,torch.Storage保存着strided张量的数据。
device(torch.device,可选):创建的张量存放的device。
requires_grad(bool,可选):要求的值为bool类型,默认为False。若为False则反向传播时不会对这个节点求导。
'''
torch.empty_like(input, *, dtype=None, layout=None, device=None, requires_grad=False, memory_format=torch.preserve_format) → Tensor
'''
返回一个与input形状一样的使用未初始化值填满的tensor,相当于torch.empty(input.size(), dtype=input.dtype, layout=input.layout,
参数说明:
dtype(torch.dtype,可选): 要求的值的类型是torch.dtype,默认值是torch.set_default_tensor_type的值。可以通过这个dtype参数来改变输出的张量的数据类型。
layout(torch.layout,可选):torch.layput表示torch.Tensor内存布局的对象。这个参数表示你希望返回的张量的内存布局类型,默认为torch.strided。torch.strided代表密集型张量,是最常见的内存布局;每个strided张量都关联一个torch.Storage,torch.Storage保存着strided张量的数据。
device(torch.device,可选):创建的张量存放的device。
requires_grad(bool,可选):要求的值为bool类型,默认为False。若为False则反向传播时不会对这个节点求导。
memory_format(torch.memory_format, 可选): 期望返回张量的保存类型,默认为torch.preserve_format。torch.memory类型用于保存torch.Tensor的储存格式。torch.preserve_format是保留输入张量的内存格式,用在clone这样的函数中。如果输入张量是分配在稠密不重叠的内存中,那么输出张量的stride与输入相同。否则,输出的strides使用torch.contiguous_format。
'''</code>
创建一个随机的初始化矩阵
<code class="language-plaintext hljs">x = torch.rand(2,3)
print(x)</code>
关于torch.rand:
<code class="language-plaintext hljs">torch.rand(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor
'''
返回服从均匀分布的初始化后的张量,张量大小由参数size定义。
参数说明:
size(int…):是一个用于定义输出的张量的形状的整形序列,也可以是list或者turple。
out(Tensor,可选):要求的值为张量,默认为none。也可以令out为一个具体张量a(a的shape与参数size相同),这样输出的张量就会和a一样。
dtype(torch.dtype,可选): 要求的值的类型是torch.dtype,默认值是torch.set_default_tensor_type的值。可以通过这个dtype参数来改变输出的张量的数据类型。
layout(torch.layout,可选):torch.layput表示torch.Tensor内存布局的对象。这个参数表示你希望返回的张量的内存布局类型,默认为torch.strided。torch.strided代表密集型张量,是最常见的内存布局;每个strided张量都关联一个torch.Storage,torch.Storage保存着strided张量的数据。
device(torch.device,可选):创建的张量存放的device。
requires_grad(bool,可选):要求的值为bool类型,默认为False。若为False则反向传播时不会对这个节点求导。
'''</code>
创建一个全是0的矩阵,并且令数据类型为torch.long
<code class="language-plaintext hljs">x = torch.zeros(2,3,dtype = torch.long)
print(x)</code>
关于torch.zeros:
<code class="language-plaintext hljs">torch.zeros(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor
'''
返回一个值全为0的张量,张量大小由参数size定义,值类型由torch.dtype定义。
参数说明:
size(int…):是一个用于定义输出的张量的形状的整形序列,也可以是list或者turple。
out(Tensor,可选):要求的值为张量,默认为none。也可以令out为一个具体张量a(a的shape与参数size相同),这样输出的张量就会和a一样。
dtype(torch.dtype,可选): 要求的值的类型是torch.dtype,默认值是torch.set_default_tensor_type的值。可以通过这个dtype参数来改变输出的张量的数据类型。
layout(torch.layout,可选):torch.layput表示torch.Tensor内存布局的对象。这个参数表示你希望返回的张量的内存布局类型,默认为torch.strided。torch.strided代表密集型张量,是最常见的内存布局;每个strided张量都关联一个torch.Storage,torch.Storage保存着strided张量的数据。
device(torch.device,可选):创建的张量存放的device。
requires_grad(bool,可选):要求的值为bool类型,默认为False。若为False则反向传播时不会对这个节点求导。
'''</code>
创建一个全是1的张量,并在此基础上创建新的张量
在现有张量上创建的张量,其属性将重用输入张量的属性,除非用户提供新的值。
<code class="language-plaintext hljs">x = x.new_ones(2,3,dtype = torch.double)#创建一个全是1的矩阵。
print(x)
x = torch.rand_like(x,dtype = torch.float)#重新设定了dtype
print(x)#可以看到形状一样,但数据类型不同了。
tensor = torch.tensor((),dtype = torch.int32)
print(tensor)#输出为tensor([], dtype=torch.int32)
tensor = tensor.new_ones(2,3)
print(tensor)#输出为tensor([[1, 1, 1],[1, 1, 1]], dtype=torch.int32),可以看到改变了形状、类型与值。</code>
关于torch.new_ones和torch.rand_like:
<code class="language-plaintext hljs">new_ones(size, dtype=None, device=None, requires_grad=False) → Tensor
'''
返回一个值全为1的张量,张量的size和dtype与tensor相同。
参数说明:
size(int…):是一个用于定义输出的张量的形状的整形序列,也可以是list或者turple。
dtype(torch.dtype,可选): 要求的值的类型是torch.dtype,默认值是None。若为None,则为与tensor相同的torch.dtype。
device(torch.device,可选):创建的张量存放的device,默认与input相同。
requires_grad(bool,可选):要求的值为bool类型,默认为False。若为False则反向传播时不会对这个节点求导。
'''
torch.randn_like(input, *, dtype=None, layout=None, device=None, requires_grad=False, memory_format=torch.preserve_format) -> Tensor
'''
返回一个和input相同size的张量,这个张量由均值为0,方差为1的标准正态分布填充。
参数说明:
dtype(torch.dtype,可选): 要求的值的类型是torch.dtype,默认值是None。若为None,则为与input相同的torch.dtype。
layout(torch.layout,可选):torch.layput表示torch.Tensor内存布局的对象。这个参数表示你希望返回的张量的内存布局类型,默认为input的分布。
device(torch.device, 可选):创建的张量存放的device,默认与input相同。
requires_grad(bool,可选):要求的值为bool类型,默认为False。若为False则反向传播时不会对这个节点求导。
memory_format(torch.memory_format, 可选): 期望返回张量的保存类型,默认为torch.preserve_format。torch.memory类型用于保存torch.Tensor的储存格式。torch.preserve_format是保留输入张量的内存格式,用在clone这样的函数中。如果输入张量是分配在稠密不重叠的内存中,那么输出张量的stride与输入相同。否则,输出的strides使用torch.contiguous_format。
'''</code>
创建一个值全为3.1416的5*3的矩阵
<code class="language-plaintext hljs">print(torch.full((5, 3), 3.1416)</code>
关于torch.full:
<code class="language-plaintext hljs">torch.full(size, fill_value, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False, pin_memory=False) → Tensor
'''
返回一个未初始化的张量,张量大小由参数size定义。
参数说明:
size(int…):是一个用于定义输出的张量的形状的整形序列,也可以是list或者turple。
out(Tensor,可选):要求的值为张量,默认为none。也可以令out为一个具体张量a(a的shape与参数size相同),这样输出的张量就会和a一样。上面的例子可以看出。
dtype(torch.dtype,可选): 要求的值的类型是torch.dtype,默认值是torch.set_default_tensor_type的值。可以通过这个dtype参数来改变输出的张量的数据类型。
layout(torch.layout,可选):torch.layput表示torch.Tensor内存布局的对象。这个参数表示你希望返回的张量的内存布局类型,默认为torch.strided。torch.strided代表密集型张量,是最常见的内存布局;每个strided张量都关联一个torch.Storage,torch.Storage保存着strided张量的数据。
device(torch.device,可选):创建的张量存放的device。
requires_grad(bool,可选):要求的值为bool类型,默认为False。若为False则反向传播时不会对这个节点求导。
'''</code>
创建一个n维单位矩阵
创建一个维度为4,对角线位置为1,其他位置全为0的二维张量。
<code class="language-plaintext hljs">eye = torch.eye(4)
print(eye.size())#获得张量eye的形状,是一个元组
print(eye)</code>
关于torch.eye:
<code class="language-plaintext hljs">torch.eye(n, m=None, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor
'''
返回一个行数为n,列数为m,对角线上为1而其他位置为0的二维张量。
参数说明:
n(int):要求输入一个整数,表示行数。
m(int):要求输入一个整数,表示列数,默认为None。如果为None,则m的值为n。
out(Tensor,可选):要求的值为张量,默认为none。也可以令out为一个具体张量a(a的shape与参数size相同),这样输出的张量就会和a一样。
dtype(torch.dtype,可选): 要求的值的类型是torch.dtype,默认值是torch.set_default_tensor_type的值。可以通过这个dtype参数来改变输出的张量的数据类型。
layout(torch.layout,可选):torch.layput表示torch.Tensor内存布局的对象。这个参数表示你希望返回的张量的内存布局类型,默认为torch.strided。torch.strided代表密集型张量,是最常见的内存布局;每个strided张量都关联一个torch.Storage,torch.Storage保存着strided张量的数据。
device(torch.device,可选):创建的张量存放的device。
requires_grad(bool,可选):要求的值为bool类型,默认为False。若为False则反向传播时不会对这个节点求导。
'''</code>
3.基本运算操作
pytorch中的加法运算
首先创建张量:
<code class="language-plaintext hljs">a = torch.rand(5,3)
b = torch.rand(5,3)
print(a)
print(b)
print(a + b)
print(torch.add(a, b))
result = torch.empty(5,3)
torch.add(a, b, out = result)#out参数提供一个输出张量作为加法的结果
print(result)
#任何改变一个张量的操作都用' _ '进行后固定。例如:‘x.copy_ (y)’, ‘x.t_()’,将改变x。
a.add_(b)#加了下划线之后,表示做a = a + b的操作,改变了a。
print(a)</code>
关于torch.add和torch.add_:
<code class="language-plaintext hljs">torch.add(input, other, *, alpha = 1,out = None) → Tensor
'''
返回input + alpha*other的结果。
参数说明:
input(Tensor):要求输入一个张量。
other(Tensor):要求输入一个张量,input和other必须是可广播的。
alpha(Number):other的乘数,要求输入是数字,默认为1。如果input是一个float的type是FloatTensor或者DoubleTensor,那么alpha必须是一个实数,否则应该是整型数。
out(Tensor,可选): 输出矩阵,默认为None。若不为None,则结果存储与out提供的张量里。
'''
Tensor.add_(other, *, alpha = 1,out = None) → Tensor
'''
torch.add()的in-place版本,各参数详解可见torch.add()。做Tensor = Tensor + other*alpha操作。
'''</code>
pytorch中的减法运算
首先创建张量:
<code class="language-plaintext hljs">a = torch.rand(5,3)
b = torch.rand(5,3)
print(a)
print(b)
print(a - b)
print(torch.sub(a, b))
result = torch.empty(5,3)
torch.sub(a, b, out = result)#out参数提供一个输出张量作为减法的结果
print(result)
a.sub_(b)#加了下划线之后,表示做a = a-b的操作,改变了a。
print(a)</code>
关于torch.sub和torch.sub_:
<code class="language-plaintext hljs">torch.sub(input, other, *, alpha = 1,out = None) → Tensor
'''
返回input - alpha*other的结果。支持广播到公共形状、类型提升以及整数、浮点和复杂输入。
参数说明:
input(Tensor):要求输入一个张量。
other(Tensor):要求输入一个张量,input和other必须是可广播的。
alpha(Number):other的乘数,要求输入是数字,默认为1。
out(Tensor,可选): 输出矩阵,默认为None。若不为None,则结果存储与out提供的张量里。
'''
Tensor.sub_(other, *, alpha = 1,out = None) → Tensor
'''
torch.sub()的in-place版本,各参数详解可见torch.sub()。做Tensor = Tensor - other*alpha操作。
'''</code>
pytorch的点乘
<code class="language-plaintext hljs">a = torch.rand(5,3)
b = torch.rand(5,3)
mul1 = a*b
mul2 = torch.mul(a,b)
torch.mul(a , b, out = mul3)
print(mul1. size())
print(mul1)
print(mul2. size())
print(mul2)
print(mul3.size())
print(mul3)</code>
关于mul
<code class="language-plaintext hljs">torch.mul(input, other, *, out = None) → Tensor
'''
返回input和other的哈达玛积(即对应元素相乘)。
参数说明:
input(Tensor):要求输入一个张量。
other(Tensor or Number):要求输入一个张量或数字,若输入的是张量则要求input和other必须是可广播的。输入类型可以是integer,float或者complex。
out(Tensor,可选): 输出矩阵,默认为None。若不为None,则结果存储与out提供的张量里。
'''</code>
pytorch的矩阵乘法
对二维Tensor
<code class="language-plaintext hljs">a = torch.rand(5,3)
b = torch.rand(3,5)
mat1 = torch.mm(a,b)
mat2 = torch.matmul(a,b)
mat3 = a@b
print(mat1.size(), mat2.size(), mat3.size())
print(mat1)
print(mat2)
print(mat3)</code>
对更高维度的Tensor,定义的矩阵乘法仅在最后两个维度上,
<code class="language-plaintext hljs">a = torch.rand(5,3,2,4,3)
b = torch.rand(5,3,2,3,4)
mat1 = torch.matmul(a,b)
print(mat1.size())</code>
torch.matmul中的广播机制以及一些例子:
<code class="language-plaintext hljs">#向量×向量
a = torch.rand(3)
b = torch.rand(3)
print(torch.matmul(a, b).size())
#torch.Size([])
#矩阵×向量
a = torch.rand(3,4)
b = torch.rand(3)
print(torch.matmul(a, b).size())
#torch.Size([3])
#批处理矩阵x广播向量
a = torch.rand(10,3,4)
b = torch.rand(3)
print(torch.matmul(a, b).size())#做矩阵乘法时b的size广播成(10,3,)了
#torch.Size([10, 3])
#批处理矩阵x批处理矩阵
a = torch.rand(10,3,4)
b = torch.rand(10,4,5)
print(torch.matmul(a, b).size())
#torch.Size([10, 3, 5])
#批处理矩阵x广播矩阵
a = torch.rand(10,3,4)
b = torch.rand(4,5)
print(torch.matmul(a, b).size())#做矩阵乘法时b的size广播成(10,4,5)了
#torch.Size([10, 3, 5])
#批处理矩阵x广播矩阵,前面维度为1的情况
a = torch.rand(10,1,3,4)
b = torch.rand(6,4,5)
print(torch.matmul(a, b).size())#做矩阵乘法时a和b的size广播成(10,6,4,5)了
# torch.Size([10, 6, 3, 5])</code>
关于torch.matmul:
<code class="language-plaintext hljs">torch.matmul( input , other , * , out=None ) → Tensor
'''
返回input和other的矩阵乘积。
参数说明:
input(Tensor):要求输入一个张量。
other(Tensor or Number):要求输入一个张量或数字,若输入的是张量则要求input和other必须是可广播的。输入类型可以是integer,float或者complex。
out(Tensor,可选): 输出矩阵,默认为None。若不为None,则结果存储与out提供的张量里。一维点积的情况不支持out参数。
'''</code>
pytorch的除法
<code class="language-plaintext hljs">a = torch.tensor([0.3810, 1.2774, -0.2972, -0.3719, 0.4637])
print(torch.div(a,0.5))#张量除标量
a = torch.tensor([[-0.3711, -1.9353, -0.4605, -0.2917],
[ 0.1815, -1.0111, 0.9805, -1.5923],
[ 0.1062, 1.4581, 0.7759, -1.2344],
[-0.1830, -0.0313, 1.1908, -1.4757]])
b = torch.tensor([ 0.8032, 0.2930, -0.8113, -0.2308])
print(torch.div(a, b))#张量除张量
print(torch.div(a,b,rounding_mode = ‘trunc’))#舍入模式为‘trunc’,则将结果向零舍入,相当于c语言的整数除法
print(torch.div(a,b,rounding_mode = ‘floor’))#舍入模式为‘floor’,则结果向下舍入,相当于python中的//运算</code>
关于torch.div:
<code class="language-plaintext hljs">torch.div(input, other, *, rounding_mode = None, out = None) → Tensor
'''
返回input的每个元素除以other对应元素的结果形成的张量。支持广播到通用形状、 类型提升以及整数、浮点数和复杂输入。始终将整数类型提升为默认标量类型。
参数说明:
input(Tensor):要求输入一个张量。被除数。
other(Tensor or Number):要求输入一个张量或数字,若输入的是张量则要求input和other必须是可广播的。输入类型可以是integer,float或者complex。
rounding_mode(str, 可选): 结果的选择类型,要求输入字符串,默认为None。若为None,则不执行舍入,相当于python中的/运算符;若为‘trunc’,则将结果向零舍入,相当于c语言的整数除法;若为‘floor’,则结果向下舍入,相当于python中的//运算符。
out(Tensor,可选): 输出矩阵,默认为None。若不为None,则结果存储与out提供的张量里。
'''</code>
pytorch的Resize
<code class="language-plaintext hljs">x = torch.randn(4,4)
print(x.view(16).size())
print(x.view(-1,8).size())#大小-1是从其他标注推断出来的</code>
关于Tensor.view:
<code class="language-plaintext hljs">Tensor.view(*shape) → Tensor
'''
返回一个数据与Tensor相同但形状与shape与所给参数一样的张量。
参数说明:
shape(torch.Size 或者int…):要求输入的是torch.size类型或者整形序列。表示输出的张量的形状。
'''</code>
4.其他一些常用操作
幂运算与开方
<code class="language-plaintext hljs">a = torch.full([2, 2], 3)
print(a.pow(2))#对应元素的乘方为值的张量
print(a.sqrt())#对应元素的开方为值的张量
print(a.rsqrt())#对应元素的开方的倒数为值的张量</code>
指数与对数
<code class="language-plaintext hljs">a = torch.full([2, 2], 1)
print(torch.exp(a))#e的对应元素次方为值的张量
print(torch.log(a))#取对应元素的值的自然对数为值的张量</code>
近似值
<code class="language-plaintext hljs">a = torch.tensor(3.1416)
print(a.floor())#向下取整
print(a.ceil())#向上取整
print(a.trunc())#取整
print(a.frac())#取小数
print(a.round())#四舍五入</code>
裁剪运算
<code class="language-plaintext hljs">#对Tensor中的元素进行过滤,超过给定上界的元素变为上界,低于给定下界的元素变为下界,常用于机器学习中的梯度裁剪。
a = torch.rand(5,3)*10
print(a.clamp(8)) #最小是8,小于8的都变成8
print(a.clamp(3,8)) # 最小是3,小于3的都变成3;最大是8,大于8的都变成8</code>
5.常用数据缩减操作
求最大最小值
<code class="language-plaintext hljs">a = torch.rand(5,3)*10
print(torch.max(a))#返回张量所有值的最大值
print(torch.max(a,0))#沿着第0维度求最大值。结果的shape为3
print(torch.max(a,1)) #沿着第1维度求最大值。结果的shape为5
print(torch.min(a))#返回张量所有值的最小值
print(torch.min(a,0))#沿着第0维度求最小值。结果的shape为3
print(torch.min(a,1)) #沿着第1维度求最小值。结果的shape为5</code>
求平均值
<code class="language-plaintext hljs">a = torch.rand(5,3)*10
print(torch.mean(a))#返回张量所有值的平均值
print(torch.mean(a,0))#沿着第0维度求平均值。结果的shape为3
print(torch.mean(a,1)) #沿着第1维度求平均值。结果的shape为5</code>
求输入张量的元素的积
<code class="language-plaintext hljs">a = torch.rand(5,3)
print(torch.prod(a))#a的所有元素的积
print(torch.prod(a,0))#沿着第0维度求积。结果的shape为3
print(torch.prod(a,1)) #沿着第1维度求积。结果的shape为5</code>
求输入张量的元素的标准差
<code class="language-plaintext hljs">a = torch.rand(5,3)
print(torch.std(a))#a的所有元素的标准差
print(torch.std(a,0))#沿着第0维度求标准差。结果的shape为3
print(torch.std(a,1)) #沿着第1维度求标准差。结果的shape为5</code>
求输入张量的元素的方差
<code class="language-plaintext hljs">a = torch.rand(5,3)
print(torch.var(a))#a的所有元素的方差
print(torch.var(a,0))#沿着第0维度求方差。结果的shape为3
print(torch.var(a,1)) #沿着第1维度求方差。结果的shape为5</code>
求输入张量的元素的和
<code class="language-plaintext hljs">a = torch.rand(5,3)
print(torch.sum(a))#a的所有元素的和
print(torch.sum(a,0))#沿着第0维度求和。结果的shape为3
print(torch.sum(a,1)) #沿着第1维度求和。结果的shape为5</code>
6.Numpy桥
可以将Torch张量转换为NumPy数组,反之亦然。Torch张量和NumPy数组将共享它们的底层内存位置(如果Torch张量在CPU上),改变一个就会改变另一个。
<code class="language-plaintext hljs">#torch转numpy
a = torch.ones(5)
print(a)
b = a.numpy()
print(b)
#改变a的值后,b的值也会发生变化。
a.add_(1)
print(a)
print(b)
#numpy转torch
a = np.ones(5)
b = torch.from_numpy(a)
np.add(a, 1, out=a)# 改变a的值后,b的值也会发生变化。
print(a)
print(b)</code>
7.结语
Numpy是一个很棒的框架,但是它不能利用gpu来加速它的数值计算。对于现代的深度神经网络,gpu通常提供50倍或更高的加速,所以很不幸numpy不足以满足现代的深度学习。
这里我们介绍最基本的PyTorch概念:张量。PyTorch张量在概念上与numpy数组相同:张量是一个n维数组,PyTorch提供了许多操作这些张量的函数。在幕后,张量可以跟踪计算图和梯度,但它们作为科学计算的通用工具也很有用。
与numpy不同的是,PyTorch张量可以利用gpu加速其数值计算。要在GPU上运行PyTorch张量,你只需要将它转换为一个新的数据类型。
最后,我想这篇文章后续还会更新一些我在学习的过程中常用的函数。关于计算图,我想另写一篇文章来介绍,也打算看看计算图可视化的一些基本操作。
8.参考
https://blog.csdn.net/Dontla/article/details/104675406/
https://blog.csdn.net/lzn025/article/details/114686880
转载:https://blog.csdn.net/weixin_43902376/article/details/128675707