ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI for Beginners:用自定义数据集重跑嵌入(Embeddings)实验——PyTorch 与 TensorFlow 双框架实战指南

AI for Beginners:用自定义数据集重跑嵌入(Embeddings)实验——PyTorch 与 TensorFlow 双框架实战指南 教程人工智能机器学习深度学习【免费下载链接】AI-For-Beginners12 Weeks, 24 Lessons, AI for All!项目地址https://gitcode.com/GitHub_Trending/ai/AI-For-Beginners点击查看免费下载在 AI-For-Beginners 课程的《词嵌入Embeddings》单元中你将从高维稀疏的词袋BoW表示转向低维稠密的嵌入表示并亲手构建嵌入层 聚合层 线性分类器的文本分类网络。本指南以课程附带的 PyTorch Notebook 与 TensorFlow Notebook 为蓝本完整复现从数据加载、词表构建、变长序列处理到 Word2Vec 预训练嵌入接入的完整流程并给出使用你自己的数据集例如 Kaggle 上的歌词、评论、新闻语料重跑实验的改造要点与踩坑提示。实验目标与数据集选型作业要求你使用本课程相关的 NotebookPyTorch 或 TensorFlow 版本改用你自己的数据集重跑并重写 Notebook 突出自己的发现。这意味着你要完成的不是一次简单的复制粘贴而是一次完整的数据替换 结果复述工程选择新数据集优先选择带有类别标签的文本数据集例如 Kaggle 上的 Beatles lyrics披头士歌词 这类歌词语料或新闻、评论、电影剧本等数据使用时要注明出处attribution重跑 Notebook把课程示例中的 AG_NEWS 新闻数据集替换为你自己的数据走完加载数据 → 构建词表 → 编码与填充 → 训练嵌入分类器 → 尝试语义嵌入的完整链路记录发现用你自己的数据记录词表规模、缺失词比例、训练收敛曲线、分类准确率等观察结果形成可复现的实验报告。课程单元 READMElessons/5-NLP/14-Embeddings/README.md明确将本单元定位为从 BoW/TF-IDF 的高维稀疏向量出发理解**嵌入embedding**如何用低维稠密向量表达词义并最终过渡到语义嵌入Word2Vec与上下文嵌入。因此实验笔记应当同时覆盖自己训练嵌入层与使用预训练嵌入两条路线。一、为什么需要嵌入从词袋到嵌入袋在课程的文本分类实验中BoW 模型将每篇文本编码为长度为vocab_size的稀疏 one-hot 向量这个做法有两个明显缺陷见 EmbeddingsPyTorch.ipynb 开篇说明内存不友好词表通常有数万甚至数十万词每个样本都要携带长度为词表大小的稀疏向量无语义关联one-hot 编码把每个词视作相互独立king与queen、car与automobile之间的距离与其他任意两个词完全一致。嵌入层Embedding layer则把每个词的整数编号直接映射为一个指定维度的稠密向量。从实现上看它与Linear/Dense层非常相似差别在于它接收的是词编号而不是 one-hot 向量从而避免了构造巨大的稀疏向量。将嵌入层作为分类网络的第一层后词袋模型就升级为**嵌入袋embedding bag**模型先为文本中的每个词查表得到对应的嵌入向量再对所有词向量执行某个聚合函数sum、average或max最后把聚合结果交给线性分类器。下图展示了词嵌入 → 聚合 → 线性分类的完整分类器结构说明本单元训练出的嵌入层主要目的是降低维度并服务分类任务嵌入向量之间并不保证具有语义相近性要让相似词向量相近需要后续的 Word2Vec 等语义嵌入预训练见第三节。二、跑通基线用自己的数据构建嵌入分类器2.1 PyTorch 路线课程 PyTorch Notebook 使用torchtext加载 AG_NEWS 新闻数据集并依赖辅助模块 torchnlp.py 提供数据加载、编码与训练函数。当你替换为自定义数据集时需要理解并复用这几个关键函数。1数据加载与词表构建import torch import torchtext import collections # 替换为你的数据加载逻辑每条样本是 (label, text) 的元组列表 train_dataset, test_dataset, classes, vocab load_dataset() vocab_size len(vocab) print(Vocab size , vocab_size)load_dataset定义于 torchnlp.py内部通过torchtext.data.utils.get_tokenizer(basic_english)做分词并用collections.Counter统计词频、以torchtext.vocab.vocab(counter, min_freqmin_freq)构建词表def load_dataset(ngrams1, min_freq1): global vocab, tokenizer train_dataset, test_dataset torchtext.datasets.AG_NEWS(root./data) train_dataset list(train_dataset) test_dataset list(test_dataset) classes [World, Sports, Business, Sci/Tech] counter collections.Counter() for (label, line) in train_dataset: counter.update(torchtext.data.utils.ngrams_iterator(tokenizer(line), ngramsngrams)) vocab torchtext.vocab.vocab(counter, min_freqmin_freq) return train_dataset, test_dataset, classes, vocab两个值得注意的参数min_freq控制词表的最小词频阈值调大可以显著压缩词表大小ngrams是否引入 n-gram 词条默认 1即纯词级。在课程原实验中AG_NEWS 训练集构建出的词表规模约为95812 词。换成你自己的语料后词表规模往往与数据量、分词方式和min_freq直接相关——这正是你可以在实验报告中记录的第一个观察点。2编码函数encode函数torchnlp.py把一段文本分词后映射为词编号序列def encode(x, vocNone, unk0, tokenizertokenizer): ... return [stoi.get(s, unk) for s in tokenizer(x)]它通过stoistring-to-index字典完成映射查不到的词返回unk0PAD/UNK 槽位。注意它同时兼容torchtext.vocab.vocab带get_stoi()方法和 GloVe 对象带stoi属性两种词表对象这为后续接入预训练词表做了铺垫。3定义嵌入分类器class EmbedClassifier(torch.nn.Module): def __init__(self, vocab_size, embed_dim, num_class): super().__init__() self.embedding torch.nn.Embedding(vocab_size, embed_dim) self.fc torch.nn.Linear(embed_dim, num_class) def forward(self, x): x self.embedding(x) x torch.mean(x, dim1) # 聚合对序列维度取平均 return self.fc(x)模型结构一目了然Embedding(vocab_size, embed_dim)查表得到每个词的向量torch.mean(x, dim1)沿序列维度做平均聚合Linear(embed_dim, num_class)输出分类 logits。在课程实验中embed_dim32、类别数num_class4训练 2.5 万条记录不到一个 epoch即可在验证集上逼近 76% 的准确率README 中提示若训练完整 epoch 并调整学习率准确率可以达到约90%的水平。4处理变长序列padding 方案嵌入层的输入是词编号序列而每条样本的序列长度不同无法直接拼成矩形的 mini-batch。PyTorch 路线给出的第一个方案是通过collate_fn把批内序列统一填充到批内最大长度def padify(b): # b 是长度为 batch_size 的元组列表(label, text) v [encode(x[1]) for x in b] l max(map(len, v)) # 批内最长序列 return ( torch.LongTensor([t[0] - 1 for t in b]), torch.stack([torch.nn.functional.pad(torch.tensor(t), (0, l - len(t)), modeconstant, value0) for t in v]) ) train_loader torch.utils.data.DataLoader(train_dataset, batch_size16, collate_fnpadify, shuffleTrue)5训练训练循环复用 torchnlp.py 中的train_epochnet EmbedClassifier(vocab_size, 32, len(classes)).to(device) train_epoch(net, train_loader, lr1, epoch_size25000)课程运行结果给出了一条清晰的收敛曲线每 3200 条记录打印一次累计准确率从 64.2% 起步逐步上升到 75.7%loss 收敛到约 0.89。换用自己的数据集后这条曲线的形状、收敛速度与最终准确率就是你的核心发现之一。2.2 TensorFlow / Keras 路线TensorFlow Notebook 使用tensorflow_datasets加载ag_news_subset并用keras.layers.experimental.preprocessing.TextVectorization完成分词与向量化。模型由四个部分串联而成vocab_size 30000 batch_size 128 vectorizer keras.layers.experimental.preprocessing.TextVectorization(max_tokensvocab_size, input_shape(1,)) model keras.models.Sequential([ vectorizer, # 文本 → 词编号张量 keras.layers.Embedding(vocab_size, 100), # 词编号 → 100 维稠密向量 keras.layers.Lambda(lambda x: tf.reduce_mean(x, axis1)), # 聚合沿序列轴取平均 keras.layers.Dense(4, activationsoftmax) # 线性分类 ]) model.summary()model.summary()显示该模型参数量约3,000,404其中绝大部分来自Embedding(30000, 100)的 300 万参数。数据侧同样需要把 (title, description) 拼成文本、再映射为 (text, label) 元组def extract_text(x): return x[title] x[description] def tupelize(x): return (extract_text(x), x[label]) print(Training vectorizer) vectorizer.adapt(ds_train.take(500).map(extract_text)) # 用 500 条子集构建词表 model.compile(losssparse_categorical_crossentropy, metrics[acc]) model.fit(ds_train.map(tupelize).batch(batch_size), validation_datads_test.map(tupelize).batch(batch_size))原实验在一轮训练后在验证集上达到约 86.4% 的准确率。两处值得注意的实践细节vectorizer.adapt(ds_train.take(500))只用 500 条数据估计词表这是为了加速代价是词表外的词会被忽略可能略微拉低准确率TextVectorization遇到不同长度序列时会自动用 PAD token编号 0补齐成矩形张量——例如vectorizer([Hello, world!,I am glad to meet you!])会输出 shape 为(2, 6)的张量第二句话有 6 个 token第一句补 4 个 0。若要替换为自定义数据集只需改写extract_text/tupelize或直接构造(text, label)的tf.data.Dataset并删除vectorizer.adapt中对ds_train的强依赖即可。三、变长序列的第二种表示EmbeddingBag 与 offset 向量padding 方案简单直观但并非最省内存。PyTorch Notebook 随后给出了第二种方案offset 向量表示。把所有样本的词编号拼接成一个大的内容向量同时用 offset 向量记录每个样本序列的起始位置从而完全避免填充。图中Offset vector为[0, 5, 10]Content vector存放HELLO, THERE的全部 token借助偏移值可以切出Sequence1区间 0–5与Sequence2区间 5–10。课程 Notebook 特别注明图中以字符序列示意实际实验中我们处理的是词序列但偏移表示的原理完全相同。对应实现使用 PyTorch 的EmbeddingBag层——它内部同时完成查表 聚合且支持mean、sum、max三种聚合模式class EmbedClassifier(torch.nn.Module): def __init__(self, vocab_size, embed_dim, num_class): super().__init__() self.embedding torch.nn.EmbeddingBag(vocab_size, embed_dim) self.fc torch.nn.Linear(embed_dim, num_class) def forward(self, text, off): x self.embedding(text, off) return self.fc(x)配套的offsetify函数负责构造 offset 向量EmbeddingsPyTorch.ipynb 与 torchnlp.py 中均有实现def offsetify(b): x [torch.tensor(encode(t[1])) for t in b] # 各序列的词编号 o [0] [len(t) for t in x] o torch.tensor(o[:-1]).cumsum(dim0) # 累加得到每个序列的起始偏移 return ( torch.LongTensor([t[0] - 1 for t in b]), # 标签 torch.cat(x), # 拼接后的内容向量 o # 偏移向量 )由于模型和 DataLoader 现在同时返回文本与偏移两个特征训练循环也需要相应调整见 torchnlp.py 的train_epoch_embnet(text, off)接收两个输入并对labels, text, off三路数据分别.to(device)。使用EmbeddingBag的变体在课程实验中同样能收敛到约 75.5% 的准确率。实践提示更换自定义数据集时如果文本很短且长度差异不大padding 方案足够若序列长度差异悬殊如歌词 vs 长评论offset EmbeddingBag方案在内存与计算上都更划算也更能体现课程强调的高效变长序列表示。四、语义嵌入Word2Vec 与预训练向量的接入4.1 Word2Vec 的两种架构上一节的嵌入层只是把词映射到稠密向量向量之间并无语义关联。要获得相似词 → 相近向量按欧氏距离等度量的性质需要在大规模语料上以特定方式预训练其中最经典的就是Word2Vec它包含两种架构连续词袋CBoW给定 n-gram $(W_{-2}, W_{-1}, W_0, W_1, W_2)$用上下文 $(W_{-2}, W_{-1}, W_1, W_2)$ 预测中心词 $W_0$连续跳元Skip-gram与 CBoW 相反用中心词 $W_0$ 预测其周围窗口内的上下文词。两种架构的对比如下图CBoW 更快skip-gram 更慢但对低频词表示得更好——这是选择预训练模型时的实用准则。4.2 用 gensim 玩转预训练 Word2Vec两个 Notebook 都使用gensim加载在 Google News 语料上预训练的word2vec-google-news-300300 维import gensim.downloader as api w2v api.load(word2vec-google-news-300)首次加载需要下载数 GB 的模型文件务必预留时间与磁盘空间。加载后可做三类经典操作1近义词检索——查与neural最相似的词for w, p in w2v.most_similar(neural): print(f{w} - {p})课程输出显示neuronal - 0.7805、neurons - 0.7327、neural_circuits - 0.7253等结果直观体现了嵌入向量的语义聚类。2提取词向量w2v.word_vec(play)[:20] # 300 维向量这里只打印前 20 维3向量算术——经典关系推理king − man woman ≈ queenw2v.most_similar(positive[king, woman], negative[man])[0] # 输出 (queen, 0.7118192911148071)Notebook 还揭示了背后的原始向量运算逻辑先计算qvec w2v[king] - 1.7*w2v[man] 1.7*w2v[woman]再在全词表中找到与qvec欧氏距离最近的词。注意课程实验为让结果成立而对man/woman向量加了系数换用你自己的数据做这类演示时同样可能需要微调系数。4.3 把预训练嵌入接回分类器PyTorch接入预训练嵌入的关键难点在于词表不一致Word2Vec/GloVe 的词表与你的语料词表几乎不可能重合。PyTorch Notebook 展示了两种解法方案 A保留自建词表缺词随机初始化embed_size len(w2v.get_vector(hello)) print(fEmbedding size: {embed_size}) net EmbedClassifier(vocab_size, embed_size, len(classes)) print(Populating matrix, this will take some time..., end) found, not_found 0, 0 for i, w in enumerate(vocab.get_itos()): try: net.embedding.weight[i].data torch.tensor(w2v.get_vector(w)) found 1 except: net.embedding.weight[i].data torch.normal(0.0, 1.0, (embed_size,)) # 缺词用标准正态随机初始化 not_found 1 print(fDone, found {found} words, {not_found} words missing) net net.to(device)课程实验在 AG_NEWS 上找到 41080 个词、缺失 54732 个词——缺失词比例高达一半以上这也是最终准确率没有显著提升的主因。由于嵌入维度从 32 升到 300参数量激增训练更慢且更易过拟合需要更多训练数据。方案 B改用 GloVe 词表重建语料torchtext内置了 GloVe 向量可直接加载为词表对象vocab torchtext.vocab.GloVe(name6B, dim50)该词表对象提供三个核心接口vocab.stoi词 → 索引vocab.itos索引 → 词vocab.vectors全部嵌入向量矩阵取词s的向量用vocab.vectors[vocab.stoi[s]]。用它验证向量算术kind − man woman ≈ queenqvec vocab.vectors[vocab.stoi[king]] - vocab.vectors[vocab.stoi[man]] 1.3*vocab.vectors[vocab.stoi[woman]] d torch.sum((vocab.vectors - qvec)**2, dim1) min_idx torch.argmin(d) vocab.itos[min_idx] # 输出 queen随后只需让encode使用 GloVe 词表编码语料并把嵌入权重直接拷贝到网络net EmbedClassifier(len(vocab), len(vocab.vectors[0]), len(classes)) net.embedding.weight.data vocab.vectors net net.to(device)方案 B 的关键代价GloVe 词表外OOV的词在编码时会被忽略映射到 PAD语料信息因此流失。课程结论指出最彻底的解决方案是在你自己的语料上重训 Word2Vec/GloVe使词表与数据完全对齐。4.4 把预训练嵌入接回分类器TensorFlow / KerasTensorFlow Notebook 同样演示了两条路线。路线 A使用 tokenizer 词表构建权重矩阵embed_size len(w2v.get_vector(hello)) vocab vectorizer.get_vocabulary() W np.zeros((vocab_size, embed_size)) found, not_found 0, 0 for i, w in enumerate(vocab): try: W[i] w2v.get_vector(w) found 1 except: not_found 1 emb keras.layers.Embedding(vocab_size, embed_size, weights[W], trainableFalse) model keras.models.Sequential([ vectorizer, emb, keras.layers.Lambda(lambda x: tf.reduce_mean(x, axis1)), keras.layers.Dense(4, activationsoftmax) ])课程实验在 30000 词表中找到 4551 词、缺失 784 词。注意trainableFalse表示冻结嵌入层不做微调——这会略微降低准确率但显著加快训练。路线 B直接采用 Word2Vec 词表vocab list(w2v.vocab.keys()) vectorizer keras.layers.experimental.preprocessing.TextVectorization(input_shape(1,)) vectorizer.set_vocabulary(vocab) model keras.models.Sequential([ vectorizer, w2v.get_keras_embedding(train_embeddingsFalse), # gensim 自动生成 Keras Embedding 层 keras.layers.Lambda(lambda x: tf.reduce_mean(x, axis1)), keras.layers.Dense(4, activationsoftmax) ]) model.compile(losssparse_categorical_crossentropy, metrics[acc]) model.fit(ds_train.map(tupelize).batch(128), validation_datads_test.map(tupelize).batch(128), epochs5)get_keras_embedding(train_embeddingsFalse)是 gensim 提供的便捷方法自动创建对应词表的 Keras 嵌入层。课程实验运行 5 个 epoch 后验证准确率约 61%——因为大量语料词不在 Word2Vec 词表中而被忽略这正是词表错配代价的直接证据。五、从静态嵌入到上下文嵌入课程还指出静态预训练嵌入Word2Vec/GloVe的一个根本局限无法区分一词多义词义消歧。例如I went to aplayat the theatre.名词戏剧John wants toplaywith his friends.动词玩耍两种语境下的play共享同一个静态向量。要解决这个问题需要基于语言模型构建上下文嵌入contextual embeddings——即根据单词所在句子动态生成向量。本单元教程不展开上下文嵌入课程将在后续语言模型单元15-LanguageModeling中详细讨论。在你自己的实验笔记中可以记录静态嵌入在 OOV 与多义词上的失败案例为理解后续 BERT 类模型的价值做铺垫。六、用自定义数据集重跑实验操作清单与发现记录综合 PyTorch 与 TensorFlow 两条路线把课程示例换成你自己的数据集时建议按以下清单操作并逐项记录发现环节PyTorch 要点TensorFlow / Keras 要点建议记录的发现数据加载替换load_dataset为你的(label, text)列表改写extract_text/tupelize或直接构造(text, label)的Dataset数据规模、类别分布、是否需要注明数据出处词表构建min_freq调优vectorizer.adapt(subset)的子集规模词表大小、低频词过滤的影响变长序列padifypadding或offsetifyEmbeddingBagTextVectorization自动 PAD 填充序列长度分布、两种方案的内存/速度差异训练嵌入分类器train_epoch/train_epoch_embmodel.fit(...)收敛曲线、最优embed_dim与学习率、最终准确率接入预训练嵌入Word2Vec 权重拷贝 / GloVe 词表重建weights[W]冻结 /get_keras_embedding词表重合率、缺失词占比、准确率变化语义验证most_similar、向量算术同上gensim 通用近义词质量、king−manwoman是否成立写作发现时注意每个结果都要绑定具体的数据集与超参数词表大小、embed_dim、学习率、训练样本数不要脱离条件谈准确率对比自训嵌入 vs 预训练嵌入时重点记录词表错配导致的 OOV 比例这正是课程反复强调的关键现象若使用 Kaggle 数据集保留数据出处标注歌词类语料还可参考课程 README 的 Challenge 部分尝试用 Word2Vec 做歌词/诗歌生成实验lessons/5-NLP/14-Embeddings/README.md。总结本单元的核心技术链条可以概括为稀疏 one-hot 词袋 → 低维稠密嵌入 → 嵌入袋聚合分类 → Word2Vec 语义嵌入 → 上下文嵌入。通过 EmbeddingsPyTorch.ipynb 与 EmbeddingsTF.ipynb 两个 Notebook你可以在 PyTorch 与 TensorFlow 两个框架下完整复现这一链条。用自己的数据集重跑时最值得深挖的三个主题分别是变长序列的两种高效表示padding 与 offset、预训练嵌入接入时的词表错配问题、以及静态嵌入在多义词上的局限——把这些观察写进你的实验笔记就完成了课程作业的核心要求。赞分享教程人工智能机器学习深度学习【免费下载链接】AI-For-Beginners12 Weeks, 24 Lessons, AI for All!项目地址https://gitcode.com/GitHub_Trending/ai/AI-For-Beginners点击查看免费下载相关推荐AI-For-Beginners 神经网络框架实战TensorFlow/Keras 与 PyTorch 双栈入门及过拟合防治AI For Beginners 神经网络框架实战TensorFlow/Keras 与 PyTorch 双栈入门及过拟合防治 本指南基于 AI For Beg教程人工智能机器学习深度学习AI-For-Beginners 文本表示实验用自有数据集重跑 Text Representation Notebook 的完整指南AI For Beginners 文本表示实验用自有数据集重跑 Text Representation Notebook 的完整指南 导读 本指南围绕 AI教程人工智能机器学习深度学习RapidOCR 处理竖排古籍从一张扫描件到可检索文本的完整走法RapidOCR 处理竖排古籍从一张扫描件到可检索文本的完整走法 我手上有一批民国线装书要数字化竖排、繁体、纸张泛黄还盖着朱印。先丢给两个通用 OCR 工人工智能计算机视觉OCR上一篇OpenArk 快速上手Windows 内核分析新手指南下一篇Sketch MeaXure重构设计交付流程的智能标注解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表