Attention-Based Bidirectional Long Short-Term Memory Networks for Relation Classification模型实现

Attention-Based Bidirectional Long Short-Term Memory Networks for Relation Classification模型实现

1. Attention

H是一个矩阵,它是由LSTM层产生的多个向量 [ h 1 , h 2 , … , h T ] [h_1,h_2,\dots,h_T] [h1​,h2​,…,hT​]组成的。其中T是句子的长度。句子的表示 r r r是输出向量的权重之和。
 M = t a n ( H ) M = tan(H) M=tan(H)  α = s o f t m a x ( W T M ) \alpha =softmax(W^TM) α=softmax(WTM)  r = H α T r=H\alpha^T r=HαT

output_h = tf.add(output_forward, output_backward) # total_num, time_steps,gru_size
output_h的维度为[total_num, time_steps,gru_size],其中total_num指的是batch_size,time_steps指的是length of sentence。

attention_w = tf.get_variable(‘attention_omega’, [gru_size, 1]) #attention_w本质上是每个GRU单元不同的权重,也就是对每个单词赋予不同的权重。

  • t1 = tf.tanh(output_h) #[total_num, time_steps,gru_size]
  • t2 = t1.reshape(t1, [total_numtime_steps, gru_size]) #total_numtime_steps, gru_size
  • t3 = tf.matmul(t2, attention_w)#total_num*time_steps,1
  • t4 = tf.reshape(t3, [total_num, time_steps]) #total_num * time_steps
  • t5 = tf.nn.softmax(t4) # softmax是针对每个词来说的, total_num * time_steps
  • t6 = tf.reshape(t5, [total_num, 1, time_steps])
  • t7 = tf.matmul(t6, output_h) # total_num * 1 * gru_size,其中三维张量的乘法,第一维不变(第一维比较相同),后两维进行二维矩阵的乘法。
  • r = tf.reshape(t7, [total_num, gru_size])
  • result = tf.tanh( r )

另外的实现代码如下所示:

def attention(inputs): # Trainable parameters # B*T*H B*T*1 hidden_size = inputs.shape[2].value u_omega = tf.get_variable("u_omega", [hidden_size], initializer=tf.keras.initializers.glorot_normal()) with tf.name_scope('v'): v = tf.tanh(inputs) # For each of the timestamps its vector of size A from `v` is reduced with `u` vector vu = tf.tensordot(v, u_omega, axes=1, name='vu') # (B,T) shape alphas = tf.nn.softmax(vu, name='alphas') # (B,T) shape # Output of (Bi-)RNN is reduced with attention vector; the result has (B,D) shape output = tf.reduce_sum(inputs * tf.expand_dims(alphas, -1), 1) # Final output with tanh output = tf.tanh(output) return output, alphas 

2. BLSTM

class AttLSTM: def __init__(self, sequence_length, num_classes, vocab_size, embedding_size, hidden_size, l2_reg_lambda=0.0): # Placeholders for input, output and dropout self.input_text = tf.placeholder(tf.int32, shape=[None, sequence_length], name='input_text') self.input_y = tf.placeholder(tf.float32, shape=[None, num_classes], name='input_y') self.emb_dropout_keep_prob = tf.placeholder(tf.float32, name='emb_dropout_keep_prob') self.rnn_dropout_keep_prob = tf.placeholder(tf.float32, name='rnn_dropout_keep_prob') self.dropout_keep_prob = tf.placeholder(tf.float32, name='dropout_keep_prob') initializer = tf.keras.initializers.glorot_normal # Word Embedding Layer with tf.device('/cpu:0'), tf.variable_scope("word-embeddings"): self.W_text = tf.Variable(tf.random_uniform([vocab_size, embedding_size], -0.25, 0.25), name="W_text") self.embedded_chars = tf.nn.embedding_lookup(self.W_text, self.input_text) # Dropout for Word Embedding with tf.variable_scope('dropout-embeddings'): self.embedded_chars = tf.nn.dropout(self.embedded_chars, self.emb_dropout_keep_prob) # Bidirectional LSTM with tf.variable_scope("bi-lstm"): _fw_cell = tf.nn.rnn_cell.LSTMCell(hidden_size, initializer=initializer()) fw_cell = tf.nn.rnn_cell.DropoutWrapper(_fw_cell, self.rnn_dropout_keep_prob) _bw_cell = tf.nn.rnn_cell.LSTMCell(hidden_size, initializer=initializer()) bw_cell = tf.nn.rnn_cell.DropoutWrapper(_bw_cell, self.rnn_dropout_keep_prob) self.rnn_outputs, _ = tf.nn.bidirectional_dynamic_rnn(cell_fw=fw_cell, cell_bw=bw_cell, inputs=self.embedded_chars, sequence_length=self._length(self.input_text), dtype=tf.float32) self.rnn_outputs = tf.add(self.rnn_outputs[0], self.rnn_outputs[1]) # Attention with tf.variable_scope('attention'): self.attn, self.alphas = attention(self.rnn_outputs) # Dropout with tf.variable_scope('dropout'): self.h_drop = tf.nn.dropout(self.attn, self.dropout_keep_prob) # Fully connected layer with tf.variable_scope('output'): self.logits = tf.layers.dense(self.h_drop, num_classes, kernel_initializer=initializer()) self.predictions = tf.argmax(self.logits, 1, name="predictions") # Calculate mean cross-entropy loss with tf.variable_scope("loss"): losses = tf.nn.softmax_cross_entropy_with_logits_v2(logits=self.logits, labels=self.input_y) self.l2 = tf.add_n([tf.nn.l2_loss(v) for v in tf.trainable_variables()]) self.loss = tf.reduce_mean(losses) + l2_reg_lambda * self.l2 # Accuracy with tf.variable_scope("accuracy"): correct_predictions = tf.equal(self.predictions, tf.argmax(self.input_y, 1)) self.accuracy = tf.reduce_mean(tf.cast(correct_predictions, tf.float32), name="accuracy") # Length of the sequence data @staticmethod def _length(seq): relevant = tf.sign(tf.abs(seq)) length = tf.reduce_sum(relevant, reduction_indices=1) length = tf.cast(length, tf.int32) return length 

3. 训练模型

def train(): with tf.device('/cpu:0'): x_text, y = data_helpers.load_data_and_labels(FLAGS.train_path) # Build vocabulary # Example: x_text[3] = "A misty <e1>ridge</e1> uprises from the <e2>surge</e2>." # ['a misty ridge uprises from the surge <UNK> <UNK> ... <UNK>'] # => # [27 39 40 41 42 1 43 0 0 ... 0] # dimension = FLAGS.max_sentence_length vocab_processor = tf.contrib.learn.preprocessing.VocabularyProcessor(FLAGS.max_sentence_length) x = np.array(list(vocab_processor.fit_transform(x_text))) print("Text Vocabulary Size: {:d}".format(len(vocab_processor.vocabulary_))) print("x = {0}".format(x.shape)) print("y = {0}".format(y.shape)) print("") # Randomly shuffle data to split into train and test(dev) np.random.seed(10) shuffle_indices = np.random.permutation(np.arange(len(y))) x_shuffled = x[shuffle_indices] y_shuffled = y[shuffle_indices] # Split train/test set # TODO: This is very crude, should use cross-validation dev_sample_index = -1 * int(FLAGS.dev_sample_percentage * float(len(y))) x_train, x_dev = x_shuffled[:dev_sample_index], x_shuffled[dev_sample_index:] y_train, y_dev = y_shuffled[:dev_sample_index], y_shuffled[dev_sample_index:] print("Train/Dev split: {:d}/{:d}\n".format(len(y_train), len(y_dev))) with tf.Graph().as_default(): session_conf = tf.ConfigProto( allow_soft_placement=FLAGS.allow_soft_placement, log_device_placement=FLAGS.log_device_placement) session_conf.gpu_options.allow_growth = FLAGS.gpu_allow_growth sess = tf.Session(config=session_conf) with sess.as_default(): model = AttLSTM( sequence_length=x_train.shape[1], num_classes=y_train.shape[1], vocab_size=len(vocab_processor.vocabulary_), embedding_size=FLAGS.embedding_dim, hidden_size=FLAGS.hidden_size, l2_reg_lambda=FLAGS.l2_reg_lambda) # Define Training procedure global_step = tf.Variable(0, name="global_step", trainable=False) optimizer = tf.train.AdadeltaOptimizer(FLAGS.learning_rate, FLAGS.decay_rate, 1e-6) gvs = optimizer.compute_gradients(model.loss) capped_gvs = [(tf.clip_by_value(grad, -1.0, 1.0), var) for grad, var in gvs] train_op = optimizer.apply_gradients(capped_gvs, global_step=global_step) # Output directory for models and summaries timestamp = str(int(time.time())) out_dir = os.path.abspath(os.path.join(os.path.curdir, "runs", timestamp)) print("Writing to {}\n".format(out_dir)) # Summaries for loss and accuracy loss_summary = tf.summary.scalar("loss", model.loss) acc_summary = tf.summary.scalar("accuracy", model.accuracy) # Train Summaries train_summary_op = tf.summary.merge([loss_summary, acc_summary]) train_summary_dir = os.path.join(out_dir, "summaries", "train") train_summary_writer = tf.summary.FileWriter(train_summary_dir, sess.graph) # Dev summaries dev_summary_op = tf.summary.merge([loss_summary, acc_summary]) dev_summary_dir = os.path.join(out_dir, "summaries", "dev") dev_summary_writer = tf.summary.FileWriter(dev_summary_dir, sess.graph) # Checkpoint directory. Tensorflow assumes this directory already exists so we need to create it checkpoint_dir = os.path.abspath(os.path.join(out_dir, "checkpoints")) checkpoint_prefix = os.path.join(checkpoint_dir, "model") if not os.path.exists(checkpoint_dir): os.makedirs(checkpoint_dir) saver = tf.train.Saver(tf.global_variables(), max_to_keep=FLAGS.num_checkpoints) # Write vocabulary vocab_processor.save(os.path.join(out_dir, "vocab")) # Initialize all variables sess.run(tf.global_variables_initializer()) # Pre-trained word2vec if FLAGS.embedding_path: pretrain_W = utils.load_glove(FLAGS.embedding_path, FLAGS.embedding_dim, vocab_processor) sess.run(model.W_text.assign(pretrain_W)) print("Success to load pre-trained word2vec model!\n") # Generate batches batches = data_helpers.batch_iter(list(zip(x_train, y_train)), FLAGS.batch_size, FLAGS.num_epochs) # Training loop. For each batch... best_f1 = 0.0 # For save checkpoint(model) for batch in batches: x_batch, y_batch = zip(*batch) # Train feed_dict = { model.input_text: x_batch, model.input_y: y_batch, model.emb_dropout_keep_prob: FLAGS.emb_dropout_keep_prob, model.rnn_dropout_keep_prob: FLAGS.rnn_dropout_keep_prob, model.dropout_keep_prob: FLAGS.dropout_keep_prob } _, step, summaries, loss, accuracy = sess.run( [train_op, global_step, train_summary_op, model.loss, model.accuracy], feed_dict) train_summary_writer.add_summary(summaries, step) # Training log display if step % FLAGS.display_every == 0: time_str = datetime.datetime.now().isoformat() print("{}: step {}, loss {:g}, acc {:g}".format(time_str, step, loss, accuracy)) # Evaluation if step % FLAGS.evaluate_every == 0: print("\nEvaluation:") feed_dict = { model.input_text: x_dev, model.input_y: y_dev, model.emb_dropout_keep_prob: 1.0, model.rnn_dropout_keep_prob: 1.0, model.dropout_keep_prob: 1.0 } summaries, loss, accuracy, predictions = sess.run( [dev_summary_op, model.loss, model.accuracy, model.predictions], feed_dict) dev_summary_writer.add_summary(summaries, step) time_str = datetime.datetime.now().isoformat() f1 = f1_score(np.argmax(y_dev, axis=1), predictions, labels=np.array(range(1, 19)), average="macro") print("{}: step {}, loss {:g}, acc {:g}".format(time_str, step, loss, accuracy)) print("[UNOFFICIAL] (2*9+1)-Way Macro-Average F1 Score (excluding Other): {:g}\n".format(f1)) # Model checkpoint if best_f1 < f1: best_f1 = f1 path = saver.save(sess, checkpoint_prefix + "-{:.3g}".format(best_f1), global_step=step) print("Saved model checkpoint to {}\n".format(path)) 

4.验证模型

def test(): with tf.device('/cpu:0'): x_text, y = data_helpers.load_data_and_labels(FLAGS.test_path) # Map data into vocabulary text_path = os.path.join(FLAGS.checkpoint_dir, "..", "vocab") text_vocab_processor = tf.contrib.learn.preprocessing.VocabularyProcessor.restore(text_path) x = np.array(list(text_vocab_processor.transform(x_text))) checkpoint_file = tf.train.latest_checkpoint(FLAGS.checkpoint_dir) graph = tf.Graph() with graph.as_default(): session_conf = tf.ConfigProto( allow_soft_placement=FLAGS.allow_soft_placement, log_device_placement=FLAGS.log_device_placement) session_conf.gpu_options.allow_growth = FLAGS.gpu_allow_growth sess = tf.Session(config=session_conf) with sess.as_default(): # Load the saved meta graph and restore variables saver = tf.train.import_meta_graph("{}.meta".format(checkpoint_file)) saver.restore(sess, checkpoint_file) # Get the placeholders from the graph by name input_text = graph.get_operation_by_name("input_text").outputs[0] # input_y = graph.get_operation_by_name("input_y").outputs[0] emb_dropout_keep_prob = graph.get_operation_by_name("emb_dropout_keep_prob").outputs[0] rnn_dropout_keep_prob = graph.get_operation_by_name("rnn_dropout_keep_prob").outputs[0] dropout_keep_prob = graph.get_operation_by_name("dropout_keep_prob").outputs[0] # Tensors we want to evaluate predictions = graph.get_operation_by_name("output/predictions").outputs[0] # Generate batches for one epoch batches = data_helpers.batch_iter(list(x), FLAGS.batch_size, 1, shuffle=False) # Collect the predictions here preds = [] for x_batch in batches: pred = sess.run(predictions, {input_text: x_batch, emb_dropout_keep_prob: 1.0, rnn_dropout_keep_prob: 1.0, dropout_keep_prob: 1.0}) preds.append(pred) preds = np.concatenate(preds) truths = np.argmax(y, axis=1) prediction_path = os.path.join(FLAGS.checkpoint_dir, "..", "predictions.txt") truth_path = os.path.join(FLAGS.checkpoint_dir, "..", "ground_truths.txt") prediction_file = open(prediction_path, 'w') truth_file = open(truth_path, 'w') for i in range(len(preds)): prediction_file.write("{}\t{}\n".format(i, utils.label2class[preds[i]])) truth_file.write("{}\t{}\n".format(i, utils.label2class[truths[i]])) prediction_file.close() truth_file.close() perl_path = os.path.join(os.path.curdir, "SemEval2010_task8_all_data", "SemEval2010_task8_scorer-v1.2", "semeval2010_task8_scorer-v1.2.pl") process = subprocess.Popen(["perl", perl_path, prediction_path, truth_path], stdout=subprocess.PIPE) for line in str(process.communicate()[0].decode("utf-8")).split("\\n"): print(line) 

Read more

前端防范 XSS(跨站脚本攻击)

目录 一、防范措施 1.layui util  核心转义的特殊字符 示例 2.js-xss.js库 安装 1. Node.js 环境(npm/yarn) 2. 浏览器环境 核心 API 基础使用 1. 基础过滤(默认规则) 2. 自定义过滤规则 (1)允许特定标签 (2)允许特定属性 (3)自定义标签处理 (4)自定义属性处理 (5)转义特定字符 常见场景示例 1. 过滤用户输入的评论内容 2. 允许特定富文本标签(如富文本编辑器内容) 注意事项 更多配置 XSS(跨站脚本攻击)是一种常见的网络攻击手段,它允许攻击者将恶意脚本注入到其他用户的浏览器中。

详细教程:如何从前端查看调用接口、传参及返回结果(附带图片案例)

详细教程:如何从前端查看调用接口、传参及返回结果(附带图片案例)

目录 1. 打开浏览器开发者工具 2. 使用 Network 面板 3. 查看具体的API请求 a. Headers b. Payload c. Response d. Preview e. Timing 4. 实际操作步骤 5. 常见问题及解决方法 a. 无法看到API请求 b. 请求失败 c. 跨域问题(CORS) 作为一名后端工程师,理解前端如何调用接口、传递参数以及接收返回值是非常重要的。下面将详细介绍如何通过浏览器开发者工具(F12)查看和分析这些信息,并附带图片案例帮助你更好地理解。 1. 打开浏览器开发者工具 按下 F12 或右键点击页面选择“检查”可以打开浏览器的开发者工具。常用的浏览器如Chrome、Firefox等都内置了开发者工具。下面是我选择我的一篇文章,打开开发者工具进行演示。 2. 使用

Cursor+Codex隐藏技巧:用截图秒修前端Bug的保姆级教程(React/Chakra UI案例)

Cursor+Codex隐藏技巧:用截图秒修前端Bug的保姆级教程(React/Chakra UI案例) 前端开发中最令人头疼的莫过于那些难以定位的UI问题——元素错位、样式冲突、响应式失效...传统调试方式往往需要反复修改代码、刷新页面、检查元素。现在,通过Cursor编辑器集成的Codex功能,你可以直接用截图交互快速定位和修复这些问题。本文将带你从零开始,掌握这套革命性的调试工作流。 1. 环境准备与基础配置 在开始之前,确保你已经具备以下环境: * Cursor编辑器最新版(v2.5+) * Node.js 18.x及以上版本 * React 18项目(本文以Chakra UI 2.x为例) 首先在Cursor中安装Codex插件: 1. 点击左侧扩展图标 2. 搜索"Codex"并安装 3. 登录你的OpenAI账户(需要ChatGPT Plus订阅) 关键配置项: // 在项目根目录创建.