十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

深度学习处理文本

深度学习处理文本 一、反向传播二、优化器1. Adam优化器1.1.Adam优化器相关参数学习率一般取0.001一阶矩估计指数衰减率一般取0.9二阶矩估计指数衰减率一般取0.999微小常数如防止除以零带有参数的随机目标函数是模型训练中需要最小化或最大化的函数初始参数向量模型参数的初始值1.2.Adam优化器算法步骤1.初始化初始化一阶矩向量为0。初始化二阶矩向量为0。初始化时间步为0。2.迭代过程2.1.更新一阶矩和二阶矩估计2.2.偏差修正 (Bias Correction)2.3.参数更新含义Adam的更新规则可以直观理解为用带有动量的梯度作为更新方向同时用类似RMSProp的来对每个参数的学习率进行自适应缩放。偏差修正确保了在训练初期矩估计也是无偏的。1.3. Adam优化器优势及适用场景1. 实现简单计算高效对内存需求少2. 超参数具有很好的解释性且通常无需调整或仅需很少的微调3. 更新的步长能够被限制在大致的范围内初始学习率4. 能够表现出自动调整学习率5. 很适合应用于大规模的数据及参数的场景6. 适用于不稳定目标函数7. 适用于梯度稀疏或梯度存在很大噪声的问题2. AdamW优化器在标准的L2正则化中损失函数会增加一项其梯度为。在Adam中这个正则项梯度会进入和的计算使得权重衰减的效果与梯度的量级耦合在一起导致对大学习率和较大权重的参数实际的权重衰减效果会减弱。AdamW 将权重衰减从梯度计算中解耦出来直接在参数更新步骤中应用1.执行标准的Adam更新 (不含正则项的梯度)2.独立进行权重衰减:含义权重衰减不再影响梯度的移动平均估计。它变成了一个独立的、对所有参数通常除了Normalization层和Bias施加的、与其梯度大小无关的“缩放”步骤更符合其作为正则化手段的初衷。三、NLP任务任务字符串分类判断字符串中是否出现了指定字符指定字符a 正样本abcd 负样本bcdbStep1字符数值化每个字符转化为同维度向量“abcd” - 4*5矩阵矩阵形状 文本长度 * 向量长度通过embedding层实现1.embedding层embedding矩阵是可训练的参数一般会在模型构建时随机初始化也可以使用预训练的词向量来做初始化此时也可以选择不训练embedding层中的参数输入的整数序列可以有重复但取值不能超过Embedding矩阵的列数核心价值将离散值转化为向量在nlp任务和各类特征工程中应用广泛搭配词表文件对于中文通常使用字对于英文使用token多个语种和符号可以出现在同一份词表中目的“abc --词表-- 0,1,2 --Embedding层-- 3*n的矩阵 -- modelimport torch import torch.nn as nn embedding层的处理 num_embeddings 6 #通常对于nlp任务此参数为字符集字符总数 embedding_dim 5 #每个字符向量化后的向量维度 embedding_layer nn.Embedding(num_embeddings, embedding_dim) print(随机初始化权重) print(embedding_layer.weight) print(################) #构造字符表 vocab { a : 0, b : 1, c : 2, d : 3, e : 4, f : 5, } def str_to_sequence(string, vocab): return [vocab[s] for s in string] string1 abcde string2 ddccb string3 fedab sequence1 str_to_sequence(string1, vocab) sequence2 str_to_sequence(string2, vocab) sequence3 str_to_sequence(string3, vocab) print(sequence1) print(sequence2) print(sequence3) x torch.LongTensor([sequence1, sequence2, sequence3]) embedding_out embedding_layer(x) print(embedding_out)Step2矩阵转化为向量池化求平均2.池化层降低了后续网络层的输入维度缩减模型大小提高计算速度提高了特征的鲁棒性防止过拟合Step3向量到数值采取最简单的线性公式Step4数值归一化sigmoid函数进行归一化处理映射到01之间注意字母向量和线性层的w和b需要通过训练优化3.NLP任务Demoimport torch import torch.nn as nn import numpy as np import random import json import matplotlib.pyplot as plt 基于pytorch的网络编写 实现一个网络完成一个简单nlp任务 判断文本中是否有某些特定字符出现 class TorchModel(nn.Module): def __init__(self, vector_dim, sentence_length, vocab): super(TorchModel, self).__init__() self.embedding nn.Embedding(len(vocab), vector_dim) #embedding层 self.pool nn.AvgPool1d(sentence_length) #池化层 self.classify nn.Linear(vector_dim, 1) #线性层 self.activation torch.sigmoid #sigmoid归一化函数 self.loss nn.functional.mse_loss #loss函数采用均方差损失 #当输入真实标签返回loss值无真实标签返回预测值 def forward(self, x, yNone): x self.embedding(x) #(batch_size, sen_len) - (batch_size, sen_len, vector_dim) x x.transpose(1, 2) #(batch_size, sen_len, vector_dim) - (batch_size, vector_dim, sen_len) x self.pool(x) #(batch_size, vector_dim, sen_len)-(batch_size, vector_dim, 1) x x.squeeze() #(batch_size, vector_dim, 1) - (batch_size, vector_dim) x self.classify(x) #(batch_size, vector_dim) - (batch_size, 1) 3*5 5*1 - 3*1 y_pred self.activation(x) #(batch_size, 1) - (batch_size, 1) if y is not None: return self.loss(y_pred, y) #预测值和真实值计算损失 else: return y_pred #输出预测结果 #字符集随便挑了一些字实际上还可以扩充 #为每个字生成一个标号 #{a:1, b:2, c:3...} #abc - [1,2,3] def build_vocab(): chars abcdefghijklmnopqrstuvwxyz #字符集 vocab {pad:0} for index, char in enumerate(chars): vocab[char] index1 #每个字对应一个序号 vocab[unk] len(vocab) #26 return vocab #随机生成一个样本 #从所有字中选取sentence_length个字 #反之为负样本 def build_sample(vocab, sentence_length): #随机从字表选取sentence_length个字可能重复 x [random.choice(list(vocab.keys())) for _ in range(sentence_length)] #指定哪些字出现时为正样本 if set(abc) set(x): y 1 #指定字都未出现则为负样本 else: y 0 x [vocab.get(word, vocab[unk]) for word in x] #将字转换成序号为了做embedding return x, y #建立数据集 #输入需要的样本数量。需要多少生成多少 def build_dataset(sample_length, vocab, sentence_length): dataset_x [] dataset_y [] for i in range(sample_length): x, y build_sample(vocab, sentence_length) dataset_x.append(x) dataset_y.append([y]) return torch.LongTensor(dataset_x), torch.FloatTensor(dataset_y) #建立模型 def build_model(vocab, char_dim, sentence_length): model TorchModel(char_dim, sentence_length, vocab) return model #测试代码 #用来测试每轮模型的准确率 def evaluate(model, vocab, sample_length): model.eval() x, y build_dataset(200, vocab, sample_length) #建立200个用于测试的样本 print(本次预测集中共有%d个正样本%d个负样本%(sum(y), 200 - sum(y))) correct, wrong 0, 0 with torch.no_grad(): y_pred model(x) #模型预测 for y_p, y_t in zip(y_pred, y): #与真实标签进行对比 if float(y_p) 0.5 and int(y_t) 0: correct 1 #负样本判断正确 elif float(y_p) 0.5 and int(y_t) 1: correct 1 #正样本判断正确 else: wrong 1 print(正确预测个数%d, 正确率%f%(correct, correct/(correctwrong))) return correct/(correctwrong) def main(): #配置参数 epoch_num 20 #训练轮数 batch_size 20 #每次训练样本个数 train_sample 500 #每轮训练总共训练的样本总数 char_dim 20 #每个字的维度 sentence_length 6 #样本文本长度 learning_rate 0.005 #学习率 # 建立字表 vocab build_vocab() # 建立模型 model build_model(vocab, char_dim, sentence_length) # 选择优化器 optim torch.optim.Adam(model.parameters(), lrlearning_rate) log [] # 训练过程 for epoch in range(epoch_num): model.train() watch_loss [] for batch in range(int(train_sample / batch_size)): x, y build_dataset(batch_size, vocab, sentence_length) #构造一组训练样本 optim.zero_grad() #梯度归零 loss model(x, y) #计算loss loss.backward() #计算梯度 optim.step() #更新权重 watch_loss.append(loss.item()) print(\n第%d轮平均loss:%f % (epoch 1, np.mean(watch_loss))) acc evaluate(model, vocab, sentence_length) #测试本轮模型结果 log.append([acc, np.mean(watch_loss)]) #画图 plt.plot(range(len(log)), [l[0] for l in log], labelacc) #画acc曲线 plt.plot(range(len(log)), [l[1] for l in log], labelloss) #画loss曲线 plt.legend() plt.show() #保存模型 torch.save(model.state_dict(), model.pth) # 保存词表 writer open(vocab.json, w, encodingutf8) writer.write(json.dumps(vocab, ensure_asciiFalse, indent2)) writer.close() return #使用训练好的模型做预测 def predict(model_path, vocab_path, input_strings): char_dim 20 # 每个字的维度 sentence_length 6 # 样本文本长度 vocab json.load(open(vocab_path, r, encodingutf8)) #加载字符表 model build_model(vocab, char_dim, sentence_length) #建立模型 model.load_state_dict(torch.load(model_path)) #加载训练好的权重 x [] for input_string in input_strings: x.append([vocab[char] for char in input_string]) #将输入序列化 model.eval() #测试模式 with torch.no_grad(): #不计算梯度 result model.forward(torch.LongTensor(x)) #模型预测 for i, input_string in enumerate(input_strings): print(输入%s, 预测类别%d, 概率值%f % (input_string, round(float(result[i])), result[i])) #打印结果 if __name__ __main__: main() test_strings [fnvfee, wzsdfg, rqwdeg, nakwww] predict(model.pth, vocab.json, test_strings)四、网络结构1.全连接层2.RNNRecurrent Neural Network循环神经网络主要思想将整个序列划分成多个时间步将每一个时间步的信息依次输入模型同时将模型输出的结果传给下一个时间步公式class TorchRNN(nn.Module): def __init__(self, input_size, hidden_size): super(TorchRNN, self).__init__() self.layer nn.RNN(input_size, hidden_size, biasFalse, batch_firstTrue) def forward(self, x): return self.layer(x)3.CNNConvolutional Neural Network卷积神经网络以卷积操作为基础的网络结构每个卷积核可以看成一个特征提取器class TorchCNN(nn.Module): def __init__(self, in_channel, out_channel, kernel): super(TorchCNN, self).__init__() self.layer nn.Conv2d(in_channel, out_channel, kernel, biasFalse) def forward(self, x): return self.layer(x)4.归一化 Normalizationbatch normalizationlayer normalization5.Dropout层作用减少过拟合按照指定概率随机丢弃一些神经元将其化为零其余元素乘以 1 / (1 – p)进行放大如何理解其作用1强迫一个神经单元和随机挑选出来的其他神经单元共同工作消除减弱了神经元节点间的联合适应性增强了泛化能力2可以看做是一种模型平均由于每次随机忽略的隐层节点都不同这样就使每次训练的网络都是不一样的每次训练都可以单做一个“新”的模型启示计算方式并不是越复杂就越好
返回列表