使用OSS加速器提升模型訓練速度
使用OSS加速器可以顯著提升資料集載入速度,從而提升整體的模型訓練速度。本文基於大量效能測試對比了使用和未使用OSS加速器的加速效果,說明在GPU利用率尚未達到瓶頸的情況下,資料載入效率至關重要。此外,本文以預訓練模型ResNet-18在Imagenet ILSVRC資料集上進行微調的訓練任務為例,指導您如何在GPU雲端服務器中使用OSS加速器來提升模型訓練速度。
加速效果
對比標準OSS Bucket,OSS加速器展現出了顯著的效能優勢。憑藉其低延遲特性,OSS加速器在使用較少的worker數量時便能實現更高的輸送量表現。在多組實驗中,OSS加速器提升訓練效率40%~400%,大幅降低了計算資源的消耗與使用成本,為使用者提供了更高效的解決方案。
方案概覽
要實現以上加速效果只需三步:
-
建立GPU雲端服務器:建立一個適合模型訓練工作需求的GPU雲端服務器。
-
建立OSS Bucket並開通OSS加速器:建立一個OSS Bucket儲存空間並開通OSS加速器,同時擷取Bucket內網網域名稱以及OSS加速器網域名稱用於後續訓練任務。
-
訓練模型:在完成上述準備工作後,先對未經處理資料集進行預先處理,再將其上傳至OSS。隨後,在訓練過程中使用OSS加速器把資料集載入到本地,以此開展模型的訓練工作。
操作步驟
步驟一:建立GPU雲端服務器
以下步驟旨在建立並串連一個適用於模型訓練任務的GPU雲端服務器執行個體。該執行個體的規格為ecs.gn6i-c4g1.xlarge,作業系統為Ubuntu 22.04、CUDA版本為12.4.1。需注意,自訂執行個體配置時,CUDA版本請選擇最新版本。
1. 建立GPU雲端服務器
-
前往執行個體建立頁。
-
選擇自訂購買頁簽。
-
按需選擇付費類型、地區、網路及可用性區域、執行個體規格、鏡像等配置。完成建立。有關各配置項詳細說明,請參見配置項說明。
重要OSS加速器功能目前在華東1(杭州)、華東2(上海)、華北2(北京)、華北6(烏蘭察布)、華南1(深圳)以及新加坡地區開放公測。請確保您所建立的GPU雲端服務器位於上述地區之一。本文將以華東1(杭州)地區為例進行說明。
-
本次實踐ECS執行個體所採用規格為ecs.gn6i-c4g1.xlarge,僅供參考。
在執行個體規格選擇頁面,單擊全部規格標籤頁,在搜尋方塊中輸入規格名稱,選中GPU 計算型 gn6i,該規格配置為 4 vCPU、15 GiB 記憶體、1 * NVIDIA T4(16 GB 顯存)。
-
選擇作業系統鏡像以Ubuntu 22.04版本為例,並勾選安裝 GPU 驅動選擇CUDA版本為CUDA 版本 12.4.1,屆時伺服器啟動時會自動安裝CUDA環境,無需額外手動設定。
同時 Driver 版本選擇 550.90.07,CUDNN 版本選擇 9.2.0.82。
-
2. 串連GPU雲端服務器
-
在Elastic Compute Service控制台的執行個體列表頁面,根據地區、執行個體ID找到建立好的ECS執行個體,單擊操作列下的遠端連線。
-
在遠程連接對話方塊中,單擊通過Workbench遠端連線對應的立即登錄。
-
在登入執行個體對話方塊中,選擇認證方式為您建立GPU雲端服務執行個體時所選擇的登入憑證方式,例如SSH密鑰認證,填寫使用者名稱,輸入或上傳建立金鑰組時下載的私密金鑰檔案,單擊登入,即可登入ECS執行個體。
說明私密金鑰檔案在建立金鑰組時自動下載到本地,請您關注瀏覽器的下載記錄,尋找
.pem格式的私密金鑰檔案。 -
顯示如下頁面後,說明您已成功登入ECS執行個體且CUDA驅動已開始自動安裝,只需等待安裝完成即可。
Welcome to Alibaba Cloud Elastic Compute Service ! Last login: Fri Dec 13 14:15:04 2024 from 100.104.86.0 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 20 100 20 0 0 645 0 --:--:-- --:--:-- --:--:-- 645 CHECKING AUTO INSTALL, DRIVER VERSION=550.90.07 CUDA_VERSION=12.4.1 CUDNN VERSION=9.2.0.82 , INSTALL RDMA=FALSE, INSTALL eRDMA=FALSE, PLEASE WAIT ...... The script automatically downloads and installs a NVIDIA GPU driver and CUDA, CUDNN library. if you choose install RDMA or ERDMA, RDMA or ERDMA software will install. if you choose install perseus, perseus environment will install as well. 1. The installation takes 15 to 20 minutes, depending on the intranet bandwidth and the quantity of vCPU cores of the instance. Please do not operate the GPU or install any GPU-related software until the GPU driver is installed successfully. 2. After the GPU is installed successfully, the instance will restarts automatically. CUDA-12.4.1 downloading, it takes 3 minutes or more. Remaining installation time 14 - 19 minutes!
步驟二:建立OSS Bucket並開通OSS加速器
以下步驟旨在與目標GPU雲端服務器同一地區下,建立一個用於儲存資料集的Bucket並開啟該Bucket的OSS加速器空間,以提高資料集的訪問速度。需注意,雲端服務器和Bucket處於同一地區且通過內網網域名稱訪問不會產生任何流量費用。
-
建立Bucket並擷取內網網域名稱
重要OSS加速器功能目前在華東1(杭州)、華東2(上海)、華北2(北京)、華北6(烏蘭察布)、華南1(深圳)以及新加坡地區開放公測。請確保您建立的Bucket位於上述地區之一,並且與目標GPU雲端服務器處於同一地區。本文將以華東1(杭州)地區為例進行說明。
-
進入Object Storage Service控制台的Bucket列表頁面,單擊建立 Bucket。
-
在建立 Bucket面板,依據面板所給出的提示資訊來完成Bucket的建立工作。
-
在目標Bucket概覽頁面,訪問連接埠地區,複製ECS 的 VPC 網絡訪問(內網)的Endpoint留作備用,以便在後續訓練時上傳資料集和checkpoint到目標Bucket。
-
-
開通OSS加速器並擷取加速器網域名稱
-
進入Object Storage Service控制台的Bucket列表頁面,選擇目標Bucket後在左側導覽列,選擇進入OSS 加速器頁面。
-
單擊建立OSS加速器,在建立OSS加速器面板設定加速器容量,本次實驗以配置500 GB為例。單擊下一步。
-
選擇指定路徑加速,並配置加速路徑為資料集所在目錄後單擊確定,然後根據頁面指引完成加速器的建立。
加速路徑填寫
dataset/,並勾選同步預熱。開啟同步預熱後,用戶端通過加速器網域名稱寫入的資料會同時寫入 OSS Bucket 和 OSS 加速器,再次讀取時可獲得更低延遲。 -
在OSS加速器介面複製加速器網域名稱留作備用,以便在後續訓練時用於從目標Bucket下載資料集。
-
步驟三:訓練模型
以下步驟旨在GPU雲端服務器上,完成模型訓練環境的配置、資料集的上傳,以及使用OSS加速器網域名稱來加速模型訓練。
-
完整代碼工程,請參見demo.tar.gz。
-
以下所有操作步驟均需要以root許可權執行,請在開始訓練前將系統切換至root使用者。
-
配置訓練環境
-
準備conda環境並配置依賴項。
-
執行以下命令,下載並安裝conda。
curl -L https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -o /tmp/miniconda.sh && bash /tmp/miniconda.sh -b -p /opt/conda/ && rm /tmp/miniconda.sh && /opt/conda/bin/conda clean -tipy && export PATH=/opt/conda/bin:$PATH && conda init bash && source ~/.bashrc && conda update conda -
執行
vim environment.yaml命令,建立並開啟名為environment.yaml的conda環境檔案,添加以下配置後儲存。name: py312 channels: - defaults - conda-forge - pytorch dependencies: - python=3.12 - pytorch>=2.5.0 - torchvision - torchaudio - transformers - torchdata - oss2 -
執行以下命令,基於conda環境檔案建立名為py312的conda環境。
conda env create -f environment.yaml -
執行
conda activate py312命令,啟用名為py312的conda環境。即已成功啟用。重要後續的操作步驟,請在已啟用的conda環境中繼續進行。
-
-
配置環境變數。
執行以下命令,配置上傳資料集時所需的訪問憑證。請注意,命令中的
<ACCESS_KEY_ID>、<ACCESS_KEY_SECRET>請分別替換為RAM使用者的AccessKey ID、AccessKeySecret。有關如何建立AccessKey ID和AccessKeySecret請參見建立AccessKey。export OSS_ACCESS_KEY_ID=<ACCESS_KEY_ID> export OSS_ACCESS_KEY_SECRET=<ACCESS_KEY_SECRET> -
配置OSS Connector。
-
執行以下命令,安裝OSS Connector。
pip install osstorchconnector -
執行以下命令,建立訪問憑證設定檔。
mkdir -p /root/.alibabacloud && touch /root/.alibabacloud/credentials -
執行
vim /root/.alibabacloud/credentials命令,開啟設定檔添加如下配置並儲存。有關OSS Connector更多配置,請參見配置OSS Connector for AI/ML。使用AccessKey ID和AccessKey Secret作為訪問憑證的配置樣本,樣本中的
<AccessKeyId>、<AccessKeySecret>請分別替換為RAM使用者的AccessKey ID、AccessKeySecret。如何建立AccessKey ID和AccessKeySecret請參見建立AccessKey。{ "AccessKeyId": "LTAI************************", "AccessKeySecret": "At32************************" } -
執行以下命令,設定credentials檔案唯讀許可權,以保障AK、SK密鑰安全。
chmod 400 /root/.alibabacloud/credentials -
執行以下命令,建立OSS Connector設定檔。
mkdir -p /etc/oss-connector/ && touch /etc/oss-connector/config.json -
執行
vim /etc/oss-connector/config.json命令,開啟設定檔添加如下配置並儲存。正常情況下使用此預設配置即可。{ "logLevel": 1, "logPath": "/var/log/oss-connector/connector.log", "auditPath": "/var/log/oss-connector/audit.log", "datasetConfig": { "prefetchConcurrency": 24, "prefetchWorker": 2 }, "checkpointConfig": { "prefetchConcurrency": 24, "prefetchWorker": 4, "uploadConcurrency": 64 } }
-
-
-
準備資料
-
上傳訓練資料集和驗證資料集到目標Bucket。
-
執行以下命令下載訓練資料集和驗證資料集至雲端服務器。需注意,此資料集並非真實實驗情境所採用資料集,僅作測試用途。
wget https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241216/jsnenr/n04487081.tar wget https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241218/dxrciv/n10148035.tar wget https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241216/senwji/val.tar -
執行以下命令解壓下載好的資料集,並在當前路徑下建立dataset目錄將資料集放入其中。
tar -zxvf n10148035.tar && tar -zxvf n04487081.tar && tar -zxvf val.tar mkdir dataset && mkdir ./dataset/train && mkdir ./dataset/val mv n04487081 ./dataset/train/ && mv n10148035 ./dataset/train/ && mv IL*.JPEG ./dataset/val/ -
執行
python3 upload_dataset.py命令運行此指令碼,將解壓好的資料集上傳至指定的Bucket中。# upload_dataset.py from torchvision import transforms from PIL import Image import oss2 import os from oss2.credentials import EnvironmentVariableCredentialsProvider # # 以杭州地區內網網域名稱為例 OSS_ENDPOINT = "oss-cn-hangzhou-internal.aliyuncs.com" #OSS內網訪問網域名稱 OSS_BUCKET_NAME = "<YourBucketName>" #目標Bucket名稱 BUCKET_REGION = "cn-hangzhou" #目標Bucket地區 # OSS_URI_BASE: 自訂OSS bucket中的儲存首碼 OSS_URI_BASE = "dataset/imagenet/ILSVRC/Data" def to_tensor(img_path): IMG_DIM_224 = 224 compose = transforms.Compose([ transforms.RandomResizedCrop(IMG_DIM_224), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) img = Image.open(img_path).convert('RGB') img_tensor = compose(img) numpy_data = img_tensor.numpy() binary_data = numpy_data.tobytes() return binary_data def list_dir(directory): for root, _, files in os.walk(directory): rel_root = os.path.relpath(root, start=directory) for file in files: rel_filepath = os.path.join(rel_root, file) if rel_root != '.' else file yield rel_filepath IMG_DIR_BASE = "./dataset" """ IMG_DIR_BASE是本地存放圖片的路徑,絕對路徑或相對路徑都可以 該路徑下結構應該和實際資料集結構一致,具體結構如下 {IMG_DIR_BASE}/ train/ n10148035/ n10148035_10034.JPEG n10148035_10217.JPEG ... n11879895/ n11879895_10016.JPEG n11879895_10019.JPEG ... ... val/ ILSVRC2012_val_00000001.JPEG ILSVRC2012_val_00000002.JPEG ... """ bucket_api = oss2.Bucket(oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider()), OSS_ENDPOINT, OSS_BUCKET_NAME, region=BUCKET_REGION) for phase in [ "val", "train"]: IMG_DIR = "%s/%s" % (IMG_DIR_BASE, phase) for _, img_relative_path in enumerate(list_dir(IMG_DIR)): img_bin_name = img_relative_path.replace(".JPEG", ".pt") object_key = "%s/%s/%s" % (OSS_URI_BASE, phase, img_bin_name) bucket_api.put_object(object_key, to_tensor("%s/%s" % (IMG_DIR,img_relative_path)))
-
-
下載映像資料集標籤檔案,用於構建資料集的分類映射關係。
wget https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241220/izpskr/imagenet_class_index.json wget https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241220/lfilrp/ILSVRC2012_val_labels.json
-
-
訓練流程
-
構建用於處理ImageNet資料集的工具模組。該模組主要通過OSS加速器網域名稱,從OSS加速器空間下載資料集並構建dataloader。
-
構建預訓練ResNet18模型初始化工具模組。
-
構建用於訓練ResNet模型的工具模組。該模組通過給定的模型(model)、資料載入器(dataloaders),以及訓練輪數(epoch_num)開展模型訓練工作。
-
構建用於整合模型訓練流程的主指令檔。該檔案整合以上多個工具模組開啟模型訓練。
-
執行
python3 main.py命令來開始模型訓練,如下所示,已成功啟動訓練流程。(py312) root@xxx :~# python3 main.py /opt/conda/envs/py312/lib/python3.12/site-packages/torchvision/models/_utils.py:208: UserWarning: The parameter 'pretrained' is deprecated since 0.13 and may be removed in the future, please use 'weights' instead. warnings.warn() /opt/conda/envs/py312/lib/python3.12/site-packages/torchvision/models/_utils.py:223: UserWarning: Arguments other than a weight enum or `None` for 'weights' are deprecated since 0.13 and may be removed in the future. The current behavior is equivalent to passing `weights=ResNet18_Weights.IMAGENET1K_V1`. You can also use `weights=ResNet18_Weights.DEFAULT` to get the most up-to-date weights. warnings.warn(msg) Downloading: "https://download.pytorch.org/models/resnet18-f37072fd.pth" to /root/.cache/torch/hub/checkpoints/resnet18-f37072fd.pth 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████| 44.7M/44.7M [00:10<00:00, 4.40MB/s] 2024/12/20 13:36:34.853415| INFO |th=00000000000000000|dataset.cpp:222|new_oss_dataset:new oss dataset, uuid: 92251a5f-7f00-45b5-aaba-b8894ab15b0d id: 0, total: 1, pid: 20655, endpoint: cn-hangzhou-internal.oss-data-acc.aliyuncs.com 2024/12/20 13:36:34.853437| INFO |th=00000000000000000|dataset.cpp:230|new_oss_dataset:[cred_path=/root/.alibabacloud/credentials][config_path=/etc/oss-connector/config.json] 2024/12/20 13:36:34.853518| INFO |th=00000000000000000|dataset.cpp:255|new_oss_dataset:set log level: 1 2024/12/20 13:36:34.853591| INFO |th=00000000000000000|dataset.cpp:262|new_oss_dataset:set log path: /var/log/oss-connector/connector_log_0 /root/oss_dataloader.py:51: UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at /home/conda/feedstock_root/build_artifacts/libtorch_1733624414920/work/torch/csrc/utils/tensor_numpy.cpp:206.) return torch.from_numpy(numpy_array_from_binary) /root/oss_dataloader.py:51: UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at /home/conda/feedstock_root/build_artifacts/libtorch_1733624414920/work/torch/csrc/utils/tensor_numpy.cpp:206.) return torch.from_numpy(numpy_array_from_binary) /root/oss_dataloader.py:51: UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at /home/conda/feedstock_root/build_artifacts/libtorch_1733624414920/work/torch/csrc/utils/tensor_numpy.cpp:206.) return torch.from_numpy(numpy_array_from_binary)
-
-
結果驗證
進入Bucket列表選擇目標Bucket,單擊後查看checkpoints目錄下的resnet18.pt檔案。訓練結束後checkpoint檔案已成功上傳至OSS。