实验室休息

2018/07/22 超级热

Posted by WangXiaoDong on July 22, 2018
    今天周日,我一早就出门吃早饭,发现昨天经过一夜的大雨,今天的天气凉爽了一点,看了去实验室应该
不会太热,因此我就去实验室,然后就把一周学到的代码再次复习一遍,不知不觉一天就过去了,晚上理个发
然后休息休息吧~

今天继续总结本周学习到的知识:

周四周五

库函数调研

在成功得到序列的预测模型后,面临一个输入显示结果的情况,因此我决定使用树的数据结构进行操作。 然后使用一种工具进行绘制。

Treelib

库函数使用

既然选择好了使用的库函数,接下来就是将结果实践一下。

Treelib

为了进行树的数据结构的时候,我首先在github上面检索tree structure,最后得到了一个代码:Treelib代码

该代码我直接下载,然后通过python 安装,之后阅读了一下文档, 发现了一些测试的例子:

>>> from treelib import Node, Tree
>>> tree = Tree()
>>> tree.create_node("Harry", "harry")  # root node
>>> tree.create_node("Jane", "jane", parent="harry")
>>> tree.create_node("Bill", "bill", parent="harry")
>>> tree.create_node("Diane", "diane", parent="jane")
>>> tree.create_node("Mary", "mary", parent="diane")
>>> tree.create_node("Mark", "mark", parent="jane")
>>> tree.show()
Harry
├── Bill
└── Jane
    ├── Diane
    │   └── Mary
    └── Mark

很明显,该库的使用非常简单,仅仅使用create_node就可以随意的增加节点,因此直接使用该函数就可以顺利的增加节点了。然后我所需要 的效果就是能够随时增加子叶节点,仔细观察该函数tree.create_node(tag[, identifier[, parent[, data]]])发现参数中有一个tag是 标签,还有一个identifier是非常重要的,因为以后如果想要索引到节点,必须使用 tree.children(nid)函数,里面传入的nid就是 标签的意思,说明文档里面也说明了节点的nid是唯一表示符。因此我在生成新的id的时候,首先使用tree.size()得到现在树中的节点 数目,然后就直接增加一个即可当成现在新生成的节点id。生成新节点的递归函数如下所示。

def genChildren(tree,nid,before_list,next_n,depth,pro_threshold):  #tree树,nid当前节点的id,before_list包含到当前节点的序列
#    print('预测到列表%s'%before_list)    
    if len(before_list) > depth :    #如果深度超过指定深度,则退出函数
        return
    pred = model.prediction_next_n(before_list,converter.vocab_size,next_n)
    pro_com = 0
    pred.reverse()
    for tup in pred:
        new_nid = str(tree.size()+1)
        tree.create_node(converter.int_to_word_table[tup[0]],
                     new_nid,
                     nid,
                     OpData(converter.int_to_word_table[tup[0]],tup[0],'%.2f%%'%(tup[1]*100)))
        new_before_list = before_list.copy()  #一定要拷贝
        if converter.int_to_word_table[tup[0]] != endToken: #如果当前不是结尾,则继续调用递归函数进行预测
            new_before_list.append(tup[0])
            genChildren(tree,new_nid,new_before_list,next_n,depth,pro_threshold)   #递归调用本身函数
        pro_com = pro_com + tup[1]
        if pro_com > pro_threshold:   #如果大于给定阈值则返回
            return

上面的递归函数就生成了我需要的树

注意,为了保存节点内部内容和传递概率,我自定义一个类来存储相关数据:

class OpData(object):
    def __init__(self, op,opNum,probability): 
            self.op = op
            self.opNum = opNum
            self.probability = probability

Graphviz

Graphviz是开放源码图形可视化软件。 图形可视化是一种将结构信息表示为抽象图形和网络图的方法。它在网络、生物信息学、软件工程、数据库和 网页设计、机器学习以及其他技术领域的可视化界面中都有重要的应用。

实际上它有固定的语法,根据固定的语法,该工具就可以生成对应的图像。比如:

在使用的时候,我们需要安装两个工具graphvizpython-graphviz 第一个工具安装好后可以在相应的文件下找到dot命令,我们只要使用该命令就可以编译上述语法的文件变成 pdf或者png之类的图像数据。因此要把这个命令的路径加入到环境变量Path里面,以便让系统能够找到这个命令的位置! 第二个工具是一个python库,用来通过编程语言生成绘图的语法,可以实现自动化。 下面就是我自动生成一个任意树的代码:

def drawChildren(dot,tree,nid):
    for child_node in tree.children(nid):
        child_nid = child_node.identifier
        dot.node(child_nid,str(child_node.data.opNum))
        dot.edge(nid,child_nid,child_node.data.probability)
        drawChildren(dot,tree,child_nid)

上面的递归函数就绘制出来了树的图像。

最终加载数据生成外加绘制代码

if __name__ == '__main__':
    startToken = 'start(开始)'
    endToken = 'end(结尾)'
    n_seqs = 10
    n_steps = 100
    model_path = os.path.join('model', 'behavior')
    checkpoint_path = model_path
    with open(os.path.join(model_path,'allData.pkl'),'rb') as f:   #读取所有数据
        allData = pickle.load(f) 
    with open(os.path.join(model_path,'testData.pkl'),'rb') as f:  #读取测试数据
        testData = pickle.load(f)
    with open(os.path.join(model_path,'trainData.pkl'),'rb') as f:  #读取测试数据
        trainData = pickle.load(f)
    converter = read_utils.TextConverter(allData)  #要用所有数据编码
    
    if os.path.isdir(checkpoint_path):
        checkpoint_path =\
            tf.train.latest_checkpoint(checkpoint_path)

    model = model.CharRNN(converter.vocab_size,sampling=True,
                    num_seqs=n_seqs,
                    num_steps=n_steps,
                    # lstm_size=FLAGS.lstm_size,
                    # num_layers=FLAGS.num_layers,
                    # learning_rate=FLAGS.learning_rate,
                    # train_keep_prob=FLAGS.train_keep_prob,
                    use_embedding=True,
                    # embedding_size=FLAGS.embedding_size
                    )
    model.load(checkpoint_path)   #读取权重
    
#    position = model.prediction_next_n([5],converter.vocab_size,3)
    
    #下面开始建立一个树
    tree = Tree()
    #创建第一个节点
    tree.create_node(startToken,
                     str(tree.size()+1),
                     data=OpData(startToken,converter.word_to_int_table[startToken],'100%')) #(tag[, identifier[, parent[, data]]])
    
    #tree,nid,before_list  下面开始递归的绘制所有节点!
    nid = str(tree.size())
    before_list = [converter.word_to_int_table[startToken]]
    next_n = 3   #设置预测步数
    depth = 50  #设置树的深度
    pro_threshold = 0.5    #设置显示阈值数目
    #开始函数
    if len(before_list) > depth:
#        return
        pass
    pred = model.prediction_next_n(before_list,converter.vocab_size,next_n)
    pred.reverse()
    pro_com = 0
    for tup in pred:
        new_nid = str(tree.size()+1)
        tree.create_node(converter.int_to_word_table[tup[0]],
                     new_nid,
                     nid,
                     OpData(converter.int_to_word_table[tup[0]],tup[0],'%.2f%%'%(tup[1]*100)))
        new_before_list = before_list.copy()  #一定要拷贝
        if converter.int_to_word_table[tup[0]] != endToken: #如果当前不是结尾,则继续调用递归函数进行预测
           new_before_list.append(tup[0])
           genChildren(tree,new_nid,new_before_list,next_n,depth,pro_threshold)  #递归调用生成树
        pro_com = pro_com + tup[1]
        if pro_com > pro_threshold:
            break
        
    #下面开始绘制这颗树
    dot = Digraph(comment='The Test Table')     
    dot.node(nid, str(tree.get_node(nid).data.opNum))
    #dot,tree,nid下面开始递归的绘制所有图像
    for child_node in tree.children(nid):
        child_nid = child_node.identifier
        dot.node(child_nid,str(child_node.data.opNum))
        dot.edge(nid,child_nid,child_node.data.probability)
        drawChildren(dot,tree,child_nid)
    
    dot.render('test-output/test-table.gv', view=True)