赞
踩
(二)机器学习应用策略
(三)卷积神经网络
(四)序列模型
(五)pytorch从零实现手写数字识别
(六)认识NLP,RNN实现文本情感分析
(六)经典试题整合
tokenization:分词 token:具体的词
常见工具
分词方法:
准备词语特征的方法,N代表能够一起使用的词的数量
分词长度:len(cuted) -1
、获取分词(以2为例)cuted[i:i+2]
举例程序:
text = input()
cuted = jieba.lcut(text)
cutlist = [cuted[i:i+2] for i in range(len(cuted)-1)]
比传统优秀的原因:词语有了一定的顺序
文本转化为项链
应用了浮点型稠密矩阵,根据词典决定向量的维度,如100、256、300等。向量的每一个值都是一个超参数,初始值是随机生成,之后会在训练的过程中进行学习。(这里的数值化一般是根据具体的词语的相关性确定,吴恩达的课没有说明具体获取的方法,这里表明了所有的值都是训练获得,并不是人工标记哈)
将长度优化 NxN(ont-hot) -> Nxn(n为选择的向量维度)
需要先把词语数值化:维度变化:[batch_sizer(有多少个句子),N(句子中词语的长度)] -> [batch_size,N,300(300代表的是超参数)]
具体形状变化:经历embedding
[batch_size,10] -[20,4]--> [batch_size,10,4]
调用torch
中的API:
embedding = nn.Embedding(vocab_size,300) # 词典的大小,自定义单词超参数长度
input_embeded = embedding(input) # embedding操作(初始化)
需要解决问题:
观察数据内容,决定切分单词方法,去除符号的方法(参考)
def tockenize(text):
filters = ['!','"','#','$','%','&','\(','\)','\*','\+',',','-','\.','/',':',
';','<','=','>','\?','@','\[','\]','\\','^','_','`','{','}','\|',
'~','\t','\n','\x97','\x96','”','“',]
text = re.sub("<.*?>"," ",text,flags=re.S)
text = re.sub("|".join(filters)," ",text,flag=re.S)
return [i.strip() for i in text.split()]
将每个词语和对应的数字用字典保存,把句子通过字典映射为包含数字的列表
<unk>
填充初始化类:
class Word2Seq: UNK_TAG = "UNK" PAD_TAG = "PAD" UNK = 0 PAD = 1 def __init__(self): # 词典构建 # 特殊符合和填充符号 self.dict = { self.UNK_TAG:self.UNK, self.PAD_TAG:self.PAD } self.count = {}
具体过程:
def fit(self,sentence):
"""单个句子保存到字典
:param sentence : [word1,word2,...]
"""
for word in sentence:
self.count[word] = self.count.get(word, 0) + 1 # 在+1,不在为1
# 2 词语存入字典,根据次数对词语进行过滤 def build_vocab(self,min=5,max=None,max_features=None): """生成词典 :param min:最小词频 :param max_features:一共保存多少词语 """ # 删除小词频 if min is not None: self.count = {word:value for word,value in self.count.items() if value>min} if max is not None: self.count = {word:value for word,value in self.count.items() if value<min} # 限制保留的词语数 if max_features is not None: # 先对字典内容排序以后选择前 temp = sorted(self.count.items(),key=lambda x:x[-1],reverse=True)[:max_features] # 转换为字典 self.count = dict(temp) for word in self.count: # 将字典当前的长度作为单词的代表,是不会重复的 self.dict[word] = len(self.dict) #得到一个反转的字典 self.inverse_dict = dict(zip(self.dict.values(),self.dict.keys()))
#序列转文本
def inverse_transform(self,indices):
"""
将数字序列转换为句子
:param indices:
:return:
"""
return [self.inverse_dict.get(idx) for idx in indices]
使用词嵌入模型,直接通过全连接层,使用带权损失
RNN:
总之一句话:循环神经网络的最大的特点就是,神经元的输出可以在下一个时间步直接作用到自身(作为输入),这就使得这种模型具有短期记忆的能力。
LSTM:
解决长期依赖
记忆细胞:通过sigmoid函数和t-1,点乘实现记忆
遗忘门:通过sigmoid函数决定哪些信息需要被遗忘
输入门:决定哪些信息会被更新
输出门:输出当前时刻的结果和隐藏的状态
输入和输出
双向:组合,既有正向的记忆也有反向的记忆
GRU:
将遗忘门和输入门组合为更新门(只有两个门)
输入:上一个隐藏状态
输出:当前隐藏状态,更新
torch.nn.LSTM
默认输入:实例化后需要输入数据、前一次隐层状态和前一次记忆细胞,lstm(input,(h0,c0))
input_size
输入的最后的一维的长度hidden_size
设置隐藏层单元数目,即每一层有多少个单元num_layer
设置多少层,为1时不会dropout
batch_first
参数的输入顺序,默认为False
即原输入顺序[seq_len,batch_size,feature]
,如果为True
即[batch_size,seq_len,feature]
dropout
,0-1层随机失活的比例,在最后一层的每个输出bidirectional
选择双向默认输出:output,(h_n,c_n)
具体API
batch_size = 10 seq_len = 20 # 句子长度 vocab_size = 100 # 词典的长度 embedding_dim = 30 # 长30的向量表示一个词语 hidden_size = 18 # 隐藏层单元数 num_layer = 2 # 隐藏层数 # 模拟输入 inputs = torch.randint(low=0,high=100,size=[batch_size,seq_len]) # [10,20] # embedding处理 embedding = nn.Embedding(vocab_size,embedding_dim) input_embedded = embedding(inputs) # [10,20,30] # embedding之后的数据传入lstm lstm = nn.LSTM(input_size=embedding_dim,hidden_size=hidden_size,num_layers=num_layer,batch_first=True,bidirectional=False) output,(h_n,c_n) = lstm(input_embedded) print(output.size()) #[10,20,18*1 if bidirectional else 18*2] print(h_n.size()) # [layer*2 if bidirectional else layer*1,10,18] print(c_n.size()) # [layer*2 if bidirectional else layer*1,10,18]
可以验证最后一次隐藏层状态和最后一个时间步上的输出相等
# 最后一个时间步上的输出
last_output = output[:,-1,:]
# 获取最后一次的隐藏层
last_hidden_state= h_n[-1,:,:]
print(last_output == last_hidden_state)
损失函数
多分类,使用softmax进行输出,使用的时需要去计算样本属于每个类别的概率。
带权损失,权重乘以值之和的负
l
o
s
s
=
−
∑
Y
t
r
u
e
∗
l
o
g
(
P
)
,
P
是
s
o
f
t
m
a
x
的
输
出
l
o
s
s
=
−
∑
w
i
x
i
loss = -\sum Y_{true} * log(P),P是softmax的输出\\ loss = -\sum w_i x_i
loss=−∑Ytrue∗log(P),P是softmax的输出loss=−∑wixi
关于双向的
output的拼接顺序:
# 双向的LSTML中的最后一个时间步的output
# 正向
last_output = output[:,-1,:18]
# 反向
last_output = output[:,0,18:]
# 获取双向LSTM中最后一个隐藏层
# 正向
last_hidden_state = h_n[-2,:,:]
# 反向
last_hidden_state = h_n[-1,:,:]
GRU(参数如同LSTML)
输入: o u t p u t , h n = g r u ( i n p u t , h 0 ) output,h_n = gru(input,h_0) output,hn=gru(input,h0)
形状同LSTM
遇到了import中的问题,发现在函数定义的默认值,是不能设置为引入变量的
实现的源码已上传,暂未整理到github
当使用权重初始值过小或者使用易饱和神经元(sigmoid,tanh),比如sigmoid在y=0,1处梯度接近0,而无法更新参数,这时候神经网络在反向传播时也会呈指数倍缩小,产生消失
当初始权重过大时,神经网络在反向传播的时候也会出现呈指数倍放大,产生爆炸
sigmoid的导函数如图所示
解决方案:
ReLU
或者leaky ReLU
,并不会出现导数的变化。正则化,每个batch训练过程中,对参数进行归一化处理,从而加快训练速度
以sigmoid为例,就会尽可能地将参数拉到[0,1]地范围,让参数地更新幅度更大
一般放在激活函数之后
对参数地随机失活
input会被容器中的构造器类依次执行:
layer = nn.Sequential (
nn.Linear(input_dim,n_hidden_1), # 形状变为[batch_size,n_hidden_1]
nn.ReLU(True),
nn.BatchNorm1d(n_hidden_1)
nn.Dropout(0.3) # 默认值为0.5
nn.Linear(n_hidden_1,n_hidden_2), # [batch_size,n_hidden_2]
nn.ReLU(True),
nn.BatchNorm1d(n_hidden_2)
nn.DropOut(0.3)
nn.Linear(n_hidden_2,output_dim) # 最后一层不需要激活函数[batch_size,output_dim]
)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。