<label id="jgr5k"></label>
    <legend id="jgr5k"><track id="jgr5k"></track></legend>

    <sub id="jgr5k"></sub>
  1. <u id="jgr5k"></u>
      久草国产视频,91资源总站,在线免费看AV,丁香婷婷社区,久久精品99久久久久久久久,色天使av,无码探花,香蕉av在线
      您正在使用IE低版瀏覽器,為了您的雷峰網(wǎng)賬號安全和更好的產(chǎn)品體驗,強烈建議使用更快更安全的瀏覽器
      此為臨時鏈接,僅用于文章預覽,將在時失效
      人工智能開發(fā)者 正文
      發(fā)私信給skura
      發(fā)送

      0

      PyTorch代碼規(guī)范最佳實踐和樣式指南

      本文作者: skura 2019-04-16 13:02
      導語:PyTorch的非官方風格指南和最佳實踐摘要

      雷鋒網(wǎng) AI 科技評論按,本文不是 Python 的官方風格指南。本文總結(jié)了使用 PyTorch 框架進行深入學習的一年多經(jīng)驗中的最佳實踐。本文分享的知識主要是以研究的角度來看的,它來源于一個開元的 github 項目。

      根據(jù)經(jīng)驗,作者建議使用 Python 3.6+,因為以下功能有助于寫出干凈簡單的代碼:

      • 支持 Python 3.6 以后的輸入。

      • 自 Python 3.6 起支持 f 字符串

      Python Styleguide 概述

      作者嘗試按照 Google Styleguide for Python 進行操作,這里是 Google 提供的 python 代碼詳細樣式指南

      常見的命名約定:

      PyTorch代碼規(guī)范最佳實踐和樣式指南

      Jupyter Notebook與Python腳本

      一般來說,建議使用 Jupyternotebook 進行初步探索和使用新的模型和代碼。如果你想在更大的數(shù)據(jù)集上訓練模型,就應(yīng)該使用 Python 腳本。在這里,復用性更為重要。

      推薦使用的工作流程是:

      1. 從Jupyter筆記本開始

      2. 探索數(shù)據(jù)和模型

      3. 在 notebook 的單元格中構(gòu)建類/方法

      4. 將代碼移動到python腳本中

      5. 在服務(wù)器上訓練/部署

      注意,不要將所有層和模型放在同一個文件中。最佳做法是將最終網(wǎng)絡(luò)分離為單獨的文件(networks.py),并將層、損耗和 ops 保存在各自的文件(layers.py、losses.py、ops.py)中。完成的模型(由一個或多個網(wǎng)絡(luò)組成)應(yīng)在一個文件中引用,文件名為 yolov3.py、dcgan.py 這樣。

      在PyTorch中構(gòu)建神經(jīng)網(wǎng)絡(luò)

      我們建議將網(wǎng)絡(luò)拆分為更小的可重用部分。網(wǎng)絡(luò)由操作或其它網(wǎng)絡(luò)模塊組成。損失函數(shù)也是神經(jīng)網(wǎng)絡(luò)的模塊,因此可以直接集成到網(wǎng)絡(luò)中。

      繼承自 nn.module 的類必須有一個 forward 方法來實現(xiàn)各個層或操作的 forward 傳遞。

      使用 self.net(input),可以在輸入數(shù)據(jù)上使用 nn.module。這只需使用對象的 call()方法。

      output = self.net(input)

      PyTorch 中的一個簡單網(wǎng)絡(luò)

      對于具有單個輸入和單個輸出的簡單網(wǎng)絡(luò),請使用以下模式:

      class ConvBlock(nn.Module):
          def __init__(self):
              super(ConvBlock, self).__init__()
              block = [nn.Conv2d(...)]
              block += [nn.ReLU()]
              block += [nn.BatchNorm2d(...)]
              self.block = nn.Sequential(*block)
          
          def forward(self, x):
              return self.block(x)

      class SimpleNetwork(nn.Module):
          def __init__(self, num_resnet_blocks=6):
              super(SimpleNetwork, self).__init__()
              # here we add the individual layers
              layers = [ConvBlock(...)]
              for i in range(num_resnet_blocks):
                  layers += [ResBlock(...)]
              self.net = nn.Sequential(*layers)
          
          def forward(self, x):
              return self.net(x)

      需要注意的是:

      • 重用簡單的、循環(huán)的構(gòu)建塊,例如 ConvBlock,它由相同的循環(huán)模式(卷積、激活、歸一化)組成,并將它們放入單獨的nn.模塊中。

      • 作者構(gòu)建了一個所需層的列表,最后使用 nn.Sequential()將它們轉(zhuǎn)換為模型。在 list 對象之前使用 * 操作符來展開它。

      • 在前向傳導中,我們只是通過模型運行輸入。

      pytorch 中跳過連接的網(wǎng)絡(luò)

      class ResnetBlock(nn.Module):
          def __init__(self, dim, padding_type, norm_layer, use_dropout, use_bias):
              super(ResnetBlock, self).__init__()
              self.conv_block = self.build_conv_block(...)

          def build_conv_block(self, ...):
              conv_block = []

              conv_block += [nn.Conv2d(...),
                             norm_layer(...),
                             nn.ReLU()]
              if use_dropout:
                  conv_block += [nn.Dropout(...)]
                  
              conv_block += [nn.Conv2d(...),
                             norm_layer(...)]

              return nn.Sequential(*conv_block)

          def forward(self, x):
              out = x + self.conv_block(x)
              return out

      在這里,ResNet 塊的跳過連接直接在前向傳導中實現(xiàn)。PyTorch 允許在前向傳導時進行動態(tài)操作。

      PyTorch中具有多個輸出的網(wǎng)絡(luò)

      對于需要多個輸出的網(wǎng)絡(luò),例如使用預訓練的 VGG 網(wǎng)絡(luò)構(gòu)建感知損失,我們使用以下模式:

      class Vgg19(nn.Module):
        def __init__(self, requires_grad=False):
          super(Vgg19, self).__init__()
          vgg_pretrained_features = models.vgg19(pretrained=True).features
          self.slice1 = torch.nn.Sequential()
          self.slice2 = torch.nn.Sequential()
          self.slice3 = torch.nn.Sequential()

          for x in range(7):
              self.slice1.add_module(str(x), vgg_pretrained_features[x])
          for x in range(7, 21):
              self.slice2.add_module(str(x), vgg_pretrained_features[x])
          for x in range(21, 30):
              self.slice3.add_module(str(x), vgg_pretrained_features[x])
          if not requires_grad:
              for param in self.parameters():
                  param.requires_grad = False

        def forward(self, x):
          h_relu1 = self.slice1(x)
          h_relu2 = self.slice2(h_relu1)        
          h_relu3 = self.slice3(h_relu2)        
          out = [h_relu1, h_relu2, h_relu3]
          return out

      請注意:

      • 這里使用 torchvision 提供的預訓練模型。

      • 這里把網(wǎng)絡(luò)分成三部分,每個部分由預訓練模型的層組成。

      • 通過設(shè)置 requires_grad = False 來凍結(jié)網(wǎng)絡(luò)。

      • 我們返回一個包含三個輸出部分的列表。

      自定義損失

      雖然 PyTorch 已經(jīng)有很多標準的損失函數(shù),但有時也可能需要創(chuàng)建自己的損失函數(shù)。為此,請創(chuàng)建單獨的文件 losses.py 并擴展 nn.module 類以創(chuàng)建自定義的損失函數(shù):

      class CustomLoss(nn.Module):
          
          def __init__(self):
              super(CustomLoss,self).__init__()
              
          def forward(self,x,y):
              loss = torch.mean((x - y)**2)
              return loss

      推薦使用的用于訓練模型的代碼結(jié)構(gòu)

      請注意,作者使用了以下模式:

      我們使用 prefetch_generator 中的 BackgroundGenerator 在后臺加載 batch。有關(guān)詳細信息,請參閱這里

      我們使用 tqdm 來監(jiān)控訓練進度并顯示計算效率。這有助于我們在數(shù)據(jù)加載管道中找到瓶頸在哪里。

      # import statements
      import torch
      import torch.nn as nn
      from torch.utils import data
      ...

      # set flags / seeds
      torch.backends.cudnn.benchmark = True
      np.random.seed(1)
      torch.manual_seed(1)
      torch.cuda.manual_seed(1)
      ...

      # Start with main code
      if __name__ == '__main__':
          # argparse for additional flags for experiment
          parser = argparse.ArgumentParser(description="Train a network for ...")
          ...
          opt = parser.parse_args()
          
          # add code for datasets (we always use train and validation/ test set)
          data_transforms = transforms.Compose([
              transforms.Resize((opt.img_size, opt.img_size)),
              transforms.RandomHorizontalFlip(),
              transforms.ToTensor(),
              transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
          ])
          
          train_dataset = datasets.ImageFolder(
              root=os.path.join(opt.path_to_data, "train"),
              transform=data_transforms)
          train_data_loader = data.DataLoader(train_dataset, ...)
          
          test_dataset = datasets.ImageFolder(
              root=os.path.join(opt.path_to_data, "test"),
              transform=data_transforms)
          test_data_loader = data.DataLoader(test_dataset ...)
          ...
          
          # instantiate network (which has been imported from *networks.py*)
          net = MyNetwork(...)
          ...
          
          # create losses (criterion in pytorch)
          criterion_L1 = torch.nn.L1Loss()
          ...
          
          # if running on GPU and we want to use cuda move model there
          use_cuda = torch.cuda.is_available()
          if use_cuda:
              net = net.cuda()
              ...
          
          # create optimizers
          optim = torch.optim.Adam(net.parameters(), lr=opt.lr)
          ...
          
          # load checkpoint if needed/ wanted
          start_n_iter = 0
          start_epoch = 0
          if opt.resume:
              ckpt = load_checkpoint(opt.path_to_checkpoint) # custom method for loading last checkpoint
              net.load_state_dict(ckpt['net'])
              start_epoch = ckpt['epoch']
              start_n_iter = ckpt['n_iter']
              optim.load_state_dict(ckpt['optim'])
              print("last checkpoint restored")
              ...
              
          # if we want to run experiment on multiple GPUs we move the models there
          net = torch.nn.DataParallel(net)
          ...
          
          # typically we use tensorboardX to keep track of experiments
          writer = SummaryWriter(...)
          
          # now we start the main loop
          n_iter = start_n_iter
          for epoch in range(start_epoch, opt.epochs):
              # set models to train mode
              net.train()
              ...
              
              # use prefetch_generator and tqdm for iterating through data
              pbar = tqdm(enumerate(BackgroundGenerator(train_data_loader, ...)),
                          total=len(train_data_loader))
              start_time = time.time()
              
              # for loop going through dataset
              for i, data in pbar:
                  # data preparation
                  img, label = data
                  if use_cuda:
                      img = img.cuda()
                      label = label.cuda()
                  ...
                  
                  # It's very good practice to keep track of preparation time and computation time using tqdm                to find any issues in your dataloader
                  prepare_time = start_time-time.time()
                  
                  # forward and backward pass
                  optim.zero_grad()
                  ...
                  loss.backward()
                  optim.step()
                  ...
                  
                  # udpate tensorboardX
                  writer.add_scalar(..., n_iter)
                  ...
                  
                  # compute computation time and *compute_efficiency*

                  process_time = start_time-time.time()-prepare_time
                  pbar.set_description("Compute efficiency: {:.2f}, epoch: {}/{}:".format(
                      process_time/(process_time+prepare_time), epoch, opt.epochs))
                  start_time = time.time()
                  
              # maybe do a test pass every x epochs
              if epoch % x == x-1:
                  # bring models to evaluation mode
                  net.eval()
                  ...
                  #do some tests
                  pbar = tqdm(enumerate(BackgroundGenerator(test_data_loader, ...)),
                          total=len(test_data_loader))
                  for i, data in pbar:
                      ...
                      
                  # save checkpoint if needed
                  ...

      用 PyTorch 在多個 GPU 上進行訓練

      PyTorch 中有兩種不同的模式去使用多個 GPU 進行訓練。根據(jù)經(jīng)驗,這兩種模式都是有效的。然而,第一種方法得到的結(jié)果更好,需要的代碼更少。由于 GPU 之間的通信較少,第二種方法似乎具有輕微的性能優(yōu)勢。

      分割每個網(wǎng)絡(luò)的批輸入

      最常見的方法是簡單地將所有網(wǎng)絡(luò)的批劃分為單個 GPU。

      因此,在批大小為 64 的 1 個 GPU 上運行的模型將在批大小為 32 的 2 個 GPU 上運行。這可以通過使用 nn.dataparallel(model)自動包裝模型來完成。

      將所有網(wǎng)絡(luò)打包到超級網(wǎng)絡(luò)中并拆分輸入批

      這種模式不太常用。Nvidia 的 pix2pixhd 實現(xiàn)中顯示了實現(xiàn)此方法的存儲庫

      什么該做什么不該做

      避免在 nn.Module 的 forward 方法中使用 numpy 代碼

      numpy 代碼在 CPU 上運行的速度比 torch 代碼慢。由于 torch 的開發(fā)理念和 numpy 類似,所以 pytorch 支持大多數(shù) numpy 函數(shù)。

      將數(shù)據(jù)加載器與主代碼分離

      數(shù)據(jù)加載管道應(yīng)該獨立于你的主要訓練代碼。PyTorch 使后臺工作人員可以更高效地加載數(shù)據(jù),但不會干擾主要的訓練過程。

      不要每個步驟都輸出結(jié)果日志

      通常,我們對模型進行數(shù)千步的訓練。因此,不要在每一步記錄結(jié)果就足以減少開銷。尤其是,在訓練過程中將中間結(jié)果保存為圖像成本高昂。

      使用命令行參數(shù)

      在代碼執(zhí)行期間使用命令行參數(shù)設(shè)置參數(shù)(批大小、學習速率等)非常方便。跟蹤實驗參數(shù)的一個簡單方法是只打印從 parse_args 接收到的字典:

      ...

      # saves arguments to config.txt file

      opt = parser.parse_args()

      with open("config.txt", "w") as f:
         f.write(opt.__str__())...

      如果可能,使用 .detach()從圖表中釋放張量

      pytorch跟蹤所有涉及張量的自動微分操作。使用 .detach()防止記錄不必要的操作。

      使用 .item()打印標量張量

      你可以直接打印變量,但是建議使用 variable.detach()或 variable.item()。在早期的 pytorch 版本中,必須使用 .data 來訪問變量的張量。

      在 nn.Module 上使用 call 方法而不是 forward

      這兩種方法不完全相同,下面的例子就可以看出這一點:

      output = self.net.forward(input)
      # they are not equal!
      output = self.net(input)

      另外,原文中還有關(guān)于常見問題的解答,感興趣的可以移步這里

      via:https://github.com/IgorSusmelj/pytorch-styleguide

      雷鋒網(wǎng)雷鋒網(wǎng)

      雷峰網(wǎng)版權(quán)文章,未經(jīng)授權(quán)禁止轉(zhuǎn)載。詳情見轉(zhuǎn)載須知

      PyTorch代碼規(guī)范最佳實踐和樣式指南

      分享:
      相關(guān)文章
      當月熱門文章
      最新文章
      請?zhí)顚懮暾埲速Y料
      姓名
      電話
      郵箱
      微信號
      作品鏈接
      個人簡介
      為了您的賬戶安全,請驗證郵箱
      您的郵箱還未驗證,完成可獲20積分喲!
      請驗證您的郵箱
      立即驗證
      完善賬號信息
      您的賬號已經(jīng)綁定,現(xiàn)在您可以設(shè)置密碼以方便用郵箱登錄
      立即設(shè)置 以后再說
      主站蜘蛛池模板: 麻豆乱码国产一区二区三区| 国产无码久久| 在线观看成人年视频免费| 伊人久久精品久久亚洲一区| 福利在线视频导航| 全亚洲精品成人| 老熟妇乱子交视频一区| 久久精品国产亚洲AV果冻传媒 | 成人小说一区| 亚洲AV永久久久久久久浪潮| 亚洲最大在线精品| 亚洲人成综合网站7777香蕉| 性大毛片视频| 国产在线视频国产永久视频| 精品久久久久国产免费| 亚洲5555| 人妻少妇精品无码专区动漫| 精品久久一区| 狠狠躁夜夜躁人人爽天天bl| 又大又紧又粉嫩18p少妇| 高清无码免费不卡视频| 伊人久久精品一区二区三区| 亚洲一区二区三区在线播放无码| 少妇人妻偷人精品无码视频新浪| 梁河县| 少妇爆乳无码专区| 亚洲日韩AV无码专区影院| 人妻资源站| 亚洲av自拍| 久久精品熟女亚洲av艳妇| 精品国产女同疯狂摩擦2| 中文字幕在线精品视频入口一区| 电影久久久久久| 女人摸下面自熨视频在线播放| 亚洲国产精品18久久久久久| 91亚洲人成电影网站在线观看| 欧美老熟妇又粗又大| xxx综合网| 茄子视频国产在线观看 | 久久精品99国产精品日本| 国产精品男女爽免费视频|