# 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)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://pytorch.zhangxiann.com/1-ji-ben-gai-nian/1.2-tensor-zhang-liang-jie-shao.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
