Oi Habr.
Na
parte anterior, observei a criação de um reconhecimento de texto simples baseado em uma rede neural. Hoje vamos usar uma abordagem semelhante e escrever um tradutor automático de textos de inglês para alemão.

Para aqueles que estão interessados em como isso funciona, os detalhes estão ocultos.
Nota : este projeto de utilização de uma rede neural para tradução é exclusivamente educacional, portanto a questão “por que” não é considerada. Apenas por diversão. Não pretendo provar que esse ou aquele método seja melhor ou pior, apenas foi interessante verificar o que acontece. O método usado abaixo é, obviamente, simplificado, mas espero que ninguém espere escrever um segundo Lingvo em meia hora.
Coleta de dados
Um arquivo encontrado na rede contendo frases em inglês e alemão separadas por guias foi usado como o conjunto de dados de origem. Um conjunto de frases é mais ou menos assim:
Hi. Hallo! Hi. Grüß Gott! Run! Lauf! Wow! Potzdonner! Wow! Donnerwetter! Fire! Feuer! Help! Hilfe! Help! Zu Hülf! Stop! Stopp! Wait! Warte! Go on. Mach weiter. Hello! Hallo! I ran. Ich rannte. I see. Ich verstehe. ...
O arquivo contém 192 mil linhas e um tamanho de 13 MB. Carregamos o texto na memória e dividimos os dados em dois blocos, para palavras em inglês e alemão.
def read_text(filename): with open(filename, mode='rt', encoding='utf-8') as file: text = file.read() sents = text.strip().split('\n') return [i.split('\t') for i in sents] data = read_text("deutch.txt") deu_eng = np.array(data) deu_eng = deu_eng[:30000,:] print("Dictionary size:", deu_eng.shape)
Também convertemos todas as palavras para minúsculas e removemos os sinais de pontuação.
O próximo passo é preparar os dados para a rede neural. A rede não sabe o que são palavras e trabalha exclusivamente com números. Felizmente para nós, o keras já possui a classe Tokenizer incorporada, que substitui palavras em frases por códigos digitais.
Seu uso é simplesmente ilustrado com um exemplo:
from keras.preprocessing.text import Tokenizer from keras.preprocessing.sequence import pad_sequences s = "To be or not to be" eng_tokenizer = Tokenizer() eng_tokenizer.fit_on_texts([s]) seq = eng_tokenizer.texts_to_sequences([s]) seq = pad_sequences(seq, maxlen=8, padding='post') print(seq)
A frase “ser ou não ser” será substituída pela matriz [1 2 3 4 1 2 0 0], onde não é difícil adivinhar, 1 = para, 2 = ser, 3 = ou, 4 = não. Já podemos enviar esses dados para a rede neural.
Treinamento em redes neurais
Nossos dados estão prontos digitalmente. Dividimos a matriz em dois blocos para dados de entrada (linhas em inglês) e saída (linhas em alemão). Também prepararemos uma unidade separada para validar o processo de aprendizado.
Agora podemos criar um modelo de rede neural e iniciar seu treinamento. Como você pode ver, a rede neural contém camadas LSTM com células de memória. Embora provavelmente funcione em uma rede "regular", quem desejar pode verificar por conta própria.
def make_model(in_vocab, out_vocab, in_timesteps, out_timesteps, n): model = Sequential() model.add(Embedding(in_vocab, n, input_length=in_timesteps, mask_zero=True)) model.add(LSTM(n)) model.add(Dropout(0.3)) model.add(RepeatVector(out_timesteps)) model.add(LSTM(n, return_sequences=True)) model.add(Dropout(0.3)) model.add(Dense(out_vocab, activation='softmax')) model.compile(optimizer=optimizers.RMSprop(lr=0.001), loss='sparse_categorical_crossentropy') return model eng_vocab_size = len(eng_tokenizer.word_index) + 1 deu_vocab_size = len(deu_tokenizer.word_index) + 1 eng_length, deu_length = 8, 8 model = make_model(eng_vocab_size, deu_vocab_size, eng_length, deu_length, 512) num_epochs = 40 model.fit(trainX, trainY.reshape(trainY.shape[0], trainY.shape[1], 1), epochs=num_epochs, batch_size=512, validation_split=0.2, callbacks=None, verbose=1) model.save('en-de-model.h5')
O treinamento em si é mais ou menos assim:

O processo, como você pode ver, não é rápido e leva cerca de meia hora em uma Core i7 + GeForce 1060 para um conjunto de 30 mil linhas. No final do treinamento (ele precisa ser feito apenas uma vez), o modelo é salvo em um arquivo e pode ser reutilizado.
Para obter a tradução, usamos a função predict_classes, cuja entrada enviamos algumas frases simples. A função get_word é usada para inverter palavras em números.
model = load_model('en-de-model.h5') def get_word(n, tokenizer): if n == 0: return "" for word, index in tokenizer.word_index.items(): if index == n: return word return "" phrs_enc = encode_sequences(eng_tokenizer, eng_length, ["the weather is nice today", "my name is tom", "how old are you", "where is the nearest shop"]) preds = model.predict_classes(phrs_enc) print("Preds:", preds.shape) print(preds[0]) print(get_word(preds[0][0], deu_tokenizer), get_word(preds[0][1], deu_tokenizer), get_word(preds[0][2], deu_tokenizer), get_word(preds[0][3], deu_tokenizer)) print(preds[1]) print(get_word(preds[1][0], deu_tokenizer), get_word(preds[1][1], deu_tokenizer), get_word(preds[1][2], deu_tokenizer), get_word(preds[1][3], deu_tokenizer)) print(preds[2]) print(get_word(preds[2][0], deu_tokenizer), get_word(preds[2][1], deu_tokenizer), get_word(preds[2][2], deu_tokenizer), get_word(preds[2][3], deu_tokenizer)) print(preds[3]) print(get_word(preds[3][0], deu_tokenizer), get_word(preds[3][1], deu_tokenizer), get_word(preds[3][2], deu_tokenizer), get_word(preds[3][3], deu_tokenizer))
Resultados
Agora, na verdade, o mais curioso são os resultados. É interessante ver como a rede neural aprende e "lembra" a correspondência entre frases em inglês e alemão. Eu especificamente tomei 2 frases mais fáceis e 2 mais difíceis de ver a diferença.
5 minutos de treinamento“O tempo está bom hoje” - “das ist ist tom”
"Meu nome é tom" - "wie für tom tom"
"Quantos anos você tem" - "wie geht ist es"
"Onde fica a loja mais próxima" - "wo ist der"
Como você pode ver, até agora existem poucos "hits". Um fragmento da frase “quantos anos você tem” confundiu a rede neural com a frase “como você está” e produziu a tradução “wie geht ist es” (como você está?). Na frase “onde está ...”, a rede neural identificou apenas o verbo where e produziu a tradução “wo ist der” (onde está?). Que, em princípio, não deixa de ter significado. Em geral, aproximadamente o mesmo que traduz para o alemão um recém-chegado ao grupo A1;)
10 minutos de treinamento“O tempo está bom hoje” - “das haus ist bereit”
"Meu nome é tom" - "mein heiße heiße tom"
"Quantos anos você tem" - "wie alt sind sie"
"Onde fica a loja mais próxima" - "wo ist paris"
Algum progresso é visível. A primeira frase está completamente fora de lugar. Na segunda frase, a rede neural “aprendeu” o verbo heißen (chamado), mas “mein heiße heiße tom” ainda está incorreta, embora você já possa adivinhar o significado. A terceira frase já está correta. Na quarta, a primeira parte correta é “wo ist”, mas a loja mais próxima foi substituída por algum motivo por paris.
30 minutos de treinamento“O tempo está bom hoje” - “das ist ist aus”
"Meu nome é tom" - "" tom "é meu nome"
"Quantos anos você tem" - "wie alt sind sie"
"Onde fica a loja mais próxima" - "wo ist der"
Como você pode ver, a segunda frase se tornou correta, embora o design pareça um tanto incomum. A terceira frase está correta, mas a primeira e a quarta frases ainda não foram "aprendidas". Com isso
para economizar eletricidade, terminei o processo.
Conclusão
Como você pode ver, em princípio, isso funciona. Gostaria de memorizar um novo idioma com tanta velocidade :) Obviamente, o resultado não é perfeito até agora, mas o treinamento em um conjunto completo de 190 mil linhas levaria mais de uma hora.
Para aqueles que querem experimentar por conta própria, o código-fonte está sob o spoiler. Teoricamente, o programa pode usar qualquer par de idiomas, não apenas inglês e alemão (o arquivo deve estar na codificação UTF-8). A questão da qualidade da tradução também permanece em aberto, há algo a ser testado.
O dicionário em si é muito grande para anexar ao artigo, o link está nos comentários.
Como sempre, todas as experiências bem-sucedidas.