«Глубокое применение» НЛП Машинный перевод Глубокое обучение Практический курс 1 (база RNN)

глубокое обучение

Глубокое обучение используется уже более года, и недавно начались исследования и разработки естественной обработки НЛП. Только что воспользовался этой возможностью, чтобы написать серию практических курсов глубокого обучения по машинному переводу НЛП.

Эта серия курсов будет проходить от объяснения принципов и обработки данных до практической практики и развертывания приложений и будет включать следующее содержание: (обновление)

Справочные блоги для этой серии руководств:Что.CSDN.net/Китай тел Эко…

Адрес в открытом доступе:GitHub.com/ Xiao Song ...

Домашняя страница:www.yansongsong.cn/

0. Предыстория проекта

В предыдущей статье мы кратко представили машинный перевод NLP, на этот раз мы объясним модель перевода на основе RNN на практике.

0.1 Введение в модель трансляции архитектуры seq2seq на основе RNN

структура seq2seq

Архитектура seq2seq на основе RNN включает кодировщик и декодер. Часть декодера разделена на два процесса: обучение и вывод. Конкретная структура показана на следующих двух рисунках:

Видно, что структура очень проста (по сравнению с CNN и базой Attention).Далее мы реализуем ее в виде кода для дальнейшего изучения и понимания внутренних принципов модели.

1. Подготовка данных

1.1 Загрузка данных

 

этот сайтwww.manythings.org/anki/На веб-сайте много данных для перевода, в том числе на многие языки, здесь в этом руководстве выбран набор данных с китайского на английский.

Адрес для скачивания обучения:woohoo.many Things.org/ankangi/from next year — гм…

Разархивируйте cmn-eng.zip, вы можете найти файл cmn.txt, содержание следующее:

with open('cmn.txt', 'r', encoding='utf-8') as f:
['Tom died.\t汤姆去世了。', 'Tom quit.\t汤姆不干了。', 'Tom swam.\t汤姆游泳了。', 'Trust me.\t相信我。', 'Try hard.\t努力。']


Можно обнаружить, что каждая пара данных перевода находится в одной строке, с английским языком слева и китайским справа, используя \t в качестве границы между английским и китайским языками.

1.2 Предварительная обработка данных

Использование обучения сети требует от нас обработки данных в формате, который может принять сеть.

Именно для этих данных необходимо преобразовать символы в числа (оцифровка предложений) и нормализовать длину предложений.

Оцифровка предложения

Вы можете обратиться к этому моему блогу:Учебное пособие для прессы с открытым исходным кодом «Применение глубины» NLP Name Entity Identification (NER), Реализация предварительной обработки данных.

Английские и китайские символы обрабатываются отдельно.

английская обработка

Поскольку каждое слово в английском языке отделяется пробелом (за исключением аббревиатур, которые здесь рассматриваются как одно слово), а между знаками препинания и словами нет разделения, также требуется особое обращение.

Здесь я использую простой метод добавления пробелов перед знаками препинания:

def split_dot(strs,dots=", . ! ?"):

for d in dots.split(" "):

        strs = strs.replace(d," "+d)

Используйте этот метод для словаря слов:

for token in sample.split(" "):

if token not in w_all_dict.keys():

    sort_w_list = sorted(w_all_dict.items(),  key=lambda d: d[1], reverse=True)

    w_keys = [x for x,_ in sort_w_list[:7000-2]]

    w_dict = { x:i for i,x in enumerate(w_keys) }

    i_dict = { i:x for i,x in enumerate(w_keys) }

Китайская обработка

При общении с китайцами можно обнаружить, что есть традиционные и упрощенные формы, поэтому лучше конвертировать в унифицированную форму :(Справочный адрес)

pip install opencc-python-reimplemented

Используйте метод для преобразования традиционного в упрощенный:

cc = opencc.OpenCC('t2s')

Затем используйте метод сегментации слов jieba, чтобы отделить слова от предложений:

def get_chn_dicts(datas):

for token in jieba.cut(sample):

if token not in w_all_dict.keys():

    sort_w_list = sorted(w_all_dict.items(),  key=lambda d: d[1], reverse=True)

    w_keys = [x for x,_ in sort_w_list[:10000-4]]

    w_dict = { x:i for i,x in enumerate(w_keys) }

    i_dict = { i:x for i,x in enumerate(w_keys) }

отступ ниже

def padding(lists,lens=LENS):

Наконец, запустите его равномерно:

if __name__ == "__main__":

    df = read2df("cmn-eng/cmn.txt")

    eng_dict,id2eng = get_eng_dicts(df["eng"])

    chn_dict,id2chn = get_chn_dicts(df["chn"])

    print(list(eng_dict.keys())[:20])

    print(list(chn_dict.keys())[:20])

    enc_in = [[get_val(e,eng_dict) for e in eng.split(" ")] for eng in df["eng"]]

    dec_in = [[get_val("<GO>",chn_dict)]+[get_val(e,chn_dict) for e in jieba.cut(eng)]+[get_val("<EOS>",chn_dict)] for eng in df["chn"]]

    dec_out = [[get_val(e,chn_dict) for e in jieba.cut(eng)]+[get_val("<EOS>",chn_dict)] for eng in df["chn"]]

    enc_in_ar = np.array(padding(enc_in,32))

    dec_in_ar = np.array(padding(dec_in,30))

    dec_out_ar = np.array(padding(dec_out,30))

Результат выглядит следующим образом:

(TF_GPU) D:\Files\Prjs\Pythons\Kerases\MNT_RNN>C:/Datas/Apps/RJ/Miniconda3/envs/TF_GPU/python.exe d:/Files/Prjs/Pythons/Kerases/MNT_RNN/mian.py        

Using TensorFlow backend.

Building prefix dict from the default dictionary ...

Loading model from cache C:\Users\xiaos\AppData\Local\Temp\jieba.cache

Loading model cost 0.788 seconds.

Prefix dict has been built succesfully.

['<UNK>', '<PAD>', '.', 'I', 'to', 'the', 'you', 'a', '?', 'is', 'Tom', 'He', 'in', 'of', 'me', ',', 'was', 'for', 'have', 'The']

['<UNK>', '<PAD>', '<GO>', '<EOS>', '。', '我', '的', '了', '你', '他', '?', '在', '汤姆', '是', '她', '吗', '我们', ',', '不', '很']
  1. Построить и обучить модель

2.1 Построение модели и гиперпараметры

Используется двухуровневая сеть LSTM.

from keras.models import Model

from keras.layers import Input, LSTM, Dense, Embedding,CuDNNLSTM

from keras.optimizers import Adam

    encoder_inputs = Input(shape=(None,))

    emb_inp = Embedding(output_dim=128, input_dim=EN_VOCAB_SIZE)(encoder_inputs)

    encoder_h1, encoder_state_h1, encoder_state_c1 = CuDNNLSTM(HIDDEN_SIZE, return_sequences=True, return_state=True)(emb_inp)

    encoder_h2, encoder_state_h2, encoder_state_c2 = CuDNNLSTM(HIDDEN_SIZE, return_state=True)(encoder_h1)

    decoder_inputs = Input(shape=(None,))

    emb_target = Embedding(output_dim=128, input_dim=CH_VOCAB_SIZE)(decoder_inputs)

    lstm1 = CuDNNLSTM(HIDDEN_SIZE, return_sequences=True, return_state=True)

    lstm2 = CuDNNLSTM(HIDDEN_SIZE, return_sequences=True, return_state=True)

    decoder_dense = Dense(CH_VOCAB_SIZE, activation='softmax')

    decoder_h1, _, _ = lstm1(emb_target, initial_state=[encoder_state_h1, encoder_state_c1])

    decoder_h2, _, _ = lstm2(decoder_h1, initial_state=[encoder_state_h2, encoder_state_c2])

    decoder_outputs = decoder_dense(decoder_h2)

    model = Model([encoder_inputs, decoder_inputs], decoder_outputs)

    encoder_model = Model(encoder_inputs, [encoder_state_h1, encoder_state_c1, encoder_state_h2, encoder_state_c2])

    decoder_state_input_h1 = Input(shape=(HIDDEN_SIZE,))

    decoder_state_input_c1 = Input(shape=(HIDDEN_SIZE,))

    decoder_state_input_h2 = Input(shape=(HIDDEN_SIZE,))

    decoder_state_input_c2 = Input(shape=(HIDDEN_SIZE,))

    decoder_h1, state_h1, state_c1 = lstm1(emb_target, initial_state=[decoder_state_input_h1, decoder_state_input_c1])

    decoder_h2, state_h2, state_c2 = lstm2(decoder_h1, initial_state=[decoder_state_input_h2, decoder_state_input_c2])

    decoder_outputs = decoder_dense(decoder_h2)

    decoder_model = Model([decoder_inputs, decoder_state_input_h1, decoder_state_input_c1, decoder_state_input_h2, decoder_state_input_c2], 

                        [decoder_outputs, state_h1, state_c1, state_h2, state_c2])

return(model,encoder_model,decoder_model)

2.2 Конфигурация модели и обучение

Аккаунт настроен для удобного отображения, но встроенный акк keras использовать нельзя

import keras.backend as K

from keras.models import load_model

def my_acc(y_true, y_pred):

    acc = K.cast(K.equal(K.max(y_true,axis=-1),K.cast(K.argmax(y_pred,axis=-1),K.floatx())),K.floatx())

if __name__ == "__main__":

    df = read2df("cmn-eng/cmn.txt")

    eng_dict,id2eng = get_eng_dicts(df["eng"])

    chn_dict,id2chn = get_chn_dicts(df["chn"])

    print(list(eng_dict.keys())[:20])

    print(list(chn_dict.keys())[:20])

    enc_in = [[get_val(e,eng_dict) for e in eng.split(" ")] for eng in df["eng"]]

    dec_in = [[get_val("<GO>",chn_dict)]+[get_val(e,chn_dict) for e in jieba.cut(eng)]+[get_val("<EOS>",chn_dict)] for eng in df["chn"]]

    dec_out = [[get_val(e,chn_dict) for e in jieba.cut(eng)]+[get_val("<EOS>",chn_dict)] for eng in df["chn"]]

    enc_in_ar = np.array(padding(enc_in,32))

    dec_in_ar = np.array(padding(dec_in,30))

    dec_out_ar = np.array(padding(dec_out,30))

        model,encoder_model,decoder_model = get_model()

        model.load_weights('e2c1.h5')

        opt = Adam(lr=LEARNING_RATE, beta_1=0.9, beta_2=0.99, epsilon=1e-08)

        model.compile(optimizer=opt, loss='sparse_categorical_crossentropy',metrics=[my_acc])

        model.fit([enc_in_ar, dec_in_ar], np.expand_dims(dec_out_ar,-1),

        encoder_model.save("enc1.h5")

        decoder_model.save("dec1.h5")

Результаты обучения 64Epoch следующие:

__________________________________________________________________________________________________

Layer (type)                    Output Shape         Param #     Connected to

==================================================================================================

input_1 (InputLayer)            (None, None)         0

__________________________________________________________________________________________________

input_2 (InputLayer)            (None, None)         0

__________________________________________________________________________________________________

embedding_1 (Embedding)         (None, None, 128)    896000      input_1[0][0]

__________________________________________________________________________________________________

embedding_2 (Embedding)         (None, None, 128)    1280000     input_2[0][0]

__________________________________________________________________________________________________

cu_dnnlstm_1 (CuDNNLSTM)        [(None, None, 256),  395264      embedding_1[0][0]

__________________________________________________________________________________________________

cu_dnnlstm_3 (CuDNNLSTM)        [(None, None, 256),  395264      embedding_2[0][0]

__________________________________________________________________________________________________

cu_dnnlstm_2 (CuDNNLSTM)        [(None, 256), (None, 526336      cu_dnnlstm_1[0][0]

__________________________________________________________________________________________________

cu_dnnlstm_4 (CuDNNLSTM)        [(None, None, 256),  526336      cu_dnnlstm_3[0][0]

__________________________________________________________________________________________________

dense_1 (Dense)                 (None, None, 10000)  2570000     cu_dnnlstm_4[0][0]

==================================================================================================

__________________________________________________________________________________________________

19004/19004 [==============================] - 98s 5ms/step - loss: 0.1371 - my_acc: 0.9832 - val_loss: 2.7299 - val_my_acc: 0.7412

19004/19004 [==============================] - 96s 5ms/step - loss: 0.1234 - my_acc: 0.9851 - val_loss: 2.7378 - val_my_acc: 0.7410

19004/19004 [==============================] - 96s 5ms/step - loss: 0.1132 - my_acc: 0.9867 - val_loss: 2.7477 - val_my_acc: 0.7419

19004/19004 [==============================] - 96s 5ms/step - loss: 0.1050 - my_acc: 0.9879 - val_loss: 2.7660 - val_my_acc: 0.7426

19004/19004 [==============================] - 96s 5ms/step - loss: 0.0983 - my_acc: 0.9893 - val_loss: 2.7569 - val_my_acc: 0.7408

19004/19004 [==============================] - 96s 5ms/step - loss: 0.0933 - my_acc: 0.9903 - val_loss: 2.7775 - val_my_acc: 0.7414

19004/19004 [==============================] - 96s 5ms/step - loss: 0.0885 - my_acc: 0.9911 - val_loss: 2.7885 - val_my_acc: 0.7420

19004/19004 [==============================] - 96s 5ms/step - loss: 0.0845 - my_acc: 0.9920 - val_loss: 2.7914 - val_my_acc: 0.7423
  1. Применение модели и прогноз

Выберите некоторые данные из обучающего набора для тестирования

if __name__ == "__main__":

df = read2df("cmn-eng/cmn.txt")

eng_dict,id2eng = get_eng_dicts(df["eng"])

chn_dict,id2chn = get_chn_dicts(df["chn"])

print(list(eng_dict.keys())[:20])

print(list(chn_dict.keys())[:20])

enc_in = [[get_val(e,eng_dict) for e in eng.split(" ")] for eng in df["eng"]]

dec_in = [[get_val("<GO>",chn_dict)]+[get_val(e,chn_dict) for e in jieba.cut(eng)]+[get_val("<EOS>",chn_dict)] for eng in df["chn"]]

dec_out = [[get_val(e,chn_dict) for e in jieba.cut(eng)]+[get_val("<EOS>",chn_dict)] for eng in df["chn"]]

enc_in_ar = np.array(padding(enc_in,32))

dec_in_ar = np.array(padding(dec_in,30))

dec_out_ar = np.array(padding(dec_out,30))

encoder_model,decoder_model = load_model("enc1.h5",custom_objects={"my_acc":my_acc}),load_model("dec1.h5",custom_objects={"my_acc":my_acc})

for k in range(16000-20,16000):

test_data = enc_in_ar[k:k+1]

h1, c1, h2, c2 = encoder_model.predict(test_data)

target_seq = np.zeros((1,1))

target_seq[0, len(outputs)] = chn_dict["<GO>"]

output_tokens, h1, c1, h2, c2 = decoder_model.predict([target_seq, h1, c1, h2, c2])

sampled_token_index = np.argmax(output_tokens[0, -1, :])

outputs.append(sampled_token_index)

target_seq[0, 0] = sampled_token_index

if sampled_token_index == chn_dict["<EOS>"] or len(outputs) > 28: break

print("< "+' '.join([id2chn[i] for i in outputs[:-1]]))

Результаты проверки таковы: в основном все переводы верны.

> I can understand you to some extent .

> I can't recall the last time we met .

< 我 想不起来 我们 上次 见面 的 情况 了 。

> I can't remember which is my racket .

> I can't stand that noise any longer .

> I can't stand this noise any longer .

> I caught the man stealing the money .

> I could not afford to buy a bicycle .

> I couldn't answer all the questions .

> I couldn't think of anything to say .

> I cry every time I watch this movie .

> I did not participate in the dialog .

> I didn't really feel like going out .

> I don't care a bit about the future .