精华内容
下载资源
问答
  • BP神经网络matlab代码讲解与实现步骤

    万次阅读 多人点赞 2020-04-02 01:39:51
    BP神经网络matlab代码实现 文章目录BP神经网络matlab代码实现1. BP神经网络的简介和结构参数1.1 BP神经网络的结构组成1.2 BP神经网络训练界面的参数解读2. 实现BP网络的步骤3. matlab代码编写4. BP代码运行结果4.1 ...

    1. BP神经网络的简介和结构参数

    神经网络是机器学习中一种常见的数学模型,通过构建类似于大脑神经突触联接的结构,来进行信息处理。在应用神经网络的过程中,处理信息的单元一般分为三类:输入单元、输出单元和隐含单元。 顾名思义:输入单元接受外部给的信号与数据;输出单元实现系统处理结果的输出;隐含单元处在输入和输出单元之间,从网络系统外部是无法观测到隐含单元的结构的。除了上述三个处理信息的单元之外,神经元间的连接强度大小由权值等参数来决定。

    1.1 BP神经网络的结构组成

    下图是训练神经网络时经常出现的一个界面,从这部分我们可以看到,这是一个2输入1输出,5个隐含层的BP网络,称为2-5-1网络结构
    在这里插入图片描述

    1.2 BP神经网络训练界面的参数解读

    需要注意的是:
    1. 泛化性: 表示BP神经网络在训练过程中,如果均方误差(MSE)连续6次不降反升,则网络停止训练
    2. 误差精度: 关于mu参数含义的一种理解是,mu是误差精度参数,用于给神经网络的权重再加一个调制,这样可以避免在BP网络训练的过程中陷入局部最小值,mu的范围为0到1。英文的释义如下:
    Mu stands for momentum constant or momentum parameter which is included in weight update expression to avoid the problem of local minimum. Sometimes network may get stuck to local minimum and convergence does not occur. Range of mu is between 0 and 1.

    在这里插入图片描述

    2. 实现BP网络的步骤

    1. 读取数据
    2. 设置训练数据和预测数据
    3. 训练样本数据归一化
    4. 构建BP神经网络
    5. 网络参数配置(训练次数,学习速率,训练目标最小误差.等)
    6. BP神经网络训练
    7. 测试样本归一化
    8. BP神经网络预测
    9. 预测结果反归一化与误差计算
    10. 验证集的真实值与预测值误差比较

    3. matlab代码编写

    %% 此程序matlab编程实现的BP神经网络
    % 清空环境变量
    clear all
    clc
    
    %%第一步 读取数据
    load input  %载入输入数据
    load output  %载入输出数据
    
    %% 第二步 设置训练数据和预测数据
    input_train = input(:,1:190);
    output_train =output(1:190,:)';
    input_test = input(:,191:200);
    output_test =output(191:200,:)';
    %节点个数
    inputnum=2;
    hiddennum=5;%隐含层节点数量经验公式p=sqrt(m+n)+a ,故分别取2~13进行试验
    outputnum=1;
    %% 第三本 训练样本数据归一化
    [inputn,inputps]=mapminmax(input_train);%归一化到[-1,1]之间,inputps用来作下一次同样的归一化
    [outputn,outputps]=mapminmax(output_train);
    %% 第四步 构建BP神经网络
    net=newff(inputn,outputn,hiddennum,{'tansig','purelin'},'trainlm');% 建立模型,传递函数使用purelin,采用梯度下降法训练
    
    W1= net. iw{1, 1};%输入层到中间层的权值
    B1 = net.b{1};%中间各层神经元阈值
    
    W2 = net.lw{2,1};%中间层到输出层的权值
    B2 = net. b{2};%输出层各神经元阈值
    
    %% 第五步 网络参数配置( 训练次数,学习速率,训练目标最小误差等)
    net.trainParam.epochs=1000;         % 训练次数,这里设置为1000次
    net.trainParam.lr=0.01;                   % 学习速率,这里设置为0.01
    net.trainParam.goal=0.00001;                    % 训练目标最小误差,这里设置为0.00001
    
    %% 第六步 BP神经网络训练
    net=train(net,inputn,outputn);%开始训练,其中inputn,outputn分别为输入输出样本
    
    %% 第七步 测试样本归一化
    inputn_test=mapminmax('apply',input_test,inputps);% 对样本数据进行归一化
    
    %% 第八步 BP神经网络预测
    an=sim(net,inputn_test); %用训练好的模型进行仿真
    
    %% 第九步 预测结果反归一化与误差计算     
    test_simu=mapminmax('reverse',an,outputps); %把仿真得到的数据还原为原始的数量级
    error=test_simu-output_test;      %预测值和真实值的误差
    
    %%第十步 真实值与预测值误差比较
    figure(1)
    plot(output_test,'bo-')
    hold on
    plot(test_simu,'r*-')
    hold on
    plot(error,'square','MarkerFaceColor','b')
    legend('期望值','预测值','误差')
    xlabel('数据组数')
    ylabel('值')
    [c,l]=size(output_test);
    MAE1=sum(abs(error./output_test))/l;
    MSE1=error*error'/l;
    RMSE1=MSE1^(1/2);
    disp(['-----------------------误差计算--------------------------'])
    disp(['隐含层节点数为',num2str(hiddennum),'时的误差结果如下:'])
    disp(['平均绝对误差MAE为:',num2str(MAE1)])
    disp(['均方误差MSE为:       ',num2str(MSE1)])
    disp(['均方根误差RMSE为:  ',num2str(RMSE1)])
    
    

    4. BP代码运行结果

    4.1 预测值和真实值的误差计算(MAE、MSE、MRSE)

    在这里插入图片描述

    4.2 BP网络训练的性能分析图像

    1. 预测值和真实值、误差的分析图像
      在这里插入图片描述
    2. 训练集、验证集、测试集和总体的均方误差随训练次数的变化图像
      注:小圆圈位置代表终止的训练次数(即代数)处的均方误差
      在这里插入图片描述
    3. BP神经网络各阶段的训练图像
      在这里插入图片描述
    4. 各个样本集和总体的相关性分析图像
      在这里插入图片描述
    5. 训练集、验证集和测试集的误差分布直方图像
      在这里插入图片描述

    5. 结语

    1. 经过一周的努力编写,终于将BP网络的搭建思路和完整代码表述清楚,供大家学习。
    2. 伙伴们只需将自己的数据代入,即可得到相应的结果,如有问题,欢迎留言交流。
    3. 若有不恰当的地方,恳请码友指正。

    6. MATLAB代码与数据下载地址

    1. BP神经网络回归预测的MATLAB代码与数据地址

    https://mianbaoduo.com/o/bread/YZmTmptv

    2. BP神经网络数据分类的MATLAB代码与数据地址

    https://mianbaoduo.com/o/bread/YZmTmp5q

    3. BP神经网络回归预测的代码讲解

    https://mianbaoduo.com/o/bread/YZmUlZpw

    展开全文
  • siamfc-pytorch代码讲解(二):train&siamfc

    千次阅读 多人点赞 2020-02-24 17:27:36
    siamfc-pytorch代码讲解(二):train&siamfc一、train.py二、siamfc.py2.1 SiamFCTransforms2.2 Pair2.3 train_step下一篇 这是第二篇的siamfc-pytorch代码讲解,主要顺着程序流讲解代码,上一篇讲解在这里: ...

    这是第二篇的siamfc-pytorch代码讲解,主要顺着程序流讲解代码,上一篇讲解在这里:
    siamfc-pytorch代码讲解(一):backbone&head
    show me code !!

    一、train.py

    因为作者使用了GOT-10k这个工具箱,train.py代码非常少,就下面几行:

    from __future__ import absolute_import
    
    import os
    from got10k.datasets import *
    
    from siamfc import TrackerSiamFC
    
    if __name__ == '__main__':
        root_dir = os.path.expanduser('~/data/GOT-10k')
        seqs = GOT10k(root_dir, subset='train', return_meta=True)
    
        tracker = TrackerSiamFC()
        tracker.train_over(seqs)
    

    首先我们就需要按照GOT-10k download界面去下载好数据集,并且按照这样的文件结构放好(因为现在用不到验证集和测试集,可以先不用下,训练集也只要先下载1个split,所以就需要把list.txt中只保留前500项,因为GOT-10k_Train_000001里面有500个squences):

      |-- GOT-10k/
         |-- train/
         |  |-- GOT-10k_Train_000001/
         |  |   ......
         |  |-- GOT-10k_Train_000500/
         |  |-- list.txt
    

    这里可以打印一下seps到底是什么,因为他是train_over的入参:

    print(seqs)
    # <got10k.datasets.got10k.GOT10k object at 0x000002366865CF28>
    print(seqs[0])
    # 这里比较多,截取一部分
    # seqs[0]就是指第一个序列GOT-10k_Train_000001,返回三个元素的元组
    # 第一个元素是一个路径列表,第二个是np.ndarray,第三个是字典,包含具体信息
    # (['D:\\GOT-10k\\train\\GOT-10k_Train_000001\\00000001.jpg', ...],
    # array([[347., 443., 429., 272.],...[551., 467., 513., 318.]]),
    # {'url': 'https://youtu.be/b0ZnfLI8YPw',...})
    

    二、siamfc.py

    顺着代码流看到调用了siamfc.py中类TrackerSiamFC的train_over方法,在这个类里面就是进行数据增强,构造和加载,然后进行训练,这里主要有三个地方需要深入思考一下:

    2.1 SiamFCTransforms

    SiamFCTransforms是transforms.py里面的一个类,主要是对输入的groung truth的z, x, bbox_z, bbox_x进行一系列变换,构成孪生网络的输入,这其中就包括了:

    • RandomStretch:主要是随机的resize图片的大小,其中要注意cv2.resize()的一点用法,可以参考我的这篇博客:cv2.resize()的一点小坑
    • CenterCrop:从img中间抠一块(size, size)大小的patch,如果不够大,以图片均值进行pad之后再crop
    • RandomCrop:用法类似CenterCrop,只不过从随机的位置抠,没有pad的考虑
    • Compose:就是把一系列的transforms串起来
    • ToTensor: 就是字面意思,把np.ndarray转化成torch tensor类型

    类初始化里面针对self.transforms_zself.transforms_x数据增强方法中具体参数的设置可以参考 issue#21,作者提到在train phase和test phase embedding size不一样没太大的影响,而且255-16可以模拟测试阶段目标的移动(个人感觉这里没有完全就按照论文上来,但也不用太在意,自己可以试着改回来看哪一个效果好)。
    下面具体讲里面的_crop函数:

        def _crop(self, img, box, out_size):
            # convert box to 0-indexed and center based [y, x, h, w]
            box = np.array([
                box[1] - 1 + (box[3] - 1) / 2,
                box[0] - 1 + (box[2] - 1) / 2,
                box[3], box[2]], dtype=np.float32)
            center, target_sz = box[:2], box[2:]
    
            context = self.context * np.sum(target_sz)
            size = np.sqrt(np.prod(target_sz + context))
            size *= out_size / self.exemplar_sz
    
            avg_color = np.mean(img, axis=(0, 1), dtype=float)
            interp = np.random.choice([
                cv2.INTER_LINEAR,
                cv2.INTER_CUBIC,
                cv2.INTER_AREA,
                cv2.INTER_NEAREST,
                cv2.INTER_LANCZOS4])
            patch = ops.crop_and_resize(
                img, center, size, out_size,
                border_value=avg_color, interp=interp)
            
            return patch
    

    因为GOT-10k里面对于目标的bbox是以ltwh(即left, top, weight, height)形式给出的,上述代码一开始就先把输入的box变成center based,坐标形式变为[y, x, h, w],结合下面这幅图就非常好理解:y=t+h2y=t+\frac{h}{2}x=l+w2x=l+\frac{w}{2}
    the annotation form of bbox in GOT-10k
    crop_and_resize

    def crop_and_resize(img, center, size, out_size,
                        border_type=cv2.BORDER_CONSTANT,
                        border_value=(0, 0, 0),
                        interp=cv2.INTER_LINEAR):
        # convert box to corners (0-indexed)
        size = round(size)  # the size of square crop
        corners = np.concatenate((
            np.round(center - (size - 1) / 2),
            np.round(center - (size - 1) / 2) + size))
        corners = np.round(corners).astype(int)
    
        # pad image if necessary
        pads = np.concatenate((
            -corners[:2], corners[2:] - img.shape[:2]))
        npad = max(0, int(pads.max()))
        if npad > 0:
            img = cv2.copyMakeBorder(
                img, npad, npad, npad, npad,
                border_type, value=border_value)
    
        # crop image patch
        corners = (corners + npad).astype(int)
        patch = img[corners[0]:corners[2], corners[1]:corners[3]]
    
        # resize to out_size
        patch = cv2.resize(patch, (out_size, out_size),
                           interpolation=interp)
    
        return patch
    

    现在进入ops.py下的crop_and_resize,这个函数的作用就是crop一块以object为中心的,边长为size大小的patch(如下面的绿色虚线的正方形框),然后将其resize成out_size的大小:传入sizecenter计算出角落坐标形式的正方形patch,即(ymin,xmin,ymax,xmax)(y_{min},x_{min},y_{max},x_{max}),如下面两个点粗的绿点,因为这样扩大的坐标有可能会超出原来的图片(如粉红色线所表示),所以就要计算左上角和右下角相对原图片超出多少,好进行pad,上面13-14行代码就是干这事。然后根据他们超出当中的最大值npad来在原图像周围pad(也就是最外面的蓝框),因为原图像增大了,所以corner相对坐标也变了,对应上面22行代码。然后就是crop下来绿色方形的那块,经过resize后返回。
    关于_crop函数的图示
    下面就是我的实验结果:
    原图与抠下来的patch图对比

    2.2 Pair

    现在继续回到train_over方法,里面构造dataset的时候用了Pair类,所以从代码角度具体来看一下,因为继承了Dataset类,所以要overwrite __getitem____len__方法:

    • __getitem__:分析代码,这个方法就是通过index索引返回item = (z, x, box_z, box_x),然后经过transforms返回一对pair(z, x),就需要像论文里面说的:The images are extracted from two frames of a video that both contain the object and are at most T frames apart
      • _filter:通过该函数筛选符合条件的有效索引val_indices,这里不详细分析,因为我也不知道为什么会有这样的filter condition。
      • _sample_pair:如果有效索引大于2个的话,就从中随机挑选两个索引,这里取的间隔不超过T=100
    • __len__:这里定义的长度就是被索引到的视频序列帧数×每个序列提供的对数

    2.3 train_step

    现在来到siamfc.py里面最后一个关键的地方,数据准备好了,经过变换和加载进来就可以训练了,下面代码是常规操作,具体在train_step里面实现了训练和反向传播:

    for epoch in range(self.cfg.epoch_num):
        # update lr at each epoch
        self.lr_scheduler.step(epoch=epoch)
    
        # loop over dataloader
        for it, batch in enumerate(dataloader):
            loss = self.train_step(batch, backward=True)
            print('Epoch: {} [{}/{}] Loss: {:.5f}'.format(
                epoch + 1, it + 1, len(dataloader), loss))
            sys.stdout.flush()
    

    train_step里面难度又是在于理解_create_labels,具体的一些tensor的shape可以看我的注释,我好奇就把他打印出来了,看来本来__getitem__返回一对pair(z, x),经过dataloader的加载,还是z堆叠一起,x堆叠一起,并不是(z, x)绑定堆叠一起【主要自己对dataloader源码不是很熟,手动捂脸】
    而且criterion使用的BalancedLoss,是调用F.binary_cross_entropy_with_logits,进行一个element-wise的交叉熵计算,所以创建出来的labels的shape其实就是和responses的shape是一样的:

    def train_step(self, batch, backward=True):
        # set network mode
        self.net.train(backward)
    
        # parse batch data
        z = batch[0].to(self.device, non_blocking=self.cuda)
        x = batch[1].to(self.device, non_blocking=self.cuda)
        # print("batch_z shape:", z.shape)  # torch.Size([8, 3, 127, 127])
        # print("batch_x shape:", x.shape)  # torch.Size([8, 3, 239, 239])
    
        with torch.set_grad_enabled(backward):
            # inference
            responses = self.net(z, x)
            # print("responses shape:", responses.shape) # torch.Size([8, 1, 15, 15])
    
            # calculate loss
            labels = self._create_labels(responses.size())
            loss = self.criterion(responses, labels)
    
            if backward:
                # back propagation
                self.optimizer.zero_grad()
                loss.backward()
                self.optimizer.step()
    

    创建标签,论文里是这么说的:
    y[u]={+1 if kucR1 otherwise  y[u]=\left\{\begin{array}{ll} {+1} & {\text { if } k\|u-c\| \leq R} \\ {-1} & {\text { otherwise }} \end{array}\right.
    因为我们的exemplar image zz 和search image xx都是以目标为中心的,所以labels的中心为1,中心以外为0。

    def _create_labels(self, size):
        # skip if same sized labels already created
        if hasattr(self, 'labels') and self.labels.size() == size:
            return self.labels
    
        def logistic_labels(x, y, r_pos, r_neg):
            dist = np.abs(x) + np.abs(y)  # block distance
            labels = np.where(dist <= r_pos,
                              np.ones_like(x),
                              np.where(dist < r_neg,
                                       np.ones_like(x) * 0.5,
                                       np.zeros_like(x)))
            return labels
    
        # distances along x- and y-axis
        n, c, h, w = size
        x = np.arange(w) - (w - 1) / 2
        y = np.arange(h) - (h - 1) / 2
        x, y = np.meshgrid(x, y)
    
        # create logistic labels 这里除以stride,是相对score map上来说
        r_pos = self.cfg.r_pos / self.cfg.total_stride
        r_neg = self.cfg.r_neg / self.cfg.total_stride
        labels = logistic_labels(x, y, r_pos, r_neg)
    
        # repeat to size
        labels = labels.reshape((1, 1, h, w))
        labels = np.tile(labels, (n, c, 1, 1))
    
        # convert to tensors
        self.labels = torch.from_numpy(labels).to(self.device).float()
    
        return self.labels
    

    其中关于np.tile、np.meshgrid、np.where函数的使用可以去看我这篇博客,最后出来的一个batch下某一个通道下的label就是下面这样的,有没有一种扫雷的既视感,😄:
    labels的创建
    至此此份repo的训练应该差不多结束了,测试部分(inference phase)我还没怎么看,且涉及到GOT-10k的使用,下一次有空再看再写~

    上下篇

    上一篇:siamfc-pytorch代码讲解(一):backbone&head
    下一篇:siamfc-pytorch代码讲解(三):demo&track

    展开全文
  • siamfc-pytorch代码讲解(三):demo&track

    千次阅读 多人点赞 2020-03-03 14:20:59
    siamfc-pytorch代码讲解(一):backbone&head siamfc-pytorch代码讲解(二):train&siamfc 代码来自:https://github.com/huanglianghua/siamfc-pytorch 今天主要看一下demo的部分,也就是涉及到测试...


    我之前的两篇博客:

    今天主要看一下demo的部分,也就是涉及到测试tracking的部分。
    直接上代码:

    一、demo.py

    from __future__ import absolute_import
    
    import os
    import glob
    import numpy as np
    
    from siamfc import TrackerSiamFC
    
    
    if __name__ == '__main__':
        seq_dir = os.path.expanduser('D:\\OTB\\Crossing\\')
        img_files = sorted(glob.glob(seq_dir + 'img/*.jpg'))
        anno = np.loadtxt(seq_dir + 'groundtruth_rect.txt', delimiter=',')
        
        net_path = 'pretrained/siamfc_alexnet_e50.pth'
        tracker = TrackerSiamFC(net_path=net_path)
        tracker.track(img_files, anno[0], visualize=True)
    
    1. 上面的第11行路径自己该,我这次是windows测试的,所以这样写了(看着有点不规范)。
    2. 13行我多加了一点代码:, delimiter=',',不加这个会报这样的错:

    ValueError: could not convert string to float

    1. 下面几行就是用训练好的siamfc_alexnet_e50.pth模型进行tracking,给定的是img_files:视频序列;anno[0]就是第一帧中的ground truth bbox。

    二、track

    现在就来看一下类TrackerSiamFC下的track方法。这个函数的作用就是传入video sequence和first frame中的ground truth bbox,然后通过模型,得到后续帧的目标位置,可以看到主要有两个函数实现:initupdate,这也是继承Tracker需要重写的两个方法:

    • init:就是传入第一帧的标签和图片,初始化一些参数,计算一些之后搜索区域的中心等等
    • update:就是传入后续帧,然后根据SiamFC网络返回目标的box坐标,之后就是根据这些坐标来show,起到一个demo的效果。
    def track(self, img_files, box, visualize=False):
        frame_num = len(img_files)
        boxes = np.zeros((frame_num, 4))
        boxes[0] = box
        times = np.zeros(frame_num)
    
        for f, img_file in enumerate(img_files):
            img = ops.read_image(img_file)
    
            begin = time.time()
            if f == 0:
                self.init(img, box)
            else:
                boxes[f, :] = self.update(img)
            times[f] = time.time() - begin
    
            if visualize:
                ops.show_image(img, boxes[f, :])
    
        return boxes, times
    

    2.1 init(self, img, box)

    我强烈建议可以用两个设备,一个看代码,一个用来看我下边的长图,对照着分析

    def init(self, img, box):
        # set to evaluation mode
        self.net.eval()
    
        # convert box to 0-indexed and center based [y, x, h, w]
        box = np.array([
            box[1] - 1 + (box[3] - 1) / 2,
            box[0] - 1 + (box[2] - 1) / 2,
            box[3], box[2]], dtype=np.float32)
        self.center, self.target_sz = box[:2], box[2:]
    
        # create hanning window
        self.upscale_sz = self.cfg.response_up * self.cfg.response_sz  # 272
        self.hann_window = np.outer(
            np.hanning(self.upscale_sz),
            np.hanning(self.upscale_sz))
        self.hann_window /= self.hann_window.sum()
    
        # search scale factors
        self.scale_factors = self.cfg.scale_step ** np.linspace(
            -(self.cfg.scale_num // 2),
            self.cfg.scale_num // 2, self.cfg.scale_num)  # 1.0375**(-1,0,1)
    
        # exemplar and search sizes
        context = self.cfg.context * np.sum(self.target_sz)
        self.z_sz = np.sqrt(np.prod(self.target_sz + context))
        self.x_sz = self.z_sz * \
                    self.cfg.instance_sz / self.cfg.exemplar_sz
    
        # exemplar image
        self.avg_color = np.mean(img, axis=(0, 1))
        z = ops.crop_and_resize(
            img, self.center, self.z_sz,
            out_size=self.cfg.exemplar_sz,
            border_value=self.avg_color)
    
        # print(z.shape) # [127,127,3]
        # exemplar features [H,W,C]->[C,H,W]
        z = torch.from_numpy(z).to(
            self.device).permute(2, 0, 1).unsqueeze(0).float()
        self.kernel = self.net.backbone(z)  # torch.Size([1, 256, 6, 6])
    
    1. 一开始,就是把输入的ltwh格式的box转变为[y, x, h, w]格式的,这个看过我第二篇的就很清楚了,然后记录bbox的中心和宽高size信息,以备后用(如下图黑色字体表示的)
    2. 这里计算了响应图上采样后的大小upscale_sz,因为论文中有这样一句话:
      We found that upsampling the score map using bicubic interpolation, from 17 × 17 to 272 × 272, results in more accurate localization since the original map is relatively coarse.也就是17×16=272
    3. 然后创建了一个汉宁窗(hanning window),也叫余弦窗【可以看这里】,论文中说是增加惩罚:Online, ... and a cosine window is added to the score map to penalize large displacements
    4. 论文中提到两个变体,一个是5个尺度的,一个是3个尺度的(这里就是),5个尺度依次是1.025[2,1,0,1,2]1.025^{[-2,-1,0,1,2]},代码中3个尺度是1.0375[2,0.5,1]1.0375^{[-2,-0.5,1]}
    5. context 就是边界的语义信息,为了计算z_szx_sz,最后送入crop_and_resize去抠出搜索区域【我第二篇博客有讲这个函数】, z_sz大小可以看下面蓝色方形框 x_sz大小可以看下面粉色方形框,最后抠出z_sz大小的作为exemplar image,并送入backbone,输出embedding,也可以看作是一个固定的互相关kernel,为了之后的相似度计算用,如论文中提到:We found that updating (the feature representation of) the exemplar online through simple strategies, such as linear interpolation, does not gain much performance and thus we keep it fixed
      关于一些tensor的shape可以看代码里的注释,下面是我当时的笔记:
      博客笔记1

    2.2 update(self, img)

    我强烈建议可以用两个设备,一个看代码,一个用来看我下边的长图,对照着分析

    def update(self, img):
        # set to evaluation mode
        self.net.eval()
    
        # search images
        x = [ops.crop_and_resize(
            img, self.center, self.x_sz * f,
            out_size=self.cfg.instance_sz,
            border_value=self.avg_color) for f in self.scale_factors]
        x = np.stack(x, axis=0)  # [3, 255, 255, 3]
        x = torch.from_numpy(x).to(
            self.device).permute(0, 3, 1, 2).float()
    
        # responses
        x = self.net.backbone(x)  # [3, 256, 22, 22]
        responses = self.net.head(self.kernel, x)  # [3, 1, 17, 17]
        responses = responses.squeeze(1).cpu().numpy()  # [3, 17, 17]
    
        # upsample responses and penalize scale changes
        responses = np.stack([cv2.resize(
            u, (self.upscale_sz, self.upscale_sz),
            interpolation=cv2.INTER_CUBIC)
            for u in responses])  # [3, 272, 272]
        responses[:self.cfg.scale_num // 2] *= self.cfg.scale_penalty
        responses[self.cfg.scale_num // 2 + 1:] *= self.cfg.scale_penalty
    
        # peak scale
        scale_id = np.argmax(np.amax(responses, axis=(1, 2)))  # which channel is max
    
        # peak location
        response = responses[scale_id]
        response -= response.min()
        response /= response.sum() + 1e-16
        response = (1 - self.cfg.window_influence) * response + \
                   self.cfg.window_influence * self.hann_window
        loc = np.unravel_index(response.argmax(), response.shape)
    
        # locate target center: disp stand for displacement
        disp_in_response = np.array(loc) - (self.upscale_sz - 1) / 2
        disp_in_instance = disp_in_response * \
                           self.cfg.total_stride / self.cfg.response_up
        disp_in_image = disp_in_instance * self.x_sz * \
                        self.scale_factors[scale_id] / self.cfg.instance_sz
        self.center += disp_in_image
    
        # update target size
        scale = (1 - self.cfg.scale_lr) * 1.0 + \
                self.cfg.scale_lr * self.scale_factors[scale_id]
        self.target_sz *= scale
        self.z_sz *= scale
        self.x_sz *= scale
    
        # return 1-indexed and left-top based bounding box
        box = np.array([
            self.center[1] + 1 - (self.target_sz[1] - 1) / 2,
            self.center[0] + 1 - (self.target_sz[0] - 1) / 2,
            self.target_sz[1], self.target_sz[0]])
    
        return box
    
    1. update顾名思义就是对后续的帧更新出bbox来,因为是tracking phase,所以把模型设成eval mode。然后在这新的帧里抠出search images,根据之前init里生成的3个尺度,然后resize成255×255,特别一点,我们可以发现search images在resize之前的边长x_sz大约为target_sz的4倍,这也印证了论文中的:we only search for the object within a region of approximately four times its previous size
    2. 然后将这3个尺度的patch(也就是3个搜索范围)拼接一起,送入backbone,生成emdding后与之前的kernel进行互相关,得到score map,这些tensor的shape代码里都有标注,得到3个17×17的responses,然后对每一个response进行上采样到272×272
    3. 上面的24,25行就是对尺度进行惩罚,我是这样理解的,因为中间的尺度肯定是接近于1,其他两边的尺度不是缩一点就是放大一点,所以给以惩罚,如论文中说:Any change in scale is penalized
    4. 之后就选出这3个通道里面最大的那个,并就行归一化和余弦窗惩罚,然后通过numpy.unravel_index找到一张response上峰值点(peak location)【关于这个函数可以看这里
    5. 接下来的问题就是:在response图中找到峰值点,那这在原图img中在哪里呢?所以我们要计算位移(displacement),因为我们原本都是以目标为中心的,认为最大峰值点应该在response的中心,所以39行就是峰值点和response中心的位移。
    6. 因为之前在img上crop下一块instance patch,然后resize,然后送入CNN的backbone,然后score map又进行上采样成response,所以要根据这过程,逆回去计算对应在img上的位移,所以上面的39-43行就是在做这件事,也可以看下面的图
    7. 根据disp_in_image修正center,然后update target size,因为论文有一句:update the scale by linear interpolation with a factor of 0.35 to provide damping,但是似乎参数不太对得上,线性插值可以看下面蓝色的图,因为更新后的scale还是很接近1,所以bbox区域不会变化很大
    8. 最后根据ops.show_image输入的需要,又得把bbox格式改回ltwh的格式
      博客笔记2

    三、checkpoint and demo

    我的模型存在这里,但是只训练了GOT-10k的前500个序列,但感觉效果也还行:
    Crossing-demo
    之后在全部训练序列上训练出来的模型(到49轮的时候电脑卡死了,感觉训练过程中cpu占用率很高):siamfc_alexnet_e49.zip

    四、test results

    这里放一下测试结果,当然和代码提供者结果,论文中的结果都是有距离的:

    OTB2013

    success OPE
    我的 0.466/0.520
    代码提供者的 0.589
    siamfc论文中的 0.612

    注意:我的OPE那栏里,前面那个是训了一部分的结果,下面也是一样的

    OTB2015

    success OPE
    我的 0.469/0.529
    代码提供者的 0.578
    siamfc论文中的 0.582

    注意:siamfc论文中的没有OTB2015的success OPE,我摘抄自SiamRPN论文,不过可以去官方地址有matlab结果文件,有机会用official toolkit评估一下,再来放个结果
    OTB2015测试precision plot和success plot
    上面的结果更新了一下,原因之前的OTB数据集没整理好,导致实际评估的序列数少了。我看过OTB benchmark官方评测代码python版本,里面评测和画图的方法和GOT-10k里面的ExperimentOTB是一样的,可以放心使用。


    五、matlab官方评测

    2020/05/20 情人节更新一下结果,这个是SiamFC官方project的结果:我使用的是
    results_SiamFC-3s_OTB-100.zip,然后用OTB official MATLAB toolkit的代码tracker_benchmark_v1.0.zip
    SiamFC-3s_OTB-100官方结果
    具体的做法如下:

    • 这篇博客下载包含otb全部序列的anno,tracker_benchmark_v1.0里面只有CVPR2013的序列注释(注意新加的序列名字不再都是小写的),把anno覆盖掉原来的,把configSeqs复制替换掉原来的configSeqs.m文件,在configTrackers.m中最后改成如下:
    trackersSiamfc={struct('name','siamfc3s','namePaper','SiamFC')};
    trackers = trackersSiamfc;
    
    • 在tracker_benchmark_v1.0的results文件夹下新建results_TRE_OTB100,并把上面下载的结果文件results_SiamFC-3s_OTB-100.zip里面的.mat文件拷贝其中,并把genPerfMat.m的13行改成rpAll=['.\results\results_TRE_OTB100\'];这个结果文件是TRE的,但是TRE的第一次就是OPE
    • 因为结果.mat文件跟我们configSeqs.m里面的seq.name不完全一样,所以得重命名,可用下面的python脚本重命名:
    import os
    
    tracker_name = 'siamfc3s'
    location = len(tracker_name) + 1
    # replace to your own path
    anno_seqs_path = 'D:\\tracker_benchmark_v1.0\\anno'
    anno_seqs = os.listdir(anno_seqs_path)
    anno_seqs.remove('att')
    assert len(anno_seqs) == 100, 'otb must have 100 seqs!'
    anno_seqs = [anno_seq[:-4] for anno_seq in anno_seqs]
    lower_anno_seqs = [i.lower() for i in anno_seqs]
    # print(anno_seqs)
    # replace to your own path
    res_seqs_path = 'D:\\tracker_benchmark_v1.0\\results\\results_TRE_OTB100'
    res_seqs = os.listdir(res_seqs_path)
    assert len(res_seqs) == len(anno_seqs), \
        'otb result must have equal length with anno'
    # remove .mat
    res_seqs = [res_seq[:-4] for res_seq in res_seqs]
    lower_res_no_tracker_name = [seq[:-location].lower() for seq in res_seqs]
    # print(lower_res_no_tracker_name)
    # different naming methods
    diff = []
    for res_seq in lower_res_no_tracker_name:
        if res_seq not in lower_anno_seqs:
            diff.append(res_seq)
    
    print('different naming methods:', diff)
    assert not diff, 'before rename, should rename diff name seqs!'
    
    # rename res file name
    for res_seq in lower_res_no_tracker_name:
        anno_idx = lower_anno_seqs.index(res_seq)
        res_idx = lower_res_no_tracker_name.index(res_seq)
        old_name = os.path.join(res_seqs_path, res_seqs[res_idx]+'.mat')
        new_name = os.path.join(res_seqs_path, anno_seqs[anno_idx]+'_'+tracker_name+'.mat')
        os.rename(old_name, new_name)
    
    • 这样运行perfPlot.m文件就能出结果了,其中105行的rankingType = 'AUC’时能得到success plot;rankingType = 'threshold’时能得到precision plot【这时得到的成功图不是0-1阈值下的,所以只有准确率图能用

    六、上下篇

    上一篇:siamfc-pytorch代码讲解(二):train&siamfc
    下一篇:OTB官方评估代码python版本–评估自己跟踪器,对比其他跟踪器

    展开全文
  • faster RCNN(keras版本)代码讲解(3)-训练流程详情

    万次阅读 热门讨论 2018-07-19 19:43:58
    faster RCNN(keras版本)代码讲解博客索引: 1.faster RCNN(keras版本)代码讲解(1)-概述 2.faster RCNN(keras版本)代码讲解(2)-数据准备 3.faster RCNN(keras版本)代码讲解(3)-训练流程详情 4.faster RCNN(keras...

    faster RCNN(keras版本)代码讲解博客索引:
    1.faster RCNN(keras版本)代码讲解(1)-概述
    2.faster RCNN(keras版本)代码讲解(2)-数据准备
    3.faster RCNN(keras版本)代码讲解(3)-训练流程详情
    4.faster RCNN(keras版本)代码讲解(4)-共享卷积层详情
    5.faster RCNN(keras版本)代码讲解(5)-RPN层详情
    6.faster RCNN(keras版本)代码讲解(6)-ROI Pooling层详情

    一.整体流程概述
    1.输入参数,其实输入1个就行了(D:\tempFile\VOCdevkit),另外一个resnet权重只是为了加快训练,如图:
    这里写图片描述
    2.从VOC2007数据集中读取数据,变成想要的数据格式
    3.定义生成数据的迭代器
    4.定义3个网络,一个是resnet共享卷积层,一个rpn层,一个分类器层
    5.进入迭代,每次只训练一张图片
    6.是否要进行图片增强
    7.根据特征图和定义框的比例,IOU等计算出y_train值,作为网络的label
    8.训练rpn层,输出物体,和物体框的坐标
    9.然后再进行分类器层层的训练

    二.代码(关键部位已经给出注释)

    from __future__ import division
    import random
    import pprint
    import sys
    import time
    import numpy as np
    from optparse import OptionParser
    import pickle
    
    from keras import backend as K
    from keras.optimizers import Adam, SGD, RMSprop
    from keras.layers import Input
    from keras.models import Model
    from keras_frcnn import config, data_generators
    from keras_frcnn import losses as losses
    import keras_frcnn.roi_helpers as roi_helpers
    from keras.utils import generic_utils
    
    sys.setrecursionlimit(40000)
    
    parser = OptionParser()
    
    parser.add_option("-p", "--path", dest="train_path", help="Path to training data.")
    parser.add_option("-o", "--parser", dest="parser", help="Parser to use. One of simple or pascal_voc",
                    default="pascal_voc")
    parser.add_option("-n", "--num_rois", type="int", dest="num_rois", help="Number of RoIs to process at once.", default=32)
    parser.add_option("--network", dest="network", help="Base network to use. Supports vgg or resnet50.", default='resnet50')
    parser.add_option("--hf", dest="horizontal_flips", help="Augment with horizontal flips in training. (Default=false).", action="store_true", default=False)
    parser.add_option("--vf", dest="vertical_flips", help="Augment with vertical flips in training. (Default=false).", action="store_true", default=False)
    parser.add_option("--rot", "--rot_90", dest="rot_90", help="Augment with 90 degree rotations in training. (Default=false).",
                      action="store_true", default=False)
    parser.add_option("--num_epochs", type="int", dest="num_epochs", help="Number of epochs.", default=2000)
    parser.add_option("--config_filename", dest="config_filename", help=
                    "Location to store all the metadata related to the training (to be used when testing).",
                    default="config.pickle")
    parser.add_option("--output_weight_path", dest="output_weight_path", help="Output path for weights.", default='./model_frcnn.hdf5')
    parser.add_option("--input_weight_path", dest="input_weight_path", help="Input path for weights. If not specified, will try to load default weights provided by keras.")
    
    (options, args) = parser.parse_args()
    
    if not options.train_path:   # if filename is not given
        parser.error('Error: path to training data must be specified. Pass --path to command line')
    
    if options.parser == 'pascal_voc':
        from keras_frcnn.pascal_voc_parser import get_data
    elif options.parser == 'simple':
        from keras_frcnn.simple_parser import get_data
    else:
        raise ValueError("Command line option parser must be one of 'pascal_voc' or 'simple'")
    
    # pass the settings from the command line, and persist them in the config object
    C = config.Config()
    
    C.use_horizontal_flips = bool(options.horizontal_flips)
    C.use_vertical_flips = bool(options.vertical_flips)
    C.rot_90 = bool(options.rot_90)
    
    C.model_path = options.output_weight_path
    C.num_rois = int(options.num_rois)
    
    #有基于VGG和resnet两种网络模型
    if options.network == 'vgg':
        C.network = 'vgg'
        from keras_frcnn import vgg as nn
    elif options.network == 'resnet50':
        from keras_frcnn import resnet as nn
        C.network = 'resnet50'
    else:
        print('Not a valid model')
        raise ValueError
    
    
    # check if weight path was passed via command line
    if options.input_weight_path:
        C.base_net_weights = options.input_weight_path
    else:
        # set the path to weights based on backend and model
        C.base_net_weights = nn.get_weight_path()
    
    all_imgs, classes_count, class_mapping = get_data(options.train_path)
    print(len(all_imgs)) #所有图片的信息,图片名称,位置等
    print(len(classes_count)) #dict,类别:数量,例如'chair': 1432
    print(len(class_mapping)) #dict,各个类别对应的标签向量,0-19,例如chair:0,car:1
    
    #再加入'背景'这个类别
    if 'bg' not in classes_count:
        classes_count['bg'] = 0
        class_mapping['bg'] = len(class_mapping)
    C.class_mapping = class_mapping
    
    # 将class_mapping中的key和value对调
    inv_map = {v: k for k, v in class_mapping.items()}
    
    print('Training images per class:')
    pprint.pprint(classes_count)
    print('Num classes (including bg) = {}'.format(len(classes_count)))
    
    config_output_filename = options.config_filename
    
    with open(config_output_filename, 'wb') as config_f:
        pickle.dump(C,config_f)
        print('Config has been written to {}, and can be loaded when testing to ensure correct results'.format(config_output_filename))
    
    # shuffle数据
    random.shuffle(all_imgs)
    
    num_imgs = len(all_imgs)
    # 将all_imgs分为训练集和测试集
    train_imgs = [s for s in all_imgs if s['imageset'] == 'trainval']
    val_imgs = [s for s in all_imgs if s['imageset'] == 'test']
    
    print('Num train samples {}'.format(len(train_imgs)))
    print('Num val samples {}'.format(len(val_imgs)))
    # 生成anchor
    data_gen_train = data_generators.get_anchor_gt(train_imgs, classes_count, C, nn.get_img_output_length, K.image_dim_ordering(), mode='train')
    # data_gen_train = data_generators.get_anchor_gt(train_imgs, classes_count, C, nn.get_img_output_length, K.image_dim_ordering(), mode='train')
    data_gen_val = data_generators.get_anchor_gt(val_imgs, classes_count, C, nn.get_img_output_length,K.image_dim_ordering(), mode='val')
    
    #查看后端是th还是tf,纠正输入方式
    if K.image_dim_ordering() == 'th':
        input_shape_img = (3, None, None)
    else:
        input_shape_img = (None, None, 3)
    
    img_input = Input(shape=input_shape_img)
    roi_input = Input(shape=(None, 4))
    
    # define the base network (resnet here, can be VGG, Inception, etc)
    #定义nn的输入层,还有faster rcnn共享卷积层
    shared_layers = nn.nn_base(img_input, trainable=True)
    print("shared_layers",shared_layers.shape)
    
    # define the RPN, built on the base layers
    #获取anchor的个数,3重基准大小快,3种比例框,3*3=9
    num_anchors = len(C.anchor_box_scales) * len(C.anchor_box_ratios)
    #定义rpn层,return [x_class, x_regr, base_layers]
    rpn = nn.rpn(shared_layers, num_anchors)
    
    classifier = nn.classifier(shared_layers, roi_input, C.num_rois, nb_classes=len(classes_count), trainable=True)
    
    #定义rpn模型的输入和输出一个框2分类(最后使用的sigmod而不是softmax)和框的回归
    model_rpn = Model(img_input, rpn[:2])
    #定义classifier的输入和输出
    model_classifier = Model([img_input, roi_input], classifier)
    
    # this is a model that holds both the RPN and the classifier, used to load/save weights for the models
    model_all = Model([img_input, roi_input], rpn[:2] + classifier)
    
    try:
        print('loading weights from {}'.format(C.base_net_weights))
        model_rpn.load_weights(C.base_net_weights, by_name=True)
        model_classifier.load_weights(C.base_net_weights, by_name=True)
    except:
        print('Could not load pretrained model weights. Weights can be found in the keras application folder \
            https://github.com/fchollet/keras/tree/master/keras/applications')
    
    optimizer = Adam(lr=1e-5)
    optimizer_classifier = Adam(lr=1e-5)
    model_rpn.compile(optimizer=optimizer, loss=[losses.rpn_loss_cls(num_anchors), losses.rpn_loss_regr(num_anchors)])
    model_classifier.compile(optimizer=optimizer_classifier, loss=[losses.class_loss_cls, losses.class_loss_regr(len(classes_count)-1)], metrics={'dense_class_{}'.format(len(classes_count)): 'accuracy'})
    model_all.compile(optimizer='sgd', loss='mae')
    
    epoch_length = 1000
    num_epochs = int(options.num_epochs)
    iter_num = 0
    
    losses = np.zeros((epoch_length, 5))
    rpn_accuracy_rpn_monitor = []
    rpn_accuracy_for_epoch = []
    start_time = time.time()
    
    best_loss = np.Inf
    
    class_mapping_inv = {v: k for k, v in class_mapping.items()}
    print('Starting training')
    
    vis = True
    
    for epoch_num in range(num_epochs):
    
        progbar = generic_utils.Progbar(epoch_length)
        print('Epoch {}/{}'.format(epoch_num + 1, num_epochs))
    
        while True:
            try:
    
                if len(rpn_accuracy_rpn_monitor) == epoch_length and C.verbose:
                    mean_overlapping_bboxes = float(sum(rpn_accuracy_rpn_monitor))/len(rpn_accuracy_rpn_monitor)
                    rpn_accuracy_rpn_monitor = []
                    print('Average number of overlapping bounding boxes from RPN = {} for {} previous iterations'.format(mean_overlapping_bboxes, epoch_length))
                    if mean_overlapping_bboxes == 0:
                        print('RPN is not producing bounding boxes that overlap the ground truth boxes. Check RPN settings or keep training.')
                print("生成data_gen_train")
                #X为经过最小边600的比例变换的原始图像,Y为[所有框位置的和类别(正例还是反例),所有框的前36层为位置和后36层(框和gt的比值)],img_data增强图像后的图像信息
                #那么RPN的reg输出也是比值
                X, Y, img_data = next(data_gen_train)
                print(X.shape,Y[0].shape,Y[1].shape)
    
                loss_rpn = model_rpn.train_on_batch(X, Y)
                print("loss_rpn",len(loss_rpn))
                print("loss_rpn0",loss_rpn[0])
                print("loss_rpn1",loss_rpn[1])
                print("loss_rpn2",loss_rpn[2])
    
                P_rpn = model_rpn.predict_on_batch(X)
    #           print("P_rpn_cls",P_rpn[0].reshape((P_rpn[0].shape[1],P_rpn[0].shape[2],P_rpn[0].shape[3]))[:,:,0])
                print("P_rpn_cls",P_rpn[0].shape)
                print("P_rpn_reg",P_rpn[1].shape)
    
                #获得最终选中的框
                R = roi_helpers.rpn_to_roi(P_rpn[0], P_rpn[1], C, K.image_dim_ordering(), use_regr=True, overlap_thresh=0.7, max_boxes=300)
    
                # note: calc_iou converts from (x1,y1,x2,y2) to (x,y,w,h) format
                #再对回归出来的框进行一次iou的计算,再一次过滤,只保留bg框和物体框
                #X2 from (x1,y1,x2,y2) to (x,y,w,h)
                #Y1为每个框对应类别标签,one-host编码
                #Y2为每个框和gt的比值,(x,x,160),前80表示框是否正确,后80为20个类别可能的框
                X2, Y1, Y2, IouS = roi_helpers.calc_iou(R, img_data, C, class_mapping)
                print("X2",X2.shape)
    #           print("X2_0",X2[0,0,:])
    #           print("X2_1",X2[0,1,:])
                print("Y1",Y1.shape)
                print("Y2",Y2.shape)
    
                if X2 is None:
                    rpn_accuracy_rpn_monitor.append(0)
                    rpn_accuracy_for_epoch.append(0)
                    continue
                #选出正例还是反例的index,背景的为反例,物体为正例
                neg_samples = np.where(Y1[0, :, -1] == 1)
                pos_samples = np.where(Y1[0, :, -1] == 0)
                print("neg_samples",len(neg_samples[0]))
                print("pos_samples",len(pos_samples[0]))
    
                if len(neg_samples) > 0:
                    neg_samples = neg_samples[0]
                else:
                    neg_samples = []
    
                if len(pos_samples) > 0:
                    pos_samples = pos_samples[0]
                else:
                    pos_samples = []
    
                rpn_accuracy_rpn_monitor.append(len(pos_samples))
                rpn_accuracy_for_epoch.append((len(pos_samples)))
                #num_rois=32,正例要求小于num_rois//2,其它全部由反例填充
                if C.num_rois > 1:
                    if len(pos_samples) < C.num_rois//2:
                        selected_pos_samples = pos_samples.tolist()
                        print("selected_pos_samples",len(selected_pos_samples))
                    else:
                        selected_pos_samples = np.random.choice(pos_samples, C.num_rois//2, replace=False).tolist()
                        print("selected_pos_samples",len(selected_pos_samples))
                    try:
                        selected_neg_samples = np.random.choice(neg_samples, C.num_rois - len(selected_pos_samples), replace=False).tolist()
                        print("selected_neg_samples",len(selected_neg_samples))
                    except:
                        selected_neg_samples = np.random.choice(neg_samples, C.num_rois - len(selected_pos_samples), replace=True).tolist()
                        print("selected_neg_samples",len(selected_neg_samples))
                    sel_samples = selected_pos_samples + selected_neg_samples
                else:
                    # in the extreme case where num_rois = 1, we pick a random pos or neg sample
                    selected_pos_samples = pos_samples.tolist()
                    selected_neg_samples = neg_samples.tolist()
                    if np.random.randint(0, 2):
                        sel_samples = random.choice(neg_samples)
                    else:
                        sel_samples = random.choice(pos_samples)
    
                print("sel_samples",len(sel_samples))
                print("sel_samples",sel_samples)
                loss_class = model_classifier.train_on_batch([X, X2[:, sel_samples, :]], [Y1[:, sel_samples, :], Y2[:, sel_samples, :]])
    #           P_classifier = model_classifier.predict([X, X2[:, sel_samples, :]])
    #           #[out_class, out_regr]
    #           print("P_classifier_out_class",P_classifier[0].shape)
    #           print("P_classifier_out_regr",P_classifier[1].shape)
    #           import cv2
    #           cv2.waitKey(0)
                losses[iter_num, 0] = loss_rpn[1]
                losses[iter_num, 1] = loss_rpn[2]
    
                losses[iter_num, 2] = loss_class[1]
                losses[iter_num, 3] = loss_class[2]
                losses[iter_num, 4] = loss_class[3]
    
                iter_num += 1
    
                progbar.update(iter_num, [('rpn_cls', np.mean(losses[:iter_num, 0])), ('rpn_regr', np.mean(losses[:iter_num, 1])),
                                          ('detector_cls', np.mean(losses[:iter_num, 2])), ('detector_regr', np.mean(losses[:iter_num, 3]))])
    
                if iter_num == epoch_length:
                    loss_rpn_cls = np.mean(losses[:, 0])
                    loss_rpn_regr = np.mean(losses[:, 1])
                    loss_class_cls = np.mean(losses[:, 2])
                    loss_class_regr = np.mean(losses[:, 3])
                    class_acc = np.mean(losses[:, 4])
    
                    mean_overlapping_bboxes = float(sum(rpn_accuracy_for_epoch)) / len(rpn_accuracy_for_epoch)
                    rpn_accuracy_for_epoch = []
    
                    if C.verbose:
                        print('Mean number of bounding boxes from RPN overlapping ground truth boxes: {}'.format(mean_overlapping_bboxes))
                        print('Classifier accuracy for bounding boxes from RPN: {}'.format(class_acc))
                        print('Loss RPN classifier: {}'.format(loss_rpn_cls))
                        print('Loss RPN regression: {}'.format(loss_rpn_regr))
                        print('Loss Detector classifier: {}'.format(loss_class_cls))
                        print('Loss Detector regression: {}'.format(loss_class_regr))
                        print('Elapsed time: {}'.format(time.time() - start_time))
    
                    curr_loss = loss_rpn_cls + loss_rpn_regr + loss_class_cls + loss_class_regr
                    iter_num = 0
                    start_time = time.time()
    
                    if curr_loss < best_loss:
                        if C.verbose:
                            print('Total loss decreased from {} to {}, saving weights'.format(best_loss,curr_loss))
                        best_loss = curr_loss
                        model_all.save_weights(C.model_path)
    
                    break
    
            except Exception as e:
                print('Exception: {}'.format(e))
                continue
    
    print('Training complete, exiting.')
    
    展开全文
  • faster RCNN(keras版本)代码讲解(1)-概述

    千次阅读 2018-07-11 17:22:28
    faster RCNN(keras版本)代码讲解博客索引: 1.faster RCNN(keras版本)代码讲解(1)-概述 2.faster RCNN(keras版本)代码讲解(2)-数据准备 3.faster RCNN(keras版本)代码讲解(3)-训练流程详情 4.faster RCNN(keras...
  • faster RCNN(keras版本)代码讲解博客索引: 1.faster RCNN(keras版本)代码讲解(1)-概述 2.faster RCNN(keras版本)代码讲解(2)-数据准备 3.faster RCNN(keras版本)代码讲解(3)-训练流程详情 4.faster RCNN(keras...
  • 图文+代码讲解spark-2.1.0集群搭建

    千次阅读 2017-04-26 15:44:40
    图文+代码讲解spark-2.1.0集群搭建
  • faster RCNN(keras版本)代码讲解博客索引: 1.faster RCNN(keras版本)代码讲解(1)-概述 2.faster RCNN(keras版本)代码讲解(2)-数据准备 3.faster RCNN(keras版本)代码讲解(3)-训练流程详情 4.faster RCNN(keras...
  • Rospy的官方教程代码讲解(四)服务

    千次阅读 2018-04-09 11:33:47
    Rospy的官方教程代码讲解(四)服务与参数 Rospy的官方教程代码讲解(四)服务与参数 服务 服务端 客户端 参数 日记性质的东西 服务 服务(services)是节点之间通讯的另一种方式。服务允许节点发送...
  • 前后端分离-根据代码讲解思路

    千次阅读 2018-10-21 19:08:50
    1.前面写过前后端分离相关文章 第一篇-为什么要前后端分离 https://blog.csdn.net/m0_37499059/article/details/82082534 第二篇-感受一下前后端分离... 2.根据代码讲解思路 用户登录时,生成一个token,并给toke...
  • faster RCNN(keras版本)代码讲解博客索引: 1.faster RCNN(keras版本)代码讲解(1)-概述 2.faster RCNN(keras版本)代码讲解(2)-数据准备 3.faster RCNN(keras版本)代码讲解(3)-训练流程详情 4.faster RCNN(keras...
  • faster RCNN(keras版本)代码讲解博客索引: 1.faster RCNN(keras版本)代码讲解(1)-概述 2.faster RCNN(keras版本)代码讲解(2)-数据准备 3.faster RCNN(keras版本)代码讲解(3)-训练流程详情 4.faster RCNN(keras...
  • 目标跟踪:相关滤波算法MOSSE实现代码讲解(视频) matlab代码,一行一行的讲解,一边讲解一边画图演示,还把代码和论文上公式一一对应。 用示例演示了为什么有必要对图像进行preprocess。 视频地址:...
  • SDR# (SDRSharp)代码讲解 (三)

    千次阅读 2017-12-31 23:07:04
    我认为前面讲的这几种类型的代码里,最重要的有两方面:一个是与硬件驱动交互的部分(这部分上一篇已经大致讲了,另外也可以参考我的另一个HackRF代码讲解系列,会找到很多类似的东西,只不过那里调用的libhackrf.so...
  • CUDA学习,第一个kernel函数及代码讲解。本博文分为三个部分,第一部分给出一个代码示例,第二部分对代码进行讲解,第三部分根据这个例子介绍如何部署和发起一个kernel函数。
  • 代码讲解 /* * 标题:Java中的异常捕获与处理 [入门级别] * 作者Nstar * 时间:2020年3月20号 * 程序中的异常分为“运行异常”和“已知异常” ,异常就像我们开车遇到了障碍物,要绕开一样 * 程序员在编写程序中,...
  • 安卓开发-Sqlite创建数据库实例(核心代码讲解
  • appium简单代码讲解

    千次阅读 2019-07-27 17:18:01
    Appium自动化 ...代码回顾: from appium import webdriver #webdriver是基于selenium扩展的一个对象 import time,traceback desired_caps = {} #存储一些配置信息,通过字典键值对来存。吧配置信息...
  • Android的xml布局文件代码讲解(TextView控件)
  • Rospy的官方教程代码讲解(三)获取订阅信息 这一篇会比较短,其实应该放在上一篇的最后,之后几个都是讲service的,所以想放在一起写。 Rospy的官方教程代码讲解三获取订阅信息 获取订阅信息 获取订阅...
  • Rospy的官方教程代码讲解(二)消息头和用户数据 刚刚发现的重大事实是ROS wiki里的rospy教程和github里rospy_tutorials代码是完全不同的 Σ(っ°Д°;)っ男默女泪啊 щ(゚Д゚щ) 我整个人都方了有木有。。。 先...
  • 一段动态生成表格的JSP代码讲解

    万次阅读 2015-11-02 14:29:09
    一段动态生成表格的JSP代码讲解 留言板 主题 内容 删除 messages=(ArrayList)session.getAttribute("messages"); if(messages!=null){ System.out.println(me
  • 简单LSTM代码讲解

    千次阅读 2018-12-16 17:24:32
    展开即可,用的少不详细讲解. Bi-LSTM搭建: 当然至少也分 tf.nn.static_bidirectional_rnn 和 tf.nn.bidirectional_dynamic_rnn() tf.nn.bidirectional_dynamic_rnn() batch_size = 5 time_step =...
  • DFS(小白式超详细讲解以及代码讲解)

    千次阅读 多人点赞 2019-12-02 22:02:10
    好了,最基础的理论知识我们已经了解完了,接下来我们要跟深一步了解这个算法,并写代码做题了 DFS算法思想:一直往深处走,直到找到解或者走不下去为止; 一般DFS使用 栈 保存未被检测的结点,结点深度优先的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 75,454
精华内容 30,181
关键字:

代码讲解