Tensor的操作

如果本文对你有帮助,欢迎点赞、订阅以及star我的项目。
你的支持是我创作的最大动力!

张量的数据属性与 NumPy 数组类似,如下所示:

张量的操作主要包括张量的结构操作和张量的数学运算操作。

  • Tensor的结构操作包括:创建张量查看属性修改形状指定设备数据转换索引切片广播机制元素操作归并操作
  • Tensor的数学运算包括:标量运算向量运算矩阵操作比较操作

创建张量

Pytorch中创建张量的方法有很多,如下图所示:

在深度学习过程中最多使用 5 5 5个维度的张量:标量(0维张量),向量(1维度张量),矩阵(2维张量),3维张量,4维张量,5维张量

创建标量**(0维张量)**

仔细观察下述代码,看看有什么区别:

x = torch.tensor(2)
print(x, x.shape, x.type())
y = torch.Tensor(2)
print(y, y.shape, y.type())
tensor(2) torch.Size([])
torch.LongTensortensor([0., 0.]) torch.Size([2])
torch.FloatTensor

注意到了torch.tensor与torch.Tensor的区别没?一字之差,结果差别却很大。

  • torch.Tensor(2) 使用全局默认 dtype(FloatTensor),返回一个size为 2 2 2的向量,初值为 0 0 0;
  • torch.tensor(2) 返回常量 2 2 2,数据类型从数据推断而来,其中的 2 2 2表示的是数据值。

创建向量(1维度张量)

向量只不过是一个元素序列的数组。例如,表示一个地区一段时间的气温。

x = torch.FloatTensor([23.5, 24.6, 25.9, 26.1])
print(x, x.shape, x.type())
tensor([23.5000, 24.6000, 25.9000, 26.1000]) torch.Size([4])
torch.FloatTensor

创建矩阵(2维向量)

从上面可知,创建矩阵的方式有很多,我们选择 from_numpy 的方式将 numpy 数组转换成 torch 张量。下面以波士顿房价的数据集为例子,它包含在机器学习包scikit-learn中。该数据集包含了 506 个样本,其中每个样本有 13 个特征。

from sklearn.datasets import load_bostonboston = load_boston() # 下载数据集
boston_tensor=torch.from_numpy(boston.data)
print(boston_tensor[:2])
print(boston_tensor.shape)
print(boston_tensor.type())
tensor([[6.3200e-03, 1.8000e+01, 2.3100e+00, 0.0000e+00, 5.3800e-01, 6.5750e+00,     6.5200e+01, 4.0900e+00, 1.0000e+00, 2.9600e+02, 1.5300e+01, 3.9690e+02,     4.9800e+00],    [2.7310e-02, 0.0000e+00, 7.0700e+00, 0.0000e+00, 4.6900e-01, 6.4210e+00,     7.8900e+01, 4.9671e+00, 2.0000e+00, 2.4200e+02, 1.7800e+01, 3.9690e+02,     9.1400e+00]], dtype=torch.float64)
torch.Size([506, 13])
torch.DoubleTensor

最常见的三维张量就是图片,例如 [ 224 , 224 , 3 ] [224, 224, 3] [224,224,3],下面我们演示如何加载图片数据。

from PIL import Image
panda = np.array(Image.open("../images/panda.jpg").resize((224,224)))
panda_tensor=torch.from_numpy(panda)
print(panda_tensor.size())
print(panda_tensor.dtype)
plt.imshow(panda_tensor)
torch.Size([224, 224, 3])torch.uint8

创建4维张量

4维张量最常见的例子就是批图像。例如,加载一批 [ 64 , 224 , 224 , 3 ] [64, 224, 224, 3] [64,224,224,3] 的图片,其中 64 64 64 表示批尺寸, [ 224 , 224 , 3 ] [224, 224, 3] [224,224,3] 表示图片的尺寸。

from glob import glob
data_path = "./data/cats/"
imgs = glob(data_path+'*.jpg')
imgs_np = np.array([np.array(Image.open(img).resize((224,224))) for img in imgs])
imgs_np = imgs_np.reshape(-1, 224, 224, 3)
imgs_tensor=torch.from_numpy(imgs_np)
print(imgs_tensor.shape)
print(imgs_tensor.dtype)
torch.Size([397, 224, 224, 3])
torch.uint8

上面代码中一共读取了 397 397 397 张图片。

创建5维张量

使用5维度张量的例子是视频数据。视频数据可以划分为片段,一个片段又包含很多张图片。例如, [ 32 , 30 , 224 , 224 , 3 ] [32, 30, 224, 224, 3] [32,30,224,224,3] 表示有 32 32 32 个视频片段,每个视频片段包含 30 30 30 张图片,每张图片的尺寸为 [ 224 , 224 , 3 ] [224, 224, 3] [224,224,3]。下面,我们模拟产生这样一个尺寸的5维数据(注意:只是模拟产生 5 5 5维数据,并不是真的视频数据)。

video_tensor=torch.randn(32,30,224,224,3)
print(video_tensor.shape)
print(video_tensor.dtype)
torch.Size([32, 30, 224, 224, 3])
torch.float32

查看属性

张量有很多属性,下面我们看看常用的属性有哪些?

  • tensor.shape,tensor.size(): 返回张量的形状;
  • tensor.ndim:查看张量的维度;
  • tensor.dtype,tensor.type():查看张量的数据类型;
  • tensor.is_cuda:查看张量是否在GPU上;
  • tensor.grad:查看张量的梯度;
  • tensor.requires_grad:查看张量是否可微。
tensor = torch.randn(2,3)
print("形状: ", tensor.shape, tensor.size())
print("维度: ", tensor.ndim)
print("类型: ", tensor.dtype, tensor.type())
print("cuda: ", tensor.is_cuda)
print("梯度: ", tensor.grad)
形状:  torch.Size([2, 3]) torch.Size([2, 3])
维度:  2
类型:  torch.float32 torch.FloatTensor
cuda:  False
梯度:  None

其中,torch.FloatTensor 就是 32 32 32位的浮点数。

修改张量的形状

在处理数据和构建网络的时候,时常需要修改 Tensor 的形状。涉及到修改形状的常见函数如下:

  • tensor.numel():计算Tensor的元素个数;
  • tensor.view(*shape):修改Tensor的形状。view()返回的Tensor与源Tensor共享内容。使用view必须要求源Tensor是连续的,否则会执行失败。view(-1)实现展平;
  • tensor.resize(*shape):功能类似与 view,resize不要求Tensor内存连续;
  • tensor.reshape(*shape):修改Tensor的形状,Reshape返回新的Tensor;
  • tensor.unsqueeze(pos):在指定位置添加一个维度;
  • tensor.squeeze():消除维度为 1 1 1的维。
import torch
x = torch.randn(2,3)
print("元素个数: {}".format(x.numel()))
# view调整尺寸
print("\ntensor.view(3,2): \n{}".format(x.view(3,2)))
print("tensor.view(-1): {}".format(x.view(-1)))
# resize调整尺寸
print("\ntensor.resize(3,2): \n{}".format(x.resize(3,2)))
# reshape调整尺寸
print("\ntensor.reshape(3,2): \n{}".format(x.reshape(3,2)))
print("tensor.reshape(-1): {}".format(x.reshape(-1)))
#添加一个维度
x123 = x.unsqueeze(0)
x213 = x.unsqueeze(1)
x231 = x.unsqueeze(2)
print("\ntensor.unsqueeze(0): {}".format(x123.shape))
print("tensor.unsqueeze(1): {}".format(x213.shape))
print("tensor.unsqueeze(2): {}".format(x231.shape))
# 去掉维度为1的维
print("\ntensor.squeeze(): {}".format(x123.squeeze().shape))
print("tensor.squeeze(): {}".format(x213.squeeze().shape))
print("tensor.squeeze(): {}".format(x231.squeeze().shape))
元素个数: 6
tensor.view(3,2):
tensor([[ 0.1274, -1.5990],        [-0.8852, -1.3436],        [-0.7716,  1.5765]])
tensor.view(-1): tensor([ 0.1274, -1.5990, -0.8852, -1.3436, -0.7716,  1.5765])
tensor.resize(3,2):
tensor([[ 0.1274, -1.5990],        [-0.8852, -1.3436],        [-0.7716,  1.5765]])
tensor.reshape(3,2):
tensor([[ 0.1274, -1.5990],        [-0.8852, -1.3436],        [-0.7716,  1.5765]])
tensor.reshape(-1):
tensor([ 0.1274, -1.5990, -0.8852, -1.3436, -0.7716,  1.5765])
tensor.unsqueeze(0): torch.Size([1, 2, 3])
tensor.unsqueeze(1): torch.Size([2, 1, 3])
tensor.unsqueeze(2): torch.Size([2, 3, 1])
tensor.squeeze(): torch.Size([2, 3])
tensor.squeeze(): torch.Size([2, 3])
tensor.squeeze(): torch.Size([2, 3])

在上述函数中,有三个函数都可以调整Tensor的尺寸:view,reshape,resize。他们之间有什么区别嘛?

  • reshape可以由torch.reshape(),tensor.reshape()调用,而view只能通过tensor.view()调用。
  • view()方法只能改变连续的张量,否则必须先调用.contiguous()方法使内存连续;.reshape()方法不受此限制。方法.transpose(), .permute()会使的Tensor在内存中不连续。
  • view() 返回的Tensor与源Tensor共享内存;.reshape()返回的Tensor与源Tensor不共享内存;
  • resize() 与 .reshape()效果类似。
  • 如果只想重塑Tensor,建议使用.reshape;如果关注内存希望两个Tensor共享内存,建议使用.view()。

指定设备

PyTorch 为CPU 和 GPU 提供了不同的张量实现。每个张量都可以转化到 GPU 中,以便大规模计算。创建Tensor时,默认指定的设备是CPU。

创建Tensor时,我们可以通过torch.tensor([…],dtype=,device=‘cpu/cuda’) 指定Tensor所属的设置是CPU还是GPU;也可以通过 tensor.to(device=cpu/cuda)或者tensor.cuda(),tensor.cpu() 把张量转化到指定的设备上。

# 创建CPU上的张量
tensor_cpu = torch.tensor([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=torch.float64, device='cpu')
print(f"tensor_cpu = \n{tensor_cpu}")
# 创建GPU上的张量
tensor_gpu = torch.tensor([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=torch.float64, device='cuda')
print(f"tensor_gpu = \n{tensor_gpu}")
tensor_cpu = tensor([[1., 2.],        [3., 4.],        [5., 6.]], dtype=torch.float64)
tensor_gpu = tensor([[1., 2.],        [3., 4.],        [5.,6.]],device='cuda:0',dtype=torch.float64)
# cpu -> gpu
tensor_gpu_cpu = tensor_gpu.to(device='cpu')print(f"tensor_gpu_cpu = {tensor_gpu_cpu}")
# gpu -> cpu
tensor_cpu_gpu = tensor_cpu.to(device='cuda')print(f"tensor_cpu_gpu = {tensor_cpu_gpu}")
tensor_gpu_cpu = tensor([[ 5., 10.],        [15., 20.],        [25., 30.]], dtype=torch.float64)
tensor_cpu_gpu = tensor([[ 5., 10.],        [15., 20.],        [25., 30.]], device='cuda:0', dtype=torch.float64)

数据转换

有时候,我们需要把Tensor转换成普通的数据,我们可以使用下列方式进行操作:

  • .numpy():把Tensor转换成numpy数据;
  • .item():如果Tensor为单元素,则返回Python标量;
  • .detach():返回一个与当前计算图分离且无梯度的新张量;
# 把tensor转化为numpy array
f = torch.tensor([1.0, 2.0, 3.0, 4.0], dtype=torch.float64)
f_numpy = f.numpy()
print(type(f_numpy), f_numpy) # <class 'numpy.ndarray'> [1. 2. 3. 4.]
# 把单元素Tensor转化为python标量
f_item = f[0].item()
print(type(f_item), f_item) # <class 'float'> 1.0
# 获取分离计算图的新张量
a = torch.tensor([1.0, 2.0], requires_grad=True)
b = torch.tensor([3.0, 4.0], requires_grad=True)
c = a + bd = c.detach()
print("c.grad: {}; d.grad: {}".format(c.requires_grad, d.requires_grad))
# c is grad: True; d is grad: False

索引切片

Tensor的索引切片操作与Numpy类似,也是Pytorch中经常使用的操作方式。需要注意的是,一般情况下索引结果与源数据共享内存。从Tensor中获取元素除了可以通过索引,也可以使用专有的函数。

常见的操作函数如下:

★提取元素的操作:

  • torch.index_select(input, dim, index):在指定维度上选择一些行或列;
  • torch.nonzero(input):获取非0元素的下标;
  • torch.masked_select(input, mask):使用二元值(真值表)进行选择元素;
  • torch.gather(input, dim, index):在指定的维度上选择数据,输出的形状与index一致;
  • torch.take(input, index):将输入看成一维数组,输出与index同形状。

★会对元素进行修改的操作:

  • torch.scatter_(input, dim, index, src):为gather的反操作,根据指定索引填充数据;
  • torch.where(condition, x, y):根据条件进行选择填充,这个操作函数用的非常多;
  • torch.masked_fill:使用二元值(真值表)进行填充元素;
  • torch.index_fill:使用下标进行填充。

代码从两部分进行演示,先展示提取元素的操作:

# 索引操作
>>> x = torch.randn(2, 3)
tensor([[ 0.3607, -0.2859, -0.3938],        [ 0.2429, -1.3833, -2.3134]])
# index_select
>>> x = torch.randn(2, 3)
>>> torch.index_select(x, dim=1, index=torch.tensor([0,2])) tensor([[-0.5883,  0.4322],        [ 0.4612, -0.2675]])
# masked_select
>>> x = torch.randn(2, 3)
>>> mask = x>0 # 产生真值Tensor
>>> select2 = torch.masked_select(x, mask) # 选择真值为True的元素
>>> select2
tensor([0.5605, 0.5895])
# nonzeros
>>> torch.nonzeros(mask)tensor([[0, 1],        [1, 0]])
# gather
>>> #out[i][j] = input[index[i][j]][j]  # if dim == 0
>>> #out[i][j] = input[i][index[i][j]]  # if dim == 1
>>> index = torch.LongTensor([[0, 1, 1]])
>>> gather1 = torch.gather(x, dim=0, index=index)
>>> print("gather1: {}".format(gather1))
gather1: tensor([[ 0.3607, -1.3833, -2.3134]])>>> index = torch.LongTensor([[0,1,1],[1,1,1]])
>>> a = torch.gather(x, dim=1, index=index)
>>> print("gather2: {}".format(a))
gather2: tensor([[ 0.3607, -0.2859, -0.2859],        [-1.3833, -1.3833, -1.3833]])
# take
>>> src = torch.tensor([[4, 3, 5], [6, 7, 8]])
>>> out = torch.take(src, index=torch.tensor([0, 3, 5]))
>>> print("out: {}".format(out))
out: tensor([4, 6, 8])

会对元素进行修改的操作:

# scatter_
>>> z = torch.zeros(2,3)
>>> b = z.scatter_(dim=1, index, a)
>>> print("b: {}".format(b))b: tensor([[ 0.3607, -0.2859,  0.0000],        [ 0.0000, -1.3833,  0.0000]])
# where
>>> x = torch.rand(3, 2)
>>> y = torch.ones(3, 2)>>> result = torch.where(x>0.5, x, y)
>>> print("result: {}".format(result))
result: tensor([[1.0000, 1.0000],        [1.0000, 0.8238],        [0.5557, 0.9770]])
# masked_fill
>>> x = torch.rand(3, 2)
>>> torch.masked_fill(x, x < 0.5, -1.0)
tensor([[-1.0000, -1.0000],        [ 0.8935, -1.0000],        [-1.0000, -1.0000]])
# index_fill
>>> x = torch.rand(3, 2)
>>> torch.index_fill(x , dim = 0, index = torch.tensor([0,1]), value = 100)
tensor([[100.0000, 100.0000],        [100.0000, 100.0000],        [  0.9798,   0.5548]])

在上述函数中,torch.gather() 和 torch.scatter_() 让人很难理解。借用官网的一段代码进行详细说明一下:

# gather
out[i][j][k] = input[index[i][j][k]][j][k]  # if dim == 0
out[i][j][k] = input[i][index[i][j][k]][k]  # if dim == 1
out[i][j][k] = input[i][j][index[i][j][k]]  # if dim == 2>>> t = torch.tensor([[1, 2], [3, 4]])
>>> tor.gather(t, dim=1, index=torch.tensor([[0, 0], [1, 0]]))
tensor([[ 1,  1],        [ 4,  3]])

我们可以想象在index上进行填数,因为输出和index是一样的形状。如果dim=1,意为在index每个元素值作为j,该元素所在的行作为i,在t中进行取值填充;如果dim=0,意为在index 每个元素值作为i,该元素所在的列作为j,在t中进行取值填充。

# scatter_
self[index[i][j][k]][j][k] = src[i][j][k]  # if dim == 0
self[i][index[i][j][k]][k] = src[i][j][k]  # if dim == 1
self[i][j][index[i][j][k]] = src[i][j][k]  # if dim == 2
>>> src = torch.arange(1, 11).reshape((2, 5))
>>> src
tensor([[ 1,  2,  3,  4,  5],        [ 6,  7,  8,  9, 10]])
>>> index = torch.tensor([[0, 1, 2, 0]])
>>> torch.zeros(3, 5, dtype=src.dtype).scatter_(0, index, src)
tensor([[1, 0, 0, 4, 0],        [0, 2, 0, 0, 0],        [0, 0, 3, 0, 0]])

scatter_ 的作用与 gather 刚好相反,取值方式与 gather 也类似。

广播机制

广播机制是向量运算的重要技巧。下面演示Tensor如何执行广播操作。torch.broadcast_tensors 可以将多个张量根据广播规则转换成相同的维度。

>>> A = np.arange(0, 40, 10).reshape(4, 1)
>>> B = np.arange(0, 3)#把ndarray转换为Tensor
>>> A1 = torch.from_numpy(A)  #形状为4x1
>>> B1 = torch.from_numpy(B)  #形状为3
#Tensor自动实现广播
>>> C = A1 + B1 # 形状为4+3
tensor([[ 0,  1,  2],        [10, 11, 12],        [20, 21, 22],        [30, 31, 32]], dtype=torch.int32)
>>> A_broad, B_broad = torch.broadcast_tensors(A1, B1)
>>> C = A_broad + B_broad
tensor([[ 0,  1,  2],        [10, 11, 12],        [20, 21, 22],        [30, 31, 32]], dtype=torch.int32)

归并分割

归并,意为对Tensor进行合并,这类操作的输出形状大于输入形状,是升维操作;分割,意为对Tensor进行切割细分,这类操作的输出形状小于输入形状,是降维操作。常见的操作函数如下:

  • torch.cat(tensor, dim=0):在指定维度连接多个Tensor,不会增加维度;
  • torch.stack(tensor, dim=0):在指定维度堆叠多个Tensor,会增加维度;
  • torch.split(tensor, split, dim=0):将一个张量分割为多个张量,不会减少维度,是torch.cat()的反向操作。
# cat操作
>>> x = torch.randn(2, 3)
>>> x
tensor([[ 0.6580, -1.0969, -0.4614],        [-0.1034, -0.5790,  0.1497]])
>>> torch.cat((x, x, x), 0)
tensor([[ 0.6580, -1.0969, -0.4614],        [-0.1034, -0.5790,  0.1497],        [ 0.6580, -1.0969, -0.4614],        [-0.1034, -0.5790,  0.1497],        [ 0.6580, -1.0969, -0.4614],        [-0.1034, -0.5790,  0.1497]])
>>> torch.cat((x, x, x), 1)
tensor([[ 0.6580, -1.0969, -0.4614,  0.6580, -1.0969, -0.4614,  0.6580,         -1.0969, -0.4614],        [-0.1034, -0.5790,  0.1497, -0.1034, -0.5790,  0.1497, -0.1034,         -0.5790,  0.1497]])
# stack
>>> x = torch.randn(2, 3)
>>> torch.stack((x, x, x), dim = 0).size()
torch.Size([3, 2, 3])
>>> torch.stack((x, x, x), dim = 1).size()
torch.Size([2, 3, 3])
>>> torch.stack((x, x, x), dim = 2).size()
torch.Size([2, 3, 3])
# split
>>> a = torch.arange(10).reshape(5,2)
>>> atensor([[0, 1],        [2, 3],        [4, 5],        [6, 7],        [8, 9]])
>>> torch.split(a, 2)(tensor([[0, 1],         [2, 3]]), tensor([[4, 5],         [6, 7]]), tensor([[8, 9]]))
>>> torch.split(a, [1,4])(tensor([[0, 1]]), tensor([[2, 3],         [4, 5],         [6, 7],         [8, 9]]))

元素操作

Tensor中也有很多元素操作的函数,也经常使用,例如:

  • abs/add:绝对值和加法;
  • ceil/floor:向上取整和向下取整;
  • clamp(t, min, max):将元素限定在指定区域内;
  • round(t):保留整数部分,四舍五入;
  • trunc(t):保留整数部分,向0归整;
  • sigmoid/tanh/softmax:激活函数。
>>> t = torch.randn(1, 3)
>>> torch.clamp(t, 0, 1)
tensor([[0., 0., 1.]])

比较操作

比较操作一般是进行逐个元素比较,常用的函数如下:

  • eq:比较两个Tensor是否相等,支持广播操作;
  • equal:比较两个Tensor是否具有相同的值和shape;
  • max/min:返回最值;
  • topk:返回指定维度上最高的K个值。
>>> x=torch.linspace(0,10,6).view(2,3)
>>> torch.max(x)
tensor(10.)
>>> torch.max(x,dim=0)
torch.return_types.max(values=tensor([ 6.,  8., 10.]),indices=tensor([1, 1, 1]))
>>> torch.topk(x, k=1, dim=0)
torch.return_types.topk(values=tensor([[ 6.,  8., 10.]]),indices=tensor([[1, 1, 1]]))

标量运算

Tensor的数学运算符分为:标量运算符,向量运算符,矩阵运算符,加减乘除,乘方,三角函数,指数,对数,逻辑比较运算等标量运算符。标量运算符的特点是逐元素运算。

>>> a = torch.tensor([[1.0,2],[-3,4.0]])
>>> b = torch.tensor([[5.0,6],[7.0,8.0]])
>>> a+b # 加法
>>> a-b # 减法
>>> a*b # 乘法
>>> a/b # 除法
>>> torch.remainder(x, 2) # 取余数
>>> a**2 # 乘方
>>> a**(0.5) # 开方
>>> torch.sqrt(a) # 开方
>>> a%3 # 求模
>>> torch.fmod(a, 2)
>>> a//3 # 地板除法
>>> a >= 2 # torch.ge(a, 2)
>>> (a >= 2)&(a <= 3) # 逻辑运算
>>> (a >= 2)|(a <= 3) # 逻辑运算

向量运算

向量运算符只在一个特定轴上运算,将一个向量映射到一个标量或者另外一个向量。

# 统计值
a=torch.arange(1,10).float()
print(torch.sum(a))
print(torch.mean(a))
print(torch.max(a))
print(torch.min(a))
print(torch.prod(a))#累乘
print(torch.std(a))#标准差
print(torch.var(a))#方差
print(torch.median(a))#中位数

矩阵操作

深度学习中存在大量的矩阵运算,常见的算法有两种:逐个元素相乘点积相乘。Pytorch中常用的矩阵函数如下:

  • dot(t1, t2):计算Tensor(1D)的内积或者点积;
  • mm(mat1,mat2)/bmm(batch1, batch2):计算矩阵乘法/含batch的3D矩阵的乘法
  • mv(t1, v1):计算矩阵与向量的乘法;
  • t:转置;
  • svd(t):计算t的SVD分解。
printf("hello world!");

完结

详解Tensor用法相关推荐

  1. OpenCV Mat类详解和用法(官网原文)

    参考文章:OpenCV Mat类详解和用法 我马克一下,日后更 官网原文链接:https://docs.opencv.org/3.2.0/d6/d6d/tutorial_mat_the_basic_i ...

  2. windows下创建进程,CreateProcess()详解及用法

    windows下想要创建一个子进程不如linux的fork函数来得方便,通过CreateProcess函数创建一个新的进程,函数的定义如下 [cpp]  view plain copy BOOL Cr ...

  3. OpenCV Mat类详解和用法

    OpenCV Mat类详解和用法 我们有多种方法可以获得从现实世界的数字图像:数码相机.扫描仪.计算机体层摄影或磁共振成像就是其中的几种.在每种情况下我们(人类)看到了什么是图像.但是,转换图像到我们 ...

  4. 【ADB 操作命令详解及用法大全(非常全)】

    ADB操作命令详解及用法大全 一.ADB是什么?   ADB,即 Android Debug Bridge 是一种允许模拟器或已连接的 Android 设备进行通信的命令行工具,它可为各种设备操作提供 ...

  5. spring注解详解与用法(总览)

    这篇文章收集了我写的所有的spring注解的详细说明与用法,点击可以跳转到对应文章,此文章会不断更新 spring注解详解与用法(1)最基础也是最常见的如下所示,详情点击这里 @Controller/ ...

  6. Symbol 详解与用法

    目录 前言: 一.什么是 Symbol? 二.Symbol 的特点 三.Symbol 的使用 总结: 前言: ES5中对象的属性名都是字符串,容易造成重名,污染环境 一.什么是 Symbol? Sym ...

  7. 最全ES6详解及用法

    最全ES6详解及用法 前言 babel babel使用方法 变量的定义 let.const this 和作用域 do 顶层对象 global对象 import class JS中的原型 原型语言 pr ...

  8. chatgpt赋能python:Python取ln函数详解:用法及常见问题解答

    Python取ln函数详解:用法及常见问题解答 Python取ln函数是一种非常常用的数学函数,它可以帮助开发者在计算中处理数据的自然指数对数.本篇文章将会介绍Python中取ln函数的基础知识,让您 ...

  9. 【C语言】结构体定义 typedef struct 用法详解和用法小结

    结构体定义 typedef struct 用法详解和用法小结 文章目录 结构体定义 typedef struct 用法详解和用法小结 0. 前言 1. 首先:在C中定义一个结构体类型要用typedef ...

最新文章

  1. webpack配置vue组件加载器
  2. 《能源专业的展望及其未来择业方向的分析》
  3. 【NLP】一份相当全面的BERT模型精讲
  4. 每日一题(9)—— 写一个标准宏MIN,这个宏输入两个参数并返回较小的一个
  5. 【TensorFlow】稀疏矢量
  6. rocketmq 消息指定_SpringBoot 整合 RocketMQ 如何实现消息生产消费?
  7. 2s相机 android6,Android Camera2 使用总结
  8. linux安装mongo卸载mongo,CentOS7安装及卸载MongoDB.md
  9. KL散度的通俗易懂理解
  10. yolov3前向传播(二)-- yolov3相关模块的解析与实现(一)
  11. 《实战突击:Java Web项目整合开发》简介及源码
  12. Phase2 Day20 事务 索引
  13. java学到什么程度可找工作_Java学到什么程度可以找工作
  14. clang static analyzer源码分析(番外篇):RegionStore以及evalCall()中的conservativeEvalCall
  15. 【论文泛读17】BERT后训练复习阅读理解和基于方面的情感分析
  16. 人机交互-1-人机交互概述
  17. 2019 前端年终总结(干货满满)
  18. OpenCV——图像特征提取(颜色:HSV与形状)
  19. 你会用turtle画画吗?
  20. 最经典的黑客技术入门知识大全

热门文章

  1. margin-left:-100%
  2. 各品牌电脑U盘启动的快捷键总结
  3. Python/numpy 设置数组某一整行列的值为0/1 修改数组行列设置为特定值
  4. 【数学模拟卷总结】2023李林六套卷数学二第三套
  5. 向5岁小朋友解释什么是微服务
  6. 装配一台计算机有哪些安全注意事项,挤出机注意事项
  7. 电脑文件夹改名快速重命名文件夹名的方法
  8. B站马士兵python入门基础版详细笔记(6)
  9. MySQL——INSERT INTO
  10. 初学者完成HBuilder X网站制作