[AI趣事]让AI成为"文学创作大师":生成式网络的创作魔法 5-17 终极篇
嗨,各位AI探索者!
还记得小时候玩的”接龙游戏”吗?一个人说”从前有座山”,下一个人接”山上有座庙”,就这样一句接一句编故事。今天我们要教AI玩这个游戏,而且它比我们玩得还要好!
🎭 从”理解”到”创作”的华丽转身
之前我们做了什么?
# 之前的AI:只会"看"文章分类
input_text = "苹果公司股价大涨"
ai_classifier = "这是财经新闻!" # 只会判断,不会创作
现在AI能做什么?
# 现在的AI:会"写"文章
prompt = "苹果公司股价"
ai_generator = "苹果公司股价大涨,投资者纷纷看好其新产品发布会带来的利好消息..."
# 能续写,能创作!
就像从”只会读书”的学霸变成了”能写小说”的作家!
🎯 RNN的四种”创作模式”
图:RNN的四种工作模式,展示不同的输入输出组合
1. One-to-One:传统翻译官
# 一个输入,一个输出
image = "一张猫的照片"
result = "这是一只猫" # 图像分类
2. One-to-Many:故事创作家
# 一个灵感,一篇文章
seed = "科技"
story = ["科", "技", "改", "变", "生", "活", "..."] # 展开成完整故事
3. Many-to-One:总结大师
# 一篇文章,一个观点
long_article = ["今天", "天气", "很好", "..."]
summary = "天气报告" # 就是我们之前做的分类
4. Many-to-Many:翻译专家
# 中文转英文
chinese = ["我", "爱", "编程"]
english = ["I", "love", "programming"]
🎨 字符级创作:从字母开始的艺术
为什么从字符开始?
想象AI是个刚学写字的小朋友:
# 词级生成:需要知道10万个词汇
word_vocab = ["苹果", "香蕉", "葡萄", ...] # 词汇量巨大
# 字符级生成:只需要26个字母+标点
char_vocab = ['a', 'b', 'c', ..., 'z', '.', '!', '?'] # 简单很多!
构建字符词典
import torch
import collections
def build_char_vocab(texts):
"""构建字符级词典"""
counter = collections.Counter()
# 统计所有字符出现频率
for text in texts:
counter.update(list(text)) # 按字符分割
# 构建词典
vocab = {char: idx for idx, char in enumerate(counter.keys())}
vocab['<eos>'] = len(vocab) # 结束标记
return vocab
# 示例
texts = ["Hello world!", "AI is amazing!"]
char_vocab = build_char_vocab(texts)
print(f"字符词典大小: {len(char_vocab)}")
print(f"'H'的编码: {char_vocab['H']}")
🏗️ 生成式RNN的训练秘籍
训练数据的制作
图:以”HELLO”为例展示RNN如何逐字符生成文本
def create_training_data(text, seq_length=10):
"""
创建训练用的输入-输出对
例如:"HELLO WORLD" →
输入:["H","E","L","L","O"," ","W","O","R","L"]
输出:["E","L","L","O"," ","W","O","R","L","D"]
"""
inputs = []
outputs = []
for i in range(len(text) - seq_length):
# 输入:当前位置开始的序列
input_seq = text[i:i + seq_length]
# 输出:向后偏移一位的序列
output_seq = text[i + 1:i + seq_length + 1]
inputs.append(input_seq)
outputs.append(output_seq)
return inputs, outputs
# 示例
text = "Hello, AI world!"
inputs, outputs = create_training_data(text, 5)
print("训练样本:")
for inp, out in zip(inputs[:3], outputs[:3]):
print(f"输入: '{inp}' → 输出: '{out}'")
LSTM生成器模型
class LSTMGenerator(torch.nn.Module):
def __init__(self, vocab_size, hidden_dim=128, num_layers=2):
super().__init__()
self.vocab_size = vocab_size
self.hidden_dim = hidden_dim
self.num_layers = num_layers
# 多层LSTM
self.lstm = torch.nn.LSTM(
vocab_size, hidden_dim,
num_layers=num_layers,
batch_first=True,
dropout=0.2
)
# 输出层:隐藏状态 → 字符概率
self.output = torch.nn.Linear(hidden_dim, vocab_size)
def forward(self, x, hidden=None):
# 字符ID → one-hot编码
x = torch.nn.functional.one_hot(x, self.vocab_size).float()
# LSTM处理
lstm_out, hidden = self.lstm(x, hidden)
# 输出概率分布
output = self.output(lstm_out)
return output, hidden
# 创建模型
vocab_size = len(char_vocab)
model = LSTMGenerator(vocab_size, hidden_dim=256, num_layers=3)
print(f"模型参数数量: {sum(p.numel() for p in model.parameters())}")
🎲 “硬”生成 vs “软”生成
硬生成:完美主义者
def generate_hard(model, start_text, length=100):
"""
硬生成:总是选择概率最高的字符
"""
model.eval()
chars = list(start_text)
hidden = None
# 处理起始文本
for char in start_text:
char_tensor = torch.tensor([[char_vocab[char]]])
output, hidden = model(char_tensor, hidden)
# 生成新字符
for _ in range(length):
# 选择概率最高的字符
next_char_idx = torch.argmax(output[0, -1]).item()
next_char = idx_to_char[next_char_idx]
chars.append(next_char)
# 继续生成
char_tensor = torch.tensor([[next_char_idx]])
output, hidden = model(char_tensor, hidden)
return ''.join(chars)
# 硬生成示例
generated_text = generate_hard(model, "Today is", 50)
print(f"硬生成: {generated_text}")
软生成:艺术创作家
def generate_soft(model, start_text, length=100, temperature=1.0):
"""
软生成:根据概率分布随机采样
temperature控制随机性
"""
model.eval()
chars = list(start_text)
hidden = None
# 处理起始文本
for char in start_text:
char_tensor = torch.tensor([[char_vocab[char]]])
output, hidden = model(char_tensor, hidden)
# 生成新字符
for _ in range(length):
# 应用温度参数
logits = output[0, -1] / temperature
probs = torch.softmax(logits, dim=0)
# 多项式采样
next_char_idx = torch.multinomial(probs, 1).item()
next_char = idx_to_char[next_char_idx]
chars.append(next_char)
char_tensor = torch.tensor([[next_char_idx]])
output, hidden = model(char_tensor, hidden)
return ''.join(chars)
# 不同温度的效果
temperatures = [0.3, 0.8, 1.0, 1.5, 2.0]
for temp in temperatures:
text = generate_soft(model, "AI is", 30, temperature=temp)
print(f"温度{temp}: {text}")
温度参数的魔法
# 温度 = 0.1: 保守派
"AI is a powerful tool for solving complex problems..."
# 几乎总是选最可能的字符,文本很规整但可能重复
# 温度 = 1.0: 平衡派
"AI is amazing and can help us in many ways..."
# 平衡的随机性,既有逻辑又有创意
# 温度 = 2.0: 疯狂派
"AI is xqz!@# random text here..."
# 高度随机,可能产生无意义文本
🚀 完整训练流程
def train_generator(model, train_data, epochs=10):
"""完整的生成器训练流程"""
optimizer = torch.optim.Adam(model.parameters(), lr=0.002)
criterion = torch.nn.CrossEntropyLoss()
for epoch in range(epochs):
model.train()
total_loss = 0
for batch_idx, (inputs, targets) in enumerate(train_data):
optimizer.zero_grad()
# 前向传播
outputs, _ = model(inputs)
# 计算损失
loss = criterion(
outputs.view(-1, vocab_size),
targets.view(-1)
)
# 反向传播
loss.backward()
# 梯度裁剪,防止梯度爆炸
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
optimizer.step()
total_loss += loss.item()
# 每1000步输出一次生成样本
if batch_idx % 1000 == 0:
sample_text = generate_soft(model, "Today", 50)
print(f"Epoch {epoch}, Step {batch_idx}: {sample_text}")
avg_loss = total_loss / len(train_data)
print(f"Epoch {epoch}: Average Loss = {avg_loss:.4f}")
# 训练模型
train_generator(model, train_loader, epochs=20)
🔧 高级优化技巧
1. 数据预处理优化
class TextDataset(torch.utils.data.Dataset):
def __init__(self, texts, vocab, seq_length=100):
self.vocab = vocab
self.seq_length = seq_length
# 将所有文本合并成一个大字符串
self.text = '\n'.join(texts)
self.chars = [vocab[c] for c in self.text if c in vocab]
def __len__(self):
return len(self.chars) - self.seq_length
def __getitem__(self, idx):
# 返回输入序列和目标序列
input_seq = torch.tensor(self.chars[idx:idx + self.seq_length])
target_seq = torch.tensor(self.chars[idx + 1:idx + self.seq_length + 1])
return input_seq, target_seq
# 使用数据集
dataset = TextDataset(train_texts, char_vocab, seq_length=50)
dataloader = torch.utils.data.DataLoader(dataset, batch_size=32, shuffle=True)
2. 学习率调度
# 学习率随训练动态调整
scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(
optimizer, 'min', patience=3, factor=0.5
)
# 在训练循环中使用
for epoch in range(epochs):
# ... 训练代码 ...
scheduler.step(avg_loss) # 根据损失调整学习率
📊 生成质量评估
def evaluate_generation_quality(model, test_prompts):
"""评估生成文本质量"""
results = []
for prompt in test_prompts:
# 生成多个版本
versions = []
for temp in [0.7, 1.0, 1.3]:
text = generate_soft(model, prompt, 100, temperature=temp)
versions.append(text)
results.append({
'prompt': prompt,
'conservative': versions[0], # 保守版本
'balanced': versions[1], # 平衡版本
'creative': versions[2] # 创意版本
})
return results
# 测试生成质量
test_prompts = ["Once upon a time", "In the future", "Scientists discovered"]
quality_results = evaluate_generation_quality(model, test_prompts)
for result in quality_results:
print(f"Prompt: {result['prompt']}")
print(f"Conservative: {result['conservative'][:50]}...")
print(f"Creative: {result['creative'][:50]}...")
print("-" * 50)
🔧 部署优化
Python环境配置
# 按你的偏好配置
import pymysql
pymysql.install_as_MySQLdb()
# 生成式模型推荐配置
"""
torch>=1.9.0
transformers>=4.0.0 # 如果要用预训练模型
numpy>=1.21.0
"""
阿里云服务器部署
# 在你的Linux服务器(宝塔面板+Apache)
pip install torch transformers flask
# 模型服务化部署
# 简单的Flask API
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/generate', methods=['POST'])
def generate_text():
data = request.json
prompt = data.get('prompt', 'Hello')
length = data.get('length', 100)
temperature = data.get('temperature', 1.0)
generated_text = generate_soft(model, prompt, length, temperature)
return jsonify({
'prompt': prompt,
'generated_text': generated_text,
'parameters': {
'length': length,
'temperature': temperature
}
})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
Golang数据处理脚本
// 大规模文本预处理和结果导出
package main
import (
"encoding/json"
"bufio"
"os"
)
type GenerationResult struct {
Prompt string `json:"prompt"`
Generated string `json:"generated"`
Temperature float64 `json:"temperature"`
Timestamp string `json:"timestamp"`
}
func exportGenerations(results []GenerationResult, filename string) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
encoder := json.NewEncoder(file)
for _, result := range results {
encoder.Encode(result)
}
return nil
}
🎯 实际应用场景
1. 智能写作助手
def writing_assistant(prompt, style="formal"):
"""智能写作助手"""
# 根据风格调整温度
temp_map = {
"formal": 0.7, # 正式文档
"creative": 1.2, # 创意写作
"technical": 0.5 # 技术文档
}
temperature = temp_map.get(style, 1.0)
return generate_soft(model, prompt, 200, temperature)
# 示例使用
business_email = writing_assistant("Dear Sir/Madam,", "formal")
creative_story = writing_assistant("In a world where", "creative")
2. 代码生成助手
# 可以训练专门的代码生成模型
def code_generator(prompt, language="python"):
"""代码生成助手"""
full_prompt = f"# {language} code\n{prompt}\n"
return generate_soft(code_model, full_prompt, 150, temperature=0.3)
# 示例
python_code = code_generator("def calculate_fibonacci(n):")
🎉 今日收获
- 生成式RNN:从理解文本到创作文本的飞跃
- 四种模式:一对一、一对多、多对一、多对多
- 字符级生成:从最基础的字符开始创作
- 温度控制:在保守和创意之间找平衡
- 实战技巧:数据处理、训练优化、质量评估
🔮 下期预告
下次我们将进入Transformer的时代!
想知道GPT、BERT这些明星模型的工作原理吗?注意力机制如何让AI”专注”理解语言?敬请期待下一个系列的开篇!
觉得有用记得点赞分享!想看AI写诗、编程的小伙伴欢迎评论区交流~
图:生成阶段的RNN工作流程,展示如何从初始提示逐步生成完整文本
#AI学习 #生成式AI #RNN #LSTM #文本生成 #深度学习 #机器学习
本作品采用《CC 协议》,转载必须注明作者和本文链接