TensorFlow神经网络构建与训练Skill tensorflow-neural-networks

这个技能专注于使用TensorFlow框架进行神经网络的构建和训练,覆盖从入门到高级的模型开发,包括图像分类、文本处理等应用。关键词:TensorFlow, 神经网络, 深度学习, Keras, 自定义层, 模型训练, AI开发, 机器学习, 计算机视觉, 自然语言处理。

深度学习 0 次安装 0 次浏览 更新于 3/25/2026

名称: tensorflow-neural-networks 描述: 使用TensorFlow构建和训练神经网络 允许工具: [Bash, Read]

TensorFlow神经网络

使用TensorFlow的高层Keras API和底层自定义实现构建和训练神经网络。这个技能覆盖从简单的顺序模型到复杂的自定义架构,包括多输出、自定义层和高级训练技术。

顺序模型与Keras

顺序API提供了通过线性堆叠层来构建神经网络的最简单方式。

基本图像分类

import tensorflow as tf
from tensorflow import keras
import numpy as np

# 加载MNIST数据集
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()

# 预处理数据
x_train = x_train.astype('float32') / 255.0
x_test = x_test.astype('float32') / 255.0
x_train = x_train.reshape(-1, 28 * 28)
x_test = x_test.reshape(-1, 28 * 28)

# 构建顺序模型
model = keras.Sequential([
    keras.layers.Dense(128, activation='relu', input_shape=(784,)),
    keras.layers.Dropout(0.2),
    keras.layers.Dense(64, activation='relu'),
    keras.layers.Dropout(0.2),
    keras.layers.Dense(10, activation='softmax')
])

# 编译模型
model.compile(
    optimizer='adam',
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)

# 显示模型架构
model.summary()

# 训练模型
history = model.fit(
    x_train, y_train,
    batch_size=32,
    epochs=5,
    validation_split=0.2,
    verbose=1
)

# 评估模型
test_loss, test_accuracy = model.evaluate(x_test, y_test, verbose=0)
print(f"测试准确率: {test_accuracy:.4f}")

# 进行预测
predictions = model.predict(x_test[:5])
predicted_classes = np.argmax(predictions, axis=1)
print(f"预测类别: {predicted_classes}")
print(f"真实类别: {y_test[:5]}")

# 保存模型
model.save('mnist_model.h5')

# 加载模型
loaded_model = keras.models.load_model('mnist_model.h5')

卷积神经网络

def create_cnn_model(input_shape=(224, 224, 3), num_classes=1000):
    """创建用于图像分类的CNN模型。"""
    model = tf.keras.Sequential([
        # 块1
        tf.keras.layers.Conv2D(64, (3, 3), activation='relu', padding='same',
                               input_shape=input_shape),
        tf.keras.layers.Conv2D(64, (3, 3), activation='relu', padding='same'),
        tf.keras.layers.MaxPooling2D((2, 2)),
        tf.keras.layers.BatchNormalization(),

        # 块2
        tf.keras.layers.Conv2D(128, (3, 3), activation='relu', padding='same'),
        tf.keras.layers.Conv2D(128, (3, 3), activation='relu', padding='same'),
        tf.keras.layers.MaxPooling2D((2, 2)),
        tf.keras.layers.BatchNormalization(),

        # 块3
        tf.keras.layers.Conv2D(256, (3, 3), activation='relu', padding='same'),
        tf.keras.layers.Conv2D(256, (3, 3), activation='relu', padding='same'),
        tf.keras.layers.MaxPooling2D((2, 2)),
        tf.keras.layers.BatchNormalization(),

        # 分类头
        tf.keras.layers.GlobalAveragePooling2D(),
        tf.keras.layers.Dense(512, activation='relu'),
        tf.keras.layers.Dropout(0.5),
        tf.keras.layers.Dense(num_classes, activation='softmax')
    ])
    return model

CIFAR-10 CNN架构

def generate_model():
    return tf.keras.models.Sequential([
        tf.keras.layers.Conv2D(32, (3, 3), padding='same', input_shape=x_train.shape[1:]),
        tf.keras.layers.Activation('relu'),
        tf.keras.layers.Conv2D(32, (3, 3)),
        tf.keras.layers.Activation('relu'),
        tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),
        tf.keras.layers.Dropout(0.25),

        tf.keras.layers.Conv2D(64, (3, 3), padding='same'),
        tf.keras.layers.Activation('relu'),
        tf.keras.layers.Conv2D(64, (3, 3)),
        tf.keras.layers.Activation('relu'),
        tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),
        tf.keras.layers.Dropout(0.25),

        tf.keras.layers.Flatten(),
        tf.keras.layers.Dense(512),
        tf.keras.layers.Activation('relu'),
        tf.keras.layers.Dropout(0.5),
        tf.keras.layers.Dense(10),
        tf.keras.layers.Activation('softmax')
    ])

model = generate_model()

自定义层

通过子类化 tf.keras.layers.Layer 创建可重用的自定义层。

自定义密集层

import tensorflow as tf

class CustomDense(tf.keras.layers.Layer):
    def __init__(self, units=32, activation=None):
        super(CustomDense, self).__init__()
        self.units = units
        self.activation = tf.keras.activations.get(activation)

    def build(self, input_shape):
        """创建层权重。"""
        self.w = self.add_weight(
            shape=(input_shape[-1], self.units),
            initializer='glorot_uniform',
            trainable=True,
            name='kernel'
        )
        self.b = self.add_weight(
            shape=(self.units,),
            initializer='zeros',
            trainable=True,
            name='bias'
        )

    def call(self, inputs):
        """前向传播。"""
        output = tf.matmul(inputs, self.w) + self.b
        if self.activation is not None:
            output = self.activation(output)
        return output

    def get_config(self):
        """启用序列化。"""
        config = super().get_config()
        config.update({
            'units': self.units,
            'activation': tf.keras.activations.serialize(self.activation)
        })
        return config

# 使用自定义组件
custom_model = tf.keras.Sequential([
    CustomDense(64, activation='relu', input_shape=(10,)),
    CustomDense(32, activation='relu'),
    CustomDense(1, activation='sigmoid')
])

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

残差块

import tensorflow as tf

class ResidualBlock(tf.keras.layers.Layer):
    def __init__(self, filters, kernel_size=3):
        super(ResidualBlock, self).__init__()
        self.conv1 = tf.keras.layers.Conv2D(filters, kernel_size, padding='same')
        self.bn1 = tf.keras.layers.BatchNormalization()
        self.conv2 = tf.keras.layers.Conv2D(filters, kernel_size, padding='same')
        self.bn2 = tf.keras.layers.BatchNormalization()
        self.activation = tf.keras.layers.Activation('relu')
        self.add = tf.keras.layers.Add()

    def call(self, inputs, training=False):
        x = self.conv1(inputs)
        x = self.bn1(x, training=training)
        x = self.activation(x)
        x = self.conv2(x)
        x = self.bn2(x, training=training)
        x = self.add([x, inputs])  # 残差连接
        x = self.activation(x)
        return x

使用TF NumPy的自定义投影层

class ProjectionLayer(tf.keras.layers.Layer):
    """使用TF NumPy的线性投影层。"""

    def __init__(self, units):
        super(ProjectionLayer, self).__init__()
        self._units = units

    def build(self, input_shape):
        import tensorflow.experimental.numpy as tnp
        stddev = tnp.sqrt(self._units).astype(tnp.float32)
        initial_value = tnp.random.randn(input_shape[1], self._units).astype(
            tnp.float32) / stddev
        # 注意TF NumPy可以与tf.Variable互操作。
        self.w = tf.Variable(initial_value, trainable=True)

    def call(self, inputs):
        import tensorflow.experimental.numpy as tnp
        return tnp.matmul(inputs, self.w)

# 使用ndarray输入调用
layer = ProjectionLayer(2)
tnp_inputs = tnp.random.randn(2, 4).astype(tnp.float32)
print("输出:", layer(tnp_inputs))

# 使用tf.Tensor输入调用
tf_inputs = tf.random.uniform([2, 4])
print("
输出: ", layer(tf_inputs))

自定义模型

通过子类化 tf.keras.Model 构建复杂架构。

多任务模型

import tensorflow as tf

class MultiTaskModel(tf.keras.Model):
    def __init__(self, num_classes_task1=10, num_classes_task2=5):
        super(MultiTaskModel, self).__init__()
        # 共享层
        self.conv1 = tf.keras.layers.Conv2D(32, 3, activation='relu')
        self.pool = tf.keras.layers.MaxPooling2D()
        self.flatten = tf.keras.layers.Flatten()
        self.shared_dense = tf.keras.layers.Dense(128, activation='relu')

        # 任务特定层
        self.task1_dense = tf.keras.layers.Dense(64, activation='relu')
        self.task1_output = tf.keras.layers.Dense(num_classes_task1,
                                                   activation='softmax', name='task1')

        self.task2_dense = tf.keras.layers.Dense(64, activation='relu')
        self.task2_output = tf.keras.layers.Dense(num_classes_task2,
                                                   activation='softmax', name='task2')

    def call(self, inputs, training=False):
        # 共享特征提取
        x = self.conv1(inputs)
        x = self.pool(x)
        x = self.flatten(x)
        x = self.shared_dense(x)

        # 任务1分支
        task1 = self.task1_dense(x)
        task1_output = self.task1_output(task1)

        # 任务2分支
        task2 = self.task2_dense(x)
        task2_output = self.task2_output(task2)

        return task1_output, task2_output

三层神经网络模块

class Model(tf.Module):
    """一个三层神经网络。"""

    def __init__(self):
        self.layer1 = Dense(128)
        self.layer2 = Dense(32)
        self.layer3 = Dense(NUM_CLASSES, use_relu=False)

    def __call__(self, inputs):
        x = self.layer1(inputs)
        x = self.layer2(x)
        return self.layer3(x)

    @property
    def params(self):
        return self.layer1.params + self.layer2.params + self.layer3.params

循环神经网络

自定义GRU单元

import tensorflow.experimental.numpy as tnp

class GRUCell:
    """构建具有密集内部变换的传统GRU单元。

    门控循环单元论文: https://arxiv.org/abs/1412.3555
    """

    def __init__(self, n_units, forget_bias=0.0):
        self._n_units = n_units
        self._forget_bias = forget_bias
        self._built = False

    def __call__(self, inputs):
        if not self._built:
            self.build(inputs)
        x, gru_state = inputs
        # 在x和h的连接上应用密集层。
        y = tnp.dot(tnp.concatenate([x, gru_state], axis=-1), self.w1) + self.b1
        # 更新和重置门。
        u, r = tnp.split(tf.sigmoid(y), 2, axis=-1)
        # 候选。
        c = tnp.dot(tnp.concatenate([x, r * gru_state], axis=-1), self.w2) + self.b2
        new_gru_state = u * gru_state + (1 - u) * tnp.tanh(c)
        return new_gru_state

    def build(self, inputs):
        # 状态最后一个维度必须为n_units。
        assert inputs[1].shape[-1] == self._n_units
        # 密集层输入是输入和一半GRU状态。
        dense_shape = inputs[0].shape[-1] + self._n_units
        self.w1 = tf.Variable(tnp.random.uniform(
            -0.01, 0.01, (dense_shape, 2 * self._n_units)).astype(tnp.float32))
        self.b1 = tf.Variable((tnp.random.randn(2 * self._n_units) * 1e-6 + self._forget_bias
                   ).astype(tnp.float32))
        self.w2 = tf.Variable(tnp.random.uniform(
            -0.01, 0.01, (dense_shape, self._n_units)).astype(tnp.float32))
        self.b2 = tf.Variable((tnp.random.randn(self._n_units) * 1e-6).astype(tnp.float32))
        self._built = True

    @property
    def weights(self):
        return (self.w1, self.b1, self.w2, self.b2)

自定义密集层实现

import tensorflow.experimental.numpy as tnp

class Dense:
    def __init__(self, n_units, activation=None):
        self._n_units = n_units
        self._activation = activation
        self._built = False

    def __call__(self, inputs):
        if not self._built:
            self.build(inputs)
        y = tnp.dot(inputs, self.w) + self.b
        if self._activation != None:
            y = self._activation(y)
        return y

    def build(self, inputs):
        shape_w = (inputs.shape[-1], self._n_units)
        lim = tnp.sqrt(6.0 / (shape_w[0] + shape_w[1]))
        self.w = tf.Variable(tnp.random.uniform(-lim, lim, shape_w).astype(tnp.float32))
        self.b = tf.Variable((tnp.random.randn(self._n_units) * 1e-6).astype(tnp.float32))
        self._built = True

    @property
    def weights(self):
        return (self.w, self.b)

顺序RNN模型

class Model:
    def __init__(self, vocab_size, embedding_dim, rnn_units, forget_bias=0.0, stateful=False, activation=None):
        self._embedding = Embedding(vocab_size, embedding_dim)
        self._gru = GRU(rnn_units, forget_bias=forget_bias, stateful=stateful)
        self._dense = Dense(vocab_size, activation=activation)
        self._layers = [self._embedding, self._gru, self._dense]
        self._built = False

    def __call__(self, inputs):
        if not self._built:
            self.build(inputs)
        xs = inputs
        for layer in self._layers:
            xs = layer(xs)
        return xs

    def build(self, inputs):
        self._embedding.build(inputs)
        self._gru.build(tf.TensorSpec(inputs.shape + (self._embedding._embedding_dim,), tf.float32))
        self._dense.build(tf.TensorSpec(inputs.shape + (self._gru._cell._n_units,), tf.float32))
        self._built = True

    @property
    def weights(self):
        return [layer.weights for layer in self._layers]

    @property
    def state(self):
        return self._gru.state

    def create_state(self, *args):
        self._gru.create_state(*args)

    def reset_state(self, *args):
        self._gru.reset_state(*args)

训练配置

模型参数

# 字符词汇表长度
vocab_size = len(vocab)

# 嵌入维度
embedding_dim = 256

# RNN单元数
rnn_units = 1024

# 批次大小
BATCH_SIZE = 64

# 用于洗牌数据集的缓冲区大小
BUFFER_SIZE = 10000

MNIST的训练常量

# 每个输入图像的大小,28 x 28像素
IMAGE_SIZE = 28 * 28
# 不同的数字标签数量,[0..9]
NUM_CLASSES = 10
# 每个训练批次中的示例数(步)
TRAIN_BATCH_SIZE = 100
# 运行的训练步数
TRAIN_STEPS = 1000

# 加载MNIST数据集。
train, test = tf.keras.datasets.mnist.load_data()
train_ds = tf.data.Dataset.from_tensor_slices(train).batch(TRAIN_BATCH_SIZE).repeat()

# 从原始数据转换为所需数据类型。
def cast(images, labels):
    images = tf.cast(
        tf.reshape(images, [-1, IMAGE_SIZE]), tf.float32)
    labels = tf.cast(labels, tf.int64)
    return (images, labels)

训练后量化

# 加载MNIST数据集
mnist = keras.datasets.mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

# 归一化输入图像,使每个像素值在0到1之间。
train_images = train_images / 255.0
test_images = test_images / 255.0

# 定义模型架构
model = keras.Sequential([
    keras.layers.InputLayer(input_shape=(28, 28)),
    keras.layers.Reshape(target_shape=(28, 28, 1)),
    keras.layers.Conv2D(filters=12, kernel_size=(3, 3), activation=tf.nn.relu),
    keras.layers.MaxPooling2D(pool_size=(2, 2)),
    keras.layers.Flatten(),
    keras.layers.Dense(10)
])

# 训练数字分类模型
model.compile(optimizer='adam',
              loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])
model.fit(
    train_images,
    train_labels,
    epochs=1,
    validation_data=(test_images, test_labels)
)

何时使用此技能

使用tensorflow-neural-networks技能当您需要:

  • 使用CNN构建图像分类模型
  • 使用RNN或transformer创建文本处理模型
  • 实现特定用例的自定义层架构
  • 设计具有共享表示的多任务学习模型
  • 为表格数据训练顺序模型
  • 实现残差连接或跳过连接
  • 为离散输入创建嵌入层
  • 构建自动编码器或生成模型
  • 使用自定义头微调预训练模型
  • 在自定义架构中实现注意力机制
  • 创建时间序列预测模型
  • 设计强化学习策略网络
  • 构建用于相似度学习的孪生网络
  • 在层中实现自定义梯度计算
  • 创建基于输入的动态架构模型

最佳实践

  1. 使用Keras顺序API处理简单架构 - 在转向函数式或子类化API之前,先从顺序API开始构建线性层堆叠。
  2. 利用预建层 - 在创建自定义层之前,先使用tf.keras.layers内置实现。
  3. 正确初始化权重 - 根据激活函数使用适当的初始化器(如glorot_uniform、he_normal)。
  4. 添加批归一化 - 在Conv2D/Dense层后放置BatchNormalization层以提高训练稳定性。
  5. 使用Dropout进行正则化 - 在全连接层应用Dropout层(0.2-0.5)以防止过拟合。
  6. 训练前编译模型 - 在fit()之前始终调用model.compile(),指定优化器、损失函数和指标。
  7. 监控验证指标 - 使用validation_split或validation_data在训练期间跟踪过拟合。
  8. 保存模型检查点 - 实现ModelCheckpoint回调以在训练期间保存最佳模型。
  9. 使用model.summary() - 在训练前验证架构和参数计数。
  10. 实现早停 - 添加EarlyStopping回调以防止不必要的训练迭代。
  11. 归一化输入数据 - 将像素值缩放到[0,1]或将特征标准化为均值=0、标准差=1。
  12. 使用适当的激活函数 - 隐藏层用ReLU,多分类用softmax,二分类用sigmoid。
  13. 设置正确的损失函数 - 整数标签用sparse_categorical_crossentropy,独热编码用categorical_crossentropy。
  14. 实现自定义get_config() - 在自定义层中重写get_config()以支持模型序列化。
  15. 在call()中使用训练参数 - 传递training标志以启用/禁用Dropout和BatchNorm行为。

常见陷阱

  1. 忘记归一化数据 - 未归一化的输入导致收敛缓慢和性能差。
  2. 标签使用错误损失函数 - 对整数标签使用categorical_crossentropy会导致错误。
  3. 缺少input_shape - 第一层需要input_shape参数以构建模型。
  4. 在小数据集上过拟合 - 添加Dropout、数据增强或减少模型容量。
  5. 学习率过高 - 导致训练不稳定和损失发散。
  6. 未洗牌训练数据 - 导致批次统计偏差和泛化能力差。
  7. 批次大小过小 - 在大数据集上导致梯度噪声和训练缓慢。
  8. 参数过多 - 大模型在有限数据上容易过拟合且训练缓慢。
  9. 深度网络中的梯度消失 - 使用残差连接或批归一化。
  10. 未使用验证数据 - 无法检测过拟合或调整超参数。
  11. 忘记设置training=False - Dropout/BatchNorm在推理期间行为不正确。
  12. 层维度不兼容 - 一个层的输出形状必须与下一层的输入匹配。
  13. 在访问权重前未调用build() - 自定义层需要适当初始化后才能访问权重。
  14. 使用错误优化器 - Adam通常表现良好,但某些任务用带动量的SGD。
  15. 忽略类别不平衡 - 为不平衡数据集实现类别权重或重采样。

资源