本文目录:

  • 一、案例介绍
    • (一)关于人名分类
    • (二)人名分类数据预览
  • 二、案例步骤
    • (一)导入工具包
    • (二)数据预处理
      • 1. 获取常用的字符数量
      • 2. 国家名种类数和个数
      • 3.读数据到内存
      • 4.构建数据源NameClassDataset
      • 5.构建迭代器遍历数据
  • 三、构建RNN模型(选择LSTM模型)
    • (一)构建模型
    • (二)模型测试
  • 四、构建训练函数并进行训练
    • (一)构建RNN训练函数
    • (二)LSTM模型训练
    • (三)模型训练日志数据制图
    • (四)模型训练结果分析
      • 1.损失对比曲线分析
      • 2 .训练耗时分析
      • 3. 训练准确率分析
      • 4.结论
  • 五、模型预测
  • 最后,附赠代码完整版(包括传统RNN、LSTM和GRU建模及预测)

前言:前面介绍了传统RNN、LSTM、GRU,本篇文章分享综合案例。

一、案例介绍

(一)关于人名分类

以一个人名为输入, 使用模型帮助我们判断它最有可能是来自哪一个国家的人名, 这在某些国际化公司的业务中具有重要意义, 在用户注册过程中, 会根据用户填写的名字直接给他分配可能的国家或地区选项, 以及该国家或地区的国旗, 限制手机号码位数等等。

(二)人名分类数据预览

数据存放路径:$(home)/data/name_classfication.txt

数据格式说明 每一行第一个单词为人名,第二个单词为国家名。中间用制表符tab分割。

Huffmann    German
Hummel  German
Hummel  German
Hutmacher   German
Ingersleben German
Jaeger  German
Jager   German
Deng    Chinese
Ding    Chinese
Dong    Chinese
Dou Chinese
Duan    Chinese
Eng Chinese
Fan Chinese
Fei Chinese
Abaimov Russian
Abakeliya   Russian
Abakovsky   Russian
Abakshin    Russian
Abakumoff   Russian
Abakumov    Russian
Abakumtsev  Russian
Abakushin   Russian
Abalakin    Russian

二、案例步骤

整个案例的实现可分为以下五个步骤:

第一步导入必备的工具包

第二步对data文件中的数据进行处理,满足训练要求

第三步构建RNN模型(选择 LSTM)

第四步构建训练函数并进行训练

第五步构建预测函数并进行预测

(一)导入工具包

# 导入torch工具
import torch
# 导入nn准备构建模型
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
# 导入torch的数据源 数据迭代器工具包
from  torch.utils.data import Dataset, DataLoader
# 用于获得常见字母及字符规范化
import string
# 导入时间工具包
import time
# 引入制图工具包  
import matplotlib.pyplot as plt
# 从io中导入文件打开方法
from io import open

(二)数据预处理

这里需要对data文件中的数据进行处理,满足训练要求。

1. 获取常用的字符数量

# 获取所有常用字符包括字母和常用标点
all_letters = string.ascii_letters + " .,;'"# 获取常用字符数量
n_letters = len(all_letters)print("n_letter:", n_letters)

运行结果:

n_letter: 57

2. 国家名种类数和个数

# 国家名 种类数
categorys = ['Italian', 'English', 'Arabic', 'Spanish', 'Scottish', 'Irish', 'Chinese', 'Vietnamese', 'Japanese','French', 'Greek', 'Dutch', 'Korean', 'Polish', 'Portuguese', 'Russian', 'Czech', 'German']
# 国家名 个数
categorynum = len(categorys)
print('categorys--->', categorys)

运行结果:

categorys---> ['Italian', 'English', 'Arabic', 'Spanish', 'Scottish', 'Irish', 'Chinese', 'Vietnamese', 'Japanese', 'French', 'Greek', 'Dutch', 'Korean', 'Polish', 'Portuguese', 'Russian', 'Czech', 'German']
categorynum---> 18

3.读数据到内存

# 思路分析
# 1 打开数据文件 open(filename, mode='r', encoding='utf-8')
# 2 按行读文件、提取样本x 样本y line.strip().split('\t')
# 3 返回样本x的列表、样本y的列表 my_list_x, my_list_y
def read_data(filename):my_list_x, my_list_y= [], []# 打开文件with  open(filename, mode='r', encoding='utf-8') as f:# 按照行读数据for line in f.readlines():if len(line) <= 5:continue# 按照行提取样本x 样本y(x, y) = line.strip().split('\t')my_list_x.append(x)my_list_y.append(y)# 打印样本的数量print('my_list_x->', len(my_list_x))print('my_list_y->', len(my_list_y))# 返回样本x的列表、样本y的列表return my_list_x, my_list_y

4.构建数据源NameClassDataset

# 原始数据 -> 数据源NameClassDataset --> 数据迭代器DataLoader
# 构造数据源 NameClassDataset,把语料转换成x y
# 1 init函数 设置样本x和y self.my_list_x self.my_list_y 条目数self.sample_len
# 2 __len__(self)函数  获取样本条数
# 3 __getitem__(self, index)函数 获取第几条样本数据
#       按索引 获取数据样本 x y
#       样本x one-hot张量化 tensor_x[li][all_letters.find(letter)] = 1
#       样本y 张量化 torch.tensor(categorys.index(y), dtype=torch.long)
#       返回tensor_x, tensor_y
class NameClassDataset(Dataset):def __init__(self, my_list_x, my_list_y):# 样本xself.my_list_x = my_list_x# 样本yself.my_list_y = my_list_y# 样本条目数self.sample_len = len(my_list_x)# 获取样本条数def __len__(self):return self.sample_len# 获取第几条 样本数据def __getitem__(self, index):# 对index异常值进行修正 [0, self.sample_len-1]index = min(max(index, 0), self.sample_len-1)# 按索引获取 数据样本 x yx = self.my_list_x[index]y = self.my_list_y[index]# 样本x one-hot张量化tensor_x = torch.zeros(len(x), n_letters)# 遍历人名 的 每个字母 做成one-hot编码for li, letter in enumerate(x):# letter2indx 使用all_letters.find(letter)查找字母在all_letters表中的位置 给one-hot赋值tensor_x[li][all_letters.find(letter)] = 1# 样本y 张量化tensor_y = torch.tensor(categorys.index(y), dtype=torch.long)# 返回结果return tensor_x, tensor_y

分析

文本张量化,这里也就是人名张量化是通过one-hot编码来完成。

# 将字符串(单词粒度)转化为张量表示,如:"ab" --->
# tensor([[[1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
#          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
#          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
#          0., 0., 0., 0., 0., 0.]],#        [[0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
#          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
#          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
#          0., 0., 0., 0., 0., 0.]]])

5.构建迭代器遍历数据

def dm_test_NameClassDataset():# 1 获取数据myfilename = './data/name_classfication.txt'my_list_x, my_list_y = read_data(myfilename)print('my_list_x length', len(my_list_x))print('my_list_y length', len(my_list_y))# 2 实例化dataset对象nameclassdataset = NameClassDataset(my_list_x, my_list_y)# 3 实例化dataloadermydataloader = DataLoader(dataset=nameclassdataset, batch_size=1, shuffle=True)for  i, (x, y) in enumerate (mydataloader):print('x.shape', x.shape, x)print('y.shape', y.shape, y)break

运行结果:

my_list_x length 20074
my_list_y length 20074
x.shape torch.Size([1, 5, 57]) tensor([[[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0.],[0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0.],[1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0.],[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0.],[1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0.]]])
y.shape torch.Size([1]) tensor([15])

三、构建RNN模型(选择LSTM模型)

(一)构建模型

# LSTM类 实现思路分析:
# 1 init函数 准备三个层 self.rnn self.linear self.softmax=nn.LogSoftmax(dim=-1)
#    def __init__(self, input_size, hidden_size, output_size, num_layers=1)# 2 forward(input, hidden)函数
#   让数据经过三个层 返回softmax结果和hn
#   形状变化 [seqlen,1,57],[1,1,128]) -> [seqlen,1,128],[1,1,128]# 3 初始化隐藏层输入数据 inithidden()
#   形状[self.num_layers, 1, self.hidden_size]
class LSTM(nn.Module):def __init__(self, input_size, hidden_size, output_size, num_layers=1):super(LSTM, self).__init__()# 1 init函数 准备三个层 self.rnn self.linear self.softmax=nn.LogSoftmax(dim=-1)self.input_size = input_sizeself.hidden_size = hidden_sizeself.output_size = output_sizeself.num_layers = num_layers# 定义rnn层self.rnn = nn.LSTM(self.input_size, self.hidden_size, self.num_layers)# 定义linear层self.linear = nn.Linear(self.hidden_size, self.output_size)# 定义softmax层self.softmax = nn.LogSoftmax(dim=-1)def forward(self, input, hidden, c):# 让数据经过三个层 返回softmax结果和 hn c# 数据形状 [6,57] -> [6,1,52]input = input.unsqueeze(1)# 把数据送给模型 提取事物特征# 数据形状 [seqlen,1,57],[1,1,128], [1,1,128]) -> [seqlen,1,18],[1,1,128],[1,1,128]rr, (hn, cn) = self.rnn(input, (hidden, c))# 数据形状 [seqlen,1,128] - [1, 128]tmprr = rr[-1]tmprr = self.linear(tmprr)return self.softmax(tmprr), hn, cndef inithidden(self):# 初始化隐藏层输入数据 inithidden()hidden = c = torch.zeros(self.num_layers, 1, self.hidden_size)return hidden, c

(二)模型测试

def dm_test_rnn_lstm_gru():# one-hot编码特征57(n_letters),也是RNN的输入尺寸input_size = 57# 定义隐层的最后一维尺寸大小n_hidden = 128# 输出尺寸为语言类别总数n_categories # 1个字符预测成18个类别output_size = 18# 1 获取数据myfilename = './data/name_classfication.txt'my_list_x, my_list_y  = read_data(myfilename)print('categorys--->', categorys)# 2 实例化dataset对象nameclassdataset = NameClassDataset(my_list_x, my_list_y)# 3 实例化dataloadermydataloader = DataLoader(dataset=nameclassdataset, batch_size=1, shuffle=True)my_lstm = LSTM(n_letters, n_hidden, categorynum)print('lstm 模型', my_lstm)for  i, (x, y) in enumerate (mydataloader):# print('x.shape', x.shape, x)# print('y.shape', y.shape, y)hidden, c = my_lstm.inithidden()output, hidden, c = my_lstm(x[0], hidden, c)print("lstm output.shape--->:", output.shape, output)if (i == 0):break

运行结果:

lstm 模型 LSTM((rnn): LSTM(57, 128)(linear): Linear(in_features=128, out_features=18, bias=True)(softmax): LogSoftmax(dim=-1)
)
lstm output.shape--->: torch.Size([1, 18]) tensor([[-2.9283, -3.0017, -2.8902, -2.8179, -2.8484, -2.8152, -2.9654, -2.8846,-2.8642, -2.8602, -2.8860, -2.9505, -2.8806, -2.9436, -2.8388, -2.9312,-2.9241, -2.8211]], grad_fn=<LogSoftmaxBackward0>)

四、构建训练函数并进行训练

(一)构建RNN训练函数

# 思路分析
# 从文件获取数据、实例化数据源对象nameclassdataset 数据迭代器对象mydataloader
# 实例化模型对象my_rnn 损失函数对象mycrossentropyloss=nn.NLLLoss() 优化器对象myadam
# 定义模型训练的参数
#       starttime total_iter_num total_loss  total_loss_list total_acc_num  total_acc_list
# 外层for循环 控制轮数 for epoch_idx in range(epochs)
# 内层for循环 控制迭代次数 for i, (x, y) in enumerate(mydataloader)# 给模型喂数据   # 计算损失  # 梯度清零 # 反向传播  # 梯度更新# 计算辅助信息   # 累加总损失和准确数 每100次训练计算一个总体平均损失 总体平均准确率 每2000次训练 打印日志# 其他          # 预测对错 i_predit_tag = (1 if torch.argmax(output).item() == y.item() else 0)# 模型保存# torch.save(my_rnn.state_dict(), './my_rnn_model_%d.bin' % (epoch_idx + 1))
# 返回 平均损失列表total_loss_list, 时间total_time, 平均准确total_acc_list

(二)LSTM模型训练

def my_train_lstm():# 获取数据myfilename = './data/name_classfication.txt'my_list_x, my_list_y = read_data(myfilename)# 实例化dataset对象nameclassdataset = NameClassDataset(my_list_x, my_list_y)# 实例化 模型input_size = 57n_hidden = 128output_size = 18my_lstm = LSTM(input_size, n_hidden, output_size)print('my_lstm模型--->', my_lstm)# 实例化 损失函数 adam优化器mycrossentropyloss = nn.NLLLoss()myadam = optim.Adam(my_lstm.parameters(), lr=mylr)# 定义模型训练参数starttime = time.time()total_iter_num = 0  # 已训练的样本数total_loss = 0.0  # 已训练的损失和total_loss_list = []  # 每100个样本求一次平均损失 形成损失列表total_acc_num = 0  # 已训练样本预测准确总数total_acc_list = []  # 每100个样本求一次平均准确率 形成平均准确率列表# 外层for循环 控制轮数for epoch_idx in range(epochs):# 实例化dataloadermydataloader = DataLoader(dataset=nameclassdataset, batch_size=1, shuffle=True)# 内层for循环 控制迭代次数for i, (x, y) in enumerate(mydataloader):# 给模型喂数据hidden, c = my_lstm.inithidden()output, hidden, c = my_lstm(x[0], hidden, c)# 计算损失myloss = mycrossentropyloss(output, y)# 梯度清零myadam.zero_grad()# 反向传播myloss.backward()# 梯度更新myadam.step()# 计算总损失total_iter_num = total_iter_num + 1total_loss = total_loss + myloss.item()# 计算总准确率i_predit_tag = (1 if torch.argmax(output).item() == y.item() else 0)total_acc_num = total_acc_num + i_predit_tag# 每100次训练 求一次平均损失 平均准确率if (total_iter_num % 100 == 0):tmploss = total_loss/total_iter_numtotal_loss_list.append(tmploss)tmpacc = total_acc_num/total_iter_numtotal_acc_list.append(tmpacc)# 每2000次训练 打印日志if (total_iter_num % 2000 == 0):tmploss = total_loss / total_iter_numprint('轮次:%d, 损失:%.6f, 时间:%d,准确率:%.3f' %(epoch_idx+1, tmploss, time.time() - starttime, tmpacc))# 每个轮次保存模型torch.save(my_lstm.state_dict(), './my_lstm_model_%d.bin' % (epoch_idx + 1))# 计算总时间total_time = int(time.time() - starttime)return total_loss_list, total_time, total_acc_list

(三)模型训练日志数据制图

def dm_test_train_rnn_lstm_gru():total_loss_list_rnn, total_time_rnn, total_acc_list_rnn = my_train_rnn()total_loss_list_lstm, total_time_lstm, total_acc_list_lstm = my_train_lstm()total_loss_list_gru, total_time_gru, total_acc_list_gru = my_train_gru()# 绘制损失对比曲线# 创建画布0plt.figure(0)# # 绘制损失对比曲线plt.plot(total_loss_list_rnn, label="RNN")plt.plot(total_loss_list_lstm, color="red", label="LSTM")plt.plot(total_loss_list_gru, color="orange", label="GRU")plt.legend(loc='upper left')plt.savefig('./img/RNN_LSTM_GRU_loss2.png')plt.show()# 绘制柱状图# 创建画布1plt.figure(1)x_data = ["RNN", "LSTM", "GRU"]y_data = [total_time_rnn, total_time_lstm, total_time_gru]# 绘制训练耗时对比柱状图plt.bar(range(len(x_data)), y_data, tick_label=x_data)plt.savefig('./img/RNN_LSTM_GRU_period2.png')plt.show()# 绘制准确率对比曲线plt.figure(2)plt.plot(total_acc_list_rnn, label="RNN")plt.plot(total_acc_list_lstm, color="red", label="LSTM")plt.plot(total_acc_list_gru, color="orange", label="GRU")plt.legend(loc='upper left')plt.savefig('./img/RNN_LSTM_GRU_acc2.png')plt.show()

模型训练日志输出:

轮次:3, 损失:0.805885, 时间:118,准确率:0.759
轮次:3, 损失:0.794148, 时间:123,准确率:0.762
轮次:3, 损失:0.783356, 时间:128,准确率:0.765
轮次:3, 损失:0.774931, 时间:133,准确率:0.767
轮次:3, 损失:0.765427, 时间:137,准确率:0.769
轮次:3, 损失:0.757254, 时间:142,准确率:0.771
轮次:3, 损失:0.750375, 时间:147,准确率:0.773
轮次:3, 损失:0.743092, 时间:152,准确率:0.775
轮次:4, 损失:0.732983, 时间:157,准确率:0.778
轮次:4, 损失:0.723816, 时间:162,准确率:0.780
轮次:4, 损失:0.716507, 时间:167,准确率:0.782
轮次:4, 损失:0.708377, 时间:172,准确率:0.785
轮次:4, 损失:0.700820, 时间:177,准确率:0.787
轮次:4, 损失:0.694714, 时间:182,准确率:0.788
轮次:4, 损失:0.688386, 时间:187,准确率:0.790
轮次:4, 损失:0.683056, 时间:191,准确率:0.791
轮次:4, 损失:0.677051, 时间:196,准确率:0.793
轮次:4, 损失:0.671668, 时间:201,准确率:0.794

(四)模型训练结果分析

1.损失对比曲线分析

在这里插入图片描述
左图:1个轮次损失对比曲线,右图4个轮次损失对比曲线

模型训练的损失降低快慢代表模型收敛程度。由图可知, 传统RNN的模型第一个轮次开始收敛情况最好,然后是GRU, 最后是LSTM, 这是因为RNN模型简单参数少,见效快。随着训练数据的增加,GRU效果最好、LSTM效果次之、RNN效果排最后。

所以在以后的模型选用时, 要通过对任务的分析以及实验对比, 选择最适合的模型。

2 .训练耗时分析

训练耗时对比图:
在这里插入图片描述
模型训练的耗时长短代表模型的计算复杂度,由图可知, 也正如我们之前的理论分析,传统RNN复杂度最低, 耗时几乎只是后两者的一半, 然后是GRU,最后是复杂度最高的LSTM。

3. 训练准确率分析

训练准确率对比图:
在这里插入图片描述
由图可知, GRU效果最好、LSTM效果次之、RNN效果排最后。

4.结论

模型选用一般应通过实验对比,并非越复杂或越先进的模型表现越好,而是需要结合自己的特定任务,从对数据的分析和实验结果中获得最佳答案。

五、模型预测

def my_predict_lstm(x):n_letters = 57n_hidden = 128n_categories = 18# 输入文本, 张量化one-hotx_tensor = lineToTensor(x)# 实例化模型 加载已训练模型参数my_lstm = LSTM(n_letters, n_hidden, n_categories)my_lstm.load_state_dict(torch.load(my_path_lstm))with torch.no_grad():# 模型预测hidden, c = my_lstm.inithidden()output, hidden, c = my_lstm(x_tensor, hidden, c)# 从预测结果中取出前3名# 3表示取前3, 1表示要排序的维度, True表示是否返回最大或是最下的元素topv, topi = output.topk(3, 1, True)print('rnn =>', x)for i in range(3):value = topv[0][i]category_idx = topi[0][i]category = categorys[category_idx]print('\t value:%d  category:%s' % (value, category))print('\t value:%d  category:%s' % (value, category))

运行结果:

rnn => zhangvalue:0  category:Chinesevalue:-1  category:Russianvalue:-1  category:German

本案例也可以构建传统rnn模型或者gru模型进行目标完成,具体大家可自行尝试。

最后,附赠代码完整版(包括传统RNN、LSTM和GRU建模及预测)

# -*-coding:utf-8-*-
# 导入torch工具
import torch
# 导入nn准备构建模型
import torch.nn as nn
#导入优化器optim
import torch.optim as optim
# 导入torch的数据源 数据迭代器工具包
from  torch.utils.data import Dataset, DataLoader
# 用于获得常见字母及字符规范化
import string
# 导入时间工具包
import time
# 引入制图工具包
import matplotlib.pyplot as plt
from tqdm import tqdm
import json# 1.todo: 获取常用的字符数量
# 此次将人名变成向量的过程:将人名中的每个字母(字符)进行one-hot张量表示,然后拼接代表整个人名的向量表示
# 因为人名的组成大部分都是由大小写英文字母以及某些特殊的字符组成,这里一个展示是57个,其实就是one-hot编码的维度all_letters = string.ascii_letters+" .,;'"
print(f'all_letters--》{all_letters}')
print(f'{all_letters.find("A")}')
n_letters = len(all_letters)
print('字符的总个数', n_letters)# 2 todo: 获取国家的类别个数
# 国家名 种类数
categorys = ['Italian', 'English', 'Arabic', 'Spanish', 'Scottish', 'Irish', 'Chinese', 'Vietnamese', 'Japanese','French', 'Greek', 'Dutch', 'Korean', 'Polish', 'Portuguese', 'Russian', 'Czech', 'German']
# 国家名 个数
categorynum = len(categorys)
print('categorys--->', categorynum)# 3 todo. 读取数据到内存中
def read_data(filename):# 定义两个空列表,分别存储人名和国家名my_list_x, my_list_y = [], []# 读取数据with open(filename, 'r', encoding='utf-8') as fr:for line in fr.readlines():# 数据清洗if len(line) <= 5:continuex, y = line.strip().split('\t')my_list_x.append(x)my_list_y.append(y)return my_list_x, my_list_y# 4 todo. 构建dataset类
class NameClassDataset(Dataset):def __init__(self, my_list_x, my_list_y):# 如果继承的父类没有__init__方法,那么此时可以省略掉super().__init__(),当然要是写上也不会报错# super().__init__()# 获取样本xself.my_list_x = my_list_x# 获取样本x对应的标签yself.my_list_y = my_list_y# 获取样本的长度self.sample_len = len(my_list_x)def __len__(self):return self.sample_lendef __getitem__(self, item):# item代表就是索引index = min(max(item, 0), self.sample_len-1)# 根据索引取出对应的x和yx = self.my_list_x[index]# print(f'x---->{x}')y = self.my_list_y[index]# print(f'y---》{y}')# 初始化全零的一个张量tensor_x = torch.zeros(len(x), n_letters)# 遍历人名的每个字母变成one-hot编码for idx, letter in enumerate(x):tensor_x[idx][all_letters.find(letter)] = 1# print(f'tensor_x--》{tensor_x}')tensor_y = torch.tensor(categorys.index(y), dtype=torch.long)return tensor_x, tensor_y# 5 todo. 实例化Dataloader
def get_dataloader():my_list_x, my_list_y = read_data(filename='./data/name_classfication.txt')nameClass_dataset = NameClassDataset(my_list_x, my_list_y)# 实例化Dataloadertrain_dataloader = DataLoader(dataset=nameClass_dataset,batch_size=1,shuffle=True)# for tensor_x, tensor_y in train_dataloader:#     print(f'tensor_x--》{tensor_x.shape}')#     print(f'tensor_y--》{tensor_y.shape}')#     breakreturn train_dataloader# 6 todo. 定义RNN模型
class NameRNN(nn.Module):def __init__(self, input_size, hidden_size, output_size, num_layers=1):super().__init__()# input_size-->输入x单词的词嵌入维度self.input_size = input_size# hidden_size-->RNN输出的隐藏层维度self.hidden_size = hidden_size# output_size-->国家类别的总个数self.output_size = output_size# num_layers:几层隐藏层self.num_layers = num_layers# 实例化RNN对象# batch_first=False,默认self.rnn = nn.RNN(input_size, hidden_size, num_layers)# 定义输出层self.out = nn.Linear(hidden_size, output_size)# 定义logsoftmax层self.softmax = nn.LogSoftmax(dim=-1)def forward(self, input_x, hidden):# input_x按照讲义,输入的时候,是个二维的【seq_len, input_size】-->[6, 57]# hidden:初始化隐藏层的值:[1, 1, 128]# 升维度,在dim=1的维度进行升维:input_x-->[6, 1, 57]input_x = input_x.unsqueeze(dim=1)# 将input_x和hidden送入rnn:rnn_output-->shape--[6,1,128];hn-->[1, 1, 128]rnn_output, hn = self.rnn(input_x, hidden)# 将上述rnn的结果经过输出层;rnn_output[-1]获取最后一个单词的词向量代表整个句子的语意# temp_vec-->[1, 128]temp_vec = rnn_output[-1]# 将temp_vec送入输出层:result-->[1, 18]result = self.out(temp_vec)return self.softmax(result), hndef inithidden(self):return torch.zeros(self.num_layers, 1, self.hidden_size)# 7 todo. 定义LSTM模型
class NameLSTM(nn.Module):def __init__(self, input_size, hidden_size, output_size, num_layers=1):super().__init__()# input_size-->输入x单词的词嵌入维度self.input_size = input_size# hidden_size-->RNN输出的隐藏层维度self.hidden_size = hidden_size# output_size-->国家类别的总个数self.output_size = output_size# num_layers:几层隐藏层self.num_layers = num_layers# 实例化LSTM对象self.lstm = nn.LSTM(input_size, hidden_size, num_layers)# 定义输出层self.out = nn.Linear(hidden_size, output_size)# 定义logsoftmax层self.softmax = nn.LogSoftmax(dim=-1)def forward(self, input_x, h0, c0):# input_x-shape-->[seq_len, embed_dim]-->[6, 57]# h0,c0-->shape-->[num_layers, batch_size, hidden_size]-->[1, 1, 128]# 1.先对input_x升维度;shape-->[6, 1, 57]input_x = input_x.unsqueeze(dim=1)# 2.将input_x, h0,c0送入lstm模型# lstm_output-->shape=-->[6, 1, 128]lstm_output, (hn, cn) = self.lstm(input_x, (h0, c0))# 3.取出lstm输出结果中最后一个单词对应的隐藏层输出结果送入输出层# temp_vec-->shape-->[1, 128]temp_vec = lstm_output[-1]# 送入输出层result->shape-->[1, 18]result = self.out(temp_vec)return self.softmax(result), hn, cndef inithidden(self):h0 = torch.zeros(self.num_layers, 1, self.hidden_size)c0 = torch.zeros(self.num_layers, 1, self.hidden_size)return h0, c0# 8 todo. 定义GRU模型
class NameGRU(nn.Module):def __init__(self, input_size, hidden_size, output_size, num_layers=1):super().__init__()# input_size-->输入x单词的词嵌入维度self.input_size = input_size# hidden_size-->RNN输出的隐藏层维度self.hidden_size = hidden_size# output_size-->国家类别的总个数self.output_size = output_size# num_layers:几层隐藏层self.num_layers = num_layers# 实例化GRU对象# batch_first=False,默认self.gru = nn.GRU(input_size, hidden_size, num_layers)# 定义输出层self.out = nn.Linear(hidden_size, output_size)# 定义logsoftmax层self.softmax = nn.LogSoftmax(dim=-1)def forward(self, input_x, hidden):# input_x按照讲义,输入的时候,是个二维的【seq_len, input_size】-->[6, 57]# hidden:初始化隐藏层的值:[1, 1, 128]# 升维度,在dim=1的维度进行升维:input_x-->[6, 1, 57]input_x = input_x.unsqueeze(dim=1)# 将input_x和hidden送入rnn:rnn_output-->shape--[6,1,128];hn-->[1, 1, 128]rnn_output, hn = self.gru(input_x, hidden)# 将上述gru的结果经过输出层;rnn_output[-1]获取最后一个单词的词向量代表整个句子的语意# temp_vec-->[1, 128]temp_vec = rnn_output[-1]# 将temp_vec送入输出层:result-->[1, 18]result = self.out(temp_vec)return self.softmax(result), hndef inithidden(self):return torch.zeros(self.num_layers, 1, self.hidden_size)my_lr = 1e-3
epochs = 1# 9 todo: 定义RNN模型的训练函数
def train_rnn():# 1.读取txt文档数据my_list_x, my_list_y = read_data(filename='./data/name_classfication.txt')# 2.实例化Dataset对象name_dataset = NameClassDataset(my_list_x, my_list_y)# 3.实例化自定义的RNN模型对象input_size = n_letters # 57hidden_size = 128output_size = categorynum # 18name_rnn = NameRNN(input_size, hidden_size, output_size)# 4.实例化损失函数对象以及优化器对象rnn_nllloss = nn.NLLLoss()rnn_adam = optim.Adam(name_rnn.parameters(), lr=my_lr)# 5.定义训练日志的参数start_time = time.time()total_iter_num = 0 # 已经训练的样本的总数total_loss = 0.0 # 已经训练的样本的总损失total_loss_list = [] # 每隔100个样本我们计算一下平均损失,并保存total_acc_num = 0 # 已经训练的样本中预测正确的个数total_acc_list = []# 每隔100个样本我们计算一下平均准确率,并保存# 6. 开始外部迭代for epoch_idx in range(epochs):# 6.1 实例化Dataloader的对象train_dataloader = DataLoader(dataset=name_dataset, batch_size=1, shuffle=True)# 6.2 开始遍历迭代器,内部迭代for idx, (tensor_x, tensor_y) in enumerate(tqdm(train_dataloader)):# 6.3 准备模型需要的数据tensor_x0 = tensor_x[0] # [seq_length, input_size]h0 = name_rnn.inithidden()# print(f'tensor_y--》{tensor_y}')# 6.4 将数据送入模型得到预测结果output-->shape-->[1, 18]output, hn = name_rnn(tensor_x0, h0)# print(f'output--》{output}')# 6.5 计算损失my_loss = rnn_nllloss(output, tensor_y)# print(f'my_loss--》{my_loss}')# 6.6 梯度清零rnn_adam.zero_grad()# 6.7 反向传播my_loss.backward()# 6.8 梯度更新rnn_adam.step()# 6.9 统计已经训练的样本的总个数total_iter_num = total_iter_num + 1# 6.10 统计已经训练的样本总损失total_loss = total_loss + my_loss.item()# 6.11 统计已经训练的样本中预测正确的样本总个数# torch.argmax(output)取出预测结果中最大概率值对应的索引predict_id = 1 if torch.argmax(output).item() == tensor_y.item() else 0total_acc_num = total_acc_num + predict_id# 6.12 每间隔100步,保存平均损失已经平均准确率if (total_iter_num % 100) == 0:# 计算平均损失并保存avg_loss = total_loss / total_iter_numtotal_loss_list.append(avg_loss)# 计算平均准确率并保存avg_acc = total_acc_num / total_iter_numtotal_acc_list.append(avg_acc)# 6.13 每间隔2000步,打印日志if (total_iter_num % 2000) == 0:temp_avg_loss = total_loss / total_iter_numtemp_avg_acc = total_acc_num / total_iter_numprint('轮次:%d, 损失:%.6f, 时间:%d,准确率:%.3f' %(epoch_idx+1, temp_avg_loss, time.time() - start_time, temp_avg_acc))# 7保存模型torch.save(name_rnn.state_dict(), './save_model/szAI_%d.bin'%(epoch_idx+1))total_time = time.time() - start_timernn_dict = {"total_loss_list": total_loss_list,"total_time": total_time,"total_acc_list": total_acc_list}with open('name_classify_rnn.json', 'w', encoding='utf-8') as fw:fw.write(json.dumps(rnn_dict))
def train_lstm():my_list_x, my_list_y = read_data(filename='./data/name_classfication.txt')# 2.实例化Dataset对象name_dataset = NameClassDataset(my_list_x, my_list_y)# 3.实例化自定义的RNN模型对象input_size = n_letters  # 57hidden_size = 128output_size = categorynum  # 18name_lstm = NameLSTM(input_size, hidden_size, output_size)# 4.实例化损失函数对象以及优化器对象rnn_nllloss = nn.NLLLoss()rnn_adam = optim.Adam(name_lstm.parameters(), lr=my_lr)# 5.定义训练日志的参数start_time = time.time()total_iter_num = 0  # 已经训练的样本的总数total_loss = 0.0  # 已经训练的样本的总损失total_loss_list = []  # 每隔100个样本我们计算一下平均损失,并保存total_acc_num = 0  # 已经训练的样本中预测正确的个数total_acc_list = []  # 每隔100个样本我们计算一下平均准确率,并保存# 6. 开始外部迭代for epoch_idx in range(epochs):# 6.1 实例化Dataloader的对象train_dataloader = DataLoader(dataset=name_dataset, batch_size=1, shuffle=True)# 6.2 开始遍历迭代器,内部迭代for idx, (tensor_x, tensor_y) in enumerate(tqdm(train_dataloader)):# 6.3 准备模型需要的数据tensor_x0 = tensor_x[0]  # [seq_length, input_size]h0,c = name_lstm.inithidden()# print(f'tensor_y--》{tensor_y}')# 6.4 将数据送入模型得到预测结果output-->shape-->[1, 18]output, hn,cn = name_lstm(tensor_x0, h0,c)# print(f'output--》{output}')# 6.5 计算损失my_loss = rnn_nllloss(output, tensor_y)# print(f'my_loss--》{my_loss}')# 6.6 梯度清零rnn_adam.zero_grad()# 6.7 反向传播my_loss.backward()# 6.8 梯度更新rnn_adam.step()# 6.9 统计已经训练的样本的总个数total_iter_num = total_iter_num + 1# 6.10 统计已经训练的样本总损失total_loss = total_loss + my_loss.item()# 6.11 统计已经训练的样本中预测正确的样本总个数# torch.argmax(output)取出预测结果中最大概率值对应的索引predict_id = 1 if torch.argmax(output).item() == tensor_y.item() else 0total_acc_num = total_acc_num + predict_id# 6.12 每间隔100步,保存平均损失已经平均准确率if (total_iter_num % 100) == 0:# 计算平均损失并保存avg_loss = total_loss / total_iter_numtotal_loss_list.append(avg_loss)# 计算平均准确率并保存avg_acc = total_acc_num / total_iter_numtotal_acc_list.append(avg_acc)# 6.13 每间隔2000步,打印日志if (total_iter_num % 2000) == 0:temp_avg_loss = total_loss / total_iter_numtemp_avg_acc = total_acc_num / total_iter_numprint('轮次:%d, 损失:%.6f, 时间:%d,准确率:%.3f' % (epoch_idx + 1, temp_avg_loss, time.time() - start_time, temp_avg_acc))# 7保存模型torch.save(name_lstm.state_dict(), './save_model/_%d.bin' % (epoch_idx + 1))total_time=time.time()-start_time# 9. 将损失列表和准确率列表以及时间保存到字典并存储到文件里lstm_dict = {"total_loss_list": total_loss_list,"total_time": total_time,"total_acc_list": total_acc_list}with open('name_classify_lstm.json', 'w', encoding='utf-8') as fw:fw.write(json.dumps(lstm_dict))
def train_gru():# 1.读取txt文档数据my_list_x, my_list_y = read_data(filename='./data/name_classfication.txt')# 2.实例化Dataset对象name_dataset = NameClassDataset(my_list_x, my_list_y)# 3.实例化自定义的RNN模型对象input_size = n_letters # 57hidden_size = 128output_size = categorynum # 18name_gru = NameGRU(input_size, hidden_size, output_size)# 4.实例化损失函数对象以及优化器对象rnn_nllloss = nn.NLLLoss()rnn_adam = optim.Adam(name_gru.parameters(), lr=my_lr)# 5.定义训练日志的参数start_time = time.time()total_iter_num = 0 # 已经训练的样本的总数total_loss = 0.0 # 已经训练的样本的总损失total_loss_list = [] # 每隔100个样本我们计算一下平均损失,并保存total_acc_num = 0 # 已经训练的样本中预测正确的个数total_acc_list = []# 每隔100个样本我们计算一下平均准确率,并保存# 6. 开始外部迭代for epoch_idx in range(epochs):# 6.1 实例化Dataloader的对象train_dataloader = DataLoader(dataset=name_dataset, batch_size=1, shuffle=True)# 6.2 开始遍历迭代器,内部迭代for idx, (tensor_x, tensor_y) in enumerate(tqdm(train_dataloader)):# 6.3 准备模型需要的数据tensor_x0 = tensor_x[0] # [seq_length, input_size]h0 = name_gru.inithidden()# print(f'tensor_y--》{tensor_y}')# 6.4 将数据送入模型得到预测结果output-->shape-->[1, 18]output, hn = name_gru(tensor_x0, h0)# print(f'output--》{output}')# 6.5 计算损失my_loss = rnn_nllloss(output, tensor_y)# print(f'my_loss--》{my_loss}')# 6.6 梯度清零rnn_adam.zero_grad()# 6.7 反向传播my_loss.backward()# 6.8 梯度更新rnn_adam.step()# 6.9 统计已经训练的样本的总个数total_iter_num = total_iter_num + 1# 6.10 统计已经训练的样本总损失total_loss = total_loss + my_loss.item()# 6.11 统计已经训练的样本中预测正确的样本总个数# torch.argmax(output)取出预测结果中最大概率值对应的索引predict_id = 1 if torch.argmax(output).item() == tensor_y.item() else 0total_acc_num = total_acc_num + predict_id# 6.12 每间隔100步,保存平均损失已经平均准确率if (total_iter_num % 100) == 0:# 计算平均损失并保存avg_loss = total_loss / total_iter_numtotal_loss_list.append(avg_loss)# 计算平均准确率并保存avg_acc = total_acc_num / total_iter_numtotal_acc_list.append(avg_acc)# 6.13 每间隔2000步,打印日志if (total_iter_num % 2000) == 0:temp_avg_loss = total_loss / total_iter_numtemp_avg_acc = total_acc_num / total_iter_numprint('轮次:%d, 损失:%.6f, 时间:%d,准确率:%.3f' %(epoch_idx+1, temp_avg_loss, time.time() - start_time, temp_avg_acc))# 7保存模型torch.save(name_gru.state_dict(), './save_model/gru_%d.bin'%(epoch_idx+1))total_time = time.time() - start_timegru_dict = {"total_loss_list": total_loss_list,"total_time": total_time,"total_acc_list": total_acc_list}with open('name_classify_gru.json', 'w', encoding='utf-8') as fw:fw.write(json.dumps(gru_dict))
def draw_picture():with (open('name_classify_gru.json','r') as fg,open('name_classify_rnn.json','r') as fr,open('name_classify_lstm.json','r') as fl):fr=json.loads(fr.read())fg=json.loads(fg.read())fl=json.loads(fl.read())plt.figure(0)plt.plot(fr['total_loss_list'],label='rnn')plt.plot(fl['total_loss_list'],label='lstm')plt.plot(fg['total_loss_list'],label='gru')plt.legend(loc='upper left')plt.show()plt.figure(1)x_list=["RNN", "LSTM", "GRU"]plt.bar(range(len(x_list)),y=[fr['total_time'],fl['total_time'],fg['total_time']],tick_label=x_list)plt.show()plt.figure(2)plt.plot(fr['total_acc_list'], label='rnn')plt.plot(fl['total_acc_list'], label='lstm')plt.plot(fg['total_acc_list'], label='gru')plt.legend(loc='upper left')plt.show()
def str_to_vec(x):len_letter=len(x)tensor_x = torch.zeros(len_letter, n_letters)for idx,letter in enumerate(x):tensor_x[idx][all_letters.find(letter)]=1return tensor_x
#模型预测
def my_predict_rnn(x):n_letters = 57n_hidden = 128n_categories = 18# 输入文本, 张量化one-hotx_tensor = str_to_vec(x)# 实例化模型 加载已训练模型参数my_rnn = NameRNN(n_letters, n_hidden, n_categories)my_rnn.load_state_dict(torch.load( './save_model/szAI_1.bin'))with torch.no_grad():# 模型预测output, hidden = my_rnn(x_tensor, my_rnn.inithidden())# 从预测结果中取出前3名# 3表示取前3, 1表示要排序的维度, True表示是否返回最大或是最下的元素topv, topi = output.topk(3, 1, True)print('rnn =>', x)for i in range(3):value = topv[0][i]category_idx = topi[0][i]category = categorys[category_idx]print('\t value:%d  category:%s' %(value, category))
def my_predict_lstm(x):n_letters = 57n_hidden = 128n_categories = 18# 输入文本, 张量化one-hotx_tensor = str_to_vec(x)# 实例化模型 加载已训练模型参数my_rnn = NameLSTM(n_letters, n_hidden, n_categories)my_rnn.load_state_dict(torch.load( './save_model/_1.bin'))with torch.no_grad():# 模型预测hidden, c=my_rnn.inithidden()output, hidden ,c= my_rnn(x_tensor,hidden,c )# 从预测结果中取出前3名# 3表示取前3, 1表示要排序的维度, True表示是否返回最大或是最下的元素topv, topi = output.topk(3, 1, True)print(topi,topv)  #一个是值,一个是索引print('lstm =>', x)for i in range(3):value = topv[0][i]category_idx = topi[0][i]category = categorys[category_idx]print('\t value:%d    category:%s' %(value, category))
def my_predict_gru(x):n_letters = 57n_hidden = 128n_categories = 18# 输入文本, 张量化one-hotx_tensor = str_to_vec(x)# 实例化模型 加载已训练模型参数my_rnn = NameGRU(n_letters, n_hidden, n_categories)my_rnn.load_state_dict(torch.load( './save_model/gru_1.bin'))with torch.no_grad():# 模型预测hidden=my_rnn.inithidden()output, hidden= my_rnn(x_tensor,hidden)# 从预测结果中取出前3名# 3表示取前3, 1表示要排序的维度, True表示是否返回最大或是最下的元素topv, topi = output.topk(3, 1, True)print(topi,topv)  #一个是值,一个是索引print('lstm =>', x)for i in range(3):value = topv[0][i]category_idx = topi[0][i]category = categorys[category_idx]print('\t value:%d    category:%s' %(value, category))if __name__ == '__main__':# train_dataloader = get_dataloader()# # name_lstm= NameLSTM(input_size=n_letters, hidden_size=128, output_size=categorynum)# name_gru= NameGRU(input_size=n_letters, hidden_size=128, output_size=categorynum)# print(name_gru)# for tensor_x, tensor_y in train_dataloader:#     h0 = name_gru.inithidden()#     x0 = tensor_x[0]#     output, hn= name_gru(x0, h0)#     print(f'output--》{output.shape}')#     print(f'output--》{output}')#     print(f'hn--》{hn.shape}')#     break# train_rnn()# train_lstm()# train_gru()# draw_picture()# tensor_x=str_to_vec('zhang')# print(tensor_x)my_predict_rnn('zhang')my_predict_lstm('zhang')my_predict_gru('zhang')my_predict_rnn('Benesch')my_predict_lstm('Benesch')my_predict_gru('Benesch')

今日分享结束。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/89841.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/89841.shtml
英文地址,请注明出处:http://en.pswp.cn/web/89841.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3分钟实战!用DeepSeek+墨刀AI生成智能对话APP原型图

如今&#xff0c;AI生成原型图已经逐渐成为产品经理的一项常用辅助技能&#xff0c;不仅能加快设计进程&#xff0c;还能显著提升前期沟通效率。最近我尝试将大语言模型工具与AI原型工具结合测试&#xff0c;目标是看看是否能生成更高质量的原型页面。直到我使用DeepSeek墨刀AI…

CentOS网络配置与LAMP环境搭建指南

一、CentOS配置网络1、查看网卡名称ifconfig2、找到网卡对应配置文件网卡存放路径 &#xff1a;/etc/sysconfig/network-scriptscd /etc/sysconfig/network-scripts3、修改网卡对应配置文件使用 vi/vim 打开文件&#xff0c;查看以下内容vim ifcfg-ens33将ONBOOTno 改为 ONBOOT…

TinyMCE 富文本编辑器在 vue2 中的使用 @tinymce/tinymce-vue

TinyMCE是一款功能强大、高度可定制的富文本编辑器。官方文档 TinyMCE DOCS tinymce-vue包的版本4及更高版本支持Vue.js 3。但不支持Vue.js 2.x。对于Vue.js 2。X应用程序&#xff0c;使用tinymce-vue版本3。 安装TinyMCE和Vue集成包 npm install tinymce/tinymce-vue3 tiny…

LP-MSPM0G3507学习--04GPIO控制

关键函数&#xff1a; DL_GPIO_readPins(GPIO_Regs* gpio, uint32_t pins):同时读一组端口DL_GPIO_writePins(GPIO_Regs* gpio, uint32_t pins)&#xff1a;同时写一组端口DL_GPIO_setPins(GPIO_Regs* gpio, uint32_t pins)&#xff1a;对指定某组端口的某管脚置高DL_GPIO_cle…

LVS(Linux virtual server)-实现四层负载均衡

一、简介LVS:Linux Virtual Server&#xff0c;负载调度器&#xff0c;内核集成&#xff0c;章文嵩&#xff0c;阿里的四层SLB(Server LoadBalance)是基 于LVSkeepalived实现LVS 官网: http://www.linuxvirtualserver.org/二、LVS运行原理2.1LVS 的集群结构2.2lvs相关概念RS&am…

Kubernetes CNI网络插件性能瓶颈排查与优化实践

Kubernetes CNI网络插件性能瓶颈排查与优化实践 CNI&#xff08;Container Network Interface&#xff09;是 Kubernetes 网络层的核心组件&#xff0c;不同 CNI 插件实现了容器间网络通信、多租户隔离、流量限速等功能。然而在大规模集群或高并发业务场景下&#xff0c;CNI 插…

20250720-6-Kubernetes 调度-nodeName字段,DaemonS_笔记

一、污点与容忍&#xfeff;1. 给节点添加污点&#xfeff;1&#xff09;命令格式基本语法&#xff1a;kubectl taint node [node] keyvalue:[effect]示例&#xff1a;kubectl taint node k8s-node1 gpuyes:NoSchedule操作说明&#xff1a;与打标签命令类似&#xff0c;将"…

微软开源项目 Detours 详细介绍与使用实例分享

目录 1、Detours概述 2、Detours功能特性 3、Detours工作原理 4、Detours应用场景 5、Detours兼容性 6、Detours具体使用方法 7、Detours使用实例 - 使用Detours拦截系统库中的UnhandledExceptionFilter接口,实现对程序异常的拦截 C++软件异常排查从入门到精通系列教程…

研发知识系统选型实战:从 Notion 到 Gitee Wiki 的迭代经验

关键词&#xff1a;知识管理、版本控制、协作编辑、国产平台、研发效能 在日常研发管理中&#xff0c;知识管理平台往往被视为“非核心工具”&#xff0c;但它的好坏直接影响着团队交接效率、文档可用性以及协作深度。过去几年&#xff0c;我们团队先后使用过 Notion、Confluen…

从一开始的网络攻防(三):sqlmap快速上手

一、确定目标 使用sqlmap的第一步是确定探测的目标&#xff0c;一般有四种&#xff1a; 数据库URL文件Google批量扫 环境 Target IP: 192.168.8.133 Port: 13306(Mysql)、8088(sqli_labs) mysql&#xff1a; docker pull的最新mysql sqlmap github&#xff1a;https://g…

《Anaconda 精简路径治理》系列 · 番外篇Conda 虚拟环境路径结构方案全解——六种路径布局对比、优劣与治理建议

Python 多版本环境治理理念驱动的系统架构设计&#xff1a;三维治理、四级隔离、五项自治 原则-CSDN博客 Anaconda 路径精简后暴露 python 及工具到环境变量的配置记录-CSDN博客 【终极实战】Conda/Poetry/Virtualenv/Pipenv/Hatch 多工具协同 AnacondaPyCharm&#xff1a;构建…

容器基础知识3-kubectl、kubeadm 和 kubelet,kube-proxy

kubectl、kubeadm 和 kubelet&#xff0c;kube-proxy的概念和关系一、kubeadm&#xff1a;K8s 集群的 “搭建工程师”核心定位如果把 K8s 集群比作一栋大楼&#xff0c;kubeadm 就是负责 “打地基、搭框架” 的工程师&#xff0c;专门用来快速搭建 K8s 集群的工具。具体工作内容…

langchain调用本地ollama语言模型和嵌入模型

参考&#xff1a;ollama兼容OpenAIEmbeddings的解决思路 解决代码&#xff1a; 访问embedding模型代码 # 测试以下两个引用都可以 from langchain_openai import OpenAIEmbeddings #from langchain_community.embeddings import OpenAIEmbeddings from typing import List,…

gitlab私有化部署

以下是整理好的Markdown格式文档&#xff0c;详细描述了从下载镜像、启动镜像、修改external_url以及设置或重置root密码的步骤。 GitLab 安装与配置指南 本文档将指导您完成GitLab的安装和基本配置过程&#xff0c;包括下载镜像、启动容器、修改外部访问URL(external_url)及设…

CCLink IE转ModbusTCP网关配置无纸记录器(上篇)

本研究案例采用CCLink IE转ModbusTCP网关技术&#xff0c;实现了将记录仪数据传输至三菱PLCPLC的过程。具体操作步骤如下所述。在确保无纸记录仪与PT100传感器传感器的连接无误后&#xff0c;应将无纸记录仪与个人计算机&#xff08;PC&#xff09;通过以太网线进行连接&#x…

近期工作感想:职业规划篇

最近整理博客时&#xff0c;撞见意外的惊喜——17年刚毕业那会儿写的职业规划&#xff0c;静静躺在回收站里。 重读那些碎碎念&#xff0c;忍不住想笑&#xff1a;那时候的焦虑太真切了&#xff0c;哪敢想后来会遇到这么多大佬&#xff0c;推着我往前一直阴暗爬行&#x1f602;…

Matlab自学笔记六十四:求解自变量带有约束条件的方程

1.说明 有一些方程由于实际问题的需要&#xff0c;需要设置一些限制约束条件&#xff0c;例如x>0等&#xff0c;若使用Matlab编程求解&#xff0c;首先尝试使用符号运算求解&#xff08;符号运算可参考文章54&#xff1a;Matlab自学笔记五十四&#xff1a;符号数学工具箱和…

Flutter状态管理篇之ChangeNotifier(二)

目录 前言 一、ChangeNotifier定义 1.ChangeNotifier定义 2.Listenable的定义 二、继承体系 三、核心方法解析 1.类结构与属性分析 1.Listenable的定义 2..核心字段 1.属性解析 1._count 2._listeners 3.为什么不用const [] 4._notificationCallStackDep…

大带宽服务器对于高流量网站的作用

随着科学技术的快速发展&#xff0c;越来越多的网站面临着高流量的访问需求&#xff0c;在同一时间中会有着大量的用户进行访问&#xff0c;同时也提高了该企业的知名度&#xff0c;但是这对于服务器的性能需求也在逐渐增高&#xff0c;而大带宽服务器卓越的性能和稳定的传输能…

2025年算法备案发号规律总结与下半年发号预测

上半年发号规律总结图太糊&#xff1f;可看下方表格&#xff08;左划看全表&#xff09;&#x1f447;今年批次算法备案总批次发布时间所发当批算法材料提交时间段审核周期25年第一批第十批2025/3/122025年1月&#xff08;春节前&#xff09;约2个月25年第二批第十一批2025/5/1…