python的单元测试和文档测试模块

unittest模块

用法炒鸡简单,基本用法如下

#!/usr/bin/env python  
#encoding: utf-8  
import unittest

def sum(x, y):
    return x+y

class TestFunc(unittest.TestCase):
    def setUp(self):
        pass
    def tearDown(self):  
        pass

    def test_sum_3_4(self):
        self.assertEqual(sum(3,4), 7)

    def test_sum_3_4_NE6(self):
        self.assertNotEqual(sum(3,4), 6)

    @unittest.expectedFailure
    def test_sum_3_4_EF(self):
        self.assertEqual(sum(3,4), 6)


if __name__ == '__main__':
    unittest.main()
    1. 首先引入 unittest 模块
    2. 定义 TestCase 类,类的 setUp 和 tearDown 函数按需使用,比如测试的一个类的话,在 setUp 中可实例化出一个被测类供测试函数使用,然后再写一堆 test_xxx 函数即可。
    3. 最后,main 模块中使用 unittest.main() 启动整个测试即可。
    4. 自动寻找文件夹中所有的单元测试文件并执行它python -m unittest discover -s ut_dir

doctest模块

doctest模块主要用于对文档字符串写的用法示例进行测试。

怎么写可以进行doctest的示例代码呢?直接实例吧

#!/usr/bin/env python  
#encoding: utf-8  

def sum( x, y):
    """sum function.
    
    Example:
    >>> sum(3,4)
    7
    """
    return x+y

if __name__ == '__main__':
    import doctest
    doctest.testmod()

直接运行这个py文件,嗯,啥结果也没有看见,那就对了,说明doctest通过了。doctest默认是不显示任何结果的,除非使用-v参数:python myfile.py -v 就可以看到doctest执行过程和结果了。

另外,doctest还提供了unittest API以方便unittest直接把doctest一块执行了。
只需要再测试模块中定义个`load_tests()`函数即可

def load_tests(loader, tests, ignore):
    tests.addTests(doctest.DocTestSuite())
    return tests

这般以后,unittest.main()会把doctest也一块给做了。

python正则表达式总结

match/search会缓存最近的对象

re.compile返回的是一个正则表达式对象。
下面两种方式等效,在使用正则较少的情况下不用太担心直接使用re.match的性能问题,因为match/search会缓存最近的对象。

pat = re.compile(pattern)
result = pat.match(string)
# is equivalent to
result = re.match(pattern, string)

re对象的方法

Method/Attribute Purpose
match() Determine if the RE matches at the beginning of the string.
search() Scan through a string, looking for any location where this RE matches.
findall() Find all substrings where the RE matches, and returns them as a list.
finditer() Find all substrings where the RE matches, and returns them as an iterator.

matchsearch在没有找到匹配时返回None,找到时返回match object。

match object的方法

Method/Attribute Purpose
group() Return the string matched by the RE
start() Return the starting position of the match
end() Return the ending position of the match
span() Return a tuple containing the (start, end) positions of the match

match还是search?还是find*?

match只检查字符串从0位置开始是否符合,而search则会搜索整个字符串。
search只搜索自一次匹配,而findall则会搜索完整个字符串提供所有匹配。

贪婪和非贪婪方式

*,+,?等都是贪婪方式。但是后面加个?号改为匹配尽可能少的字符,即*?,+?,??,{m,n}?

标识

Flag Meaning
DOTALL, S Make . match any character, including newlines
IGNORECASE, I Do case-insensitive matches
LOCALE, L Do a locale-aware match
MULTILINE, M Multi-line matching, affecting ^ and $
VERBOSE, X Enable verbose REs, which can be organized more cleanly and understandably.
UNICODE, U Makes several escapes like \w, \b, \s and \d dependent on the Unicode character database.

一些定位元字符

Metacharacter Meaning
| or
^ 行首
$ 行位
\A 字符串首
\Z 字符串尾
\b 单词边界
\B 非单词边界

group分组

group()group(0)是匹配串,group(n)[n>0]是第n个子分组, group(L,m,n)可以接受多个index返回元祖,groups()返回所有匹配子组。

非捕获组(?:…)和命名组(?P…)

非捕获组不能后向引用了,比如只需要单词或的匹配但是又不想捕获它时。
(...)\1使用序号后向引用,(?P<name>...)(?P=name)后向引用命名组。

Lookahead Assertions

(?=...)确定性断言,(?!...)否定性断言。

简单分支判断

(?(id/name)yes-pattern|no-pattern)提供一个简单的分支判断,如果id/name组存在匹配,就检索匹配yes-pattern,否则检索匹配no-pattern,否定项可选可省略。

git中的各种后悔药

FAQ 常用后悔药


工作区的代码想撤销: git checkout <file name>
add到暂存区的代码想撤销: git reset HEAD [<file name>]
提交到本地仓库的代码想撤销: git reset --hard <版本号>
把刚刚的提交撤回到暂存区: git reset --soft HEAD~1
revert某修改: git revert <id>
回滚后反悔怎么办?: git reflog 记录了我们的每一次命令( commit、merge 等信息), 根据这命令来查出我们的历史 commit id,然后 git reset即可
另外,git rebase -i也可以撤销之前的提交。 edit修改,drop丢弃,squash合并压缩

修改历史提交中的用户和邮箱

修改已提交的某一次的信息, 这个使用git rebasegit commit --amend 配合一步一步完成修改。
修改git全部已提交的用户名和邮箱 , 此方案直接全部过滤修改的方式,方便快捷。

删除分支、远程跟踪分支和远程分支

https://stackoverflow.com/questions/2003505/how-do-i-delete-a-git-branch-both-locally-and-remotely?rq=1

# Deleting a remote branch,删除远程分支
git push origin --delete <branch>  # Git version 1.7.0 or newer
git push origin :<branch>          # Git versions older than 1.7.0
 
# Deleting a local branch,删除本地分支
git branch --delete <branch>
git branch -d <branch> # Shorter version
git branch -D <branch> # Force delete un-merged branches
 
# Deleting a local remote-tracking branch,删除本地的远程跟踪分支
git branch --delete --remotes <remote>/<branch>
git branch -dr <remote>/<branch> # Shorter
# only deleted his local remote-tracking branch origin/bugfix, and not the actual remote branch bugfix on origin
# 注:只会删除本地分支对应的远程跟踪分支,不会删除远程服务器上的分支

git fetch <remote> --prune # Delete multiple obsolete tracking branches
git fetch <remote> -p      # Shorter

# delete local tag
git tag -d <tagname>
# delete remote tag
git push origin :tagname #1
git push --delete origin tagname #2
git push origin :refs/tags/<tagname> #3 

建立空的新分支

这里以github的操作为例,创建一个名为gh-pages的空分支

# 创建一个独立的orphan的分支
git checkout --orphan gh-pages

# 删除原来的所有文件
git rm -rf .

注意这个时候你用git branch命令是看不见当前分支的名字的,除非你进行了一次commit。

caffe的输入层总结

来自图片:ImageDataLayer

最简单的输入方式,适用于分类任务,输入就是一个文件文件,而文本文件每行就是一个图片保存路径名称和它的数值标签即可。如果图片都已以文件夹或文件名保存了,可以非常容易地使用lsawk sed等命令建立其要求的文件文件。

来自LMDB或LevelDB数据库:DataLayper

每个条目记录值就是一个Datum,具体代码中就是使用datum.ParseFromString(cursor_->value())获取的。

但是原始的Datum只有一个data项和一个label项和可供使用的float_data项(直接保存的浮点数数据替代bytes表示的data)。如果您的输入数据除了图片还有别的,想自己新写输入层,除了使用这个float_data项外,您可以使用我pCaffe,对Datum定义了扩展条目,可以通过设置扩展字段的方式增加别的data条目。

来自HDF5数据文件:HDF5DataLayer

HDF5数据层参数中不能包含transform参数,不支持数据的图像预处理,直接拷贝数据使用。如果数据确实需要预处理,可以在其后增加reshape crop等层。

来自内存:MemoryDataLayer

每个batch开始前,数据必须使用MemoryDataLayer::Reset方法将内存地址传给网络,caffe会免拷贝地使用它。

自动切图:WindowData

主要是根据窗口定义文件自动地切图贴标签,与基准窗口overlap大于阈值的设为前景窗,否则设为背景窗。 窗口文件里可根据每张图手工控制这些指标,比如可以通过增大小样本类的窗口数以平衡样本不均衡现象。

DummyDataLayer

DummyData有Filler参数,设置来可以自动根据需要填充数据,在构建测试代码时相当好用。

InputLayer

这层参数只有shape,一般仅用于deploy网络中。替代旧式的位于网络参数中的input_shape参数。

PythonLayer

python层用来书写自定义数据的输入层是相当方便的。比如py-faster-rcnn就使用python层来搞定 GroundTruth BoundingBox 的输入。

支持动态并行和源码级plugins的Caffe——pCaffe

支持动态并行和源码级plugins的Caffe——pCaffe

https://github.com/wadefelix/caffe

特性:

  1. 开启了 CUDA Dynamic Parallelism 特性,在 Makefile.config 定义 CUDA_DYNAMIC_PARALLEL := 1 即可。
  2. 支持源码级别的代码 plugins 以支持开发新层等代码,每个新插入的层放置在 src/caffe/plugins 目录下单独的子目录中,方便交流新代码。
  3. plugins 目录已放置了 fast_rcnnSSD 的代码可供使用和参考。
    该 fast_rcnn 所有层均是caffe移植,无需python,且每个minibatch支持多张图,并且实践应用了 CUDA Dynamic Parallelism 特性。

继续阅读支持动态并行和源码级plugins的Caffe——pCaffe

linux上的任务

jobs, bg, fg 命令

jobs列出本会话所有任务
bg命令用于将作业放到后台运行,使前台可以执行其他任务。该命令的运行效果与在指令后面添加符号&的效果是相同的,都是将其放到系统后台执行。 Ctrl+Z后任务会暂停,bg命令可以让任务在后台继续运行。
fg命令用于将后台作业(在后台运行的或者在后台挂起的作业)放到前台终端运行。与bg命令一样,若后台任务中只有一个,则使用该命令时,可以省略任务号。

让进程在后台可靠运行的几种方法

技巧:让进程在后台可靠运行的几种方法

nohup ping www.ibm.com &
setsid ping www.ibm.com
(ping www.ibm.com &)
# disown 命令
# screen 命令
[/bash]

如何将正在运行的任务放入后台

使用& nohup启动的命令直接被放入后台,但是如果忘记输入&,或者你还要注销登录这次会话时,怎么办?
:第一步,Ctrl+Z把任务暂停,然后 bg %jobnumber 把任务放入后台运行。
若想在切回前台,使用fg %jobnumber 即可。

第二步,disown可以让任务忽略本任务的hangup信号。只放入后台的任务而不是使用nohup启动的,它也是要接受本会话的hangup的。
disown "%./experiments/scripts/faster_rcnn_end2end.sh"

其他知识

disown是bash内部命令,nohup是外部命令
disownbg,fg一样是针对job进行操作,nohup是针对命令操作
disown -hnohup一样,在退出bash后,把进程的控制权都交给init

其他用于管理用户会话的命令:
tty 列出本会话会话号
w 列出当前所有登录会话
skillpkill 可以给任务发信号, 如 skill -KILL -v pts/4 把会话pts/4的所有任务发kill信号。

更强大的是使用screen管理会话,但是ubuntu默认没有安装该程序,此命令网上知识也很多。

挂载指定标签的磁盘到指定挂载点

按标签挂载挂载保证同样标签的磁盘挂载都同一个地方。

/etc/fstab内容

# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# 把LABEL是MYDATADISK的磁盘挂载到/home/renwei/datadisk目录
LABEL=MYDATADISK /home/renwei/datadisk ext4 defaults 0 2

磁盘的LABEL怎么管理?

1 命令 e2label 或者tune2fs
Usage:

e2label device [newlabel]
tune2fs -L labelname /dev/your_block_device

2 ubuntu系统的disks工具(图形界面)
“Edit Filesystem…” 就是更改磁盘LABEL的,只不过ubuntu这里这名字取的无语。

使用WQL获取硬件信息

WQL(SQL for WMI),就是用SQL语法来查询硬件信息,简单吧。

示例代码:Example: Getting WMI Data from the Local Computer,示例的是查询操作系统名称,你也可以查询磁盘信息等等,具体能查什么,那就去Win32 Provider这儿查就行了。

获取硬件信息有什么用?

制作软件授权系统啊,让客户端发来采集的硬件信息,我们把这些硬件信息和授权信息一块用私钥签名一下发给客户端,客户端只需要用携带的公钥验证下签名就可以知道授权文件是否合法。比注册串码系统简单好用多了。

加密、解密、签名和验证签名

tensorflow几个简单tips

tensorboard

# default port 6006, use `--port=xxxx` to specify port 
tensorboard --logdir=/path/to/logdir
# or
python ~/.local/lib/python2.7/site-packages/tensorflow/tensorboard/tensorboard.py --logdir=/path/to/logdir

对于keras,有内容callback能记录日志支持

    tb = keras.callbacks.TensorBoard(log_dir='/path/to/logdir', histogram_freq=0, batch_size=32, write_graph=True, write_grads=False,
                                write_images=False, embeddings_freq=0, embeddings_layer_names=None,
                                embeddings_metadata=None)
    callbacks.append(tb)

设置使用的GPU

shell终端命令执行程序时设置使用的GPU

CUDA_VISIBLE_DEVICES=1 python my_training_script.py

2 python代码中设置使用的GPU

import os
os.environ["CUDA_VISIBLE_DEVICES"] = "2"

设置tensorflow使用的显存大小

定量(定比例)设置显存

默认tensorflow是使用GPU尽可能多的显存。可以通过下面的方式,来设置使用的GPU显存:

gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.7)
sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options))

上面分配给tensorflow的GPU显存大小为:GPU实际显存*0.7。
可以按照需要,设置不同的值,来分配显存。

按需设置显存

上面的只能设置固定的大小。如果想按需分配,可以使用allow_growth参数(参考网址:http://blog.csdn.net/cq361106306/article/details/52950081):

gpu_options = tf.GPUOptions(allow_growth=True)
sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options))

tensorflow models

tensorflow models 提供的object_detection/export_inference_graph.py会生成frozen_inference_graph.pbmodel.ckptsaved_model.pb
ckpt的data保存了weights,meta保存了graph和metatada。 仅从.ckpt-meta.ckpt-data中就可以恢复出模型。pb文件一个文件就包含graph和data。
生产环境中进行预测的时候是只需要模型和权重,不需要metadata,所以需要将其提出进行freeze操作,将所需的部分放到一个文件,方便之后的调用,也减少模型加载所需的内存。(在下载的预训练模型解压后可以找到4个文件,其中名为frozen_inference_graph.pb的文件就是freeze后产生的模型文件,比weights文件大,但是比weights和meta文件加起来要小不少。)
tensorflow目标检测模型的压缩和ncnn转换
Tensorflow物体检测(Object Detection)API的使用

 

mantisBT和git集成

mantisBT上的设置


注:我使用的是cgit提供git库的web服务。

git hook内容

repositories/dockertrain.git/hooks/post-receive 文件内容

#!/bin/sh
API_KEY=6dcde9b4c68c4507f68b6ec3
# Repository ID
ID=20
CURL=/usr/bin/curl
URL="http://localhost/mantis/plugin.php?page=Source/import&amp;api_key=${API_KEY}&amp;id=${ID}"
${CURL} ${URL}

API_KEY 在MantisBT插件配置页面Source Control Integration: Configuration获取或设置。