【目标检测】SSD+Tensorflow 300&512 配置详解
SSD_300_vgg和SSD_512_vgg weights下载链接【需要科学上网~】:
Model | Training data | Testing data | mAP | FPS |
---|---|---|---|---|
SSD-300 VGG-based | VOC07+12+COCO trainval | VOC07 test | 0.817 | - |
SSD-300 VGG-based | VOC07+12 trainval | VOC07 test | 0.778 | - |
SSD-512 VGG-based | VOC07+12+COCO trainval | VOC07 test | 0.837 | - |
我的csdn下载链接【没法科学上网的同学】:
ssd-512:https://download.csdn.net/download/qq_36396104/10792340
ssd-300:https://download.csdn.net/download/qq_36396104/10792337
ssd源码https://github.com/DengZhuangSouthRd/SSD-TinyObject/blob/master/COMMANDS.md
转自:https://blog.csdn.net/liuyan20062010/article/details/78905517
1. 搭建SSD框架,下载解压即可
2. 下载pascalvoc数据,自己的数据根据voc格式改写(图片的名称,不用拘泥于6位数字,其他命名也可以)
解压后不要混合在一个文件夹下,要生成三个,主要是利用训练集测试的文件夹,VOCtrainval用来训练,VOCtest用来测试。
VOCtrainval 中JPEGImage文件夹中仅是训练和验证的图片,Main文件夹中仅是trainval.txt, train.txt, val.txt
VOCtest中JPEGImage文件夹中仅是测试图片,Main文件夹中仅是test.txt.
3. 图片数据重命名为6位数字
python代码
import os class BatchRename():
# '''''
# 批量重命名文件夹中的图片文件 # '''
def __init__(self):
#我的图片文件夹路径horse
self.path = '/home/xxx/imagedata/image_xml' def rename(self):
filelist = os.listdir(self.path)
total_num = len(filelist)
i = 1
n = 6
for item in filelist:
if item.endswith('.jpg'):
n = 6 - len(str(i))
src = os.path.join(os.path.abspath(self.path), item)
dst = os.path.join(os.path.abspath(self.path), str(0)*n + str(i) + '.jpg')
try:
os.rename(src, dst)
print 'converting %s to %s ...' % (src, dst)
i = i + 1 except:
continue
print 'total %d to rename & converted %d jpgs' % (total_num, i) if __name__ == '__main__':
demo = BatchRename()
demo.rename()
3.标记数据
4.生成txt文件,train.txt, trainval.txt, test.txt, val.txt
python代码
import os
import random xmlfilepath=r'/home/xxx/subimage_xml_xiao'
saveBasePath=r"/home/xxx/txt" trainval_percent=0.7
train_percent=0.7
total_xml = os.listdir(xmlfilepath)
num=len(total_xml)
list=range(num)
tv=int(num*trainval_percent)
tr=int(tv*train_percent)
trainval= random.sample(list,tv)
train=random.sample(trainval,tr) print("train and val size",tv)
print("traub suze",tr)
ftrainval = open(os.path.join(saveBasePath,'Main/trainval.txt'), 'w')
ftest = open(os.path.join(saveBasePath,'Main/test.txt'), 'w')
ftrain = open(os.path.join(saveBasePath,'Main/train.txt'), 'w')
fval = open(os.path.join(saveBasePath,'Main/val.txt'), 'w') for i in list:
name=total_xml[i][:-4]+'\n'
if i in trainval:
ftrainval.write(name)
if i in train:
ftrain.write(name)
else:
fval.write(name)
else:
ftest.write(name) ftrainval.close()
ftrain.close()
fval.close()
ftest .close()
5. 将训练类别修改为和自己一样的
SSD-Tensorflow-master—>datasets—>pascalvoc_common.py
根据实际情况进行修改
VOC_LABELS = {
'none': (0, 'Background'),
'aeroplane': (1, 'Vehicle'),
'bicycle': (2, 'Vehicle'),
'bird': (3, 'Animal'),
'boat': (4, 'Vehicle'),
'bottle': (5, 'Indoor'),
'bus': (6, 'Vehicle'),
'car': (7, 'Vehicle'),
'cat': (8, 'Animal'),
'chair': (9, 'Indoor'),
'cow': (10, 'Animal'),
'diningtable': (11, 'Indoor'),
'dog': (12, 'Animal'),
'horse': (13, 'Animal'),
'motorbike': (14, 'Vehicle'),
'Person': (15, 'Person'),
'pottedplant': (16, 'Indoor'),
'sheep': (17, 'Animal'),
'sofa': (18, 'Indoor'),
'train': (19, 'Vehicle'),
'tvmonitor': (20, 'Indoor'),
}
6. 将图像数据转换为tfrecods格式
SSD-Tensorflow-master—>datasets—>pascalvoc_to_tfrecords.py 。。。然后更改文件的83行读取方式为’rb’)
修改读取图片的类型:修改如下两个地方
“image_format = b'JPEG'”
“filename = directory + DIRECTORY_IMAGES + name + '.jpg'”中 jpg 可以修改读取图片的类型
修改67行,可以修改几张图片转为一个tfrecords,如下图
在SSD-Tensorflow-master文件夹下创建tf_conver_data.sh
1 #!/bin/bash
2 #this is a shell script to convert pascal VOC datasets into tf-records only
3 #directory where the original dataset is stored
4
5 DATASET_DIR=/home/xxx/imagedata/VOCdevkit/VOC2007/ #VOC数据保存的文件夹(VOC的目录格式未改变)
6
7 #output directory where to store TFRecords files
8 OUTPUT_DIR=/home/xxx/imagedata/xingshizheng_tf #自己建立的保存tfrecords数据的文件夹
9
10 python3 ./tf_convert_data.py \
11 --dataset_name=pascalvoc \
12 --dataset_dir=${DATASET_DIR} \
13 --output_name=voc_2007_train \
14 --output_dir=${OUTPUT_DIR}
~
7. 训练模型
train_ssd_network.py修改第154行的最大训练步数,将None改为比如50000。(tf.contrib.slim.learning.training函数中max-step为None时训练会无限进行。)
train_ssd_network.py,网络参数配置,若需要改,再此文件中进行修改
修改如下图中的数字600,可以改变训练多长时间保存一次模型
需要修改的地方:
a. nets/ssd_vgg_300.py (因为使用此网络结构) ,修改87 和88行的类别
default_params = SSDParams(
img_shape=(300, 300),
num_classes=21, #根据自己的数据修改为类别+1
no_annotation_label=21, #根据自己的数据修改为类别+1
feat_layers=['block4', 'block7', 'block8', 'block9', 'block10', 'block11'],
feat_shapes=[(38, 38), (19, 19), (10, 10), (5, 5), (3, 3), (1, 1)],
anchor_size_bounds=[0.15, 0.90],
# anchor_size_bounds=[0.20, 0.90],
b. train_ssd_network.py,修改类别120行,GPU占用量,学习率,batch_size等
tf.app.flags.DEFINE_integer(
'num_classes', 21, 'Number of classes to use in the dataset.')
#根据自己的数据修改为类别+1
c eval_ssd_network.py 修改类别,66行
# =========================================================================== #
# Main evaluation flags.
# =========================================================================== #
tf.app.flags.DEFINE_integer(
'num_classes', 21, 'Number of classes to use in the dataset.') #根据自己的数据修改为类别+1
d. datasets/pascalvoc_2007.py 根据自己的训练数据修改整个文件
TRAIN_STATISTICS = {
'none': (0, 0),
'aeroplane': (238, 306), #238图片书, 306目标总数
'bicycle': (243, 353),
'bird': (330, 486),
'boat': (181, 290),
'bottle': (244, 505),
'bus': (186, 229),
'car': (713, 1250),
'cat': (337, 376),
'chair': (445, 798),
'cow': (141, 259),
'diningtable': (200, 215),
'dog': (421, 510),
'horse': (287, 362),
'motorbike': (245, 339),
'person': (2008, 4690),
'pottedplant': (245, 514),
'sheep': (96, 257),
'sofa': (229, 248),
'train': (261, 297),
'tvmonitor': (256, 324),
'total': (5011, 12608), //5011 为训练的图片书,12608为目标总数
}
TEST_STATISTICS = {
'none': (0, 0),
'aeroplane': (1, 1),
'bicycle': (1, 1),
'bird': (1, 1),
'boat': (1, 1),
'bottle': (1, 1),
'bus': (1, 1),
'car': (1, 1),
'cat': (1, 1),
'chair': (1, 1),
'cow': (1, 1),
'diningtable': (1, 1),
'dog': (1, 1),
'horse': (1, 1),
'motorbike': (1, 1),
'person': (1, 1),
'pottedplant': (1, 1),
'sheep': (1, 1),
'sofa': (1, 1),
'train': (1, 1),
'tvmonitor': (1, 1),
'total': (20, 20),
}
SPLITS_TO_SIZES = {
'train': 5011, #训练数据量
'test': 4952, #测试数据量
}
SPLITS_TO_STATISTICS = {
'train': TRAIN_STATISTICS,
'test': TEST_STATISTICS,
}
NUM_CLASSES = 20 #类别,根据自己数据的实际类别修改(不包含背景)
方案1 从vgg开始训练其中某些层的参数
# 通过加载预训练好的vgg16模型,对“voc07trainval+voc2012”进行训练
# 通过checkpoint_exclude_scopes指定哪些层的参数不需要从vgg16模型里面加载进来
# 通过trainable_scopes指定哪些层的参数是需要训练的,未指定的参数保持不变,若注释掉此命令,所有的参数均需要训练
DATASET_DIR=/home/doctorimage/kindlehe/common/dataset/VOC0712/
TRAIN_DIR=.././log_files/log_finetune/train_voc0712_20170816_1654_VGG16/
CHECKPOINT_PATH=../checkpoints/vgg_16.ckpt python3 ../train_ssd_network.py \
--train_dir=${TRAIN_DIR} \ #训练生成模型的存放路径
--dataset_dir=${DATASET_DIR} \ #数据存放路径
--dataset_name=pascalvoc_2007 \ #数据名的前缀
--dataset_split_name=train \
--model_name=ssd_300_vgg \ #加载的模型的名字
--checkpoint_path=${CHECKPOINT_PATH} \ #所加载模型的路径
--checkpoint_model_scope=vgg_16 \ #所加载模型里面的作用域名
--checkpoint_exclude_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block10,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_300_vgg/block10_box,ssd_300_vgg/block11_box \
--trainable_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block10,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_300_vgg/block10_box,ssd_300_vgg/block11_box \
--save_summaries_secs=60 \ #每60s保存一下日志
--save_interval_secs=600 \ #每600s保存一下模型
--weight_decay=0.0005 \ #正则化的权值衰减的系数
--optimizer=adam \ #选取的最优化函数
--learning_rate=0.001 \ #学习率
--learning_rate_decay_factor=0.94 \ #学习率的衰减因子
--batch_size=24 \
--gpu_memory_fraction=0.9 #指定占用gpu内存的百分比
方案2 : 从自己预训练好的模型开始训练(依然可以指定要训练哪些层)
(当你的模型通过vgg训练的模型收敛到大概o.5mAP的时候,可以进行这一步的fine-tune) # 通过加载预训练好的vgg16模型,对“voc07trainval+voc2012”进行训练
# 通过checkpoint_exclude_scopes指定哪些层的参数不需要从vgg16模型里面加载进来
# 通过trainable_scopes指定哪些层的参数是需要训练的,未指定的参数保持不变
DATASET_DIR=/home/doctorimage/kindlehe/common/dataset/VOC0712/
TRAIN_DIR=.././log_files/log_finetune/train_voc0712_20170816_1654_VGG16/
CHECKPOINT_PATH=./log_files/log_finetune/train_voc0712_20170712_1741_VGG16/model.ckpt-253287 python3 ../train_ssd_network.py \
--train_dir=${TRAIN_DIR} \ #训练生成模型的存放路径
--dataset_dir=${DATASET_DIR} \ #数据存放路径
--dataset_name=pascalvoc_2007 \ #数据名的前缀
--dataset_split_name=train \
--model_name=ssd_300_vgg \ #加载的模型的名字
--checkpoint_path=${CHECKPOINT_PATH} \ #所加载模型的路径
--checkpoint_model_scope=vgg_16 \ #所加载模型里面的作用域名
--checkpoint_exclude_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block10,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_300_vgg/block10_box,ssd_300_vgg/block11_box \
--trainable_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block10,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_300_vgg/block10_box,ssd_300_vgg/block11_box \
--save_summaries_secs=60 \ #每60s保存一下日志
--save_interval_secs=600 \ #每600s保存一下模型
--weight_decay=0.0005 \ #正则化的权值衰减的系数
--optimizer=adam \ #选取的最优化函数
--learning_rate=0.001 \ #学习率
--learning_rate_decay_factor=0.94 \ #学习率的衰减因子
--batch_size=24 \
--gpu_memory_fraction=0.9 #指定占用gpu内存的百分比
从自己训练的ssd_300_vgg模型开始训练ssd_512_vgg的模型
因此ssd_300_vgg中没有block12,又因为block7,block8,block9,block10,block11,中的参数张量两个网络模型中不匹配,因此ssd_512_vgg中这几个模块的参数不从ssd_300_vgg模型中继承,因此使用checkpoint_exclude_scopes命令指出。
因为所有的参数均需要训练,因此不使用命令--trainable_scopes
1 #/bin/bash
2 DATASET_DIR=/home/data/xxx/imagedata/xing_tf/train_tf/
3 TRAIN_DIR=/home/data/xxx/model/xing300512_model/
4 CHECKPOINT_PATH=/home/data/xxx/model/xing300_model/model.ckpt-60000 #加载的ssd_300_vgg模型
5 python3 ./train_ssd_network.py \
6 --train_dir=${TRAIN_DIR} \
7 --dataset_dir=${DATASET_DIR} \
8 --dataset_name=pascalvoc_2007 \
9 --dataset_split_name=train \
10 --model_name=ssd_512_vgg \
11 --checkpoint_path=${CHECKPOINT_PATH} \
12 --checkpoint_model_scope=ssd_300_vgg \
13 --checkpoint_exclude_scopes=ssd_512_vgg/block7,ssd_512_vgg/block7_box,ssd_512_vgg/block8,ssd_512_vgg/block8_box, ssd_512_vgg/block9,ssd_512_vgg/block9_box,ssd_512_vgg/block10,ssd_512_vgg/block10_box,ssd_512_vgg/block11,ssd_512_vgg/b lock11_box,ssd_512_vgg/block12,ssd_512_vgg/block12_box \
14 #--trainable_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block1 0,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_3 00_vgg/block10_box,ssd_300_vgg/block11_box \
15 --save_summaries_secs=28800 \
16 --save_interval_secs=28800 \
17 --weight_decay=0.0005 \
18 --optimizer=adam \
19 --learning_rate_decay_factor=0.94 \
20 --batch_size=16 \
21 --num_classes=4 \
22 -gpu_memory_fraction=0.8 \
另外由300转512后还需修改:
1. 首先修改ssd_vgg_512.py的训练类别
2.修改train_ssd_network.py的model_name
修改为ssd_512_vgg
3. 修改nets/np_methods.py
修改:将300改为512, 将类别改为自己数据的类别(+背景)
4. 修改preprocessing/ssd_vgg_preprocessing.py
修改:将300改为512
5. 修改ssd_notbook.ipynb
a 将文件中数字“300”改为“512”
其他修改可以参考:http://blog.csdn.net/liuyan20062010/article/details/78905517
方案3:从头开始训练自己的模型
# 注释掉CHECKPOINT_PATH,不提供初始化模型,让模型自己随机初始化权重,从头训练
# 删除checkpoint_exclude_scopes和trainable_scopes,因为是从头开始训练
# CHECKPOINT_PATH=./log_files/log_finetune/train_voc0712_20170712_1741_VGG16/model.ckpt-253287 python3 ../train_ssd_network.py \
--train_dir=${TRAIN_DIR} \ #训练生成模型的存放路径
--dataset_dir=${DATASET_DIR} \ #数据存放路径
--dataset_name=pascalvoc_2007 \ #数据名的前缀
--dataset_split_name=train \
--model_name=ssd_300_vgg \ #加载的模型的名字
#--checkpoint_path=${CHECKPOINT_PATH} \ #所加载模型的路径,这里注释掉
#--checkpoint_model_scope=vgg_16 \ #所加载模型里面的作用域名
--save_summaries_secs=60 \ #每60s保存一下日志
--save_interval_secs=600 \ #每600s保存一下模型
--weight_decay=0.0005 \ #正则化的权值衰减的系数
--optimizer=adam \ #选取的最优化函数
--learning_rate=0.00001 \ #学习率
--learning_rate_decay_factor=0.94 \ #学习率的衰减因子
--batch_size=32
8. 测试或验证
首先将测试数据转换为tfrecords
1 #!/bin/bash
2 #this is a shell script to convert pascal VOC datasets into tf-records only
3 #directory where the original dataset is stored
4
5 DATASET_DIR=/home/xxx/imagedata/VOCdevkit/VOC2007/ #VOC数据保存的文件夹(VOC的目录格式未改变)
6
7 #output directory where to store TFRecords files
8 OUTPUT_DIR=/home/xxx/imagedata/xingshizheng_tf #自己建立的保存tfrecords数据的文件夹
9
10 python3 ./tf_convert_data.py \
11 --dataset_name=pascalvoc \
12 --dataset_dir=${DATASET_DIR} \
13 --output_name=voc_2007_test \ #注意修改为test
14 --output_dir=${OUTPUT_DIR}
~
在SSD-Tensorflow-master文件夹下建立一个sh文件
#!/bin/bash
# This is the eval script.
DATASET_DIR=/home/xxx/voc2007_test_tfrecords/ #保存的转换为tfrcodes格式的数据
EVAL_DIR=/home/xxx/ssd_eval_log/ # Directory where the results are saved to
CHECKPOINT_PATH=/home/xxx/Downloads/SSD-Tensorflow-master/checkpoints/VGG_VOC0712_SSD_300x300_iter_120000.ckpt #换为自己训练的模型
python3 ./eval_ssd_network.py \
--eval_dir=${EVAL_DIR} \
--dataset_dir=${DATASET_DIR} \
--dataset_name=pascalvoc_2007 \
--dataset_split_name=test \
--model_name=ssd_300_vgg \
--checkpoint_path=${CHECKPOINT_PATH} \
--batch_size=1
9. 利用ssd_notebook.ipynb显示训练测试模型的结果
修改红框标注的位置,一个是修改为自己的模型所在的路径,另一个是修改为自己图片所在的路径
10. 注意
- –dataset_name=pascalvoc_2007 、–dataset_split_name=train、–model_name=ssd_300_vgg这三个参数不要自己随便取,在代码里,这三个参数是if…else…语句,有固定的判断值,所以要根据实际情况取选择
- TypeError: expected bytes, NoneType found SystemError: returned a result with an error set 这是由于CHECKPOINT_PATH定义的时候不小心多了个#号键,将输入给注释掉了,如果不想使用预训练的模型,需要将--checkpoint_path=${CHECKPOINT_PATH} \注释掉即可
- SSD有在VOC07+12的训练集上一起训练的,用一个笨一点的办法: pascalvoc_to_tfrecords.py文件中,改变SAMPLES_PER_FILES,减少输出tfrecord文件的个数,再修改tf_convert_data.py的dataset参数,记得将前后两次的输出名改变一下,前后两次转换的tfrecords放在同一个文件夹下,然后手工重命名。(这里由于只是验证论文的训练方法是否有效,所以没必要写这些自动化代码实现合并,以后要用自己的数据集训练的时候就可以写一些自动化脚本)
- 有时候运行脚本会报错,可能是之前依次运行导致显存占满。
- 从pyCharm运行时,如果模型保存路径里之前的模型未删除,将会报错,必须保证该文件夹为空。
- 在TRAIN_DIR路径下会产生四中文件: 1. checkpoint :文本文件,包含所有model.ckpt-xxxx,相当于是不同时间节点生成的所有ckpt文件的一个索引。 2. model.ckpt-2124.data-000000-of-000001:模型文件,保存模型的权重 3. model.ckpt-2124.meta: 图文件,保存模型的网络图 4. model.ckpt-2124.index : 这个没搞太清楚 5. graph.pbtxt: 用protobuf格式保存的模型的图
- error:Default MaxPoolingOp only supports NHWC,这有两种原因:1、你的电脑没有gpu(情况很少)2、你使用的tensorflow版本有问题,看看是不是使用了非gpu版的tensorflow,或者使用的虚拟环境没切换过来。
【目标检测】SSD+Tensorflow 300&512 配置详解的更多相关文章
- 第三十一节,目标检测算法之 Faster R-CNN算法详解
Ren, Shaoqing, et al. “Faster R-CNN: Towards real-time object detection with region proposal network ...
- 目标检测之Faster-RCNN的pytorch代码详解(模型准备篇)
十月一的假期转眼就结束了,这个假期带女朋友到处玩了玩,虽然经济仿佛要陷入危机,不过没关系,要是吃不上饭就看书,吃精神粮食也不错,哈哈!开个玩笑,是要收收心好好干活了,继续写Faster-RCNN的代码 ...
- 第三十节,目标检测算法之Fast R-CNN算法详解
Girshick, Ross. “Fast r-cnn.” Proceedings of the IEEE International Conference on Computer Vision. 2 ...
- 目标检测之Faster-RCNN的pytorch代码详解(模型训练篇)
本文所用代码gayhub的地址:https://github.com/chenyuntc/simple-faster-rcnn-pytorch (非本人所写,博文只是解释代码) 好长时间没有发博客了 ...
- 目标检测算法之Faster R-CNN算法详解
Fast R-CNN存在的问题:选择性搜索,非常耗时. 解决:加入一个提取边缘的神经网络,将候选框的选取交给神经网络. 在Fast R-CNN中引入Region Proposal Network(RP ...
- 目标检测算法之Fast R-CNN算法详解
在介绍Fast R-CNN之前我们先介绍一下SPP Net 一.SPP Net SPP:Spatial Pyramid Pooling(空间金字塔池化) 众所周知,CNN一般都含有卷积部分和全连接部分 ...
- 目标检测之Faster-RCNN的pytorch代码详解(数据预处理篇)
首先贴上代码原作者的github:https://github.com/chenyuntc/simple-faster-rcnn-pytorch(非代码作者,博文只解释代码) 今天看完了simple- ...
- 深度学习与CV教程(13) | 目标检测 (SSD,YOLO系列)
作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/37 本文地址:http://www.showmeai.tech/article-det ...
- sshd_config配置详解
sshd_config配置详解 名称 sshd_config - OpenSSH SSH 服务器守护进程配置文件 大纲 /etc/ssh/sshd_config 描述 sshd(8) 默认从 /etc ...
随机推荐
- 第二次作业:卷积神经网络 part 1
第二次作业:卷积神经网络 part 1 视频学习 数学基础 受结构限制严重,生成式模型效果往往不如判别式模型. RBM:数学上很漂亮,且有统计物理学支撑,但主流深度学习平台不支持RBM和预训练. 自编 ...
- Spring bean自定义命名策略(注解实现)
我们都知道项目后台开发是从 控制层——业务层——mybatis层,@Controller.@Service.@Mapper...等等注解可以将对象自动加载到bean容器中,还能实现相应的功能,使用起来 ...
- Java语言特性
Java的语言特性: 1.语法相对简单 2.面向对象 3.分布性 4.可移植性 5.安全性 6.健壮性 7.解释性 8.多线程 9.动态性与并发性 Java中的面向对象编程: 面向对象程序设计(Obj ...
- CI4框架应用五 - 加载视图
这节我们来看一下CI4框架中视图的加载, CI4中提供了几种方式加载视图. 1. 利用CI4框架提供的全局函数view(‘模板名’),如果需要传参数可以在第二个参数传一个数组 我们先修改一下之前定义的 ...
- JS click延迟解决方案
click延迟解决方案 移动端click事件会有300ms的延迟,原因是移动端屏幕双击会缩放页面 1.禁止缩放功能 浏览器禁用默认双击缩放行为去掉300ms的点击延迟 user-scalabl ...
- db2 创建function报错
create function fun_fw_sfyczy(pi_operunitid varchar(2)) returns varchar(2)LANGUAGE SQL BEGIN ATOMIC ...
- 题解 poj 3304
题目描述 线段和直线判交板子题 分析题目,如果存在这一条直线,那么过这条直线作垂线,一定有一条垂线穿过所有线段,否则不存在.题目转化为寻找一条直线与所有线段有交点. 直线线段判交方法: 1.先判断线段 ...
- Goland 生成可执行文件
Goland通过调用go build 生成可执行文件. 默认Goland是可以执行程序,但你找不到可执行文件. 你需要自定义配置文件. 创建go build配置文件 Run kind 选Directo ...
- 学长小清新题表之UOJ 14.DZY Loves Graph
学长小清新题表之UOJ 14.DZY Loves Graph 题目描述 \(DZY\)开始有 \(n\) 个点,现在他对这 \(n\) 个点进行了 \(m\) 次操作,对于第 \(i\) 个操作(从 ...
- you-get的一点修改
一直用you-get这个python写的开源软件下载一些视频网站的视频(主要是太烦不断插入的广告),最近看了点python,就对于自己觉得不够方便的地方,尝试修改.因为感觉他的github上提交修改建 ...