当前位置: 首页 > news >正文

深圳签网站口碑营销话题

深圳签网站,口碑营销话题,wordpress标题修改,网站接入商排名有时候我也想听听#xff0c;我在你心里#xff0c;是什么样子 —— 25.1.12 一、什么是语言模型 语言是灵活的#xff0c;也是有规律的 了解一门语言的人可以判断一句话是否“合理” 通俗来讲#xff0c;语言模型用来评价一句话(句子可以看作是字的组合)是否“合理”或… 有时候我也想听听我在你心里是什么样子                                                                 —— 25.1.12 一、什么是语言模型 语言是灵活的也是有规律的 了解一门语言的人可以判断一句话是否“合理” 通俗来讲语言模型用来评价一句话(句子可以看作是字的组合)是否“合理”或“是人话” 数学上讲P(今天天气不错) P(今错不天天气) 、P(I have a dream) P(I is are boy) 语言模型用于计算文本的成句概率模型需要做到对合理的句子给出高分对不合理的句子给出低分 二、语言模型的主要用途 1.语言模型 —— 语音识别ASR 语音识别声音 —— 文本 声音本质是一种波将波按时间段切分很多帧如25ms一段 之后进行声学特征提取将每一帧转化成一个向量 以声学特征提取后的向量为输入经过声学模型预测得到音素 音素与拼音类似但要考虑声调 音素序列对应多条文本序列由语言模型挑选出成句概率最高的序列 使用 beam search 或 维特比 的方式解码 例 语音识别的大致流程 2.语言模型 —— 手写识别OCR 识别模型将图片中文字转化为候选汉字一般分为定位和识别两步再由语言模型挑选出成句概率最高的序列判断候选汉字是否是常见词语的组合并给定一个分数根据分数高低对手写文字进行判断 例 3.语言模型 —— 输入法 输入即为拼音序列每个拼音自然的有多个候选汉字根据语言模型挑选高概率序列 输入法是一个细节繁多的任务在语言模型这一基础算法上需要考虑常见的打字手误常见误读拼音缩略中英混杂输出符号用户习惯等能力 手写输入法语音输入法同理 三、语言模型的分类 1.统计语言模型 (SLM)         S Statistics ngram语言模型等 2.神经语言模型 (NLM)        N Neural rnn语言模型等 3.预训练语言模型 (PLM)        P Pre-train Bert、GPT等  4.大语言模型(LLM)         L Large ChatGPT等 注从上到下由简单到复杂 四、语言模型训练方式的分类 1.自回归auto regressive语言模型 在训练时由上文预测下文或反过来 单向模型仅使用单侧序列信息   代表N-gramELMO,  GPT 2.自编码auto encoding语言模型 在训练时预测序列中任意位置的字符     双向模型吸收上下文信息     代表BERT 五、N-gram 统计语言模型 N-gram 语言模型是一种基于统计的语言模型它基于这样一个假设一个词的出现概率仅与它前面的N-1个词有关 例如在一个句子中对于一个 3-gram(也称为 trigram)模型第 n 个词的出现概率可以表示为P(w„ | w„-2, w„-1)即第 n 个词在已知其前两个词的条件下的出现概率。 1.如何计算成句概率 计算成句概率 等价于 计算字/词按特定顺序出现的概率条件概率 例 ① 以字为单位 P(今天天气不错) P(今) * P(天|今) * P(天|今天) * P(气|今天天) * P(不|今天天气) * P(错|今天天气不) ② 以词为单位 P(今天  天气  不错) P(今天)*P(天气 | 今天) *P(不错 | 今天  天气) ③ 如何计算P(今天) P(今天)   Count(今天) / Count_total        Count_total语料总词数  P(天气 | 今天) Count(今天  天气) / Count(今天) P(不错 | 今天 天气) Count(今天 天气 不错) / Count(今天 天气) 二元组今天 天气              2 gram(多元组出现的次数) 三元组今天 天气 不错      3 gram(多元组出现的次数) 困难 句子太多了对任意一门语言N-gram数量都非常庞大无法穷举需要简化 2.N-gram简化 —— 马尔可夫假设 P(wn|w1,…,wn-1) ≈ P(wn|wn-3,wn-2,wn-1) 假设第n个词出现的概率仅受其前面有限个词影响 例P(今天天气不错) P(今) * P(天|今) * P(天|今天) * P(气|天天) * P(不|天气) * P(错|气不) Ⅰ 马尔可夫假设的缺陷 1.影响第n个词的因素可能出现在前面很远的地方long distance dependency 例         我读过关于马尔科夫的生平的书         我看过关于马尔科夫的生平的电影         我听过关于马尔科夫的生平的故事 2.影响第n个词的因素可能出现在其后面 3.影响第n个词的因素可能并不在文中 但是马尔科夫假设下依然可以得到非常有效的模型 N-gram中的N越大统计前几个词越多需要的语料越大预测的越准确 例  3.如何给出语料中没出现过的词或N-gram概率 Ⅰ 平滑问题smoothing 理论上说任意的词组合成的句子概率都不应当为零 如何给没见过的词或ngram分配概率即为平滑问题也称折扣问题discounting Ⅱ 平滑方法 1.回退backoff 当多元组在词表中不存在如何处理 当三元组a b c不存在时退而寻找b c二元组的概率 P(c | a b) P(c | b) * Bow(ab)【回退概率一般设置为一个小于一的常数0.4谷歌开源方案中给出】 Bow(ab)称为二元组a b的回退概率 如果ab出现的次数多 而abc却没有出现过则我们应该对ab大力惩罚Bow(ab)的值应该很小 回退概率有很多计算方式甚至可以设定为常数 回退可以迭代进行 如序列 a b c d P(d | a b c)  P(d | b c) * Bow(abc)         P(d | b c) P(d | c) * Bow(bc) P(d | c ) P(d) * Bow(c) 2.加1平滑add-one smooth 最终单独的词不存在如何处理 对于单独的词 1gram 的概率 Count(total word)是语料的大小语料中的词数 V是词表大小词表中的词数词表大小不受语料大小的影响 对于高阶概率同样可以运用加1平滑 3.UNK 出现词表外的词如何处理 将低频词转化为UNK 预测中遇到的未见过的词也用UNK代替 例一语成谶 —— 一语成UNK P(UNK | 一 语 成) 这是一种 nlp处理未登录词(OOV) 的常见方法 4.插值 受到回退平滑的启发在计算高阶ngram概率的同时考虑低阶的ngram概率值以插值给出最终结果 实践证明这种方式效果有提升 λ 可以在验证集上调参确定 4.语言模型的评价指标 困惑度 perplexityPPL 一种PPL成句概率的倒数开n次根号 PPL值与成句概率成反比 另一种PPL用对数求和代替小数乘积 本质是相同的与成句概率成反比 思考PPL越小语言模型效果越好这一结论是否正确         成句概率是个相对值         PPL不是评价语言模型效果的唯一指标         我们一般使用一些一定合理的目标文本来计算PPL若PPL值低则说明成句概率高也就说明由此语言模型来判断该句子的合理性高这样是一个好的语言模型此语言模型效果还可以         通常来讲我们需要用语言模型的下游任务一件具体的事来评价语言模型的效果好坏 5.N-gram语言模型代码实现 Ⅰ 初始化类 ① 初始化参数和属性 n设定n-gram模型的阶数默认为3 sep、sos、eos定义分隔符、句子开始和结束标识符 unk_prob、fix_backoff_prob设置未知词概率和回退概率 ② 创建两个字典 ngram_count_dict用于存储n-gram的频率统计 ngram_count_prob_dict用于存储n-gram的概率 ③ 调用方法 ngram_count(corpus)统计语料库中的n-gram频率 calc_ngram_prob()计算n-gram的概率 dict()Python 内置的字典类型构造函数用于创建键值对集合。 参数形式是否必需默认值描述无参数否空字典创建空字典mapping否-接受另一个字典或映射对象如 collections.ChainMapiterable否-可迭代对象元素为 (key, value) 元组**kwargs否-关键字参数如 dict(a1, b2) defaultdict()collections 模块中的类是 dict 的子类自动为不存在的键生成默认值。 参数是否必需默认值描述default_factory是None工厂函数用于生成缺失键的默认值如 int, list, lambda其他参数否-同 dict() 的初始化参数映射、可迭代对象、关键字参数 range() 生成一个不可变的整数序列常用于循环或列表生成。 参数形式是否必需默认值描述range(stop)stop 必需-生成 0 到 stop-1 的整数序列range(start, stop)start 可选start0生成 start 到 stop-1 的整数序列range(start, stop, step)step 可选step1生成 start 开始步长为 step 的序列 def __init__(self, corpusNone, n3):self.n nself.sep _ # 用来分割两个词没有实际含义只要是字典里不存在的符号都可以self.sos sos #start of sentence句子开始的标识符self.eos eos #end of sentence句子结束的标识符self.unk_prob 1e-5 #给unk分配一个比较小的概率值避免集外词概率为0self.fix_backoff_prob 0.4 #使用固定的回退概率self.ngram_count_dict dict((x 1, defaultdict(int)) for x in range(n))self.ngram_count_prob_dict dict((x 1, defaultdict(int)) for x in range(n))self.ngram_count(corpus)self.calc_ngram_prob() Ⅱ 将文本切分成词或字或token split()Python 字符串对象的内置方法用于将一个字符串按照指定的分隔符分割成多个子字符串并返回一个包含这些子字符串的列表。如果不指定分隔符默认使用空白字符如空格、制表符、换行符等作为分隔符。 参数名参数类型默认值是否必填描述sepstrNone否用于指定分割字符串的分隔符。如果不提供该参数则默认使用空白字符作为分隔符。maxsplitint-1否最大分割次数。如果指定为 -1 或不指定则进行尽可能多的分割若指定为正整数 n则最多分割 n 次。 jieba.lcut() jieba 库中的一个函数jieba 是一个强大的中文分词库lcut() 用于对中文文本进行分词操作将中文句子分割成一个个有意义的词语并返回一个包含这些词语的列表。 参数名参数类型默认值是否必填描述sentencestr无是要进行分词的中文句子。cut_allboolFalse否分词模式选择。False 表示精确模式试图将句子最精确地切开适合文本分析True 表示全模式把句子中所有可以成词的词语都扫描出来速度快但可能存在大量冗余。HMMboolTrue否是否使用隐马尔可夫模型HMM来识别未登录词。 #将文本切分成词或字或tokendef sentence_segment(self, sentence):return sentence.split()#return jieba.lcut(sentence) Ⅲ 统计ngram的数量 ① 遍历语料库 逐句处理语料库中的句子 ② 分词并添加边界符 将句子分词并在前后添加开始符self.sos和结束符self.eos ③ 按不同窗长扫描 使用不同长度的窗口从1到self.n扫描每个句子生成n-gram ④ 过滤不完整的n-gram 跳过末尾不足窗长的部分 ⑤ 存储n-gram 将生成的n-gram用分隔符self.sep连接后存储到字典中并计数 ⑥ 计算总词数 统计所有一阶n-gram的总词数用于后续概率计算 range() Python 的内置函数用于生成一个不可变的整数序列通常用于在 for 循环中控制迭代次数。它可以根据传入的参数生成指定范围的整数序列。 参数名参数类型默认值是否必填描述startint0否序列的起始值包含该值。如果不提供默认从 0 开始。stopint无是序列的结束值不包含该值。stepint1否序列中相邻两个数的差值。如果不提供默认步长为 1。 enumerate()Python 的内置函数用于将一个可迭代对象如列表、元组、字符串等组合为一个索引序列同时列出数据和数据的索引一般用于在 for 循环中同时获取元素和其索引。 参数名参数类型默认值是否必填描述iterable可迭代对象如列表、元组、字符串等无是要进行枚举的可迭代对象。startint0否索引的起始值。如果不提供默认从 0 开始。 join()字符串对象的方法用于将一个可迭代对象中的元素连接成一个字符串连接时使用调用该方法的字符串作为分隔符。可迭代对象中的元素必须是字符串类型。 参数名参数类型默认值是否必填描述iterable可迭代对象如列表、元组、字符串等元素为字符串无是要连接的可迭代对象。 values()字典dict对象的方法用于返回一个视图对象该视图对象包含字典中所有的值。这个视图对象会随着字典的变化而动态更新。 #统计ngram的数量def ngram_count(self, corpus):for sentence in corpus:word_lists self.sentence_segment(sentence)word_lists [self.sos] word_lists [self.eos] #前后补充开始符和结尾符for window_size in range(1, self.n 1): #按不同窗长扫描文本for index, word in enumerate(word_lists):#取到末尾时窗口长度会小于指定的gram跳过那几个if len(word_lists[index:index window_size]) ! window_size:continue#用分隔符连接word形成一个ngram用于存储ngram self.sep.join(word_lists[index:index window_size])self.ngram_count_dict[window_size][ngram] 1#计算总词数后续用于计算一阶ngram概率self.ngram_count_dict[0] sum(self.ngram_count_dict[1].values())return Ⅳ 计算ngram的概率 ① 遍历窗口大小 从1到self.n逐个处理不同长度的N-gram ② 遍历N-gram 对于每个窗口大小遍历对应的N-gram及其出现次数 ③ 处理前缀 如果窗口大小大于1将N-gram拆分为前缀和最后一个词并获取前缀的计数 如果窗口大小为1直接使用总词数作为分母 ④ 计算概率 将当前N-gram的计数除以前缀的计数存储在self.ngram_count_prob_dict中。 split()Python 字符串对象的内置方法用于将一个字符串按照指定的分隔符分割成多个子字符串并返回一个包含这些子字符串的列表。如果不指定分隔符默认使用空白字符如空格、制表符、换行符等作为分隔符。 参数名参数类型默认值是否必填描述sepstrNone否用于指定分割字符串的分隔符。如果不提供该参数则默认使用空白字符作为分隔符。maxsplitint-1否最大分割次数。如果指定为 -1 或不指定则进行尽可能多的分割若指定为正整数 n则最多分割 n 次。 join()字符串对象的方法用于将一个可迭代对象中的元素连接成一个字符串连接时使用调用该方法的字符串作为分隔符。可迭代对象中的元素必须是字符串类型。 参数名参数类型默认值是否必填描述iterable可迭代对象如列表、元组、字符串等元素为字符串无是要连接的可迭代对象。 #计算ngram概率def calc_ngram_prob(self):for window_size in range(1, self.n 1):for ngram, count in self.ngram_count_dict[window_size].items():if window_size 1:ngram_splits ngram.split(self.sep) #Class1_ngram :a b cngram_prefix self.sep.join(ngram_splits[:-1]) #ngram_prefix :a bngram_prefix_count self.ngram_count_dict[window_size - 1][ngram_prefix] #Count(a,b)else:ngram_prefix_count self.ngram_count_dict[0] #count(total word)# word ngram_splits[-1]# self.ngram_count_prob_dict[word | ngram_prefix] count / ngram_prefix_countself.ngram_count_prob_dict[window_size][ngram] count / ngram_prefix_countreturn Ⅴ 获取ngram概率 ① 计算n-gram长度 通过self.sep分隔符将n-gram拆分成单词并计算长度n。 ② 查找概率 如果n-gram存在于self.ngram_count_prob_dict[n]中直接返回其概率。 如果n-gram是一阶即单个词且未找到则返回未知词概率self.unk_prob。 对于高于一阶的n-gram移除第一个词后递归调用get_ngram_prob并乘以回退概率self.fix_backoff_prob。  join()字符串对象的方法用于将一个可迭代对象中的元素连接成一个字符串连接时使用调用该方法的字符串作为分隔符。可迭代对象中的元素必须是字符串类型。 参数名参数类型默认值是否必填描述iterable可迭代对象如列表、元组、字符串等元素为字符串无是要连接的可迭代对象。 # 获取ngram概率其中用到了回退平滑回退概率采取固定值def get_ngram_prob(self, ngram):n len(ngram.split(self.sep))if ngram in self.ngram_count_prob_dict[n]:#尝试直接取出概率return self.ngram_count_prob_dict[n][ngram]elif n 1:#一阶gram查找不到说明是集外词不做回退return self.unk_probelse:#高于一阶的可以回退ngram self.sep.join(ngram.split(self.sep)[1:])return self.fix_backoff_prob * self.get_ngram_prob(ngram) Ⅵ 回退法预测句子概率 ① 分词 将输入句子 sentence 分割成单词列表 word_list。 ② 添加边界标记 在单词列表的开头和结尾分别添加起始标记 self.sos 和结束标记 self.eos。 ③ 初始化概率 初始化 sentence_prob 为 0用于累加每个n-gram的概率对数。 ④ 遍历单词列表 对于每个单词构建对应的n-gram并获取其概率 prob。 ⑤ 累加对数概率 将每个n-gram的概率的对数累加到 sentence_prob 中。 ⑥ 计算困惑度 根据公式 2 ** (sentence_prob * (-1 / len(word_list))) 计算并返回句子的困惑度 enumerate()Python 的内置函数用于将一个可迭代对象如列表、元组、字符串等组合为一个索引序列同时列出数据和数据的索引一般用于在 for 循环中同时获取元素和其索引。 参数名参数类型默认值是否必填描述iterable可迭代对象如列表、元组、字符串等无是要进行枚举的可迭代对象。startint0否索引的起始值。如果不提供默认从 0 开始。 join()字符串对象的方法用于将一个可迭代对象中的元素连接成一个字符串连接时使用调用该方法的字符串作为分隔符。可迭代对象中的元素必须是字符串类型。 参数名参数类型默认值是否必填描述iterable可迭代对象如列表、元组、字符串等元素为字符串无是要连接的可迭代对象。 math.log()Python 标准库 math 模块中的一个函数用于计算一个数的自然对数或者以指定底数的对数。自然对数是以常数 约等于 2.71828为底的对数。在数学和科学计算中对数函数是一种常见的运算math.log() 为我们在 Python 中进行对数计算提供了便利。 参数名参数类型默认值是否必填描述x数值类型如 int、float无是要计算对数的数值必须为正数。如果传入负数或零会抛出 ValueError 异常。base数值类型如 int、float无计算自然对数时否对数的底数。如果不提供该参数默认计算自然对数以  为底。底数必须为正数且不等于 1。 #回退法预测句子概率def calc_sentence_ppl(self, sentence):word_list self.sentence_segment(sentence)word_list [self.sos] word_list [self.eos]sentence_prob 0for index, word in enumerate(word_list):ngram self.sep.join(word_list[max(0, index - self.n 1):index 1])prob self.get_ngram_prob(ngram)# print(Class1_ngram, prob)sentence_prob math.log(prob)return 2 ** (sentence_prob * (-1 / len(word_list)))Ⅶ 实现n-gram语言模型 import math from collections import defaultdictclass NgramLanguageModel:def __init__(self, corpusNone, n3):self.n nself.sep _ # 用来分割两个词没有实际含义只要是字典里不存在的符号都可以self.sos sos #start of sentence句子开始的标识符self.eos eos #end of sentence句子结束的标识符self.unk_prob 1e-5 #给unk分配一个比较小的概率值避免集外词概率为0self.fix_backoff_prob 0.4 #使用固定的回退概率self.ngram_count_dict dict((x 1, defaultdict(int)) for x in range(n))self.ngram_count_prob_dict dict((x 1, defaultdict(int)) for x in range(n))self.ngram_count(corpus)self.calc_ngram_prob()#将文本切分成词或字或tokendef sentence_segment(self, sentence):return sentence.split()#return jieba.lcut(sentence)#统计ngram的数量def ngram_count(self, corpus):for sentence in corpus:word_lists self.sentence_segment(sentence)word_lists [self.sos] word_lists [self.eos] #前后补充开始符和结尾符for window_size in range(1, self.n 1): #按不同窗长扫描文本for index, word in enumerate(word_lists):#取到末尾时窗口长度会小于指定的gram跳过那几个if len(word_lists[index:index window_size]) ! window_size:continue#用分隔符连接word形成一个ngram用于存储ngram self.sep.join(word_lists[index:index window_size])self.ngram_count_dict[window_size][ngram] 1#计算总词数后续用于计算一阶ngram概率self.ngram_count_dict[0] sum(self.ngram_count_dict[1].values())return#计算ngram概率def calc_ngram_prob(self):for window_size in range(1, self.n 1):for ngram, count in self.ngram_count_dict[window_size].items():if window_size 1:ngram_splits ngram.split(self.sep) #Class1_ngram :a b cngram_prefix self.sep.join(ngram_splits[:-1]) #ngram_prefix :a bngram_prefix_count self.ngram_count_dict[window_size - 1][ngram_prefix] #Count(a,b)else:ngram_prefix_count self.ngram_count_dict[0] #count(total word)# word ngram_splits[-1]# self.ngram_count_prob_dict[word | ngram_prefix] count / ngram_prefix_countself.ngram_count_prob_dict[window_size][ngram] count / ngram_prefix_countreturn#获取ngram概率其中用到了回退平滑回退概率采取固定值def get_ngram_prob(self, ngram):n len(ngram.split(self.sep))if ngram in self.ngram_count_prob_dict[n]:#尝试直接取出概率return self.ngram_count_prob_dict[n][ngram]elif n 1:#一阶gram查找不到说明是集外词不做回退return self.unk_probelse:#高于一阶的可以回退ngram self.sep.join(ngram.split(self.sep)[1:])return self.fix_backoff_prob * self.get_ngram_prob(ngram)#回退法预测句子概率def calc_sentence_ppl(self, sentence):word_list self.sentence_segment(sentence)word_list [self.sos] word_list [self.eos]sentence_prob 0for index, word in enumerate(word_list):ngram self.sep.join(word_list[max(0, index - self.n 1):index 1])prob self.get_ngram_prob(ngram)# print(Class1_ngram, prob)sentence_prob math.log(prob)return 2 ** (sentence_prob * (-1 / len(word_list)))if __name__ __main__:corpus open(sample.txt, encodingutf8).readlines()lm NgramLanguageModel(corpus, 3)print(词总数:, lm.ngram_count_dict[0])print(lm.ngram_count_prob_dict)print(lm.calc_sentence_ppl(c d b d b))⭐七、NN语言模型神经网络语言模型 Bengio et al.  2003 与ngram模型相似使用前n个词预测下一个词 输出在字表上的概率分布 语言模型训练得到了词向量这一副产品 随着相关研究的发展隐含层模型结构的复杂度不断提升 DNN  ——  CNN / RNN  ——  LSTM / GRU ——  transformer                                                                 LSTM示意图 1.代码实现RNN语言模型 Ⅰ、模型搭建 nn.Embedding()PyTorch 中用于创建词嵌入层的模块。在自然语言处理任务中我们通常需要将离散的词转换为连续的向量表示这个过程就叫做词嵌入。nn.Embedding() 模块可以学习一个词嵌入矩阵将输入的词索引映射到对应的词向量。 参数名参数类型描述num_embeddingsint词表的大小即不同词的数量。embedding_dimint每个词向量的维度。padding_idxint, 可选用于指定填充的词索引填充位置的向量会被固定为零向量。max_normfloat, 可选词向量的最大范数如果超过该值会进行归一化。norm_typefloat, 可选计算范数时使用的范数类型默认为 2 范数。scale_grad_by_freqbool, 可选是否根据词频缩放梯度。sparsebool, 可选是否使用稀疏梯度更新。 nn.RNN()PyTorch 中用于创建循环神经网络RNN层的模块。RNN 是一种能够处理序列数据的神经网络它可以在不同的时间步之间传递信息从而捕捉序列中的时间依赖关系。 参数名参数类型描述input_sizeint输入序列的特征维度。hidden_sizeint隐藏状态的维度。num_layersint, 可选RNN 层的数量默认为 1。nonlinearitystr, 可选非线性激活函数可选值为 tanh 或 relu默认为 tanh。biasbool, 可选是否使用偏置项默认为 True。batch_firstbool, 可选输入和输出张量的形状是否以批量大小作为第一维默认为 False。dropoutfloat, 可选除最后一层外每层的丢弃率范围在 0 到 1 之间默认为 0。bidirectionalbool, 可选是否使用双向 RNN默认为 False。 nn.Linear()PyTorch 中用于创建全连接层线性层的模块。全连接层将输入的每个神经元与输出的每个神经元都进行连接通过学习一组权重和偏置来实现线性变换。 参数名参数类型描述in_featuresint输入特征的维度。out_featuresint输出特征的维度。biasbool, 可选是否使用偏置项默认为 True。 nn.Dropout()PyTorch 中用于防止过拟合的模块。在训练过程中Dropout 会以一定的概率随机丢弃置为零输入张量中的某些元素这样可以迫使模型学习到更鲁棒的特征减少对某些特定神经元的依赖。 参数名参数类型描述pfloat, 可选丢弃元素的概率范围在 0 到 1 之间默认为 0.5。inplacebool, 可选是否原地操作默认为 False。 nn.functional.cross_entropy()PyTorch 中用于计算交叉熵损失的函数。交叉熵损失常用于分类任务它衡量了模型预测的概率分布与真实标签的概率分布之间的差异。 参数名参数类型描述inputtorch.Tensor模型的预测输出形状为 (批量大小类别数)。targettorch.Tensor真实标签形状为 (批量大小)每个元素是对应的类别索引。weighttorch.Tensor, 可选每个类别的权重用于处理类别不平衡问题。size_averagebool, 可选已弃用使用 reduction 参数代替。ignore_indexint, 可选忽略的标签索引这些标签不会参与损失计算默认为 -100。reducebool, 可选已弃用使用 reduction 参数代替。reductionstr, 可选损失的缩减方式可选值为 none、mean 或 sum默认为 mean。 class LanguageModel(nn.Module):def __init__(self, input_dim, vocab):super(LanguageModel, self).__init__()self.embedding nn.Embedding(len(vocab) 1, input_dim)self.layer nn.RNN(input_dim, input_dim, num_layers2, batch_firstTrue)self.classify nn.Linear(input_dim, len(vocab) 1)self.dropout nn.Dropout(0.1)self.loss nn.functional.cross_entropy Ⅱ、前馈运算  torch.softmax()PyTorch 中的一个函数主要用于将输入张量的元素转换为概率分布。在深度学习的分类任务中模型的输出往往是一组未经归一化的得分logitstorch.softmax() 可以将这些得分转换为概率值使得每个类别的概率值在 0 到 1 之间并且所有类别的概率值之和为 1。这样可以方便地根据概率值确定输入样本属于各个类别的可能性大小。 参数名参数类型描述inputtorch.Tensor输入的张量通常是模型的输出 logits。dimint指定在哪个维度上进行 softmax 操作。该维度上的元素会被转换为概率分布。例如对于二维张量如果 dim 0则按列进行 softmax 操作如果 dim 1则按行进行 softmax 操作。_stacklevelint内部使用的参数一般不需要用户手动指定。dtypetorch.dtype, 可选指定输出张量的数据类型。如果不指定输出的数据类型将与输入保持一致。 x x[:, -1, :] 取最后一个位置字对应的向量 第一个 :表示选择所有的第一维元素。这里的第一维通常对应批量大小在深度学习的批量训练中或者矩阵的行对于二维矩阵。-1表示选择第二维的最后一个元素。在不同的应用场景下第二维可能代表时间步在处理序列数据时、特征维度的某个特定位置等。最后一个 :表示选择所有的第三维元素。第三维可以代表特征的不同分量等。 #当输入真实标签返回loss值无真实标签返回预测值def forward(self, x, yNone):x self.embedding(x) #output shape:(batch_size, sen_len, input_dim)x, _ self.layer(x) #output shape:(batch_size, sen_len, input_dim)x x[:, -1, :] #output shape:(batch_size, input_dim)x self.dropout(x)y_pred self.classify(x) #output shape:(batch_size, vocab_size)if y is not None:return self.loss(y_pred, y) #[1*vocab_size] []else:return torch.softmax(y_pred, dim-1) Ⅲ、获取字符集  set()Python 的内置函数用于创建一个集合对象。集合是一种无序且元素唯一的数据结构它可以用来去除重复元素还能进行集合运算如交集、并集、差集等。 参数参数类型是否必填描述iterable可迭代对象如列表、元组、字符串等否用于初始化集合的可迭代对象若不提供则创建空集合 open()Python 的内置函数用于打开文件并返回一个文件对象。借助这个文件对象我们可以对文件进行读取、写入、追加等操作。 参数参数类型是否必填描述file字符串是要打开的文件的路径可为相对或绝对路径mode字符串否打开文件的模式常见有r只读默认、w写入、a追加、b二进制模式等buffering整数否设置缓冲策略-1 表示使用默认缓冲encoding字符串否文件的编码格式如utf-8、gbk等用于文本文件errors字符串否指定如何处理编码错误newline字符串否控制通用换行模式的行为closefd布尔值否如果为True默认则在文件关闭时关闭文件描述符opener可调用对象否自定义开启文件的方式 enumerate()Python 的内置函数它能将一个可迭代对象组合成一个索引序列在循环中可以同时获取元素及其索引。 参数参数类型是否必填描述iterable可迭代对象如列表、元组、字符串等是要进行枚举的可迭代对象start整数否索引的起始值默认为 0 add()集合set对象的方法用于向集合中添加一个元素。如果该元素已经存在于集合中集合不会发生改变因为集合中的元素具有唯一性。 参数参数类型是否必填描述element可哈希对象如数字、字符串、元组等是要添加到集合中的元素 sorted()Python 的内置函数用于对可迭代对象进行排序并返回一个新的已排序列表原可迭代对象不会被修改。 参数参数类型是否必填描述iterable可迭代对象如列表、元组、字符串等是要进行排序的可迭代对象key函数否指定排序依据的函数该函数接受一个元素作为输入返回用于比较的值reverse布尔值否False 表示升序默认True 表示降序 #读取语料获得字符集 #输出一份 def build_vocab_from_corpus(path):vocab set()with open(path, encodingutf8) as f:for index, char in enumerate(f.read()):vocab.add(char)vocab.add(UNK) #增加一个unk token用来处理未登录词writer open(vocab.txt, w, encodingutf8)for char in sorted(vocab):writer.write(char \n)return vocab Ⅳ、加载字表  #加载字表 def build_vocab(vocab_path):vocab {}with open(vocab_path, encodingutf8) as f:for index, line in enumerate(f):char line[:-1] #去掉结尾换行符vocab[char] index 1 #留出0位给pad tokenvocab[\n] 1return vocab Ⅴ、 加载语料 read()从文件对象中读取指定数量的字符文本模式或字节二进制模式并将其作为字符串文本模式或字节对象二进制模式返回。若不指定读取的数量它会尝试读取文件的全部内容。 参数名参数类型是否必填描述sizeint否可选参数指定要读取的字符文本模式或字节二进制模式的数量。若省略该参数或传入 -1则会读取文件的全部内容。 #加载语料 def load_corpus(path):return open(path, encodingutf8).read() Ⅵ、生成样本 random.randint()Python 标准库 random 模块中的一个函数用于生成指定范围内的随机整数。该函数在需要随机选取整数的场景中非常有用比如随机抽奖、随机生成测试数据等。 参数名参数类型是否必填描述aint是随机整数范围的下限生成的随机整数会大于等于这个值。bint是随机整数范围的上限生成的随机整数会小于等于这个值。且要求 b a。 get()Python 字典dict对象的一个方法用于根据键获取字典中对应的值。与直接使用方括号 [] 访问键值不同的是当键不存在时get() 方法不会抛出 KeyError 异常而是返回一个默认值。 参数名参数类型是否必填描述key任意可哈希类型如 int、str、tuple 等是要查找的键。default任意类型否当键不存在时返回的默认值默认为 None。 #随机生成一个样本 #从文本中截取随机窗口前n个字作为输入最后一个字作为输出 def build_sample(vocab, window_size, corpus):start random.randint(0, len(corpus) - 1 - window_size)end start window_sizewindow corpus[start:end]target corpus[end]# print(window, target)x [vocab.get(word, vocab[UNK]) for word in window] #将字转换成序号y vocab[target]return x, yⅦ、建立数据集和模型 range() Python 的内置函数用于生成一个不可变的整数序列通常用于 for 循环中控制迭代次数也可用于创建列表等可迭代对象。 参数名参数类型是否必填描述startint否形式一可不填序列的起始值包含该值。如果不提供默认从 0 开始。stopint是序列的结束值不包含该值。stepint否形式一、二可不填序列中相邻两个数的差值。如果不提供默认步长为 1。 append()Python 列表list对象的方法用于在列表的末尾添加一个元素从而改变原列表的内容。 参数名参数类型是否必填描述object任意类型是要添加到列表末尾的元素可以是数字、字符串、列表、元组等任意 Python 对象。 LongTensor()PyTorch 库中的一个函数用于创建一个 torch.Tensor 对象其数据类型为 64 位有符号整数torch.long。在深度学习中常用来存储整数类型的数据如索引、标签等。 参数名参数类型是否必填描述dataarray_like如列表、元组、NumPy 数组等否用于初始化张量的数据。如果不提供将创建一个空张量。dtypetorch.dtype否指定张量的数据类型通常不需要手动指定默认会创建 torch.long 类型的张量。devicetorch.device否指定张量存储的设备如 cpu 或 cuda用于 GPU 计算。如果不指定默认存储在 CPU 上。requires_gradbool否指定是否需要对该张量进行梯度计算。如果为 True在后续的计算中会跟踪梯度信息用于反向传播。默认值为 False。 #建立数据集 #sample_length 输入需要的样本数量。需要多少生成多少 #vocab 词表 #window_size 样本长度 #corpus 语料字符串 def build_dataset(sample_length, vocab, window_size, corpus):dataset_x []dataset_y []for i in range(sample_length):x, y build_sample(vocab, window_size, corpus)dataset_x.append(x)dataset_y.append(y)return torch.LongTensor(dataset_x), torch.LongTensor(dataset_y)#建立模型 def build_model(vocab, char_dim):model LanguageModel(char_dim, vocab)return model Ⅷ、计算文本ppl range() Python 的内置函数用于生成一个不可变的整数序列通常用于 for 循环中控制迭代次数也可用于创建列表等可迭代对象。 参数名参数类型是否必填描述startint否形式一可不填序列的起始值包含该值。如果不提供默认从 0 开始。stopint是序列的结束值不包含该值。stepint否形式一、二可不填序列中相邻两个数的差值。如果不提供默认步长为 1。 model.eval()PyTorch 中模型对象的一个方法主要用于将模型设置为评估模式。在深度学习模型的训练和评估过程中有些层如 Dropout、BatchNorm 等在训练和评估时的行为是不同的。调用 model.eval() 可以确保这些层在评估时使用正确的模式避免在评估阶段引入不必要的随机性或统计信息更新。 torch.no_grad()PyTorch 中的一个上下文管理器用于临时禁用梯度计算。在模型评估阶段或者不需要计算梯度的场景如推理过程中禁用梯度计算可以减少内存消耗提高计算速度。 max()返回可迭代对象中的最大值或者返回多个参数中的最大值。 参数名参数类型是否必填描述iterable可迭代对象如列表、元组等是第一种形式要查找最大值的可迭代对象。arg1, arg2, *args任意可比较类型是第二种形式多个要比较的参数。key函数否一个用于自定义比较规则的函数该函数接受一个元素作为输入返回一个用于比较的值。default任意类型否当可迭代对象为空时返回的默认值。 torch.cuda.is_available()PyTorch 中的一个函数用于检查当前环境中是否有可用的 CUDA 设备即 GPU。如果返回 True表示可以使用 GPU 进行计算如果返回 False则只能使用 CPU 进行计算。 #计算文本ppl def calc_perplexity(sentence, model, vocab, window_size):prob 0model.eval()with torch.no_grad():for i in range(1, len(sentence)):start max(0, i - window_size)window sentence[start:i]x [vocab.get(char, vocab[UNK]) for char in window]x torch.LongTensor([x])target sentence[i]target_index vocab.get(target, vocab[UNK])if torch.cuda.is_available():x x.cuda()pred_prob_distribute model(x)[0]target_prob pred_prob_distribute[target_index]prob math.log(target_prob, 10)return 2 ** (prob * ( -1 / len(sentence))) Ⅸ、模型训练 torch.cuda.is_available()PyTorch 中的一个函数用于检查当前环境中是否有可用的 CUDA 设备即 GPU。如果返回 True表示可以使用 GPU 进行计算如果返回 False则只能使用 CPU 进行计算。 model.cuda()PyTorch 中用于将模型参数和缓冲区移动到 CUDA 设备GPU上的方法。在深度学习中使用 GPU 进行计算可以显著加速模型的训练和推理过程因为 GPU 具有强大的并行计算能力。 参数名参数类型是否必填描述devicetorch.device 或 int否指定要将模型移动到的 CUDA 设备。如果不提供该参数默认使用当前的 CUDA 设备。 torch.optim.Adam()PyTorch 中实现 AdamAdaptive Moment Estimation优化算法的类。Adam 是一种常用的优化算法结合了动量法和自适应学习率的思想能够自适应地调整每个参数的学习率具有收敛速度快、稳定性好的优点。 参数名参数类型是否必填描述params可迭代对象是包含模型参数的可迭代对象通常使用 model.parameters() 来获取。lrfloat否学习率控制参数更新的步长默认值为 0.001。betastuple否用于计算梯度一阶矩估计和二阶矩估计的指数衰减率默认值为 (0.9, 0.999)。epsfloat否用于数值稳定性的小常数防止分母为零默认值为 1e-08。weight_decayfloat否权重衰减系数用于正则化防止过拟合默认值为 0。amsgradbool否是否使用 AMSGrad 变种的 Adam 算法默认值为 False。 model.train()PyTorch 中用于将模型设置为训练模式的方法。在训练模式下一些特殊层如 Dropout、BatchNorm 等会按照训练时的规则进行操作例如 Dropout 会随机丢弃一些神经元BatchNorm 会更新统计信息。 参数名参数类型是否必填描述modebool否指定是否将模型设置为训练模式默认值为 True。如果设置为 False则等同于 model.eval()。 optim.zero_grad() PyTorch 中优化器对象的方法用于将模型参数的梯度清零。在每次进行反向传播计算梯度之前需要将之前的梯度清零以避免梯度累积。 参数名参数类型是否必填描述set_to_nonebool否是否将梯度设置为 None 而不是零默认值为 False。将梯度设置为 None 可以减少内存占用。 backward()PyTorch 中张量对象的方法用于进行反向传播计算梯度。在计算图中通过调用 backward() 方法可以根据损失函数的值计算出模型参数的梯度。 参数名参数类型是否必填描述gradienttorch.Tensor否梯度张量用于非标量张量的反向传播。如果 tensor 是标量则不需要提供该参数。retain_graphbool否是否保留计算图默认值为 None。如果需要多次调用 backward()则需要将该参数设置为 True。create_graphbool否是否创建计算图以进行高阶导数计算默认值为 False。inputs可迭代对象否指定要计算梯度的输入张量。 optim.step() PyTorch 中优化器对象的方法用于根据计算得到的梯度更新模型的参数。在调用 backward() 计算梯度后需要调用 optim.step() 来更新参数。 参数名参数类型是否必填描述closure可调用对象否一个闭包函数用于重新评估模型并返回损失通常用于一些需要多次评估的优化算法默认值为 None。 os.listdir() Python 标准库 os 模块中的函数用于返回指定目录下的所有文件和文件夹的名称列表。 参数名参数类型是否必填描述path字符串否指定要列出内容的目录路径默认值为当前工作目录.。 def train(corpus_path, save_weightTrue):epoch_num 10 #训练轮数batch_size 128 #每次训练样本个数train_sample 10000 #每轮训练总共训练的样本总数char_dim 128 #每个字的维度window_size 6 #样本文本长度vocab build_vocab(vocab.txt) #建立字表corpus load_corpus(corpus_path) #加载语料model build_model(vocab, char_dim) #建立模型if torch.cuda.is_available():model model.cuda()optim torch.optim.Adam(model.parameters(), lr0.001) #建立优化器for epoch in range(epoch_num):model.train()watch_loss []for batch in range(int(train_sample / batch_size)):x, y build_dataset(batch_size, vocab, window_size, corpus) #构建一组训练样本if torch.cuda.is_available():x, y x.cuda(), y.cuda()optim.zero_grad() #梯度归零loss model(x, y) #计算losswatch_loss.append(loss.item())loss.backward() #计算梯度optim.step() #更新权重print(\n第%d轮平均loss:%f % (epoch 1, np.mean(watch_loss)))if not save_weight:returnelse:base_name os.path.basename(corpus_path).replace(txt, pth)model_path os.path.join(model, base_name)torch.save(model.state_dict(), model_path)return#训练corpus文件夹下的所有语料根据文件名将训练后的模型放到莫得了文件夹 def train_all():for path in os.listdir(corpus):corpus_path os.path.join(corpus, path)train(corpus_path) Ⅹ、基于pytorch的rnn语言模型 #coding:utf8import torch import torch.nn as nn import numpy as np import math import random import os import re import matplotlib.pyplot as plt 基于pytorch的rnn语言模型 class LanguageModel(nn.Module):def __init__(self, input_dim, vocab):super(LanguageModel, self).__init__()self.embedding nn.Embedding(len(vocab) 1, input_dim)self.layer nn.RNN(input_dim, input_dim, num_layers2, batch_firstTrue)self.classify nn.Linear(input_dim, len(vocab) 1)self.dropout nn.Dropout(0.1)self.loss nn.functional.cross_entropy#当输入真实标签返回loss值无真实标签返回预测值def forward(self, x, yNone):x self.embedding(x) #output shape:(batch_size, sen_len, input_dim)x, _ self.layer(x) #output shape:(batch_size, sen_len, input_dim)x x[:, -1, :] #output shape:(batch_size, input_dim)x self.dropout(x)y_pred self.classify(x) #output shape:(batch_size, vocab_size)if y is not None:return self.loss(y_pred, y) #[1*vocab_size] []else:return torch.softmax(y_pred, dim-1)#读取语料获得字符集 #输出一份 def build_vocab_from_corpus(path):vocab set()with open(path, encodingutf8) as f:for index, char in enumerate(f.read()):vocab.add(char)vocab.add(UNK) #增加一个unk token用来处理未登录词writer open(vocab.txt, w, encodingutf8)for char in sorted(vocab):writer.write(char \n)return vocab#加载字表 def build_vocab(vocab_path):vocab {}with open(vocab_path, encodingutf8) as f:for index, line in enumerate(f):char line[:-1] #去掉结尾换行符vocab[char] index 1 #留出0位给pad tokenvocab[\n] 1return vocab#加载语料 def load_corpus(path):return open(path, encodingutf8).read()#随机生成一个样本 #从文本中截取随机窗口前n个字作为输入最后一个字作为输出 def build_sample(vocab, window_size, corpus):start random.randint(0, len(corpus) - 1 - window_size)end start window_sizewindow corpus[start:end]target corpus[end]# print(window, target)x [vocab.get(word, vocab[UNK]) for word in window] #将字转换成序号y vocab[target]return x, y#建立数据集 #sample_length 输入需要的样本数量。需要多少生成多少 #vocab 词表 #window_size 样本长度 #corpus 语料字符串 def build_dataset(sample_length, vocab, window_size, corpus):dataset_x []dataset_y []for i in range(sample_length):x, y build_sample(vocab, window_size, corpus)dataset_x.append(x)dataset_y.append(y)return torch.LongTensor(dataset_x), torch.LongTensor(dataset_y)#建立模型 def build_model(vocab, char_dim):model LanguageModel(char_dim, vocab)return model#计算文本ppl def calc_perplexity(sentence, model, vocab, window_size):prob 0model.eval()with torch.no_grad():for i in range(1, len(sentence)):start max(0, i - window_size)window sentence[start:i]x [vocab.get(char, vocab[UNK]) for char in window]x torch.LongTensor([x])target sentence[i]target_index vocab.get(target, vocab[UNK])if torch.cuda.is_available():x x.cuda()pred_prob_distribute model(x)[0]target_prob pred_prob_distribute[target_index]prob math.log(target_prob, 10)return 2 ** (prob * ( -1 / len(sentence)))def train(corpus_path, save_weightTrue):epoch_num 10 #训练轮数batch_size 128 #每次训练样本个数train_sample 10000 #每轮训练总共训练的样本总数char_dim 128 #每个字的维度window_size 6 #样本文本长度vocab build_vocab(vocab.txt) #建立字表corpus load_corpus(corpus_path) #加载语料model build_model(vocab, char_dim) #建立模型if torch.cuda.is_available():model model.cuda()optim torch.optim.Adam(model.parameters(), lr0.001) #建立优化器for epoch in range(epoch_num):model.train()watch_loss []for batch in range(int(train_sample / batch_size)):x, y build_dataset(batch_size, vocab, window_size, corpus) #构建一组训练样本if torch.cuda.is_available():x, y x.cuda(), y.cuda()optim.zero_grad() #梯度归零loss model(x, y) #计算losswatch_loss.append(loss.item())loss.backward() #计算梯度optim.step() #更新权重print(\n第%d轮平均loss:%f % (epoch 1, np.mean(watch_loss)))if not save_weight:returnelse:base_name os.path.basename(corpus_path).replace(txt, pth)model_path os.path.join(model, base_name)torch.save(model.state_dict(), model_path)return#训练corpus文件夹下的所有语料根据文件名将训练后的模型放到莫得了文件夹 def train_all():for path in os.listdir(corpus):corpus_path os.path.join(corpus, path)train(corpus_path)if __name__ __main__:# build_vocab_from_corpus(corpus/all.txt)# train(corpus.txt, True)train_all() 2.使用训练好的语言模型作预测 Ⅰ、加载训练好的语言模型 load_state_dict() PyTorch 中模型对象的一个方法用于将预训练的模型参数加载到当前模型中。在深度学习中我们常常会使用预训练模型来加速训练过程或提高模型性能通过该方法可以方便地将保存的参数应用到新的模型实例上。 参数名参数类型是否必填描述state_dict字典是包含模型参数的字典通常是通过 torch.save() 保存的模型状态字典。strict布尔值否指定是否严格匹配模型的状态字典和加载的状态字典。若为 True则要求两者的键和形状完全一致若为 False则允许部分匹配忽略不匹配的键。默认值为 True。 torch.load()PyTorch 中的一个函数用于从文件中加载保存的对象如模型的状态字典、整个模型、张量等。它可以处理不同格式的文件并且支持在 CPU 和 GPU 之间迁移数据。 参数名参数类型是否必填描述f字符串或文件对象是要加载的文件路径或文件对象。map_location字符串、torch.device、函数或字典否指定加载数据的设备。可以是 cpu、cuda 等也可以是自定义的映射函数用于在不同设备之间迁移数据。默认情况下数据会加载到保存时的设备上。pickle_module模块否用于反序列化的 pickle 模块默认使用 Python 内置的 pickle 模块。**pickle_load_args可变关键字参数否传递给 pickle.load() 的其他参数。 model.eval()PyTorch 中模型对象的一个方法用于将模型设置为评估模式。在深度学习模型中有些层如 Dropout、BatchNorm 等在训练和评估阶段的行为是不同的。例如Dropout 在训练时会随机丢弃部分神经元以防止过拟合而在评估时则不进行丢弃操作BatchNorm 在训练时会更新统计信息而在评估时使用训练阶段统计好的均值和方差。调用 model.eval() 可以确保这些层在评估阶段使用正确的行为。 def load_trained_language_model(path):char_dim 128 #每个字的维度,与训练时保持一直window_size 6 #样本文本长度,与训练时保持一直vocab build_vocab(vocab.txt) # 加载字表model build_model(vocab, char_dim) # 加载模型model.load_state_dict(torch.load(path)) #加载训练好的模型权重model.eval()if torch.cuda.is_available():model model.cuda()model.window_size window_sizemodel.vocab vocabreturn model Ⅱ、计算文本ppl range() Python 的内置函数用于生成一个不可变的整数序列通常用于 for 循环中控制迭代次数也可用于创建列表等可迭代对象。 参数名参数类型是否必填描述startint否形式一可不填序列的起始值包含该值。如果不提供默认从 0 开始。stopint是序列的结束值不包含该值。stepint否形式一、二可不填序列中相邻两个数的差值。如果不提供默认步长为 1。 torch.no_grad()PyTorch 中的一个上下文管理器用于临时禁用梯度计算。在模型评估阶段或者不需要计算梯度的场景如推理过程中禁用梯度计算可以减少内存消耗提高计算速度。 max()返回可迭代对象中的最大值或者返回多个参数中的最大值。 参数名参数类型是否必填描述iterable可迭代对象如列表、元组等是第一种形式要查找最大值的可迭代对象。arg1, arg2, *args任意可比较类型是第二种形式多个要比较的参数。key函数否一个用于自定义比较规则的函数该函数接受一个元素作为输入返回一个用于比较的值。default任意类型否当可迭代对象为空时返回的默认值。 torch.cuda.is_available()PyTorch 中的一个函数用于检查当前环境中是否有可用的 CUDA 设备即 GPU。如果返回 True表示可以使用 GPU 进行计算如果返回 False则只能使用 CPU 进行计算。 #计算文本ppl def calc_perplexity(sentence, model):prob 0with torch.no_grad():for i in range(1, len(sentence)):start max(0, i - model.window_size)window sentence[start:i]x [model.vocab.get(char, model.vocab[UNK]) for char in window]x torch.LongTensor([x])target sentence[i]target_index model.vocab.get(target, model.vocab[UNK])if torch.cuda.is_available():x x.cuda()pred_prob_distribute model(x)[0]target_prob pred_prob_distribute[target_index]# print(window , -, target, prob:, float(target_prob))prob math.log(target_prob, 10)return 2 ** (prob * ( -1 / len(sentence)))Ⅲ、加载训练好的所有模型 os.listdir()列出指定路径下的所有文件和子目录名称 os.path.dirname()提取路径中的目录部分不包含末尾文件/目录名 os.path.abspath()将相对路径转换为绝对路径 replace()字符串替换方法属于字符串对象非os模块 os.path.join()智能拼接多个路径组件自动处理系统路径分隔符 函数/方法主要用途输入类型输出类型是否处理系统差异os.listdir()列出目录内容目录路径字符串列表是路径格式os.path.dirname()提取父目录路径路径字符串字符串是os.path.abspath()获取绝对路径路径字符串字符串是str.replace()通用字符串替换字符串字符串否os.path.join()安全拼接路径多个字符串字符串是 #加载训练好的所有模型 def load_models():model_paths os.listdir(os.path.dirname(os.path.abspath(__file__)) /model)class_to_model {}for model_path in model_paths:class_name model_path.replace(.pth, )model_path os.path.join(model, model_path)class_to_model[class_name] load_trained_language_model(model_path)return class_to_model Ⅳ、基于语言模型的文本分类方法 items()Python 字典dict对象的一个方法用于返回一个视图对象该视图对象包含字典中所有的键 - 值对每个键 - 值对以元组的形式呈现。这个视图对象会动态反映字典的变化即当字典的内容发生改变时视图对象也会相应地更新。 append()Python 列表list对象的一个方法用于在列表的末尾添加一个新元素从而修改原列表的内容。 参数名参数类型是否必填描述object任意类型是要添加到列表末尾的元素可以是数字、字符串、列表、元组等任意 Python 对象。 sorted()Python 的内置函数用于对可迭代对象进行排序并返回一个新的已排序列表原可迭代对象不会被修改。 参数名参数类型是否必填描述iterable可迭代对象如列表、元组、字符串等是要进行排序的可迭代对象。key函数否一个用于自定义排序规则的函数该函数接受一个元素作为输入返回一个用于比较的值。reverse布尔值否False 表示升序默认True 表示降序。 #基于语言模型的文本分类伪代码 #class_to_model: {class1:language model obj1, class2:language model obj2, ..} #每个语言模型用对应的领域语料训练 def text_classification_based_on_language_model(class_to_model, sentence):ppl []for class_name, class_lm in class_to_model.items():#用每个语言模型计算pplppl.append([class_name, calc_perplexity(sentence, class_lm)])ppl sorted(ppl, keylambda x:x[1])print(sentence)print(ppl[0: ])print()return ppl Ⅴ、加载训练好的模型做预测 #coding:utf8import torch import torch.nn as nn import numpy as np import math import random import re import os from demo2_nnlm import build_model, build_vocab 使用训练好的语言模型 def load_trained_language_model(path):char_dim 128 #每个字的维度,与训练时保持一直window_size 6 #样本文本长度,与训练时保持一直vocab build_vocab(vocab.txt) # 加载字表model build_model(vocab, char_dim) # 加载模型model.load_state_dict(torch.load(path)) #加载训练好的模型权重model.eval()if torch.cuda.is_available():model model.cuda()model.window_size window_sizemodel.vocab vocabreturn model#计算文本ppl def calc_perplexity(sentence, model):prob 0with torch.no_grad():for i in range(1, len(sentence)):start max(0, i - model.window_size)window sentence[start:i]x [model.vocab.get(char, model.vocab[UNK]) for char in window]x torch.LongTensor([x])target sentence[i]target_index model.vocab.get(target, model.vocab[UNK])if torch.cuda.is_available():x x.cuda()pred_prob_distribute model(x)[0]target_prob pred_prob_distribute[target_index]# print(window , -, target, prob:, float(target_prob))prob math.log(target_prob, 10)return 2 ** (prob * ( -1 / len(sentence)))#加载训练好的所有模型 def load_models():model_paths os.listdir(os.path.dirname(os.path.abspath(__file__)) /model)class_to_model {}for model_path in model_paths:class_name model_path.replace(.pth, )model_path os.path.join(model, model_path)class_to_model[class_name] load_trained_language_model(model_path)return class_to_model#基于语言模型的文本分类伪代码 #class_to_model: {class1:language model obj1, class2:language model obj2, ..} #每个语言模型用对应的领域语料训练 def text_classification_based_on_language_model(class_to_model, sentence):ppl []for class_name, class_lm in class_to_model.items():#用每个语言模型计算pplppl.append([class_name, calc_perplexity(sentence, class_lm)])ppl sorted(ppl, keylambda x:x[1])print(sentence)print(ppl[0: ])print()return pplsentence [在全球货币体系出现危机的情况下,点击进入双色球玩法经典选号图表,慢时尚服饰最大的优点是独特,做处女座朋友的人真的很难,网戒中心要求家长全程陪护,在欧巡赛扭转了自己此前不利的状态,选择独立的别墅会比公寓更适合你,]class_to_model load_models() for s in sentence:text_classification_based_on_language_model(class_to_model, s) 八、两类语言模型的对比 NN神经网络语言模型在概率预测时自带平滑模型可以自动处理非零预测问题模型体型固定不受训练语料的影响不需要寻找回退策略泛化能力较强 如果模型足够优秀则神经网络语言模型的长度不用考虑而N-gram模型随着记录长度的增加训练数据的增大而增大神经网络的训练数据不会改变 1.数据稀疏性处理 N-gram 语言模型 稀疏性问题由于自然语言的复杂性和多样性在训练数据中很多 N-gram 序列可能不会出现导致零概率问题。 平滑技术使用平滑方法(如加一平滑、Kneser-Ney 平滑等)来解决稀疏性问题但效果有限可能导致性能下降。 神经网络语言模型: 词嵌入将词映射到低维向量空间利用词嵌入的相似性来缓解稀疏性问题即使在训练数据中没有出现的词组合也可以通过相似词的信息来估计概率。 泛化能力神经网络通过训练可以学习到词之间的潜在语义关系具有更好的泛化能力对未出现的词组合也能做出相对合理的预测。 2.性能和效率 N-gram 语言模型 计算复杂度存储和计算 N-gram 计数相对简单但对于大规模语料库存储大量的 N-gram 计数需要大量的内存且计算概率的时间复杂度较高尤其是在处理长序列时。 可扩展性在处理大规模数据时存储和性能会成为瓶颈难以处理长距离依赖关系 神经网络语言模型 计算复杂度训练神经网络需要更多的计算资源和时间但可以通过 GPU 加速。 可扩展性可以处理大规模数据能够学习长距离依赖通过调整网络结构和参数可以适应不同的任务和数据规模。 3.对上下文的处理 N-gram 语言模型 局部依赖只能处理有限长度的上下文(N-1个词)难以捕捉长距离依赖关系例如在处理长句子时由于依赖范围的限制可能无法准确预测后续词。 神经网络语言模型 长距离依赖理论上可以通过网络结构(如循环神经网络 RNN、长短时记忆网络 LSTM、门控循环单元GRU 或 Transformer)学习长距离依赖关系捕捉更远的上下文信息。 4.总结 N-gram 语言模型简单、易于理解和实现适合处理小规模数据和简单的语言任务但受限于数据稀疏性和短距离依赖。 神经网络语言模型计算成本高但功能强大通过深度学习技术可以处理大规模数据和复杂的语言现象能够学习长距离依赖和语义关系适合高级的自然语言处理任务但需要更多的计算资源和数据。 九、语言模型的应用 1.话者分离 ① 根据说话内容判断说话人 常用于语言识别系统中判断录音对话中角色 如客服对话录音判断坐席或客户 ② 根据不同腔调判断说话人 翻译腔 这倒霉的房子里竟然有蟑螂你可以想象到吗这真是太可怕了 港台腔你这个人怎么可以这个样子 东北味 我不稀得说你那些事儿就拉倒了 话者分离本质上为文本分类任务 步骤  1.对于每个类别使用类别语料训练语言模型 2.对于一个新输入的文本用所有语言模型计算成句概率 3.选取概率最高的类别为预测类别 相比一般文本分类模型如贝叶斯rf神经网络等NN语言模型的优势 1.每个类别模型互相独立样本不均衡或样本有错误对其他模型没有影响 2..可以随时增加新的类别而不影响旧的类别的效果在加入新的类别时不需要重新训练模型 效果上讲一般不会有显著优势        效率上讲一般会低于统一的分类模型 2.文本纠错 纠正文本中的错误 如 我今天去了天暗门看人民英雄记念碑       我今天去了天安门看人民英雄纪念碑 错误可能是同音字或形近字等 步骤 ① 对每一个字建立一个混淆字集合 ② 计算整句话成句概率 ③ 用混淆字集合中的词替代原句中的字重新计算概率 ④ 选取得分最高的一个候选句子如果这个句子比原句的得分增长超过一定的阈值 ⑤ 对下一个字重复步骤3-4直到句子末尾 同音字有完整字表 形似字可以通过 ocr 收集 也可以依照实际情况手动添加一些 缺陷 这种方式有一些缺陷 ① 无法解决多字少字问题 ② 阈值的设置非常难把握如果设置过大达不到纠错效果如果设置过小造成大量替换有可能改变句子的原意 ③ 混淆字字表难以完备错误可能是同音字或形近字 ④ 语言模型的领域性会影响修改结果 ⑤ 连续的错字会大幅提升纠错难度如今天上午要过来办事 - 今天商务要过来办事 一般工业做法 限定一个修改白名单只判断特定的字词是否要修改 如限定只对所有发音为shang wu的片段计算是否修改为“商务”其余一概不做处理 对于深度学习模型而言错别字是可以容忍的所以纠错本身的重要性在下降一般只针对展示类任务 3.数字归一化 将一个文本中的数字部分转化为对读者友好的样式 常见于语言识别系统后展示文本时使用 如 秦皇岛港煤炭库存量在十一月初突然激增从四百五十四点九万吨增加到七百七十三点四万吨打破了一九九九年以来的记录 秦皇岛港煤炭库存量在11月初突然激增从454.9万吨增加到773.4万吨打破了1999年以来的记录 十一届三中全会、“十二五”规划、一贫如洗、二龙戏珠 步骤 ① 找到数字形式符合规范的文本作为原始语料 ② 用正则表达式找到数字部分任意形式 ③ 将数字部分依照其格式替换为阿拉伯数字汉字数字汉字连读等token ④ 使用带token文本训练语言模型 ⑤ 对于新输入的文本同样使用正则表达式找到数字部分之后分别带入各个token使用语言模型计算概率 ⑥ 选取概率最高的token最为最终数字格式按照规则转化后填入原文本 4.文本打标 给文本添加标点或语气停顿等 例我最近 抽了点时间 读了一本 关于 马尔可夫生平 的书 可以理解为一种粗粒度的分词 常用于语音合成任务中辅助做出发音的停顿 需要有标注数据在停顿处添加token s 如 我最近 s 抽了点时间 s 读了一本 s 关于 s 马尔可夫生平 s 的书 带token训练语言模型 预测过程 ① 选定一个窗口长度首先预测第一次停顿位置 我s最近抽了点时间   ppl:10 我最s近抽了点时间   ppl:20 我最近s抽了点时间   ppl:5   ②  选择ppl值较小的地方作为第一次停顿 …、 ③ 之后从“抽了点时间”开始向后重复此过程 本质为序列标注任务 可以依照类似方式处理分词、文本加标点、文本段落切分等任务 分词或切分段落只需要一种token打标点时可以用多种分隔token代表不同标点 十、总结 1.语言模型的核心能力是计算成句概率计算下一个字的概率分布依赖这一能力可以完成大量不同类型的NLP任务。 2.基于统计的语言模型和基于神经网络的语言模型各有使用的场景大体上讲基于统计的模型优势在于解码速度而神经网络的模型通常效果更好。 3.单纯通过PPL评价语言模型是有局限的通过下游任务效果进行整体评价更好。 4.深入的理解一种算法有助于发现更多的应用方式。 5.看似简单甚至错误的假设也能带来有意义的结果事实上这是简化问题的常见方式。
http://www.hkea.cn/news/14256847/

相关文章:

  • o2o网站wordpress斜杠
  • 广州网站建设设计公司手机网页打不开是什么原因
  • 如何选择电商网站建设wordpress 内容 管理
  • 办网站租服务器做旅游攻略的网站
  • 建行网站会员是什么logo在线设计制作
  • 律所网站建设国队男子接力赛上海公司建立网站吗
  • wordpress软件站主题兰州网站建设专家
  • 西宁公司网站设计线上营销方法有哪些
  • 深圳知名网站建设平台dedecms5.7装饰公司网站模板
  • 网站建设能赚多少钱网站内容建设和管理
  • 网站建设投标文件如何网推
  • 重庆网站建设公司招聘前端直播网站怎么做
  • 陕西榆林市信息网站建设公司兰州 网站建设公司
  • 如果查询网站内页的收录情况石家庄seo管理
  • 申请网站建设经费玉泉路网站建设
  • 网站开发发展存在的问题新余 网站建设
  • 网站开发与托管协议合肥有什么好的网站建设公司
  • h5网站开发软件有名vi设计公司
  • 制作网站怎么制作网页无法访问但是有网什么原因
  • 网站建设主机耗电量淘宝网页版手机登录
  • 净水机企业网站源码东山县建设银行网站
  • 有没有做生鲜配送的网站骨科医院网站模板
  • 保定门户网站昆明网站建设手机版
  • 网站建设工资郑州一个县城广告公司利润
  • 企业网站开发公司管理咨询人员的基本素质
  • 怎样推广自己的商城为什么打开网址都是seo综合查询
  • 做食品那些网站好衡水哪里做网站
  • 湖南营销型网站建设公司如何创建软件app
  • 坪山网站建设代理商高校二级网站建设方案
  • 做建材的哪些网站凡科可以做淘客网站吗