Task6 简单神经网络
1. 文本表示:从one-hot到word2
目录
1.1one hot 相关概念
什么是one hot 编码?
one hot编码,又称独热编码,一位有效编码。其方法是使用N位状态寄存器来对N个状态进行编码,每个状态都有它独立寄存器,并且在任意时候,其中只有一位有效。
one hot 优点:1.解决了分类器不好处理离散数据的问题;2.在一定程度上也起了扩充特征的作用
one hot 缺点:在文本特征表示上有些缺点就非常突出,首先,它是一个词袋模型,不考虑词与词之间的顺序,其次,它假设词与词相互独立(大多数情况下,词与词是相互影响的,最后,它得到的特征是离散稀疏的。
1.2 word2vec相关概念
word2vec是什么?
Word2vec是词的一种表示,他将词以固定维数的向量表示出来。 那么 这个时候这三个词都将表示为n维的词向量中国= [x1, x2,.....,xn]
为什么要用word2vec?word2vec有什么好处。
-
传统的基于词袋模型 one-hot representation在判定同义词,相似句子的时候很无力。
-
例如在一个只有两个词的词典中。快递被编码为v1 = [0,1],快件被编码为v2 =[1,0],计算两个的相似度。为v1*v2 = 0
-
而word2vec充分利用上下文信息,对上下文进行训练。每个词不在是只有一个位置为1,其余位置为0的稀疏向量。而是一个稠密的固定维度向量。
word2vec关键点:直观上可以减少额外存储和计算开销,其次,在深层次的语义理解上,经过训练后的词微量能利用上下文信息,能判定找也相似词语。
word2vec的几种实现方式?
1)用上下文预测中心词cbow (continue bag of word)
2)利用中心词预测一下文skip-gram
从实现方式上看两者只是输入输出发生了变化。
word2vec本质
是无监督学习,因为输出并没有label,但是从输入和输出的形式上来看,输入的是一对对单词,看起来像是有监督的,其实不是,办为词向量的本质可以看出是一个只有一层的神经网络,因此必须有输入,输出,而训练过程或者目的不是得到预测结果单词,或是对单词进行分类,最这关键的是获得hidden layer 中权重,也就是说借助了sequence2sequence模型训练过程,得到了hidden layer权重。
Skip-Gram模型(跳字模型)中,我们用一个词,来预测它在文本序列周围的词,数学描述:假设词典索引集V的大小为|V|,且V={0,1,....|V|-1},给定一个长度为T的文本序列中,时间步t的词为w(t)。当时间窗口大小 为m时,跳字模型要最大化给定任一中心词生成所有背景词的概率:,我们可以用V和U分别表示中心词和背景词的向量。换言之,对于词典中索引 为i的词,它在作为中心词和背景词时的向量表示分别是vi和ui。而词典中所 有词的这两种向量正是跳字模型所要学习的模型参数。为了将模型参数植入 损失函数,我们需要使用模型参数表达损失函数中的给定中心词生成背景词 的条件概率。给定中心词,假设生成各个背景词是相互独立的。设中心词
在词典中索引 为c,背景词Wo在词典中索引为o,损失函数中的给定中心词生成背景词的条 件概率可以通过 softmax 函数定义。
跳字模型,随机采样的子序列有关其他向量的梯度同理可理,训练模型时,每次迭代实际上是用这些梯度来迭代子序列中出现过的中心词和背景词的向量,训练结束后,对于词典中的任一索引为i的词,我们均得到该词作为中心词和背景词的两组词向量vi和Ui,在自然语言处理中,我们使用跳字模型词向量。
CBOW模型(连续词袋模型),CBOW模型用一个中心词在文本序列前后的背景词来预测中心词。数学描述:假设词典索引集 V 的大小为 |V|,且 V={0,1,...,|V|−1}。给定一个长度为T 的文本序列中,时间步 t 的词为 w(t)。当时间窗口大小为 m 时,CBOW 模型需要最大化给定背景词生成任一中心词的概率;
1.1 词袋模型:离散、高维、稀疏。
1.2 分布式表示:连续、低维、稠密。word2vec词向量原理并实践,用来表示文本。
2. 走进FastText
fasttext最优的地方是,和前沿的深度神经网络模型相比,能够做到效果好,速度快,主要是利用词内n-gram信息(subword n-gram information),二是用到层次化Softmax回归(Hierarchical |Softmax)的训练trick.Subword n-gram information是对输入的上下文中每一个词,都进行基于词的n-gram,之后将所有的n-gram和原词相加,来代表上下文信息,这种做法的好处是英文单词中,可以由前缀或者后缀等语言形态上相似性,在词与词之间建立联系。
在fastText的工作之前,大部分的文本向量化的工作,都是以词汇表 中的独立单词作为基本单元来进行训练学习的。这种想法非常自然, 但也会带来如下的问题:
低频词、罕见词,由于在语料中本身出现的次数就少,得不到足够的训练,效果不佳;未登录词,如果出现了一些在词典中都没有出现过的词,或者带有某些拼写错误的词,传统模型更加无能为力。 fastText引入了subword n-gram的概念来解决词形变化(morphology)的问题。直观上,它将一个单词打散到字符级别,并且利用字符级别 的n-gram信息来捕捉字符间的顺序关系,希望能够以此丰富单词内部 更细微的语义。我们知道,西方语言文字常常通过前缀、后缀、字根来构词,汉语也有单字表义的传统,所以这样的做法听起来还是有一 定的道理。
Hierarchical Softmax
Softmax大家都比较熟悉,它是逻辑回归(logisticregression)在多分类任务上的推广,是我们训练的神经网络中的最后一层。一般地, Softmax以隐藏层的输出h为输入,经过线性和指数变换后,再进行全局的归一化处理,找到概率最大的输出项。当词汇数量V较大时(一 般会到几十万量级),Softmax计算代价很大,是O(V)量级。层次化的Softmax的思想实质上是将一个全局多分类的问题,转化成 为了若干个二元分类问题,从而将计算复杂度从O(V)降到O(logV)。每个二元分类问题,由一个基本的逻辑回归单元来实现。如下图所示, 从根结点开始,每个中间结点(标记成灰色)都是一个逻辑回归单元, 根据它的输出来选择下一步是向左走还是向右走。下图示例中实际上 走了一条“左-左-右”的路线,从而找到单词w2。而最终输出单词w2 的概率,等于中间若干逻辑回归单元输出概率的连乘积。
2.1 FastText的原理
1、应用场景
fastText是一种Facebook AI Research在16年开源的一个文本分类器。 其特点就是fast。相对于其它文本分类模型,如SVM,Logistic Regression和neural network等模型,fastText在保持分类效果的同时,大大缩短了训练时间。
2、优缺点
适合大型数据+高效的训练速度:能够训练模型“在使用标准多核CPU的情况下10分钟内处理超过10亿个词汇”支持多语言表达:利用其语言形态结构,fastText能够被设计用来支持包括英语、德语、西班牙语、法语以及捷克语等多种语言。FastText的性能比时下流行的word2vec工具明显好上不少,也比其他目前最先进的词态词汇表征要好。fastText专注于文本分类,在许多标准问题上实现当下最好的表现(例如文本倾向性分析或标签预测)。
3、FastText的原理
fastText 方法包含三部分:模型架构、层次 Softmax 和 N-gram 特征。
fastText 模型输入一个词的序列(一段文本或者一句话),输出这个词序列属于不同类别的概率。
序列中的词和词组组成特征向量,特征向量通过线性变换映射到中间层,中间层再映射到标签。
fastText 在预测标签时使用了非线性**函数,但在中间层不使用非线性**函数。
fastText 模型架构和 Word2Vec 中的 CBOW 模型很类似。不同之处在于,fastText 预测标签,而 CBOW 模型预测中间词。
第一部分:fastText的模型架构类似于CBOW,两种模型都是基于Hierarchical Softmax,都是三层架构:输入层、 隐藏层、输出层。
4.fasttext模型结构
5.模型对比
模型结构
上图没有展示词向量的训练过程。可以看到,和CBOW一样,fastText模型也只有三层:输入层、隐含层、输出层(Hierarchical Softmax), 输入都是多个经向量表示的单词,输出都是一个特定的target,隐含层 都是对多个词向量的叠加平均。不同的是,CBOW的输入是目标单词的上下文,fastText的输入是多个单 词及其n-gram特征,这些特征用来表示单个文档;CBOW的输入单词被 onehot编码过,fastText的输入特征是被embedding过;CBOW的输出是 目标词汇,fastText的输出是文档对应的类标。值得注意的是,fastText在输入时,将单词的字符级别的n-gram向量作 为额外的特征;在输出时,fastText采用了分层Softmax,大大降低了 模型训练时间。
3.利用FastText模型进行文本分类
from BaseUtil.BaseModel import BaseModel
import tensorflow as tf
class fastTextModel(BaseModel):
"""
A simple implementation of fasttext for text classification
"""
def __init__(self, sequence_length, num_classes, vocab_size,
embedding_size, learning_rate, decay_steps, decay_rate,
l2_reg_lambda, is_training=True,
initializer=tf.random_normal_initializer(stddev=0.1)):
self.vocab_size = vocab_size
self.embedding_size = embedding_size
self.num_classes = num_classes
self.sequence_length = sequence_length
self.learning_rate = learning_rate
self.decay_steps = decay_steps
self.decay_rate = decay_rate
self.is_training = is_training
self.l2_reg_lambda = l2_reg_lambda
self.initializer = initializer
self.input_x = tf.placeholder(tf.int32, [None, self.sequence_length], name='input_x')
self.input_y = tf.placeholder(tf.int32, [None, self.num_classes], name='input_y')
self.global_step = tf.Variable(0, trainable=False, name='global_step')
self.instantiate_weight()
self.logits = self.inference()
self.loss_val = self.loss()
self.train_op = self.train()
self.predictions = tf.argmax(self.logits, axis=1, name='predictions')
correct_prediction = tf.equal(self.predictions, tf.argmax(self.input_y, 1))
self.accuracy = tf.reduce_mean(tf.cast(correct_prediction, 'float'), name='accuracy')
def instantiate_weight(self):
with tf.name_scope('weights'):
self.Embedding = tf.get_variable('Embedding', shape=[self.vocab_size, self.embedding_size],
initializer=self.initializer)
self.W_projection = tf.get_variable('W_projection', shape=[self.embedding_size, self.num_classes],
initializer=self.initializer)
self.b_projection = tf.get_variable('b_projection', shape=[self.num_classes])
def inference(self):
"""
1. word embedding
2. average embedding
3. linear classifier
:return:
"""
# embedding layer
with tf.name_scope('embedding'):
words_embedding = tf.nn.embedding_lookup(self.Embedding, self.input_x)
self.average_embedding = tf.reduce_mean(words_embedding, axis=1)
logits = tf.matmul(self.average_embedding, self.W_projection) +self.b_projection
return logits
def loss(self):
# loss
with tf.name_scope('loss'):
losses = tf.nn.softmax_cross_entropy_with_logits(labels=self.input_y, logits=self.logits)
data_loss = tf.reduce_mean(losses)
l2_loss = tf.add_n([tf.nn.l2_loss(cand_var) for cand_var in tf.trainable_variables()
if 'bias' not in cand_var.name]) * self.l2_reg_lambda
data_loss += l2_loss * self.l2_reg_lambda
return data_loss
def train(self):
with tf.name_scope('train'):
learning_rate = tf.train.exponential_decay(self.learning_rate, self.global_step,
self.decay_steps, self.decay_rate,
staircase=True)
train_op = tf.contrib.layers.optimize_loss(self.loss_val, global_step=self.global_step,
learning_rate=learning_rate, optimizer='Adam')
return train_op
import tensorflow as tf
import numpy as np
import os
import time
import datetime
from cnn_classification import data_process
from fastText import fastTextModel
from tensorflow.contrib import learn
# define parameters
#data load params
tf.flags.DEFINE_string("positive_data_file", "../cnn_classification/data/rt-polarity.pos", "Data source for the positive data.")
tf.flags.DEFINE_string("negative_data_file", "../cnn_classification/data/rt-polarity.neg", "Data source for the negative data.")
#configuration
tf.flags.DEFINE_float("learning_rate", 0.01, "learning rate")
tf.flags.DEFINE_integer("num_epochs", 60, "embedding size")
tf.flags.DEFINE_integer("batch_size", 100, "Batch size for training/evaluating.") #批处理的大小 32-->128
tf.flags.DEFINE_integer("decay_steps", 12000, "how many steps before decay learning rate.")
tf.flags.DEFINE_float("decay_rate", 0.9, "Rate of decay for learning rate.") # 0.5一次衰减多少
tf.flags.DEFINE_string("ckpt_dir", "text_fastText_checkpoint/", "checkpoint location for the model")
tf.flags.DEFINE_integer('num_checkpoints', 10, 'save checkpoints count')
tf.flags.DEFINE_integer("sequence_length", 300, "max sentence length")
tf.flags.DEFINE_integer("embedding_size", 128, "embedding size")
tf.flags.DEFINE_boolean("is_training", True, "is traning.true:tranining,false:testing/inference")
tf.flags.DEFINE_integer("validate_every", 1, "Validate every validate_every epochs.") #每10轮做一次验证
tf.flags.DEFINE_float("dev_sample_percentage", .1, "Percentage of the training data to use for validation")
tf.flags.DEFINE_integer('dev_sample_max_cnt', 1000, 'max cnt of validation samples, dev samples cnt too large will case high loader')
tf.flags.DEFINE_float("dropout_keep_prob", 0.5, "Dropout keep probability (default: 0.5)")
tf.flags.DEFINE_float("l2_reg_lambda", 0.0001, "L2 regularization lambda (default: 0.0)")
tf.flags.DEFINE_boolean("allow_soft_placement", True, "Allow device soft device placement")
tf.flags.DEFINE_boolean("log_device_placement", False, "Log placement of ops on devices")
FLAGS = tf.flags.FLAGS
def prepocess():
"""
For load and process data
:return:
"""
print("Loading data...")
x_text, y = data_process.load_data_and_labels(FLAGS.positive_data_file, FLAGS.negative_data_file)
# bulid vocabulary
max_document_length = max(len(x.split(' ')) for x in x_text)
vocab_processor = learn.preprocessing.VocabularyProcessor(max_document_length)
x = np.array(list(vocab_processor.fit_transform(x_text)))
# shuffle
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 dataset
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:]
del x, y, x_shuffled, y_shuffled
print('Vocabulary Size: {:d}'.format(len(vocab_processor.vocabulary_)))
print('Train/Dev split: {:d}/{:d}'.format(len(y_train), len(y_dev)))
return x_train, y_train, vocab_processor, x_dev, y_dev
def train(x_train, y_train, vocab_processor, x_dev, y_dev):
with tf.Graph().as_default():
session_conf = tf.ConfigProto(
# allows TensorFlow to fall back on a device with a certain operation implemented
allow_soft_placement= FLAGS.allow_soft_placement,
# allows TensorFlow log on which devices (CPU or GPU) it places operations
log_device_placement=FLAGS.log_device_placement
)
sess = tf.Session(config=session_conf)
with sess.as_default():
# initialize cnn
fasttext = fastTextModel(sequence_length=x_train.shape[1],
num_classes=y_train.shape[1],
vocab_size=len(vocab_processor.vocabulary_),
embedding_size=FLAGS.embedding_size,
l2_reg_lambda=FLAGS.l2_reg_lambda,
is_training=True,
learning_rate=FLAGS.learning_rate,
decay_steps=FLAGS.decay_steps,
decay_rate=FLAGS.decay_rate
)
# output dir for models and summaries
timestamp = str(time.time())
out_dir = os.path.abspath(os.path.join(os.path.curdir, 'run', timestamp))
if not os.path.exists(out_dir):
os.makedirs(out_dir)
print('Writing to {} \n'.format(out_dir))
# checkpoint dir. checkpointing – saving the parameters of your model to restore them later on.
checkpoint_dir = os.path.abspath(os.path.join(out_dir, FLAGS.ckpt_dir))
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
sess.run(tf.global_variables_initializer())
def train_step(x_batch, y_batch):
"""
A single training step
:param x_batch:
:param y_batch:
:return:
"""
feed_dict = {
fasttext.input_x: x_batch,
fasttext.input_y: y_batch,
}
_, step, loss, accuracy = sess.run(
[fasttext.train_op, fasttext.global_step, fasttext.loss_val, fasttext.accuracy],
feed_dict=feed_dict
)
time_str = datetime.datetime.now().isoformat()
print("{}: step {}, loss {:g}, acc {:g}".format(time_str, step, loss, accuracy))
def dev_step(x_batch, y_batch):
"""
Evaluate model on a dev set
Disable dropout
:param x_batch:
:param y_batch:
:param writer:
:return:
"""
feed_dict = {
fasttext.input_x: x_batch,
fasttext.input_y: y_batch,
}
step, loss, accuracy = sess.run(
[fasttext.global_step, fasttext.loss_val, fasttext.accuracy],
feed_dict=feed_dict
)
time_str = datetime.datetime.now().isoformat()
print("dev results:{}: step {}, loss {:g}, acc {:g}".format(time_str, step, loss, accuracy))
# generate batches
batches = data_process.batch_iter(list(zip(x_train, y_train)), FLAGS.batch_size, FLAGS.num_epochs)
# training loop
for batch in batches:
x_batch, y_batch = zip(*batch)
train_step(x_batch, y_batch)
current_step = tf.train.global_step(sess, fasttext.global_step)
if current_step % FLAGS.validate_every == 0:
print('\n Evaluation:')
dev_step(x_dev, y_dev)
print('')
path = saver.save(sess, checkpoint_prefix, global_step=current_step)
print('Save model checkpoint to {} \n'.format(path))
def main(argv=None):
x_train, y_train, vocab_processor, x_dev, y_dev = prepocess()
train(x_train, y_train, vocab_processor, x_dev, y_dev)
if __name__ == '__main__':
tf.app.run()
还没运行完。