淘先锋技术网

首页 1 2 3 4 5 6 7

本文内容多是个人理解,如有问题望多多指正


一、误差:

误差分析

在论文中,使用了三个标准误差测量法来估计单目深度预测的准确性,这三个标准误差测量法是目前最先进的方法[21,22,14,6]中常用的。这些误差是为每个像素定义的,并对图像中的所有像素和数据集中的所有图像进行平均。


三个标准误差测量法如下:

标准误差测量法


对训练数据量的鲁棒性: 为了评估对训练量的敏感性,文中通过逐步减少训练数据来模拟该方法在两个数据集上的行为。并没有使用完整的训练集,而是随机抽取一小部分训练数据进行训练。下图中的曲线表明,当训练数据量逐渐减少时,误差值(‘ rel’和‘ log10’)的变化。即可知,当随着培训数据量的逐渐减少,这两个误差指标都缓慢增加,所以误差值越小越好

误差指标


二、checkpoint.pth.tar:

其实训练一个深度神经网络是需要挺长的时间的,即使是在高性能服务器上,有些训练也要持续几天之久。
如果当你遇到这种尴尬的情况:花了一天时间**好不容易训练模型到 60% 啦,突然,**机房要停电?学长要占用服务器?购买的 GPU 计算时间用完了等等。

这时候该怎么办呢??

训练了一大半的模型不能功亏一篑呀,所以这时候就要未雨绸缪回头有机会了加载接着训练,所以这时候就要将模型保存为一个文件:

#未雨绸缪,防止丢失
        if err < best_val_err:
            best_val_err = err#当前最好精度
            torch.save({
                'epoch': start_epoch + epoch + 1,#保存的当前轮数
                'state_dict': model.state_dict(),#训练好的参数
                'optimizer': optimizer.state_dict(),#优化器参数,为了后续的resume
            }, 'checkpoint.pth.tar')#保存模型到checkpoint.pth.tar

然后再重新加载

resume_file = 'checkpoint.pth.tar'
    if resume_from_file:
        if os.path.isfile(resume_file):
            print("=> loading checkpoint '{}'".format(resume_file))
            checkpoint = torch.load(resume_file)
            start_epoch = checkpoint['epoch']#epoch,可以用于更新学习率等
            model.load_state_dict(checkpoint['state_dict'])#模型参数
            print("=> loaded checkpoint '{}' (epoch {})"
                  .format(resume_file, checkpoint['epoch']))
        else:
            print("=> no checkpoint found at '{}'".format(resume_file))

这样就可以保存(save)&加载(load)训练中的 PyTorch 模型啦,而且这样也不怕服务器突然掉链子,还能够把训练各个阶段的模型都保存下来,用于研究模型训练的各个步骤。


三、nyu_depth_v2_labeled.mat数据集:

由于是.mat文件,所以我用matlab把该文件打开后如下图:

nyu数据集

其中列举一些变量的含义:

(1)depths-HxWxN维度的矩阵深度图,其中H和W分别为高度和宽度,N为图像的个数。深度元素的值是米。

(2)images-HxWx3xN RGB图像矩阵,其中H和W分别是高度和宽度,N是图像的数量

(3)labels-HxWxN标签矩阵,其中H和W分别是高度和宽度,N是图像数量。 标签范围从1…C,其中C是类的总数。 标签的范围从1…C是类的总数。如果一个像素的标签值为0,那么这个像素就没有标记。


代码中首先应用交叉验证将训练集划分为两部分,训练集验证集
训练集:用于训练模型
验证集:在使用测试集得出模型误差之前,用验证测试模型的误差
先给定一个分隔位置,然后确定测试集和验证集:

val_start_idx = int(len(train_lists) * 0.8)                 #交叉验证集

    val_lists = train_lists[val_start_idx:-1]
    train_lists = train_lists[0:val_start_idx]

后再用torch.utils.data.DataLoader()迭代取该数据集(一个一个batch读入),该接口主要用来将自定义的数据读取接口的输出或者PyTorch已有的数据读取接口的输入按照batch size封装成Tensor,后续只需要再包装成Variable即可作为模型的输入

train_loader = torch.utils.data.DataLoader(NyuDepthLoader(data_path, train_lists),
                                               batch_size=batch_size, shuffle=True, drop_last=True)
    val_loader = torch.utils.data.DataLoader(NyuDepthLoader(data_path, val_lists),
                                               batch_size=batch_size, shuffle=True, drop_last=True)
    test_loader = torch.utils.data.DataLoader(NyuDepthLoader(data_path, test_lists),
                                             batch_size=batch_size, shuffle=True, drop_last=True)

再根据以下代码获得原始图和深度图,注意要提取深度图像,要记得取max

        for input, depth in val_loader:
            input_var = Variable(input.type(dtype))#模型的输入
            depth_var = Variable(depth.type(dtype))

            output = model(input_var)#resnet50模型处理后的输出

            input_rgb_image = input_var[0].data.permute(1, 2, 0).cpu().numpy().astype(np.uint8)#原始图像
            input_gt_depth_image = depth_var[0][0].data.cpu().numpy().astype(np.float32)#depth图像
            pred_depth_image = output[0].data.squeeze().cpu().numpy().astype(np.float32)

            input_gt_depth_image /= np.max(input_gt_depth_image)#提取depth图像
            pred_depth_image /= np.max(pred_depth_image)#提取预测的深度图像

            plot.imsave('input_rgb_epoch_0.png', input_rgb_image)
            plot.imsave('gt_depth_epoch_0.png', input_gt_depth_image, cmap="viridis")
            plot.imsave('pred_depth_epoch_0.png', pred_depth_image, cmap="viridis")

四、test模块误差和阈值部分的代码理解:

这里误差计算中pred_depth_image多表示观测值input_gt_depth_image则多表示真值阈值Threshold部分没有查到太多与该代码有关的相关资料,我理解的是他给定一个阈值部分,这样图像的深浅或许会有不同的显现,在这里等待大家不同的理解

初始化:

Threshold_1_25 = 0
Threshold_1_25_2 = 0
Threshold_1_25_3 = 0
RMSE_linear = 0.0
RMSE_log = 0.0
RMSE_log_scale_invariant = 0.0
ARD = 0.0
SRD = 0.0

计算:(注释中也有部分理解)

 #观测次数n
        n = np.sum(input_gt_depth_image > 1e-3)

        idxs = (input_gt_depth_image <= 1e-3)
        pred_depth_image[idxs] = 1
        input_gt_depth_image[idxs] = 1

        pred_d_gt = pred_depth_image / input_gt_depth_image
        pred_d_gt[idxs] = 100
        gt_d_pred = input_gt_depth_image / pred_depth_image
        gt_d_pred[idxs] = 100

        # 设定阈值
        Threshold_1_25 += np.sum(np.maximum(pred_d_gt, gt_d_pred) < 1.25) / n
        Threshold_1_25_2 += np.sum(np.maximum(pred_d_gt, gt_d_pred) < 1.25 * 1.25) / n
        Threshold_1_25_3 += np.sum(np.maximum(pred_d_gt, gt_d_pred) < 1.25 * 1.25 * 1.25) / n

        log_pred = np.log(pred_depth_image)#求观测值的log,为了便于下面求误差
        log_gt = np.log(input_gt_depth_image)#求真实值的log,为了便于下面求误差

        d_i = log_gt - log_pred

#下为不同误差计算
#均方根误差(RMSE),它是观测值与真值偏差的平方和观测次数n比值的平方根,pred_depth_image:观测值,input_gt_depth_image:真值
        RMSE_linear += np.sqrt(np.sum((pred_depth_image - input_gt_depth_image) ** 2) / n)#均方根误差
        RMSE_log += np.sqrt(np.sum((log_pred - log_gt) ** 2) / n)#rms(log)
        RMSE_log_scale_invariant += np.sum(d_i ** 2) / n + (np.sum(d_i) ** 2) / (n ** 2)
        ARD += np.sum(np.abs((pred_depth_image - input_gt_depth_image)) / input_gt_depth_image) / n#rel,相对误差
        SRD += np.sum(((pred_depth_image - input_gt_depth_image) ** 2) / input_gt_depth_image) / n

Threshold_1_25 /= num_samples
Threshold_1_25_2 /= num_samples
Threshold_1_25_3 /= num_samples
RMSE_linear /= num_samples
RMSE_log /= num_samples
RMSE_log_scale_invariant /= num_samples
ARD /= num_samples
SRD /= num_samples

print('Threshold_1_25: {}'.format(Threshold_1_25))
print('Threshold_1_25_2: {}'.format(Threshold_1_25_2))
print('Threshold_1_25_3: {}'.format(Threshold_1_25_3))
print('RMSE_linear: {}'.format(RMSE_linear))
print('RMSE_log: {}'.format(RMSE_log))
print('RMSE_log_scale_invariant: {}'.format(RMSE_log_scale_invariant))
print('ARD: {}'.format(ARD))
print('SRD: {}'.format(SRD))

五、NYU_ResNet-UpProj.npy:

模型文件(.npy)部分内容如下:由一个字典组成,字典中的每一个键对应一层网络模型参数

由于numpy版本存在不兼容的问题,所以我用如下代码在控制台上输出了.npy文件的内容:

import numpy as np
old = np.load
np.load = lambda *a,**k: old(*a,**k,allow_pickle=True)
test=np.load('NYU_ResNet-UpProj.npy',encoding = "latin1")  #加载文件
#doc = open('1.txt', 'a')  #打开一个存储文件,并依次写入
#print(test, file=doc)  #将打印内容写入文件中
print(test)

输出的部分内容如下:

.npy文件

或写入文件,内容如图:

npy文件


所以可直接利用如下语句加载模型权重

weights_file = "NYU_ResNet-UpProj.npy"

 model_params = model.state_dict()
 data_dict = np.load(weights_file, encoding='latin1').item()#加载npy文件格式


越努力,越幸运


end~~~