文章目录
- 介绍
- 机器翻译之数据处理
- 数据收集
- 数据清洗
- 数据分词
- 数据标注
- 数据划分
- 代码实现
- 导包
- 数据查看
- 处理函数
- 数据预处理
- 词元化
- 统计每句话的长度的分布情况
- 截断或者填充文本序列
- 将机器翻译的文本序列转换成小批量tensor
- 加载数据
- 试用一下
个人主页:道友老李
欢迎加入社区:道友老李的学习社区
介绍
**自然语言处理(Natural Language Processing,NLP)**是计算机科学领域与人工智能领域中的一个重要方向。它研究的是人类(自然)语言与计算机之间的交互。NLP的目标是让计算机能够理解、解析、生成人类语言,并且能够以有意义的方式回应和操作这些信息。
NLP的任务可以分为多个层次,包括但不限于:
- 词法分析:将文本分解成单词或标记(token),并识别它们的词性(如名词、动词等)。
- 句法分析:分析句子结构,理解句子中词语的关系,比如主语、谓语、宾语等。
- 语义分析:试图理解句子的实际含义,超越字面意义,捕捉隐含的信息。
- 语用分析:考虑上下文和对话背景,理解话语在特定情境下的使用目的。
- 情感分析:检测文本中表达的情感倾向,例如正面、负面或中立。
- 机器翻译:将一种自然语言转换为另一种自然语言。
- 问答系统:构建可以回答用户问题的系统。
- 文本摘要:从大量文本中提取关键信息,生成简短的摘要。
- 命名实体识别(NER):识别文本中提到的特定实体,如人名、地名、组织名等。
- 语音识别:将人类的语音转换为计算机可读的文字格式。
NLP技术的发展依赖于算法的进步、计算能力的提升以及大规模标注数据集的可用性。近年来,深度学习方法,特别是基于神经网络的语言模型,如BERT、GPT系列等,在许多NLP任务上取得了显著的成功。随着技术的进步,NLP正在被应用到越来越多的领域,包括客户服务、智能搜索、内容推荐、医疗健康等。
机器翻译之数据处理
在机器翻译中,数据处理是关键环节,对模型训练和翻译质量影响重大。
数据收集
- 多源获取:从学术文献库、新闻网站、社交媒体、政府文件等多渠道收集平行语料(两种或多种语言对照的文本)。例如,联合国文件有多语言版本,是优质平行语料来源;许多新闻机构会发布多语言报道,也可用于采集数据。
- 领域针对性:依据应用场景,收集特定领域语料,像医学、法律、科技等领域。医学机器翻译需收集医学论文、病历、医学书籍等专业语料,以提升特定领域翻译准确性。
数据清洗
- 去除噪声:清除文本中的乱码、特殊符号、HTML标签等噪声信息。比如网页采集的文本可能含大量HTML标签,需通过正则表达式等方式去除。
- 重复数据处理:识别并删除重复的平行句对,降低数据冗余,提升训练效率。可通过计算文本哈希值等方法判断重复。
- 异常值处理:剔除长度异常(过长或过短)、质量差(如翻译错误、语义不通顺)的句对。例如,设置句长阈值,过滤掉过短(如少于3个词)或过长(超过100个词)的句子。
数据分词
- 源语言与目标语言分词:对源语言和目标语言文本分别进行分词处理。在英语等语言中,可按空格简单分词;对于中文等语言,需借助专业分词工具(如jieba)。如“我爱自然语言处理”,jieba分词可能得到“我 爱 自然语言 处理”。
- 子词单元处理:对于稀有词或未登录词,采用字节对编码(BPE)等方法切分。如单词“unhappiness”,经BPE可能切分为“un - happy - ness”,增加词表覆盖度,减少稀有词问题。
数据标注
- 添加元信息:为语料添加如语言对、领域、文本来源等元信息,方便后续管理和筛选。比如标注“中文 - 英文”语言对、“医学”领域等。
- 对齐标注:对平行句对中的词或短语进行对齐标注,可手动或用工具自动标注。如“我喜欢苹果” - “I like apples”,可标注“我” - “I”,“喜欢” - “like” ,“苹果” - “apples”,帮助模型学习词对齐关系。
数据划分
- 训练集、验证集和测试集:按一定比例(如80% - 10% - 10%)将数据划分为训练集、验证集和测试集。训练集用于模型训练,验证集用于调整超参数、监控模型性能,防止过拟合,测试集用于评估最终模型泛化能力。
- 分层抽样:为保证各子集数据分布相似,采用分层抽样。比如按领域分层,确保训练集、验证集和测试集在各领域的比例相近,使模型在不同领域都能良好学习和泛化。
代码实现
数据文件内容:
导包
import os
import torch
import dltools
数据查看
with open('../data/fra-eng/fra.txt', 'r', encoding='utf-8') as f:raw_text = f.read()print(raw_text[:75])
Go. Va !
Hi. Salut !
Run! Cours !
Run! Courez !
Who? Qui ?
Wow! Ça alors !
处理函数
数据预处理
def preprocess_nmt(text):# 判断标点符号前面是否有空格def no_space(char, prev_char):return char in set(',.!?') and prev_char != ' '# 替换识别不了的字符, 替换不正常的空格, 变小写.text = text.replace('\u202f', ' ').replace('\xa0', ' ').lower()# 在单词和标点之间插入空格. out = [' ' + char if i > 0 and no_space(char, text[i - 1]) else char for i, char in enumerate(text)]return ''.join(out)text = preprocess_nmt(raw_text)
print(text[:80])
go . va !
hi . salut !
run ! cours !
run ! courez !
who ? qui ?
wow ! ça alors !
词元化
def tokenize_nmt(text, num_examples=None):source, target = [], []for i, line in enumerate(text.split('\n')):if num_examples and i > num_examples:breakparts = line.split('\t')if len(parts) == 2:source.append(parts[0].split(' '))target.append(parts[1].split(' '))return source, targetsource, target = tokenize_nmt(text)
source[:6], target[:6]
([['go', '.'],['hi', '.'],['run', '!'],['run', '!'],['who', '?'],['wow', '!']],[['va', '!'],['salut', '!'],['cours', '!'],['courez', '!'],['qui', '?'],['ça', 'alors', '!']])
统计每句话的长度的分布情况
def show_list_len_pair_hist(legend, xlabel, ylabel, xlist, ylist):dltools.set_figsize()# plt.hist()_, _, patches = dltools.plt.hist([[len(l) for l in xlist], [len(l) for l in ylist]])dltools.plt.xlabel(xlabel)dltools.plt.ylabel(ylabel)for patch in patches[1].patches:patch.set_hatch('/')dltools.plt.legend(legend)show_list_len_pair_hist(['source', 'target'], '# tokens per sequence', 'count', source, target)
截断或者填充文本序列
def truncate_pad(line, num_steps, padding_token):if len(line) > num_steps:return line[:num_steps] # 太长, 截断. return line + [padding_token] * (num_steps - len(line)) # 填充truncate_pad(src_vocab[source[0]], 10, src_vocab['<pad>'])
将机器翻译的文本序列转换成小批量tensor
def build_array_nmt(lines, vocab, num_steps):# 通过vocab拿到line的索引lines = [vocab[l] for l in lines]lines = [l + [vocab['eos']] for l in lines]array = torch.tensor([truncate_pad(l, num_steps, vocab['<pad>']) for l in lines])valid_len = (array != vocab['<pad>']).type(torch.int32).sum(1)return array, valid_len
加载数据
def load_data_nmt(batch_size, num_steps, num_examples=600):# 需要返回数据集的迭代器和词表text = preprocess_nmt(raw_text)source, target = tokenize_nmt(text, num_examples)src_vocab = dltools.Vocab(source, min_freq=2, reserved_tokens=['<pad>', '<bos>', '<eos>'])tgt_vocab = dltools.Vocab(target, min_freq=2, reserved_tokens=['<pad>', '<bos>', '<eos>'])src_array, src_valid_len = build_array_nmt(source, src_vocab, num_steps)tgt_array, tgt_valid_len = build_array_nmt(target, tgt_vocab, num_steps)data_arrays = (src_array, src_valid_len, tgt_array, tgt_valid_len)data_iter = dltools.load_array(data_arrays, batch_size)return data_iter, src_vocab, tgt_vocab
试用一下
train_iter, src_vocab, tgt_vocab = load_data_nmt(batch_size=2, num_steps=8)for X, X_valid_len, Y, Y_valid_len in train_iter:print('X:', X.type(torch.int32))print('X的有效长度:', X_valid_len)print('Y:', Y.type(torch.int32))print('Y的有效长度:', Y_valid_len)break