从零到一搭建AI诗人:深度解读RNN循环神经网络与古诗生成实战
告别机械化的“硬语言”,让AI学会创作中国古诗
前言
计算机能够理解“硬语言”——编程语言的语法规则是确定的、无歧义的,编译器可以按照机械化的规则解析每一行代码的含义。然而,当我们试图让计算机理解汉语或英语这样的“软语言”时,传统方法便捉襟见肘了。汉语的含义和形式灵活多变,新词层出不穷,同一个词语在不同语境下可能表达截然不同的意思。
如何让计算机不仅理解语言,还能像人类一样“创作”语言?这正是本文要深入探讨的核心问题。
一、自然语言处理:让计算机“学会”人类语言
1.1 什么是自然语言处理
自然语言处理(Natural Language Processing, NLP)的目标是让计算机理解人类语言,进而完成对人类有帮助的事情。与编程语言的“硬”特性不同,自然语言是一种“软语言”——它的含义和形式会灵活变化,并且会不断出现新的词语或新的含义。这让NLP成为人工智能领域最具挑战性也最富有魅力的方向之一。
要让计算机理解自然语言,使用常规方法是无法办到的。传统的前馈神经网络假设输入之间相互独立,对于文本这种具有内在序列结构的数据,显得力不从心。
1.2 词表示方法的演进
在深入RNN之前,我们需要先理解一个核心问题:计算机如何“表示”一个词的语义?
(1)基于同义词词典的方法
早期NLP采用构建同义词词典的方式。通过将同义词或近义词归入同一类别,并根据“整体-部分”或“上位-下位”关系构建层级的树状图,形成一个庞大的“单词网络”,以此教会计算机单词之间的关系,从而计算出单词的“相似度”。
这种方法存在明显缺陷:
-
需要人工逐个定义单词之间的相关性,费时费力;
-
新词不断出现,语言不断变化,词典维护成本极高;
-
表现力有限,难以覆盖语言的丰富性。
(2)基于计数的方法
随着大数据时代的到来,研究人员开始从海量文本语料中自动提取语言的“本质”。最基础的做法就是统计“词频”:
- 分词
:对文本内容进行切分,找出基本单元;
- 词关联ID
:为每个单词分配唯一ID,构建“词表”;
- 词向量化
:用固定长度的向量表示单词,也称为词的“分布式表示”。
具体做法是:统计每个词周围出现了哪些词、出现了多少次(称为“上下文”),将这些词频统计结果构成向量,这个向量就可以表示当前词,称为“词向量”(word vector)。所有词对应的向量汇总起来形成一个矩阵,被称为“共现矩阵”(co-occurrence matrix)。
然而,这种方法对所有词进行向量化表示的计算复杂度极高,难以在大规模语料上实用。
(3)基于推理的方法
基于推理的方法另辟蹊径:希望在已知上下文的前提下,“推测”当前位置的词是什么。利用神经网络接收上下文信息作为输入,通过模型计算,输出各个单词可能出现的概率,从而根据上下文预测该出现的单词。这正是Word2Vec等现代词嵌入技术的核心思想。
1.3 词嵌入:自然语言的向量化革命
词嵌入(Word Embedding)是将词映射到向量的技术,也是让计算机“理解”单词含义的关键一步。词向量是用于表示单词意义的向量,可以看作词的特征向量。
为什么词嵌入比传统方法更优?传统词袋模型存在三大缺陷:
- 高维稀疏性
:词汇表规模达数十万时,向量维度爆炸且90%以上元素为0;
- 语义缺失
:无法捕捉词语之间的语义关联性;
- 词序忽略
:完全丢失“狗咬人”与“人咬狗”的语义差异。
而词嵌入将词映射为稠密、低维的连续向量,使语义相近的词在向量空间中距离更近。以五维词向量为例,每个词都用一串浮点数表示:
|
词 |
词向量 |
|
你 |
[0.3307, 0.4814, 1.4244, -0.3161, 0.0859] |
|
我 |
[0.9491, -0.1030, 2.5101, 0.1955, -0.0147] |
|
他 |
[0.2709, -0.2052, -0.6052, -0.5227, 0.9971] |
另一种表示方式是独热向量(one-hot vector)。独热向量很容易构建,但它不是一个好的选择:
-
任意两个不同词的独热向量之间的余弦相似度为0,无法编码词之间的相似性;
-
随着词汇量的增大,独热向量的大小会线性增长,消耗大量存储与计算资源。
二、RNN的数学原理与架构解析
2.1 为什么需要RNN
文本是连续的,具有序列特性——词序的改变往往意味着意义的根本变化。比如“狗咬人”和“人咬狗”表达的是完全不同的意思。
然而,前馈型神经网络(feedforward neural network)假设输入之间相互独立,信息仅在一个方向上传播:从输入层到隐藏层再到输出层。虽然这种网络结构简单易懂,但它有一个致命问题——不能很好地处理时间序列数据。更确切地说,单纯的前馈网络无法充分学习时序数据中蕴含的依赖关系。
2.2 RNN的核心原理
循环神经网络(Recurrent Neural Network, RNN)专门设计用于识别序列数据中的模式,其核心在于循环连接机制:每个时间步的输出不仅依赖于当前输入,还依赖于前一个时间步的隐藏状态(Hidden State)。
RNN层具有环路,通过这个环路,数据可以在层内循环传递。向时序数据 $(x_0, x_1, \dots, x_t)$ 输入层中,相应的会输出 $(h_0, h_1, \dots, h_t)$。

将RNN的环路按时间步展开后,可以看到:
-
各个时刻的RNN层接收当前输入 $x_t$ 和前一时刻的输出 $h_{t-1}$(隐藏状态);
-
根据这两部分信息计算当前时刻的输出 $h_t$。
核心数学公式:
ht=tanh(ht−1Wh+xtWx+b)ht=tanh(ht−1Wh+xtWx+b)
其中:
-
$h_t$ 是当前时刻的隐藏状态(相当于网络的“记忆”);
-
$x_t$ 是当前时刻的输入向量;
-
$W_h$ 是与前一时刻隐藏状态运算的权重矩阵;
-
$W_x$ 是与当前输入运算的权重矩阵;
-
$b$ 是偏置项;
-
$\tanh$ 是激活函数,输出范围在[-1, 1]之间。
RNN层的输出 $h_t$ 既作为当前时刻的输出,又传递给下一时刻作为“记忆”。这种设计让RNN能够“记住”之前的信息,并用这些信息来影响当前时间步的输出。
2.3 RNN的参数共享机制
RNN的一个关键特性是参数共享:在不同时间步之间,模型使用相同的权重矩阵 $W_h$ 和 $W_x$。这意味着无论序列有多长,模型的总参数量保持不变。这种设计显著减少了模型复杂度,并确保模型能够处理任意长度的序列。
2.4 RNN的局限性
传统RNN并非完美无缺。在处理长序列时,RNN面临两个核心问题:
- 梯度消失
:当序列很长时,通过时间反向传播(BPTT)的梯度会逐渐衰减,导致远距离依赖信息无法有效传递,模型难以捕捉长期依赖关系;
- 梯度爆炸
:在反向传播过程中,梯度可能指数级增长,导致网络权重不稳定,训练难以收敛。
为了解决这些问题,研究人员提出了LSTM(长短期记忆网络)和GRU(门控循环单元)等改进架构。LSTM通过引入遗忘门、输入门和输出门三个门控机制来控制信息流,同时维护独立的“细胞状态”以存储长期信息。GRU则是LSTM的简化版本,将输入门和遗忘门合并为“更新门”,参数量更少、训练更快。
三、RNN的PyTorch实现
3.1 torch.nn.RNN API详解
在PyTorch中,torch.nn.RNN类用于构建循环神经网络。其关键参数如下:
|
参数 |
含义 |
默认值 |
|
input_size |
输入特征的数量 |
必填 |
|
hidden_size |
隐藏层的特征数量 |
必填 |
|
num_layers |
RNN的层数(堆叠层数) |
1 |
|
nonlinearity |
激活函数类型,可选'tanh'或'relu' |
'tanh' |
|
batch_first |
是否将batch_size放在输入张量的第一位 |
False |
|
dropout |
除最后一层外各层应用dropout的概率 |
0 |
|
bidirectional |
是否使用双向RNN |
False |
调用方式:
import torch
import torch.nn as nn
# 初始化RNN层
rnn = nn.RNN(input_size=8, hidden_size=16, num_layers=2)
# 准备输入数据
# input的形状: [seq_len, batch_size, input_size]
input = torch.rand(1, 3, 8) # 序列长度1,批量大小3,特征数8
# 初始化隐藏状态
# hx的形状: [num_layers, batch_size, hidden_size]
hx = torch.randn(2, 3, 16) # 2层RNN,批量大小3,隐藏维度16
# 前向传播
output, hn = rnn(input=input, hx=hx)
print(output.shape) # torch.Size([1, 3, 16]) 输出序列
print(hn.shape) # torch.Size([2, 3, 16]) 最终隐藏状态
参数解释:
-
num_layers=2表示堆叠两个RNN层,第二个RNN接收第一个RNN的输出并计算最终结果;
-
当batch_first=False(默认)时,输入形状为(seq_len, batch_size, input_size);设置batch_first=True后,形状变为(batch_size, seq_len, input_size);
-
输出output包含每个时间步的隐藏状态,形状与输入序列长度对应;hn只保留最后一个时间步的隐藏状态。
3.2 词嵌入层详解
在将文本输入RNN之前,需要先将文字转换为数值向量。PyTorch提供了torch.nn.Embedding模块来实现词嵌入:
embed = nn.Embedding(num_embeddings=len(vocab), embedding_dim=embedding_dim)
-
num_embeddings:词表的大小(词汇量);
-
embedding_dim:词向量的维度,即每个词被映射成的向量长度。
词嵌入矩阵实际上是一个可训练的参数矩阵,形状为[num_embeddings, embedding_dim]。通过词索引查表即可获得对应的词向量:
word_vec = embed(torch.tensor(idx)) # 通过索引获取词向量
四、实战案例:基于RNN的古诗生成器
理论部分讲完了,接下来我们用PyTorch完整实现一个古诗生成模型。这个项目将串联前面讲解的所有知识点:文本预处理→词嵌入→RNN序列建模→模型训练→文本生成。
4.1 数据预处理
数据预处理是整个项目的基石。我们需要将原始的诗歌文本转换成模型可以处理的数值形式。
import torch
import torch.nn as nn
import jieba
import re
from torch.utils.data import Dataset, DataLoader
import torch.optim as optim
def process_poems(file_path):
"""
古诗数据预处理函数
Args:
file_path: 古诗文件路径
Returns:
sequences: 每首诗转换后的索引序列列表
word2idx: 词到索引的映射字典
vocab: 词表列表
"""
poems = [] # 保存处理后的诗(字符列表形式)
char_set = set() # 保存所有不重复的字
with open(file_path, "r", encoding="utf-8") as f:
for line in f:
# 逐行处理:去掉标点符号与两侧空白
# 这里我们去掉常见的标点符号:逗号、句号、问号、感叹号、冒号
line = re.sub(r"[,。、?!:]", "", line).strip()
# 按字分割并添加到字符集合中(用于构建词表)
char_set.update(list(line))
# 按字符存储(保留顺序)
poems.append(list(line))
# 构建词表:所有不重复的字符 + 未知词标记<UNK>
vocab = list(char_set) + ["<UNK>"]
# 创建词到索引的映射字典
word2idx = {word: idx for idx, word in enumerate(vocab)}
# 将每首诗转换为索引序列
sequences = []
for poem in poems:
seq = [word2idx.get(word, word2idx["<UNK>"]) for word in poem]
sequences.append(seq)
return sequences, word2idx, vocab
# 调用预处理函数
sequences, word2idx, vocab = process_poems("data/poems.txt")
数据集下载:https://pan.baidu.com/s/13qx0ximJZUTX8HWQ-kd7AA?pwd=7spw
代码解读:
-
首先读取诗歌文件,逐行处理;
-
使用正则表达式re.sub删除所有中文标点符号;
-
将每首诗按字符分割成列表,同时收集所有不重复的字符构建词表;
-
添加<UNK>标记用于处理训练集中未出现的新词;
-
最终输出索引序列,便于模型读取。
4.2 构建训练数据集
对于语言模型任务,我们需要构建“输入-目标”对:给定前seq_len个字符作为输入,预测下一个字符作为目标。
例如,对于诗句“兰叶春葳蕤桂华秋皎洁欣欣此生意自尔为佳节谁知林栖”,如果设定seq_len=24:
- 输入
:前24个字符“兰叶春葳蕤桂华秋皎洁欣欣此生意自尔为佳节谁知林栖”
- 目标
:后24个字符“叶春葳蕤桂华秋皎洁欣欣此生意自尔为佳节谁知林栖者”
class PoetryDataset(Dataset):
"""
自定义诗歌数据集
继承自torch.utils.data.Dataset,实现__len__和__getitem__方法
"""
def __init__(self, sequences, seq_len):
"""
Args:
sequences: 所有诗的索引序列列表
seq_len: 序列长度(每个训练样本包含的字符数)
"""
self.seq_len = seq_len
self.data = []
# 对每首诗,滑动窗口生成训练样本
for seq in sequences:
for i in range(0, len(seq) - self.seq_len):
# 输入:从i开始的seq_len个字符
# 目标:从i+1开始的seq_len个字符(即预测下一个字符)
self.data.append((seq[i:i+self.seq_len], seq[i+1:i+1+self.seq_len]))
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
x = torch.LongTensor(self.data[idx][0])
y = torch.LongTensor(self.data[idx][1])
return x, y
# 创建数据集实例,序列长度设为24
dataset = PoetryDataset(sequences, 24)
4.3 搭建RNN模型
模型架构采用经典的三层结构:词嵌入层 → RNN层 → 全连接层。
class PoetryRNN(nn.Module):
"""
基于RNN的古诗生成模型
架构:词嵌入层 -> RNN层 -> 全连接输出层
"""
def __init__(self, vocab_size, embedding_dim=128, hidden_size=256, num_layers=1):
"""
Args:
vocab_size: 词表大小(词汇量)
embedding_dim: 词嵌入维度,将每个词映射为embedding_dim维向量
hidden_size: RNN隐藏层维度
num_layers: RNN堆叠层数
"""
super().__init__()
# 1. 词嵌入层:将词索引转换为稠密向量
# 形状变换:[batch, seq_len] -> [batch, seq_len, embedding_dim]
self.embed = nn.Embedding(
num_embeddings=vocab_size,
embedding_dim=embedding_dim
)
# 2. RNN层:处理序列数据,捕捉时序依赖关系
self.rnn = nn.RNN(
input_size=embedding_dim, # 输入特征数 = 词嵌入维度
hidden_size=hidden_size, # 隐藏状态维度
num_layers=num_layers # RNN堆叠层数
)
# 3. 全连接层:将RNN输出映射为词表大小的概率分布
# 形状变换:[seq_len, batch, hidden_size] -> [seq_len, batch, vocab_size]
self.linear = nn.Linear(
in_features=hidden_size,
out_features=vocab_size
)
def forward(self, input, hx=None):
"""
前向传播
Args:
input: 输入序列,形状 [seq_len, batch_size]
hx: 初始隐藏状态,形状 [num_layers, batch_size, hidden_size]
Returns:
output: 输出概率分布,形状 [seq_len, batch_size, vocab_size]
hidden: 最终隐藏状态,形状 [num_layers, batch_size, hidden_size]
"""
# Step 1: 词嵌入
embed = self.embed(input) # [seq_len, batch, embedding_dim]
# Step 2: RNN处理
output, hidden = self.rnn(embed, hx) # output: [seq_len, batch, hidden_size]
# Step 3: 全连接层输出
output = self.linear(output) # [seq_len, batch, vocab_size]
return output, hidden
# 设备配置:优先使用GPU加速
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"当前使用设备: {device}")
# 实例化模型
model = PoetryRNN(
vocab_size=len(vocab), # 词表大小
embedding_dim=256, # 词嵌入维度
hidden_size=512, # 隐藏层维度
num_layers=2 # RNN层数
).to(device)
模型架构解读:
- 词嵌入层
:将离散的词索引转换为连续的稠密向量,让模型能够学习词之间的语义关系;
- RNN层
:核心序列处理模块,通过循环连接保持“记忆”,捕捉诗歌中的韵律和语义依赖;
- 全连接层
:将RNN的输出映射为词表大小的向量,经过softmax后即为各词的概率分布。
4.4 模型训练
训练语言模型本质上是一个多分类任务:在每个时间步,模型需要从整个词表中选择正确的下一个词。
def train(model, dataset, lr, epoch_num, batch_size, device):
"""
模型训练函数
Args:
model: 待训练的模型
dataset: 训练数据集
lr: 学习率
epoch_num: 训练轮数
batch_size: 批量大小
device: 计算设备(CPU/GPU)
"""
model.train() # 设置为训练模式(启用dropout等)
# 创建数据加载器,自动进行批次划分和随机打乱
dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)
# 损失函数:交叉熵损失
# 适用于多分类问题,内部结合了LogSoftmax和NLLLoss
loss_fn = nn.CrossEntropyLoss()
# 优化器:Adam
# Adam结合了动量和自适应学习率的优点,是深度学习的默认选择
optimizer = optim.Adam(model.parameters(), lr=lr)
for epoch in range(epoch_num):
loss_accumulate = 0 # 累加当前epoch的损失
for batch_count, (x, y) in enumerate(dataloader):
# 将数据移动到指定设备
x, y = x.to(device), y.to(device)
# x.shape: [batch, seq_len]
# y.shape: [batch, seq_len]
# ----- 前向传播 -----
# 需要将x转置为[seq_len, batch]格式(因为RNN默认batch_first=False)
output, _ = model(x.transpose(0, 1))
# output.shape: [seq_len, batch, vocab_size]
# ----- 计算损失 -----
# CrossEntropyLoss期望输入形状为[batch, vocab_size]或[seq_len*batch, vocab_size]
# 因此将output转置为[batch, seq_len, vocab_size]再计算
loss_value = loss_fn(output.transpose(0, 1).transpose(1, 2), y)
# ----- 反向传播 -----
optimizer.zero_grad() # 清空梯度
loss_value.backward() # 计算梯度
optimizer.step() # 更新参数
# 累加损失用于监控
loss_accumulate += loss_value.item()
# 打印训练进度
print(f"Epoch {epoch:02d} | Loss: {loss_accumulate/len(dataloader):.6f}")
# 开始训练
train(
model=model,
dataset=dataset,
lr=1e-3, # 学习率
epoch_num=20, # 训练20轮
batch_size=32, # 批量大小
device=device
)
训练细节解析:
- 交叉熵损失
(CrossEntropyLoss):衡量模型预测的概率分布与真实标签分布之间的差异。在分类问题中,交叉熵损失能够准确反映模型的预测质量。
- Adam优化器
:Adam能够根据训练过程动态调整学习率——训练初期梯度噪声较大时进行较大幅度调整,训练稳定后进行精细微调。这使Adam成为深度学习的首选优化器。
- 维度转置
:由于RNN默认batch_first=False,输入需要是[seq_len, batch]格式,因此调用x.transpose(0, 1)进行转置。
4.5 文本生成
模型训练完成后,就可以让它“创作”诗歌了。生成过程采用自回归方式:每生成一个字符后,将其作为输入继续生成下一个字符,直到达到预设长度。
def generate_poem(model, word2idx, vocab, start_token, line_num=4, line_length=7):
"""
生成古诗
Args:
model: 训练好的模型
word2idx: 词到索引的映射
vocab: 词表
start_token: 起始字符
line_num: 生成的行数
line_length: 每行诗句的字数
Returns:
生成的诗句字符串
"""
model.eval() # 设置为评估模式(禁用dropout和batch norm)
poem = [] # 记录生成结果
current_line_length = line_length # 当前句剩余需要生成的字符数
# 获取起始字符的索引
start_idx = word2idx.get(start_token, word2idx["<UNK>"])
# 如果起始字符在词典中,添加到结果列表
if start_idx != word2idx["<UNK>"]:
poem.append(vocab[start_idx])
current_line_length -= 1
# 初始化输入张量和隐藏状态
input_tensor = torch.LongTensor([[start_idx]]).to(device) # [1, 1]
hidden = None # 初始隐藏状态为None,RNN内部会自动初始化为全零
with torch.no_grad(): # 禁用梯度计算,加速推理并节省显存
for _ in range(line_num): # 遍历每一行
for _ in range(2): # 每行两句
while current_line_length > 0: # 生成一句中的每个字
# 前向传播
output, hidden = model(input_tensor, hidden)
# output.shape: [1, 1, vocab_size]
# 计算概率分布并采样
# squeeze(0)去掉序列维度,softmax转换为概率
prob = torch.softmax(output[0, 0], dim=-1)
# 从概率分布中随机采样(增加生成多样性)
next_token = torch.multinomial(prob, 1)
# 记录生成的字符
poem.append(vocab[next_token.item()])
# 更新输入为刚生成的字符
input_tensor = next_token.unsqueeze(0) # [1, 1]
current_line_length -= 1
# 一句结束,重置计数器并添加标点
current_line_length = line_length
poem.append(",") # 单句结尾添加逗号
poem.append("\n") # 每行结束后换行
# 注意:这里需要重置current_line_length,但上面已经重置了
# 将列表转换为字符串并返回
return "".join(poem)
# 测试生成
generated_poem = generate_poem(
model, word2idx, vocab,
start_token="春", # 以"春"字开篇
line_num=4, # 生成4行
line_length=7 # 每行7字(七言绝句)
)
print(generated_poem)
生成策略解析:
- 自回归生成
:模型每次只预测下一个字符,然后将预测结果作为下一时间步的输入,如此循环直至生成完整诗歌;
- 随机采样
:使用torch.multinomial从概率分布中随机采样,而非总是选择概率最高的字符。这样做可以增加生成结果的多样性,避免重复输出同一内容;
- 温度系数调优
(可选改进):在实际应用中,可以通过softmax(logits / temperature)来控制生成的“创造性”。temperature越高,生成结果越多样(但也可能更不连贯);temperature越低,生成结果越保守(但也可能更稳定)。
五、进阶优化方向
5.1 使用LSTM/GRU替代标准RNN
前文提到,标准RNN存在梯度消失问题。一个简单的改进是用LSTM或GRU替换RNN层:
# 使用LSTM替代RNN
self.lstm = nn.LSTM(
input_size=embedding_dim,
hidden_size=hidden_size,
num_layers=num_layers
)
# 或使用GRU(更轻量,训练更快)
self.gru = nn.GRU(
input_size=embedding_dim,
hidden_size=hidden_size,
num_layers=num_layers
)
LSTM vs GRU 选择指南:
- LSTM
:通过遗忘门、输入门和输出门三个门控机制控制信息流,并维护独立的细胞状态,能够稳定捕捉长距离依赖,适合长序列任务;
- GRU
:LSTM的简化版本,合并输入门和遗忘门为更新门,参数量减少约25-30%,训练速度快30-40%,在多数任务上性能与LSTM相当。
5.2 双向RNN
如果任务需要同时利用前文和后文信息(如命名实体识别),可以使用双向RNN:
self.rnn = nn.RNN(
input_size=embedding_dim,
hidden_size=hidden_size,
num_layers=num_layers,
bidirectional=True # 启用双向
)
# 注意:bidirectional=True时,hidden_size会翻倍
5.3 模型调优技巧
- 增加模型深度
:通过增加num_layers参数,堆叠多层RNN可以增强模型的表达能力;
- 使用Dropout正则化
:在RNN层间添加dropout防止过拟合;
- 梯度裁剪
:使用torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=5)防止梯度爆炸;
- 学习率调度
:使用torch.optim.lr_scheduler在训练过程中动态调整学习率。
六、总结
本文从自然语言处理的基础概念出发,系统讲解了词嵌入技术和循环神经网络(RNN)的核心原理,并完整实现了一个基于PyTorch的古诗生成系统。总结要点如下:
1. 词嵌入是NLP的基石。相比传统独热编码,稠密词向量能够捕捉词语间的语义相似性,是实现计算机“理解”语言的关键技术。
2. RNN通过循环机制解决序列建模问题。其核心公式 $h_t = \tanh(h_{t-1}W_h + x_tW_x + b)$ 精妙地实现了信息的传递与记忆。尽管存在梯度消失/爆炸的局限性,但RNN及其变体LSTM、GRU仍是序列处理任务的基石。
3. 古诗生成是一个经典的序列生成任务。通过“词嵌入层 → RNN层 → 全连接层”的标准架构,配合滑动窗口构建训练样本,可以训练出具有一定创作能力的“AI诗人”。
4. 自回归生成策略与随机采样是文本生成的核心技巧,在保证语义连贯性的同时增加了生成结果的多样性。
随着大模型时代的到来,Transformer架构凭借其并行计算能力和全局依赖捕捉能力,在许多NLP任务中取代了RNN。但RNN轻量、高效、易于理解的特点,使其在教育、边缘计算和资源受限场景中依然具有不可替代的价值。理解RNN的原理,也为学习更复杂的Transformer模型打下了坚实的基础。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)