PytochはGPUを効率よく使う操作です。

7649 ワード

前言
深さ学習は多くのベクトルまたは複数のマトリックス演算に関連し、例えばマトリックス相乗、マトリックス加算、マトリックスベクトル乗算などがある。深層モデルのアルゴリズムは、BP、Auto-Encerr、CNNなど、マトリックス演算の形に書くことができます。循環演算に書く必要はありません。しかしながら、シングルコアCPUで実行すると、マトリックス演算はサイクルとして展開され、本質的にはシリアルで実行されます。GPU(Graphic Process Unity)のコアアーキテクチャは数千のストリームプロセッサを含み、マトリックス演算を並列化して実行し、計算時間を大幅に短縮することができる。NVIDIA、AMDなどがGPUの大規模な並列アーキテクチャを推進していくにつれて、汎用計算向けGPUは並列アプリケーションを加速させる重要な手段となっている。GPUコア(many-core)システムのおかげで、GPUシステムでのプログラムの動作速度はシングルコアCPUよりも数十倍以上千倍以上になります。
GPUは現在、より成熟した段階に発展している。GPUを利用して深度神経ネットワークを訓練することで、コアを計算する能力を十分に発揮し、膨大な量のトレーニングデータを使用するシーンでは、時間が大幅に短縮され、占有するサーバも少ない。適切な深さ神経ネットワークを合理的に最適化すれば、1つのGPUカードは数十台以上のCPUサーバの計算能力に相当します。したがって、GPUはすでに業界の深さ学習モデルトレーニングにおける優先解決策となりました。
GPUはどう使いますか?今は多くの深さ学習ツールがGPU演算に対応しています。簡単に配置すればいいです。PytochはGPUをサポートしています。to関数によってデータをメモリからGPUメモリに転送できます。複数のGPUがあれば、どのGPUかまたはどのGPUかを特定できます。Pytouchは一般的にGPUをテンソル(Tensor)やモデル(touch.nnの下のいくつかのネットワークモデルと自分で作成したモデルを含む)などのデータ構造に作用させる。
シングルGPU加速
GPUを使う前に、GPUが使えるようにする必要があります。available()の戻り値で判断します。Trueに戻ると、使えるGPUがあります。
touch.cuda.deviceを通してcount()は使用できるGPUの数を得ることができます。
どのようにプラットフォームGPUの配置情報を調べますか?コマンドラインにコマンドnvidia-smiを入力すればいいです。図5-13はGPU構成情報の一例であり、2つのGPUがあることがわかる。

図GPU配置情報
データをメモリからGPUに転送します。テンソル(私たちが必要とするデータ)とモデルに対して一般的です。テンソル(タイプはFloat TensorまたはLongTensorなど)に対しては、すべて直接的に方法を使用します。to(device)または.cuda()でいいです。

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# device = torch.device("cuda:0")
device1 = torch.device("cuda:1") 
for batch_idx, (img, label) in enumerate(train_loader):
  img=img.to(device)
  label=label.to(device)
モデルにとっても同様の方法であり、GPUにネットワークを現像するためにtoまたは.cudaを使用する。

#     
model = Net()
model.to(device)  #     0 GPU
# model.to(device1) #     1 GPU
マルチGPU加速
ここでは、シングルホストマルチGPUsの場合、シングルマシン多GPUsは主にDataPalel関数を採用しています。DisttributedParalelではなく、後者は一般的にマルチホスト多GPUsに使用されます。もちろん、シングルマシン多GPUにも使用できます。
マルチカードを使って訓練する方法はたくさんあります。もちろん前提は私達の設備の中に二つ以上のGPUがあります。
使用時に直接modelでtouch.nn.DataParalel関数に入ればいいです。次のコードです。
同前
net=touch.nn.Data Paralel(model)
この場合、デフォルトでは存在するすべてのグラフィックカードが使用されます。
もしあなたのコンピュータに多くのグラフィックカードがあるとしたら、その一部だけを利用したいです。例えば、番号が0、1、3、4の4つのGPUだけを使用すれば、以下のようになります。

#   4 GPU, id    
device_ids =[0,1,2,3]
#   
input_data=input_data.to(device=device_ids[0])
#    
net = torch.nn.DataParallel(model)
net.to(device)
または
os.environ[CUDA_]VISIBLE_DEVICES'=','.jun(map(str,[0,1,2,3])
net=touch.nn.Data Paralel(model)
その中のCUDA_VISIBLE_DEVICESは、Pytochプログラムで現在検出可能なGPUを示しています。
以下は単一マシン多GPUの実現コードです。
背景の説明
ここではボストンの住宅価格のデータを例にとって、全部で506サンプルで、13の特徴があります。データはトレーニングセットとテストセットに分割され、data.Data Loaderを用いてバッチロードの方式に変換される。nn.Data Paralelの同時メカニズムを採用し、環境は2つのGPUがあります。もちろん、データ量が小さいので、nn.DataPalelは使わないはずです。ここでは使い方を説明するためだけに。
データをロード

boston = load_boston()
X,y  = (boston.data, boston.target)
 
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
#         
myset = list(zip(X_train,y_train))
データをバッチ処理に変換し、ロード方式のバッチサイズは128で、データをシャッフルする。

from torch.utils import data
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
dtype = torch.FloatTensor
train_loader = data.DataLoader(myset,batch_size=128,shuffle=True)
ネットワークを定義

class Net1(nn.Module):
  """
    sequential    ,Sequential()                
  """
  def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):
    super(Net1, self).__init__()
    self.layer1 = torch.nn.Sequential(nn.Linear(in_dim, n_hidden_1))
    self.layer2 = torch.nn.Sequential(nn.Linear(n_hidden_1, n_hidden_2))
    self.layer3 = torch.nn.Sequential(nn.Linear(n_hidden_2, out_dim))
    
 
  def forward(self, x):
    x1 = F.relu(self.layer1(x))
    x1 = F.relu(self.layer2(x1))
    x2 = self.layer3(x1)
    #    GPU       
    print("\tIn Model: input size", x.size(),"output size", x2.size())
    return x2
モデルを多GPUに変換し、併せて処理するフォーマットです。

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#     
model = Net1(13, 16, 32, 1)
if torch.cuda.device_count() > 1:
  print("Let's use", torch.cuda.device_count(), "GPUs")
  # dim = 0 [64, xxx] -> [32, ...], [32, ...] on 2GPUs
  model = nn.DataParallel(model)
model.to(device)
実行結果

Let's use 2 GPUs
DataParallel(
(module): Net1(
(layer1): Sequential(
(0): Linear(in_features=13, out_features=16, bias=True)
)
(layer2): Sequential(
(0): Linear(in_features=16, out_features=32, bias=True)
)
(layer3): Sequential(
(0): Linear(in_features=32, out_features=1, bias=True)
)
)
)
最適化器と損失関数を選択
optimizer_orig=touch.optim.Adam(model.parameters()、lr=0.01)
loss_func=toch.nn.MSELLS()
モデルトレーニングを行い、損失値を可視化する。

from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter(log_dir='logs')
for epoch in range(100):    
  model.train()
  for data,label in train_loader:
    input = data.type(dtype).to(device)
    label = label.type(dtype).to(device)
    output = model(input)    
    loss = loss_func(output, label)
    #     
    optimizer_orig.zero_grad()
    loss.backward()
    optimizer_orig.step()
    print("Outside: input size", input.size() ,"output_size", output.size())
  writer.add_scalar('train_loss_paral',loss, epoch)
運転の結果の一部

In Model: input size torch.Size([64, 13]) output size torch.Size([64, 1])
In Model: input size torch.Size([64, 13]) output size torch.Size([64, 1])
Outside: input size torch.Size([128, 13]) output_size torch.Size([128, 1])
In Model: input size torch.Size([64, 13]) output size torch.Size([64, 1])
In Model: input size torch.Size([64, 13]) output size torch.Size([64, 1])
Outside: input size torch.Size([128, 13]) output_size torch.Size([128, 1])
運転結果から、1ロットのデータ(batch-size=128)は2つに分割され、各サイズは64で、それぞれ異なるGPUに配置されていることが分かります。GPUモニタを使っても、2つのGPUが同時に使用されていることが分かります。

8.webで損失値の変化状況を確認する

図併発運転訓練損失値の変化状況を示す。
図に大きな振幅が出ているのはロット処理を採用しているためで、データの前処理は一切していません。データを正規化するにはもっと平滑化すべきです。試してみてください。
シングルマシンのマルチGPUもDisttributedParalelを使用することができます。分布トレーニングに多く使われていますが、単一マシンのマルチGPUでのトレーニングにも使えます。構成はnn.DataPalelを使うよりも少し面倒ですが、トレーニング速度と効果はもっと良いです。具体的な設定は:

#     nccl  
torch.distributed.init_process_group(backend="nccl")
#     
model=torch.nn.parallel.DistributedDataParallel(model)
単機運転時は次の方法で起動します。
python-m touch.distributed.launch main.py
GPU使用上の注意事項
GPUを使うと、私たちが訓練した速度が上がります。使い方が間違っていると、使用効率に影響を与える可能性があります。具体的に使う時は以下の点に注意してください。
GPUの数はできれば偶数で、奇数のGPUは異常中断する場合があります。
GPUは速いですが、データ量が小さいので、効果は単一GPUほど良くないかもしれません。CPUにも及ばないです。
メモリが足りない場合は、マルチGPUを使ってトレーニングする時にpin_を設定することができます。memoryはFalseであり、もちろん使用精度がやや低いデータタイプも効果があります。
以上のPytouchはGPUを効率的に使って操作します。小編集は皆さんに全部の内容を共有します。参考にしてもらいたいです。どうぞよろしくお願いします。