[ 今天最開心的事情! ]
PyTorch的stable版本更新為1.0之后,原本3D模型無腦out of memory、3D模型torch.backends.cudnn.benchmark必須False的問題總算解決了!!!*★,°*:.☆( ̄▽ ̄)/$:*.°★* 。
在訓練ResNet50 I3D時發現,benchmark在3D模型訓練時仍然要為False!
[ PyTorch基礎API ]
PyTorch中基礎API包括:
Network architecture: torch.nn.Module
Data: torch.utils.data.Dataset (need to implement __init__, __getitem__, __len__), torch.utils.data.DataLoader (need to give Dataset, batch_size, shuffle and so on)
Parallelism: torch.nn.DataParallel, Tensor.to(), Tensor.cuda()
[ Python延遲實例化 ]
Python 的類名可以作為參數直接傳遞,而不需要實例化,在使用該類對象之前對其進行實例化即可。
* use [ isinstance( object, classinfo) ] can detect whether the object is the instance of the classinfo.
[ Parameter and Hyperparameter ]
Parameter: the parameter inside the model, such as Weight, Bias .etc.
Hyperparameter: the parameter used to describe the model, is the configuration of network, such as the size of the input or output.
[ single-asterisk form of *args ]
def multiply(*args): z = 1 for num in args: z *= num print(z)
Convey an argument list to the funcion.
[ The launch command of the first model ]
CUDA_VISIBLE_DEVICES=2,3 \
python main.py \
ucf101 \
data/ucf101/ucf101_train_split1_list.txt \
data/ucf101/ucf101_val_split1_list.txt \
--arch resnet50_3d \
--dro 0.2 \
--mode 3D \
--t_length 16 \
--t_stride 4 \
--pretrained \
--epochs 95 \
--batch-size 64 \
--lr 0.001 \
--lr_steps 40 80 90 \
--workers 16 \
--image_tmpl img_{:05d}.jpg \
* Description: 1) 使用兩塊Titan x,因此batch-size改為16。如果報錯out of memory,則batch-size要調小。 2)workers是數據加載的線程數,根據log中batch的數值,可以判斷workers是否合理,合理的情況是內存不超並且batch=0,即批加載時間為0。
[ in_channels & out_channels ]
also called inplanes & outplanes
輸入通道數與卷積核的卷積通道數一致,3通道2D圖像IMG(3*W*H),2D卷積核(3*w*h),每一個卷積核每一次對IMG的一個3*w*h局部卷積產生一個點,該卷積核卷積完成后產生一個feature map。一個卷積核生成一張feature map,N個卷積核產生N個feature map,構成了N通道的輸出。
(the draft made by me, shows the process of the conv)
[ Weight sharing ]
also called parameter sharing
It relies on one reasonable assumption: if a patch feature is useful to compute at some spatial position, then it should also be useful to compute at other positions. (refered Wikipedia)
The weights of a filter( also called kernel) should be fixed, which means the filter is shared by a certain input feature map. Actually it is obvious and natural to do this. But in contrast, we can imagine that what if we change the weights of the filter once it moves. Apparently the network will have more parameters to optimize. It is not a good news for GPUs. So the parameter sharing fashion is GPU-friendly.
[ ReLU ]
Rectified Linear Unit
目前,只知道NN的非線性能力來源於此。
[ Batch Normalization ]
The target of normalization is to set the input of norm layer be a Standard Norm Distribution.
BN是以Batch為單位進行操作的,
[ class torch.utils.data.Dataset ]
An abstract class representing a Dataset.
All other datasets should subclass it. All subclasses should override __len__
, that provides the size of the dataset, and __getitem__
, supporting integer indexing in range from 0 to len(self) exclusive.
[ torch.backends.cudnn.benchmark ]
大部分情況下,設置這個 flag 可以讓內置的 cuDNN 的 auto-tuner 自動尋找最適合當前配置的高效算法,來達到優化運行效率的問題。
一般來講,應該遵循以下准則:
(1) 如果網絡的輸入數據維度或類型上變化不大,設置 torch.backends.cudnn.benchmark = true 可以增加運行效率;
(2) 如果網絡的輸入數據在每次 iteration 都變化的話,會導致 cuDNN 每次都會去尋找一遍最優配置,這樣反而會降低運行效率。
*開啟這個flag,可能會造成CUDNN_STATUS_NOT_INITIALIZED報錯。
[ enumerate and __getitem__ ]
An instance of the class implemented the __getitem__ method can be the parameter of the enumerate().
To find more info about Interator and Generator: http://www.bubuko.com/infodetail-2330183.html
[ 一次訓練的時間感受 ]
num_traindata=9537, num_valdata=3783, architecture=resnet50_3d, GPU=Nvidia Titan x, num_GPUs=2, num_workers=16
consumed time = 24 hours
[ RuntimeError: CuDNN error: CUDNN_STATUS_MAPPING_ERROR ]
Traceback (most recent call last):
Error information is as below:
$ ...
$ training, momentum, eps, torch.backends.cudnn.enabled
$ RuntimeError: CuDNN error: CUDNN_STATUS_MAPPING_ERROR
出現這種問題,我也很無奈啊....不過好在我對照另一份代碼發現了一點問題,那就是torch.nn.Module.cuda()調用之前,要過一次torch.nn.DataParallel(),至於原因目前還不知道。
有些回答說這種情況和CUDA版本過舊,可以作為一種參考思路。
[ Connection error: connection reset by peer ]
系統的並行能力已經超載,連接被斷開。查看登錄用戶情況,然后關閉部分已經不用的登錄賬戶創建的進程。
[ Caffe中BN+Scale 與 PyTorch中BN ]
在Caffe中,Batch Normalization是通過BN + Scale兩個層實現的,BN層是調整數據的均值和標准差,Scale是對調整后的數據進行放縮和偏移(Y=wX+b)。
在PyTorch中,兩個步驟合二為一,只需要一個BN層即可。
另外,PyTorch中的momentum是真正的momentum,而Caffe中的是1-momentum。
[ 叉乘與點乘 ]
Cross product: torch.matmul(Tensor_A, Tensor_B), or torch.mm(Tensor_A, Tensor_B)
Dot product: torch.mul(Tensor_A, Tensor_B), or Tensor_A * Tensor_B
[ Tensor維度重整的空間連續性要求 ]
在PT中,使用Tensor.view()或者torch.reshape()操作對Tensor進行重整時,要求該Tensor對象所處的內存或顯存空間具有連續性,因此若在執行view或reshape操作前對Tensor有permute這種會改變其內存或顯存地址的操作,需要使用一次Tensor.contiguous()操作,使其空間連續即可。
[ allow_unreachable=True & device-side assert triggered ]
Model中#classes值 或 label范圍不正確,如果是400類,則label的范圍是 [0, 399]。如果是0-1分類,則num_class應該為2,而不是1;label范圍為{ 0, 1 }。
[ 使用FC (torch.nn.Linear) 后出現size mismatch的問題 ]
在使用Linear之前,需要使用view或者reshape整理維度:
out = out.view(out.shape[0], -1)
[ 測試時網絡infer出現不穩定周期性卡頓 ]
一種可能的原因是DataLoader在加載數據時,出現了“供不應求”的情況,也就是參與數據傳輸的線程數不足,不能及時供應數據。因為在訓練的時候,網絡需要forward和backward兩個過程,少量的線程數可以來得及傳輸數據到顯存,但是在測試時只有forward一個過程,這時若使用同樣的線程數,就會來不及傳輸數據了。
在網上看了一下,基本上建議線程數在GPU數量的2倍~4倍。根據個人經驗,可能在訓練的時候可以考慮1倍~2倍,測試的時候2倍~4倍。
[ tensor類型轉換 ]
①使用Tensor的類型成員函數: .long() .float() .int() .double()
②使用Tensor的.type()成員函數:
import torch tensor = torch.randn(3, 5) print(tensor) int_tensor = tensor.type(torch.IntTensor) print(int_tensor)
③使用Tensor的.type_as()成員函數:
import torch tensor_1 = torch.FloatTensor(5) tensor_2 = torch.IntTensor([10, 20]) tensor_1 = tensor_1.type_as(tensor_2)
[ PyTorch中feature map數據類型 ]
通過debug模式發現:dataset類中讀入圖像使用PIL.image.open(),讀入的數據格式為PIL的圖像格式(RGB),在經過transform中的ToTorchFormatTensor()之后,數據變成了Tensor,此時的數據格式為torch.float32,即32位浮點(4 Byte)。
根據 https://blog.csdn.net/gaishi_hero/article/details/81153361
經過ToTorchFormatTensor()之后,不僅僅是數據類型的變化,數據維度也會有HWC變為CHW。
[ BN在單GPU上實現 ]
[ 玄學報錯 ]
回了一趟本科學校,回來再調代碼出現了一些報錯,讓我莫名其妙,故稱其為“玄學報錯”,用了一晚上+一上午的時間解決了,做下記錄。
1. 報 THCudaCheck FAIL file=/opt/conda/conda-bld/pytorch_1535491974311/work/aten/src/THC/THCCachingHostAllocator.cpp line=265 error=77 : an illegal memory access was encountered
同時還有一大串frame #0: <unknown function>...
可能的原因是在3D模式下開啟了B*M*,會出現這種錯誤。
2. 從師兄那了解到,在測試時給了過多的workers也有可能導致 an illegal memory access was encountered 這種報錯,減少workers和batchsize可以解決。
3. 使用PyCharm對測試程序進行debug時,無法正常啟動運行,並且報錯:RuntimeError: all tensors must be on devices[0]. 可是在服務器上直接運行時沒有問題。
net = torch.nn.DataParallel(net, device_ids=[0, 1, 2, 3, 4, 5, 6, 7]).cuda()
在做並行化的時候,需要指定GPU編號。
4. 加載訓練好的模型時報錯:
...python3.6/site-packages/torch/nn/modules/module.py", line 769, in load_state_dict
self.__class__.__name__, "\n\t".join(error_msgs)))
RuntimeError: Error(s) in loading state_dict for DataParallel:
Missing key(s) in state_dict: "module.base_model.operation1.fc_t1.weight" ...
Unexpected key(s) in state_dict: "module.base_model.stc1.fc_t1.weight" ...
是由於名稱不對應,所以加載失敗。state_dict是一個OrderedDict,使用items()方法獲取其鍵值對,使用str.replace()修改鍵即可。
從同學那了解到,'module.'是並行訓練存儲模型參數時才有的前綴,如果先加載模型,再並行分布,則需要去掉前綴,操作方法與上類似。
5. RuntimeError: DataLoader worker (pid 5657) is killed by signal: Killed. Details are lost due to multiprocessing. Rerunning with num_workers=0 may give better error trace.
使用PyCharm在server上debug時出現這個報錯,度娘查了一圈是說debug導致server上某塊空間不夠了,無法multiprocess,因此把worker調成0就可以正常debug了。