发表于 | 分类于

蒙特卡洛法求积分

如果我们要求解一个函数 $h(x)$ 的积分,我们可以将积分分解成如下的形式:

$\int h(x)dx = \int f(x)p(x)dx$

于是,函数h(x)的积分可以表示为函数f(x)关于概率密度函数p(x)的数学期望,我们只需要取f(x) = h(x)/p(x)。

求解积分举例

求解积分$\int_0^1x^2dx$

解:另 p(x) = 1,表示0-1上的均匀分布,$f(x) = x^2$

求解代码:

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np

def calc_res(values):
res = 0
for one_value in values:
res += one_value * one_value
res = res / len(values)
return res

for i in [100, 1000, 10000, 100000, 1000000]:
res = np.random.uniform(0, 1, i)
print(calc_res(res))

结果:
0.3097443410375912
0.33154677188274595
0.3363434070471736
0.33119288078816694
0.33372059640184654

发表于 | 分类于

Bert Pretraining代码刨析

本篇文章结合实际例子对bert pretraining源码进行刨析,更清晰的展现bert的整个过程。pretraining主要包括三个文件,create_pretraining_data.py, run_pretraining.py, modeling.py。

create_pretraining_data

构造pretraining的训练数据,我们使用的数据(chg_data)是周杰伦的四句歌词

1
2
3
4
5
素胚勾勒出青花笔锋浓转淡转淡
瓶身描绘的牡丹一如你初妆初妆

冉冉檀香透过窗心事我了然了然
宣纸上走笔至此搁一半一半

构造训练数据的代码如下:

1
2
3
4
5
6
7
8
9
10
CUDA_VISIBLE_DEVICES=3 python create_pretraining_data.py \
--input_file=./chg_data \
--output_file=./tmp/tf_examples.tfrecord \
--vocab_file=$BERT_BASE_DIR/vocab.txt \
--do_lower_case=True \
--max_seq_length=128 \
--max_predictions_per_seq=20 \
--masked_lm_prob=0.15 \
--random_seed=12345 \
--dupe_factor=5

下面对create_pretraining_data的代码进行一下解析。首先,create_training_instances函数读取chg_data数据,根据空行,将数据分成两个文档,如下所示。

1
[[['素', '胚', '勾', '勒', '出', '青', '花', '笔', '锋', '浓', '转', '淡'], ['瓶', '身', '描', '绘', '的', '牡', '丹', '一', '如', '你', '初', '妆']], [['冉', '冉', '檀', '香', '透', '过', '窗', '心', '事', '我', '了', '然'], ['宣', '纸', '上', '走', '笔', '至', '此', '搁', '一', '半']]]

create_training_instances中的关键代码如下,功能是将数据进行拆分,构造sentence/next_sentence对

1
2
3
4
5
6
7
# 构造多组first_sen & next_sen对,并对数据进行mask
for _ in range(dupe_factor):
for document_index in range(len(all_documents)):
instances.extend(
create_instances_from_document(
all_documents, document_index, max_seq_length, short_seq_prob,
masked_lm_prob, max_predictions_per_seq, vocab_words, rng))

最终生成的数据instance如下,并将数据写入tf_examples.tfrecord,用于之后的pertaining。当然这是命中80%概率进行mask的情况。

1
2
3
4
5
tokens : [CLS] [MASK] 胚 勾 勒 出 青 花 [MASK] 锋 浓 转 淡 [SEP] 瓶 身 描 绘 的 牡 丹 一 如 [MASK] 初 [MASK] [SEP]
segment_ids : 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1
is_random_next : False
masked_lm_positions: 1 8 23 25
masked_lm_labels: 素 笔 你 妆

tf_record格式的数据如下,需要注意的是next_sentence_labels中0表示是next_sentence, 1表示不是next_sentence。

1
2
3
4
5
6
7
8
tokens: [CLS] [MASK] 胚 勾 勒 出 青 花 [MASK] 锋 浓 转 淡 [SEP] 瓶 身 描 绘 的 牡 丹 一 如 [MASK] 初 [MASK] [SEP]
input_ids: 101 103 5524 1256 1239 1139 7471 5709 103 7226 3849 6760 3909 102 4486 6716 2989 5313 4638 4285 710 671 1963 103 1159 103 102 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
intput_mask: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
segment_ids: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
masked_lm_positions: 1 8 23 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
masked_lm_ids: 5162 5011 872 1966 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
masked_lm_weights: 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
next_sentence_labels: 0

run_pretraining

主要包括两个loss,一个是get_masked_lm_output用于预测mask后的词,一个是get_next_sentence_output用来预测next_sen的概率。最终的loss是这两个loss的和,用来作为优化目标。

modeling

该模块完整实现了transformer的encoder部分的代码,实现了multi-head attention结构。

最终的输出包括get_sequence_output返回所有token的隐层表示,get_pooled_output返回[CLS]对应的隐层表示。

下面这段代码要表达的是,[CLS]位置不是直接使用encode的输出,而是又增加了一个hidden layer,作为最终[CLS]的输出。

1
2
3
4
5
6
7
8
9
with tf.variable_scope("pooler"):
# We "pool" the model by simply taking the hidden state corresponding
# to the first token. We assume that this has been pre-trained
first_token_tensor = tf.squeeze(self.sequence_output[:, 0:1, :], axis=1)
self.pooled_output = tf.layers.dense(
first_token_tensor,
config.hidden_size,
activation=tf.tanh,
kernel_initializer=create_initializer(config.initializer_range))

总结

看论文的同时还要去看下源代码来加深理解,更需要我们跑一些case来验证我们的想法。

发表于 | 分类于

背景

Rnn全名Recurrent Neural Network,对时序进行了建模,能够记忆之前看到的信息。

举例来说:订一张从北京到上海的机票 vs 订一张从上海到北京的机票,如果直接用bow模型是无法区分这两个文本的,而使用rnn可以刻画出时序关系。

介绍

模型结构

rnn有两个输入,一个是真实输入$X^t,ドル一个是上一层的输入$H^{t-1},ドル上一层的输入能够对上一个cell的状态进行记忆。模型将$X^t$和$H^{t-1}$进行拼接后,通过一个ffc(W)得到下一层的$H^t,ドル同时再通过一个FFC得到输出$Y^t$。

具体公式:

$H^t = \sigma{(W^{hh}h^{t - 1}+ W^{hx}X^t + b)}$

$Y^t = softmax(W^{S}h^t)$

具体流程如下:

rnn

相关代码

计算$H^t$相关代码,将inputs 和 state拼接后,和_kernel矩阵相乘,加bias和激活函数,得到最终的输出。

1
2
3
4
5
6
7
8
def call(self, inputs, state):
"""Most basic RNN: output = new_state = act(W * input + U * state + B)."""

gate_inputs = math_ops.matmul(
array_ops.concat([inputs, state], 1), self._kernel)
gate_inputs = nn_ops.bias_add(gate_inputs, self._bias)
output = self._activation(gate_inputs)
return output, output

kernel相关定义:

1
2
3
self._kernel = self.add_variable(
_WEIGHTS_VARIABLE_NAME,
shape=[input_depth + self._num_units, self._num_units])

注意

  1. 所有的rnn cell的权重是共享的。可以想象成输入是不动的,使rnn_cell在输入上不断的滑动。
  2. rnn容易出现梯度消失和梯度爆炸,可以考虑使用lstm。
  3. 无法并行,可以考虑使用transformer。

参考

  1. https://towardsdatascience.com/animated-rnn-lstm-and-gru-ef124d06cf45
  2. https://github.com/tensorflow/tensorflow/blob/r1.13/tensorflow/python/ops/rnn_cell_impl.py

发表于 | 分类于

常用命令

  1. 查看tensorboard

    1
    2
    在estimator模式下查看tensorboard
    tensorboard --logdir model_dir --host 0.0.0.0 --port 8888
  2. 指定gpu

    1
    2
    import os
    os.environ["CUDA_VISIBLE_DEVICES"] = "3"
  3. 查看gpu使用情况

    1
    nvidia-smi
  4. 查看tensorflow版本

    1
    2
    import tensorflow as tf
    print(tf.__version__)
  5. 查看cuda版本

    1
    2
    cat /usr/local/cuda/version.txt
    CUDA Version 8.0.44

总结

  1. https://github.com/c00h00g/tf_chg/

发表于 | 分类于

背景

rnn可以解决时序问题,但是容易出现梯度爆炸/梯度爆炸的问题,当文本较长的时候,效果并不好。LSTM,是Long Short-Term Memory,中文可以理解成比较长的Short-Term Memory,因为当文本非常长的时候,效果也会有问题(可以通过加入attention方式解决)。

介绍

具体网络结构

下面这张图,是目前我看到的最清晰的描述LSTM网络结构的图片,使用一个实例描述了整个过程。其中S表示该神经元使用sigmoid激活函数触发,T表示该神经元使用tanh函数触发。输入的纬度是3,隐层的纬度是2。

lstm_cell

抽象网络结构

下面这张图画的也很不错,从抽象的角度定义了LSTM,可以对比来看,一个是抽象,一个是实例。

lstm_cell_con

lstm_single_cell

几个公式:

  1. 遗忘门:$f_t = \sigma(W_f [h_{t-1}, x_t] + b_f)$
  2. 输入门:$i_t = \sigma(W_i[h_{t-1}, x_t] + b_i)$
  3. $\tilde{C_t} = tanh(W_C [h_{t-1}, x_t] + b_C)$
  4. $C_t = f_t C_{t - 1} + i_t \tilde {C_t}$
  5. $O_t = \sigma(W_o[h_{t-1}, x_t] + b_o)$
  6. $h_t = o_t * tanh(C_t)$

相关代码

下面代码构造网络参数,我们可以看出来_kernel用来存储模型参数,可以看出来存储了4倍的参数,因为我们有四个FFC网络。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def build(self, inputs_shape):
if inputs_shape[-1] is None:
raise ValueError("Expected inputs.shape[-1] to be known, saw shape: %s"
% str(inputs_shape))

input_depth = inputs_shape[-1]
h_depth = self._num_units
self._kernel = self.add_variable(
_WEIGHTS_VARIABLE_NAME,
shape=[input_depth + h_depth, 4 * self._num_units])
self._bias = self.add_variable(
_BIAS_VARIABLE_NAME,
shape=[4 * self._num_units],
initializer=init_ops.zeros_initializer(dtype=self.dtype))

self.built = True

下面这段代码是实际的计算过程,需要注意的是,每次更新,需要返回两个状态$h_t$和$C_t$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
def call(self, inputs, state):
"""Long short-term memory cell (LSTM).
Args:
inputs: `2-D` tensor with shape `[batch_size, input_size]`.
state: An `LSTMStateTuple` of state tensors, each shaped
`[batch_size, num_units]`, if `state_is_tuple` has been set to
`True`. Otherwise, a `Tensor` shaped
`[batch_size, 2 * num_units]`.
Returns:
A pair containing the new hidden state, and the new state (either a
`LSTMStateTuple` or a concatenated state, depending on
`state_is_tuple`).
"""
sigmoid = math_ops.sigmoid
one = constant_op.constant(1, dtype=dtypes.int32)
# Parameters of gates are concatenated into one multiply for efficiency.
if self._state_is_tuple:
c, h = state
else:
c, h = array_ops.split(value=state, num_or_size_splits=2, axis=one)

gate_inputs = math_ops.matmul(
array_ops.concat([inputs, h], 1), self._kernel)
gate_inputs = nn_ops.bias_add(gate_inputs, self._bias)

# i = input_gate, j = new_input, f = forget_gate, o = output_gate
i, j, f, o = array_ops.split(
value=gate_inputs, num_or_size_splits=4, axis=one)

forget_bias_tensor = constant_op.constant(self._forget_bias, dtype=f.dtype)
# Note that using `add` and `multiply` instead of `+` and `*` gives a
# performance improvement. So using those at the cost of readability.
add = math_ops.add
multiply = math_ops.multiply
new_c = add(multiply(c, sigmoid(add(f, forget_bias_tensor))),
multiply(sigmoid(i), self._activation(j)))
new_h = multiply(self._activation(new_c), sigmoid(o))

if self._state_is_tuple:
new_state = LSTMStateTuple(new_c, new_h)
else:
new_state = array_ops.concat([new_c, new_h], 1)
return new_h, new_state

参考

  1. https://towardsdatascience.com/animated-rnn-lstm-and-gru-ef124d06cf45
  2. http://colah.github.io/posts/2015-08-Understanding-LSTMs/
© 2020 Soulight
Hexo 强力驱动
主题 - NexT.Mist
| 本站总访问量次 | 本站访客数人次
k

AltStyle によって変換されたページ (->オリジナル) /