赞
踩
虽然 one-hot 编码允许我们保留结构信息,但它确实存在两个主要缺点。
在这个笔记本中,我们将激发对嵌入的需求以及它们如何解决 one-hot 编码的所有缺点。嵌入的主要思想是为文本中的标记提供固定长度的表示,而不考虑词汇表中标记的数量。使用 one-hot 编码,每个标记都由一个大小为 的数组表示vocab_size
,但使用嵌入,每个标记现在都具有形状embed_dim
。表示中的值不是固定的二进制值,而是通过改变浮点数来实现细粒度的学习表示。
我们可以通过在 PyTorch 中创建模型来学习嵌入,但首先,我们将使用一个专门研究嵌入和主题建模的库,称为Gensim。
- import nltk
- nltk.download("punkt");
- import numpy as np
- import re
- import urllib
- [nltk_data] 正在下载包 punkt 到 /root/nltk_data...
- [nltk_data] 解压缩标记器/punkt.zip。
SEED = 1234
- # Set seed for reproducibility
- np.random.seed(SEED)
- # Split text into sentences
- tokenizer = nltk.data.load("tokenizers/punkt/english.pickle")
- book = urllib.request.urlopen(url="https://raw.githubusercontent.com/GokuMohandas/Made-With-ML/main/datasets/harrypotter.txt")
- sentences = tokenizer.tokenize(str(book.read()))
- print (f"{len(sentences)} sentences")
- def preprocess(text):
- """Conditional preprocessing on our text."""
- # Lower
- text = text.lower()
-
- # Spacing and filters
- text = re.sub(r"([-;;.,!?<=>])", r" \1 ", text)
- text = re.sub("[^A-Za-z0-9]+", " ", text) # remove non alphanumeric chars
- text = re.sub(" +", " ", text) # remove multiple spaces
- text = text.strip()
-
- # Separate into word tokens
- text = text.split(" ")
-
- return text
'运行
- # Preprocess sentences
- print (sentences[11])
- sentences = [preprocess(sentence) for sentence in sentences]
- print (sentences[11])
- Snape nodded, but did not elaborate.
- ['snape', 'nodded', 'but', 'did', 'not', 'elaborate']
但是我们首先如何学习嵌入呢?嵌入背后的直觉是令牌的定义不取决于令牌本身,而是取决于其上下文。有几种不同的方法可以做到这一点:
所有这些方法都涉及创建数据来训练我们的模型。句子中的每个词都成为目标词,上下文词由窗口确定。在下图中(skip-gram),窗口大小为 2(目标词左右各 2 个词)。我们对语料库中的每个句子都重复此操作,这会产生我们用于无监督任务的训练数据。这是一种无监督学习技术,因为我们没有官方的上下文标签。这个想法是相似的目标词将出现在相似的上下文中,我们可以通过使用(上下文,目标)对重复训练我们的模式来学习这种关系。
我们可以使用上述任何一种方法来学习嵌入,其中一些方法比其他方法效果更好。您可以检查学习的嵌入,但选择方法的最佳方法是凭经验验证监督任务的性能。
当我们有大量词汇来学习嵌入时,事情会很快变得复杂。回想一下,使用 softmax 的反向传播会更新正确和不正确的类权重。对于我们所做的每一次反向传递,这都会成为一个巨大的计算,因此一种解决方法是使用负采样,它只更新正确的类和一些任意不正确的类(NEGATIVE_SAMPLING
=20)。我们之所以能够做到这一点,是因为我们会在大量的训练数据中多次看到与目标类相同的词。
- import gensim
- from gensim.models import KeyedVectors
- from gensim.models import Word2Vec
- EMBEDDING_DIM = 100
- WINDOW = 5
- MIN_COUNT = 3 # Ignores all words with total frequency lower than this
- SKIP_GRAM = 1 # 0 = CBOW
- NEGATIVE_SAMPLING = 20
- # Super fast because of optimized C code under the hood
- w2v = Word2Vec(
- sentences=sentences, size=EMBEDDING_DIM,
- window=WINDOW, min_count=MIN_COUNT,
- sg=SKIP_GRAM, negative=NEGATIVE_SAMPLING)
- print (w2v)
Word2Vec(vocab=4937, size=100, alpha=0.025)
- # Vector for each word
- w2v.wv.get_vector("potter")
- array([-0.11787166, -0.2702948 , 0.24332453, 0.07497228, -0.5299148 ,
- 0.17751476, -0.30183575, 0.17060578, -0.0342238 , -0.331856 ,
- -0.06467848, 0.02454215, 0.4524056 , -0.18918884, -0.22446074,
- 0.04246538, 0.5784022 , 0.12316586, 0.03419832, 0.12895502,
- -0.36260423, 0.06671549, -0.28563526, -0.06784113, -0.0838319 ,
- 0.16225453, 0.24313857, 0.04139925, 0.06982274, 0.59947336,
- 0.14201492, -0.00841052, -0.14700615, -0.51149386, -0.20590985,
- 0.00435914, 0.04931103, 0.3382509 , -0.06798466, 0.23954925,
- -0.07505646, -0.50945646, -0.44729665, 0.16253233, 0.11114362,
- 0.05604156, 0.26727834, 0.43738437, -0.2606872 , 0.16259147,
- -0.28841105, -0.02349186, 0.00743417, 0.08558545, -0.0844396 ,
- -0.44747537, -0.30635086, -0.04186366, 0.11142804, 0.03187608,
- 0.38674814, -0.2663519 , 0.35415238, 0.094676 , -0.13586426,
- -0.35296437, -0.31428036, -0.02917303, 0.02518964, -0.59744245,
- -0.11500382, 0.15761602, 0.30535367, -0.06207089, 0.21460988,
- 0.17566076, 0.46426776, 0.15573359, 0.3675553 , -0.09043553,
- 0.2774392 , 0.16967005, 0.32909656, 0.01422888, 0.4131812 ,
- 0.20034142, 0.13722987, 0.10324971, 0.14308734, 0.23772323,
- 0.2513108 , 0.23396717, -0.10305202, -0.03343603, 0.14360961,
- -0.01891198, 0.11430877, 0.30017182, -0.09570111, -0.10692801],
- dtype=float32)
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- # Get nearest neighbors (excluding itself)
- w2v.wv.most_similar(positive="scar", topn=5)
- [('pain', 0.9274871349334717),
- ('forehead', 0.9020695686340332),
- ('heart', 0.8953317999839783),
- ('mouth', 0.8939940929412842),
- ('throat', 0.8922691345214844)]
- # Saving and loading
- w2v.wv.save_word2vec_format("model.bin", binary=True)
- w2v = KeyedVectors.load_word2vec_format("model.bin", binary=True)
当我们的词汇表中不存在一个单词时会发生什么?我们可以分配一个用于所有 OOV(词汇表外)单词的 UNK 标记,或者我们可以使用FastText,它使用字符级 n-gram 来嵌入单词。这有助于嵌入稀有词、拼写错误的词,以及我们的语料库中不存在但与我们的语料库中的词相似的词。
from gensim.models import FastText
-
- # Super fast because of optimized C code under the hood
- ft = FastText(sentences=sentences, size=EMBEDDING_DIM,
- window=WINDOW, min_count=MIN_COUNT,
- sg=SKIP_GRAM, negative=NEGATIVE_SAMPLING)
- print (ft)
FastText(vocab=4937, size=100, alpha=0.025)
- # This word doesn't exist so the word2vec model will error out
- w2v.wv.most_similar(positive="scarring", topn=5)
- # FastText will use n-grams to embed an OOV word
- ft.wv.most_similar(positive="scarring", topn=5)
- [('sparkling', 0.9785991907119751),
- ('coiling', 0.9770463705062866),
- ('watering', 0.9759057760238647),
- ('glittering', 0.9756022095680237),
- ('dazzling', 0.9755154848098755)]
- # Save and loading
- ft.wv.save("model.bin")
- ft = KeyedVectors.load("model.bin")
我们可以使用上述方法之一从头开始学习嵌入,但我们也可以利用已在数百万个文档上训练的预训练嵌入。流行的包括Word2Vec (skip-gram) 或GloVe (global word-word co-occurrence)。我们可以通过确认这些嵌入来验证它们是否捕获了有意义的语义关系。
-
- from gensim.scripts.glove2word2vec import glove2word2vec
- from io import BytesIO
- import matplotlib.pyplot as plt
- from sklearn.decomposition import PCA
- from urllib.request import urlopen
- from zipfile import ZipFile
-
- # Arguments
- EMBEDDING_DIM = 100
- def plot_embeddings(words, embeddings, pca_results):
- for word in words:
- index = embeddings.index2word.index(word)
- plt.scatter(pca_results[index, 0], pca_results[index, 1])
- plt.annotate(word, xy=(pca_results[index, 0], pca_results[index, 1]))
- plt.show()
-
- # Unzip the file (may take ~3-5 minutes)
- resp = urlopen("http://nlp.stanford.edu/data/glove.6B.zip")
- zipfile = ZipFile(BytesIO(resp.read()))
- zipfile.namelist()
- ['glove.6B.50d.txt',
- 'glove.6B.100d.txt',
- 'glove.6B.200d.txt',
- 'glove.6B.300d.txt']
-
- # Write embeddings to file
- embeddings_file = "glove.6B.{0}d.txt".format(EMBEDDING_DIM)
- zipfile.extract(embeddings_file)
/content/glove.6B.100d.txt
- # Preview of the GloVe embeddings file
- with open(embeddings_file, "r") as fp:
- line = next(fp)
- values = line.split()
- word = values[0]
- embedding = np.asarray(values[1:], dtype='float32')
- print (f"word: {word}")
- print (f"embedding:\n{embedding}")
- print (f"embedding dim: {len(embedding)}")
- word: the
- embedding:
- [-0.038194 -0.24487 0.72812 -0.39961 0.083172 0.043953 -0.39141 0.3344 -0.57545 0.087459 0.28787 -0.06731 0.30906 -0.26384
- -0.13231 -0.20757 0.33395 -0.33848 -0.31743 -0.48336
- 0.1464 -0.37304 0.34577 0.052041
- 0.44946 -0.46971 0.02628 -0.54155
- - 0.15518 -0.14107 -0.039722 0.28277 0.14393 0.23464 -0.31021 0.086173 0.20397 0.52624 0.17164 -0.082378 -0.71787 -0.41531 0.20335 -0.12763
- 0.41367 0.55187 0.57908 -0.33477 -0.36559 -0.54857 -0.062892 0.26584
- 0.30205 0.99775 -0.80481 -3.0243
- 0.01254 -0.36942 2.2167
- 0.72201 -0.24978 0.92136 0.034514
- 0.46745 1.1079 -0.19358 -0.074575 0.23353 -0.052062 -0.22044 0.057162 -0.15806 -0.30798 -0.41625 0.37972 0.15006 -0.53212 -0.2055 -1.2526
- 0.071624 0.70565 0.49744 -0.42063 0.26148 -1.538
- -0.30223 -0.073438 -0.28312 0.37104
- -0.25217 0.016215 -0.017099
- -0.38984 0.87424 - 0.72569 -0.51058 -0.52028 -0.1459
- 0.8278 0.27062 ]
- 嵌入暗度:100
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- # Save GloVe embeddings to local directory in word2vec format
- word2vec_output_file = "{0}.word2vec".format(embeddings_file)
- glove2word2vec(embeddings_file, word2vec_output_file)
(400000, 100)
- # Load embeddings (may take a minute)
- glove = KeyedVectors.load_word2vec_format(word2vec_output_file, binary=False)
- # (king - man) + woman = ?
- # king - man = ? - woman
- glove.most_similar(positive=["woman", "king"], negative=["man"], topn=5)
- [('王后', 0.7698541283607483),
- ('君主', 0.6843380928039551),
- ('王位', 0.6755735874176025),
- ('女儿', 0.6594556570053101),
- ('公主', 0.6532054]43
-
- # Get nearest neighbors (excluding itself)
- glove.wv.most_similar(positive="goku", topn=5)
- [('
- gohan', 0.7246542572975159), ('bulma', 0.6497020125389099),
- ('raistlin', 0.6443604230880737),
- ('skaar', 0.6316742897033691),
- ('guybrush', 0.6239)
-
- # Reduce dimensionality for plotting
- X = glove[glove.wv.vocab]
- pca = PCA(n_components=2)
- pca_results = pca.fit_transform(X)
- # Visualize
- plot_embeddings(
- words=["king", "queen", "man", "woman"], embeddings=glove,
- pca_results=pca_results)
- # Bias in embeddings
- glove.most_similar(positive=["woman", "doctor"], negative=["man"],topn=5)
- [('护士', 0.7735227346420288),
- ('医生', 0.7189429998397827),
- ('医生', 0.6824328303337097),
- ('病人', 0.6750682592391968),
- ('牙医', 0.65520)]
让我们为我们的主要任务设置种子和设备。
1 2 3 4 5 |
|
1 |
|
1 2 3 4 5 6 7 |
|
1 2 |
|
1 2 3 4 5 6 7 8 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">不同的
- </span></span>
我们将下载AG News 数据集Business
,该数据集包含来自 4 个独特类别( 、Sci/Tech
、Sports
、World
) 的 120K 文本样本
1 2 3 4 5 |
|
标题 | 类别 | |
---|---|---|
0 | 沙龙接受减少加沙军队行动的计划...... | 世界 |
1 | 野生动物犯罪斗争中的互联网关键战场 | 科技 |
2 | 7 月耐用品订单增长 1.7% | 商业 |
3 | 华尔街放缓的迹象越来越多 | 商业 |
4 | 真人秀的新面孔 | 世界 |
我们将首先通过执行诸如下部文本、删除停止(填充)词、使用正则表达式的过滤器等操作来清理我们的输入数据。
1 2 3 4 |
|
1 2 3 4 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">[nltk_data] 正在下载包停用词到 /root/nltk_data...
- [nltk_data] 包停用词已经是最新的!
- ['我','我','我的','我自己','我们']
- </span></span>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
1 2 3 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">纽约证券交易所伟大的一周
- </span></span>
1 2 3 4 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">沙龙接受减少加沙军队行动的计划,国土报说
-
- 沙龙接受减少加沙军队行动的计划 国土报说
- </span></span>
警告
如果您有计算标准化等预处理步骤,则需要先分离训练集和测试集,然后再应用这些操作。这是因为我们不能在预处理/训练期间意外应用从测试集获得的任何知识(数据泄漏)。然而,对于像上面的函数这样的全局预处理步骤,我们没有从数据本身学习任何东西,我们可以在拆分数据之前执行。
1 2 |
|
1 2 3 |
|
1 2 3 4 5 |
|
1 2 3 |
|
1 2 3 4 5 6 7 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">X_train: (84000,), y_train: (84000,)
- X_val: (18000,), y_val: (18000,)
- X_test: (18000,), y_test: (18000,)
- 样本点:中国与朝鲜核谈判→世界
- </span></span>
接下来,我们将定义 aLabelEncoder
将我们的文本标签编码为唯一索引
1 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
|
1 2 3 4 5 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">{“商业”:0,“科技”:1,“体育”:2,“世界”:3}
- </span></span>
1 2 3 4 5 6 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">y_train[0]:世界
- y_train[0]:3
- </span></span>
1 2 3 4 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">计数:[21000 21000 21000 21000]
- 权重:{0: 4.761904761904762e-05, 1: 4.761904761904762e-05, 2: 4.761904761904762e-05, 3: 4.76190476190
- </span></span>
我们将定义一个Tokenizer
将我们的文本输入数据转换为标记索引。
1 2 3 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
|
警告
重要的是,我们只适合使用我们的训练数据拆分,因为在推理过程中,我们的模型并不总是知道每个标记,因此使用我们的验证和测试拆分复制该场景也很重要。
1 2 3 4 5 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)"><Tokenizer(num_tokens=5000)>
-
- </span></span>
1 2 3 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">[('<pad>',0),('',1),('39',2),('b',3),('gt',4)]
- 至少弗雷克令牌的freq: 14
- </span></span>
1 2 3 4 5 6 7 8 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">文本到索引:(
- 预处理)→NBA包裹neal 40热量向导
- (令牌化)→[299 359 3869 1 1648 734 1 2021]
- </span></span>
我们可以使用 PyTorch 的嵌入层嵌入我们的输入。
1 2 3 4 5 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">张量([[2, 6, 5, 2, 6]])
- torch.Size([1, 5])
- </span></span>
1 2 3 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">火炬大小([10, 100])
- </span></span>
1 2 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">火炬大小([1, 5, 100])
- </span></span>
输入中的每个标记都通过嵌入表示(所有词汇表外(OOV)标记都被赋予了标记的嵌入UNK
。)在下面的模型中,我们将看到如何将这些嵌入设置为预训练的 GloVe 嵌入以及如何选择是否在训练期间冻结(固定嵌入权重)这些嵌入。
我们的输入都是不同的长度,但我们需要每个批次的形状一致。因此,我们将使用填充使批次中的所有输入具有相同的长度。我们的填充索引将为 0(请注意,这与<PAD>
我们定义的令牌一致Tokenizer
)。
虽然嵌入我们的输入标记将创建一批形状 (
N
,max_seq_len
,embed_dim
),但我们只需要提供一个 2D 矩阵 (N
,max_seq_len
) 即可在 PyTorch 中使用嵌入。
1 2 3 4 5 6 7 |
|
1 2 3 4 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">(3, 8)
- [[2.990e+02 3.590e+02 3.869e+03 1.000e+00 1.648e+03 7.340e+02 1.000e+00
- 2.021e+03]
- [4.977e+03 1.000e+00 8.070 e+02 0.000e+00 0.000e+00 0.000e+00 0.000e+00
- 0.000e+00]
- [5.900e+01 1.213e+03 1.160e+02 4.042e+03 2.040e+02 4.190e+02 1.000 e+00
- 0.000e+00]]
- </span></span>
我们将创建数据集和数据加载器,以便能够使用我们的数据拆分有效地创建批次。
1 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">数据集:
- 训练数据集:<Dataset(N=84000)>
- Val 数据集:<Dataset(N=18000)>
- 测试数据集:<Dataset(N=18000)>
- 样本点:
- X:[299 359 3869 1 1648 734 1 2021]
- 是:2
- </span></span>
1 2 3 4 5 6 7 8 9 10 11 12 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">样本批次:
- X: [64, 9]
- y: [64]
- 样本点:
- X: tensor([ 299, 359, 3869, 1, 1648, 734, 1, 2021, 0], device="cpu")
- y: 2
- </span></span>
我们将在嵌入式令牌之上使用卷积神经网络来提取有意义的空间信号。这一次,我们将使用许多过滤器宽度来充当 n-gram 特征提取器。
让我们可视化模型的前向传播。
batch_size
, max_seq_len
)。batch_size
, max_seq_len
, embedding_dim
)。filter_size
, embedding_dim
, num_filters
) 应用卷积,然后进行批量归一化。我们的过滤器充当字符级 n-gram 检测器。我们有三种不同的过滤器大小(2、3 和 4),它们将分别充当二元、三元和 4-gram 特征提取器。
1 2 |
|
1 2 3 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
|
我们将创建一些实用函数,以便能够将预训练的 GloVe 嵌入加载到我们的嵌入层中。
1 2 3 4 5 6 7 8 9 10 |
|
1 2 3 4 5 6 7 8 |
|
1 2 3 4 5 6 7 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)"><嵌入(字数=5000,暗淡=100)>
- </span></span>
我们首先必须决定是否使用预训练嵌入随机初始化的嵌入。然后,我们可以选择冻结我们的嵌入或继续使用监督数据训练它们(这可能导致过度拟合)。以下是我们将要进行的三个实验:
1 2 3 |
|
1 2 3 4 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
1 2 |
|
1 2 3 4 5 6 7 8 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)"><bound method Module.named_parameters of CNN(
- (embeddings): Embedding(5000, 100, padding_idx=0)
- (conv): ModuleList(
- (0): Conv1d(100, 50, kernel_size=(1,), stride=(1) ,))
- (1): Conv1d(100, 50, kernel_size=(2,), stride=(1,))
- (2): Conv1d(100, 50, kernel_size=(3,), stride=(1,) )
- )
- (dropout): Dropout(p=0.1, inplace=False)
- (fc1): Linear(in_features=150, out_features=100, bias=True)
- (fc2): Linear(in_features=100, out_features=4, bias=真的)
- )>
- </span></span>
1 2 3 |
|
1 2 3 4 |
|
1 2 3 4 |
|
1 2 3 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">时代:1 | train_loss:0.77038,val_loss:0.59683,lr:1.00E-03,_patience:3
- Epoch:2 | train_loss:0.49571,val_loss:0.54363,lr:1.00E-03,_patience:3
- Epoch:3 | train_loss:0.40796,val_loss:0.54551,lr:1.00E-03,_patience:2
- Epoch:4 | train_loss:0.34797,val_loss:0.57950,lr:1.00E-03,_patience:1
- 提前停止!
- </span></span>
1 2 3 |
|
1 2 3 4 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">{
- “精度”:0.8070310520771562,
- “召回”:0.7999444444444445,
- “f1”:0.8012357147662316,
- “num_samples”:18000.0
- }
- </span></span>
1 2 |
|
1 2 3 4 5 6 7 8 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)"><bound method Module.named_parameters of CNN(
- (embeddings): Embedding(5000, 100, padding_idx=0)
- (conv): ModuleList(
- (0): Conv1d(100, 50, kernel_size=(1,), stride=(1) ,))
- (1): Conv1d(100, 50, kernel_size=(2,), stride=(1,))
- (2): Conv1d(100, 50, kernel_size=(3,), stride=(1,) )
- )
- (dropout): Dropout(p=0.1, inplace=False)
- (fc1): Linear(in_features=150, out_features=100, bias=True)
- (fc2): Linear(in_features=100, out_features=4, bias=真的)
- )>
- </span></span>
1 2 3 |
|
1 2 3 4 |
|
1 2 3 4 |
|
1 2 3 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">时代:1 | train_loss:0.51510,val_loss:0.47643,lr:1.00E-03,_patience:3
- Epoch:2 | train_loss:0.44220,val_loss:0.46124,lr:1.00E-03,_patience:3
- Epoch:3 | train_loss:0.41204,val_loss:0.46231,lr:1.00E-03,_patience:2
- Epoch:4 | train_loss:0.38733,val_loss:0.46606,lr:1.00E-03,_patience:1
- 提前停止!
- </span></span>
1 2 3 |
|
1 2 3 4 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">{
- “精度”:0.8304874226557859,
- “召回”:0.8281111111111111,
- “f1”:0.828556487688813,
- “num_samples”:18000.0
- }
- </span></span>
1 2 |
|
1 2 3 4 5 6 7 8 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)"><bound method Module.named_parameters of CNN(
- (embeddings): Embedding(5000, 100, padding_idx=0)
- (conv): ModuleList(
- (0): Conv1d(100, 50, kernel_size=(1,), stride=(1) ,))
- (1): Conv1d(100, 50, kernel_size=(2,), stride=(1,))
- (2): Conv1d(100, 50, kernel_size=(3,), stride=(1,) )
- )
- (dropout): Dropout(p=0.1, inplace=False)
- (fc1): Linear(in_features=150, out_features=100, bias=True)
- (fc2): Linear(in_features=100, out_features=4, bias=真的)
- )>
- </span></span>
1 2 3 |
|
1 2 3 4 |
|
1 2 3 4 |
|
1 2 3 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">时代:1 | train_loss:0.48908,val_loss:0.44320,lr:1.00E-03,_patience:3
- Epoch:2 | train_loss:0.38986,val_loss:0.43616,lr:1.00E-03,_patience:3
- Epoch:3 | train_loss:0.34403,val_loss:0.45240,lr:1.00E-03,_patience:2
- Epoch:4 | train_loss:0.30224,val_loss:0.49063,lr:1.00E-03,_patience:1
- 提前停止!
- </span></span>
1 2 3 |
|
1 2 3 4 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">{
- “精度”:0.8297157849772082,
- “召回”:0.8263333333333334,
- “f1”:0.8266579939871359,
- “num_samples”:18000.0
- }
- </span></span>
1 2 3 4 5 6 7 8 9 |
|
1 2 3 4 5 6 7 8 |
|
1 2 3 4 5 6 7 8 9 10 11 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">CNN(
- (embeddings): Embedding(5000, 100, padding_idx=0)
- (conv): ModuleList(
- (0): Conv1d(100, 50, kernel_size=(1,), stride=(1,))
- (1): Conv1d(100, 50, kernel_size=(2,), stride=(1,))
- (2): Conv1d(100, 50, kernel_size=(3,), stride=(1,))
- )
- (dropout): Dropout (p=0.1,inplace=False)
- (fc1):线性(in_features=150,out_features=100,bias=True)
- (fc2):线性(in_features=100,out_features=4,bias=True)
- )
- </span></span>
1 2 |
|
1 2 3 4 5 6 7 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">['决赛网球锦标赛下周开始']
- </span></span>
1 2 3 4 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">['运动的']
- </span></span>
1 2 3 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">{
- “体育”:0.9999998807907104,
- “世界”:6.336378532978415e-08,
- “科技”:2.107449992294619e-09,
- “商业”:3.706519813295728e-10
- }
- </span></span>
我们经历了在卷积之前填充输入的所有麻烦,结果是与输入形状相同的输出,因此我们可以尝试获得一些可解释性。由于每个标记都映射到我们应用最大池化的卷积输出,因此我们可以看到哪个标记的输出对预测影响最大。我们首先需要从我们的模型中获取 conv 输出:
1 2 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
|
1 2 |
|
1 2 3 4 5 6 7 8 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">InterpretableCNN(
- (embeddings): Embedding(5000, 100, padding_idx=0)
- (conv): ModuleList(
- (0): Conv1d(100, 50, kernel_size=(1,), stride=(1,))
- (1): Conv1d(100, 50, kernel_size=(2,), stride=(1,))
- (2): Conv1d(100, 50, kernel_size=(3,), stride=(1,))
- )
- (dropout): Dropout (p=0.1,inplace=False)
- (fc1):线性(in_features=150,out_features=100,bias=True)
- (fc2):线性(in_features=100,out_features=4,bias=True)
- )
- </span></span>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">(3, 50, 6)
- </span></span>
1 2 3 4 |
|
一维全局最大池化将从我们num_filters
的每个中提取最高值filter_size
。我们也可以采用相同的方法来确定哪个 n-gram 最相关,但请注意在上面的热图中,许多过滤器没有太大的差异。为了缓解这种情况,本文使用阈值来确定用于可解释性的过滤器。但为了简单起见,让我们通过最大池最频繁地提取哪些令牌的过滤器输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
- <span style="background-color:#ffffff"><span style="color:var(--md-code-fg-color)">原文:
- 网球总决赛下周开始。
-
- 预处理文本:
- 网球决赛将于下周开始
-
- 最重要的 n-gram:
- [1-gram]:网球
- [2-gram]:网球锦标赛
- [3-gram]:网球决赛</span></span>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。