# W11-W2V-RNN **Repository Path**: liam1030/W11-W2V-RNN ## Basic Information - **Project Name**: W11-W2V-RNN - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2018-12-10 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 心得 ### word embedding 部分 **过程** : 1.理解上无大碍,就是利用含一个隐藏层的神经网络对目标数据进行特征提取得到的向量表示,提取到的向量中包含着词和词之间的相关性和上下文关系。 2.开始尝试了删除标点,后来醒悟没必要,标点也需要学习。 3. 中文代码问题解决方法: 一、下载SimHei.ttf字体,拷贝到~python安装路径/site-packages/matplotlib/mpl-data/fonts/ttf中; 二、删除~/.cache/matplotlib; 三、修改~python安装路径/site-packages/matplotlib/mpl-data/matplotlibrc; font.family : sans-serif font.sans-serif : SimHei, axes.unicode_minus : False 四、reload一下(非常关键,不然还会报错) > ```py from matplotlib.font_manager import _rebuild _rebuild() #reload一下 ``` #### 图片输出(挺合理): ![embedding](tsne.png) ### rnn训练部分 **心得:** : 1.使用BasicLSTMCell作为基础Cell,网络结构较为简单,深度主要体现在时间维度上,网络可以从数据的输入顺序中获取信息 2.训练速度比较慢,而且感觉和CNN不同,使用GPU并没有加速很多 3.最后结果不太行,准备尝试从数据预处理方面优化一下 **过程:** : #### 数据预处理utils.py 将W2V处理后的索引文件进行批处理,生成训练数据 ```py def get_train_data(vocabulary, batch_size, num_steps): with open ('dictionary.json', encoding='utf-8') as dic: dictionary = json.load(dic, encoding='utf-8') X_d = [] Y_d = [] for vo in vocabulary: if vo in dictionary.keys(): X_d.append(dictionary[vo]) else: X_d.append(dictionary['UNK']) for vo in vocabulary[1:]: if vo in dictionary.keys(): Y_d.append(dictionary[vo]) else: Y_d.append(dictionary['UNK']) data_length = len(X_d) Y_d.append(0) #get batch data batch_partition_length = data_length // batch_size data_x = np.zeros([batch_size, batch_partition_length], dtype=np.int32) data_y = np.zeros([batch_size, batch_partition_length], dtype=np.int32) for i in range(batch_size): data_x[i] = X_d[batch_partition_length * i:batch_partition_length * (i + 1)] data_y[i] = Y_d[batch_partition_length * i:batch_partition_length * (i + 1)] epoch_size = batch_partition_length // num_steps for i in range(epoch_size): x = data_x[:, i * num_steps:(i + 1) * num_steps] y = data_y[:, i * num_steps:(i + 1) * num_steps] yield (x,y) ``` #### 构建LSTM网络model.py tf.nn.rnn_cell.BasicLSTMCell:参数是state_size,输出的h和c两个隐状态形状都是(batch_size,state_size) tf.nn.rnn_cell.MultiRNNCell:第一个参数是输入rnn形成的列表*层数,第二个让状态成为元组 tf.nn.dynamic_rnn:一次执行多步,无需重复执行call操作 dynamic_rnn的输出是128维,在计算softmax之前,需要与[dim_embedding, num_words]的权重矩阵相乘,输出对应num_words个汉字的概率 ```py def build(self, embedding_file=None): # global step self.global_step = tf.Variable( 0, trainable=False, name='self.global_step', dtype=tf.int64) self.X = tf.placeholder( tf.int32, shape=[None, self.num_steps], name='input') self.Y = tf.placeholder( tf.int32, shape=[None, self.num_steps], name='label') self.keep_prob = tf.placeholder(tf.float32, name='keep_prob') with tf.variable_scope('embedding'): if embedding_file: # if embedding file provided, use it. embedding = np.load(embedding_file) embed = tf.constant(embedding, name='embedding') else: # if not, initialize an embedding and train it. embed = tf.get_variable( 'embedding', [self.num_words, self.dim_embedding]) tf.summary.histogram('embed', embed) data = tf.nn.embedding_lookup(embed, self.X) with tf.variable_scope('rnn'): ################## # Your Code here # 选择cell lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(self.dim_embedding) lstm_cell = tf.nn.rnn_cell.DropoutWrapper(lstm_cell, output_keep_prob=self.keep_prob) # 构造深度为rnn_layers的网络 cell = tf.nn.rnn_cell.MultiRNNCell([lstm_cell] * self.rnn_layers, state_is_tuple=True) self.state_tensor = cell.zero_state(self.batch_size, dtype=tf.float32) seq_output, self.outputs_state_tensor = tf.nn.dynamic_rnn(cell, data, initial_state=self.state_tensor) ################## # flatten it seq_output_final = tf.reshape(seq_output, [-1, self.dim_embedding]) with tf.variable_scope('softmax'): ################## # Your Code here weights = tf.get_variable("weights", [self.dim_embedding, (self.num_words)],initializer=tf.random_normal_initializer(stddev=0.01)) bias = tf.get_variable("bias", [(self.num_words)],initializer=tf.constant_initializer(0.0)) logits = tf.matmul(seq_output_final, weights) + bias ################## tf.summary.histogram('logits', logits) self.predictions = tf.nn.softmax(logits, name='predictions') loss = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=tf.reshape(self.Y, [-1]), logits = logits) mean, var = tf.nn.moments(logits, -1) self.loss = tf.reduce_mean(loss) tf.summary.scalar('logits_loss', self.loss) var_loss = tf.divide(10.0, 1.0+tf.reduce_mean(var)) tf.summary.scalar('var_loss', var_loss) # 把标准差作为loss添加到最终的loss里面,避免网络每次输出的语句都是机械的重复 self.loss = self.loss + var_loss tf.summary.scalar('total_loss', self.loss) # gradient clip tvars = tf.trainable_variables() grads, _ = tf.clip_by_global_norm(tf.gradients(loss, tvars), 5) train_op = tf.train.AdamOptimizer(self.learning_rate) self.optimizer = train_op.apply_gradients( zip(grads, tvars), global_step=self.global_step) tf.summary.scalar('loss', self.loss) self.merged_summary_op = tf.summary.merge_all() ``` #### 训练的输出log ```sh 2018-12-10 22:24:01,861 - INFO - tf_logging.py:115 - Restoring parameters from ./rnn_log/model.ckpt-259800 2018-12-10 22:24:01,895 - DEBUG - sample.py:45 - restore from [./rnn_log/model.ckpt-259800] 2018-12-10 22:24:02,336 - DEBUG - sample.py:80 - ==============[江神子]============== 2018-12-10 22:24:02,337 - DEBUG - sample.py:81 - 江神子 水调歌头(和赵子韵) 一笑一年去,不是此时间。一年一笑不是,不见此时人。不见一枝风雨,不见江南一笑,不见此时人。不见一年去 2018-12-10 22:24:02,569 - DEBUG - sample.py:80 - ==============[蝶恋花]============== 2018-12-10 22:24:02,569 - DEBUG - sample.py:81 - 蝶恋花春风吹雨。 满庭芳(和前韵) 一点春风,一番春色,一番春色。一点春风,一番春色,一番春色。 一枝春 一点春风,一枝春雨, 2018-12-10 22:24:02,782 - DEBUG - sample.py:80 - ==============[渔家傲]============== 2018-12-10 22:24:02,783 - DEBUG - sample.py:81 - 渔家傲 水调歌头(和赵子韵) 一点一枝雪,一片一声声。一片春风无限,一片一番春。 ``` #### 要点提示 - 构建RNN网络需要的API如下,请自行查找tensorflow相关文档。 - tf.nn.rnn_cell.DropoutWrapper - tf.nn.rnn_cell.BasicLSTMCell - tf.nn.rnn_cell.MultiRNNCell - RNN部分直接以embedding作为输入,所以其hiddenunit这里取128,也就是embedding的维度即可。 - RNN的输出是维度128的,是个batch_size*num_steps*128这种的输出,为了做loss方便,对输出进行了一些处理,concat,flatten等。具体请参考api文档和代码。 - RNN输出的维度与num_words维度不符,所以需要在最后再加一个矩阵乘法,用一个128*num_words的矩阵将输出维度转换为num_words。 - RNN可能出现梯度爆炸或者消失的问题,对于梯度爆炸,这里直接对gradient做了裁剪,细节参考model代码。 - 这里模型的规模比较小,所以输出的内容可能不是特别有意义,而且训练过程中,不同的checkpoint,其输出也有一些区别。 - 数据处理中,data为文本中一段随机截取的文字,label为data对应的下一个标号的文字。以苏轼的江神子(江城子)为例:输入为 “老夫聊发少年”,则对应的label为"夫聊发少年狂"。 - 训练过程至少要到第二个epoch才能看到一些比较有意义的输出,第一个epoch的输出可能是大量的标点,换行等等。而且这种情况后面还会有。 - 这里的代码,train_eval.py用于在tinymind上运行训练和采样,按照代码中默认的设置,运行一个epoch需要19220步,在tinymind上需要半小时左右。 - rnn作业中,dictiionary和reverse_dictionary为汉字的索引,可以使用word embeding作业生成的,也可以重新生成这两个字典。如果model.build中使用word embeding作业中生成的embeding_file.npy,则为了保证汉字索引的对应关系,必须使用与embeding_file.npy一起生成的dictionary和reverse_dictionary ## 参考资料 各文件简介: - flags.py 命令行参数处理 - model.py 模型定义 - QuanSongCi.txt 《全宋词》文本 - sample.py 用最近的checkpoint,对三个词牌进行生成操作,结果似乎不是很好 - train.py 训练脚本 - utils.py 数据读取,训练数据生成等