日子系列数据的贮存和测算,统计laravel假数据填充步骤

by admin on 2019年2月4日
  1. 概念好模型 xxx.php
  2. 概念好数据变动的平整 database/factories/XxxlFactory.php
  3. 写入生成数据的代码,控制好转变的数码数目,对转移后的数额做出修改 database/seeds/XxxTableSeeder.php
  4. 注册

对数码做增查改删(CRUD)是交互式互连网利用的着力功效。对于用户,我们只提供了前三项操作;而对博文,四项操作我们的施用都要提供。

摘要: 什么是时刻连串数据   什么是光阴序列(提姆e
Series,以下简称时序)数据?从概念上来说,就是一串按时间维度索引的多少。用描述性的言语来分解怎么样是时序数据,简单的讲,就是那类数据描述了某个被测量的珍重点在一个时日范围内的各类时间点上的测量值。

日子系列数据的贮存和测算,统计laravel假数据填充步骤。本项目地址:caffe/ssd

(对于模型中隐藏 $hidden 的字段,需求利用 makeVisible()
方法来暂时平息 hidden, 放置写入数据库时出错)

创办博文的模型

如本体系第二片段所说的,博文应该有如下数据:

  • slug:为后端为每篇博文自动生成的独一字符串,用于数据库里的查询。假使你对这几个概念不熟知,请阅读这一维基百科页面
  • title:标题
  • body:大家的博客平台运用马克down编辑器,所以body里积存的是本篇博文的马克down文本
  • description:对本篇博文的一小段介绍
  • favoritesCount:得到的点赞数
  • tagList:标签列表
  • author:小编,为其公共音讯对象

大家先来为地方的数量新建Mongoose模式,并将其注册为可用的模子。新建models/Article.js文件,写入:

const mongoose = require('mongoose');
const uniqueValidator = require('mongoose-unique-validator');
const slug = require('slug');

const ArticleSchema = new mongoose.Schema({
  slug: {type: String, lowercase: true, unique: true},
  title: String,
  description: String,
  body: String,
  favoritesCount: {type: Number, default: 0},
  tagList: [{type: String}],
  author: {type: mongoose.Schema.Types.ObjectId, ref: 'User'}
}, {timestamps: true});

ArticleSchema.plugin(uniqueValidator, {message: 'is already taken'});

mongoose.model('Article', ArticleSchema);

犹如用户方式里平等,大家那里运用了mongoose-unique-validator来验证slug是绝无仅有的。

地方的代码已经导入了slug包。接下来,大家要定义一个新章程,使用那个包来生成博文slug。为了保险slug的唯一性,我们会在原题目生成的字符串后再添加多个随机字符。

ArticleSchema.plugin(uniqueValidator, {message: 'is already taken'});

// +++
ArticleSchema.methods.slugify = function() {
  this.slug = slug(this.title) + '-' + (Math.random() * Math.pow(36, 6) | 0).toString(36);
};
// +++

mongoose.model('Article', ArticleSchema);

如什么时候候调用那些主意呢?每当一篇新博文创设后要么是一篇已有博文的题目暴发变动后,往数据库保存的时候,大家需要调用这几个方法生成新的slug。

俺们能够借助Mongoose中间件来在上述的场合自动调用slugify方法。

models/Article.js加盟以下代码:

// +++
ArticleSchema.pre('validate', function (next) {
  if (!this.slug || this.isModified('title'))
    this.slugify();
  return next();
});
// +++

mongoose.model('Article', ArticleSchema);

slug的成形应该爆发在Mongoose检验数据从前,否则没有slug字段,检验必然战败。这也是地点代码中pre'validate'发挥的意思。

日子系列数据的贮存和测算,统计laravel假数据填充步骤。其余注意,那里回调函数中的this本着的是现阶段的博文对象;因而,定义Mongoose中间件时也无法用箭头函数。

最后,大家还索要加上一个办法,重临博文的JSON对象。不要忘了参预Mongoose自动创立的createAtupdateAt这两条数据。

// +++
ArticleSchema.methods.toJSONFor = function (user) {
  return {
    slug: this.slug,
    title: this.title,
    description: this.description,
    body: this.body,
    createdAt: this.createdAt,
    updatedAt: this.updatedAt,
    tagList: this.tagList,
    favoritesCount: this.favoritesCount,
    author: this.author.toProfileJSONFor(user)
  };
};
// +++

ArticleSchema.pre('validate', ...);

值得提议的是,author一行,大家用到了前边为用户模型定义的toProfileJSONFor(user)方法。

末段,大家需求在后端应用中运行方面的脚本,否则之后的中间件不可以选拔Article模型。

app.js文本里插足一行代码:

require('./models/User');
// +++
require('./models/Article');
// +++
require('./config/passport');

到此博文模型就创办完结了。我们接下去要做的就是丰裕增查改删博文的路由及相应的中间件。

如何是时间体系数据

SSD: Single Shot MultiBox Detector

By Wei
Liu,
Dragomir
Anguelov,
Dumitru
Erhan,
Christian
Szegedy,
Scott
Reed,
Cheng-Yang
Fu,
Alexander C. Berg.

为博文操作新建路由对象

跟之前的步调一样,大家率先要为博文的装有操作(其跟URL都将是/api/articles)新建一个Router对象。

新建文件/routes/api/articles.js,写入:

const router = require('express').Router();
const passport = require('passport');
const mongoose = require('mongoose');
const Article = mongoose.model('Article');
const User = mongoose.model('User');
const auth = require('../auth');

module.exports = router;

相同地,那个路由索要登记到API的主路由上。打开routes/api/index.js,加入:

router.use('/profiles', require('./profiles'));
// +++
router.use('/articles', require('./articles'));
// +++

路由对象建好了,也注册到主路由上了,接下去就该兑现具体的中间件了。

  什么是时间种类(提姆e
Series,以下简称时序)数据?从概念上的话,就是一串按时间维度索引的数量。用描述性的言语来分解如何是时序数据,简单来讲,就是那类数据描述了某个被测量的侧重点在一个光阴限定内的每个日子点上的测量值。
  对时序数据开展建模的话,会蕴藏几个至关主要片段,分别是:主体,时间点和测量值。套用那套模型,你会意识你在平凡工作生活中,无时无刻不在接触着那类数据。

简介

SSD是选用单个互连网开展物体检测任务的集合框架.
你可以采用本代码磨炼/评估物体检测任务. 越多细节请见 arXiv
paper
以及
slide.

bf88必发唯一官网 1

MultiBox

System VOC2007 test mAP FPS (Titan X) Number of Boxes Input resolution
Faster R-CNN (VGG16) 73.2 7 ~6000 ~1000 x 600
YOLO (customized) 63.4 45 98 448 x 448
SSD300* (VGG16) 77.2 46 8732 300 x 300
SSD512* (VGG16) 79.8 19 24564 512 x 512

bf88必发唯一官网 2

测试对照

Note: SSD300\ and SSD512* are the latest models. Current code should
reproduce these results.*

新建博文

新建博文的端点为POST /api/articles,而且只有登录的用户才能实施,所以须要身份验证。

routes/api/articles.js参加如下代码:

// +++
const loadCurrentUser = require('./user').loadCurrentUser;

const respondArticle = (req, res, next) => {
  return res.json({article: res.locals.article.otJSONFor(res.locals.res)});
}

router.post('/', auth.required, loadCurrentUser, (req, res, next) => {
  const article = new Article(req.body.article);
  article.author = res.locals.user;
  return article.save().then(() => {
    res.locals.article = article;
    return next();
  }).catch(next);
}, respondArticle);
// +++

module.exports = router;

假若您是一个股民,某只股票的股价就是一类时序数据,其记录着各种日子点该股票的股价。
一旦您是一个运维人士,监控数据是一类时序数据,例如对于机器的CPU的监控数据,就是记录着种种时刻点机器上CPU的实际消耗值。
  那一个世界是由数据整合的,在这些世界上存在的每个物体,每时每刻都在发出着数量。而对这么些数量的挖沙和使用,在那些时期,正在默默的变更人们的生活方法。例如通过可穿戴设备对民用健康的管住,就是经过配备源源采撷你的民用健康数据,例如心跳、体温等等,收集完数据后套用模型测算来评估你的健康度。
  假若您的视野和想象空间充分大,你会发现你可以挖掘并动用的数目充斥在您所生存的环境中。那么些可以发出多少的对象,会包含你的无绳电话机、小车、空调、冰橱等等。当前相比炎热的物联网的主题绪想,其实就是打造一个足以让所有物体生产数据并打通其价值的网络。而经过这些网络征集的多寡,就是百里挑一的时序数据。
  时序数据用于描述一个实体在历史的岁月维度上的动静变化新闻,而对于时序数据的解析,就是尝试了解并把控其变动的原理的长河。随着物联网、大数额和人工智能技术的进步,时序数据也呈一个发生式的提升。而为了更好的支撑那类数据的囤积和剖析,在市场上衍生出了丰富多彩的新生的数据库产品。那类数据库产品的讲明都是为驾驭决传统关系型数据库在时序数据存储和剖析上的阙如和短处,这类产品被联合归类为时序数据库。

目录

  1. 安装
  2. 预备
  3. 训练/评估
  4. 模型
  5. 全新的数据集

从URL中拿走博文slug

博文的查、改、删操作,都急需从数据库中通过其slug读取该博文的数额。就像上一讲获取用户名相同,大家可以在routes/api/articles.js中用router.param为路由定义一个拿走博文slug的参数中间件,如下:

// +++
router.param('slug', (req, res, next, slug) => {
  Article.findOne({slug})
    //.populate('author')
    .then(article => {
      if (!article)
        return res.status(404).json({errors: {slug: `no such slug: ${slug}`}});
      res.locals.article = article;
      return next();
    })
    .catch(next);
});
// +++

router.post('/', auth.required, loadCurrentUser, ...

每当该路由境遇的URL中有和:slug对应的局地时,Express就会调用上述中间件,把截取到的多寡传给第多少个参数slug,然后从数据库中读取相应的博文,存给res.locals.article如故重返404。

  从DB-Engines的数据库序列流行度趋势榜上得以看出,时序数据库(提姆e
Series DB)的流行度在最近的两年内,平素都是有限接济一个很高的拉长方向。
  接下去我会写几篇小说,分别来分析:
  1. 时序数据的基本概念,包括模型、特性和骨干的查询和拍卖操作。
  2. 多少个流行开源时序数据库的平底落成分析
  3. 阿里云表格存储(TableStore)的时序数据存储和计量解决方案

安装

  1. 下载代码。要是把Caffe克隆到目录$CAFFE_ROOT

  git clone https://github.com/weiliu89/caffe.git
  cd caffe
  git checkout ssd
  1. Build 代码. 按照 Caffe
    instruction
    安装
    必要的packages,然后build。

# 根据Caffe安装的方式修改Makefile.config。
cp Makefile.config.example Makefile.config
make -j8
# 确保include $CAFFE_ROOT/python到PYTHONPATH环境变量内.
make py
make test -j8
# 运行测试,可选   
make runtest -j8

翻开博文

端点为GET /api/articles/:slug,身份验证可有可无。

routes/api/articles.js中写入:

// +++
router.get('/:slug', auth.optional, loadCurrentUser, (req, res, next) => {
  res.locals.article.populate('author')
    .execPopulate()
    .then(() => next())
    .catch(next);
}, respondArticle);
// +++

Mongoose提供的populate()格局,允许一个文档(那里是个Article)读取关联的另一个文档(那里属于User)。

光阴连串数据的特征

预备

  1. 下载 fully convolutional reduced (atrous)
    VGGNet.
    假诺文件被下载到了$CAFFE_ROOT/models/VGGNet/目录

  2. 下载VOC2007和VOC2012数据集.
    对Pascal VOC数据集的简介:

    bf88必发唯一官网 3

    pascal_voc2012_detection_table.jpg

假设下载到了`$HOME/data/`目录

  # 下载数据.
  cd $HOME/data
  wget http://host.robots.ox.ac.uk/pascal/VOC/voc2012/VOCtrainval_11-May-2012.tar
  wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtrainval_06-Nov-2007.tar
  wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtest_06-Nov-2007.tar
  # 解压数据.
  tar -xvf VOCtrainval_11-May-2012.tar
  tar -xvf VOCtrainval_06-Nov-2007.tar
  tar -xvf VOCtest_06-Nov-2007.tar

VOC 二零零七年的数据分为VOCtrainval和VOCtest四个tar包,VOC
二零一二年的数量只有VOCtrainval一个tar包,如下

bf88必发唯一官网 4

VOC0712的三个tar包

解压后,2007和2012两年的多少在VOCdevkit目录的VOC2007VOC2012几个子目录中。每个子目录下,分别包涵了八个公文夹,分别是Annotations
ImageSets JPEGImages SegmentationClass 以及
SegmentationObject。对于SSD的Object义务,要求利用Annotations中的xml标注文件,ImagesSets/Main/目录中的trainval.txttest.txt,以及JPEGImages目录下的图像。

bf88必发唯一官网 5

VOC2007解压

bf88必发唯一官网 6

VOC2012解压后

  1. 创建LMDB文件.

  cd $CAFFE_ROOT
  # Create the trainval.txt, test.txt, and test_name_size.txt in data/VOC0712/
  ./data/VOC0712/create_list.sh
  # 如有必要,可以按需修改create_data.sh文件.
  # 编码trainval和test原始图像,生成lmdb文件:
  #   - $HOME/data/VOCdevkit/VOC0712/lmdb/VOC0712_trainval_lmdb
  #   - $HOME/data/VOCdevkit/VOC0712/lmdb/VOC0712_test_lmdb
  # and make soft links at examples/VOC0712/
  ./data/VOC0712/create_data.sh

变化的trainval.txt格式如图,文件内容是图像的路径和标注文件的路径,中间用空格分隔开:

bf88必发唯一官网 7

trainval.txt

生成的test_name_size.txt是测试图像的id heightwidth

bf88必发唯一官网 8

test_name_size.txt

末尾,生成trainval和test多少个lmdb数据库,分别用来陶冶和测试SSD模型。

bf88必发唯一官网 9

voc0712 trainval and test lmdbs

trainval LMDB

bf88必发唯一官网 10

trainval lmdb

同时,在.../caffe/examples/VOC0712/路线下保留了位置七个lmdb数据库的链接,截图如下:

bf88必发唯一官网 11

voc0712_lmdb_link

变动博文

端点是PUT /api/articles/:slug,身份验证是不可或缺的,请求体的数据会覆盖相应字段。其它,我们还需确保当前报到的用户必须是该博文的撰稿人,否则重临403。

routes/api/articles.js中写入:

// +++
const checkAuthor = (req, res, next) => {
  if (!res.locals.user.equals(res.locals.article.author))
    return res.status(403).json({errors: {user: 'not the author'}});
  return next();
};

router.put('/:slug', auth.required, loadCurrentUser, checkAuthor,
  (req, res, next) => {
    ['title', 'description', 'body'].forEach(propName => {
      if (!req.body.article.hasOwnProperty(propName)) return;
      res.locals.article[propName] = req.body.article[propName];
    });
    res.locals.article.save()
      .then(() => next())
      .catch(next);
  }, respondArticle);
// +++

module.exports = router;

  对于时序数据的特性的剖析,会从数量的写入、查询和储存那八个维度来演讲,通过对其性状的分析,来演绎对时序数据库的主干要求。

训练/评估

  1. 陶冶你自己的模子并评估.

# 创建模型定义文件并保存模型训练快照到如下路径:
#   - $CAFFE_ROOT/models/VGGNet/VOC0712/SSD_300x300/
# and job file, log file, and the python script in:
#   - $CAFFE_ROOT/jobs/VGGNet/VOC0712/SSD_300x300/
# 保存当前评估结果到:
#   - $HOME/data/VOCdevkit/results/VOC2007/SSD_300x300/
# 120K次迭代之后,应该可以达到77.*的mAP.
python examples/ssd/ssd_pascal.py

万一不乐意自己训练模型,可以在here下载预锻练好的模型.注意是用PASCAL
VOC数据集训练的。

透过分析ssd_pascal.py的源码,可以领略练习ssd模型需求几个文件输入,分别是
train_data = "examples/VOC0712/VOC0712_trainval_lmdb"
test_data = "examples/VOC0712/VOC0712_test_lmdb"
name_size_file = "data/VOC0712/test_name_size.txt"
pretrain_model = "models/VGGNet/VGG_ILSVRC_16_layers_fc_reduced.caffemodel"
label_map_file = "data/VOC0712/labelmap_voc.prototxt"
train_net_file = "models/VGGNet/VOC0712/SSD_300x300/train.prototxt"
test_net_file = "models/VGGNet/VOC0712/SSD_300x300/test.prototxt"
deploy_net_file = "models/VGGNet/VOC0712/SSD_300x300/deploy.prototxt"
solver_file = "models/VGGNet/VOC0712/SSD_300x300/solver.prototxt"

其中,train_datatest_data是后边成立的LMDB数据库文件,用于磨炼和测试模型。name_size_file是前面创设的测试图像集的图像id和size文件,用于模型的测试。pretrain_model是base
network部分(VGG_16的卷积层)的预练习参数。label_map_file保留的是实体的name和label的映照文件,用于陶冶和测试。那四个文本是事先都准备好的.

后边的多少个文件,train_net_file test_net_file
deploy_net_filesolver_file是在ssd_pascal.py剧本中依照模型定义和教练方针参数自动生成的。例如,train_net_file,也就是train.prototxt,生成语句是shutil.copy(train_net_file, job_dir),具体的代码片段如下:

# Create train net.
net = caffe.NetSpec()
net.data, net.label = CreateAnnotatedDataLayer(train_data, batch_size=batch_size_per_device,
        train=True, output_label=True, label_map_file=label_map_file,
        transform_param=train_transform_param, batch_sampler=batch_sampler)

VGGNetBody(net, from_layer='data', fully_conv=True, reduced=True, dilated=True,
    dropout=False)

AddExtraLayers(net, use_batchnorm, lr_mult=lr_mult)

mbox_layers = CreateMultiBoxHead(net, data_layer='data', from_layers=mbox_source_layers,
        use_batchnorm=use_batchnorm, min_sizes=min_sizes, max_sizes=max_sizes,
        aspect_ratios=aspect_ratios, steps=steps, normalizations=normalizations,
        num_classes=num_classes, share_location=share_location, flip=flip, clip=clip,
        prior_variance=prior_variance, kernel_size=3, pad=1, lr_mult=lr_mult)

# Create the MultiBoxLossLayer.
name = "mbox_loss"
mbox_layers.append(net.label)
net[name] = L.MultiBoxLoss(*mbox_layers, multibox_loss_param=multibox_loss_param,
        loss_param=loss_param, include=dict(phase=caffe_pb2.Phase.Value('TRAIN')),
        propagate_down=[True, True, False, False])

with open(train_net_file, 'w') as f:
    print('name: "{}_train"'.format(model_name), file=f)
    print(net.to_proto(), file=f)
shutil.copy(train_net_file, job_dir)
  1. 运用新型模型快照评估模型.

  # 如果你需要对训练的模型进行评估,执行脚本:
  python examples/ssd/score_ssd_pascal.py
  1. 动用webcam视频头测试模型. 注意: 按 <kbd>esc</kbd> 为止.

  # 连接webcam摄像头和预训练的模型进行演示,运行:
  python examples/ssd/ssd_pascal_webcam.py

Here
浮现了一个在
MSCOCO
数据集上操练的模型SSD500的示范视频.

  1. 查看
    examples/ssd_detect.ipynb
    或者
    examples/ssd/ssd_detect.cpp
    怎样利用ssd模型检测物体. 查看
    examples/ssd/plot_detections.py
    怎样绘制 ssd_detect.cpp的检测结果.

  2. bf88必发唯一官网,假定采纳其余数据集磨炼, 请参考data/OTHERDATASET 驾驭更加多细节.
    方今支撑COCO 和 ILSVRC2016数码集. 指出采纳
    examples/ssd.ipynb
    检查新的数据集是或不是相符要求.

除去博文

端点为DELETE /api/articles/:slug,需求身份验证,不须求请求体。同上,大家必要检查当前用户是不是该博文的小编。即便去除成功,大家回到状态码为204且无响应体的响应。

routes/api/articles.js中写入:

// +++
router.delete('/:slug', auth.required, loadCurrentUser, checkAuthor,
  (req, res, next) => {
    res.locals.article.remove()
      .then(() => res.sendStatus(204))
      .catch(next);
  });
// +++

module.exports = router;

到此,博文增查改删就整个落到实处了。

数量写入的风味

模型

在分化数额集上陶冶了模型以供下载. 为了复现杂文Table
6中的结果,
每个模型文件夹内都含有一个.caffemodel 文件, 几个.prototxt 文件,
以及python脚本文件.

  1. PASCAL VOC 模型:

    • 07+12:
      SSD300*,
      SSD512*
    • 07++12:
      SSD300*,
      SSD512*
    • COCO\[1\]:
      SSD300*,
      SSD512*
    • 07+12+COCO:
      SSD300*,
      SSD512*
    • 07++12+COCO:
      SSD300*,
      SSD512*
  2. COCO 模型:

    • trainval35k:
      SSD300*,
      SSD512*
  3. ILSVRC 模型:

    • trainval1:
      SSD300*,
      SSD500

写入平稳、持续、高并发高吞吐:时序数据的写入是相比较平静的,那一点与应用数据不一致,应用数据一般与利用的访问量成正比,而接纳的访问量平日存在波峰波谷。时序数据的发生寻常是以一个恒定的日子频率爆发,不会受其余因素的钳制,其数据变动的速度是相持比较平稳的。时序数据是由各样个体独立生成,所以当私家数量过多时,日常写入的出现和吞吐量都是比较高的,越发是在物联网场景下。写入并发和吞吐量,可以省略的经过个人数量和数码生成频率来总结,例若是你有1000个个体以10秒的成效暴发多少,则你平分每秒爆发的出现和写入量就是100。
写多读少:时序数据上95%-99%的操作都是写操作,是百里挑一的写多读少的数码。那与其数量特性相关,例如监控数据,你的监控项可能很多,不过你实在去读的也许相比少,平日只会关怀多少个特定的要紧目的或者在特定的场景下才会去读数据。
实时写入近期转变的数量,无更新:时序数据的写入是实时的,且每一趟写入都是近年来生成的数额,那与其数量变化的特色有关,因为其数额变动是随着时光推进的,而新生成的多寡会实时的进展写入。数据写入无更新,在岁月那几个维度上,随着时间的推波助澜,每回数据都是新数据,不会设有旧数据的革新,然而不消除人为的对数码做校对。

全新的数据集

在头里的训练/评估的首先有些,大家介绍了何等准备数据集:

  • dbname_trainval_lmdb
  • dbname_test_lmdb
  • test_name_size.txt
  • labelmap_dbname.prototxt
  • VGG_ILSVRC_16_layers_fc_reduced.caffemodel

崭新的多寡意味着差其他教练/测试图像,不一样的object name
label映射关系,不相同的网络模型定义参数。首先,大家必要按照新的图像数据集生成模型的输入部分,也就是下边的多少个文件。

  1. VGG_ILSVRC_16_layers_fc_reduced.caffemodel是预训练好的VGG_16的卷积层的参数,直接下载应用即可,那里不再介绍怎么样重新磨炼VGG_16分类模型。

  2. labelmap_dbname.prototxt是标注文件中object的name和label的投射文件,一般项目不会太多,直接编写此文件即可。例如,一个或者的映照文件:

    item {
      name: "none_of_the_above"
      label: 0
      display_name: "background"
    }
    item {
      name: "Car"
      label: 1
      display_name: "car"
    }
    item {
      name: "Bus"
      label: 2
      display_name: "bus"
    }
    item {
      name: "Van"
      label: 3
      display_name: "van"
    }
    ...
    
  3. test_name_size.txt文本保留了拥有测试图像的id height
    width信息,由create_list.sh剧本完结创建。通过分析create_list.sh剧本可领略,该脚本共创立了多个txt文件,分别是trainval.txt
    test.txtdbname_name_size.txt

    • trainval.txttest.txt中,每一行保存了图像文件的途径和图像标注文件的路径,中间以空格分开。片段如下:

    VOC2012/JPEGImages/2010_003429.jpg VOC2012/Annotations/2010_003429.xml
    VOC2007/JPEGImages/008716.jpg VOC2007/Annotations/008716.xml
    VOC2012/JPEGImages/2009_004804.jpg VOC2012/Annotations/2009_004804.xml
    VOC2007/JPEGImages/005293.jpg VOC2007/Annotations/005293.xml
    

    小心,trainval中的顺序是乱糟糟的,test中的顺序不必打乱。

    • test_name_size.txt文件是由.../caffe/get_image_size程序生成的,其源码位于.../caffe/tools/get_image_size.cpp中。那段程序的功能是依据test.txt中提供的测试图像的路线音讯和数目集根目录音讯(两段路径拼合得到图像的相对路径),自动测算每张图像的heightwidthget_image_size.cpp中的宗旨代码段为:

    // Storing to outfile
    boost::filesystem::path root_folder(argv[1]);
    std::ofstream outfile(argv[3]);
    if (!outfile.good()) {
      LOG(FATAL) << "Failed to open file: " << argv[3];
    }
    int height, width;
    int count = 0;
    for (int line_id = 0; line_id < lines.size(); ++line_id) {
      boost::filesystem::path img_file = root_folder / lines[line_id].first;
      GetImageSize(img_file.string(), &height, &width);
      std::string img_name = img_file.stem().string();
      if (map_name_id.size() == 0) {
        outfile << img_name << " " << height << " " << width << std::endl;
      } else {
        CHECK(map_name_id.find(img_name) != map_name_id.end());
        int img_id = map_name_id.find(img_name)->second;
        outfile << img_id << " " << height << " " << width << std::endl;
      }
    
      if (++count % 1000 == 0) {
        LOG(INFO) << "Processed " << count << " files.";
      }
    }
    // write the last batch
    if (count % 1000 != 0) {
      LOG(INFO) << "Processed " << count << " files.";
    }
    outfile.flush();
    outfile.close();
    

    保存到test_name_size.txt中的内容片段如下:

    000001 500 353
    000002 500 335
    000003 375 500
    000004 406 500
    000006 375 500
    000008 375 500
    000010 480 354
    

    现在,trainval.txt
    test.txttest_name_size.txt的内容已经很清晰了,可以选取现成的代码程序,适当修改图像数据集名称和路线就能够创立那多个文件。当然,也可以按照自己的编程喜好,重新编写脚本生成符合地点格式的txt文件即可。

  4. dbname_trainval_lmdb
    扭转该数据库文件的顺序为create_data.sh,其要旨代码是实施python脚本.../caffe/scripts/create_annoset.py,该脚本须求事先准备的
    labelmap_dbname.prototxttrainval.txt
    作为输入,以及多少个可配置项。
    .../caffe/scripts/create_annoset.py剧本的主导代码是实践.../caffe/build/tools/convert_annoset程序。labelmap_dbname.prototxt

    trainval.txt就是为convert_annoset次第准备的,其源码在.../caffe/tools/convert_annoset.cpp中。创制并写入数据库的基本代码片段如下:

// 创建一个新的数据库
scoped_ptr<db::DB> db(db::GetDB(FLAGS_backend));
db->Open(argv[3], db::NEW);
scoped_ptr<db::Transaction> txn(db->NewTransaction());

// 把数据存储到数据库
std::string root_folder(argv[1]);
AnnotatedDatum anno_datum;
Datum* datum = anno_datum.mutable_datum();
int count = 0;
int data_size = 0;
bool data_size_initialized = false;

for (int line_id = 0; line_id < lines.size(); ++line_id) {
  bool status = true;
  std::string enc = encode_type;
  if (encoded && !enc.size()) {
    // Guess the encoding type from the file name
    string fn = lines[line_id].first;
    size_t p = fn.rfind('.');
    if ( p == fn.npos )
      LOG(WARNING) << "Failed to guess the encoding of '" << fn << "'";
    enc = fn.substr(p);
    std::transform(enc.begin(), enc.end(), enc.begin(), ::tolower);
  }
  filename = root_folder + lines[line_id].first;
  if (anno_type == "classification") {
    label = boost::get<int>(lines[line_id].second);
    status = ReadImageToDatum(filename, label, resize_height, resize_width,
        min_dim, max_dim, is_color, enc, datum);
  } else if (anno_type == "detection") {
    labelname = root_folder + boost::get<std::string>(lines[line_id].second);
    status = ReadRichImageToAnnotatedDatum(filename, labelname, resize_height,
        resize_width, min_dim, max_dim, is_color, enc, type, label_type,
        name_to_label, &anno_datum);
    anno_datum.set_type(AnnotatedDatum_AnnotationType_BBOX);
  }
  if (status == false) {
    LOG(WARNING) << "Failed to read " << lines[line_id].first;
    continue;
  }
  if (check_size) {
    if (!data_size_initialized) {
      data_size = datum->channels() * datum->height() * datum->width();
      data_size_initialized = true;
    } else {
      const std::string& data = datum->data();
      CHECK_EQ(data.size(), data_size) << "Incorrect data field size "
          << data.size();
    }
  }
  // 序列化
  string key_str = caffe::format_int(line_id, 8) + "_" + lines[line_id].first;

  // 把数据Put到数据库
  string out;
  CHECK(anno_datum.SerializeToString(&out));
  txn->Put(key_str, out);

  if (++count % 1000 == 0) {
    // Commit db
    txn->Commit();
    txn.reset(db->NewTransaction());
    LOG(INFO) << "Processed " << count << " files.";
  }// end if
}//end for
// 写入最后一个batch的数据
if (count % 1000 != 0) {
  txn->Commit();
  LOG(INFO) << "Processed " << count << " files.";
}

那段代码中最根本的一行是对ReadRichImageToAnnotatedDatum()办法的调用,将图像文件和标注音信一起写入到了anno_datum变量中,再种类化,提交到数据库缓存区,缓存到自然数量的记录后四遍性写入数据库。

ReadRichImageToAnnotatedDatum()措施由Caffe提供,是caffe/src/util/io.cpp中定义的一个措施,该方法及其其调用的ReadImageToDatum方法和GetImageSize格局源码如下:

bool ReadImageToDatum(const string& filename, const int label,
    const int height, const int width, const int min_dim, const int max_dim,
    const bool is_color, const std::string & encoding, Datum* datum) {
  cv::Mat cv_img = ReadImageToCVMat(filename, height, width, min_dim, max_dim,
                                    is_color);
  if (cv_img.data) {
    if (encoding.size()) {
      if ( (cv_img.channels() == 3) == is_color && !height && !width &&
          !min_dim && !max_dim && matchExt(filename, encoding) ) {
        datum->set_channels(cv_img.channels());
        datum->set_height(cv_img.rows);
        datum->set_width(cv_img.cols);
        return ReadFileToDatum(filename, label, datum);
      }
      EncodeCVMatToDatum(cv_img, encoding, datum);
      datum->set_label(label);
      return true;
    }
    CVMatToDatum(cv_img, datum);
    datum->set_label(label);
    return true;
  } else {
    return false;
  }
}

void GetImageSize(const string& filename, int* height, int* width) {
  cv::Mat cv_img = cv::imread(filename);
  if (!cv_img.data) {
    LOG(ERROR) << "Could not open or find file " << filename;
    return;
  }
  *height = cv_img.rows;
  *width = cv_img.cols;
}

bool ReadRichImageToAnnotatedDatum(const string& filename,
    const string& labelfile, const int height, const int width,
    const int min_dim, const int max_dim, const bool is_color,
    const string& encoding, const AnnotatedDatum_AnnotationType type,
    const string& labeltype, const std::map<string, int>& name_to_label,
    AnnotatedDatum* anno_datum) {
  // Read image to datum.
  bool status = ReadImageToDatum(filename, -1, height, width,
                                 min_dim, max_dim, is_color, encoding,
                                 anno_datum->mutable_datum());
  if (status == false) {
    return status;
  }
  anno_datum->clear_annotation_group();
  if (!boost::filesystem::exists(labelfile)) {
    return true;
  }
  switch (type) {
    case AnnotatedDatum_AnnotationType_BBOX:
      int ori_height, ori_width;
      GetImageSize(filename, &ori_height, &ori_width);
      if (labeltype == "xml") {
        return ReadXMLToAnnotatedDatum(labelfile, ori_height, ori_width,
                                       name_to_label, anno_datum);
      } else if (labeltype == "json") {
        return ReadJSONToAnnotatedDatum(labelfile, ori_height, ori_width,
                                        name_to_label, anno_datum);
      } else if (labeltype == "txt") {
        return ReadTxtToAnnotatedDatum(labelfile, ori_height, ori_width,
                                       anno_datum);
      } else {
        LOG(FATAL) << "Unknown label file type.";
        return false;
      }
      break;
    default:
      LOG(FATAL) << "Unknown annotation type.";
      return false;
  }
}

可以见到在地点的形式中继承调用了io.cpp中的七个艺术ReadFileToDatumReadXMLToAnnotatedDatum,分别把图像和图像的标注XML写入到了anno_datum中。其中,图像保存到了anno_datummutable_datum中,XML标注音信被封存到了anno_datumanno_group->anno->bbox中,anno_group还保留了label等信息。

  1. dbname_test_lmdb
    4.dbname_trainval_lmdb
  2. 使用examples/ssd.ipynb核准上边生成的公文的没错

\[1\]We use
examples/convert_model.ipynb
to extract a VOC model from a pretrained COCO model.

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图