机器翻译:谷歌翻译是如何对几乎所有语言进行翻译的?

谷歌翻译大家想必都不陌生,但你有没有想过,它究竟是如何将几乎所有的已知语言翻译成我们所选择的语言?

作者:读芯术来源:今日头条|2020-10-11 22:05

收藏

分享

谷歌翻译大家想必都不陌生,但你有没有想过,它究竟是如何将几乎所有的已知语言翻译成我们所选择的语言?本文将解开这个谜团,并且向各位展示如何用长短期记忆网络(LSTM)构建语言翻译程序。

本文分为两部分。第一部分简单介绍神经网络机器翻译(NMT)和编码器-解码器(Encoder-Decoder)结构。第二部分提供了使用Python创建语言翻译程序的详细步骤。

图源:谷歌

什么是机器翻译?

机器翻译是计算语言学的一个分支,主要研究如何将一种语言的源文本自动转换为另一种语言的文本。在机器翻译领域,输入已经由某种语言的一系列符号组成,而计算机必须将其转换为另一种语言的一系列符号。

神经网络机器翻译是针对机器翻译领域所提出的主张。它使用人工神经网络来预测某个单词序列的概率,通常在单个集成模型中对整个句子进行建模。

凭借神经网络的强大功能,神经网络机器翻译已经成为翻译领域最强大的算法。这种最先进的算法是深度学习的一项应用,其中大量已翻译句子的数据集用于训练能够在任意语言对之间的翻译模型。

谷歌语言翻译程序

理解Seq2Seq架构

顾名思义,Seq2Seq将单词序列(一个或多个句子)作为输入,并生成单词的输出序列。这是通过递归神经网络(RNN)实现的。具体来说,就是让两个将与某个特殊令牌一起运行的递归神经网络尝试根据前一个序列来预测后一个状态序列。

一种简单的编码器-解码器架构

它主要由编码器和解码器两部分构成,因此有时候被称为编码器-解码器网络。

· 编码器:使用多个深度神经网络层,将输入单词转换为相应的隐藏向量。每个向量代表当前单词及其语境。

· 解码器:与编码器类似。它将编码器生成的隐藏向量、自身的隐藏状态和当前单词作为输入,从而生成下一个隐藏向量,最终预测下一个单词。

任何神经网络机器翻译的最终目标都是接收以某种语言输入的句子,然后将该句子翻译为另一种语言作为输出结果。下图是一个汉译英翻译算法的简单展示:

将“Knowledge ispower”翻译成汉语。

它如何运行?

第一步,通过某种方式将文本数据转换为数字形式。为了在机器翻译中实现这一点,需要将每个单词转换为可输入到模型中的独热编码(One Hot Encoding)向量。独热编码向量是在每个索引处都为0(仅在与该特定单词相对应的单个索引处为1)的向量。

独热编码

为输入语言中的每个唯一单词设置索引来创建这些向量,输出语言也是如此。为每个唯一单词分配唯一索引时,也就创建了针对每种语言的所谓的“词汇表”。理想情况下,每种语言的词汇表将仅包含该语言的每个唯一单词。

如上图所示,每个单词都变成了一个长度为9(这是词汇表的大小)的向量,索引中除去一个1以外,其余全部都是0。

通过为输入和输出语言创建词汇表,人们可以将该技术应用于任何语言中的任何句子,从而将语料库中所有已翻译的句子彻底转换为适用于机器翻译任务的格式。

现在来一起感受一下编码器-解码器算法背后的魔力。在最基本的层次上,模型的编码器部分选择输入语言中的某个句子,并从该句中创建一个语义向量(thought vector)。该语义向量存储句子的含义,然后将其传递给解码器,解码器将句子译为输出语言。

编码器-解码器结构将英文句子“Iam astudent”译为德语

就编码器来说,输入句子的每个单词会以多个连续的时间步分别输入模型。在每个时间步(t)中,模型都会使用该时间步输入到模型单词中的信息来更新隐藏向量(h)。

该隐藏向量用来存储输入句子的信息。这样,因为在时间步t=0时尚未有任何单词输入编码器,所以编码器在该时间步的隐藏状态从空向量开始。下图以蓝色框表示隐藏状态,其中下标t=0表示时间步,上标E表示它是编码器(Encoder)的隐藏状态[D则用来表示解码器(Decoder)的隐藏状态]。

在每个时间步中,该隐藏向量都会从该时间步的输入单词中获取信息,同时保留从先前时间步中存储的信息。因此,在最后一个时间步中,整个输入句子的含义都会储存在隐藏向量中。最后一个时间步中的隐藏向量就是上文中提到的语义向量,它之后会被输入解码器。

另外,请注意编码器中的最终隐藏向量如何成为语义向量并在t=0时用上标D重新标记。这是因为编码器的最终隐藏向量变成了解码器的初始隐藏向量。通过这种方式,句子的编码含义就传递给了解码器,从而将其翻译成输出语言。但是,与编码器不同,解码器需要输出长度可变的译文。因此,解码器将在每个时间步中输出一个预测词,直到输出一个完整的句子。

开始翻译之前,需要输入<SOS>标签作为解码器第一个时间步的输入。与编码器一样,解码器将在时间步t=1处使用<SOS>输入来更新其隐藏状态。但是,解码器不仅会继续进行到下一个时间步,它还将使用附加权重矩阵为输出词汇表中的所有单词创建概率。这样,输出词汇表中概率最高的单词将成为预测输出句子中的第一个单词。

解码器必须输出长度可变的预测语句,它将以该方式继续预测单词,直到其预测语句中的下一个单词为<EOS>标签。一旦该标签预测完成,解码过程就结束了,呈现出的是输入句子的完整预测翻译。

通过Keras和Python实现神经网络机器翻译

了解了编码器-解码器架构之后,创建一个模型,该模型将通过Keras和python把英语句子翻译成法语。第一步,导入需要的库,为将在代码中使用的不同参数配置值。

  1. #Import Libraries
  2. import os, sys
  3. from keras.models importModel
  4. from keras.layers importInput, LSTM, GRU, Dense, Embedding
  5. fromkeras.preprocessing.text importTokenizer         fromkeras.preprocessing.sequence import pad_sequences
  6. from keras.utils import to_categorical
  7. import numpy as np
  8. import pandas as pd
  9. import pickle
  10. importmatplotlib.pyplot as plt
  11. #Values fordifferent parameters:         BATCH_SIZE=64
  12. EPOCHS=20
  13. LSTM_NODES=256
  14. NUM_SENTENCES=20000
  15. MAX_SENTENCE_LENGTH=50
  16. MAX_NUM_WORDS=20000
  17. EMBEDDING_SIZE=200

数据集

我们需要一个包含英语句子及其法语译文的数据集,下载fra-eng.zip文件并将其解压。每一行的文本文件都包含一个英语句子及其法语译文,通过制表符分隔。继续将每一行分为输入文本和目标文本。

  1. input_sentences = []
  2. output_sentences = []                output_sentences_inputs = []             count =0
  3. for line inopen('./drive/MyDrive/fra.txt', encoding="utf-8"):
  4. count +=1
  5. if count >NUM_SENTENCES:
  6. break
  7. if'\t'notin line:
  8. continue
  9. input_sentence = line.rstrip().split('\t')[0]
  10. output = line.rstrip().split('\t')[1]
  11. output_sentence = output +' <eos>'
  12. output_sentence_input ='<sos> '+ output
  13. input_sentences.append(input_sentence)
  14. output_sentences.append(output_sentence)
  15. output_sentences_inputs.append(output_sentence_input)
  16. print("Number ofsample input:", len(input_sentences))
  17. print("Number ofsample output:", len(output_sentences))
  18. print("Number ofsample output input:", len(output_sentences_inputs))
  1. Output:
  2. Number of sample input: 20000
  3. Number of sample output: 20000
  4. Number of sample output input: 20000

在上面的脚本中创建input_sentences[]、output_sentences[]和output_sentences_inputs[]这三个列表。接下来,在for循环中,逐个读取每行fra.txt文件。每一行都在制表符出现的位置被分为两个子字符串。左边的子字符串(英语句子)插入到input_sentences[]列表中。制表符右边的子字符串是相应的法语译文。

此处表示句子结束的<eos>标记被添加到已翻译句子的前面。同理,表示“句子开始”的<sos>标记和已翻译句子的开头相连接。还是从列表中随机打印一个句子:

  1. print("English sentence: ",input_sentences[180])
  2. print("French translation: ",output_sentences[180])
  3. Output:English sentence:  Join us.French translation:  Joignez-vous à nous.<eos>

标记和填充

下一步是标记原句和译文,并填充长度大于或小于某一特定长度的句子。对于输入而言,该长度将是输入句子的最大长度。对于输出而言,它也是输出句子的最大长度。在此之前,先设想一下句子的长度。将分别在两个单独的英语和法语列表中获取所有句子的长度。

  1. eng_len = []
  2. fren_len = []             # populate thelists with sentence lengths       for i ininput_sentences:
  3. eng_len.append(len(i.split()))
  4. for i inoutput_sentences:
  5. fren_len.append(len(i.split()))
  6. length_df = pd.DataFrame({'english':eng_len, 'french':fren_len})
  7. length_df.hist(bins =20)
  8. plt.show()

上面的直方图显示,法语句子的最大长度为12,英语句子的最大长度为6。

接下来,用Keras的Tokenizer()类矢量化文本数据。句子将因此变为整数序列。然后,用零填充这些序列,使它们长度相等。

标记器类的word_index属性返回一个单词索引词典,其中键表示单词,值表示对应的整数。最后,上述脚本打印出词典中唯一单词的数量和输入的最长英文句子的长度。

  1. #tokenize the input sentences(inputlanguage)
  2. input_tokenizer =Tokenizer(num_words=MAX_NUM_WORDS)                input_tokenizer.fit_on_texts(input_sentences)                input_integer_seq = input_tokenizer.texts_to_sequences(input_sentences)                print(input_integer_seq)
  3. word2idx_inputs =input_tokenizer.word_index                print('Total uniquewords in the input: %s'%len(word2idx_inputs))
  4. max_input_len =max(len(sen) for sen in input_integer_seq)
  5. print("Length oflongest sentence in input: %g"% max_input_len)
  1. Output:
  2. Total unique words in the input: 3501
  3. Length of longest sentence in input: 6

同样,输出语句也可以用相同的方式标记:

  1. #tokenize theoutput sentences(Output language)
  2. output_tokenizer =Tokenizer(num_words=MAX_NUM_WORDS, filters='')
  3. output_tokenizer.fit_on_texts(output_sentences+output_sentences_inputs)  output_integer_seq =output_tokenizer.texts_to_sequences(output_sentences)  output_input_integer_seq =output_tokenizer.texts_to_sequences(output_sentences_inputs)  print(output_input_integer_seq)
  4. word2idx_outputs=output_tokenizer.word_index  print('Total uniquewords in the output: %s'%len(word2idx_outputs))
  5. num_words_output=len(word2idx_outputs)+1
  6. max_out_len =max(len(sen) for sen inoutput_integer_seq)
  7. print("Length oflongest sentence in the output: %g"% max_out_len)
  1. Output:
  2. Total unique words in the output: 9511
  3. Length of longest sentence in the output: 12

现在,可以通过上面的直方图来验证两种语言中最长句子的长度。还可以得出这样的结论:英语句子通常较短,平均单词量比法语译文句子的单词量要少。

接下来需要填充输入。填充输入和输出的原因是文本的句子长度不固定,但长短期记忆网络希望输入的例句长度都相等。因此需要将句子转换为长度固定的向量。为此,一种可行的方法就是填充。

  1. #Padding theencoder input
  2. encoder_input_sequences =pad_sequences(input_integer_seq,maxlen=max_input_len)  print("encoder_input_sequences.shape:",encoder_input_sequences.shape)
  3. #Padding thedecoder inputs  decoder_input_sequences =pad_sequences(output_input_integer_seq,maxlen=max_out_len, padding='post')
  4. print("decoder_input_sequences.shape:",decoder_input_sequences.shape)
  5. #Padding thedecoder outputs  decoder_output_sequences =pad_sequences(output_integer_seq,maxlen=max_out_len, padding='post')
  6. print("decoder_output_sequences.shape:",decoder_output_sequences.shape)
  1. encoder_input_sequences.shape: (20000, 6)
  2. decoder_input_sequences.shape: (20000, 12)
  3. decoder_output_sequences.shape: (20000, 12)

输入中有20000个句子(英语),每个输入句子的长度都为6,所以现在输入的形式为(20000,6)。同理,输出中有20000个句子(法语),每个输出句子的长度都为12,所以现在输出的形式为(20000,12),被翻译的语言也是如此。

大家可能还记得,索引180处的原句为join us。标记生成器将该句拆分为join和us两个单词,将它们转换为整数,然后通过对输入列表中索引180处的句子所对应的整数序列的开头添加四个零来实现前填充(pre-padding)。

  1. print("encoder_input_sequences[180]:",encoder_input_sequences[180])Output:
  2. encoder_input_sequences[180]: [  0   0  0   0 464  59]

要验证join和us的整数值是否分别为464和59,可将单词传递给word2index_inputs词典,如下图所示:

  1. prnt(word2idx_inputs["join"])
  2. print(word2idx_inputs["us"])Output:
  3. 464
  4. 59

更值得一提的是,解码器则会采取后填充(post-padding)的方法,即在句子末尾添加零。而在编码器中,零被填充在开头位置。该方法背后的原因是编码器输出基于出现在句末的单词,因此原始单词被保留在句末,零则被填充在开头位置。而解码器是从开头处理句子,因此对解码器的输入和输出执行后填充。

词嵌入向量(Word Embeddings)

图源:unsplash

我们要先将单词转换为对应的数字向量表示,再将向量输入给深度学习模型。我们也已经将单词转化成了数字。那么整数/数字表示和词嵌入向量之间有什么区别呢?

单个整数表示和词嵌入向量之间有两个主要区别。在整数表示中,一个单词仅用单个整数表示。而在向量表示中,一个单词可以用50、100、200或任何你喜欢的维数表示。因此词嵌入向量可以获取更多与单词有关的信息。其次,单个整数表示无法获取不同单词之间的关系。而词嵌入向量却能做到这一点。

对于英语句子(即输入),我们将使用GloVe词嵌入模型。对于输出的法语译文,我们将使用自定义词嵌入模型。点击此处可下载GloVe词嵌入模型。

首先,为输入内容创建词嵌入向量。在此之前需要将GloVe词向量加载到内存中。然后创建一个词典,其中单词为键,其对应的向量为值:

  1. from numpy import array
  2. from numpy import asarray
  3. from numpy import zeros
  4. embeddings_dictionary=dict()             glove_file =open(r'./drive/My Drive/glove.twitter.27B.200d.txt', encoding="utf8")
  5. for line in glove_file:
  6. rec = line.split()      word= rec[0]
  7. vector_dimensions =asarray(rec[1:], dtype='float32')
  8. embeddings_dictionary[word] = vector_dimensions  glove_file.close()

回想一下,输入中包含3501个唯一单词。我们将创建一个矩阵,其中行数代表单词的整数值,而列数将对应单词的维数。该矩阵将包含输入句子中单词的词嵌入向量。

  1. num_words =min(MAX_NUM_WORDS, len(word2idx_inputs)+1)
  2. embedding_matrix =zeros((num_words, EMBEDDING_SIZE))                     for word, index inword2idx_inputs.items():                         embedding_vector = embeddings_dictionary.get(word)                         if embedding_vector isnotNone:                             embedding_matrix[index] =embedding_vector

创建模型

第一步,为神经网络创建一个嵌入层。嵌入层被认为是网络的第一隐藏层。它必须指定3个参数:

· input_dim:表示文本数据中词汇表的容量。比如,如果数据被整数编码为0-10之间的值,那么词汇表的容量为11个单词。

· output_dim:表示将嵌入单词的向量空间大小。它决定该层每个单词的输出向量大小。比如,它可以是32或100,甚至还可以更大。如果大家对此有疑问,可以用不同的值测试。

· input_length:表示输入序列的长度,正如大家为Keras模型的输入层所定义的那样。比如,如果所有的输入文档都由1000个单词组成,那么该值也为1000。

  1. embedding_layer = Embedding(num_words, EMBEDDING_SIZE,weights=[embedding_matrix], input_length=max_input_len)

接下来需要做的是定义输出,大家都知道输出将是一个单词序列。回想一下,输出中唯一单词的总数为9511。因此,输出中的每个单词都可以是这9511个单词中的一个。输出句子的长度为12。每个输入句子都需要一个对应的输出句子。因此,输出的最终形式将是:(输入量、输出句子的长度、输出的单词数)

  1. #shape of the output
  2. decoder_targets_one_hot = np.zeros((len(input_sentences), max_out_len,num_words_output),
  3. dtype='float32'
  4. )decoder_targets_one_hot.shapeShape: (20000, 12, 9512)

为了进行预测,该模型的最后一层将是一个稠密层(dense layer),因此需要以独热编码向量的形式输出,因为我们将在稠密层使用softmax激活函数。为创建独热编码输出,下一步是将1分配给与该单词整数表示对应的列数。

  1. for i, d in enumerate(decoder_output_sequences):
  2. for t, word in enumerate(d):
  3. decoder_targets_one_hot[i, t,word] = 1

下一步是定义编码器和解码器网络。编码器将输入英语句子,并输出长短期记忆网络的隐藏状态和单元状态。

  1. encoder_inputs =Input(shape=(max_input_len,))
  2. x =embedding_layer(encoder_inputs)                              encoder =LSTM(LSTM_NODES, return_state=True)
  3. encoder_outputs,h, c =encoder(x)                              encoder_states = [h, c]

下一步是定义解码器。解码器将有两个输入:编码器的隐藏状态和单元状态,它们实际上是开头添加了令牌后的输出语句。

  1. decoder_inputs =Input(shape=(max_out_len,))
  2. decoder_embedding =Embedding(num_words_output,LSTM_NODES)  decoder_inputs_x =decoder_embedding(decoder_inputs)             decoder_lstm =LSTM(LSTM_NODES,return_sequences=True, return_state=True)
  3. decoder_outputs, _, _ =decoder_lstm(decoder_inputs_x,initial_state=encoder_states)             #Finally, theoutput from the decoder LSTM is passed through a dense layer to predict decoderoutputs.
  4. decoder_dense =Dense(num_words_output,activation='softmax')
  5. decoder_outputs =decoder_dense(decoder_outputs)

训练模型

编译定义了优化器和交叉熵损失的模型。

  1. #Compile
  2. model =Model([encoder_inputs,decoder_inputs],decoder_outputs)
  3. model.compile(
  4. optimizer='rmsprop',
  5. loss='categorical_crossentropy',
  6. metrics=['accuracy']
  7. )
  8. model.summary()

结果在意料之中。编码器lstm_2接受来自嵌入层的输入,而解码器lstm_3使用编码器的内部状态及嵌入层。该模型总共有大约650万个参数!训练模型时,笔者建议指定EarlyStopping()的参数,以避免出现计算资源的浪费和过拟合。

  1. es =EarlyStopping(monitor='val_loss', mode='min', verbose=1)
  2. history = model.fit([encoder_input_sequences,decoder_input_sequences], decoder_targets_one_hot,                                      batch_size=BATCH_SIZE,                                      epochs=20,
  3. callbacks=[es],                                      validation_split=0.1,
  4. )

保存模型权重。

  1. model.save('seq2seq_eng-fra.h5')

绘制训练和测试数据的精度曲线。

  1. #Accuracy
  2. plt.title('model accuracy')
  3. plt.plot(history.history['accuracy'])
  4. plt.plot(history.history['val_accuracy'])
  5. plt.ylabel('accuracy')
  6. plt.xlabel('epoch')
  7. plt.legend(['train', 'test'], loc='upper left')
  8. plt.show()

如大家所见,该模型达到了约87%的训练精度和约77%的测试精度,这表示该模型出现了过拟合。我们只用20000条记录进行了训练,所以大家可以添加更多记录,还可以添加一个dropout层来减少过拟合。

测试机器翻译模型

加载模型权重并测试模型。

  1. encoder_model = Model(encoder_inputs, encoder_states)
  2. model.compile(optimizer='rmsprop', loss='categorical_crossentropy')
  3. model.load_weights('seq2seq_eng-fra.h5')

设置好权重之后,是时候通过翻译几个句子来测试机器翻译模型了。推理模式的工作原理与训练过程略有不同,其过程可分为以下4步:

· 编码输入序列,返回其内部状态。

· 仅使用start-of-sequence字符作为输入,并使用编码器内部状态作为解码器的初始状态来运行解码器。

· 将解码器预测的字符(在查找令牌之后)添加到解码序列中。

· 将先前预测的字符令牌作为输入,重复该过程,更新内部状态。

由于只需要编码器来编码输入序列,因此我们将编码器和解码器分成两个独立的模型。

  1. decoder_state_input_h =Input(shape=(LSTM_NODES,))
  2. decoder_state_input_c=Input(shape=(LSTM_NODES,))                           decoder_states_inputs=[decoder_state_input_h, decoder_state_input_c]             decoder_inputs_single=Input(shape=(1,))
  3. decoder_inputs_single_x=decoder_embedding(decoder_inputs_single)             decoder_outputs,h, c =decoder_lstm(decoder_inputs_single_x, initial_state=decoder_states_inputs)             decoder_states = [h, c]                           decoder_outputs =decoder_dense(decoder_outputs)             decoder_model =Model(                               [decoder_inputs_single] +decoder_states_inputs,                               [decoder_outputs] + decoder_states

我们想让输出内容为法语的单词序列。因此需要将整数转换回单词。我们将为输入和输出创建新词典,其中键为整数,对应的值为单词。

  1. idx2word_input = {v:k for k, v inword2idx_inputs.items()}
  2. idx2word_target = {v:k for k, v inword2idx_outputs.items()}

该方法将接受带有输入填充序列的英语句子(整数形式),并返回法语译文。

  1. deftranslate_sentence(input_seq):
  2. states_value = encoder_model.predict(input_seq)                                   target_seq = np.zeros((1, 1))
  3. target_seq[0, 0] =word2idx_outputs['<sos>']
  4. eos = word2idx_outputs['<eos>']
  5. output_sentence = []                 for _ inrange(max_out_len):
  6. output_tokens, h, c = decoder_model.predict([target_seq] + states_value)                                       idx = np.argmax(output_tokens[0, 0, :])
  7. if eos == idx:
  8. break
  9. word =''
  10. if idx >0:
  11. word =idx2word_target[idx]                                           output_sentence.append(word)                     target_seq[0, 0] = idx
  12. states_value = [h, c]                 return' '.join(output_sentence)

预测

为测试该模型性能,从input_sentences列表中随机选取一个句子,检索该句子的对应填充序列,并将其传递给translate_sentence()方法。该方法将返回翻译后的句子。

  1. i = np.random.choice(len(input_sentences))
  2. input_seq=encoder_input_sequences[i:i+1]
  3. translation=translate_sentence(input_seq)                                       print('Input Language: ', input_sentences[i])
  4. print('Actualtranslation : ', output_sentences[i])
  5. print('Frenchtranslation : ', translation)

结果:

很成功!该神经网络翻译模型成功地将这么多句子译为了法语。大家也可以通过谷歌翻译进行验证。当然,并非所有句子都能被正确翻译。为进一步提高准确率,大家可以搜索“注意力”机制(Attention mechanism),将其嵌入编码器-解码器结构。

图源:unsplash

大家可以从manythings.org上面下载德语、印地语、西班牙语、俄语、意大利语等多种语言的数据集,并构建用于语言翻译的神经网络翻译模型。

神经机器翻译(NMT)是自然语言处理领域中的一个相当高级的应用,涉及非常复杂的架构。本文阐释了结合长短期记忆层进行Seq2Seq学习的编码器-解码器模型的功能。编码器是一种长短期记忆,用于编码输入语句,而解码器则用于解码输入内容并生成对应的输出内容。

【编辑推荐】

  1. 投资管理与AI:提升客户关系和投资回报
  2. 新的保健解决方案 医疗保健中的AI和IoT如何帮助痴呆症患者
  3. 开发好物推荐7之对象存储服务Minio
  4. 重磅!剑桥年度 AI 全景报告出炉:美顶尖 AI 人才中 27% 具备中国教育背景
  5. 麻省理工选出的全球十大突破性技术

机器翻译:谷歌翻译是如何对几乎所有语言进行翻译的?相关推荐

  1. 解密谷歌机器学习工程最佳实践——机器学习43条军规 翻译 2017年09月19日 10:54:58 98310 本文是对Rules of Machine Learning: Best Practice

    解密谷歌机器学习工程最佳实践--机器学习43条军规 翻译 2017年09月19日 10:54:58 983 1 0 本文是对Rules of Machine Learning: Best Practi ...

  2. python语言无需翻译成_python实现谷歌翻译

    背景 这个功能是在工作时,上级有个需求是让我将json文件中指定字段的英文翻译成中文,并且指定要使用谷歌翻译,理由是翻译的结果可能会比较准确. 过程 因为之前写过用python实现有道翻译,是在aja ...

  3. Python实现谷歌翻译爬虫,翻译PDF,翻译Excel,支持excel文档打开翻译,支持xlsx,xlsm等格式。

    前言: 这两个Python脚本是我在实习期间完成的,具体来自于小组主管的两个小需求.做完之后感觉还是挺有收获的. 实现谷歌翻译,首先需要将我们写的Python脚本还有需要翻译的文件放到谷歌浏览器的安装 ...

  4. 讯飞翻译战略强势发布 助力人类语言大互通

    博鳌亚洲论坛上讯飞翻译机2.0首次亮相便引起大众热议,新品尚未揭开"庐山真面目",却已红遍全论坛.4月20日,迎来了"科大讯飞翻译战略暨新品上市发布会",惊艳亮 ...

  5. 浏览器翻译插件 沙拉查词;图片翻译;pdf 阅读器软件、pdf翻译工具

    1.浏览器翻译插件 沙拉查词 google翻译也可以,这里推荐沙拉查词,直接在浏览器应用商店可以搜索 2.图片翻译 下面是微信自带的图片翻译 下面是谷歌图片翻译 3.pdf 阅读器软件.pdf翻译工具 ...

  6. 知云文献翻译打不开_知云文献翻译 for mac v1.0.1

    知云文献翻译Mac版是一款十分专业且功能实用的文献翻译工具.知云最新版专为研究生服务的学术文献翻译神器,翻译精准高效完全免费,从此再无看不懂的文献.知云文献翻译官方版专注文献翻译,确保文献原文排版,全 ...

  7. 浏览器翻译功能在哪里,如何使用浏览器翻译网页

    对于英文不是很好的用户来说,使用浏览器浏览网页真的太头疼了,不过还好很多浏览器都有翻译功能网页的功能,那么这个翻译功能在哪里,我们如何使用浏览器翻译页面呢?本文将针对不同的浏览器,介绍如何使用浏览器翻 ...

  8. 【愚公系列】2022年12月 .NET CORE工具案例-多语言离线翻译系统

    文章目录 前言 1.在线翻译 2.离线翻译 一.多语言离线翻译系统 1.开发环境 2.准备离线翻译包 3.准备python代码 4.调试翻译结果 5.Python翻译服务对接到.NET Core 前言 ...

  9. 翻译英语的软件-免费翻译软件-各种语言互相翻译

    翻译英语的软件,免费的翻译英语的软件哪个好?什么样的翻译英语的软件称为好呢,首先第一点翻译质量高,第二点可以批量翻译,第三点保留翻译前的格式.第四点支持采集翻译.今天我给大家分享一款免费的翻译英语的软 ...

最新文章

  1. 怎么用python做表格-怎么用python画表格?
  2. 18计算机二级考试用word吗,计算机二级Word篇-实操真题详解18
  3. java 二维数组对角线_二维数组(矩阵)对角线输出
  4. 饿了么超时20分钟_饿了么:5分钟;美团:8分钟......消费者:???
  5. 这是一条“神奇”的评论
  6. 有关SQLite数据库的一些实证数据,有一定历史比较和参考意义
  7. 记录下docker命令
  8. 六大基酒——朗姆酒的喝法
  9. react native实现兼容Android与ios的视频播放器
  10. moviepy音视频开发:音频合成类AudioArrayClip介绍
  11. 《数据结构与算法基础 严蔚敏版》第三章 堆栈与队列
  12. 嵌入式linux下控制电机运动
  13. Arm指令模拟器开发参考指南【翻译自 armDeveloper】
  14. 自己制作Chrome便携版实现多版本共存
  15. JavaEE体系架构
  16. 01_搭建百度apollo环境实操可用
  17. 如何将ES6转换成ES5?
  18. 离婚时夫妻共同债务和个人债务如何区分
  19. 工具篇:Git与Github+GitLib常用操作(不定期持续更新)
  20. 复活谷歌翻译流程(亲测好用)

热门文章

  1. pythonassertbug_还在 Bug 不断?不妨试试这 2 个装X技巧
  2. java输出回文数原代码_JAVA怎么用循环语句编写一个判别是否为回文数的代码?...
  3. 树状笔记软件for linux,Ubuntu 14.04安装开源树状笔记管理软件 WikidPad 2.2
  4. 排序算法三:插入排序
  5. JTABLE加滚动条
  6. 好书 《古代的中医》 《麦肯锡卓越工作方法》
  7. linux ps(process status) 命令详解
  8. 刘铁岩:如何四两拨千斤,高效地预训练NLP模型?
  9. 聊一聊多源最短路径问题(只有5行代码哦)
  10. VS2010 + Qt5.3.2配置教程