想记录一下一个 bug 改了一上午改到最后发现并没有 bug 的 bug。
总结:
- 因为下午要跑很久,为了省 GPU 算力,我想上午先用 CPU 把数据处理部分跑出来(感觉数据处理部分不像网络训练那样涉及太多计算,所以感觉用 CPU 就可以了)。
- 结果因为没用 GPU 导致计算量太大程序阻塞没有输出,用了一上午改了一个不是 bug 的 bug。
故事拉开序幕
当我运行:
# generate train data
!python3.7 generate_feature.py -m train
# generate validation data
!python3.7 generate_feature.py -m valid
输出是这样的:
!!!! mode_type: train !!!!
idx_path:./index/fold0_train_idx.npy
fold_name: _fold0
!!!! mode_type: valid !!!!
idx_path:./index/fold0_valid_idx.npy
fold_name: _fold0
=========>>mode:valid JA finished!!! <<=========
=========>>mode:valid J finished!!! <<=========
=========>>mode:valid BA finished!!! <<=========
=========>>mode:valid B finished!!! <<=========
=========>>mode:valid JB finished!!! <<=========
=========>>mode:valid JMj finished!!! <<=========
=========>>mode:valid Mb finished!!! <<=========
- 可以看到输出,只生成了 valid 的数据 JA,J,BA 等,没有生成 train 的数据?
- 这两个 mode (train or valid)都是调用下面的这个 gen_train_valid 函数,是同一个函数呀,这是为什么呢?
def gen_train_valid(mode):
data_path = '/home/aistudio/data/data118104/train_data.npy'
labels_path = '/home/aistudio/data/data118104/train_label.npy'
data = np.load(data_path)[:, 0:2, :, :, :].astype('float32')
labels = np.load(labels_path)
for idx in range(5):
idx_path = './index/fold{}_{}_idx.npy'.format(idx, mode)
print('idx_path:{}'.format(idx_path)) # 打印路径看看 mode 对不对
fold_idx = np.load(idx_path)
data_fold = data[fold_idx]
labels_fold = labels[fold_idx]
fold_name = '_fold{}'.format(idx)
print('fold_name: {}'.format(fold_name)) # 打印 fold_name
JA = get_JA(data_fold, labels_fold, fold_name, mode)
get_J(JA, fold_name, mode)
get_BA(JA, fold_name, mode)
B = get_B(JA, fold_name, mode)
get_JB(JA, B, fold_name, mode)
get_JMj(JA, fold_name, mode)
get_Mb(B, fold_name, mode)
分析没有看到 train 相关的输出信息,可能的原因包括:
- 输出信息被隐藏了;
- 程序跑出了异常:检查程序是否报错,如果有错误信息请提供相关的报错信息以便进一步分析问题所在。
- 训练集中没有数据:请您检查训练集中是否有数据,如果没有数据则会导致训练集特征无法生成。
可是再排查:
- 输出信息没有被隐藏,因为 train文件夹中没有生成一个文件。
- 于是我打印了 work/dataset/index/fold0_train_idx.npy 里的值,证明数据集中有数据;
- 可是既然 valid 能正常输出,不是说明了程序没有问题吗?
没办法,我又检查了 generate_feature.py 脚本的源代码,然后把问题原因定位到 get_JA 函数,因为从这个函数开始 train 就没有输出了。
def get_JA(J, labels, fold_name, mode):
N, C, T, V, M = J.shape
save_data_path = './{}/JA{}.npy'.format(mode, fold_name)
if mode != 'test':
save_label_path = './{}/fold{}_label.npy'.format(mode, fold_name[-1])
l = [pairs_local, pairs_center1, pairs_center2, pairs_hands, pairs_elbows, pairs_knees, pairs_feet]
res = np.zeros((N, len(l), T, V, M), dtype='float32')
for i, pairs in enumerate(l):
ans = get_single_angle(pairs, J)
res[:, i, :, :, :] = ans.squeeze(1)
JA = np.concatenate((J , res), axis=1).astype('float32')
if mode == 'train':
JA, labels = upsampling(JA, labels)
然后我在这个函数里添加了很多 print 语句,发现问题出现在这3行:
for i, pairs in enumerate(l):
ans = get_single_angle(pairs, J)
res[:, i, :, :, :] = ans.squeeze(1)
我又把 get_single_angle 函数单独调出来运行发现是可以正常输出的,输出的结果通过打印形状,也是符合预期的,不过我还是给这个函数加上了异常捕获;
加入异常捕获代码之后,程序不会直接退出,而是会在遇到异常时输出错误信息并返回 None。
为了检查输出是否被遗漏,我在循环结束后再添加一行 print(‘i: {}’.format(i)) 进行检查:
for i, pairs in enumerate(l):
print('i_start: {}'.format(i))
ans = get_single_angle(pairs, J)
print(ans.shape) # (2337, 1, 2500, 25, 1)
res[:, i, :, :, :] = ans.squeeze(1)
print(res.shape) # (2337, 7, 2500, 25, 1)
print('i_end: {}'.format(i)) i_start: 0
发现没有 i_end 的输出。
结合问题:在 valid 模式下可以正常输出,但在 train 模式下没有输出。
可能是因为训练集数据量较大,在执行 get_JA 函数时需要处理的数据量很大,导致在输出语句之前程序被阻塞,无法顺利输出。
解决办法
解决办法:增加硬件资源。如果计算机性能较低,可以尝试增加硬件资源,例如更换更高配置的 CPU 或 GPU,以提高计算速度。
果然用了 GPU V100 32GB,输出就正常了。
i_end
正常输出了:
i_start: 0
(2337, 1, 2500, 25, 1)
(2337, 7, 2500, 25, 1)
i_end: 0
终于 train 也输出文件了: