1.【Pytorchプログラミング】テンソルの概念、構築方法、格納方法を理解する

1.【Pytorchプログラミング】テンソルの概念、構築方法、格納方法を理解する

私のブログ コラムPytorch プログラミングシリーズ。Python 環境の構成については、「[Python の学習] Windows 10 で Anaconda のインストールと Python 環境の管理を開始する」または「[Python の学習] Anaconda のインストールと Python 環境の管理を開始するためのピュア ターミナル コマンド」を参照してください。

著者: Chen Yirong
コード環境: Python3.6、Pytorch1.4.0、jupyter notebook

このセクションの参考資料

コード環境のバージョンを表示

import torch
print(torch.__file__) # 查看安装位置
print(torch.__version__) # 查看版本号
print(torch.cuda.is_available()) # 查看CUDA版本是否可用
/home/phd-chen.yirong/anaconda3/envs/py36/lib/python3.6/site-packages/torch/__init__.py
1.4.0
True

テンソルの基本概念

tensor の英語名Tensor。たとえば、よく知られている深層学習フレームワークは+TensorFlowであり、これはテンソル フローを意味します。テンソルを理解するには、まずデータ構造とアルゴリズムを予備的に理解する必要があります。Tensormermaid flowchat

Python のデータ構造

Python の古典的なデータ構造はリストです. リストに基づいて、キューやスタックなどの古典的なデータ構造を実装することもできます。簡単に言うと、データ構造とは、キューの「先入れ先出し」やスタックの「先入れ先出し」など、データを格納および編成する方法です。
参照: https://docs.python.org/zh-cn/3/tutorial/datastructures.html

# 列表
list1 = [1,2,3,4,5,6,7,8]
print(list1)
print(type(list1))
## 列表末尾添加元素
list1.append(9)
print(list1)
[1, 2, 3, 4, 5, 6, 7, 8]
<class 'list'>
[1, 2, 3, 4, 5, 6, 7, 8, 9]

NumPy の Ndarray データ構造

Ndarray、そのフルネームは N 次元配列であり、N 次元配列に変換されます。配列は、同じデータ型の要素のコレクションとして表されるデータ構造でもあります。したがって、Python のリスト オブジェクトの各要素のデータ型が同じでなければならないことに同意する場合、このリストは配列と見なすことができます。Ndarrayそれはそのような特別なデータ構造です。具体的には、Ndarray内部は次のように構成されています。

  • データ (メモリ内のデータ ブロックまたはメモリ マップト ファイル) へのポインター。
  • 配列内の固定サイズの値のグリッドを表すデータ型 (dtype)。
  • 配列の形状を表すタプル、各次元のサイズを表すタプル。
  • ストライド タプル (ストライド)。整数は、現在の次元の次の要素に進むために「ストライド」するバイト数を表します。

ndarray オブジェクトは、コンピューター メモリの連続する 1 次元部分で構成され、各要素をメモリ ブロック内の場所にマップするインデックス パターンと組み合わされます。
参考: https: //www.runoob.com/numpy/numpy-ndarray-object.html

オブジェクトを作成するにNdarrayは、NumPy 関数を呼び出すだけですarray

numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
import numpy as np 
list1 = [1,2,3,4,5,6,7,8]
array1 = np.array(list1)  
print(array1)
print(type(array1))
[1 2 3 4 5 6 7 8]
<class 'numpy.ndarray'>

Ndarray から Pytorch へのテンソル データ構造

ここには歴史的な背景があり、多くの研究者は Pytorch を Numpy の代替、つまりGPUの性能を計算に利用するために PyTorch を使用すると考えています。
CPU と GPU という 2 つの一般的な科学概念があります。

  • CPU: 中央演算処理装置 (略して CPU) は、コンピュータ システムの計算および制御コアであり、情報処理およびプログラム操作の最終実行ユニットです。
  • GPU: グラフィックス プロセッシング ユニット (英語: グラフィックス プロセッシング ユニット、略称: GPU) は、ディスプレイ コア、ビジュアル プロセッサ、ディスプレイ チップとも呼ばれ、パーソナル コンピューター、ワークステーション、ゲーム コンソール、および一部のモバイル デバイス (タブレット コンピュータ、スマートフォンなど) は、画像およびグラフィック関連の操作を行うマイクロプロセッサです。

いくつかの違い: CPU: 計算量が少ない、原理: 4 つの計算ユニットのみ、複雑な演算を計算できる、複数の 1+1 算術問題の計算速度が遅い、GPU: 計算量が多い、原理: 1000 演算ユニット、できる単純な 1+1 算術問題のみを計算し、複数の 1+1 算術問題の計算速度は高速です。したがって、多くの場合、多数の並列計算を必要とする操作には、 GPU を使用する利点があります。

Tensor は、このコンピューター開発の背景から生まれました。

参考:https://zhuanlan.zhihu.com/p/156171120?utm_source=wechat_session

このように単純に理解できます: TensorNumPy に似ておりNdarrayTensorGPU を同時に計算に使用できます。したがってTensor、多くのプロパティとメソッドはNdarrayに似ています。

テンソルの一般的な構築方法

import torch
import numpy as np
  • torch.tensor は、リスト、タプル、NumPy ndarray、スカラー、およびその他のデータ型にする
    torch.tensor(data, *, dtype=None, device=None, requires_grad=False, pin_memory=False) → Tensor
    ことができます
    data
    dtype作成されたテンソルの要素のデータ型を指定します。これはtorch.dtypeのいずれかである可能性があり、一般的に使用されるのはtorch.floattorch.doubletorch.int
    deviceテンソルによって割り当てられたデバイスを指定する 'cpu' または 'cuda' 、 'cuda:0' 、.. .
    requires_gradテンソルが自動勾配操作の結果を記録するかどうかを指定します。
    pin_memoryテンソルが固定メモリに割り当てられることを指定します。このパラメーターは、CPU テンソルでのみ使用できます。
    torch.tensor の形式パラメーターから、実際にテンソルのいくつかの特徴を見つけることができます: 配列タイプ、機器を指定する必要がある、勾配計算をサポートし、勾配計算値を記録できます。
tensor1 = torch.tensor([[1, 2], [3, 4]])
print(tensor1)
print(tensor1[1])
print(tensor1[0,0])
print(type(tensor1))
tensor([[1, 2],
        [3, 4]])
tensor([3, 4])
tensor(1)
<class 'torch.Tensor'>

テンソルのプロパティを表示します。

print(tensor1.shape)
print(tensor1.dtype)
print(tensor1.device)
torch.Size([2, 2])
torch.int64
cpu

テンソルのデータ型とデバイス情報を指定します。

tensor2 = torch.tensor([[1, 2], [3, 4]],dtype=torch.float,device=torch.device('cuda'))
print(tensor2)
print(tensor2[1])
print(tensor2[0,0])
print(type(tensor2))
tensor([[1., 2.],
        [3., 4.]], device='cuda:0')
tensor([3., 4.], device='cuda:0')
tensor(1., device='cuda:0')
<class 'torch.Tensor'>

特別なテンソル:

# 0维张量(也叫做标量)
tensor3 = torch.tensor(2022,dtype=torch.int,device=torch.device('cuda'))
print(tensor3)
# Use torch.Tensor.item() to get a Python number from a tensor containing a single value
print(tensor3.item())
tensor(2022, device='cuda:0', dtype=torch.int32)
2022
# 空张量
tensor4 = torch.tensor([],dtype=torch.int,device=torch.device('cuda'))
print(tensor4)
tensor([], device='cuda:0', dtype=torch.int32)
  • torch.from_numpy は
    NumPy.ndarray 型のデータからテンソルを作成し、返されたテンソルと ndarray は同じメモリを共有します。
    テンソルへの変更は ndarray に反映され、その逆も同様です。返されたテンソルはサイズ変更できません。
np_array = np.array([[1,2,3,4,5,6],[1,2,3,4,5,6]])
x_np = torch.from_numpy(np_array)
print(x_np)
tensor([[1, 2, 3, 4, 5, 6],
        [1, 2, 3, 4, 5, 6]])
  • すべて 0 またはすべて 1 のテンソルを作成するか、別のテンソルの次元を参照してランダムに初期化します
x = torch.tensor([[1,2,3],[3,2,1]],dtype=torch.float,device=torch.device("cuda"))
print(x)
# 创建全为1张量,维度等与张量x相同
x_ones = torch.ones_like(x)
print(x_ones)
# 创建全为0张量,维度等与张量x相同
x_zeros = torch.zeros_like(x)
print(x_zeros)
# 创建随机设置元素的张量,维度等与张量x相同
x_rand = torch.rand_like(x, dtype=torch.float)
print(x_rand)
tensor([[1., 2., 3.],
        [3., 2., 1.]], device='cuda:0')
tensor([[1., 1., 1.],
        [1., 1., 1.]], device='cuda:0')
tensor([[0., 0., 0.],
        [0., 0., 0.]], device='cuda:0')
tensor([[0.9553, 0.0353, 0.3714],
        [0.2786, 0.4967, 0.8638]], device='cuda:0')
  • テンソルの次元を指定し、ランダムなテンソルまたは定数で構成されるテンソルを作成します
shape = (2,2)
rand_tensor = torch.rand(shape)
print(rand_tensor)
ones_tensor = torch.ones(shape)
print(ones_tensor)
zeros_tensor = torch.zeros(shape)
print(zeros_tensor)
tensor([[0.7727, 0.7495],
        [0.1478, 0.7323]])
tensor([[1., 1.],
        [1., 1.]])
tensor([[0., 0.],
        [0., 0.]])

テンソルの基本操作

1. テンソル.to演算

device = "cuda" if torch.cuda.is_available() else "cpu"
tensor5 = torch.tensor([[1, 2], [3, 4]])
tensor5 = tensor5.to(device)
print(tensor5)
tensor([[1, 2],
        [3, 4]], device='cuda:0')
tensor5 = tensor5.to("cpu")
print(tensor5)
tensor([[1, 2],
        [3, 4]])

2.テンソルの要素インデックス

tensor6 = torch.rand(3, 3)
print(tensor6)
print(f"First row: {
      
      tensor6[0]}")
print(f"First column: {
      
      tensor6[:, 0]}")
print(f"Last column: {
      
      tensor6[..., -1]}")
print(f"Last column: {
      
      tensor6[:, -1]}")
tensor6[:,1] = 1
print(tensor6)
tensor([[0.4778, 0.4452, 0.2678],
        [0.2579, 0.0155, 0.9202],
        [0.5348, 0.2705, 0.2810]])
First row: tensor([0.4778, 0.4452, 0.2678])
First column: tensor([0.4778, 0.2579, 0.5348])
Last column: tensor([0.2678, 0.9202, 0.2810])
Last column: tensor([0.2678, 0.9202, 0.2810])
tensor([[0.4778, 1.0000, 0.2678],
        [0.2579, 1.0000, 0.9202],
        [0.5348, 1.0000, 0.2810]])

3. テンソル スプライシング
この操作は、機能融合を処理するときによく使用されます。たとえば、3 つのモデルの機能を一緒にスプライシングし、それらを別のモデルに入力して機能融合を実現します。

tensor7 = torch.tensor([[1, 2], [3, 4]])
tensor3 = torch.cat([tensor7, tensor7, tensor7], dim=1)
print(tensor3)
tensor8 = torch.cat([tensor7, tensor7, tensor7], dim=0) # 最外层进行拼接
print(tensor8)
tensor9 = torch.cat([tensor7, tensor7, tensor7], dim=-1) # 最内层进行拼接
print(tensor9)
tensor([[1, 2, 1, 2, 1, 2],
        [3, 4, 3, 4, 3, 4]])
tensor([[1, 2],
        [3, 4],
        [1, 2],
        [3, 4],
        [1, 2],
        [3, 4]])
tensor([[1, 2, 1, 2, 1, 2],
        [3, 4, 3, 4, 3, 4]])

ビュー機能を通じてテンソルの格納を理解する

pytorch と numpy が MxN 配列を格納する場合、どちらも2 次元テンソルなどの行の優先度に従って配列を 1 次元ストレージに拡張することに注意してください。

t = torch.tensor([[1, 3, 5], [2, 4, 6]])

記憶にあるのは実際には

[1, 3, 5, 2, 4, 6]

このように収納。

  • view() 関数: It does not change the real shape of the tensor in memory. ビュー関数を使用した後、テンソルの数値は通常、意味的に連続していますが、メモリ内では連続していません。
    pytorch の関数の機能は、numpy のview関数と同等のテンソルの次元を再構築することですresize返されるテンソルは同じデータを共有し、同じ数の要素を持つ必要がありますが、サイズが異なる場合があります。viewテンソルが有効であるためには、view最終的なテンソルの次元は元の次元および次元と互換性がなければなりません。
    viewこのメソッドは、連続性条件を満たすテンソルにのみ適用できます。この操作は、新しいメモリ空間を開くのではなく、元のストレージ空間への新しいエイリアスと参照を生成するだけであり、戻り値はビューです。
t0 = torch.randn(4, 4)
print("t0=",t0)
print(t0.size())
t1 = t0.view(16)
print("t1=",t1)
print(t1.size())
t2 = t0.view(2, 8)  # the size -1 is inferred from other dimensions
print("t2=",t2)
print(t2.size())
t0= tensor([[ 0.0713,  0.2641, -1.6546,  1.0520],
        [ 2.0892,  0.9782, -0.6922,  0.8448],
        [-1.9219, -0.0295,  0.6358, -1.1346],
        [ 0.3436,  0.2619,  0.2935, -2.4253]])
torch.Size([4, 4])
t1= tensor([ 0.0713,  0.2641, -1.6546,  1.0520,  2.0892,  0.9782, -0.6922,  0.8448,
        -1.9219, -0.0295,  0.6358, -1.1346,  0.3436,  0.2619,  0.2935, -2.4253])
torch.Size([16])
t2= tensor([[ 0.0713,  0.2641, -1.6546,  1.0520,  2.0892,  0.9782, -0.6922,  0.8448],
        [-1.9219, -0.0295,  0.6358, -1.1346,  0.3436,  0.2619,  0.2935, -2.4253]])
torch.Size([2, 8])
t3 = t.view(-1) # 等价于t.view(16)
print("t3=",t3)
print(t3.size())
t3= tensor([1, 3, 5, 2, 4, 6])
torch.Size([6])

関数を使用しviewた後, テンソルの数値は通常, 意味的に連続していますが, メモリ内では連続していません. このとき,.contiguous()新しいテンソルが意味論とメモリの両方で連続であることを保証するために関数を使用できます. .contiguous()このメソッドは、最初にテンソルのアドレスをメモリにコピーし、次に形状変更後のテンソルのセマンティクスに従ってアドレスを配置します。

t4 = torch.randn(3, 4)
print("t4=",t4)
t5 = t4.view(4, 3).contiguous() 
print("t5=",t5)
print(t5.size())
t4= tensor([[ 1.4501,  0.0161, -0.0799,  0.8645],
        [-0.2330, -0.8001, -1.6973, -0.2469],
        [ 0.9000,  0.2703, -0.1075,  1.4058]])
t5= tensor([[ 1.4501,  0.0161, -0.0799],
        [ 0.8645, -0.2330, -0.8001],
        [-1.6973, -0.2469,  0.9000],
        [ 0.2703, -0.1075,  1.4058]])
torch.Size([4, 3])
# [[1,3,5],
#  [2,4,6]]
#
t6 = torch.tensor([[1, 3, 5], [2, 4, 6]])
t6_v = t6.view(-1)
print('t6.view(-1)=', t6_v) # [1, 3, 5, 2, 4, 6]
t6.view(-1)= tensor([1, 3, 5, 2, 4, 6])

以下のテンソル t7 は、意味的には次のようになります。

[[1, 2],
 [3, 4],
 [5, 6]]

しかし、メモリ内では t6 と同じで、次のようになります。

[1, 3, 5, 2, 4, 6]

メモリの連続性が満たされる場合は、次のように保存する必要があります。

[1, 2, 3, 4, 5, 6]
t7 = t.transpose(0, 1) # 内存上:[1, 3, 5, 2, 4, 6]
print('t7=', t7)
t7= tensor([[1, 2],
        [3, 4],
        [5, 6]])
# 不满足语义和存储上的连续一致性,无法使用view函数
print(t7.view(-1))
---------------------------------------------------------------------------

RuntimeError                              Traceback (most recent call last)

<ipython-input-61-e4b044462be1> in <module>
      1 # 不满足语义和存储上的连续一致性,无法使用view函数
----> 2 print(t7.view(-1))


RuntimeError: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Use .reshape(...) instead.
t8 = t7.contiguous() # 内存上:[1, 2, 3, 4, 5, 6]
t8_v = t8.view(-1)
print('t8.view(-1)=', t8_v) # [1, 2, 3, 4, 5, 6]
t8.view(-1)= tensor([1, 2, 3, 4, 5, 6])

おすすめ

転載: blog.csdn.net/m0_37201243/article/details/123725982