<jupyter_start><jupyter_text>2.2 数据操作<jupyter_code>import torch

torch.manual_seed(0)
torch.cuda.manual_seed(0)
print(torch.__version__, torch.manual_seed(0))<jupyter_output>1.8.1 <torch._C.Generator object at 0x00000221EE8590F0><jupyter_text>2.2.1 创建`Tensor`创建一个5x3的未初始化的`Tensor`：<jupyter_code>x = torch.empty(5, 3)
print(x, type(x))<jupyter_output>tensor([[8.9082e-39, 5.9694e-39, 8.9082e-39],
        [1.0194e-38, 9.1837e-39, 4.6837e-39],
        [9.2755e-39, 1.0837e-38, 8.4490e-39],
        [1.1112e-38, 1.0194e-38, 9.0919e-39],
        [8.7245e-39, 1.0102e-38, 8.4490e-39]]) <class 'torch.Tensor'><jupyter_text>创建一个5x3的随机初始化的`Tensor`:<jupyter_code>x = torch.rand(5, 3)
print(x)<jupyter_output>tensor([[0.4963, 0.7682, 0.0885],
        [0.1320, 0.3074, 0.6341],
        [0.4901, 0.8964, 0.4556],
        [0.6323, 0.3489, 0.4017],
        [0.0223, 0.1689, 0.2939]])<jupyter_text>创建一个5x3的long型全0的`Tensor`:<jupyter_code>x = torch.zeros(5, 3, dtype=torch.long)
print(x)<jupyter_output>tensor([[0, 0, 0],
        [0, 0, 0],
        [0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]])<jupyter_text>直接根据数据创建:<jupyter_code>x = torch.tensor([5.5, 3])
print(x)<jupyter_output>tensor([5.5000, 3.0000])<jupyter_text>还可以通过现有的`Tensor`来创建，此方法会默认重用输入`Tensor`的一些属性，例如数据类型，除非自定义数据类型。<jupyter_code>x = x.new_ones(5, 3, dtype=torch.float64)      # 返回的tensor默认具有相同的torch.dtype和torch.device
print(x)

x = torch.randn_like(x, dtype=torch.float)    # 指定新的数据类型
print(x)<jupyter_output>tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]], dtype=torch.float64)
tensor([[ 0.6035,  0.8110, -0.0451],
        [ 0.8797,  1.0482, -0.0445],
        [-0.7229,  2.8663, -0.5655],
        [ 0.1604, -0.0254,  1.0739],
        [ 2.2628, -0.9175, -0.2251]])<jupyter_text>我们可以通过`shape`或者`size()`来获取`Tensor`的形状:<jupyter_code>print(x.size())
print(x.shape)<jupyter_output>torch.Size([5, 3])
torch.Size([5, 3])<jupyter_text>> 注意：返回的torch.Size其实就是一个tuple, 支持所有tuple的操作。  2.2.2 操作 算术操作* **加法形式一**<jupyter_code>x = torch.rand(5, 3)
y = torch.rand(5, 3)
print(x)
print(y)
z = x + y
print(z, id(z))
x += 1
print(z)
print(x + y)<jupyter_output>tensor([[0.1473, 0.5223, 0.1475],
        [0.2248, 0.2086, 0.6709],
        [0.2020, 0.4891, 0.5210],
        [0.8223, 0.1220, 0.1567],
        [0.2097, 0.8500, 0.3203]])
tensor([[0.9217, 0.6808, 0.5633],
        [0.4963, 0.4012, 0.5627],
        [0.3858, 0.4965, 0.5638],
        [0.1089, 0.2379, 0.9037],
        [0.0942, 0.4641, 0.9946]])
tensor([[1.0691, 1.2031, 0.7108],
        [0.7210, 0.6098, 1.2336],
        [0.5879, 0.9856, 1.0848],
        [0.9312, 0.3600, 1.0605],
        [0.3039, 1.3141, 1.3149]]) 2344831250048
tensor([[1.0691, 1.2031, 0.7108],
        [0.7210, 0.6098, 1.2336],
        [0.5879, 0.9856, 1.0848],
        [0.9312, 0.3600, 1.0605],
        [0.3039, 1.3141, 1.3149]])
tensor([[2.0691, 2.2031, 1.7108],
        [1.7210, 1.6098, 2.2336],
        [1.5879, 1.9856, 2.0848],
        [1.9312, 1.3600, 2.0605],
        [1.3039, 2.3141, 2.3149]])<jupyter_text>* **加法形式二**<jupyter_code>print(torch.add(x, y))
result = torch.empty(5, 3)
torch.add(x, y, out=result)
print(result)<jupyter_output>tensor([[ 1.3967,  1.0892,  0.4369],
        [ 1.6995,  2.0453,  0.6539],
        [-0.1553,  3.7016, -0.3599],
        [ 0.7536,  0.0870,  1.2274],
        [ 2.5046, -0.1913,  0.4760]])<jupyter_text>* **加法形式三、inplace**<jupyter_code># adds x to y
y.add_(x)
print(y)<jupyter_output>tensor([[ 1.3967,  1.0892,  0.4369],
        [ 1.6995,  2.0453,  0.6539],
        [-0.1553,  3.7016, -0.3599],
        [ 0.7536,  0.0870,  1.2274],
        [ 2.5046, -0.1913,  0.4760]])<jupyter_text>> **注：PyTorch操作inplace版本都有后缀"_", 例如`x.copy_(y), x.t_()`** 索引我们还可以使用类似NumPy的索引操作来访问`Tensor`的一部分，需要注意的是：**索引出来的结果与原数据共享内存，也即修改一个，另一个会跟着修改。**<jupyter_code>import torch
x = torch.rand(5, 5)
print(x)
y = x[0, :]
y += 1
print(y)
print(x[0, :]) # 源tensor也被改了
z = x[2, :]
z -= 1
print(z, x)<jupyter_output>tensor([[0.2038, 0.6511, 0.7745, 0.4369, 0.5191],
        [0.6159, 0.8102, 0.9801, 0.1147, 0.3168],
        [0.6965, 0.9143, 0.9351, 0.9412, 0.5995],
        [0.0652, 0.5460, 0.1872, 0.0340, 0.9442],
        [0.8802, 0.0012, 0.5936, 0.4158, 0.4177]])
tensor([1.2038, 1.6511, 1.7745, 1.4369, 1.5191])
tensor([1.2038, 1.6511, 1.7745, 1.4369, 1.5191])
tensor([-0.3035, -0.0857, -0.0649, -0.0588, -0.4005]) tensor([[ 1.2038e+00,  1.6511e+00,  1.7745e+00,  1.4369e+00,  1.5191e+00],
        [ 6.1585e-01,  8.1019e-01,  9.8010e-01,  1.1469e-01,  3.1677e-01],
        [-3.0350e-01, -8.5725e-02, -6.4896e-02, -5.8822e-02, -4.0049e-01],
        [ 6.5209e-02,  5.4600e-01,  1.8720e-01,  3.4023e-02,  9.4425e-01],
        [ 8.8018e-01,  1.2360e-03,  5.9359e-01,  4.1577e-01,  4.1772e-01]])<jupyter_text>改变形状用`view()`来改变`Tensor`的形状：<jupyter_code>x = torch.rand(5, 3)
y = x.view(15)
z = x.view(-1, 5)  # -1所指的维度可以根据其他维度的值推出来
m = x.view(3, -1)
print(x.size(), y.size(), z.size())
print(x)
print(y)
print(z)
print(m)<jupyter_output>torch.Size([5, 3]) torch.Size([15]) torch.Size([3, 5])
tensor([[0.2711, 0.6923, 0.2038],
        [0.6833, 0.7529, 0.8579],
        [0.6870, 0.0051, 0.1757],
        [0.7497, 0.6047, 0.1100],
        [0.2121, 0.9704, 0.8369]])
tensor([0.2711, 0.6923, 0.2038, 0.6833, 0.7529, 0.8579, 0.6870, 0.0051, 0.1757,
        0.7497, 0.6047, 0.1100, 0.2121, 0.9704, 0.8369])
tensor([[0.2711, 0.6923, 0.2038, 0.6833, 0.7529],
        [0.8579, 0.6870, 0.0051, 0.1757, 0.7497],
        [0.6047, 0.1100, 0.2121, 0.9704, 0.8369]])
tensor([[0.2711, 0.6923, 0.2038, 0.6833, 0.7529],
        [0.8579, 0.6870, 0.0051, 0.1757, 0.7497],
        [0.6047, 0.1100, 0.2121, 0.9704, 0.8369]])<jupyter_text>**注意`view()`返回的新tensor与源tensor共享内存，也即更改其中的一个，另外一个也会跟着改变。**<jupyter_code># x += 1
# print(x)
# print(y) # 也加了1

x = torch.rand(5, 5)
print(x)
y = x
z = x.view(-1, 25)
print("id: ", id(x), id(z))
m = x[0, :]
print("id:", id(m))
x += 1
print(x)
print(y)
print(z)
print(m)<jupyter_output>tensor([[0.3986, 0.7742, 0.7703, 0.0178, 0.8119],
        [0.1087, 0.3943, 0.2973, 0.4037, 0.4018],
        [0.0513, 0.0683, 0.4218, 0.5065, 0.2729],
        [0.6883, 0.0500, 0.4663, 0.9397, 0.2961],
        [0.9515, 0.6811, 0.0488, 0.8163, 0.4423]])
id:  2344810515968 2344810513152
id: 2344716438656
tensor([[1.3986, 1.7742, 1.7703, 1.0178, 1.8119],
        [1.1087, 1.3943, 1.2973, 1.4037, 1.4018],
        [1.0513, 1.0683, 1.4218, 1.5065, 1.2729],
        [1.6883, 1.0500, 1.4663, 1.9397, 1.2961],
        [1.9515, 1.6811, 1.0488, 1.8163, 1.4423]])
tensor([[1.3986, 1.7742, 1.7703, 1.0178, 1.8119],
        [1.1087, 1.3943, 1.2973, 1.4037, 1.4018],
        [1.0513, 1.0683, 1.4218, 1.5065, 1.2729],
        [1.6883, 1.0500, 1.4663, 1.9397, 1.2961],
        [1.9515, 1.6811, 1.0488, 1.8163, 1.4423]])
tensor([[1.3986, 1.7742, 1.7703, 1.0178, 1.8119, 1.1087, 1.3943, 1.2973, 1.4037,
         1.4018, 1.0513, 1.0683, 1.4218, 1.5065, 1.2729, 1.6883, 1.0500, 1.4663,
         1.9397, 1.2961, 1.9515, 1[...]<jupyter_text>如果不想共享内存，推荐先用`clone`创造一个副本然后再使用`view`。<jupyter_code>x_cp = x.clone().view(15)
x -= 1
print(x)
print(x_cp)<jupyter_output><empty_output><jupyter_text>另外一个常用的函数就是`item()`, 它可以将一个标量`Tensor`转换成一个Python number：<jupyter_code>x = torch.randn(1)
print(x)
print(x.item())<jupyter_output>tensor([2.3466])
2.3466382026672363<jupyter_text>2.2.3 广播机制<jupyter_code>x = torch.arange(1, 3).view(1, 2)
print(x)
y = torch.arange(1, 4).view(3, 1)
print(y)
print(x + y)<jupyter_output>tensor([[1, 2]])
tensor([[1],
        [2],
        [3]])
tensor([[2, 3],
        [3, 4],
        [4, 5]])<jupyter_text>2.2.4 运算的内存开销<jupyter_code>x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
y = y + x
print(id(y) == id_before)
x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
y[:] = y + x
print(id(y) == id_before)
x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
torch.add(x, y, out=y) # y += x, y.add_(x)
print(id(y) == id_before)<jupyter_output>True<jupyter_text>2.2.5 `Tensor`和NumPy相互转换**`numpy()`和`from_numpy()`这两个函数产生的`Tensor`和NumPy array实际是使用的相同的内存，改变其中一个时另一个也会改变！！！** `Tensor`转NumPy<jupyter_code>a = torch.ones(5)
b = a.numpy()
print(a, b)

a += 1
print(a, b)
b += 1
print(a, b)<jupyter_output>tensor([1., 1., 1., 1., 1.]) [1. 1. 1. 1. 1.]
tensor([2., 2., 2., 2., 2.]) [2. 2. 2. 2. 2.]
tensor([3., 3., 3., 3., 3.]) [3. 3. 3. 3. 3.]<jupyter_text>NumPy数组转`Tensor`<jupyter_code>import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
print(a, b)

a += 1
print(a, b)
b += 1
print(a, b)<jupyter_output>[1. 1. 1. 1. 1.] tensor([1., 1., 1., 1., 1.], dtype=torch.float64)
[2. 2. 2. 2. 2.] tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
[3. 3. 3. 3. 3.] tensor([3., 3., 3., 3., 3.], dtype=torch.float64)<jupyter_text>直接用`torch.tensor()`将NumPy数组转换成`Tensor`，该方法总是会进行数据拷贝，返回的`Tensor`和原来的数据不再共享内存。<jupyter_code># 用torch.tensor()转换时不会共享内存
c = torch.tensor(a)
a += 1
print(a, c)<jupyter_output>[4. 4. 4. 4. 4.] tensor([3., 3., 3., 3., 3.], dtype=torch.float64)<jupyter_text>2.2.6 `Tensor` on GPU<jupyter_code># 以下代码只有在PyTorch GPU版本上才会执行
if torch.cuda.is_available():
    device = torch.device("cuda")          # GPU
    y = torch.ones_like(x, device=device)  # 直接创建一个在GPU上的Tensor
    x = x.to(device)                       # 等价于 .to("cuda")
    z = x + y
    print(id(z))
    print(z.to("cpu"))       # to()还可以同时更改数据类型
    print(id(z))<jupyter_output>2344830634688
tensor([[2.1473, 2.5223, 2.1475],
        [2.2248, 2.2086, 2.6709],
        [2.2020, 2.4891, 2.5210],
        [2.8223, 2.1220, 2.1567],
        [2.2097, 2.8500, 2.3203]])
2344830634688
{'fraction_non_alphanumeric': 0.23258745666561614, 'fraction_numerical': 0.249500998003992, 'mean_word_length': 3.08058294042006, 'pattern_counts': {'":': 0, '<': 67, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '21', 'dir': 'jupyter-structured-clean-dedup', 'id': '66589', 'license': 'Apache-2.0', 'n_tokens_mistral': 6445, 'n_tokens_neox': 5272, 'n_words': 784, 'path': 'code/chapter02_prerequisite/2.2_tensor.ipynb', 'repo_name': 'ceezous/Dive-into-DL-PyTorch', 'size': '9519'}