解读某语义角色标注的文章

我不生产代码,我只是代码的搬运工~
侵删!!!!!!!若有冒犯,立马删除。--------csdn小透明
原博文:click
针对论文:click
工作:
NO1:针对其中涉及问题记录所看到的较为赞的回答进行陈列~
NO2:带有注释的代码
1、反向传播(backpropagation 算法)图示。click
2、神经网络反向传播算法(过程及公式推导)难啃至极 / _ \ 。 click
3、神经网络中权值w和偏置b的作用。click
改变偏置的sigmoid图示。click
(两链接组合食用效果更佳)简单来说,权重w就是分割平面的方向(或理解为斜率),而偏置b就是将该平面进行左、右移动,以更好的拟合数据。
函数的梯度:带有方向的向量,函数在某点变化率最大的方向
4、自然语言处理使用RNN(使用Paddlefluid和tensorflow实现);梯度爆炸、梯度消失解释到位,赞!click
好博文都是通俗易懂的。(杰言杰语)
5、关于“门控循环神经网络单元”GRU(Gate Recurrent Unit)和LSTM(long-short term memory)的异同。click
6、softmax层(softmax函数),简言之:计算概率–>对号入座
7、索引数据结构:LoD。作用:不要求每个 mini-batch 中的序列数据必须保持长度一致,不再使用0进行填充。click
8、指数衰减学习率:exponential_decay
假设给定初始学习率learning_rate为0.1,学习率衰减率为0.1,decay_steps为10000。则随着迭代次数从1到10000,当前的学习率decayed_learning_rate慢慢的从0.1降低为0.1*0.1=0.01, 指数形式变化。click
9、维特比算法
利用动态规划的思想来求解概率最大路径(可理解为求图最短路径)。常用语HMM、CRF的预测、seq2seq模型概率。click
看完最后应用才算真正领会!

from __future__ import print_function

import math, os
import numpy as np
#安装paddlepaddle,环境为root
import paddle
import paddle.dataset.conll05 as conll05
import paddle.fluid as fluid
import six#兼容 Python 2 和 Python 3 的库
import time
import argparse
#-------------------------定义输入数据维度及模型超参数。--------------------------
with_gpu = os.getenv('WITH_GPU', '0') != '0'
#word_dict:输入句子的词典,共计44068个词;predicate_dict:谓词的词典,共计3162个词;label_dict:标记的词典,共计106个标记
word_dict, verb_dict, label_dict = conll05.get_dict()
word_dict_len = len(word_dict)
label_dict_len = len(label_dict)
pred_dict_len = len(verb_dict)
#定义输入数据维度及模型超参数。
mark_dict_len = 2    # 谓上下文区域标志的维度,是一个0-12值特征,因此维度为2
word_dim = 32        # 词向量维度
mark_dim = 5         # 谓词上下文区域通过词表被映射为一个实向量,这个是相邻的维度
hidden_dim = 512     # LSTM隐层向量的维度 : 512 / 4
depth = 8            # 栈式LSTM的深度
mix_hidden_lr = 1e-3 # linear_chain_crf层的基础学习率

IS_SPARSE = True     # 是否以稀疏方式更新embedding
PASS_NUM = 10        # 训练轮数
BATCH_SIZE = 10      # batch size 大小

embedding_name = 'emb'
#-------------------------------------------------------------------------------
def parse_args():
    parser = argparse.ArgumentParser("label_semantic_roles")#ArgumentParser:建立解析对象,生成实例:parse_args()
    #为实例增加属性
    #属性名前加‘--’,使其成为可选属性
    #属性均是自己命名
    #如果设置,则使用连续的评估日志运行任务
    parser.add_argument('--enable_ce',action='store_true',help="If set, run the task with continuous evaluation logs.")
    parser.add_argument( '--use_gpu', type=int, default=0, help="Whether to use GPU or not.")
    parser.add_argument('--num_epochs', type=int, default=100, help="number of epochs.")
    args = parser.parse_args(args=[])#此处‘args=[]’为本人新添加内容;创建实例
    return args

# ---------------------这里加载PaddlePaddle保存的二进制参数-----------------------
#用基于英文维基百科训练好的词向量来初始化序列输入、谓词上下文总共6个特征的embedding层参数,在训练中不更新。
#在大概219行train_loop方法中使用
def load_parameter(file_name, h, w):
    with open(file_name, 'rb') as f:
        f.read(16)  # skip header.
        return np.fromfile(f, dtype=np.float32).reshape(h, w)

#--------------------------------------------------------------------------------
#--------------------------------定义网络结构------------------------------------
def db_lstm(word, predicate, ctx_n2, ctx_n1, ctx_0, ctx_p1, ctx_p2, mark,**ignored):
    #----------------------------定义模型输入层--------------------------------------
    # 8 features
    #预训练谓词和谓词上下区域标志
    #embedding:分布式表示方法;distributed representation 用几个编码单元而不是一个编码单元来表示一个个体,是一类表示学习方法,
    #用一个更低维度的实向量表示“一个概念”将高度稀疏的离散输入嵌入到一个新的实向量空间,对抗维数灾难,使用更少的维度,编码更丰富的信息。
    #我们观测的不同离散变量都可以嵌入同一个实向量空间,得到统一的表达形式。embedding层主要的作用是词嵌套,即将词转换为对应的向量
    predicate_embedding = fluid.embedding(
        input=predicate,
        size=[pred_dict_len, word_dim],
        dtype='float32',
        is_sparse=IS_SPARSE,#是否使用稀疏更新的标志。
        param_attr='vemb')#图层参数

    mark_embedding = fluid.embedding(
        input=mark,
        size=[mark_dict_len, mark_dim],
        dtype='float32',
        is_sparse=IS_SPARSE)
    #句子序列和谓词上下文5个特征并预训练
    word_input = [word, ctx_n2, ctx_n1, ctx_0, ctx_p1, ctx_p2]
    # 因词向量是预训练好的,这里不再训练embedding表,
    # 参数属性trainable设置成False阻止了embedding表在训练过程中被更新
    emb_layers = [
        fluid.embedding(
            size=[word_dict_len, word_dim],
            input=x,
            param_attr=fluid.ParamAttr(name=embedding_name, trainable=False))
        for x in word_input
    ]
    #加入谓词和谓词上下区域标志的预训练结果
    emb_layers.append(predicate_embedding)
    emb_layers.append(mark_embedding)
    #--------------------------------------------------------------------------
    # --------------共有8LSTM单元被训练,每个单元的方向为从左到右或从右到左由参数`is_reverse`确定-------
    # 第一层栈结构
    #fc层,即全连接层,它的实质是矩阵乘法。通过反向传播算法获得梯度,通过梯度下降算法进行相应参数的更新
    #size全连接层输出单元的数目,即特征维度,应用于输出上的激活函数,如tanh、softmax、sigmoid,relu
    #fluid.layers.fc会自动生成该层对应的可学习参数(权重和偏置)
    hidden_0_layers = [
        fluid.layers.fc(input=emb, size=hidden_dim, act='tanh')
        for emb in emb_layers]
    #计算多个输入Tensor逐个元素相加的和
    #https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/layers_cn/sums_cn.html
    hidden_0 = fluid.layers.sums(input=hidden_0_layers)
    lstm_0 = fluid.layers.dynamic_lstm(
        input=hidden_0,
        size=hidden_dim,
        candidate_activation='relu',
        gate_activation='sigmoid',
        cell_activation='sigmoid')

    #用直连的边来堆叠L-LSTMR-LSTM
    input_tmp = [hidden_0, lstm_0]#隐层和lstm层
    # 其余的栈结构
    for i in range(1, depth):
        mix_hidden = fluid.layers.sums(input=[
            fluid.layers.fc(input=input_tmp[0], size=hidden_dim, act='tanh'),
            fluid.layers.fc(input=input_tmp[1], size=hidden_dim, act='tanh')
        ])

        lstm = fluid.layers.dynamic_lstm(
            input=mix_hidden,
            size=hidden_dim,
            candidate_activation='relu',
            gate_activation='sigmoid',
            cell_activation='sigmoid',
            is_reverse=((i % 2) == 1))

        input_tmp = [mix_hidden, lstm]
    # 取最后一个栈式LSTM的输出和这个LSTM单元的输入到隐层映射,经过一个全连接层映射到标记字典的维度,来学习 CRF 的状态特征
    feature_out = fluid.layers.sums(input=[
        fluid.layers.fc(input=input_tmp[0], size=label_dict_len, act='tanh'),
        fluid.layers.fc(input=input_tmp[1], size=label_dict_len, act='tanh')
    ])

    return feature_out
    #-----------------------------------------------------------------------
#------------------------------------------------------------------------------------------------------------
#--------------------开始训练------------------------------------------------
def train(use_cuda, save_dirname=None, is_local=True):
    #tensor:多维数组;神经网络的输入数据也是一个特殊的 Tensor;在这个 Tensor 中,
    #一些维度的大小在定义模型时无法确定,在定义模型时需要占位。
    #fluid.layers.data 来接收输入数据,需要提供输入 Tensor 的形状信息,
    #遇到无法确定(或可变)的维度时,相应维度指定为 None 或 -1,要在执行过程中才能知道
    #dtype='int64':有符号 64 位整数数据类型
    
    # 配置数据输入层
    
    # 句子序列
    word = fluid.data(
        name='word_data', shape=[None, 1], dtype='int64', lod_level=1)
    # 谓词
    predicate = fluid.data(
        name='verb_data', shape=[None, 1], dtype='int64', lod_level=1)
    # 谓词上下文5个特征
    ctx_n2 = fluid.data(
        name='ctx_n2_data', shape=[None, 1], dtype='int64', lod_level=1)
    ctx_n1 = fluid.data(
        name='ctx_n1_data', shape=[None, 1], dtype='int64', lod_level=1)
    ctx_0 = fluid.data(
        name='ctx_0_data', shape=[None, 1], dtype='int64', lod_level=1)
    ctx_p1 = fluid.data(
        name='ctx_p1_data', shape=[None, 1], dtype='int64', lod_level=1)
    ctx_p2 = fluid.data(
        name='ctx_p2_data', shape=[None, 1], dtype='int64', lod_level=1)
    # 谓词上下区域标志
    mark = fluid.data(
        name='mark_data', shape=[None, 1], dtype='int64', lod_level=1)

    if args.enable_ce:
        fluid.default_startup_program().random_seed = 90#default_startup_program():网络参数初始化
        fluid.default_main_program().random_seed = 90

    # 定义网络拓扑
    feature_out = db_lstm(**locals())#以字典类型返回当前位置的全部局部变量
    # 标注序列
    target = fluid.layers.data(
        name='target', shape=[1], dtype='int64', lod_level=1)
    # 学习 CRF 的转移特征
    crf_cost = fluid.layers.linear_chain_crf(
        input=feature_out,
        label=target,
        param_attr=fluid.ParamAttr(name='crfw', learning_rate=mix_hidden_lr))
    #损失函数采用均方差函数
    avg_cost = fluid.layers.mean(crf_cost)
    # 使用最基本的SGD优化方法(momentum设置为0)
    #确定损失函数后再通过前向计算得到损失值,然后通过链式求导法则得到参数的梯度值,再更新参数,最简单的算法是随机梯度下降法:w=w−η⋅g,
    sgd_optimizer = fluid.optimizer.SGD(
        #exponential_decay:指数衰减学习率
        learning_rate=fluid.layers.exponential_decay(
            learning_rate=0.01,
            decay_steps=100000,
            decay_rate=0.5,
            staircase=True))
    #minimize:非线性规划
    sgd_optimizer.minimize(avg_cost)
    #使用测试集训练供大家学习。conll05.test()每次产生一条样本,包含9个特征,shuffle和组完batch后作为训练的输入
    #解码。param_attr:指定权重参数属性的对象。
    crf_decode = fluid.layers.crf_decoding(
        input=feature_out, param_attr=fluid.ParamAttr(name='crfw'))
    #该接口是一个reader的装饰器。将输入reader的数据打包成指定的batch_size大小的批处理数据(batched data)。
    #训练数据:train_data
    if args.enable_ce:
        train_data = paddle.batch(
            paddle.dataset.conll05.test(), batch_size=BATCH_SIZE)
    else:
        train_data = paddle.batch(
            paddle.reader.shuffle(paddle.dataset.conll05.test(), buf_size=8192),
            batch_size=BATCH_SIZE)

    place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
    #使用DataFeeder传入训练/预测数据 
    feeder = fluid.DataFeeder(
        feed_list=[
            word, ctx_n2, ctx_n1, ctx_0, ctx_p1, ctx_p2, predicate, mark, target
        ],
        place=place)#place传入CPU还是GPU
    exe = fluid.Executor(place)
    #----------------------开始训练-----------------------
    def train_loop(main_program):
        exe.run(fluid.default_startup_program())#使用初始化的数据进行预训练
        embedding_param = fluid.global_scope().find_var(embedding_name).get_tensor()
        # conll05.get_embedding():基于维基百科语料库的训练词向量,只是一个文件路径
        embedding_param.set(load_parameter(conll05.get_embedding(), word_dict_len, word_dim),place)

        start_time = time.time()
        batch_id = 0
        for pass_id in six.moves.xrange(PASS_NUM):
            for data in train_data():
                cost = exe.run(main_program, feed=feeder.feed(data), fetch_list=[avg_cost])
                cost = cost[0]
                #每十组数据输出一次
                if batch_id % 10 == 0:#大约 30*10=300组数据,共输出30次avg_cost和 second per batch
                    print("avg_cost:" + str(cost))
                    if batch_id != 0:
                        print("second per batch: " + str((time.time() - start_time) / batch_id))
                    # 低阈值加速CI检测
                    if float(cost) < 60.0:
                        if args.enable_ce:
                            print("kpis\ttrain_cost\t%f" % cost)

                        if save_dirname is not None:
                            # TODO(liuyiqun): Change the target to crf_decode
                            fluid.io.save_inference_model(save_dirname, [
                                'word_data', 'verb_data', 'ctx_n2_data',
                                'ctx_n1_data', 'ctx_0_data', 'ctx_p1_data',
                                'ctx_p2_data', 'mark_data'
                            ], [feature_out], exe)
                        return

                batch_id = batch_id + 1
#----------------------------------------------------------------------------------------
    train_loop(fluid.default_main_program())
    
#---------------------------应用模型进行预测。---------------------------------------------------
#加载已训练好的模型进行预测。
def infer(use_cuda, save_dirname=None):
    if save_dirname is None:
        return
    #简单的选择测试集上标记错误最少的那个模型。
    place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
    exe = fluid.Executor(place)
    #同一个python文件中,出现 2个或2个以上模型时,为了防止环境变量的冲突,需要把后面的模型切换到另外一个作用域运行
    inference_scope = fluid.core.Scope()
    #scope_guard:加载训练好的模型
    with fluid.scope_guard(inference_scope):
        #使用fluid.io.load_inference_model加载inference_program,feed_target_names是模型的输入变量的名称,fetch_targets是预测对象。
        [inference_program, feed_target_names,fetch_targets] = fluid.io.load_inference_model(save_dirname, exe)

        #创建LoDTensor,索引数据结构,以避免为达到minibatch使用零进行填充
        lod = [[3, 4, 2]]
        base_shape = [1]
        # 构造假数据作为输入,整数随机数的范围是[low, high]
        word = fluid.create_random_int_lodtensor(
            lod, base_shape, place, low=0, high=word_dict_len - 1)
        pred = fluid.create_random_int_lodtensor(
            lod, base_shape, place, low=0, high=pred_dict_len - 1)
        ctx_n2 = fluid.create_random_int_lodtensor(
            lod, base_shape, place, low=0, high=word_dict_len - 1)
        ctx_n1 = fluid.create_random_int_lodtensor(
            lod, base_shape, place, low=0, high=word_dict_len - 1)
        ctx_0 = fluid.create_random_int_lodtensor(
            lod, base_shape, place, low=0, high=word_dict_len - 1)
        ctx_p1 = fluid.create_random_int_lodtensor(
            lod, base_shape, place, low=0, high=word_dict_len - 1)
        ctx_p2 = fluid.create_random_int_lodtensor(
            lod, base_shape, place, low=0, high=word_dict_len - 1)
        mark = fluid.create_random_int_lodtensor(
            lod, base_shape, place, low=0, high=mark_dict_len - 1)

        #构造feed字典 {feed_target_name: feed_target_data},results是由预测目标构成的列表
        assert feed_target_names[0] == 'word_data'
        assert feed_target_names[1] == 'verb_data'
        assert feed_target_names[2] == 'ctx_n2_data'
        assert feed_target_names[3] == 'ctx_n1_data'
        assert feed_target_names[4] == 'ctx_0_data'
        assert feed_target_names[5] == 'ctx_p1_data'
        assert feed_target_names[6] == 'ctx_p2_data'
        assert feed_target_names[7] == 'mark_data'
        #执行预测
        results = exe.run(
            inference_program,
            feed={
                feed_target_names[0]: word,
                feed_target_names[1]: pred,
                feed_target_names[2]: ctx_n2,
                feed_target_names[3]: ctx_n1,
                feed_target_names[4]: ctx_0,
                feed_target_names[5]: ctx_p1,
                feed_target_names[6]: ctx_p2,
                feed_target_names[7]: mark
            },
            fetch_list=fetch_targets,
            return_numpy=False)#result为对象
        #输出结果
        print(results[0].lod())#results[0]可以调用的函数有:lod、dim(9,109)、layout、dtype(float)、data
        np_data = np.array(results[0])
        print("results[0]: ",results[0])
        print("Inference Shape: ", np_data.shape)#shape即m*n的m、n,可以直接使用(.dim())函数

#-------------------------------------------------------------------------------------------------------
def main(use_cuda, is_local=True):
    if use_cuda and not fluid.core.is_compiled_with_cuda():
        return

    #训练得到的模型参数保存在文件中
    save_dirname = "label_semantic_roles.inference.model"
    train(use_cuda, save_dirname, is_local)
    infer(use_cuda, save_dirname)
#https://www.cnblogs.com/freewsf/p/10038320.html   ;可添加调试代码,使脚本模块既可以导入到别的模块中用,另外该模块自己也可执行。
if __name__ == '__main__':
    args = parse_args()#调用parse_args方法
    use_cuda = args.use_gpu#0
    PASS_NUM = args.num_epochs#100
    main(use_cuda)

到此为止~lui了。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值