第7课代码 WikiGPT 中 WikiText2数据集无法载入的问题,请参考 此处
LSTM 通过引入门控机制解决了 RNN 中的梯度消 失和梯度爆炸问题,
解决改为缓解。
输出改为
词汇表: ['Kage', 'Niuzong', 'Xiaoxue', 'Mazong', 'Xiaobing', 'Teacher', 'is', 'Boss', 'Student'] 词汇到索引的字典: {'Kage': 0, 'Niuzong': 1, 'Xiaoxue': 2, 'Mazong': 3, 'Xiaobing': 4, 'Teacher': 5, 'is': 6, 'Boss': 7, 'Student': 8} 索引到词汇的字典: {0: 'Kage', 1: 'Niuzong', 2: 'Xiaoxue', 3: 'Mazong', 4: 'Xiaobing', 5: 'Teacher', 6: 'is', 7: 'Boss', 8: 'Student'} 词汇表大小: 9
print("Skip-Gram 数据样例(已编码):", [(one_hot_encoding(context, word_to_idx), word_to_idx[target]) for context, target in skipgram_data[:3]])
改为
print("Skip-Gram数据样例(已编码):", [(one_hot_encoding(target, word_to_idx), word_to_idx[context]) for context, target in skipgram_data[:3]])
输出改为
One-Hot 编码前的单词: Teacher One-Hot 编码后的向量: tensor([0., 0., 0., 0., 0., 1., 0., 0., 0.]) Skip-Gram数据样例(已编码): [(tensor([1., 0., 0., 0., 0., 0., 0., 0., 0.]), 6), (tensor([1., 0., 0., 0., 0., 0., 0., 0., 0.]), 5), (tensor([0., 0., 0., 0., 0., 0., 1., 0., 0.]), 0)]
这是因为前后编码要对齐 (P51和P53)
输出改为
词汇表: {'爸爸': 0, '我': 1, '玩具': 2, '爱': 3, '挨打': 4, '喜欢': 5, '讨厌': 6} 词汇表大小: 7
输出改为
输入批处理数据: tensor([[1, 5], [1, 3]]) 输入批处理数据对应的原始词: [['我', '喜欢'], ['我', '爱']] 目标批处理数据: tensor([2, 0]) 目标批处理数据对应的原始词: ['玩具', '爸爸']
这是因为前后编码要对齐 (P73和P74)
零基础机器学习 改成 零基础学机器学习
原文:
我们使用 PyTorch 实现了一个简单的 Word2Vec(这里是 Skip Gram)模型。模型包括输入层、隐藏层和输出层。输入层接收周围词(以 One-Hot 编码后的向量形式表示)。接下来,输入层到隐藏层的权重矩阵(记为 input_to_hidden)将这个向量转换为词嵌入,该词嵌入直接作为隐藏层的输出。隐藏层到输出层的权重矩阵(记为 hidden_to_output)将隐藏层的输出转换为一个概率分布,用于预测与周围词相关的中心词(以索引形式表示)。通过最小化预测词和实际目标词之间的分类交叉熵损失,可以学习词嵌入向量。下图展示了这个流程。
改为:
我们使用 PyTorch 实现了一个简单的 Word2Vec(这里是 Skip Gram)模型。模型包括输入层、隐藏层和输出层。输入层接收中心词(以 One-Hot 编码后的向量形式表示)。接下来,输入层到隐藏层的权重矩阵(记为 input_to_hidden)将这个向量转换为词嵌入,该词嵌入直接作为隐藏层的输出。隐藏层到输出层的权重矩阵(记为 hidden_to_output)将隐藏层的输出转换为一个概率分布,用于预测与中心词相关的周围词(以索引形式表示)。通过最小化预测词和实际目标词之间的分类交叉熵损失,可以学习词嵌入向量。下图展示了这个流程。
图 图中“前缀”改为“前后缀”。
接收前时间步 改为 接收当前时间步
数据集的维度和网络结构前后不一致,以Notebook为准
attn_weights = F.softmax(raw_weights, dim=2) # 形 状 (batch_size, seq_len1, seq_len2)
改为
attn_weights = F.softmax(scaled_weights, dim=2) # 形 状 (batch_size, seq_len1, seq_len2)
新代码(删除冗余的参数num_heads):
def combine_heads(tensor):
batch_size, num_heads, seq_len, head_dim = tensor.size()
feature_dim = num_heads * head_dim
output = tensor.transpose(1, 2).contiguous().view(batch_size, seq_len, feature_dim)
return output# 形状 : (batch_size, seq_len, feature_dim)
attn_outputs = combine_heads(attn_outputs) # 形状 (batch_size, seq_len, feature_dim)
第二个维度信息后增加一行注释线,排版整齐
#------------------------- 维度信息 --------------------------------
# enc_outputs 的维度是 [batch_size, seq_len, embedding_dim]
# attn_weights 的维度是 [batch_size, n_heads, seq_len, seq_len]
# 将多头自注意力 outputs 输入位置前馈神经网络层
增加注释线
#------------------------- 维度信息 --------------------------------
# enc_outputs 的维度是 [batch_size, seq_len, embedding_dim]
# attn_weights 的维度是 [batch_size, n_heads, seq_len, seq_len]
#-----------------------------------------------------------------
# 将多头自注意力 outputs 输入位置前馈神经网络层
“人工通用智能”,改为 “通用人工智能”, 全书都要改。 “通用人工智能”是更让人接受的翻译。
“CBOW模型通过预测一个单词的上下文来学习词向量,”单词的上下文"这里指代不明,这里应该是表示目标词,所以修改为: “CBOW模型通过预测单词上下文(周围词)的目标单词来学习词向量”
sentences = ["Kage is Teacher ","Mazong is Boss ","Niuzong is Boss ","Xiaobing is Student ","Xiaoxue is Student "] words = ''.join(sentences).split()如果每条数据最后的字不加空格,字符会黏连一起,分割错误.
解决:' '.join(sentences).split()中加个空格。
words = ''.join(sentences).split()
改为
words = ' '.join(sentences).split()
data.append((neighbor, word))
改为
data.append((word, neighbor))
每个数据包含两个张量(Tensor),前一个是输入(Input),格式是上下文词的One-Hot编码,后一个是目标(Target),格式则是目标词的索引”
改为
每个数据包含两个张量(Tensor),前一个是输入(Input),格式是中心词的One-Hot编码,后一个是要预测的目标(Target),格式是上下文词的索引”
“而在forward方法中,定义了前向传播的方式,首先将输入通过输入层到隐藏层的映射生成隐藏层,然后将隐藏层通过隐藏层到输出层的映射生成输出。”
修改为
“而在forward方法中,定义了前向传播的方式,首先将输入通过输入层到隐藏层的映射生成隐藏层的数据,然后将隐藏层的数据通过隐藏层到输出层的映射生成输出。”,
由于网络是提前定义好的,所以这里的“生成隐藏层”其实是计算得到隐藏层的数据
for context, target in skipgram_data:
X = one_hot_encoding(target, word_to_idx).float().unsqueeze(0) # 将中心词转换为 One-Hot 向量
改为
for center_word, context in skipgram_data:
X = one_hot_encoding(center_word, word_to_idx).float().unsqueeze(0) # 将中心词转换为 One-Hot 向量
第一段代码最好加上下面几行,意味着实例化并打印模型
embedding_size = 2 # 设定嵌入层的大小,这里选择 2 是为了方便展示
skipgram_model = SkipGram(voc_size, embedding_size) # 实例化 Skip-Gram 模型
print("Skip-Gram 模型:", skipgram_model)
"因为我们只是提取Word2Vec神经网络中嵌入层的输出",把“输出”修改为“权重”。 --- 特别感谢读者,laiqli,为本书提出大量有见地的勘误!
“然后将其输入神经网络(论文中称其为隐藏层)”,修改为“然后将其输入隐藏层”,,修改的理由是在隐藏层之前的线性变换也是神经网络的一部分,所以这里直接写隐藏层不容易引起歧义。--- 特别感谢读者,laiqli,为本书提出大量有见地的勘误!
“也就是把每个输入序列的词嵌入串联起来,形成一个更大的向量”,修改为: “也就是把每个输入序列的词嵌入连接起来,形成一个更大的向量,表示前面连续的N个词”。从电路的角度来看,这里其实是并联,而不是串联~ --- 我觉得先改为连接。并联或串联,继续探讨。
“将输入批处理数据传入训练好的模型”,修改为“将批处理的数据传入训练好的模型”;修改的理由是“输入”和“传入”意思相同,同时出现的情况下,有一句话出现两个动词的感觉。
“后面跟着一个使用tanh激活的线性层”,修改为“后面跟一个线性层,然后再使用tanh来激活”;修改的理由是: “既然使用了非线性变换,所以它就不是一个线性层,应该把激活函数放到线性层的后面,而不是用它来修饰线性层”。
”模型结构简单:NPLM 使用了线性层和激活函数进行前向传播,这使得模型的表达能力受到限制。”修改为: “使用了较少的线性层和激活函数,神经网络的层数不够深
,这使得模型的表达能力受到限制”。当线性层和激活函数的层数和节点数越多的时候,它能模拟任意函数,所以“使用了线性层和激活函数”不是模型表达受限的原因,原因是模型不够深
。
--- 特别感谢读者,laiqli,为本书提出大量有见地的勘误!
“缺乏位置信息:NPLM不考虑输入序列中单词的顺序,这可能导致模型无法捕捉序列中单词之间的顺序关系。”修改:将这段整个删掉,由于NPLM输入了前面N-1个词的信息,并且在嵌入层后以并联的方式输入到下一层,所以它是能捕捉到单词之间的顺序关系的。
在“以上所有的权重矩阵和偏置项都是在模型的训练过程中通过反向传播和优化算法学习得到的。” 之后,换行。加上: “求得的i_t是输入层保留的比例,取值为0到1之间;f_t是历史状态保留的比例,当其为0时,表示遗忘所有历史信息;o_t是输出保留的比例。”
以上所有的权重矩阵和偏置项都是在模型的训练过程中通过反向传播和优化算法学习得到的。
求得的i_t是输入层保留的比例,取值为0到1之间;f_t是历史状态保留的比例,当其为0时,表示遗忘所有历史信息;o_t是输出保留的比例。
“接收前时间步”,改为 “接收当前时间步”。
"此x1元素"改成"x1中第一个元素"
“在__init__方法中,它接收一个参数hidden_size,表示隐藏层大小。”去掉这行文字,__init__方法没有这个参数。
“在Decoder类的__init__方法中,添加了一个新的参数attention,这是一个Attention类的实例。此外”删掉这部分,__init__函数里面没有这个参数。
return output # 形状 (batch_size, num_heads, seq_len, feature_dim)
改为
return output # 形状 (batch_size, num_heads, seq_len, header_dim)
注释中的
dec_self_attns 是一个列表,每个元素的维度是 [batch_size, n_heads, tgt_seq_len, src_seq_len]
改为
dec_self_attns 是一个列表,每个元素的维度是 [batch_size, n_heads, tgt_seq_len, tgt_seq_len]
最后一段 “不过,这次训练效果不理想”,改成“不过,这次测试效果不理想”
删去下面一行,因为后来没展示它。
"hi , how are you?",