2018年9月

使用Kaggle的步骤

我在参与新类型Kaggle竞赛时采用的步骤如下,在赛程一半的时候进入(很多图像类竞赛没办法用Kernel跑完,可以在Discussion里找github上的代码,或者直接上github搜baseline代码,用谷歌搜比赛名也会出来不少github代码)。

  1. 仔细阅读Overview和Data中的内容。

  2. 下载数据后,对Kernels分数排序,优先查看分数高的和票数高的,如果某个Kernel是fork别人的,先看源头,选择几个采用不同方法的代码复制下来跑,感受下运行时间和效果。

  3. 按照方法名称搜原理,基本看懂这个方法的用途、优缺点、有哪些参数影响较大。

  4. 查看该方法的文档,对照着手上的代码看懂,然后把文档看几遍,里面会有少量技巧和调参方法,然后搜一下他人对参数的理解。

  5. 手工调参,看时间和效果的变化(本地和提交的差距)。

  6. 查看Kernels中的EDA,增加对这些数据的感受,大概记一下数据的分布、范围、意义。

  7. 查看Kernels中fork别人然后改进的代码,找一下哪里的代码变了,分析一下为什么好,是否会过拟合。

  8. 尝试自己想一些预处理方法,或者是特征工程,看效果。

  9. 然后再手工调参,注意观察Discussion里大家的讨论,有时候会有一些灵感,也可以直接根据提示写代码执行。

  10. 在觉得排名还可以时,可以使用多折平均,分数一般都会好一些,而且减少过拟合的概率。

  11. 调参可以使用Grid或者Bayesian Optimization。

  12. 使用不同方法得到相似分数的结果进行平均,通常分数可以高一截。

  13. 尝试stacking,方式很多,有时会过拟合,处理得好可以提高非常多,融合多个方法,多层stacking。

  14. 手工平均可以根据验证集的分数选择合适的权重,也可以根据测试集分数选择权重。注意在选择哪些结果进行平均时,可以计算一下相关系数corr,选择相关系数小并且在测试集表现不错的结果进行平均。

  15. 有些情况下伪标签效果不错。

  16. 选择最终的两个提交很重要,如果测试数据非常多,分布也很均匀(比如正例只有1%就是不均匀),基本上可以尽情过拟合。根据一定逻辑进行后处理风险很大。小测试数据对stacking很敏感,不过直接平均的方法在小数据上一般都还行。

  17. 可以看到这里用的很多方法,在工作环境中是没有的,我猜测优化单模型是主流,而且我在参与过程中花时间最多的也是优化单模型,融合水平很低。如何根据Kaggle中学到的知识解决实际问题,是我非常想知道的。

设计简单的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)