当前位置: 首页 > article >正文

rnn/lstm 项目实战

tip:本项目用到的数据和代码在https://pan.baidu.com/s/1Cw6OSSWJevSv7T1ouk4B6Q?pwd=z6w2 

1. RNN : 预测股价

任务:基于zgpa_train.csv数据,建立RNN模型,预测股价

1.完成数据预处理,将序列数据转化为可用于RNN输入的数据

2.对新数据zgpa_test.csv进行预测,可视化结果

3.存储预测结果,并观察局部预测结果

备注:模型结构:单层RNN,输出有5个神经元,每次使用前8个数据预测第9个数据

1.1 数据准备

下面是一个预测股票的一个项目实战。

任务:基于zgpa_train.csv数据,建立RNN模型,预测股价

1.完成数据预处理,将序列数据转化为可用于RNN输入的数据

2.对新数据zgpa_test.csv进行预测,可视化结果

3.存储预测结果,并观察局部预测结果

备注:模型结构:单层RNN,输出有5个神经元,每次使用前8个数据预测第9个数据。

数据内容大致如下:

开始项目,代码如下: 

import pandas as pd
import numpy as np
data = pd.read_csv('zgpa_train.csv')
data.head()

# 加载收盘价
price = data.loc[:, 'close']
price.head()

# 归一化处理
price_norm = price/max(price)
print(price_norm)

# 归一化之前的数据可视化
%matplotlib inline
from matplotlib import pyplot as plt
fig1 = plt.figure(figsize=(8,5))
plt.plot(price)
plt.title('close_price')  # 归一化之前的数据
plt.xlabel('time')
plt.ylabel('price')
plt.show()

%matplotlib inline的作用:

%matplotlib inline 是一个 IPython 魔法命令,用于在 Jupyter Notebook 中将 matplotlib 绘图直接嵌入到输出单元中。这样可以使绘图在 Notebook 中显示,而无需调用 plt.show() 方法。此外,它可以确保每次执行绘图代码时,图形都能在相应的输出单元显示,而不是在外部窗口中弹出。

inline:表示图像“在线”显示,意思是在 Jupyter Notebook 的输出单元中直接显示图像,而不是在单独的窗口中弹出。

# 对 X 与 y 进行赋值
# 定义方法去提取 X 与 y
def extract_data(data, time_step):
  X = []  # list
  y = []  # list
  # 例如,10个样本;time_step=8;
  # 第一组样本,0,1,2,...7
  # 第二组样本,1,2,3,...8
  # 第三组样本,2,3,4,...9
  # 共有2组样本可供观测
  for i in range(len(data)-time_step):
    X.append([a for a in data[i:i+time_step]])
    y.append(data[i+time_step])
  X = np.array(X)
  X = X.reshape(X.shape[0], X.shape[1], 1)
  return X, y

上面是设计数组X、y的函数,即X是因,y是果,用X的一个数组得到y的一个对应值;这里把X处理成了最后一个维度只有一个元素的维度,即X.shape =(*,*,...,1)。 

# 定义 X 与 y
time_step = 8
X, y = extract_data(price_norm, time_step)
print(X.shape) # 723个样本,每个样本有8个数据,每个样本对应1个单独数值,(723,8,1)
print(X[0, :, :]) # 第一个样本数据

这里使用刚才的函数,提供data和time_step,创建出X,y。

jupyter里可以不需要用那么多print,直接在单元格输入X.shape,X[0]就能得到相应的结果。

---------------------------------------------------------------------------------------------------------------------------

1.2 模型建立

下面是建立模型的主要代码,这段代码使用 Keras 构建了一个简单的 循环神经网络(RNN)模型,它适合用于 回归任务。以下是代码中各个步骤的解释::

from keras.models import Sequential        
from keras.layers import Dense, SimpleRNN  # 引入层相关,输出层与 RNN 层

model = Sequential() # 创建实例
model.add(SimpleRNN(units=5, input_shape=(time_step, 1), activation='relu')) # RNN 层
model.add(Dense(units=1, activation='linear')) # 输出层,回归任务直接使用 linear 激活函数
model.compile(optimizer='adam', loss='mean_squared_error') # 回归使用mse评测
model.summary() 

逐步解析代码:

1. 导入模块
from keras.models import Sequential        
from keras.layers import Dense, SimpleRNN
  • Sequential:用于构建 Keras 的顺序模型,可以按顺序堆叠各层。
  • DenseSimpleRNN:分别代表全连接层和简单循环神经网络(RNN)层。
2. 创建模型实例
model = Sequential()

使用 Sequential() 创建一个顺序模型实例 model,可以层层堆叠神经网络层。

3. 添加 SimpleRNN 层
model.add(SimpleRNN(units=5, input_shape=(time_step, 1), activation='relu'))
  • SimpleRNN:一种简单的循环神经网络层。
  • units=5:表示 RNN 层有 5 个隐藏单元(Hidden Units)。
  • input_shape=(time_step, 1):输入的形状。假设时间步为 time_step,每步有一个特征。
  • activation='relu':使用 ReLU 激活函数。

1. 这一步就对应理论部分的由x到h,这里 units=5 表示 RNN 层有 5 个隐藏单元h,每个单元可以理解为负责捕捉某一方面的特征,这些单元共同作用,从输入数据中提取序列信息,并将提取到的特征传递到下一层或输出层。在这个RNN 模型中,每个时间步都会产生 5 个隐藏单元的输出

隐藏单元越多,模型能够捕捉的特征就越多,模型也会更复杂,适合处理高维和复杂数据。

2. input_shape=(time_step, 1):说明输入序列的长度和每个时间步的特征数量,用来告诉模型输入数据的形状。这里的特征指的是,描述了每个时间步的输入信息量,比如传感器数据流中每个时间步可能有多个传感器特征(例如温度、湿度、压力等)。这个模型只用到了一个特征,即close收盘价,对应之前数据准备只取了那一列。

3. activation='relu':指定了隐藏状态计算中的激活函数,即计算由x到h的激活函数。

4. 添加 Dense 输出层
model.add(Dense(units=1, activation='linear'))
  • 是在给模型添加一个 全连接层(Dense 层),该层有如下配置:

  • units=1:表示该层包含一个神经元,输出为一个值。对于回归任务(例如预测一个连续值),输出层通常只需一个神经元,因为只需输出一个预测结果。

  • activation='linear':激活函数设置为 linear,即线性激活函数。线性激活函数的作用是直接输出该层计算的值,不做任何非线性变换,这非常适合回归任务,因为回归问题中预测的目标值是连续的,需要直接输出真实值的估计。

即上面的隐藏状态h到这里的y,一个时间步对应只有一个y的输出,具体来说就是一个时间步里,刚才得到的5个隐藏状态h到输出的y,用到的激活函数是 linear。

5. 编译模型
model.compile(optimizer='adam', loss='mean_squared_error')
  • optimizer='adam':使用 Adam 优化器,适合多种神经网络优化。
  • loss='mean_squared_error':使用均方误差(MSE)作为损失函数,MSE 常用于回归问题评估模型预测的误差。

Adam 是一种自适应优化算法,具有以下特点:

  1. 自适应学习率:Adam 会为每个参数动态调整学习率,使得每个参数都能有合适的更新步长。
  2. 结合动量和 RMSProp 的优势:Adam 使用动量(Momentum)来平滑梯度的更新,同时利用 RMSProp 的方法来控制梯度的变化幅度,从而加速收敛。
 6. 模型结构总结
model.summary()

输出模型的层次结构、参数数量等信息,便于了解模型的总体结构和参数情况。 

总结

  • 该模型是一个用于回归任务的简单 RNN 模型,包含一个 RNN 层和一个全连接输出层。
  • 使用 ReLU 激活函数在隐藏层,线性激活函数在输出层,以适应回归任务。

--------------------------------------------------------------------------------------------------------------------------------

1.3 模型层数介绍

在深度学习模型中,层数概念指的是网络结构中的不同计算层,它们共同完成数据的逐步抽象和特征提取。一般来说,一个模型的层可以分为 输入层隐藏层输出层。这些层共同构成了模型的数据流动路径和特征提取结构。

(1). 输入层
  • 作用:接收输入数据并将其传递给模型的第一层。输入层本身不进行任何计算操作,仅定义输入数据的形状。
  • 表示方式:在 Keras 中,输入层是通过指定第一层的 input_shape 参数来隐式定义的,不会单独显示在 model.summary() 中。
  • 例子:在你的模型中,input_shape=(time_step, 1) 就定义了输入层,表示输入数据是一个具有 time_step 个时间步且每个时间步有 1 个特征的序列。
(2). 隐藏层
  • 作用:模型中真正进行特征提取、模式识别和学习的层。隐藏层可以是各种类型的神经网络层,例如全连接层(Dense)、卷积层(Conv2D)、循环层(SimpleRNN、LSTM)等。
  • 数量和类型:一个模型可以有多个隐藏层,这些层负责将输入数据逐步转换为更高层次的特征。
  • 例子:在你的模型中,SimpleRNN 层就是一个隐藏层。它接受输入数据的时间序列,并通过 5 个隐藏单元来提取时序特征。
(3). 输出层
  • 作用:生成最终的模型输出。输出层的形状和激活函数通常根据具体任务(如分类或回归)进行设置。
  • 设置:输出层通常是一个全连接层(Dense),其单元数量和激活函数会根据任务调整。例如,分类任务会使用 softmax 激活函数,而回归任务则使用 linear 激活函数。
  • 例子:在你的模型中,Dense(units=1, activation='linear') 是输出层,用于回归任务,输出一个连续值。

在深度学习模型中,层数包括输入层(逻辑上存在)、隐藏层(特征提取层)和输出层(生成预测结果)。在大多数框架中,输入层是隐式的,所以模型的“层数”通常只统计显式的隐藏层和输出层。

Dense 层可以同时作为 隐藏层输出层,它的角色取决于其在模型中的位置和任务。

  • 作为隐藏层:如果 Dense 层在模型的中间部分,用于进一步处理和转换特征,那么它就是隐藏层。例如,在一个深层神经网络中,前几层 Dense 层可以作为隐藏层,以提取输入数据的特征。

  • 作为输出层:如果 Dense 层是模型的最后一层,用于生成最终的输出(如分类概率或回归值),那么它就是输出层。例如,在分类任务中,最后一个 Dense 层通常会使用 softmax 激活函数作为输出层;在回归任务中,通常使用 linear 激活函数作为输出层。

上面提到的模型有 2 个显式的计算层(SimpleRNNDense):

  • 输入层(隐式):指定输入的形状 (time_step, 1),传入 SimpleRNN 层。
  • SimpleRNN 层:接收输入数据并生成 5 个隐藏状态的输出,作为时序特征。
  • Dense 输出层:接收 5 维的隐藏状态,将它转化为一个数值输出,用于回归任务。

--------------------------------------------------------------------------------------------------------------------------

1.4 训练模型

# 训练模型
model.fit(X, np.array(y), batch_size = 30, epochs = 200)

这一步使用 fit() 方法来训练模型,参数说明如下:

  • X:训练数据的输入特征。
  • y:训练数据的标签(目标值),这里先转换为 NumPy 数组 np.array(y)
  • batch_size=30:批量大小,每次更新模型权重时使用 30 个样本的数据,这样可以加快训练速度。
  • epochs=200:训练的轮数,将整个数据集训练 200 次,模型会在每个 epoch 后更新权重以逐步优化性能。

在训练过程中,模型会通过前向传播计算预测结果,通过反向传播调整权重,逐步减小预测值与真实值之间的误差。

在训练模型时,使用批量大小(batch_size=30)而不是全部样本进行权重更新,主要是为了在效率和性能上做出平衡。选择 batch_size=30,可以加快训练速度、减少内存占用,同时还可以引入一定的随机性,使得训练过程更稳定,减少陷入局部最优的风险。

------------------------------------------------------------------------------------------------------------------------------

1.5 基于训练数据做预测


# 基于训练数据做预测
y_train_predict = model.predict(X)*max(price) # 预测结果:去除归一化
y_train = [i * max(price) for i in y] # 训练数据真实结果

这部分代码进行基于训练数据的预测,并将预测结果“去归一化”,即将预测值和真实值还原到原始价格范围。详细说明如下:

  • y_train_predict:使用 model.predict(X) 基于训练数据 X 进行预测,得到归一化状态下的预测结果。之后通过 * max(price) 将预测结果恢复到原始数据范围,因为在数据预处理时可能将 price 归一化过,所以这里乘以 max(price) 还原到真实价格范围。

  • y_train:真实的训练数据 y 也被还原到原始数据范围。代码 [i * max(price) for i in y] 中,将归一化状态下的 y 乘以 max(price),以得到真实的训练数据价格。

tip:model.predict(X) 的详细过程

  1. 前向传播predict() 方法会将输入数据 X 逐层传递,通过网络结构中的每一层(如 RNN 层、Dense 层),并应用层中的权重和激活函数计算输出。

  2. 生成预测值:经过前向传播后,predict() 会输出每个输入样本的预测结果。这些结果的形状取决于模型的输出层结构。在你的模型中,输出层是一个 Dense 层,有一个神经元,所以 predict() 将返回每个输入样本的单一预测值。

--------------------------------------------------------------------------------------------------------------------------------

1.6 展示真实值和预测值

fig2 = plt.figure(figsize=(8, 5))
plt.plot(y_train, label='real price')
plt.plot(y_train_predict, label='predict price')
plt.title('close_price')  # 归一化之前的数据
plt.xlabel('time')
plt.ylabel('price')
plt.legend()
plt.show()

1.7 对测试数据进行预测

最后把测试数据放到刚才训练的模型,得到相应的预测值。

现预处理数据

# 对测试数据进行预测
data_test = pd.read_csv('zgpa_test.csv')
data_test.head()
price_test = data_test.loc[:, 'close']
price_test.head()

# extract X_test and y_test
price_test_norm = price_test/max(price)
X_test_norm, y_test_norm = extract_data(price_test_norm, time_step)
print(X_test_norm.shape, len(y_test_norm))

拿训练好的模型,做预测,并画图做对比,比较预测值和真实值:

# make prediction based on the test data
y_test_predict = model.predict(X_test_norm)*max(price)
y_test = [i*max(price) for i in y_test_norm]

fig3 = plt.figure(figsize=(8, 5))
plt.plot(y_test, label='real price_test')
plt.plot(y_test_predict, label='predict price_test')
plt.title('close_price')  # 归一化之前的数据
plt.xlabel('time')
plt.ylabel('price')
plt.legend() # 展示图例
plt.show()

把预测的数据存储起来:

# 存储数据
result_y_test = np.array(y_test).reshape(-1, 1) # 若干行,1列
result_y_test_predict = y_test_predict
print(result_y_test.shape, result_y_test_predict.shape)
result = np.concatenate((result_y_test, result_y_test_predict), axis=1)
print(result.shape)
result = pd.DataFrame(result, columns=['real_price_test', 'predict_price_test'])
result.to_csv('zgpa_predict_test.csv')

--------------------------------------------------------------------------------------------------------------------------------

1.8 pandas的一点知识点

(1) -1在reshape的应用 

这里提到了reshape(-1),那就讲一下其作用。reshape 中只能有一个 -1。如果有多个 -1,NumPy 无法确定数组的形状。当使用 -1 作为 reshape() 参数中的某个维度时,NumPy 会根据数组的总元素数量和指定的其他维度,自动计算 -1 所在维度的大小。举几个例子:

单独一个-1,将数组展平为一维数组。不论原数组的形状是什么,reshape(-1) 会将其拉平成一个一维向量。

arr = np.array([[1, 2, 3], [4, 5, 6]])
arr_reshaped = arr.reshape(-1)
print(arr_reshaped)

[1 2 3 4 5 6]

下面将数组转换为二维数组,其中有多行(具体行数由原数组长度决定),每行只有 1 列。-1 表示行数由系统自动计算,而 1 则指定了列数为 1。 

arr = np.array([1, 2, 3, 4, 5, 6])
arr_reshaped = arr.reshape(-1, 1)
print(arr_reshaped)

[[1][2][3][4][5][6]]

reshape(3, -1) 告诉 NumPy 重新将数组的形状调整为 3 行,而列数(-1)则由 NumPy 自动计算为 4,以确保元素总数(3x4=12)不变。 

arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])

arr_reshaped = arr.reshape(3, -1)
print(arr_reshaped)

[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]
(2) numpy中concatenate的应用 

把两个长度为n的一维array合并成一个二维shape为(n,2)的array,可以用以下两个方法:

1. 先把一维array用方法reshape(-1,1),转化成[[1][2][3][4][5][6]],这种格式,然后指定axis=1,在里面那层进行合并。

# 将一维数组转换为二维数组,每个数组为一列
# a = np.array([1,2,3,4,5])

a1 = a.reshape(-1, 1)
b1 = b.reshape(-1, 1)

# 按列方向(axis=1)合并成一个二维数组
result = np.concatenate((a1, b1), axis=1)

2. 或者直接使用np.column_stack()。 

result2 = np.column_stack((a,b))

1.9 总结

这个股票预测rnn模型的局限性:预测结果比实际结果趋势变化较慢。

 如上图所示,实际数据已经开始上升了,而预测的数据还在下降,并在下一个时间点上才开始上升。

2. LSTM:预测序列文字

任务:基于 flare 文本数据,建立 LSTM 模型,预测序列文字

1.完成数据预处理,将文字序列数据转化为可用于LSTM输入的数据

2.查看文字数据预处理后的数据结构,并进行数据分离操作

3.针对字符串输入(" flare is a teacher in ai industry. He obtained his phd in Australia."),预测其对应的后续字符

备注:模型结构:单层LSTM,输出有20个神经元:每次使用前20个字符预测第21个字符

2.1 数据预处理

加载文本数据,把换行符和制表符替换成空格。

# load the data
data = open('flare').read()
data = data.replace('\n','').replace('\r', '') # 替换换行符
print(data)

用set函数对字符数据进行处理,得到去重后的字符。

# 字符去重处理
letters = list(set(data))
print(letters)
num_letters = len(letters)
print(num_letters)           # 进行独热数值编码,23行1列的数组

#['A', 'o', 'c', 'h', 'l', 'm', 'p', '.', 's', 'S', ' ', 't', 'n', 'H', 'e', 'b', 'd', 'a', 'u', 'f', 'y', 'r', 'i']
23

利用for循环加上enumerate函数配合得到由序号、字符组成的字典。

# 建立字典
# int to char
int_to_char = {a:b for a,b in enumerate(letters)}
print(int_to_char)
# char to int
char_to_int = {b:a for a,b in enumerate(letters)}
print(char_to_int)

{0: 'A', 1: 'o', 2: 'c', 3: 'h', 4: 'l', 5: 'm', 6: 'p', 7: '.', 8: 's', 9: 'S', 10: ' ', 11: 't', 12: 'n', 13: 'H', 14: 'e', 15: 'b', 16: 'd', 17: 'a', 18: 'u', 19: 'f', 20: 'y', 21: 'r', 22: 'i'}
{'A': 0, 'o': 1, 'c': 2, 'h': 3, 'l': 4, 'm': 5, 'p': 6, '.': 7, 's': 8, 'S': 9, ' ': 10, 't': 11, 'n': 12, 'H': 13, 'e': 14, 'b': 15, 'd': 16, 'a': 17, 'u': 18, 'f': 19, 'y': 20, 'r': 21, 'i': 22}

设置time_step = 20,即用连续的20个字符预测第21个字符。

2.1.1 构建数据处理函数

然后构建能得到训练数据X、y的函数。

# time_step
time_step = 20

# 数据预处理
import numpy as np
from tensorflow.keras.utils import to_categorical # 库发生了迁移

# 滑动窗口提取数据
def extract_data(data, slide):
  x = []
  y = []
  for i in range(len(data) - slide):
    x.append([a for a in data[i : i + slide]])
    y.append(data[i+slide])
  return x,y

# 字符到数字的批量转化
def char_to_int_Data(x, y, chat_to_int):
  x_to_int = []
  y_to_int = []
  for i in range(len(x)):
    x_to_int.append([char_to_int[char] for char in x[i]])
    y_to_int.append([char_to_int[char] for char in y[i]])  
  return x_to_int, y_to_int

# 实现输入字符文章的批量处理,输入整个字符,滑动窗口大小,转化字典
def data_preprocessing(data, slide, num_letters, char_to_int):
  char_Data = extract_data(data, slide)  
  int_Data = char_to_int_Data(char_Data[0], char_Data[1], char_to_int)  
  Input = int_Data[0]
  Output = list(np.array(int_Data[1]).flatten())
  Input_RESHAPED = np.array(Input).reshape(len(Input), slide)
  new = np.random.randint(0, 10, size=[Input_RESHAPED.shape[0], Input_RESHAPED.shape[1], num_letters])  
  for i in range(Input_RESHAPED.shape[0]):
    for j in range(Input_RESHAPED.shape[1]):
      new[i, j, :] = to_categorical(Input_RESHAPED[i, j], num_classes = num_letters)  
  return new, Output

这里的函数比较复杂,最终data_preprocessing函数嵌套了之前构建的函数,最后要求传入文本数据,time_step(用多少个字符预测下一个), num_letters(文本数据中不重复字符个数), char_to_int(文本-序号字典)。

2.1.2 One-hot 编码

这里从tensorflow.keras.utils 模块中导入 to_categorical 函数。to_categorical 是一个工具函数,主要用于将整数编码的类别标签转换为 One-hot 编码 格式。

One-hot 编码是一种常用的编码方式,主要用于将类别数据转换为数值数据,使其可以用于机器学习或深度学习模型中。它的核心思想是使用一个向量表示每一个类别,其中只有一个位置是 1,其余位置是 0。这个唯一的 1 表示该类别的位置。

假设我们有 4 个类别:苹果香蕉橘子葡萄。我们可以为这 4 个类别进行 One-hot 编码:

类别One-hot 编码
苹果[1, 0, 0, 0]
香蕉[0, 1, 0, 0]
橘子[0, 0, 1, 0]
葡萄[0, 0, 0, 1]

--------------------------------------------------------------------------------------------------------------------------------

2.1.3 得到训练集、测试集

下面传入相应的参数,得到转化成数字的数据X,y。

X、y都只能是数字,其中X转化成了One-hot 编码,y转化成了字符-数字字典里字符对应的数字。

# extract X and y from text data
X, y = data_preprocessing(data, time_step, num_letters, char_to_int) # X 已经被独热编码,y 稍后处理

试着了解下得到的数据是什么样的。

print(X)       # 独热格式
print(X.shape) # 23 个映射

[[[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 1]]

 [[0 0 0 ... 0 0 0]
  [0 0 0 ... 0 0 0]
  [0 0 0 ... 0 1 0]
  ...

(44962, 20, 23)

print(len(y))

44962

首先看shape,这个文本有44962+20个字符,得到44962个组,后面对应的y是一个有44962个元素的列表,和X相对应。后面的(20,23)表示用20个字符来预测下一个字符,这20个字符每一个字符都是用的One-hot 编码来表示的。

大概是这个意思:X[0]得到的20*23二维矩阵,根据One-hot 编码中23个字符对应的位置,得到对应的字符,再用20个字符预测得到y[0],即y的第一个数字,对应的字符。(图里的字符只是举个例子。)

把刚才处理得到的44962组转化成数字类型数据,根据0.1的比例,分90%的数据给训练集,10%的数据给测试集。

# split the data
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=10)
print(X_train.shape, len(y_train))  

(40465, 20, 23) 40465

把刚才的y也转化成One-hot 编码。

y_train_category = to_categorical(y_train, num_letters)
print(y_train_category)

tip:刚才rnn也分了训练集和测试集,只不过lstm这个项目用一个文件按比例(9:1)拆成训练集和测试集,而rnn模型则是分别用两个文件当成训练集和测试集。 

2.2 构造模型 

和之前构建rnn模型类似,相似的内容不再赘述。

# set up the model
from keras.models import Sequential
from keras.layers import Dense, LSTM

model = Sequential()
model.add(LSTM(units=20, input_shape=(X_train.shape[1], X_train.shape[2]), activation='relu'))
model.add(Dense(units=num_letters, activation='softmax'))
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.summary()

这里指定的损失函数为categorical_crossentropy,这是多分类任务中常用的损失函数,用于 One-hot 编码格式的标签。 

metrics指定评估指标,评估指标用于在训练和评估时衡量模型的表现。accuracy准确率是最常用的分类评估指标之一,表示模型预测正确的样本占总样本的比例。在训练和验证过程中,模型会输出 accuracy 指标值,以便观察模型的分类性能。

2.3 训练模型

# train the model
model.fit(X_train, y_train_category, batch_size = 1000, epochs = 10)

模型在每次迭代时会从训练数据中随机抽取 1000 个样本进行训练,暂时先训练轮数为10。

2.4 利用模型进行预测(训练值)

# make prediction based on the training data
predict_x = model.predict(X_train)         # 笔者可能与视频使用的keras不是一个版本,故而有所更改
y_train_predict = np.argmax(predict_x, axis=1)  
print(y_train_predict)

 这里得到的predict_x是二维数组:

根据argmax函数,配合axis=1,找出第二层每个中括号中最大值的索引(从0开始)。 得到一维数组y_train_predict(40465):

 把数字数组根据之前的字典转化回字符:

# transform the int to letters
y_train_predict_char = [int_to_char[i] for i in y_train_predict]
print(y_train_predict_char)

计算下训练集的真实值和预测值的准确度: 

from sklearn.metrics import accuracy_score
accuracy_train = accuracy_score(y_train, y_train_predict)
print(accuracy_train)

2.5 测试集的预测 

方法和上面差不多,最后得到测试集的真实值和预测值的准确度。

predict_x = model.predict(X_test)         # 笔者可能与视频使用的keras不是一个版本,故而有所更改
y_test_predict = np.argmax(predict_x, axis=1)
accuracy_test = accuracy_score(y_test, y_test_predict)  
print(accuracy_test)
print(y_test_predict)
print(y_test)

2.6 用模型预测一段其他文本

拿一段另外的文本,用前二十个字符预测第21个字符,这段文本得保证里面的字符都包括在一开始得到的字符集合里。 

# 预测样例
new_letters = "flare is a teacher in ai industry. He obtained his phd in Australia."
X_new, y_new = data_preprocessing(new_letters, time_step, num_letters, char_to_int)
predict_x = model.predict(X_new)         # 笔者可能与视频使用的keras不是一个版本,故而有所更改
y_new_predict = np.argmax(predict_x, axis=1)
print(y_new_predict)

# transform the int to letters
y_new_predict_char = [int_to_char[i] for i in y_new_predict]
print(y_new_predict_char)

还是像之前的操作:用数据处理函数先得到X_new三维数组,用模型预测得到二位数组predict_x,然后用argmax配合axis=1得到一维数组y_new_predict,最后把用序号-字符字典把数组转化成字符组,得到预测值。

可以配合下面代码,返回的内容使得预测可视化更加合理:

for i in range(0, X_new.shape[0]-20):
  print(new_letters[i:i+20], '--predict next letter is--', y_new_predict_char[i])

得到结果如下:

如图,可以看到预测的结果不是很理想。可以再次训练模型,然后重复刚才2.6的操作:

# train the model
model.fit(X_train, y_train_category, batch_size = 1000, epochs = 10)

# 预测样例
new_letters = "flare is a teacher in ai industry. He obtained his phd in Australia."
X_new, y_new = data_preprocessing(new_letters, time_step, num_letters, char_to_int)
predict_x = model.predict(X_new)         # 笔者可能与视频使用的keras不是一个版本,故而有所更改
y_new_predict = np.argmax(predict_x, axis=1)
print(y_new_predict)

# transform the int to letters
y_new_predict_char = [int_to_char[i] for i in y_new_predict]
print(y_new_predict_char)

for i in range(0, X_new.shape[0]-20):
  print(new_letters[i:i+20], '--predict next letter is--', y_new_predict_char[i])

这次得到的结果就更加满意了:

 2.7 总结

总结一下rnn和lstm两个项目中,训练和预测用到的数据:

rnn:用一个文件做训练集,对模型进行训练;用另外一个文件直接拿来做预测。

lstm:将一个文件按9:1分成训练集和测试集;用另外一个文本拿来做预测。

 

 

 


http://www.kler.cn/a/378798.html

相关文章:

  • CSharp Ollama
  • 这款Chrome 插件,帮助我们复制网页上不能复制的内容
  • copyq禁止访问网络(ubuntu cgroup)
  • 杂货 | 每日资讯 | 2024.11.1
  • 江协科技STM32学习- P34 I2C通信外设
  • SpringMVC笔记 一万字
  • 关于使用K8s实现容器化作业的总时效最优调度
  • 【设计模式】结构型模式(一):适配器模式、装饰器模式
  • 爬虫技术——小白入狱案例
  • “灵境·石景山杯”数字文旅创新大赛晋级名单
  • 路由策略与路由控制
  • CNN-Attention分类预测 | Matlab实现多特征分类预测
  • qt QBrush详解
  • R 语言科研配色 --- 第 9 期
  • 基于SSM的在线作业管理系统 -octopus-master(源码+调试)
  • Go语言有哪些数据类型?
  • Java集合使用注意事项总结
  • 数据结构之二叉树--前序,中序,后序详解(含源码)
  • oracle如何在不同业务场景下正确使用聚合查询、联合查询及分组查询?
  • 使用Java实现机器学习:一个入门指南
  • JS中DOM和BOM
  • Linux常用基本指令和shell
  • RK3568平台开发系列讲解(内存篇)Linux 内存优化
  • wordpress调用指定ID分类内容 并判断第一个与其它输出不同
  • 2025年PMP考试的3A好考吗?
  • YOLO系列再创新高:迎接YOLO11的到来!