Pytorch DataLoader बेहद धीमा पहला युग

Aug 30 2020

जब मैं PyTorch DataLoader बनाता हूं और पुनरावृत्ति शुरू करता हूं - मुझे एक बेहद धीमी गति वाला पहला युग (x10 - x30 धीमा तब सभी अगले युग) मिलते हैं। इसके अलावा, यह समस्या केवल कागल से Google लैंडमार्क मान्यता 2020 से ट्रेन डेटासेट के साथ होती है। मैं इसे सिंथेटिक छवियों पर पुन: पेश नहीं कर सकता, इसके अलावा, मैंने GLR2020 से 500k छवियों के साथ एक फ़ोल्डर बनाने की कोशिश की, और सब कुछ अच्छी तरह से काम किया। बिना किसी समाधान के PyTorch फोरम में कुछ समान समस्याएं मिलीं।

import argparse
import pandas as pd
import numpy as np
import os, sys
import multiprocessing, ray
import time
import cv2
import logging
import albumentations as albu
from torch.utils.data import Dataset, DataLoader

samples = 50000 # count of samples to speed up test
bs = 64 # batch size
dir = '/hdd0/datasets/ggl_landmark_recognition_2020/train' # directory with train data
all_files = pd.read_csv('/hdd0/datasets/ggl_landmark_recognition_2020/train.csv')
files = np.random.choice(all_files.id.values, 50000)
files = [os.path.join(_[0], _[1], _[2], _+'.jpg') for _ in files]

# augmentations
aug =  albu.Compose([albu.Resize(400, 400),
        albu.Rotate(limit=15),
        albu.ChannelDropout(p=0.1),
        albu.Normalize(),])

class ImgDataset:
    def __init__(self, path, files, augmentation = None):
        self.path = path
        self.files = {k:v for k, v in enumerate(files)}
        self.augmentation = augmentation

    def __len__(self):
        return len(self.files)

    def __getitem__(self, idx):
        img_name = self.files[idx]
        img = np.array(cv2.imread(os.path.join(self.path, img_name)))
        if self.augmentation is not None:
            return self.augmentation(image=img)['image']


dtset = ImgDataset(dir,files, aug)
torchloader = DataLoader(dataset= dtset, batch_size=64, num_worker=16, shuffle=True)
for _ in range(3):
   t1 = time.time()
   for idx, val in enumerate(torchloader):
       pass
   t2 = time.time()
   print(str(t2-t1) +' sec')

यहाँ num_workersDataLoader में विभिन्न के साथ निष्पादन की गति के कुछ उदाहरण दिए गए हैं

#num_workers=0
273.1584792137146 sec
83.15653467178345 sec
83.67923021316528 sec

# num_workers = 8 
165.62366938591003 sec
10.405716896057129 sec
10.495309114456177 sec

# num_workers = 16
156.60744667053223 sec
8.051618099212646 sec
7.922858238220215 sec

ऐसा लगता है कि समस्या DataLoader के साथ नहीं है, लेकिन डेटासेट के साथ है। जब मैं पहले "लंबे" पुनरावृत्ति के बाद DataLoader ऑब्जेक्ट को हटाता हूं और पुनर्निवेश करता हूं, तब भी सब कुछ ठीक रहता है। जब मैं डेटासेट पुन: उपयोग करता हूं - लंबे समय तक पहली पुनरावृत्ति फिर से दिखाई देती है। इसके अलावा, मैंने htopइस अवधि के दौरान अपने सीपीयू उपयोग num_workersको 32 के साथ व्यवस्थित किया, और पहले युग के दौरान, उपयोग वास्तव में कम है; केवल 32 में से 1-2 कोर काम कर रहे हैं, अन्य काल के दौरान ~ सभी कोर काम कर रहे हैं।

जवाब

10 PoeDator Sep 04 2020 at 01:51

स्लावका,

मैंने पूरे GLR2020 डेटासेट को डाउनलोड नहीं किया था, लेकिन मैं छवि डेटासेट पर इस आशय का निरीक्षण करने में सक्षम था कि मेरे पास स्थानीय स्तर पर (लगभग 400x400 आकार के 80000 jpg चित्र) थे।

प्रदर्शन के अंतर के कारणों को जानने के लिए मैंने निम्नलिखित प्रयास किए:

  1. केवल आकार बदलने के लिए वृद्धि को कम करना
  2. परीक्षण सिर्फ ImgDataset.__getitem__()समारोह
  3. ImgDataset.__getitem__() वृद्धि के बिना
  4. बस कच्चे jpg छवि लोड हो रहा है और यह भी रूपांतरण के बिना डेटासेट से गुजर रहा है।

यह पता चला है कि अंतर छवि लोडिंग समय से आता है। पायथन (या ओएस ही) कुछ प्रकार के कैशिंग को लागू करता है जो निम्न परीक्षण में कई बार छवि को लोड करते समय देखा जाता है।

for i in range(5):    
    t0 = time.time()
    data = cv2.imread(filename)
    print (time.time() - t0)
    
0.03395271301269531
0.0010004043579101562
0.0010004043579101562
0.0010008811950683594
0.001001119613647461

जब फ़ाइल से चर में सिर्फ पढ़ने के लिए ही देखा जाता है

for i in range(5):    
    t0 = time.time()
    with open(filename, mode='rb') as file: 
        data = file.read()
    print (time.time() - t0)

0.036234378814697266
0.0028831958770751953
0.0020024776458740234
0.0031833648681640625
0.0028734207153320312

लोडिंग गति को कम करने का एक तरीका यह है कि डेटा को बहुत तेजी से स्थानीय एसएसडी पर रखा जाए। यदि आकार की अनुमति देता है, तो डेटासेट के भाग को रैम में लोड करने और वहां से खिलाने के लिए कस्टम डटलोडर लिखने की कोशिश करें ...

BTW मेरे निष्कर्षों के आधार पर यह प्रभाव किसी भी डेटासेट के साथ प्रतिलिपि प्रस्तुत करने योग्य होना चाहिए - यह देखें कि क्या आपने विभिन्न ड्राइव या कुछ कैशिंग का उपयोग किया है।

2 Multihunter Sep 10 2020 at 12:26

ऐसा प्रतीत होता है कि ओएस डेटासेट तक आईओ पहुंच को कैशिंग कर रहा है। यह जाँचने के लिए कि क्या यह निश्चित रूप से समस्या है, sync; echo 3 > /proc/sys/vm/drop_cachesपहले युग के बाद (उबंटू पर) चलाने का प्रयास करें । यदि आप ऐसा करते समय दूसरा युग समान रूप से धीमा है, तो यह कैशिंग है जो बाद के रीड्स को इतना तेज बना रहा है।

यदि आप एक HDD का उपयोग कर रहे हैं, तो आप डिस्क पर अपनी सभी छोटी छवि फ़ाइलों के सह-पता लगाकर अपने पहले युग के लिए महत्वपूर्ण गति सुधार प्राप्त कर सकते हैं।

आप अपने संपूर्ण डेटासेट को एकल फ़ाइल में संपीड़ित करने के लिए स्क्वाशएफ (यह उबंटू के साथ पहले से इंस्टॉल आता है) का उपयोग कर सकते हैं, फिर उस फाइल को एक डायरेक्टरी के रूप में माउंट करें और इसे उसी तरह एक्सेस करें जैसे आप पहले थे (अब केवल डिस्क पर सह-स्थित हैं)। घुड़सवार निर्देशिका केवल-पढ़ने के लिए है।

जैसे

mksquashfs /path/to/data data.sqsh
mount data.sqsh /path/to/data_sqsh -t squashfs -o loop

तब आप /path/to/data_sqshठीक उसी तरह से उपयोग कर सकते हैं जिस तरह से आपने उपयोग किया था /path/to/data। कंप्यूटर को पुनरारंभ करने पर आपको इसे फिर से माउंट करना होगा

देख: https://tldp.org/HOWTO/SquashFS-HOWTO/creatingandusing.html