Skip to content

Commit a764418

Browse files
Merge pull request apachecn#370 from jiangzhonglian/dev
修改笔误的地方
2 parents 89c994b + b8eeb03 commit a764418

5 files changed

Lines changed: 556 additions & 1 deletion

File tree

src/py3.x/7.AdaBoost/adaboost.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def build_stump(data_arr, class_labels, D):
109109
if weighted_err < min_err:
110110
min_err = weighted_err
111111
best_class_est = predicted_vals.copy()
112-
best_stump['dim'] = 1
112+
best_stump['dim'] = i
113113
best_stump['thresh'] = thresh_val
114114
best_stump['ineq'] = inequal
115115
# best_stump 表示分类器的结果,在第几个列上,用大于/小于比较,阈值是多少 (单个弱分类器)
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
# coding: utf-8
2+
# 作者: Robert Guthrie
3+
4+
import torch
5+
import torch.autograd as autograd
6+
import torch.nn as nn
7+
import torch.optim as optim
8+
9+
torch.manual_seed(1)
10+
11+
12+
def to_scalar(var):
13+
# 返回 python 浮点数 (float)
14+
return var.view(-1).data.tolist()[0]
15+
16+
17+
def argmax(vec):
18+
# 以 python 整数的形式返回 argmax
19+
_, idx = torch.max(vec, 1)
20+
return to_scalar(idx)
21+
22+
23+
def prepare_sequence(seq, to_ix):
24+
idxs = [to_ix[w] for w in seq]
25+
tensor = torch.LongTensor(idxs)
26+
return autograd.Variable(tensor)
27+
28+
29+
# 使用数值上稳定的方法为前向算法计算指数和的对数
30+
def log_sum_exp(vec):
31+
max_score = vec[0, argmax(vec)]
32+
max_score_broadcast = max_score.view(1, -1).expand(1, vec.size()[1])
33+
return max_score + \
34+
torch.log(torch.sum(torch.exp(vec - max_score_broadcast)))
35+
36+
37+
class BiLSTM_CRF(nn.Module):
38+
def __init__(self, vocab_size, tag_to_ix, embedding_dim, hidden_dim):
39+
super(BiLSTM_CRF, self).__init__()
40+
self.embedding_dim = embedding_dim
41+
self.hidden_dim = hidden_dim
42+
self.vocab_size = vocab_size
43+
self.tag_to_ix = tag_to_ix
44+
self.tagset_size = len(tag_to_ix)
45+
46+
self.word_embeds = nn.Embedding(vocab_size, embedding_dim)
47+
self.lstm = nn.LSTM(
48+
embedding_dim, hidden_dim // 2, num_layers=1, bidirectional=True)
49+
50+
# 将LSTM的输出映射到标记空间
51+
self.hidden2tag = nn.Linear(hidden_dim, self.tagset_size)
52+
53+
# 过渡参数矩阵. 条目 i,j 是
54+
# *从 * j *到* i 的过渡的分数
55+
self.transitions = nn.Parameter(
56+
torch.randn(self.tagset_size, self.tagset_size))
57+
58+
# 这两句声明强制约束了我们不能
59+
# 向开始标记标注传递和从结束标注传递
60+
self.transitions.data[tag_to_ix[START_TAG], :] = -10000
61+
self.transitions.data[:, tag_to_ix[STOP_TAG]] = -10000
62+
63+
self.hidden = self.init_hidden()
64+
65+
def init_hidden(self):
66+
return (autograd.Variable(torch.randn(2, 1, self.hidden_dim // 2)),
67+
autograd.Variable(torch.randn(2, 1, self.hidden_dim // 2)))
68+
69+
def _forward_alg(self, feats):
70+
# 执行前向算法来计算分割函数
71+
init_alphas = torch.Tensor(1, self.tagset_size).fill_(-10000.)
72+
# START_TAG 包含所有的分数
73+
init_alphas[0][self.tag_to_ix[START_TAG]] = 0.
74+
75+
# 将其包在一个变量类型中继而得到自动的反向传播
76+
forward_var = autograd.Variable(init_alphas)
77+
78+
# 在句子中迭代
79+
for feat in feats:
80+
alphas_t = [] # 在这个时间步的前向变量
81+
for next_tag in range(self.tagset_size):
82+
# 对 emission 得分执行广播机制: 它总是相同的,
83+
# 不论前一个标注如何
84+
emit_score = feat[next_tag].view(
85+
1, -1).expand(1, self.tagset_size)
86+
# trans_score 第 i 个条目是
87+
# 从i过渡到 next_tag 的分数
88+
trans_score = self.transitions[next_tag].view(1, -1)
89+
# next_tag_var 第 i 个条目是在我们执行 对数-求和-指数 前
90+
# 边缘的值 (i -> next_tag)
91+
next_tag_var = forward_var + trans_score + emit_score
92+
# 这个标注的前向变量是
93+
# 对所有的分数执行 对数-求和-指数
94+
alphas_t.append(log_sum_exp(next_tag_var))
95+
forward_var = torch.cat(alphas_t).view(1, -1)
96+
terminal_var = forward_var + self.transitions[self.tag_to_ix[STOP_TAG]]
97+
alpha = log_sum_exp(terminal_var)
98+
return alpha
99+
100+
def _get_lstm_features(self, sentence):
101+
self.hidden = self.init_hidden()
102+
embeds = self.word_embeds(sentence).view(len(sentence), 1, -1)
103+
lstm_out, self.hidden = self.lstm(embeds, self.hidden)
104+
lstm_out = lstm_out.view(len(sentence), self.hidden_dim)
105+
lstm_feats = self.hidden2tag(lstm_out)
106+
return lstm_feats
107+
108+
def _score_sentence(self, feats, tags):
109+
# 给出标记序列的分数
110+
score = autograd.Variable(torch.Tensor([0]))
111+
tags = torch.cat([torch.LongTensor([self.tag_to_ix[START_TAG]]), tags])
112+
for i, feat in enumerate(feats):
113+
score = score + \
114+
self.transitions[tags[i + 1], tags[i]] + feat[tags[i + 1]]
115+
score = score + self.transitions[self.tag_to_ix[STOP_TAG], tags[-1]]
116+
return score
117+
118+
def _viterbi_decode(self, feats):
119+
backpointers = []
120+
121+
# 在对数空间中初始化维特比变量
122+
init_vvars = torch.Tensor(1, self.tagset_size).fill_(-10000.)
123+
init_vvars[0][self.tag_to_ix[START_TAG]] = 0
124+
125+
# 在第 i 步的 forward_var 存放第 i-1 步的维特比变量
126+
forward_var = autograd.Variable(init_vvars)
127+
for feat in feats:
128+
bptrs_t = [] # 存放这一步的后指针
129+
viterbivars_t = [] # 存放这一步的维特比变量
130+
131+
for next_tag in range(self.tagset_size):
132+
# next_tag_var[i] 存放先前一步标注i的
133+
# 维特比变量, 加上了从标注 i 到 next_tag 的过渡
134+
# 的分数
135+
# 我们在这里并没有将 emission 分数包含进来, 因为
136+
# 最大值并不依赖于它们(我们在下面对它们进行的是相加)
137+
next_tag_var = forward_var + self.transitions[next_tag]
138+
best_tag_id = argmax(next_tag_var)
139+
bptrs_t.append(best_tag_id)
140+
viterbivars_t.append(next_tag_var[0][best_tag_id])
141+
# 现在将所有 emission 得分相加, 将 forward_var
142+
# 赋值到我们刚刚计算出来的维特比变量集合
143+
forward_var = (torch.cat(viterbivars_t) + feat).view(1, -1)
144+
backpointers.append(bptrs_t)
145+
146+
# 过渡到 STOP_TAG
147+
terminal_var = forward_var + self.transitions[self.tag_to_ix[STOP_TAG]]
148+
best_tag_id = argmax(terminal_var)
149+
path_score = terminal_var[0][best_tag_id]
150+
151+
# 跟着后指针去解码最佳路径
152+
best_path = [best_tag_id]
153+
for bptrs_t in reversed(backpointers):
154+
best_tag_id = bptrs_t[best_tag_id]
155+
best_path.append(best_tag_id)
156+
# 弹出开始的标签 (我们并不希望把这个返回到调用函数)
157+
start = best_path.pop()
158+
assert start == self.tag_to_ix[START_TAG] # 健全性检查
159+
best_path.reverse()
160+
return path_score, best_path
161+
162+
def neg_log_likelihood(self, sentence, tags):
163+
feats = self._get_lstm_features(sentence)
164+
forward_score = self._forward_alg(feats)
165+
gold_score = self._score_sentence(feats, tags)
166+
return forward_score - gold_score
167+
168+
def forward(self, sentence): # 不要把这和上面的 _forward_alg 混淆
169+
# 得到 BiLSTM 输出分数
170+
lstm_feats = self._get_lstm_features(sentence)
171+
172+
# 给定特征, 找到最好的路径
173+
score, tag_seq = self._viterbi_decode(lstm_feats)
174+
return score, tag_seq
175+
176+
177+
START_TAG = "<START>"
178+
STOP_TAG = "<STOP>"
179+
EMBEDDING_DIM = 5
180+
HIDDEN_DIM = 4
181+
182+
# 编造一些训练数据
183+
training_data = [(
184+
"the wall street journal reported today that apple corporation made money".
185+
split(), "B I I I O O O B I O O".split()),
186+
("georgia tech is a university in georgia".split(),
187+
"B I O O O O B".split())]
188+
189+
word_to_ix = {}
190+
for sentence, tags in training_data:
191+
for word in sentence:
192+
if word not in word_to_ix:
193+
word_to_ix[word] = len(word_to_ix)
194+
195+
tag_to_ix = {"B": 0, "I": 1, "O": 2, START_TAG: 3, STOP_TAG: 4}
196+
197+
model = BiLSTM_CRF(len(word_to_ix), tag_to_ix, EMBEDDING_DIM, HIDDEN_DIM)
198+
optimizer = optim.SGD(model.parameters(), lr=0.01, weight_decay=1e-4)
199+
200+
# 在训练之前检查预测结果
201+
precheck_sent = prepare_sequence(training_data[0][0], word_to_ix)
202+
precheck_tags = torch.LongTensor([tag_to_ix[t] for t in training_data[0][1]])
203+
print(model(precheck_sent))
204+
205+
# 确认从之前的 LSTM 部分的 prepare_sequence 被加载了
206+
for epoch in range(300): # 又一次, 正常情况下你不会训练300个 epoch, 这只是示例数据
207+
for sentence, tags in training_data:
208+
# 第一步: 需要记住的是Pytorch会累积梯度
209+
# 我们需要在每次实例之前把它们清除
210+
model.zero_grad()
211+
212+
# 第二步: 为我们的网络准备好输入, 即
213+
# 把它们转变成单词索引变量 (Variables)
214+
sentence_in = prepare_sequence(sentence, word_to_ix)
215+
targets = torch.LongTensor([tag_to_ix[t] for t in tags])
216+
217+
# 第三步: 运行前向传递.
218+
neg_log_likelihood = model.neg_log_likelihood(sentence_in, targets)
219+
220+
# 第四步: 计算损失, 梯度以及
221+
# 使用 optimizer.step() 来更新参数
222+
neg_log_likelihood.backward()
223+
optimizer.step()
224+
225+
# 在训练之后检查预测结果
226+
precheck_sent = prepare_sequence(training_data[0][0], word_to_ix)
227+
print(model(precheck_sent))
228+
# 我们完成了!
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# coding: utf-8
2+
# 作者: Robert Guthrie
3+
4+
import torch
5+
import torch.autograd as autograd
6+
import torch.nn as nn
7+
import torch.nn.functional as F
8+
import torch.optim as optim
9+
10+
11+
def prepare_sequence(seq, to_ix):
12+
idxs = [to_ix[w] for w in seq]
13+
tensor = torch.LongTensor(idxs)
14+
return autograd.Variable(tensor)
15+
16+
17+
training_data = [
18+
("The dog ate the apple".split(), ["DET", "NN", "V", "DET", "NN"]),
19+
("Everybody read that book".split(), ["NN", "V", "DET", "NN"])
20+
]
21+
word_to_ix = {}
22+
for sent, tags in training_data:
23+
for word in sent:
24+
if word not in word_to_ix:
25+
word_to_ix[word] = len(word_to_ix)
26+
print(word_to_ix)
27+
tag_to_ix = {"DET": 0, "NN": 1, "V": 2}
28+
29+
# 实际中通常使用更大的维度如32维, 64维.
30+
# 这里我们使用小的维度, 为了方便查看训练过程中权重的变化.
31+
EMBEDDING_DIM = 6
32+
HIDDEN_DIM = 6
33+
34+
35+
class LSTMTagger(nn.Module):
36+
def __init__(self, embedding_dim, hidden_dim, vocab_size, tagset_size):
37+
super(LSTMTagger, self).__init__()
38+
self.hidden_dim = hidden_dim
39+
40+
self.word_embeddings = nn.Embedding(vocab_size, embedding_dim)
41+
42+
# LSTM 以 word_embeddings 作为输入, 输出维度为 hidden_dim 的隐状态值
43+
self.lstm = nn.LSTM(embedding_dim, hidden_dim)
44+
45+
# 线性层将隐状态空间映射到标注空间
46+
self.hidden2tag = nn.Linear(hidden_dim, tagset_size)
47+
self.hidden = self.init_hidden()
48+
49+
def init_hidden(self):
50+
# 开始时刻, 没有隐状态
51+
# 关于维度设置的详情,请参考 Pytorch 文档
52+
# 各个维度的含义是 (num_layers, minibatch_size, hidden_dim)
53+
return (autograd.Variable(torch.zeros(1, 1, self.hidden_dim)),
54+
autograd.Variable(torch.zeros(1, 1, self.hidden_dim)))
55+
56+
def forward(self, sentence):
57+
embeds = self.word_embeddings(sentence)
58+
lstm_out, self.hidden = self.lstm(
59+
embeds.view(len(sentence), 1, -1), self.hidden)
60+
tag_space = self.hidden2tag(lstm_out.view(len(sentence), -1))
61+
tag_scores = F.log_softmax(tag_space, dim=1)
62+
return tag_scores
63+
64+
65+
model = LSTMTagger(EMBEDDING_DIM, HIDDEN_DIM, len(word_to_ix), len(tag_to_ix))
66+
loss_function = nn.NLLLoss()
67+
optimizer = optim.SGD(model.parameters(), lr=0.1)
68+
69+
# 查看下训练前得分的值
70+
# 注意: 输出的 i,j 元素的值表示单词 i 的 j 标签的得分
71+
inputs = prepare_sequence(training_data[0][0], word_to_ix)
72+
tag_scores = model(inputs)
73+
print(tag_scores)
74+
75+
for epoch in range(300): # 再次说明下, 实际情况下你不会训练300个周期, 此例中我们只是构造了一些假数据
76+
for sentence, tags in training_data:
77+
# Step 1. 请记住 Pytorch 会累加梯度
78+
# 每次训练前需要清空梯度值
79+
model.zero_grad()
80+
81+
# 此外还需要清空 LSTM 的隐状态
82+
# 将其从上个实例的历史中分离出来
83+
model.hidden = model.init_hidden()
84+
85+
# Step 2. 准备网络输入, 将其变为词索引的 Variables 类型数据
86+
sentence_in = prepare_sequence(sentence, word_to_ix)
87+
targets = prepare_sequence(tags, tag_to_ix)
88+
89+
# Step 3. 前向传播
90+
tag_scores = model(sentence_in)
91+
92+
# Step 4. 计算损失和梯度值, 通过调用 optimizer.step() 来更新梯度
93+
loss = loss_function(tag_scores, targets)
94+
loss.backward()
95+
optimizer.step()
96+
97+
98+
# 查看训练后得分的值
99+
inputs = prepare_sequence(training_data[0][0], word_to_ix)
100+
print('inputs: \n', inputs)
101+
tag_scores = model(inputs)
102+
# 句子是 "the dog ate the apple", i,j 表示对于单词 i, 标签 j 的得分.
103+
# 我们采用得分最高的标签作为预测的标签. 从下面的输出我们可以看到, 预测得
104+
# 到的结果是0 1 2 0 1. 因为 索引是从0开始的, 因此第一个值0表示第一行的
105+
# 最大值, 第二个值1表示第二行的最大值, 以此类推. 所以最后的结果是 DET
106+
# NOUN VERB DET NOUN, 整个序列都是正确的!
107+
print('tag_scores: \n', tag_scores)

src/py3.x/NLP/lstm/test.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# coding: utf-8
2+
# 作者: Robert Guthrie
3+
4+
import torch
5+
import torch.autograd as autograd
6+
import torch.nn as nn
7+
import torch.nn.functional as F
8+
import torch.optim as optim
9+
10+
torch.manual_seed(1)
11+
12+
lstm = nn.LSTM(3, 3) # 输入维度是3, 输出维度也是3
13+
inputs = [autograd.Variable(torch.randn((1, 3)))
14+
for _ in range(5)] # 构造一个长度为5的序列
15+
16+
# 初始化隐藏状态
17+
hidden = (autograd.Variable(torch.randn(1, 1, 3)),
18+
autograd.Variable(torch.randn((1, 1, 3))))
19+
for i in inputs:
20+
# 将序列的元素逐个输入到LSTM
21+
# 经过每步操作,hidden 的值包含了隐藏状态的信息
22+
out, hidden = lstm(i.view(1, 1, -1), hidden)
23+
24+
# 另外, 我们还可以一次对整个序列进行训练. LSTM 返回的第一个值表示所有时刻的隐状态值,
25+
# 第二个值表示最近的隐状态值 (因此下面的 "out"的最后一个值和 "hidden" 的值是一样的).
26+
# 之所以这样设计, 是为了通过 "out" 的值来获取所有的隐状态值, 而用 "hidden" 的值来
27+
# 进行序列的反向传播运算, 具体方式就是将它作为参数传入后面的 LSTM 网络.
28+
29+
# 增加额外的第二个维度
30+
inputs = torch.cat(inputs).view(len(inputs), 1, -1)
31+
hidden = (autograd.Variable(torch.randn(1, 1, 3)), autograd.Variable(
32+
torch.randn((1, 1, 3)))) # 清空输出隐状态
33+
out, hidden = lstm(inputs, hidden)
34+
print("out: \n", out)
35+
print("hidden: \n", hidden)

0 commit comments

Comments
 (0)