Elmo

ELMO在textClassifier中的应用

环境配置

Python版本为3.6
tensorflow版本为1.13

数据集

IMDB 电影影评

导入预训练模型

将optionFile,vocabFile,weightsFile,tokenEmbeddingFile的路径配置上,注意这里的embeddingSize的值要和ELMo的词向量的大小一致

数据预处理

1)将数据读取出来

2)根据训练集生成vocabFile文件

3)调用bilm文件夹中的dump_token_embeddings方法生成初始化的词向量表示,并保存为hdf5文件,文件中的键为"embedding"

4)固定输入数据的序列长度

5)分割成训练集和测试集

Batch数据生成

每一个epoch时,都要打乱数据集

模型构建

在这里输入的不再是词的索引表示的数据,而是动态生成了词向量的数据,因此inputX的维度是三维。另外在输入到Bi-LSTM之前,加一个全连接层,可以训练输入的词向量,否则就是将ELMo的词向量直接输入到Bi-LSTM中,而这样的词向量可能并不是最优的词向量。

class BiLSTMAttention(object):
""""""
def __init__(self, config):
    # 定义模型的输入
    self.inputX = tf.placeholder(tf.float32, [None, config.sequenceLength, config.model.embeddingSize],
                                 name="inputX")
    self.inputY = tf.placeholder(tf.float32, [None, 1], name="inputY")

    self.dropoutKeepProb = tf.placeholder(tf.float32, name="dropoutKeepProb")

    # 定义l2损失
    l2Loss = tf.constant(0.0)

    with tf.name_scope("embedding"):
        embeddingW = tf.get_variable(
            "embeddingW",
            shape=[config.model.embeddingSize, config.model.embeddingSize],
            initializer=tf.contrib.layers.xavier_initializer())

        reshapeInputX = tf.reshape(self.inputX, shape=[-1, config.model.embeddingSize])

        self.embeddedWords = tf.reshape(tf.matmul(reshapeInputX, embeddingW),
                                        shape=[-1, config.sequenceLength, config.model.embeddingSize])
        self.embeddedWords = tf.nn.dropout(self.embeddedWords, self.dropoutKeepProb)

    # 定义两层双向LSTM的模型结构
    with tf.name_scope("Bi-LSTM"):
        for idx, hiddenSize in enumerate(config.model.hiddenSizes):
            with tf.name_scope("Bi-LSTM" + str(idx)):
                # 定义前向LSTM结构
                lstmFwCell = tf.nn.rnn_cell.DropoutWrapper(
                    tf.nn.rnn_cell.LSTMCell(num_units=hiddenSize, state_is_tuple=True),
                    output_keep_prob=self.dropoutKeepProb)
                # 定义反向LSTM结构
                lstmBwCell = tf.nn.rnn_cell.DropoutWrapper(
                    tf.nn.rnn_cell.LSTMCell(num_units=hiddenSize, state_is_tuple=True),
                    output_keep_prob=self.dropoutKeepProb)

                # 采用动态rnn,可以动态的输入序列的长度,若没有输入,则取序列的全长
                # outputs是一个元祖(output_fw, output_bw),其中两个元素的维度都是[batch_size, max_time, hidden_size],fw和bw的hidden_size一样
                # self.current_state 是最终的状态,二元组(state_fw, state_bw),state_fw=[batch_size, s],s是一个元祖(h, c)
                outputs_, self.current_state = tf.nn.bidirectional_dynamic_rnn(lstmFwCell, lstmBwCell,
                                                                               self.embeddedWords, dtype=tf.float32,
                                                                               scope="bi-lstm" + str(idx))

                # 对outputs中的fw和bw的结果拼接 [batch_size, time_step, hidden_size * 2], 传入到下一层Bi-LSTM中
                self.embeddedWords = tf.concat(outputs_, 2)

    # 将最后一层Bi-LSTM输出的结果分割成前向和后向的输出
    outputs = tf.split(self.embeddedWords, 2, -1)

    # 在Bi-LSTM+Attention的论文中,将前向和后向的输出相加
    with tf.name_scope("Attention"):
        H = outputs[0] + outputs[1]

        # 得到Attention的输出
        output = self._attention(H, config)
        outputSize = config.model.hiddenSizes[-1]

    # 全连接层的输出
    with tf.name_scope("output"):
        outputW = tf.get_variable(
            "outputW",
            shape=[outputSize, 1],
            initializer=tf.contrib.layers.xavier_initializer())

        outputB = tf.Variable(tf.constant(0.1, shape=[1]), name="outputB")
        l2Loss += tf.nn.l2_loss(outputW)
        l2Loss += tf.nn.l2_loss(outputB)
        self.predictions = tf.nn.xw_plus_b(output, outputW, outputB, name="predictions")
        self.binaryPreds = tf.cast(tf.greater_equal(self.predictions, 0.5), tf.float32, name="binaryPreds")

    # 计算二元交叉熵损失
    with tf.name_scope("loss"):
        losses = tf.nn.sigmoid_cross_entropy_with_logits(logits=self.predictions, labels=self.inputY)
        self.loss = tf.reduce_mean(losses) + config.model.l2RegLambda * l2Loss

def _attention(self, H, config):
    """
    利用Attention机制得到句子的向量表示
    """
    # 获得最后一层LSTM的神经元数量
    hiddenSize = config.model.hiddenSizes[-1]

    # 初始化一个权重向量,是可训练的参数
    W = tf.Variable(tf.random_normal([hiddenSize], stddev=0.1))

    # 对Bi-LSTM的输出用激活函数做非线性转换
    M = tf.tanh(H)

    # 对W和M做矩阵运算,W=[batch_size, time_step, hidden_size],计算前做维度转换成[batch_size * time_step, hidden_size]
    # newM = [batch_size*time_step, 1],每一个时间步的输出由向量转换成一个数字
    newM = tf.matmul(tf.reshape(M, [-1, hiddenSize]), tf.reshape(W, [-1, 1]))

    # 对newM做维度转换成[batch_size, time_step]
    restoreM = tf.reshape(newM, [-1, config.sequenceLength])

    # 用softmax做归一化处理[batch_size, time_step]
    self.alpha = tf.nn.softmax(restoreM)

    # 利用求得的alpha的值对H进行加权求和,用矩阵运算直接操作
    r = tf.matmul(tf.transpose(H, [0, 2, 1]), tf.reshape(self.alpha, [-1, config.sequenceLength, 1]))

    # 将三维压缩成二维sequeezeR=[batch_size, hidden_size]
    sequeezeR = tf.squeeze(r)

    sentenceRepren = tf.tanh(sequeezeR)

    # 对Attention的输出可以做dropout处理
    output = tf.nn.dropout(sentenceRepren, self.dropoutKeepProb)

	return output
模型评估

AUC ACC

模型训练

动态的生成词向量表示,在session的全局下需要实例化BiLM模型,定义一个elmo的方法来动态的生成ELMO词向量

项目地址

https://github.com/siyuxin/NLP/tree/master/Elmo

参考

[1]https://github.com/allenai/bilm-tf
[2]https://allennlp.org/elmo
[3]https://github.com/siyuxin/textClassifier

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值