在Pytorch中構建流數據集

2020-12-04 deephub

在處理監督機器學習任務時,最重要的東西是數據——而且是大量的數據。當面對少量數據時,特別是需要深度神經網絡的任務時,該怎麼辦?如何創建一個快速高效的數據管道來生成更多的數據,從而在不花費數百美元在昂貴的雲GPU單元上的情況下進行深度神經網絡的訓練?

這是我們在MAFAT雷達分類競賽中遇到的一些問題。我的隊友hezi hershkovitz為生成更多訓練數據而進行的增強,以及我們首次嘗試使用數據加載器在飛行中生成這些數據。

要解決的問題

我們在比賽中使用數據管道也遇到了一些問題,主要涉及速度和效率:

它沒有利用Numpy和Pandas在Python中提供的快速矢量化操作的優勢

每個批次所需的信息都首先編寫並存儲為字典,然後使用Python for循環在getitem方法中進行訪問,從而導致迭代和處理速度緩慢。

從音軌生成「移位的」片段會導致每次檢索新片段時都重新構建相同的音軌,這也會減緩管道的速度。

管道無法處理2D或3D輸入,因為我們同時使用了scalograms和spectrograms但是無法處理。

如果我們簡單地按照批處理的方式進行所有的移位和翻轉,那麼批處理中就會充斥著與其他示例過於相似的示例,從而使模型不能很好地泛化。

這些低效率的核心原因是,管道是以分段作為基本單元運行,而不是在音軌上運行。

數據格式概述

在製作我們的流數據之前,先再次介紹一下數據集,MAFAT數據由都卜勒雷達信號的固定長度段組成,表示為128x32 I / Q矩陣; 但是,在數據集中,有許多段屬於同一磁軌,即,雷達信號持續時間較長,一條磁軌中有1到43個段。

上面的圖像來自hezi hershkovitz 的文章,並顯示了一個完整的跟蹤訓練數據集時,結合所有的片段。紅色的矩形是包含在這條軌跡中的單獨的部分。白點是「都卜勒脈衝」,代表被跟蹤物體的質心。

藉助「都卜勒脈衝」白點,我們可以很容易地看到,航跡是由相鄰的段組成的,即段id 1942之後是1943,然後是1944,等等。

片段相鄰的情況下允許我們使用移位來創建「新的」樣本。

但是,由於每個音軌由不同數量的片段組成,因此從任何給定音軌生成的增補數目都會不同,這使我們無法使用常規的Pytorch Dataset 類。 這裡就需要依靠Pytorch中的IterableDataset 類從每個音軌生成數據流。

數據流管道設計

這三個對象的高級目標是創建一個_Segment對象流,它能夠足夠靈活地處理音軌和段,並且在代碼中提供一致的語義:

class _Segment(Dict, ABC):segment_id: Union[int, str] output_array: np.ndarray doppler_burst: np.ndarray target_type: np.ndarray segment_count: int

為此,我們創建了:

一個配置類,它將為一個特定的實驗保存所有必要的超參數和環境變量——這實際上只是一個具有預定義鍵的簡單字典。

一個DataDict類,它處理原始片段的加載,驗證每一條軌跡,創建子軌跡以防止數據洩漏,並將數據轉換為正確的格式,例如2D或3D,並為擴展做好準備

StreamingDataset類,是Pytorch IterableDataset的子類,處理模型的擴充和流段。

config = Config(file_path=PATH_DATA, num_tracks=3, valratio=6, get_shifts=True, output_data_type='spectrogram', get_horizontal_flip=True, get_vertical_flip=True, mother_wavelet='cgau1', wavelet_scale=3, batch_size=50, tracks_in_memory=25, include_doppler=True, shift_segment=2)dataset = DataDict(config=config)train_dataset = StreamingDataset(dataset.train_data, config, shuffle=True)train_loader = DataLoader(train_dataset,batch_size=config['batch_size'])

DataDict實現

在DataDict中將片段處理為音軌,然後再處理為片段,為加速代碼提供了很好的機會,特別是在數據驗證、重新分割和軌創建都可以向量化的情況下。

我們使用了Numpy和Pandas中的一堆技巧和簡潔的特性,大量使用了布爾矩陣來進行驗證,並將scalogram/spectrogram 圖轉換應用到音軌中連接的片段上。代碼太長,但你可以去最後的原始碼地址中查看一下DataDict createtrackobjects方法。

生成細分流

一旦將數據集轉換為軌跡,下一個問題就是以更快的方式進行拆分和移動。 在這裡,Numpy提供了執行快速的,基於矩陣的操作和從一條軌跡快速生成一組新的片段所需的所有工具。

def split_Nd_array(array: np.ndarray, nsplits: int) -> List[np.ndarray]:if array.ndim == 1: indices = range(0, len(array) - 31, nsplits) segments = [np.take(array, np.arange(i, i + 32), axis=0).copy() for i in indices] else: indices = range(0, array.shape[1] - 31, nsplits) segments = [np.take(array, np.arange(i, i + 32), axis=1).copy() for i in indices] return segmentsdef create_new_segments_from_splits(segment: _Segment, nsplits: int) -> List[_Segment]: new_segments = [] if segment['output_array'].shape[1] > 32: output_array = split_Nd_array(array=segment['output_array'], nsplits=nsplits) bursts = split_Nd_array(array=segment['doppler_burst'], nsplits=nsplits) new_segments.extend([_Segment(segment_id=f'{segment["segment_id"]}_{j}', output_array=array, doppler_burst=bursts[j], target_type=segment['target_type'], segment_count=1) for j, array in enumerate(output_array)]) else: new_segments.append(segment) return new_segments

Pytorch Iterable數據集

註:torch.utils.data.IterableDataset 是 PyTorch 1.2中新的數據集類

一旦音軌再次被分割成段,我們需要編寫一個函數,每次增加一個音軌,並將新生成的段發送到流中,從流中從多個音軌生成成批的段。最後一點對於確保每個批的數據分布合理是至關重要的。

生成流數據集正是IterableDataset類的工作。 它與Pytorch中的經典(Map)Dataset類的區別在於,對於IterableDataset,DataLoader調用next(iterable_Dataset),直到它構建了一個完整的批處理,而不是實現一個接收映射到數據集中某個項的索引的方法。

創建批次

在這個例子的基礎上,我們創建了一個實現,它的核心進程是「processtracksshuffle」,以確保DataLoader提供的每個批處理都包含來自多個音軌的段的良好混合。我們通過設置tracksinmemory超參數來實現這一點,該參數允許我們調整在生成新的流之前將處理多少條音軌並將其保存到工作內存中。

def segments_generator(self, segment_list: _Segment) -> None:""" Generates original and augmented segments from a track. """ if self.config.get('get_shifts'): segment_list = create_new_segments_from_splits(segment_list, nsplits=self.config['shift_segment']) else: segment_list = create_new_segments_from_splits(segment_list, nsplits=32) if self.config.get('get_vertical_flip'): flips = create_flipped_segments(segment_list, flip_type='vertical') segment_list.extend(flips) if self.config.get('get_horizontal_flip'): flips = create_flipped_segments(segment_list, flip_type='horizontal') segment_list.extend(flips) for segment in segment_list: if self.config['output_data_type'] == 'scalogram': segment.assert_valid_scalogram() else: segment.assert_valid_spectrogram() self.segment_blocks.extend(segment_list) random.shuffle(self.segment_blocks) def process_tracks_shuffle(self): for i, track in enumerate(self.data): self.segments_generator(track) if i % self.config.get('tracks_in_memory', 100) == self.config.get('tracks_in_memory', 100): segment_blocks = self.segment_blocks self.segment_blocks = [] random.shuffle(segment_blocks) yield segment_blocks segment_blocks = self.segment_blocks self.segment_blocks = [] random.shuffle(segment_blocks) yield segment_blocks def shuffle_stream(self): return chain(self.process_tracks_shuffle())# def linear_stream(self):# return chain(self.segments_generator(track) for track in self.data) def __iter__(self): for segments in chain(self.shuffle_stream()): yield from segments

並行化

在進一步加速數據處理方面,我們沒有利用通過在多個GPU並行化的處理來生成多個流。不過需要記住的一件事是,IterableDataset的並行化並不像標準Dataset類那樣簡單,因為僅僅用IterableDataset添加workers會導致每個worker獲得數據的底層完整副本。

結論

在Pytorch中學習使用流數據是一次很好的學習經歷,也是一次很好的編程挑戰。這裡通過改變我們對pytorch傳統的dataset的組織的概念的理解,開啟一種更有效地處理數據的方式。

眾所周知,我們80%的時間都花在了數據清理和管道建立上。然而,我們不應將數據處理視為必須處理而又經常被忽略的工作,而去深入研究20%建模的「樂趣」。我們而應將管道和處理視為一個同樣具有樂趣和關鍵性的工作。因為這是必要的,因為管道速度越快,運行的實驗就越多,數據處理的越好,得到的結果就會越好。

作者:Adam Cohn

deephub翻譯組

代碼地址:github/ShaulSolomon/sota-mafat-radar/

相關焦點

  • 新版PyTorch 1.2 已發布:功能更多、兼容更全、操作更快!
    TorchScript 改進在 PyTorch 1.0 中加入 TorchScript 之後,它為 PyTorch 的 Eager 類模型提供了構建途徑。TorchScript 編譯器將 PyTorch 模型轉換為靜態類型的圖形表示,為 Python 不可用受限環境中的優化和執行提供了機會。
  • 雲計算學習:用PyTorch實現一個簡單的分類器
    主要流程分為以下三個部分:1,自定義生成一個訓練集,具體為在二維平面上的一些點,分為兩類;2,構建一個淺層神經網絡,實現對特徵的擬合,主要是明白在 pytorch 中網絡結構如何搭建;3,完成訓練和測試部分的工作,熟悉 pytorch 如何對網絡進行訓練和測試。1.
  • 獨家 | 教你使用torchlayers 來構建PyTorch 模型(附連結)
    torchlayers 旨在做Keras為TensorFlow所做的事情,它提供了更高級的模型構建的API和一些方便的默認值以及附加功能,這些功能對構建PyTorch神經網絡很有用。通過在線搜索的趨勢判斷(連結:https://trends.google.com/trends/explore?
  • 《PyTorch中文手冊》來了
    PyTorch 有許多優勢,如採用 Python 語言、動態圖機制、網絡構建靈活以及擁有強大的社群等。由於其靈活、動態的編程環境和用戶友好的界面,PyTorch 是快速實驗的理想選擇。API 的改動不是很大,本教程已經通過測試,保證能夠在 1.0 中正常運行。 不過目前看影響不大,因為畢竟內容還不多。 v0.4.1 已經新建了分支作為存檔,並且該不會再進行更新了。
  • PyTorch框架歷史和特性更迭與安裝過程
    另外,在這個版本中,也增加了對Windows作業系統的支持,實現了張量(Tensor)和變量(Variable)的合併,而在之前的版本中,這兩個概念是相互獨立的,變量是可以構建計算圖且能夠進行自動求導的張量。在PyTorch 0.4.0中,通過指定張量支持導數的選項,就不再需要用到變量。因此,這兩個概念合併為張量。到了PyTorch 1.0,深度學習框架本身又有了幾個重大的變化。
  • 語音識別開源工具PyTorch-Kaldi:兼顧Kaldi效率與PyTorch靈活性
    包括它們的存儲路徑、窗口的特徵以及數據集被分割成塊的數量。PyTorch-Kaldi 的一個特點就是可以管理多個語音特徵流,用戶在實際開發的過程中可以定義使用多個特徵參數組合的模型。用於訓練聲學模型的主要特徵來自於語音特徵和上下文無關的音素序列,這是通過 Kaldi 的音素決策樹生成的。
  • 60分鐘入門深度學習工具PyTorch
    print(x)tensor([[0, 0, 0],[0, 0, 0],[0, 0, 0],[0, 0, 0],[0, 0, 0]])從數據中直接構建一個張量你現在可能在思考:數據哪裡來呢?關於數據通常,當你處理圖像,文本,音頻和視頻數據時,你可以使用標準的Python包來加載數據到一個numpy數組中.然後把這個數組轉換成torch.*Tensor。
  • PyTorch最佳實踐,教你寫出一手風格優美的代碼
    最後,我們分享了一些使用其它框架的見解和經驗,這些框架通常幫助我們改進工作流。如果你想在更大的數據集上訓練該模型,就應該使用 Python 腳本,因為在更大的數據集上,復現性更加重要。 我們推薦你採取下面的工作流程: 在開始的階段,使用 Jupyter Notebook 對數據和模型進行探索 在 notebook 的單元中構建你的類/方法 將代碼移植到 Python 腳本中
  • 清華構建新一代數據集NICO,定義圖像分類新標準
    但是目前絕大部分的數據集都是基於獨立同分布的實驗場景設定,並沒有考慮到數據本身的特性,也沒有更多因果關係可言,這對於模型的泛化幫助甚微,也很難看到新一代數據集的萌芽。針對這些問題,近日,清華大學計算機系長聘副教授崔鵬團隊構建了一個新型的具有跨數據集泛化性指標的數據集NICO,該數據集的發布旨在引起大家對新型數據集的更多關注,並促進對人工智慧內在學習機制的研究。
  • PyTorch實現,GitHub4000星:微軟開源的CV庫
    這需要使用者完成一些任務,如基於自己的數據微調模型的簡單任務,或者難例挖掘甚至模型部署等更複雜的任務。1. 圖像分類任務該目錄提供了構建圖像分類系統的示例和最佳實踐,旨在讓用戶能夠在自己的數據集上輕鬆快速地訓練高準確率分類器。這裡提供的示例 notebook 具備預置的默認參數,可以很好地處理多個數據集。該目錄還提供了有關常見缺陷和最佳實踐的大量文檔。
  • PyTorch中使用DistributedDataParallel進行多GPU分布式模型訓練
    該算法提供了一種優雅的方式來同步一組進程之間的一組變量(在本例中為張量)的狀態。 向量在直接的worker到worker連接的序列中直接傳遞。 這消除了worker與參數伺服器之間的連接所造成的網絡瓶頸,從而大大提高了性能。在該方案中,梯度更新計算如下:每個worker維護它自己的模型權重副本和它自己的數據集副本。
  • Deep CARs:使用Pytorch學習框架實現遷移學習
    例如,如果想要構建一個網絡識別鳥類,與其從頭開始編寫一個複雜的模型,不如用一個現成的的模型,用於針對相同或相似任務的模型(在該實例中,可以使用一個識別其他動物的網絡系統來完成任務)。遷移學習法的優勢在於:學習過程更快、信息更準確,所需的訓練數據也更少。在遷移學習中,現有的這個模型稱為預訓練模型。大多數用於遷移學習的預訓練模型都是基於大型卷積神經網絡之上的。
  • 利用Pytorch-BigGraph 從知識圖中提取知識詳解
    在類似的上下文中,使用的單詞通常是相似的。在本例中,上下文由附近的單詞定義。單詞序列的圖表示法我們看到的是,考慮到這些原則,我們可以通過在一個預先定義的窗口(通常是 5 個詞)內簡單地將每個詞與其相鄰詞連接起來,從文本中構建一個圖。
  • 應用手機GPS數據預測交通流速度
    本文採用基於主成分分析的多元線性回歸的方法構建預測模型,利用GPS定位數據對短時交通流速度進行預測。實驗結果表明,基於手機GPS數據所構建的回歸模型能夠對交通流速度進行有效的預測。便捷的手機網絡可以解決交通預測過程中遇到的覆蓋區域限制和實時性差等問題,與此同時,GPS定位準確性高,可以作為目標點的交通探測器使用[1],收集定點的實時數據用於交通流速度預測。分析實時交通情況,提供相應的信息服務,對於緩解交通堵塞變得尤為重要。傳統交通流速靠地感線圈數據進行估算和預測,而地感線圈覆蓋範圍小、造價高且普及率低下。
  • 使用PyTorch 檢測眼部疾病
    在這篇文章中,我將向你展示如何構建一個簡單的神經網絡,用PyTorch從視網膜光學相干斷層掃描圖像中檢測不同的眼部疾病。 數據集 OCT 是一種成像技術,用於捕捉活體患者視網膜的高解析度橫截面。每年大約要進行3000萬次 OCT 掃描,這些圖像的分析和解釋需要大量的時間。
  • PyTorch 0.2發布:更多NumPy特性,高階梯度、分布式訓練等
    PyTorch的GitHub新版發布說明中介紹了0.2版的以下新特性:NumPy風格的Tensor BroadcastingBroadcasting是NumPy在算數運算中處理不同形狀數組的一種方式,在特定條件下,比較小的數組會通過比較大的數組進行「廣播」,來獲得相應的形狀。
  • PyTorch更新!谷歌幫助開發,正式支持TensorBoard | 5大開源項目
    分布式訓練:改進了常見模型(如CNN)的性能,增加了對多設備模塊的支持,包括在仍使用分布式數據並行(DDP)的情況下跨GPU分割模型的能力,以及對並非所有參數都用於每次迭代的模塊的支持(如控制流,如自適應SoftMax等)。
  • 還不會使用PyTorch框架進行深度學習的小夥伴,看過來
    這個張量的梯度將在「.grad」屬性中積累。如果你想要從計算歷史中分離出一個張量,請調用「.detach()」函數。這也可以防止將來對張量的計算被跟蹤。另一種防止歷史跟蹤的方法是用「torch.no_grad()」方法封裝代碼。你可以將張量「Tensor」和函數「Function」類相連接,構建一個編碼了完整計算歷史的無環圖。
  • PyTorch 1.7發布,支持CUDA 11、Windows分布式訓練
    PyTorch 1.7 版本包含很多新的 API,如支持 NumPy 兼容的 FFT 操作、性能分析工具,以及對基於分布式數據並行(DDP)和基於遠程過程調用(RPC)的分布式訓練的重要更新。此外,一些特性也更新為穩定版,包括自定義 C++ 類、內存分析器、通過自定義類張量對象進行擴展、RPC 中的用戶異步函數,以及 torch.distributed 中的許多其他特性(如 Per-RPC 超時、DDP dynamic bucketing、RRef helper)。
  • 如何在PyTorch和TensorFlow中訓練圖像分類模型
    在本文中,我們將了解如何在PyTorch和TensorFlow中建立基本的圖像分類模型。我們將從PyTorch和TensorFlow的簡要概述開始。然後,我們將使用MNIST手寫數字分類數據集,並在PyTorch和TensorFlow中使用CNN(卷積神經網絡)建立圖像分類模型。這將是你的起點,然後你可以選擇自己喜歡的任何框架,也可以開始構建其他計算機視覺模型。