分类 自然语言处理 下的文章

设计简单的LSTM、GRU模型

设计简单的LSTM、GRU模型,其中的embedding_matrix见上一篇文章。

from sklearn.cross_validation import train_test_split
from keras.models import Model
from keras.layers import Dense, Embedding, Input, concatenate, Flatten, SpatialDropout1D
from keras.layers import LSTM, Bidirectional, GlobalMaxPool1D, Dropout, CuDNNLSTM, GRU, CuDNNGRU, GlobalAveragePooling1D, GlobalMaxPooling1D
from keras.preprocessing import text, sequence
from keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau, TensorBoard, LearningRateScheduler, Callback
from keras.optimizers import Adam, Adadelta, SGD, RMSprop, Nadam
from keras import backend as K
def get_model():
    inp = Input(shape=(maxlen,))
    x = Embedding(nb_words, embed_size, weights=[embedding_matrix], trainable=False)(inp)
    x = SpatialDropout1D(0.2)(x)
    x = Bidirectional(CuDNNLSTM(256, return_sequences=True))(x)
    x = Dropout(0.2)(x)
    x = Bidirectional(CuDNNGRU(128, return_sequences=True))(x)
    x = Dropout(0.2)(x)
    avg_pool = GlobalAveragePooling1D()(x)
    max_pool = GlobalMaxPooling1D()(x)
    x = concatenate([avg_pool, max_pool])
    x = Dense(64, activation="relu")(x)
    x = Dense(6, activation="sigmoid")(x)
    model = Model(inputs=inp, outputs=x)
    opt = Adam(lr=1e-3)
    model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy'])
    return model
INPUT = './'
batch_size = 32
epochs = 10
model = get_model()

X_train, X_val = train_test_split(train_sequence, random_state=17, train_size=0.90)
y_train, y_val = train_test_split(y, random_state=17, train_size=0.90)

exp_decay = lambda init, fin, steps: (init/fin)**(1/(steps-1)) - 1
steps = int(len(train_df)/batch_size) * epochs
lr_init, lr_fin = 0.001, 0.0005
lr_decay = exp_decay(lr_init, lr_fin, steps)
K.set_value(model.optimizer.lr, lr_init)
K.set_value(model.optimizer.decay, lr_decay)

num = 0
if not os.path.isdir(INPUT+"models/"):
    os.mkdir(INPUT+"models/")
if not os.path.isdir(INPUT+"models/"+str(num)):
    os.mkdir(INPUT+"models/"+str(num))
file_path_best=INPUT+"models/"+str(num)+"/"+"weights_best"+str(num)+".hdf5"
checkpoint_best = ModelCheckpoint(file_path_best, monitor='val_loss', verbose=1, save_best_only=True, mode='min')
early = EarlyStopping(monitor="val_loss", mode="min", patience=3)

callbacks_list = [checkpoint_best, early]
model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, validation_data=(X_val,y_val), callbacks=callbacks_list)

if os.path.isfile(file_path_best):
    print ('load ',file_path_best)
    model.load_weights(file_path_best)

y_test = model.predict([test_sequence], batch_size=256, verbose=1)


合并词向量预训练模型和自训练模型

合并词向量预训练模型和自训练模型,其中的tokenizer来自上一篇文章。

import numpy as np
import codecs
EMBEDDING_FILE='../glove.6B/crawl-300d-2M.vec'
EMBEDDING_TRAIN = '../glove.6B/vectors_train.txt'
embed_size = 300
#EMBEDDING_FILE=INPUT+'glove.6B/glove.6B.300d.txt'
cn = 0
def get_coefs(word,*arr): 
    global cn
    cn += 1
    dict_v = np.asarray(arr, dtype='float32')
    if len(dict_v)<>embed_size:
        dict_v = np.zeros((embed_size))
    return word, dict_v
f_emb = codecs.open(EMBEDDING_FILE)
emb_list = f_emb.readlines()
embeddings_index = dict(get_coefs(*o.strip().split()) for o in emb_list)
print cn
f_emb.close()
f_emb = codecs.open(EMBEDDING_TRAIN,'r','utf-8')
emb_list = f_emb.readlines()
cn = 0
embeddings_index_train = dict(get_coefs(*o.strip().split()) for o in emb_list)
print cn
f_emb.close()
all_embs = np.stack(embeddings_index.values())
emb_mean,emb_std = all_embs.mean(), all_embs.std()
print emb_mean,emb_std
word_index = tokenizer.word_index
nb_words = min(max_features, len(word_index))
embedding_matrix = np.random.normal(emb_mean, emb_std, (nb_words, embed_size))
novector = 0
for word, i in word_index.items():
    if i >= nb_words: continue
    embedding_vector = embeddings_index.get(word)
    embedding_vector_train = embeddings_index_train.get(word)
    if embedding_vector is not None: embedding_matrix[i] = embedding_vector
    elif embedding_vector_train is not None: 
        embedding_matrix[i] = embedding_vector_train
    else: 
        print word
        novector += 1

其中的自训练模型如下。

full_df = pd.concat([train, test])
full_df.to_csv('text.txt',index=False,sep=' ',quotechar=' ',columns=['text'],header=False,encoding='utf-8') 

"""
Get 'text.txt'.
https://nlp.stanford.edu/projects/glove/

GloVe-1.2.zip
demo.sh:

CORPUS=text.txt
VOCAB_FILE=vocab.txt
COOCCURRENCE_FILE=cooccurrence.bin
COOCCURRENCE_SHUF_FILE=cooccurrence.shuf.bin
BUILDDIR=build
SAVE_FILE=vectors_train
VERBOSE=2
MEMORY=4.0
VOCAB_MIN_COUNT=2
VECTOR_SIZE=300
MAX_ITER=60
WINDOW_SIZE=15
BINARY=2
NUM_THREADS=8
X_MAX=10

You can get "vectors_train.txt".
"""

使用keras.preprocessing进行文本序列化

使用keras.preprocessing进行文本序列化。

from keras.preprocessing import text, sequence
max_features = 200000
maxlen = 500
list_sentences_train = train["text"].fillna("[na]").values
list_sentences_test = test["text"].fillna("[na]").values
tokenizer = text.Tokenizer(num_words=max_features)
tokenizer.fit_on_texts(list(list_sentences_train))
list_tokenized_train = tokenizer.texts_to_sequences(list_sentences_train)
list_tokenized_test = tokenizer.texts_to_sequences(list_sentences_test)
train_sequence = sequence.pad_sequences(list_tokenized_train, maxlen=maxlen)
test_sequence = sequence.pad_sequences(list_tokenized_test, maxlen=maxlen)


多个句子词频统计

使用collections.Counter计算词频,顺便去除只出现1次的单词。

from collections import Counter
cc = Counter()
def get_count(text):
    try:
        text_split = text.strip().split(' ')
        count = Counter(text_split)
        cc.update(count)
        return text_split
    except: 
        return text
def remove_one(text):
    try:
        text = u" ".join([x for x in [y for y in text.strip().split(u" ")] if cc[x] > 1])
        return text
    except: 
        return text
df['text_split'] = df['text'].apply(lambda x: get_count(x))
df['text'] = df['text'].apply(lambda x: remove_one(x))


文本预处理

过滤符号,去掉上标,转换为小写,非英文字符用空格隔开,连续重复字母数大于等于3的只保留1个,去掉指定单词中的空格。

import regex as re
import unicodedata
def process(text):
    try:
        text = re.sub(ur"\p{P}+|\p{Z}+|\p{S}+|\p{N}+", u' ', text)
        text = unicodedata.normalize('NFKD',text)#.encode('ascii','ignore')
        text = re.sub(ur"\p{M}+", u'', text)
        text = re.sub(ur"\p{P}+|\p{S}+|\p{N}+|\p{Cs}+|\p{Cf}+|\p{Co}+", u'', text)
        text = re.sub("([A-Za-z]+)", lambda m:m.group(1).lower(),text)
        text = re.sub(ur'([^\x00-\x7f])', lambda m:u' '+m.group(1)+u' ', text)
        text = re.sub(ur"(\w)\1{2,}",lambda m:m.group(1), text)
        text = re.sub("(\s+)", u' ',text)
        for fword in fword_list:
            f_re = ''
            for i in xrange(len(fword)):
                w = fword[i]
                f_re += w + "+\s*" if i < (len(fword)-1) else w + "+" 
            text = re.sub(f_re, u' '+fword+u' ',text)
        text = re.sub("(\s+)", u' ',text)
        return text
    except: 
        return text
df['text'] = df['text'].apply(lambda x: process(x))