李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
NLP
正文
02.Pytorch张量的创建
Leefs
2024-11-30 PM
213℃
0条
[TOC] ### 前言 PyTorch 是一个 Python 深度学习框架,它将数据封装成张量(Tensor)来进行运算。 PyTorch 中的张量就是元素为同一种数据类型的多维矩阵。在 PyTorch 中,张量以 "类" 的形式封装起来,对张量的一些运算、处理的方法被封装在类中。 ### 一、理解 Tensor Tensor 可以简单理解为是标量、向量、矩阵的高维扩展。 你可以把张量看作多维数组,但相较于ndarray,Tensor 包含了grad、requires_grad、grad_fn、device 等属性,是为服务于神经网络而设计的类型。 标量可以看作是零维张量、向量可以看作是一维张量、矩阵可以看作是二维张量。 若把二维张量看作一个平面,三维张量就是多个二维张量平面两两平行摆放。 灰度图像是典型的二维张量,RGB图像是典型的三维张量(channel, height, width)。 ![02.Pytorch张量的创建01.png](https://lilinchao.com/usr/uploads/2024/11/2086059780.png) 那怎么理解四维张量、五维张量等高维张量? 在之后的深度学习过程中,我们处理图像时会经常遇到四维张量(batch_size, channel, height, width),表示有 batch_size 个 RGB 图像。 更高维的张量无非是在前面添加 batch, 如五维张量(batch', batch, c, h, w)。batch 是高维张量的单位。 下面通过简图理解一下高维张量: ![02.Pytorch张量的创建02.png](https://lilinchao.com/usr/uploads/2024/11/38951576.png) 将三维张量看成零维张量,那四维张量不就是一维张量,五维张量不就是二维张量了吗!张量的升维其实也是在降维!!! ### 二、基本创建方式 #### 2.1 直接从数据来创建张量 > **torch.tensor** 根据指定数据创建张量 ```python torch.tensor(data, dtype=None, device=None, requires_grad=False) ``` PyTorch中的tensor函数是一个创建张量的工厂函数,可以用来快速创建各种类型的张量。 **参数说明** - **data**: 数据,像数组的类型都可以,如list、tuple、numpy.ndarray等 - **dtype**: 数据类型,默认与data的数据类型一致 - **device**: 指定张量所在的设备,例如CPU或GPU - **requires_grad**: 指定是否需要计算梯度,默认为False***注意,整形张量不支持求梯度。*** **示例** ```python # 创建一个标量(零维张量) scalar_tensor = torch.tensor(42) print(scalar_tensor) # 创建一个一维张量 vector_tensor = torch.tensor([1, 2, 3]) print(vector_tensor) # 创建一个二维张量 matrix_tensor = torch.tensor([[1, 2], [3, 4]]) print(matrix_tensor) ``` #### 2.2 从numpy数据创建张量 在PyTorch中,`from_numpy`函数是用于从NumPy数组创建张量的工厂函数之一。这个函数将`NumPy数组`转换为`PyTorch张量`,在转换时`不会复制数据`,因此可以`节省内存`和`时间`。 > from_numpy函数 ```python torch.from_numpy(ndarray) ``` 以下是该函数的参数及其解释: + `numpy_array`:要转换为张量的NumPy数组。 + `requires_grad`:指定是否需要计算梯度,默认为False。 利用该方法创建的tensor与原ndarray共享内存,当修改其中一个数据,另外一个也会被更新。 **示例代码** ```python import numpy as np import torch # 创建一个numpy数组 numpy_array = np.array([[1, 2, 3], [4, 5, 6]]) # 从numpy数组创建一个Tensor,并保持数据共享(更改Tensor内容会同时改变numpy数组) tensor_from_numpy = torch.from_numpy(numpy_array) print(tensor_from_numpy) # 输出: # tensor([[1, 2, 3], # [4, 5, 6]], dtype=torch.int32) # 修改tensor,array也会被修改 print("# -----------修改tensor--------------*") t[0, 0] = -1 print("numpy array: ", arr) # 输出: # numpy array: [[-1 2 3] # [ 4 5 6]] print("tensor : ", t) # 输出: # tensor([[-1, 2, 3], # [4, 5, 6]], dtype=torch.int32) ``` 可以看到,通过使用`from_numpy`函数,可以轻松地将NumPy数组转换为PyTorch张量,并且不需要进行任何额外的操作。 此外,由于PyTorch张量与NumPy数组共享底层内存,因此对其中一个的更改可能会影响另一个的值。 #### 2.3 根据形状创建张量 > **torch.Tensor** 根据形状创建张量, 其也可用来创建指定数据的张量(不建议使用) 关于torch.Tensor()函数,现在一般很少使用,或者说并不建议使用,其相对于`torch.tensor()`的优势在于可以指定张量形状进行创建 ```python import torch data1 = torch.Tensor(2, 3) print(data1) # tensor([[-2.1118e+14, 1.5905e-42, 0.0000e+00], # [ 0.0000e+00, 0.0000e+00, 0.0000e+00]]) ``` 可以看到上述代码创建了一个两行三列的随机张量,这里的随机并不符合均匀分布或者正态分布,而是其内存位置上的原本任意值。 同样torch.Tensor()也支持传入数据进行张量转换,但是要注意,这里并不支持传入整形或者浮点型数据,只能传入列表、元组或者ndarray类型数据 ```python import torch data1 = torch.Tensor(3) print(data1) data2 = torch.Tensor(2.0) print(data2) # tensor([-1.4512e+25, 2.1398e-42, 0.0000e+00]) # Traceback (most recent call last): # File "D:\Pythonproject\teach_day_01\demo01.py", line 5, in
# data2 = torch.Tensor(2.) # ^^^^^^^^^^^^^^^^ # TypeError: new(): data must be a sequence (got float) ``` **说明** 由上述代码可以看出data1在创建的时候参数3被识别为了要创建一个一维随机张量,长度为3,而data2在创建的时候可以看到报错中要求data要为一个序列,所以并不支持单数值作为参数使用 ```python import torch import numpy as np data1 = torch.Tensor([1, 2, 3]) print(data1, data1.dtype) data2 = torch.Tensor((1, 2, 3)) print(data2, data2.dtype) data3 = torch.Tensor(np.array([1, 2, 3])) print(data3, data3.dtype) # tensor([1., 2., 3.]) torch.float32 # tensor([1., 2., 3.]) torch.float32 # tensor([1., 2., 3.]) torch.float32 ``` 上述代码演示了由列表、元组和ndarray作为参数的时候的情况,***可以注意到的一点是,torch.Tensor()不会主动识别参数的数据类型,并且没有dtype参数设置来改变数据类型,所有数据最后都会变成float32数据类型,这也是目前不推荐使用Tensor()创建张量的原因。*** #### 2.4 创建指定类型的张量 > **torch.IntTensor**、**torch.FloatTensor**、**torch.DoubleTensor** 创建指定类型的张量 张量的基本数据类型基本包括如下几种数据类型: + ShortTensor + IntTensor + LongTensor + FloatTensor + DoubleTensor 上面五种类型分别对应`torch.int16`,`torch.int32`,`torch.int64`,`torch.float32`,`torch.float64`。 可以使用这几种类型进行指定进行张量的实例化 ```python import torch data1 = torch.ShortTensor([1.2, 2.3, 3.4]) data2 = torch.IntTensor([1.2, 2.3, 3.4]) data3 = torch.LongTensor([1.2, 2.3, 3.4]) data4 = torch.FloatTensor([1, 2, 3]) data5 = torch.DoubleTensor([1, 2, 3]) print(data1) print(data2) print(data3) print(data4) print(data5) # tensor([1, 2, 3], dtype=torch.int16) # tensor([1, 2, 3], dtype=torch.int32) # tensor([1, 2, 3]) # tensor([1., 2., 3.]) # tensor([1., 2., 3.], dtype=torch.float64) ``` 注意,上述的五个张量创建函数,都不支持在定义的时候设置`requires_grad`,都需要在定义完张量后再设置 ```python import torch data1 = torch.FloatTensor([1, 2, 3]) data1.requires_grad = True print(data1) # tensor([1., 2., 3.], requires_grad=True) ``` #### 2.5 完整使用示例 ```python import torch import numpy as np # 1. 根据已有的数据创建张量 def test01(): # 1.1 创建标量 data = torch.tensor(10) print(data) # 1.2 使用numpy数组来创建张量 data = np.random.randn(2,3) data = torch.tensor(data) print(data) # 1.3 使用list列表来创建张量 # tensor默认小数类型是float32 # 数字后面加".",表示是小数类型 data = [[10.,20.,30.],[40.,50.,60.]] data = torch.tensor(data) print(data) # 2. 创建指定形状的张量 def test02(): # 2.1 创建2行3列的张量 data = torch.Tensor(2, 3) print(data) # 2.2 可以创建指定值的张量 # 注意: 传递列表 data = torch.Tensor([2, 3]) print(data) data = torch.Tensor([10]) print(data) # 3. 创建指定类型的张量 def test03(): # 前面创建的张量都是使用默认类型或者元素类型 # 创建一个 int32 类型的张量 data = torch.IntTensor(2,3) print(data) # torch.ShortTensor(2, 3) # 表示创建的是 int16 类型张量 # torch.LongTensor(2, 3) # 表示创建的是 int32 类型的张量 # torch.FloatTensor(2, 3) # 表示创建的是 float32 张量 # 注意: 如果创建指定类型的张量,但是传递的数据不匹配,会发生类型转换 data = torch.IntTensor([2.5, 3.5]) print(data) if __name__ == '__main__': # test01() # test02() test03() ``` ### 三、创建线性和随机张量 #### 3.1 创建线性张量 > `torch.arange` 、 `torch.linspace` 和`torch.logspace`创建线性张量 **(1)创建等差的一维张量** ```python torch.arange(start=0, end, step=1, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) ``` **参数说明** + **start**:数列起始值,默认为0 + **end**:数列结束值,开区间,取不到结束值 + **step**:数列公差,默认为1 **示例** ```python import torch t = torch.arange(2, 10, 2) print(t) # tensor([2, 4, 6, 8]) ``` + **注意区间为:[start,end)**。 **(2)创建均分的一维张量** ```python torch.linspace(start, end, steps=100, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) ``` **参数说明** + **step**:数列长度(元素个数) **示例** ```python import torch t = torch.linspace(2, 10, 3) print(t) # tensor([ 2., 6., 10.]) ``` + **注意区间为:[start,end]**。 **(3)创建对数均分的一维张量** ```python torch.logspace(start, end, steps, base=10, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) ``` **参数说明** + **step**:数列长度(元素个数) + **base**:对数函数的底,默认为 10 **示例** ```python import torch t = torch.logspace(2, 4, 3) print(t) # tensor([100., 1000., 10000.]) ``` + **注意区间为:[start,end]。** #### 3.2 创建随机张量 > `torch.random.init_seed` 和 `torch.random.manual_seed` 随机种子设置 > > ##### `torch.rand`、`torch.randn`、`torch.randint`、`torch.empty` 创建随机张量 **(1)torch.rand()** ```python torch.rand(*size, *, generator=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False, pin_memory=False) ``` **作用** + 创建0-1区间内**均匀分布**的随机值 **参数说明** + **size**:为形状,高维可以使用列表或元组形式,也可不使用括号 **示例** ```python import torch #torch.rand(4) #torch.rand(2, 3) data1 = torch.rand(2, 3, device="cuda", dtype=torch.float64, requires_grad=True) print(data1) # tensor([[0.1615, 0.7415, 0.6346], # [0.3183, 0.6323, 0.9578]], device='cuda:0', dtype=torch.float64, # requires_grad=True) ``` **(2)torch.randn()** ```python torch.randn(*size, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False, pin_memory=False) ``` **作用** + 生成标准正态分布的随机浮点数向量 **示例** ```python import torch #torch.randn(4) #torch.randn(2, 3) data1 = torch.randn(2, 3, device="cuda", dtype=torch.float64, requires_grad=True) print(data1) # tensor([[-1.1177, -0.6240, -1.4654], # [-0.6016, 0.1243, -0.2280]], device='cuda:0', dtype=torch.float64, # requires_grad=True) ``` **(3)torch.randint** ```python def randint(low: int, high: int, size: Size | List[int] | Tuple[int, ...], *, dtype: dtype | None = None, device: device | str | None = None, requires_grad: bool = False) -> Tensor ``` **作用** + 用于生成指定范围指定形状的随机整形张量,设计的主要参数包括low,high,size,分布对应了生成数值的下限,上限,和形状。 *注意,这里的生成范围为[low,high)也就是不包括上限的,并且生成的数据符合均匀分布* **示例** ```python import torch data1 = torch.randint(0, 10, (2, 3), device="cuda") print(data1) # tensor([[9, 0, 0], # [6, 4, 2]], device='cuda:0') ``` **(4)torch.empty()** ```python def empty(size: Size | List[int] | Tuple[int, ...], *, names: List[str | None] | None, memory_format: memory_format | None = None, out: Tensor | None = None, dtype: dtype | None = None, layout: layout = strided, device: device | str | None = None, requires_grad: bool = False) -> Tensor ``` **作用** + 生成指定形状的未初始化的随机张量,其值取决于先前内存中存储的随机值 **示例** ```python import torch data1 = torch.empty(2, 3, requires_grad=True) print(data1) # tensor([[0., 0., 0.], # [0., 0., 0.]], requires_grad=True) ``` 还有 torch.rand_like()、torch.randperm()、torch.bernoulli()等。 #### 3.3 完整示例代码 ```python import torch # 1. 创建线性空间的张量 def test01(): # 1. 在指定区间按照步长生成元素 [start,end,step) # 第一个参数: 开始值 # 第二个参数: 结束值 # 第三个参数: 步长 data = torch.arange(0,10,2) print(data) # 2. 在指定区间指定元素个数 # 第一个参数: 开始值 # 第二个参数: 结束值 # 第三个参数: 创建元素的个数 data = torch.linspace(0,10,10) print(data) # 2. 创建随机张量 def test02(): # 1. 创建随机张量 data = torch.randn(2, 3) # 创建2行3列张量 print(data) # 2. 随机数种子设置 print('随机数种子:',torch.random.initial_seed()) torch.random.manual_seed(100) print('随机数种子:',torch.random.initial_seed()) if __name__ == '__main__': # test01() test02() ``` ### 四、创建01张量 #### 4.1 创建全0张量 > torch.zeros 和 torch.zeros_like 创建全0张量 **(1)torch.zeros()** ``` torch.zeros(*size, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) ``` **作用** + 创建指定形状的全0张量,参数为创建张量的形状以及包括tensor()中的device,dtype,requires_grad参数 **参数说明** - **size(int...)**: 张量的形状 - **out(Tensor)**: 输出张量,将新建的张量写入 out 张量中 - **layout**: 内存中布局形式,有strided、sparse_coo 等。当是稀疏矩阵时,设置为 sparse_coo 可以减少内存占用 - **device**:张量所在的设备(cuda或cpu) - **requires_grad**:是否需要梯度 **示例** ```python import torch data1 = torch.zeros([2, 3]) print(data1) data2 = torch.zeros(2, 3) print(data2) # tensor([[0., 0., 0.], # [0., 0., 0.]]) # tensor([[0., 0., 0.], # [0., 0., 0.]]) ``` 注意形状参数如为高维可以使用元组或者列表的形式,也可以不加括号 ```python import torch data1 = torch.zeros(2, 3, device="cuda", requires_grad=True, dtype=torch.float64) print(data1) # tensor([[0., 0., 0.], # [0., 0., 0.]], device='cuda:0', dtype=torch.float64, # requires_grad=True) ``` **(2)torch.zeros_like()** ``` torch.zeros_like(input, *, dtype=None, layout=None, device=None, requires_grad=False, memory_format=torch.preserve_format) ``` **作用** + 区别于`torch.zeros()`在于第一个参数,`zeros()`是形状,`zeros_like()`的第一个参数是另一个张量,作用是创建与其形状相同的全0张量,其余参数设置与`zeros()`相同 **示例** ```python import torch data1 = torch.tensor([1, 2, 3]) data2 = torch.zeros_like(data1, dtype=torch.float32, device="cuda", requires_grad=True) print(data1) print(data2) # tensor([1, 2, 3]) # tensor([0., 0., 0.], device='cuda:0', requires_grad=True) ``` #### 4.2 创建全1张量 > `torch.ones` 和 `torch.ones_like` 创建全1张量 **(1)torch.ones()** 详情与torch.zeros()类似,区别为创建的是全1张量 **示例** ```python import torch data1 = torch.ones(2, 3, requires_grad=True, dtype=torch.float32, device="cuda") print(data1) # tensor([[1., 1., 1.], # [1., 1., 1.]], device='cuda:0', requires_grad=True) ``` **(2)torch.ones_like()** 详情与torch.zeros_like()类似,区别为创建的是全1张量 ```python import torch data1 = torch.tensor([1, 2, 3]) data2 = torch.ones_like(data1, requires_grad=True, dtype=torch.float32, device="cuda") print(data2) # tensor([1., 1., 1.], device='cuda:0', requires_grad=True) ``` #### 4.3 创建全为指定值张量 > torch.full 和 torch.full_like 创建全为指定值张量 **(1)torch.full()** ```python torch.full(size, fill_value, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) ``` **作用** + 用于创建全指定值元素的张量,注意函数前两个参数分别为`size`和`fill_value`,所以这里的size若为高维需要使用元组或列表的形式,否则可能造成参数错位。 **参数说明** + **size**:张量的形状,可以是一个整数或一个元组或者一个列表。 + **fill_value**:要填充到新张量中的数值。 + **dtype**:新张量的数据类型,默认为float32。 + **device**:新张量所在的设备,例如CPU或GPU。 + **requires_grad**:指定是否需要计算梯度,默认为False。 **示例** ```python import torch data1 = torch.full((2, 3), 10, device="cuda", dtype=torch.float32, requires_grad=True) print(data1) # tensor([[10., 10., 10.], # [10., 10., 10.]], device='cuda:0', requires_grad=True) ``` **(2)torch.full_like()** ```python def full_like(self: Tensor, fill_value: int | float | bool, *, memory_format: memory_format | None = None, dtype: dtype | None = None, layout: layout = strided, device: device | str | None = None, requires_grad: bool = False) -> Tensor ``` **作用** + 用于创建与另一张量相同形状的全指定值张量,与full()的区别在于第一个参数需要设置为用于模仿形状的张量 **示例** ```python import torch data1 = torch.tensor([1, 2, 3]) data2 = torch.full_like( data1, 10, device="cuda", dtype=torch.float32, requires_grad=True ) print(data2) # tensor([10., 10., 10.], device='cuda:0', requires_grad=True) ``` #### 4.4 完整代码示例 ```python import torch # 创建全为0的张量 def test01(): # 1.1 创建指定形状全为 0 的张量 data = torch.zeros(2, 3) print(data) # 1.2 根据其他张量的形状去创建全 0 张量 data = torch.zeros_like(data) print(data) # 创建全为1的张量 def test02(): # 2.1 创建指定形状全为 1 的张量 data = torch.ones(2, 3) print(data) # 2.2 根据其他张量的形状去创建全 1 张量 data = torch.ones_like(data) print(data) # 3. 创建全为指定值的张量 def test03(): # 3.1 创建形状为2行3列,值全部为10的张量 data = torch.full([2,3],100) print(data) # 3.2 创建一个形状和data一样,但是值全部为200的张量 data = torch.full_like(data,200) print(data) if __name__ == '__main__': # test01() # test02() test03() ``` ### 五、Tensor数据类型和元素类型转换 #### 5.1 Tensor数据类型 torch.dtype属性标识了torch.Tensor的数据类型。PyTorch有八种不同的数据类型: ![02.Pytorch张量的创建03.png](https://lilinchao.com/usr/uploads/2024/11/3893193883.png) 使用 PyTorch 中的 `dtype` 属性可以获取 Tensor 的数据类型。例如: ```python x = t.randn(3, 4) # 创建一个随机的 FloatTensor print(x.dtype) # 输出 torch.float32 ``` ##### Tensor所在设备 ![02.Pytorch张量的创建04.png](https://lilinchao.com/usr/uploads/2024/11/2229759288.png) 如图所示,可以看到每种类型的数据都有一个CPU和一个GPU版本,因此对张量进行处理的时候需要指定一个设备,它要么是CPU要么是GPU,这是数据被分配的位置,这决定了给定张量的张量计算位置。 Pytorch支持多种设备的使用,可以用torch.device来创建一个设备,并指定索引,例如: ``` device=torch.device('cuda:0') ``` 输出结果为:device(type=‘cuda’,index=0),可看到类型为’cuda’,即GPU,索引0表示为第一个GPU。 #### 5.2 Tensor元素类型转换 张量在创建之后也是支持元素类型的转换的,通常有两种方式: + 通过tensor.type()函数进行类型转换 + 通过对应类型方法直接进行类型转换 + 具体的方法有short(),int(),long(),float(),double(),分别对应torch.int16,torch.int32,torch.int64,torch.float32,torch.float64的转换。 + 要注意,该方法不会修改并覆盖原数据,需要重新赋值。 **示例代码** ```python import torch data1 = torch.tensor([1, 2, 3]) data1 = data1.float() print(data1, data1.dtype) data1 = data1.short() print(data1, data1.dtype) data1 = data1.int() print(data1, data1.dtype) data1 = data1.double() print(data1, data1.dtype) data1 = data1.long() print(data1, data1.dtype) # tensor([1., 2., 3.]) torch.float32 # tensor([1, 2, 3], dtype=torch.int16) torch.int16 # tensor([1, 2, 3], dtype=torch.int32) torch.int32 # tensor([1., 2., 3.], dtype=torch.float64) torch.float64 # tensor([1, 2, 3]) torch.int64 ``` #### 5.3 完整示例代码 ```python import torch # 1. type 函数进行转换 def test01(): data = torch.full([2,3],10) print(data.dtype) # 注意: 返回一个新的类型转换过的张量 data = data.type(torch.DoubleTensor) print(data.dtype) # 转换为其他类型 # data = data.type(torch.ShortTensor) # data = data.type(torch.IntTensor) # data = data.type(torch.LongTensor) # data = data.type(torch.FloatTensor) # 2. 使用具体类型函数进行转换 def test02(): data = torch.full([2,3],10) print(data.dtype) # 转换成 float64 类型 data = data.double() print(data.dtype) # data = data.short() # 将张量元素转换为 int16 类型 # data = data.int() # 将张量转换为 int32 类型 # data = data.long() # 将张量转换为 int64 类型 # data = data.float() # 将张量转换为 float32 if __name__ == '__main__': # test01() test02() ``` ### 六、Tensor形状属性 张量具有如下形状属性: - `Tensor.ndim`:张量的维度,例如向量的维度为1,矩阵的维度为2。 - `Tensor.shape`:张量每个维度上元素的数量。 - `Tensor.shape[n]`:张量第n维的大小。第n维也称为轴(axis)。 - `Tensor.numel`:张量中全部元素的个数。 如下是创建一个四维Tensor,并通过图形直观表达以上几个概念的关系。 ```python import torch Tensor=torch.ones([2,3,4,5]) print("Number of dimensions:", Tensor.ndim) print("Shape of Tensor:", Tensor.shape) print("Elements number along axis 0 of Tensor:", Tensor.shape[0]) print("Elements number along the last axis of Tensor:", Tensor.shape[-1]) print('Number of elements in Tensor: ', Tensor.numel()) #用.numel表示元素个数 ``` ![02.Pytorch张量的创建05.png](https://lilinchao.com/usr/uploads/2024/11/2872956084.png) Tensor的axis、shape、dimension、ndim之间的关系如下图所示。 ![02.Pytorch张量的创建06.png](https://lilinchao.com/usr/uploads/2024/11/203712625.png)
标签:
pytorch
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://lilinchao.com/archives/2937.html
上一篇
01.Pytorch在Windows10系统安装教程
下一篇
03.Pytorch张量数值计算
评论已关闭
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
NLP
4
标签云
Java编程思想
Http
SpringCloudAlibaba
前端
微服务
Filter
Typora
GET和POST
Tomcat
Flink
Linux
持有对象
pytorch
nginx
Hadoop
Java阻塞队列
Docker
Ubuntu
SpringBoot
MyBatisX
并发编程
Git
随笔
Java工具类
FastDFS
算法
Jenkins
稀疏数组
MyBatis-Plus
JavaWEB项目搭建
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
评论已关闭