# 1.2 Tensor(张量)介绍

> 本章代码：
>
> * <https://github.com/zhangxiann/PyTorch_Practice/blob/master/lesson1/tensor_introduce1.py>
> * <https://github.com/zhangxiann/PyTorch_Practice/blob/master/lesson1/tensor_introduce1.py>

## Tensor 的概念

Tensor 中文为张量。张量的意思是一个多维数组，它是标量、向量、矩阵的高维扩展。

标量可以称为 0 维张量，向量可以称为 1 维张量，矩阵可以称为 2 维张量，RGB 图像可以表示 3 维张量。你可以把张量看作多维数组。

![](https://image.zhangxiann.com/20200515144610.png)

### Tensor 与 Variable

在 PyTorch 0.4.0 之前，torch.autograd 包中存在 Variable 这种数据类型，主要是用于封装 Tensor，进行自动求导。Variable 主要包含下面几种属性。

* data: 被包装的 Tensor。
* grad: data 的梯度。
* grad\_fn: 创建 Tensor 所使用的 Function，是自动求导的关键，因为根据所记录的函数才能计算出导数。
* requires\_grad: 指示是否需要梯度，并不是所有的张量都需要计算梯度。
* is\_leaf: 指示是否叶子节点(张量)，叶子节点的概念在计算图中会用到，后面详细介绍。

![](https://image.zhangxiann.com/20200515145120.png)\
在 PyTorch 0.4.0 之后，Variable 并入了 Tensor。在之后版本的 Tensor 中，除了具有上面 Variable 的 5 个属性，还有另外 3 个属性。

* dtype: 张量的数据类型，如 torch.FloatTensor，torch.cuda.FloatTensor。
* shape: 张量的形状。如 (64, 3, 224, 224)
* device: 张量所在设备 (CPU/GPU)，GPU 是加速计算的关键

![](https://image.zhangxiann.com/20200515145801.png)\
关于 dtype，PyTorch 提供了 9 种数据类型，共分为 3 大类：float (16-bit, 32-bit, 64-bit)、integer (unsigned-8-bit ,8-bit, 16-bit, 32-bit, 64-bit)、Boolean。模型参数和数据用的最多的类型是 float-32-bit。label 常用的类型是 integer-64-bit。

![](https://image.zhangxiann.com/20200515150439.png)

## Tensor 创建的方法

### 直接创建 Tensor

#### torch.tensor()

```python
torch.tensor(data, dtype=None, device=None, requires_grad=False, pin_memory=False)
```

* data: 数据，可以是 list，numpy
* dtype: 数据类型，默认与 data 的一致
* device: 所在设备，cuda/cpu
* requires\_grad: 是否需要梯度
* pin\_memory: 是否存于锁页内存

代码示例：

```python
arr = np.ones((3, 3))
print("ndarray的数据类型：", arr.dtype)
# 创建存放在 GPU 的数据
# t = torch.tensor(arr, device='cuda')
t= torch.tensor(arr)
print(t)
```

输出为：

```python
ndarray的数据类型： float64
tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]], dtype=torch.float64)
```

#### torch.from\_numpy(ndarray)

从 numpy 创建 tensor。利用这个方法创建的 tensor 和原来的 ndarray 共享内存，当修改其中一个数据，另外一个也会被改动。

![](https://image.zhangxiann.com/20200515161227.png)\
代码示例：

```python
arr = np.array([[1, 2, 3], [4, 5, 6]])
t = torch.from_numpy(arr)

# 修改 array，tensor 也会被修改
# print("\n修改arr")
# arr[0, 0] = 0
# print("numpy array: ", arr)
# print("tensor : ", t)

# 修改 tensor，array 也会被修改
print("\n修改tensor")
t[0, 0] = -1
print("numpy array: ", arr)
print("tensor : ", t)
```

输出为：

```python
修改tensor
numpy array:  [[-1  2  3]
 [ 4  5  6]]
tensor :  tensor([[-1,  2,  3],
        [ 4,  5,  6]], dtype=torch.int32)
```

### 根据数值创建 Tensor

#### torch.zeros()

```
torch.zeros(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
```

功能：根据 size 创建全 0 张量

* size: 张量的形状
* out: 输出的张量，如果指定了 out，那么`torch.zeros()`返回的张量和 out 指向的是同一个地址
* layout: 内存中布局形式，有 strided，sparse\_coo 等。当是稀疏矩阵时，设置为 sparse\_coo 可以减少内存占用。
* device: 所在设备，cuda/cpu
* requires\_grad: 是否需要梯度

代码示例：

```python
out_t = torch.tensor([1])
# 这里制定了 out
t = torch.zeros((3, 3), out=out_t)
print(t, '\n', out_t)
# id 是取内存地址。最终 t 和 out_t 是同一个内存地址
print(id(t), id(out_t), id(t) == id(out_t))
```

输出是：

```python
tensor([[0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]]) 
 tensor([[0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]])
2984903203072 2984903203072 True
```

#### torch.zeros\_like

```python
torch.zeros_like(input, dtype=None, layout=None, device=None, requires_grad=False, memory_format=torch.preserve_format)
```

功能：根据 input 形状创建全 0 张量

* input: 创建与 input 同形状的全 0 张量
* dtype: 数据类型
* layout: 内存中布局形式，有 strided，sparse\_coo 等。当是稀疏矩阵时，设置为 sparse\_coo 可以减少内存占用。

同理还有全 1 张量的创建方法：`torch.ones()`，`torch.ones_like()`。

#### torch.full()，torch.full\_like()

```
torch.full(size, fill_value, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
```

功能：创建自定义数值的张量

* size: 张量的形状，如 (3,3)
* fill\_value: 张量中每一个元素的值

代码示例：

```python
t = torch.full((3, 3), 1)
print(t)
```

输出为：

```
tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]])
```

#### torch.arange()

```python
torch.arange(start=0, end, step=1, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
```

功能：创建等差的 1 维张量。注意区间为\[start, end)。

* start: 数列起始值
* end: 数列结束值，开区间，取不到结束值
* step: 数列公差，默认为 1

代码示例：

```python
t = torch.arange(2, 10, 2)
print(t)
```

输出为：

```
tensor([2, 4, 6, 8])
```

#### torch.linspace()

```python
torch.linspace(start, end, steps=100, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
```

功能：创建均分的 1 维张量。数值区间为 \[start, end]

* start: 数列起始值
* end: 数列结束值
* steps: 数列长度 (元素个数)

代码示例：

```python
# t = torch.linspace(2, 10, 5)
t = torch.linspace(2, 10, 6)
print(t)
```

输出为：

```
tensor([ 2.0000,  3.6000,  5.2000,  6.8000,  8.4000, 10.0000])
```

#### torch.logspace()

```python
torch.logspace(start, end, steps=100, base=10.0, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
```

功能：创建对数均分的 1 维张量。数值区间为 \[start, end]，底为 base。

* start: 数列起始值
* end: 数列结束值
* steps: 数列长度 (元素个数)
* base: 对数函数的底，默认为 10

代码示例：

```python
# t = torch.logspace(2, 10, 5)
t = torch.logspace(2, 10, 6)
print(t)
```

输出为：

```
tensor([1.0000e+02, 3.9811e+03, 1.5849e+05, 6.3096e+06, 2.5119e+08, 1.0000e+10])
```

#### torch.eye()

```
torch.eye(n, m=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
```

功能：创建单位对角矩阵( 2 维张量)，默认为方阵

* n: 矩阵行数。通常只设置 n，为方阵。
* m: 矩阵列数

### 根据概率创建 Tensor

#### torch.normal()

```
torch.normal(mean, std, *, generator=None, out=None)
```

功能：生成正态分布 (高斯分布)

* mean: 均值
* std: 标准差

有 4 种模式：

1. mean 为标量，std 为标量。这时需要设置 size。

   代码示例：

   ```
   # mean：标量 std: 标量
   # 这里需要设置 size
   t_normal = torch.normal(0., 1., size=(4,))
   print(t_normal)
   ```

   输出为：

   ```
   tensor([0.6614, 0.2669, 0.0617, 0.6213])
   ```
2. mean 为标量，std 为张量
3. mean 为张量，std 为标量

   代码示例：

   ```python
   # mean：张量 std: 标量
   mean = torch.arange(1, 5, dtype=torch.float)
   std = 1
   t_normal = torch.normal(mean, std)
   print("mean:{}\nstd:{}".format(mean, std))
   print(t_normal)
   ```

   输出为：

   ```
   mean:tensor([1., 2., 3., 4.])
   std:1
   tensor([1.6614, 2.2669, 3.0617, 4.6213])
   ```

   这 4 个数采样分布的均值不同，但是方差都是 1。
4. mean 为张量，std 为张量

   代码示例：

   ```python
   # mean：张量 std: 张量
   mean = torch.arange(1, 5, dtype=torch.float)
   std = torch.arange(1, 5, dtype=torch.float)
   t_normal = torch.normal(mean, std)
   print("mean:{}\nstd:{}".format(mean, std))
   print(t_normal)
   ```

   输出为：

   ```
   mean:tensor([1., 2., 3., 4.])
   std:tensor([1., 2., 3., 4.])
   tensor([1.6614, 2.5338, 3.1850, 6.4853])
   ```

   其中 1.6614 是从正态分布 $N(1,1)$ 中采样得到的，其他数字以此类推。

#### torch.randn() 和 torch.randn\_like()

```
torch.randn(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
```

功能：生成标准正态分布。

* size: 张量的形状

#### torch.rand() 和 torch.rand\_like()

```
torch.rand(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
```

功能：在区间 \[0, 1) 上生成均匀分布。

#### torch.randint() 和 torch.randint\_like()

```python
randint(low=0, high, size, *, generator=None, out=None,
dtype=None, layout=torch.strided, device=None, requires_grad=False)
```

功能：在区间 \[low, high) 上生成整数均匀分布。

* size: 张量的形状

#### torch.randperm()

```
torch.randperm(n, out=None, dtype=torch.int64, layout=torch.strided, device=None, requires_grad=False)
```

功能：生成从 0 到 n-1 的随机排列。常用于生成索引。

* n: 张量的长度

#### torch.bernoulli()

```
torch.bernoulli(input, *, generator=None, out=None)
```

功能：以 input 为概率，生成伯努利分布 (0-1 分布，两点分布)

* input: 概率值

**参考资料**

* [深度之眼 PyTorch 框架班](https://ai.deepshare.net/detail/p_5df0ad9a09d37_qYqVmt85/6)

如果你觉得这篇文章对你有帮助，不妨点个赞，让我有更多动力写出好文章。

我的文章会首发在公众号上，欢迎扫码关注我的公众号**张贤同学**。

![](https://image.zhangxiann.com/QRcode_8cm.jpg)
