cpuwdl 发布的文章

LeetCode感想

面试考上机,不能用编译器,不能用long long,LeetCode里的第八题atoi,1小时没写完,真惨。我这里显示是5个月前做过,当时写了好久,用的方法也没有规划,速度较慢。当时上机的时候优化了一下,如果能写完速度应该还行。看来做过的题如果没有巩固,下次再碰到不一定能在规定时间内完成,不过要巩固的东西太多了,都掌握还是很困难的。

最近两天刷了一下LeetCode的中等难度题,直接从第二页开始,一天15题,一天17题,其中有一题没想出思路,看了答案。发现有些题目有“Follow up”,如果没有按照更高的要求完成,写起来相对比较容易,后续如果有时间再做一遍,应该要研究一下。现在注意到每次AC都会显示所写的代码在运行时间上打败了多少人,大部分都没办法做到时间最优,经常为了省事多遍历一次,如果靠自己想优化时间感觉很困难,过一遍别人的最优代码吸取一下经验,下一轮可能就能好一点。像那些树和图的题,如果调试的话写起来比较麻烦,其中刚好有很多简单题,直接交的话刷得快一点。好多题都是用递归写的,其中有些题如果不用笔来写,还是挺绕的,部分题目为了避免超时要加一个数组持久化,感觉如果转成动态规划会快一些。目前就一道明显的动态规划,后面应该会有更难的题。

使用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".
"""