TensorFlow / Keras-如何正确转换文本?

时间:2018-12-08 23:19:33

标签: python tensorflow machine-learning keras

我正在尝试创建一个模型,该模型确定句子的主要主题是否是布拉格市。

句子使用斯洛伐克语。即:

  

“ V Prahe bolo dobre”,“ Praha je vČesku” ...

我的csv文件如下:

Praha je v Česku,1 
Chodím do Blavy,0 
Neviem čo to je za vetu,0
Pražský hrad,1

如您所见,布拉格一词具有多种形式,所以我不想仅将csv中的每个词替换为某个数字。我的目标是在角色级别上进行检测。

尝试过:

train = pandas.read_csv("prague_train_set.csv",
                        usecols=[ "title"])

train['title'] = train['title'].fillna("None")
train['title'] = le.fit_transform(train['title'])

results = pandas.read_csv("prague_train_set.csv",
                        usecols=["result"])    

# create model
model = Sequential()
model.add(Dense(12, input_dim=1, init='uniform', activation='relu'))
model.add(Dense(10, init='uniform', activation='relu'))
model.add(Dense(1, init='uniform', activation='sigmoid'))
# Compile model
model.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])
# Fit the model
model.fit(train, results, epochs=150, batch_size=10, verbose=2)
# calculate predictions
predictions = model.predict(train)

但是输出就像是完全随机的:

编辑,大​​约1/4的书名与布拉格有关

...
Epoch 145/150
 - 0s - loss: 0.1826 - acc: 0.7589
Epoch 146/150
 - 0s - loss: 0.1827 - acc: 0.7589
Epoch 147/150
 - 0s - loss: 0.1826 - acc: 0.7589
Epoch 148/150
 - 0s - loss: 0.1827 - acc: 0.7589
Epoch 149/150
 - 0s - loss: 0.1827 - acc: 0.7589
Epoch 150/150
 - 0s - loss: 0.1827 - acc: 0.7589

我认为这是因为train['title'] = le.fit_transform(train['title'])将整个句子转换为数字,但不确定。你知道该怎么办吗?

1 个答案:

答案 0 :(得分:0)

因为您要在字符级别上进行分类,所以我建议使用CHAR-CNN:

https://papers.nips.cc/paper/5782-character-level-convolutional-networks-for-text-classification.pdf

要处理数据,您只需要做两件事:

1)获取一组您要使用的字符-这可能是每个字符(包括标点符号)或只是最常见的字符

2)建立并将字符编码保存为整数。如果您未使用1)中定义的集合内的所有字符,请为未知字符创建一个整数

3)修剪或填充句子以使其具有标准长度

下面是一个简单的CHAR-CNN示例,旨在预测字符串中是否存在“ a”:

首先预处理数据: 此代码可能类似于:

import numpy as np
import sympy as sp
import itertools as it
from sympy.abc import x, y, z


class Solver:
    def __init__(self, vmat):
        self._vfunc = sp.lambdify((x, y, z),
                                  expr=vmat,
                                  modules='numpy')
        self._q_count, self._qs = None, []  # these depend on ksep!

    ################################################################
    # How to vectorize this?
    def eval_s(self, stiff):
        assert len(self._qs) == self._q_count, "Run 'populate_qs' first!"
        result = 0
        for k in self._qs:
            evs = np.linalg.eigvalsh(self._vfunc(*k))
            result += np.sum(np.divide(1., (stiff + evs)))
        return result.real - 4 * self._q_count
    ################################################################

    def populate_qs(self, ksep: float = 1.7):
        self._qs = [(kx, ky, kz) for kx, ky, kz
                    in it.product(np.arange(-3*np.pi, 3.01*np.pi, ksep),
                                  np.arange(-3*np.pi, 3.01*np.pi, ksep),
                                  np.arange(-3*np.pi, 3.01*np.pi, ksep))]
        self._q_count = len(self._qs)


def test():
    vmat = sp.Matrix([[1, sp.cos(x/4+y/4), sp.cos(x/4+z/4), sp.cos(y/4+z/4)],
                      [sp.cos(x/4+y/4), 1, sp.cos(y/4-z/4), sp.cos(x/4 - z/4)],
                      [sp.cos(x/4+z/4), sp.cos(y/4-z/4), 1, sp.cos(x/4-y/4)],
                      [sp.cos(y/4+z/4), sp.cos(x/4-z/4), sp.cos(x/4-y/4), 1]]) * 2
    solver = Solver(vmat)
    solver.populate_qs(ksep=1.7)  # <---- Performance starts to worsen (in eval_s) when ksep is reduced!
    print(solver.eval_s(0.65))


if __name__ == "__main__":
    import timeit
    print(timeit.timeit("test()", setup="from __main__ import test", number=100))

将编码字典保存在某个位置,您可以将所有输入转换为整数:

from random import choice

lowercase = 'abcdefghijklmnopqrstuvwxyz'
x = [''.join(choice(lowercase) for _ in range(10)) for _ in range(5000)]
y = [int('a' in i) for i in x]

char_set = set(char for word in x for char in word)
encoding = {i: char+1 for char, i in enumerate(char_set)} # let 0 be the unknown character

然后填充序列:

x = [[encoding.get(char, 0) for char in sentence] for sentence in x]

每个句子变成一个整数列表。

对数据进行预处理后,您将构建模型。由于我们的预处理数据是整数列表,因此我们将遇到一个大问题:

如果“ a” => 2和“ b” => 7,则即使不正确,模型也会天真地假定为“ b”>“ a”。

为解决这个问题(并使模型建立每个字符的内部表示形式),我将使用嵌入层将每个字符映射到N维向量。

max_len = max(len(i) for i in x)

from keras.preprocessing.sequence import pad_sequences
x = pad_sequences(x, maxlen=max_len)

在此阶段,我们可以使用Conv1D图层开始检测特征。不幸的是,我无法为您提供确切的超参数,因为我无法访问您的整个数据集,因此,这只是一个示例模型。

from keras.models import Sequential
from keras.layers import Embedding, Conv1D, GlobalMaxPooling1D, Dense

VOCAB_SIZE = len(encoding) + 1
N_VECTORS = 12

model = Sequential()
model.add(Embedding(VOCAB_SIZE, N_VECTORS, input_length = max_len))

由于在此阶段我们正在处理3D张量(嵌入层返回3D输出model.add(Conv1D(64, kernel_size=(3,))) model.add(Conv1D(32, kernel_size=(3,))) ,并且我们想返回2D输出(batch_size, max_len, N_VECTORS)),所以我们将输出和提要最大化变成致密层。

(batch_size, one_or_zero)

为方便起见,最后我上传了我在pastebin:https://pastebin.com/SvvJaQJv上使用的完整代码副本。在玩具数据集上运行模型可在2个纪元内获得100%的准确性。

我希望这个答案可以使您更好地理解为nlp预处理文本以及可以使用的一些技术。祝你好运!