1. 深度神经网络(DNN):从多层感知机到智能核心

如果你刚接触深度学习,可能会被各种缩写吓到,但别怕,咱们就从最基础的“深度神经网络”(DNN)开始。你可以把它想象成一个超级复杂的“连连看”或者“信号处理流水线”。它本质上就是多层感知机(MLP)的豪华升级版,由一层一层的神经元连接而成。我刚开始学的时候,总觉得这东西跟老式的电话交换机有点像,输入的数据就像一通电话,从一层交换机(神经元层)转到下一层,每经过一层,信息就被加工、提炼一次,最后输出一个结果。

为什么它这么重要?因为在过去,算力不够,数据也少,这种有很多隐藏层的网络被大家嘲笑是“理论巨人,行动矮子”,根本训练不起来。直到最近十来年,GPU算力大爆发,加上互联网产生了海量数据,DNN才真正展现出它的威力。它的核心原理其实不复杂:每一层都把接收到的数据进行一次非线性变换。这个“非线性”是关键,如果只是简单的加减乘除,层数再多也学不到复杂模式。通过这种一层层的非线性组合,DNN就能从原始数据(比如一堆像素点)中,自己提炼出高级特征(比如这是眼睛的轮廓,那是车轮的形状)。

训练一个DNN,最经典的方法就是“反向传播”加“梯度下降”。我打个比方,这就像蒙着眼睛下山(寻找最低点即损失最小)。你每走一步(一次参数更新),都需要用脚探一探周围哪个方向是下坡(计算梯度),然后往那个方向挪一点。这个过程反复进行,直到你走到山谷底部。在实际操作中,你需要定义一个损失函数(比如预测值和真实值的差距),然后用反向传播算法,把误差从输出层一层层倒推回去,计算出每一层参数该调整多少。

我最初用TensorFlow实现一个简单的DNN做手写数字识别(MNIST数据集),代码骨架大概是这样的:

import tensorflow as tf

model = tf.keras.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),  # 把28x28的图片压平
    tf.keras.layers.Dense(128, activation='relu'),   # 第一个隐藏层,128个神经元
    tf.keras.layers.Dropout(0.2),                    # 丢弃一些神经元,防止过拟合
    tf.keras.layers.Dense(64, activation='relu'),    # 第二个隐藏层
    tf.keras.layers.Dense(10, activation='softmax')  # 输出层,10个数字类别
])

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(train_images, train_labels, epochs=10)

跑起来之后你会发现,即使这么简单的结构,准确率也能轻松超过95%。DNN的优点很明显,就是特征学习能力超强,能搞定非常复杂的非线性关系。但它也有坑,最著名的就是“梯度消失”问题:网络太深时,误差反向传播到前面的层会变得极小,导致前面的参数几乎得不到更新,网络学不动了。所以早期训练深一点的网络都需要小心翼翼的初始化技巧和正则化方法。

它的应用场景几乎无处不在,是很多复杂模型的基石。从你手机相册的智能分类,到语音助手的唤醒词识别,再到电商平台猜你喜欢什么商品,背后都有DNN的影子。它就像深度学习领域的“普通话”,是必须掌握的基础。

1.1 实战踩坑:你的第一个DNN项目

理论懂了,不实操永远学不会。我建议第一个实战项目就从电影评论情感分析开始。数据好找(比如IMDb数据集),任务直观(判断评论是正面还是负面)。这里的关键不是追求极致准确率,而是走通全流程并理解每个环节。

第一步永远是数据预处理。文本数据不能直接喂给网络,你需要把它变成数字。最简单的方法是使用词袋模型或者TF-IDF,但更常用的(也是为后续学Word2Vec、Transformer打基础)是使用Tokenizer进行序列化:

from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences

tokenizer = Tokenizer(num_words=10000)  # 只考虑最常见的10000个词
tokenizer.fit_on_texts(train_texts)     # 在训练文本上构建词汇表

train_sequences = tokenizer.texts_to_sequences(train_texts)  # 转成数字序列
train_padded = pad_sequences(train_sequences, maxlen=200)     # 统一填充/截断到200长度

接下来构建一个稍深的DNN模型。注意,对于文本这种序列数据,简单的全连接DNN效果有限,但作为入门练习完全没问题。我们可以加入嵌入层(Embedding Layer),它能把整数索引映射为密集向量,这是学习词表示的第一步:

model = tf.keras.Sequential([
    tf.keras.layers.Embedding(10000, 16, input_length=200),  # 嵌入层
    tf.keras.layers.Flatten(),                               # 压平,接入全连接层
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Dense(32, activation='relu'),
    tf.keras.layers.Dense(1, activation='sigmoid')           # 二分类输出
])

编译模型时,二分类问题用binary_crossentropy损失,优化器用Adam是万金油选择。训练时,一定要把数据分成训练集和验证集,监控验证集上的准确率和损失,这是判断模型是否过拟合的关键:

model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
history = model.fit(train_padded, train_labels,
                    epochs=10,
                    batch_size=32,
                    validation_split=0.2)  # 20%数据作为验证集

我踩过的坑主要有两个:一是数据没洗干净,比如文本里有很多HTML标签、特殊符号,严重影响嵌入层学习,一定要用正则表达式仔细清洗;二是过拟合,训练集准确率很快到99%,验证集却卡在85%上不去。解决方法除了增加Dropout层,还可以尝试L2正则化,或者最简单的——收集更多数据。跑完这个项目,你对DNN的输入输出、训练流程、调参和问题排查就有了最直接的体感。

2. 卷积神经网络(CNN):让计算机“看见”世界

如果说DNN是全能战士,那卷积神经网络(CNN)就是专为视觉任务打造的“特种兵”。它的设计灵感来源于生物的视觉皮层,其核心思想是:不需要让每个神经元都看整张图片,只需要让它看一小块区域(局部感受野),并且在不同位置共享同样的模式识别能力(参数共享)。这大大减少了参数数量,让网络能更深、更高效地处理图像。

我记得最早接触CNN是读LeCun的LeNet-5论文,那个用于手写数字识别的网络结构现在看来很简单,但思想是革命性的。CNN的关键组件就两个:卷积层池化层。卷积层就像拿着一组小滤镜(卷积核)在图像上滑动,每个滤镜负责提取一种特征,比如边缘、纹理、颜色过渡。池化层(通常是最大池化)则跟在卷积层后面,进行“降采样”,它只保留一个小区域(比如2x2)里最显著的特征,这样既能降低数据维度、减少计算量,又能让网络对微小的位置变化不那么敏感(平移不变性)。

用Keras搭建一个经典的CNN结构(比如用于CIFAR-10图像分类)非常直观:

model = tf.keras.Sequential([
    # 第一个卷积块
    tf.keras.layers.Conv2D(32, (3, 3), activation='relu', padding='same', input_shape=(32, 32, 3)),
    tf.keras.layers.Conv2D(32, (3, 3), activation='relu', padding='same'),
    tf.keras.layers.MaxPooling2D((2, 2)),
    tf.keras.layers.Dropout(0.25),

    # 第二个卷积块
    tf.keras.layers.Conv2D(64, (3, 3), activation='relu', padding='same'),
    tf.keras.layers.Conv2D(64, (3, 3), activation='relu', padding='same'),
    tf.keras.layers.MaxPooling2D((2, 2)),
    tf.keras.layers.Dropout(0.25),

    # 展平后接全连接层
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(512, activation='relu'),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Dense(10, activation='softmax')  # CIFAR-10有10类
])

这个结构里,你可以看到卷积层数量逐渐增加(32 -> 64),特征图尺寸逐渐减小(通过池化),最后通过全连接层输出分类结果。CNN的优点在图像领域太突出了:参数共享让它参数效率极高,平移不变性让它鲁棒性强,分层结构让它能自动学习从边缘到部件再到物体的层次化特征。

2.1 实战进阶:用预训练CNN快速搞定图像分类

从头训练一个CNN需要大量数据和算力,对于大多数应用,我们更常用的是迁移学习。也就是拿一个在超大数据集(如ImageNet)上预训练好的模型(比如VGG16、ResNet50),把它当成一个强大的特征提取器,只微调最后几层,或者直接接一个新的分类头。这能让你用很少的数据和计算资源,就达到很好的效果。

以用Keras应用VGG16对猫狗图片分类为例:

from tensorflow.keras.applications import VGG16
from tensorflow.keras.preprocessing.image import ImageDataGenerator

# 加载预训练的VGG16,不包括顶部分类层,使用ImageNet上学习的权重
base_model = VGG16(weights='imagenet', include_top=False, input_shape=(150, 150, 3))

# 冻结基础模型的所有层,这样在训练初期不会更新它们的权重
base_model.trainable = False

# 在基础模型上添加新的分类头
model = tf.keras.Sequential([
    base_model,
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(256, activation='relu'),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Dense(1, activation='sigmoid')  # 猫狗二分类
])

model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

接下来,使用ImageDataGenerator来方便地做数据增强和批量加载。数据增强是防止图像模型过拟合的神器,它能通过对训练图片进行随机旋转、缩放、平移、翻转等操作,凭空“创造”出更多的训练样本:

train_datagen = ImageDataGenerator(
    rescale=1./255,
    rotation_range=20,
    width_shift_range=0.2,
    height_shift_range=0.2,
    horizontal_flip=True,
    validation_split=0.2  # 直接从训练集中分一部分做验证
)

train_generator = train_datagen.flow_from_directory(
    'path/to/train_data',
    target_size=(150, 150),
    batch_size=32,
    class_mode='binary',
    subset='training'
)

validation_generator = train_datagen.flow_from_directory(
    'path/to/train_data',
    target_size=(150, 150),
    batch_size=32,
    class_mode='binary',
    subset='validation'
)

history = model.fit(
    train_generator,
    steps_per_epoch=train_generator.samples // 32,
    epochs=10,
    validation_data=validation_generator,
    validation_steps=validation_generator.samples // 32
)

跑完几轮后,如果验证集准确率上不去了,你可以考虑解冻基础模型的最后几个卷积块,进行精细微调。这个过程我称之为“解冻-微调”策略,通常能再提升几个点的性能。通过这个实战,你不仅能学会用CNN解决实际问题,更能理解现代深度学习实践中“站在巨人肩膀上”的高效工作流。

3. 残差网络(ResNet)与长短时记忆网络(LSTM):攻克深度与序列的难题

当大家拼命把CNN和DNN往深了做的时候,两个恼人的问题出现了:梯度消失模型退化。网络越深,训练反而越困难,甚至更深的网络比浅的网络在测试集上错误率更高。这太反直觉了!ResNet的提出就是为了解决这个。它的天才之处在于引入了“残差块”和“跳跃连接”。简单说,它不让每一层直接去拟合一个复杂的底层映射,而是去拟合一个“残差”,也就是输入和输出之间的差值。通过一条跳跃连接,把输入直接加到这一层的输出上。这样,即使这一层的权重被训练得很小,输出也不会比输入差,至少能保证信息畅通无阻地向前传播。这就好比你在学习时,不是每次都从头开始学一套全新的知识,而是在已有知识的基础上,只学习需要“修正”或“补充”的那部分。

我第一次用ResNet-50做迁移学习时,明显感觉它比普通的VGG收敛更快、更稳定。在Keras里调用它和调用VGG一样简单:

from tensorflow.keras.applications import ResNet50

base_model = ResNet50(weights='imagenet', include_top=False, input_shape=(224, 224, 3))

它的成功彻底打破了“网络越深越难训练”的魔咒,直接催生了成百上千层的超深网络,把图像识别等任务的性能推到了新高度。现在,ResNet及其变体已经是计算机视觉领域事实上的骨干网络。

另一边,在处理文本、语音、时间序列这类序列数据时,我们面临的是另一个维度的难题:如何让网络记住“上文”的信息?传统的RNN(循环神经网络)设计上具有记忆功能,但它同样饱受梯度消失之苦,对于长序列,它根本记不住开头说了啥。LSTM(长短时记忆网络)通过精巧的“门控”机制解决了这个问题。你可以把LSTM单元想象成一个有传送带的小工厂,它有三个门:遗忘门决定从记忆细胞中扔掉哪些旧信息;输入门决定放哪些新信息进来;输出门决定基于当前的细胞状态输出什么。这套机制让LSTM能够有选择地保留和传递信息,从而有效地学习长距离依赖关系。

3.1 实战双星:用ResNet做目标检测,用LSTM写文本生成

理解了原理,我们来看两个更综合的实战。第一个是用基于ResNet的Faster R-CNN做目标检测。目标检测不仅要识别图中有什么,还要框出它们的位置。Faster R-CNN是一个经典的两阶段检测器:第一阶段,一个区域提议网络(RPN)在特征图上滑动,找出可能包含物体的候选框;第二阶段,对这些候选框对应的特征进行裁剪和池化,然后进行分类和边界框回归。虽然现在有更多单阶段检测器(如YOLO)更流行,但理解Faster R-CNN的设计思想依然非常重要。使用现成的框架(如Detectron2或MMDetection)可以大大降低实现难度,但核心在于理解如何将ResNet作为特征提取主干,以及RPN和ROI Align等关键组件是如何工作的。

第二个实战是用LSTM写一个简单的文本生成模型,比如模仿莎士比亚的戏剧风格。这个项目能让你深刻体会LSTM如何学习序列中的模式。步骤大致如下:

  1. 准备数据:获取莎士比亚文本,转换成字符或单词级别的序列。
  2. 构建训练样本:采用滑动窗口,用前面N个字符作为输入,预测第N+1个字符。
  3. 构建模型:一个简单的单层LSTM模型就足够有趣。
model = tf.keras.Sequential([
    tf.keras.layers.LSTM(128, input_shape=(seq_length, len(chars))),  # 输入是序列和字符的one-hot
    tf.keras.layers.Dense(len(chars), activation='softmax')  # 输出下一个字符的概率分布
])
  1. 训练与生成:训练完成后,你给它一个种子字符串(如“ROMEO: ”),模型会输出下一个字符最可能的概率分布,你根据这个分布采样一个字符,加到种子后面,再作为新的输入,如此循环,就能生成一段新的“莎翁”文本。初期生成的可能是乱码,但随着训练,它会逐渐学会单词拼写、基本语法甚至一些风格。这个过程中,你能直观感受到LSTM的“记忆”能力——它生成的文本在上下文中是连贯的。

通过ResNet和LSTM的实战,你能掌握解决“深度”和“长期依赖”这两大核心难题的利器,它们分别代表了计算机视觉和自然语言处理领域一个时代的基石性突破。

4. 从Word2Vec到Transformer:自然语言处理的范式革命

在Transformer一统江湖之前,自然语言处理(NLP)的世界是另一番景象。Word2Vec无疑是那个时代的明星,它的目标简单而深刻:为每个词找到一个数值向量表示,使得语义相似的词在向量空间里也挨得近。比如,“国王”的向量减去“男人”的向量,再加上“女人”的向量,结果应该接近“女王”的向量。这种类比关系的神奇出现,让所有人看到了分布式表示的威力。

Word2Vec有两种主要训练方式:CBOW(用上下文词预测中心词)和Skip-gram(用中心词预测上下文词)。我通常用gensim库来快速体验:

from gensim.models import Word2Vec
sentences = [["cat", "say", "meow"], ["dog", "say", "woof"]]  # 示例语料,实际需要大规模文本
model = Word2Vec(sentences, vector_size=100, window=5, min_count=1, workers=4)
vector = model.wv['cat']  # 获取“cat”的词向量
similar_words = model.wv.most_similar('cat', topn=5)  # 找出与“cat”最相似的5个词

它的优点是训练相对高效,得到的词向量可解释性强,能直接用于计算语义相似度。但缺点也很明显:它是“静态”的,一个词无论出现在什么上下文,都只有一个固定的向量表示,无法解决一词多义问题。而且,它只建模了局部上下文窗口内的共现关系。

这一切都被Transformer模型颠覆了。Transformer完全摒弃了循环和卷积结构,纯粹基于自注意力机制。自注意力机制让序列中的每个词,都能够直接与序列中所有其他词进行交互,计算一个“注意力分数”,从而动态地决定在编码当前词时,应该“注意”其他词的多少信息。这完美解决了长距离依赖问题,并且由于没有递归,计算可以高度并行化,训练速度极大提升。

Transformer的编码器-解码器架构最初是为机器翻译设计的,但真正让它封神的是其后续变体:BERT(仅用编码器,通过掩码语言模型进行预训练)和GPT(仅用解码器,通过自回归语言模型进行预训练)。它们开启了“预训练-微调”的NLP新范式。

4.1 实战体验:用Hugging Face Transformers库快速微调BERT

现在,我们不需要从零实现Transformer,利用Hugging Face的transformers库,我们可以像搭积木一样使用最先进的模型。假设我们要做一个新闻文本分类任务:

from transformers import AutoTokenizer, TFAutoModelForSequenceClassification
import tensorflow as tf

# 加载预训练的BERT模型和分词器
model_name = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = TFAutoModelForSequenceClassification.from_pretrained(model_name, num_labels=5)  # 假设5个新闻类别

# 准备数据:将文本转换为BERT需要的输入格式(input_ids, attention_mask)
def preprocess(texts, labels):
    encodings = tokenizer(texts, truncation=True, padding=True, max_length=128)
    return dict(encodings), labels

train_encodings, train_labels = preprocess(train_texts, train_labels)

# 构建TensorFlow数据集
train_dataset = tf.data.Dataset.from_tensor_slices((train_encodings, train_labels)).batch(16)

# 编译并训练(微调)
optimizer = tf.keras.optimizers.Adam(learning_rate=5e-5)
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
model.compile(optimizer=optimizer, loss=loss, metrics=['accuracy'])
model.fit(train_dataset, epochs=3)

就这么几行代码,你就在一个强大的预训练BERT基础上,为你的特定任务微调了一个分类器。相比从零训练,这种方法只需要很少的标注数据就能达到极佳的效果。在这个过程中,你可以尝试调整学习率(通常很小,如5e-5)、训练轮数(防止过拟合),以及尝试不同的预训练模型(如roberta-base, distilbert-base-uncased等更小更快的模型)。这个实战会让你真切感受到,Transformer生态如何将最前沿的NLP技术民主化,让开发者能快速构建强大的语言应用。

5. 生成对抗网络(GAN)与扩散模型(Diffusion):创造的艺术

深度学习不仅能“理解”世界,还能“创造”世界,这主要归功于生成模型。生成对抗网络(GAN) 的提出极具想象力,它让两个网络——生成器(G)和判别器(D)——相互对抗、共同进化。G的目标是生成以假乱真的数据(如图片),D的目标是火眼金睛地分辨出真实数据和G生成的假数据。两者在对抗中不断提升,直到G生成的数据逼真到D无法区分。这就像古董造假者和鉴定专家之间的博弈。

我最早尝试用DCGAN(深度卷积GAN)生成人脸图片,代码结构清晰:

# 生成器:输入一个随机噪声向量,通过反卷积层逐步“放大”成一张图片
def build_generator():
    model = tf.keras.Sequential([
        tf.keras.layers.Dense(7*7*256, use_bias=False, input_shape=(100,)),
        tf.keras.layers.BatchNormalization(),
        tf.keras.layers.LeakyReLU(),
        tf.keras.layers.Reshape((7, 7, 256)),
        # 上采样和卷积层...
        tf.keras.layers.Conv2DTranspose(3, (5,5), strides=(2,2), padding='same', activation='tanh')
    ])
    return model

# 判别器:输入一张图片,输出一个标量表示其为真的概率
def build_discriminator():
    model = tf.keras.Sequential([
        tf.keras.layers.Conv2D(64, (5,5), strides=(2,2), padding='same', input_shape=[28,28,1]),
        tf.keras.layers.LeakyReLU(),
        tf.keras.layers.Dropout(0.3),
        # 更多卷积层...
        tf.keras.layers.Flatten(),
        tf.keras.layers.Dense(1)
    ])
    return model

训练GAN是个技术活,非常不稳定,常遇到模式崩溃问题——生成器只学会生成少数几种样本,缺乏多样性。需要精心调整损失函数(如用Wasserstein距离)、优化器参数,并使用一些训练技巧。

扩散模型则走了一条完全不同的生成路径。它的思想很哲学:先通过一个前向过程,逐步给一张真实图片加噪声,直到它变成纯高斯噪声;然后,训练一个神经网络去学习这个过程的逆过程——如何从噪声中一步步“去噪”,还原出图片。这就像一个画家先胡乱泼墨(加噪),再慢慢精心修饰,勾勒出细节(去噪)。扩散模型的训练更稳定,生成的图片质量和多样性都极高,直接推动了AIGC(人工智能生成内容)的爆发,比如DALL-E 2、Stable Diffusion都是基于扩散模型。

5.1 实战创造:用Stable Diffusion生成你的第一幅AI画作

对于大多数开发者,现在不需要从零训练扩散模型,直接使用开源的Stable Diffusion等工具进行推理生成,是体验AI创造力的最快方式。你可以使用diffusers库:

from diffusers import StableDiffusionPipeline
import torch

# 加载预训练管道
pipe = StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5", torch_dtype=torch.float16)
pipe = pipe.to("cuda")  # 如果有GPU

# 输入提示词,生成图像
prompt = "A beautiful fantasy landscape with a crystal clear river and ancient trees, digital art"
image = pipe(prompt).images[0]
image.save("fantasy_landscape.png")

你可以通过调整提示词(Prompt)来精确控制生成内容,添加如“4k, photorealistic, detailed”等修饰词来提升质量,或使用负面提示词(Negative Prompt)来排除不想要的元素。更进阶的,你可以学习LoRA等微调技术,用少量图片让模型学会特定风格或人物。这个实战会让你直观感受到,生成式AI如何将语言描述直接转化为视觉创造,其背后的扩散模型正在重塑内容生产的未来。

6. 图神经网络(GNN)与深度Q网络(DQN):连接结构与决策的智能

现实世界中很多数据天生就是图结构:社交网络(用户是节点,关注关系是边)、分子结构(原子是节点,化学键是边)、推荐系统(用户和商品是节点,交互是边)。传统神经网络难以直接处理这种非欧几里得数据。图神经网络(GNN) 应运而生,它的核心思想是通过聚合邻居节点的信息来更新当前节点的表示。每一层,节点都会从它的直接邻居那里收集信息,融合后更新自己的特征向量。经过多层这样的“消息传递”,一个节点就能感知到多跳之外邻居的信息,从而捕捉到整个图的全局结构。

我用PyTorch Geometric(一个常用的GNN库)做过一个简单的节点分类实验,比如在引文网络数据集Cora上:

import torch
from torch_geometric.datasets import Planetoid
from torch_geometric.nn import GCNConv

class GCN(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = GCNConv(dataset.num_node_features, 16)  # 第一层图卷积
        self.conv2 = GCNConv(16, dataset.num_classes)        # 第二层图卷积

    def forward(self, data):
        x, edge_index = data.x, data.edge_index
        x = self.conv1(x, edge_index)
        x = torch.relu(x)
        x = torch.dropout(x, p=0.5, train=self.training)
        x = self.conv2(x, edge_index)
        return torch.log_softmax(x, dim=1)

dataset = Planetoid(root='/tmp/Cora', name='Cora')
model = GCN()

GNN的强大在于它能直接建模关系,在社交推荐、药物发现、交通预测等领域潜力巨大。它的挑战在于计算复杂度高,且对超参数(如层数、聚合方式)比较敏感。

另一个从不同角度模拟智能的算法是深度Q网络(DQN),它属于深度强化学习。想象一下训练一个玩游戏的AI:它观察当前游戏画面(状态),选择一个动作(如跳跃),获得奖励或惩罚,然后进入下一个状态。DQN的目标是学习一个最优策略,使得长期累积奖励最大。它的创新在于用深度神经网络来近似Q函数(状态-动作价值函数),并结合了经验回放(打破数据相关性)和目标网络(稳定训练)两大关键技术。

6.1 实战综合:用GNN做推荐,用DQN玩经典游戏

一个有趣的GNN实战是构建一个简单的图推荐系统。我们可以把用户和物品视为二部图的两种节点,用户-物品的交互(点击、购买)视为边。然后,使用LightGCN等GNN模型,通过多层消息传递来学习用户和物品的嵌入表示,最后用内积预测用户对未交互物品的偏好分数。这个过程能显式地利用“协同过滤”信号(即相似用户或物品的关系),往往比传统的矩阵分解方法效果更好。

DQN的经典实战环境是OpenAI Gym。比如让AI学习玩CartPole(平衡杆)游戏:

import gym
import numpy as np
from collections import deque
import random
from tensorflow.keras import models, layers

env = gym.make('CartPole-v1')
state_size = env.observation_space.shape[0]
action_size = env.action_space.n

# 构建Q网络
model = models.Sequential([
    layers.Dense(24, input_dim=state_size, activation='relu'),
    layers.Dense(24, activation='relu'),
    layers.Dense(action_size, activation='linear')
])

# 经验回放缓冲区
memory = deque(maxlen=2000)

def train_dqn():
    state = env.reset()
    state = np.reshape(state, [1, state_size])
    for time in range(500):
        # ε-贪婪策略选择动作
        if np.random.rand() <= epsilon:
            action = np.random.randint(action_size)
        else:
            act_values = model.predict(state, verbose=0)
            action = np.argmax(act_values[0])
        # 执行动作,存储经验
        next_state, reward, done, _ = env.step(action)
        next_state = np.reshape(next_state, [1, state_size])
        memory.append((state, action, reward, next_state, done))
        state = next_state
        # 从记忆中采样进行训练
        if len(memory) > batch_size:
            minibatch = random.sample(memory, batch_size)
            # ... 计算目标Q值,训练网络 ...
        if done:
            break

你需要实现经验回放采样、目标Q值计算(使用目标网络)和模型更新的完整逻辑。当看到AI从胡乱摆动到能长时间稳定平衡杆时,你会对强化学习如何通过试错学习策略有深刻理解。GNN和DQN代表了AI向更复杂的结构化数据和序列决策问题的进军,它们是构建更通用智能体的重要拼图。

把这十大算法走一遍,就像在深度学习的世界里进行了一次深度旅行。从基础的全连接,到专精视觉的CNN,解决深度和序列难题的ResNet、LSTM,引发NLP革命的Word2Vec和Transformer,再到能够进行创造的GAN和扩散模型,最后是处理图结构和序列决策的GNN与DQN。每个算法都解决了一类关键问题,它们的组合与演进构成了现代AI的壮丽图景。我的经验是,不要只停留在理论理解,一定要动手复现哪怕是最简单的示例代码,在调试和跑通的过程中,你会遇到各种预料之外的问题,解决它们才是真正的学习。这些算法不是孤立的,在实际项目中,你经常会组合使用它们,比如用CNN提取图像特征输入给LSTM生成描述(图像字幕),或用Transformer作为GNN的消息函数。希望这份实战指南能成为你探索AI世界的一张可靠地图,剩下的,就是开始你的编码之旅了。

更多推荐