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

移动网站怎么做石家庄网站营销

移动网站怎么做,石家庄网站营销,ps网页设计尺寸,最火的网络推广平台跳元模型 回顾一下第一节讲过的跳元模型 跳元模型#xff08;Skip-gram Model#xff09;是一种用于学习词向量的模型#xff0c;属于Word2Vec算法中的一种。它的目标是通过给定一个中心词语来预测其周围的上下文词语。 这节我们以跳元模型为例#xff0c;讲解word2vec的…跳元模型 回顾一下第一节讲过的跳元模型 跳元模型Skip-gram Model是一种用于学习词向量的模型属于Word2Vec算法中的一种。它的目标是通过给定一个中心词语来预测其周围的上下文词语。 这节我们以跳元模型为例讲解word2vec的实现 文章内容来自李沐大神的《动手学深度学习》并加以我的理解感兴趣可以去https://zh-v2.d2l.ai/查看完整书籍 文章目录 跳元模型数据集数据集的获取词表的构建下采样中心词和上下文词的提取负采样小批量加载训练实例整合所有代码 训练word2vec跳元模型嵌入层定义前向传播 训练二元交叉熵损失初始化模型参数定义训练阶段代码 应用词嵌入 数据集 我们在这里使用的数据集是Penn Tree BankPTB。该语料库取自“华尔街日报”的文章分为训练集、验证集和测试集。在原始格式中文本文件的每一行表示由空格分隔的一句话。在这里我们将每个单词视为一个词元。 数据集的获取 import math import os import random import torch from d2l import torch as d2l #save d2l.DATA_HUB[ptb] (d2l.DATA_URL ptb.zip,319d85e578af0cdc590547f26231e4e31cdf1e42)#save def read_ptb():将PTB数据集加载到文本行的列表中data_dir d2l.download_extract(ptb)# Readthetrainingset.with open(os.path.join(data_dir, ptb.train.txt)) as f:raw_text f.read()return [line.split() for line in raw_text.split(\n)]sentences read_ptb() f# sentences数: {len(sentences)}在读取训练集之后我们为语料库构建了一个词表其中出现次数少于10次的任何单词都将由“”词元替换。请注意原始数据集还包含表示稀有未知单词的“”词元。 词表的构建 vocab d2l.Vocab(sentences, min_freq10) fvocab size: {len(vocab)}词表Vocabulary也被称为词典Dictionary或词汇表是在自然语言处理NLP任务中用于表示文本数据中所有不同单词的集合。 在文本处理中将文本数据转换为机器可处理的形式通常需要对单词进行编码。词表是一个重要的组成部分它将每个单词映射到一个唯一的标识符例如整数索引。通过构建词表我们可以将文本数据中的单词转换为数字表示以便机器学习模型可以对其进行处理。 词表的构建过程包括以下步骤 收集所有的单词遍历文本数据将其中出现的所有单词进行收集。去重去除重复的单词确保每个单词只在词表中出现一次。分配唯一标识符为每个单词分配一个唯一的标识符例如整数索引。常见的做法是按照单词出现的频率进行排序频率高的单词通常被分配较小的索引。特殊标记词表通常还包括一些特殊标记如未知词元UNK、填充词元PAD、开始词元START、结束词元END等。这些标记用于表示特定的语义或在模型中的特殊处理。 词表在NLP任务中起到了关键的作用它不仅提供了单词到数字的映射还可以用于统计词频、计算词向量等。构建一个良好的词表对于成功实施文本处理任务至关重要。 d2l中的词表如下实现 class Vocab:Vocabulary for text.def __init__(self, tokensNone, min_freq0, reserved_tokensNone):Defined in :numref:sec_text_preprocessingif tokens is None:tokens []if reserved_tokens is None:reserved_tokens []# Sort according to frequenciescounter count_corpus(tokens)self._token_freqs sorted(counter.items(), keylambda x: x[1],reverseTrue)# The index for the unknown token is 0self.idx_to_token [unk] reserved_tokensself.token_to_idx {token: idxfor idx, token in enumerate(self.idx_to_token)}for token, freq in self._token_freqs:if freq min_freq:breakif token not in self.token_to_idx:self.idx_to_token.append(token)self.token_to_idx[token] len(self.idx_to_token) - 1def __len__(self):return len(self.idx_to_token)def __getitem__(self, tokens):if not isinstance(tokens, (list, tuple)):return self.token_to_idx.get(tokens, self.unk)return [self.__getitem__(token) for token in tokens]def to_tokens(self, indices):if not isinstance(indices, (list, tuple)):return self.idx_to_token[indices]return [self.idx_to_token[index] for index in indices]def count_corpus(tokens):Count token frequencies.Defined in :numref:sec_text_preprocessing# Here tokens is a 1D list or 2D listif len(tokens) 0 or isinstance(tokens[0], list):# Flatten a list of token lists into a list of tokenstokens [token for line in tokens for token in line]return collections.Counter(tokens)propertydef unk(self): # Index for the unknown tokenreturn 0propertydef token_freqs(self): # Index for the unknown tokenreturn self._token_freqs下采样 文本数据通常有“the”“a”和“in”等高频词它们在非常大的语料库中甚至可能出现数十亿次。然而这些词经常在上下文窗口中与许多不同的词共同出现提供的有用信息很少。例如考虑上下文窗口中的词“chip”直观地说它与低频单词“intel”的共现比与高频单词“a”的共现在训练中更有用。此外大量高频单词的训练速度很慢。因此当训练词嵌入模型时可以对高频单词进行下采样 (Mikolov et al., 2013)。具体地说数据集中的每个词 w i w_i wi​将有概率 P ( w i ) P(w_i) P(wi​)地被丢弃: P ( w i ) m a x ( 1 − t f ( w i ) , 0 ) P(w_i)max(1-\sqrt{\frac{t}{f(w_i)}},0) P(wi​)max(1−f(wi​)t​ ​,0) 其中 f ( w i ) f(w_i) f(wi​)是 w i w_i wi​的词数与数据集中的总词数的比率常量 t t t是超参数在实验中为 1 0 − 4 10^{-4} 10−4。我们可以看到只有当相对比率 f ( w i ) t f(w_i)t f(wi​)t时高频词 w i w_i wi​才能被丢弃且该词的相对比率越高被丢弃的概率就越大。 #save def subsample(sentences, vocab):下采样高频词# 排除未知词元unksentences [[token for token in line if vocab[token] ! vocab.unk]for line in sentences]counter d2l.count_corpus(sentences)num_tokens sum(counter.values())# 如果在下采样期间保留词元则返回Truedef keep(token):return(random.uniform(0, 1) math.sqrt(1e-4 / counter[token] * num_tokens))return ([[token for token in line if keep(token)] for line in sentences],counter)subsampled, counter subsample(sentences, vocab)这段代码是一个用于下采样高频词的函数。 函数的输入参数包括 sentences句子列表和 vocab词表。该函数的输出是一个经过下采样处理后的句子列表和词频统计计数器。 下采样的过程如下 首先函数排除了句子中的未知词元 unk即词表中未知词的标记。然后使用 count_corpus 函数统计句子中每个词元的频次并计算语料中总的词元数。定义了一个内部函数 keep(token)用于判断是否在下采样过程中保留词元。这里使用了一个阈值 1e-4 和词元的频次来决定是否保留词元。频次较高的词元将有较小的概率保留下来而频次较低的词元将有较大的概率保留下来。最后函数遍历每个句子中的词元根据 keep 函数的结果来决定是否保留该词元。保留的词元构成了经过下采样处理后的句子列表。 下面的代码片段绘制了下采样前后每句话的词元数量的直方图。正如预期的那样下采样通过删除高频词来显著缩短句子这将使训练加速。 d2l.show_list_len_pair_hist([origin, subsampled], # tokens per sentence,count, sentences, subsampled);我们看出句子的长度显著降低。对于单个词元高频词“the”的采样率不到1/20。 def compare_counts(token):return (f{token}的数量f之前{sum([l.count(token) for l in sentences])}, f之后{sum([l.count(token) for l in subsampled])})compare_counts(the)相比之下低频词“join”则被完全保留。 compare_counts(join)在下采样之后我们将词元映射到它们在语料库中的索引。 中心词和上下文词的提取 下面的get_centers_and_contexts函数从corpus中提取所有中心词及其上下文词。它随机采样1到max_window_size之间的整数作为上下文窗口。对于任一中心词与其距离不超过采样上下文窗口大小的词为其上下文词。 #save def get_centers_and_contexts(corpus, max_window_size):返回跳元模型中的中心词和上下文词centers, contexts [], []for line in corpus:# 要形成“中心词-上下文词”对每个句子至少需要有2个词if len(line) 2:continuecenters linefor i in range(len(line)): # 上下文窗口中间iwindow_size random.randint(1, max_window_size)indices list(range(max(0, i - window_size),min(len(line), i 1 window_size)))# 从上下文词中排除中心词indices.remove(i)contexts.append([line[idx] for idx in indices])return centers, contexts函数的输入参数包括 corpus 和 max_window_size。corpus 是一个包含多个句子的语料库每个句子由单词列表表示。max_window_size 是一个整数表示上下文窗口的最大大小。 函数的输出是两个列表分别是中心词列表 centers 和上下文词列表 contexts。 代码的逻辑如下 创建空的中心词列表 centers 和上下文词列表 contexts。对于语料库中的每个句子 line执行以下步骤 如果句子的长度小于 2即句子中不足两个词则跳过该句子。将句子中的所有单词添加到中心词列表 centers 中。对于句子中的每个词的索引 i执行以下步骤 随机生成一个上下文窗口的大小 window_size范围为 1 到 max_window_size。计算上下文窗口的左边界索引为 max(0, i - window_size)右边界索引为 min(len(line), i 1 window_size)。创建一个索引列表 indices包含上下文窗口范围内的索引。从索引列表中移除中心词的索引 i得到最终的上下文词索引列表。根据最终的上下文词索引列表获取对应的上下文词并将其添加到上下文词列表 contexts 中。 完成语料库中所有句子的处理后返回中心词列表 centers 和上下文词列表 contexts。 接下来我们创建一个人工数据集分别包含7个和3个单词的两个句子。设置最大上下文窗口大小为2并打印所有中心词及其上下文词。 tiny_dataset [list(range(7)), list(range(7, 10))] print(数据集, tiny_dataset) for center, context in zip(*get_centers_and_contexts(tiny_dataset, 2)):print(中心词, center, 的上下文词是, context)在PTB数据集上进行训练时我们将最大上下文窗口大小设置为5。下面提取数据集中的所有中心词及其上下文词。 all_centers, all_contexts get_centers_and_contexts(corpus, 5) f# “中心词-上下文词对”的数量: {sum([len(contexts) for contexts in all_contexts])}负采样 我们使用负采样进行近似训练。为了根据预定义的分布对噪声词进行采样我们定义以下RandomGenerator类其中可能未规范化的采样分布通过变量sampling_weights传递。 sampling_weights具体来说是一个和population相同形状的列表代表了population中对应元素被采样的概率 #save class RandomGenerator:根据n个采样权重在{1,...,n}中随机抽取def __init__(self, sampling_weights):# Excludeself.population list(range(1, len(sampling_weights) 1))self.sampling_weights sampling_weightsself.candidates []self.i 0def draw(self):#每次调用函数缓存10000个采样输出一个采样i自增1直到用完整个缓存继续采样if self.i len(self.candidates):# 缓存k个随机采样结果self.candidates random.choices(self.population, self.sampling_weights, k10000)self.i 0self.i 1return self.candidates[self.i - 1]这段代码定义了一个名为 RandomGenerator 的类用于根据给定的采样权重在整数范围 {1, ..., n} 中进行随机抽取。 构造函数 __init__ 在创建类的实例时被调用并接受一个采样权重列表 sampling_weights 作为参数。在构造函数内部以下操作被执行 创建一个整数列表 population其中包含了从 1 到 len(sampling_weights) 的整数范围用于表示可能的抽样候选项。将采样权重列表存储在实例变量 sampling_weights 中。创建一个空的候选项列表 candidates用于缓存采样结果。初始化一个索引变量 i用于追踪当前采样的位置。 draw 方法用于执行随机抽取操作。方法的逻辑如下 首先检查当前采样位置 i 是否等于候选项列表 candidates 的长度。如果相等说明之前缓存的采样结果已经用完需要重新生成一批新的采样结果。调用 random.choices 函数来生成 k10000 个随机采样结果其中 population 参数为整数范围 {1, ..., n}sampling_weights 参数为采样权重列表k 参数表示生成的采样结果数量。生成的结果存储在候选项列表 candidates 中。将索引变量 i 增加 1表示进行了一次新的采样。返回候选项列表中当前采样位置对应的元素。 这种设计的目的是为了提高采样效率。通过一次性生成一批采样结果并进行缓存可以减少对 random.choices 函数的调用次数提高整体的性能。每次调用 draw 方法时通过逐个返回缓存的采样结果避免了每次调用都进行一次完整的随机抽取操作。 例如我们可以在索引1、2和3中绘制10个随机变量 X X X采样概率为 P ( X 1 ) 2 / 9 , P ( X 2 ) 3 / 9 和 P ( X 3 ) 4 / 9 P(X1)2/9,P(X2)3/9和P(X3)4/9 P(X1)2/9,P(X2)3/9和P(X3)4/9如下所示。 #save generator RandomGenerator([2, 3, 4]) [generator.draw() for _ in range(10)]对于一对中心词和上下文词我们随机抽取了K个实验中为5个噪声词。根据word2vec论文中的建议将噪声词 w w w的采样概率 P ( w ) P(w) P(w)设置为其在字典中的相对频率其幂为0.75 (Mikolov et al., 2013)。 #save def get_negatives(all_contexts, vocab, counter, K):返回负采样中的噪声词# 索引为1、2、...索引0是词表中排除的未知标记sampling_weights [counter[vocab.to_tokens(i)]**0.75for i in range(1, len(vocab))]all_negatives, generator [], RandomGenerator(sampling_weights)for contexts in all_contexts:negatives []while len(negatives) len(contexts) * K:neg generator.draw()# 噪声词不能是上下文词if neg not in contexts:negatives.append(neg)all_negatives.append(negatives)return all_negativesall_negatives get_negatives(all_contexts, vocab, counter, 5)函数接受以下参数 all_contexts表示所有的上下文词的列表或可迭代对象。vocab表示词汇表的对象。counter表示词频计数器的对象。K表示每个上下文词应采样的噪声词数量。 函数的逻辑如下 首先根据词频计数器 counter 和词汇表 vocab计算每个词的采样权重列表 sampling_weights。对于词汇表中的每个词除了未知标记使用词频的 0.75 次方作为权重值。这样可以使较低频次的词有更高的采样概率。创建一个空列表 all_negatives用于存储每个上下文对应的噪声词列表。创建一个随机生成器对象 generator并将前面计算得到的采样权重列表 sampling_weights 作为参数传递给生成器的构造函数。对于每个上下文词列表 contexts执行以下操作 创建一个空列表 negatives用于存储当前上下文词的噪声词。在噪声词列表中采样直到噪声词的数量达到当前上下文词数量乘以 K。每次从随机生成器 generator 中使用 draw 方法进行采样得到一个噪声词。检查采样得到的噪声词是否不在当前上下文词列表 contexts 中如果满足条件则将噪声词添加到 negatives 列表中。将 negatives 列表添加到 all_negatives 列表中表示当前上下文对应的噪声词列表。 最后函数返回 all_negatives其中包含了每个上下文对应的噪声词列表。 小批量加载训练实例 在提取所有中心词及其上下文词和采样噪声词后将它们转换成小批量的样本在训练过程中可以迭代加载。 在小批量中 i t h i^{th} ith个样本包括中心词及其 n i n_i ni​个上下文词和 m i m_i mi​个噪声词。由于上下文窗口大小不同 n i m i n_im_i ni​mi​对于不同的 i i i是不同的。因此对于每个样本我们在contexts_negatives个变量中将其上下文词和噪声词连结起来并填充零直到连结长度达到 m a x ( n i m i ) max(n_im_i) max(ni​mi​)。为了在计算损失时排除填充我们定义了掩码变量masks。在masks中的元素和contexts_negatives中的元素之间存在一一对应关系其中masks中的0否则为1对应于contexts_negatives中的填充。 为了区分正反例我们在contexts_negatives中通过一个labels变量将上下文词与噪声词分开。类似于masks在labels中的元素和contexts_negatives中的元素之间也存在一一对应关系其中labels中的1否则为0对应于contexts_negatives中的上下文词的正例。 上述思想在下面的batchify函数中实现。其输入data是长度等于批量大小的列表其中每个元素是由中心词center、其上下文词context和其噪声词negative组成的样本。此函数返回一个可以在训练期间加载用于计算的小批量例如包括掩码变量。 #save def batchify(data):返回带有负采样的跳元模型的小批量样本#计算最大长度max_len max(len(c) len(n) for _, c, n in data)centers, contexts_negatives, masks, labels [], [], [], []for center, context, negative in data:cur_len len(context) len(negative)centers [center]contexts_negatives \[context negative [0] * (max_len - cur_len)]masks [[1] * cur_len [0] * (max_len - cur_len)]labels [[1] * len(context) [0] * (max_len - len(context))]#负采样的部分也标注为0return (torch.tensor(centers).reshape((-1, 1)), torch.tensor(contexts_negatives), torch.tensor(masks), torch.tensor(labels))函数接受一个数据列表 data其中每个元素包含了中心词、上下文词列表和负采样的噪声词列表。 函数的逻辑如下 首先计算所有样本中上下文词列表和负采样噪声词列表的最大长度 max_len。这将用于确定小批量样本的张量形状。 创建四个空列表centers 用于存储中心词contexts_negatives 用于存储拼接后的上下文词列表和负采样噪声词列表masks 用于存储掩码张量labels 用于存储标签张量。 对于数据列表 data 中的每个元组 (center, context, negative)执行以下操作 计算当前样本中上下文词列表和负采样噪声词列表的长度 cur_len。将中心词 center 添加到 centers 列表中。将上下文词列表、负采样噪声词列表和填充的零元素拼接成一个长度为 max_len 的列表并将结果添加到 contexts_negatives 列表中。创建一个掩码张量**其中上下文词部分和负采样的部分为 1填充部分为 0**并将结果添加到 masks 列表中。创建一个标签张量**其中上下文词部分为 1负采样噪声词和填充部分为 0**并将结果添加到 labels 列表中。 最后函数将四个列表转换为张量并返回一个包含中心词张量、上下文词列表和负采样噪声词列表的元组。 让我们使用一个小批量的两个样本来测试此函数。 x_1 (1, [2, 2], [3, 3, 3, 3]) x_2 (1, [2, 2, 2], [3, 3]) batch batchify((x_1, x_2))names [centers, contexts_negatives, masks, labels] for name, data in zip(names, batch):print(name, , data)整合所有代码 #save def load_data_ptb(batch_size, max_window_size, num_noise_words):下载PTB数据集然后将其加载到内存中num_workers 0;#获取数据集sentences read_ptb()#生成词表vocab d2l.Vocab(sentences, min_freq10)#下采样subsampled, counter subsample(sentences, vocab)#采样结果转索引corpus [vocab[line] for line in subsampled]#获取所有中心词和上下文词all_centers, all_contexts get_centers_and_contexts(corpus, max_window_size)#获取所有噪声词all_negatives get_negatives(all_contexts, vocab, counter, num_noise_words)# 定义数据集class PTBDataset(torch.utils.data.Dataset):def __init__(self, centers, contexts, negatives):assert len(centers) len(contexts) len(negatives)self.centers centersself.contexts contextsself.negatives negativesdef __getitem__(self, index):return (self.centers[index], self.contexts[index],self.negatives[index])def __len__(self):return len(self.centers)dataset PTBDataset(all_centers, all_contexts, all_negatives)data_iter torch.utils.data.DataLoader(dataset, batch_size, shuffleTrue,collate_fnbatchify, num_workersnum_workers)return data_iter, vocab注意collate_fnbatchify collate_fn是torch.utils.data.DataLoader类的一个可选参数用于指定在加载每个小批量样本时要使用的函数。 当collate_fn参数被指定时DataLoader会在每个小批量样本加载时调用这个函数并将单个样本作为输入。collate_fn函数负责对单个样本进行处理并将它们组合成一个小批量样本。 通常情况下collate_fn函数用于将单个样本转换为张量形式并根据需要进行填充或其他数据转换操作。这样可以确保每个小批量样本具有相同的形状以便于输入到模型进行训练或推理。 让我们打印数据迭代器的第一个小批量。 data_iter, vocab load_data_ptb(512, 5, 5) for batch in data_iter:for name, data in zip(names, batch):print(name, shape:, data.shape)break训练word2vec 使用上述定义的函数获取数据集 batch_size, max_window_size, num_noise_words 512, 5, 5 data_iter, vocab d2l.load_data_ptb(batch_size, max_window_size,num_noise_words)跳元模型 嵌入层 嵌入层Embedding Layer是深度学习中常用的一种层类型用于将离散的符号如词、字符等表示为连续的向量形式也被称为词嵌入或向量表示。 在自然语言处理NLP任务中文本数据通常以离散的符号形式表示如词汇表中的单词。嵌入层可以将这些离散符号映射到连续的低维向量空间中其中每个维度代表了一个语义特征。嵌入层的目的是通过学习这种映射关系将相似的符号映射到相近的向量表示从而捕捉到词之间的语义关系。 嵌入层通常通过一个可训练的参数矩阵来实现。该参数矩阵的维度是词汇表大小词的数量乘以嵌入向量的维度。在训练过程中这些嵌入向量会根据模型的优化目标逐渐调整以最大程度地捕捉到词汇之间的语义关系。 嵌入层在深度学习中的应用非常广泛特别是在NLP任务中。它可以作为模型的第一层将输入的离散符号例如单词或字符转换为密集向量表示进而输入到后续层进行进一步处理如循环神经网络RNN或卷积神经网络CNN等。 嵌入层将词元的索引映射到其特征向量。该层的权重是一个矩阵其行数等于字典大小input_dim列数等于每个标记的向量维数output_dim。在词嵌入模型训练之后这个权重就是我们所需要的。 # 创建嵌入层的参数矩阵 embedding_weights torch.randn(vocab_size, embedding_dim)我们可以使用torch中的Embedding创建嵌入层 embed nn.Embedding(num_embeddings20, embedding_dim4) print(fParameter embedding_weight ({embed.weight.shape}, fdtype{embed.weight.dtype}))嵌入层的输入是词元词的索引。对于任何词元索引 i i i其向量表示可以从嵌入层中的权重矩阵的第 i i i行获得。由于向量维度output_dim被设置为4因此当小批量词元索引的形状为23时嵌入层返回具有形状234的向量。 x torch.tensor([[1, 2, 3], [4, 5, 6]]) embed(x)定义前向传播 在前向传播中跳元语法模型的输入包括形状为批量大小1的中心词索引center和形状为批量大小max_len的上下文与噪声词索引contexts_and_negatives这两个变量首先通过嵌入层从词元索引转换成向量然后它们的批量矩阵相乘,返回形状为批量大小1max_len的输出。输出中的每个元素是中心词向量和上下文或噪声词向量的点积。 跳元的定义 def skip_gram(center, contexts_and_negatives, embed_v, embed_u):v embed_v(center)u embed_u(contexts_and_negatives)pred torch.bmm(v, u.permute(0, 2, 1))#批量矩阵乘法return pred在给定中心词center和上下文词汇contexts_and_negatives的情况下代码使用embed_v和embed_u分别对中心词和上下文词汇进行嵌入操作。然后通过调用torch.bmm函数执行批量矩阵乘法计算中心词向量v与上下文词汇向量u的转置之间的乘积。最终返回预测结果pred。 值得注意的是torch.bmm函数接受的输入张量的形状需满足要求。在这个例子中v的形状应为(batch_size, 1, embedding_dim)u的形状应为(batch_size, num_negatives num_contexts, embedding_dim)其中batch_size表示批量大小embedding_dim表示词向量维度num_negatives表示负样本数量num_contexts表示上下文词汇数量。 skip_gram(torch.ones((2, 1), dtypetorch.long),torch.ones((2, 4), dtypetorch.long), embed, embed).shape训练 在训练带负采样的跳元模型之前我们先定义它的损失函数。 二元交叉熵损失 交叉熵Cross-Entropy是一种常用的损失函数常用于分类任务中。它用于衡量模型的输出与目标标签之间的差异。 CrossEntropy − ∑ i 1 N ∑ j 1 K y i j log ⁡ ( p i j ) \text{CrossEntropy} -\sum_{i1}^{N}\sum_{j1}^{K} y_{ij} \log(p_{ij}) CrossEntropy−i1∑N​j1∑K​yij​log(pij​) 其中 y i j y_{ij} yij​表示第i个样本的真实标签的第j个元素0或1 p i j p_{ij} pij​表示模型预测的第i个样本属于第j个类别的概率。 二元交叉熵损失Binary Cross-Entropy Loss是交叉熵损失函数在二分类问题中的特殊形式。它用于衡量二分类模型的预测结果与真实结果之间的差异。 在二分类问题中我们有两个类别通常将它们表示为正例positive和反例negative。对于每个样本我们用一个标签值来表示其真实类别通常为0或1其中0表示反例1表示正例。模型给出的预测结果是一个介于0和1之间的概率值表示样本属于正例的概率。 二元交叉熵损失的计算公式如下 H ( p , q ) − 1 N ∑ i 1 N [ y i log ⁡ ( p i ) ( 1 − y i ) log ⁡ ( 1 − p i ) ] H(p, q) -\frac{1}{N}\sum_{i1}^{N}[y_{i}\log(p_{i}) (1-y_{i})\log(1-p_{i})] H(p,q)−N1​i1∑N​[yi​log(pi​)(1−yi​)log(1−pi​)] 其中 N N N表示样本数量 y i y_i yi​表示第 i i i个样本的真实标签取值为0或1 p i p_i pi​表示预测为类别1的概率。 为什么使用二元交叉熵损失 我们回顾上一节我们计算出的损失的函数 观察到和二元交叉熵损失非常相似其中中心词的上下文词被视为正例而其他随机选择的词负采样部分则被视为负例。 对于每个训练样本我们将中心词作为输入然后使用模型进行预测。预测结果是一个介于0和1之间的概率值表示上下文词是正例的概率。然后我们使用二元交叉熵损失函数来计算预测结果与真实结果之间的差异并通过优化算法如梯度下降来最小化这个损失函数。 class SigmoidBCELoss(nn.Module):# 带掩码的二元交叉熵损失def __init__(self):super().__init__()def forward(self, inputs, target, maskNone):out nn.functional.binary_cross_entropy_with_logits(inputs, target, weightmask, reductionnone)return out.mean(dim1)loss SigmoidBCELoss()在forward方法中调用了nn.functional.binary_cross_entropy_with_logits函数该函数是PyTorch中用于计算二元交叉熵损失的函数。它接收模型的输出未经过Sigmoid函数、真实标签和掩码作为输入并返回一个张量其中包含每个样本的损失值。 nn.functional.binary_cross_entropy_with_logits 是 PyTorch 中用于计算二分类问题的交叉熵损失函数。它可以在处理具有二元标签的分类任务时非常有用。该函数的输入是模型的输出 logits 和对应的目标标签它会自动将 logits 通过 sigmoid 函数转换为概率并计算预测概率与目标标签之间的交叉熵损失。 以下是 nn.functional.binary_cross_entropy_with_logits 函数的实现原理 首先输入的 logits 应该是一个具有任意形状的张量通常来自于模型的输出层没有经过 sigmoid 函数处理。 函数内部会将 logits 通过 sigmoid 函数转换为概率即将 logits 的每个元素 x 转换为 p 1 / (1 exp(-x))。 然后函数会将目标标签 target 转换为与 logits 相同的形状以便进行逐元素的比较。 接下来函数会计算每个预测概率 p 与对应的目标标签 t 之间的交叉熵损失使用上述公式计算 最后函数会返回所有样本的平均损失即将每个样本的损失相加并除以样本总数如果 reduction 参数设置为 mean。 pred torch.tensor([[1.1, -2.2, 3.3, -4.4]] * 2) label torch.tensor([[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0]]) mask torch.tensor([[1, 1, 1, 1], [1, 1, 0, 0]]) loss(pred, label, mask) * mask.shape[1] / mask.sum(axis1)计算过程 def sigmd(x):return -math.log(1 / (1 math.exp(-x)))print(f{(sigmd(1.1) sigmd(2.2) sigmd(-3.3) sigmd(4.4)) / 4:.4f}) print(f{(sigmd(-1.1) sigmd(-2.2)) / 2:.4f})初始化模型参数 我们定义了两个嵌入层将词表中的所有单词分别作为中心词和上下文词使用。字向量维度embed_size被设置为100。 embed_size 100 net nn.Sequential(nn.Embedding(num_embeddingslen(vocab),embedding_dimembed_size),nn.Embedding(num_embeddingslen(vocab),embedding_dimembed_size))定义训练阶段代码 训练阶段代码实现定义如下。由于填充的存在损失函数的计算与以前的训练函数略有不同。 def train(net, data_iter, lr, num_epochs, deviced2l.try_gpu()):def init_weights(m):if type(m) nn.Embedding:nn.init.xavier_uniform_(m.weight)net.apply(init_weights)net net.to(device)optimizer torch.optim.Adam(net.parameters(), lrlr)animator d2l.Animator(xlabelepoch, ylabelloss,xlim[1, num_epochs])# 规范化的损失之和规范化的损失数metric d2l.Accumulator(2)for epoch in range(num_epochs):timer, num_batches d2l.Timer(), len(data_iter)for i, batch in enumerate(data_iter):optimizer.zero_grad()center, context_negative, mask, label [data.to(device) for data in batch]pred skip_gram(center, context_negative, net[0], net[1])l (loss(pred.reshape(label.shape).float(), label.float(), mask)/ mask.sum(axis1) * mask.shape[1])l.sum().backward()optimizer.step()metric.add(l.sum(), l.numel())if (i 1) % (num_batches // 5) 0 or i num_batches - 1:animator.add(epoch (i 1) / num_batches,(metric[0] / metric[1],))print(floss {metric[0] / metric[1]:.3f}, f{metric[1] / timer.stop():.1f} tokens/sec on {str(device)})现在我们可以使用负采样来训练跳元模型。 lr, num_epochs 0.002, 5 train(net, data_iter, lr, num_epochs)应用词嵌入 在训练word2vec模型之后我们可以使用训练好模型中词向量的余弦相似度来从词表中找到与输入单词语义最相似的单词。 def get_similar_tokens(query_token, k, embed):W embed.weight.datax W[vocab[query_token]]# 计算余弦相似性。增加1e-9以获得数值稳定性cos torch.mv(W, x) / torch.sqrt(torch.sum(W * W, dim1) *torch.sum(x * x) 1e-9)topk torch.topk(cos, kk1)[1].cpu().numpy().astype(int32)for i in topk[1:]: # 删除输入词print(fcosine sim{float(cos[i]):.3f}: {vocab.to_tokens(i)})get_similar_tokens(chip, 3, net[0])
http://www.w-s-a.com/news/374328/

相关文章:

  • app 与网站网站建设要做什么
  • 厦门国外网站建设公司郑州核酸点推vip服务
  • 免费网线seo外链怎么做
  • 宽带技术网网站wordpress widget hook
  • 山西省住房和城乡建设厅网站报名wordpress添加标签插件
  • 网站怎么自己做外贸网站案例
  • 做网站的优势公司网站怎么做站外链接
  • 海城网站制作建设精准营销的营销方式
  • 北京短视频拍摄公司重庆网站seo推广公司
  • 广州免费推广网站建设4399网页游戏大全
  • 网站的构架与组成建站公司兴田德润
  • php网站部署步骤邯郸哪有做网站的
  • 做设计什么设计比较好的网站南充市住房和城乡建设局考试网站
  • 郑州做系统集成的公司网站龙岩
  • 厦门SEO_厦门网站建设网络营销课程视频
  • vs 2015 网站开发开网店在线咨询
  • 前端如何优化网站性能大学学校类网站设计
  • 中国铁路建设投资公司网站熊学军中国it外包公司排名前50
  • 房产网站的建设广州推广排名
  • 湟源县网站建设wordpress删除未分类
  • 营销型网站开发推广厦门百度seo公司
  • 遵义网站开发培训上海中高风险地区名单最新
  • 禹州市门户网站建设做网站可以申请个体户么
  • 大良营销网站建设效果彩票网站搭建 做网站
  • 做网站的公司为什么人少了在中国如何推广外贸平台
  • 盘锦网站制作工业电商网站怎么配色
  • 白云企业网站建设seo排名点击软件
  • wordpress跨站脚本攻击漏洞国外注册的域名国内能用吗
  • 西部数码网站管理助手2工信部资质查询网站
  • 公司网站哪个建的好吉林网站制作