PyTorch 与 TensorFlow 模型搭建的区别

server/2024/11/19 7:32:42/

PyTorch 与 TensorFlow 模型搭建的区别

在深度学习领域,PyTorch 和 TensorFlow 是两个最流行的框架。本文将通过手写数字识别(MNIST 数据集)作为例子,探讨这两个框架在模型搭建中的主要区别,包括 PyTorch 的动态性、卷积层、全连接层和池化层的定义差异,以及训练过程的不同。

1. PyTorch 的动态性

动态计算图

PyTorch 使用动态计算图(Define-by-Run),这意味着计算图在每次前向传播时都是动态生成的。您可以在模型运行时根据输入数据的形状和内容灵活地修改网络结构。这种特性使得调试和实验变得更加简单。

示例代码

在 PyTorch 的手写数字识别代码中,模型的定义如下:

class CNN(nn.Module):def __init__(self):super(CNN, self).__init__()self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)  # 第一层卷积self.pool = nn.MaxPool2d(kernel_size=2, stride=2)  # 池化层self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)  # 第二层卷积self.fc1 = nn.Linear(64 * 7 * 7, 128)  # 全连接层self.fc2 = nn.Linear(128, 10)  # 输出层def forward(self, x):x = self.pool(torch.relu(self.conv1(x)))  # 通过第一层卷积和池化x = self.pool(torch.relu(self.conv2(x)))  # 通过第二层卷积和池化x = x.view(-1, 64 * 7 * 7)  # 展平特征图x = torch.relu(self.fc1(x))  # 通过全连接层x = self.fc2(x)  # 输出层return x

forward 方法中,=可以根据输入数据的形状和内容灵活调整模型结构。调试时,可以使用标准的 Python 调试工具(如 print 语句)来逐步检查中间结果。

2. 卷积层、全连接层和池化层的定义差异

PyTorch 中的定义

在 PyTorch 中,卷积层、全连接层和池化层的定义需要显式指定输入和输出通道数。例如:

self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)  # 第一层卷积
self.pool = nn.MaxPool2d(kernel_size=2, stride=2)  # 池化层
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)  # 第二层卷积
self.fc1 = nn.Linear(64 * 7 * 7, 128)  # 全连接层
self.fc2 = nn.Linear(128, 10)  # 输出层
  • 卷积层:需要明确输入和输出通道数。
  • 池化层:定义池化操作的类型和大小。
  • 全连接层:输入特征数和输出特征数需要明确。

TensorFlow 中的定义

在 TensorFlow 中,卷积层、全连接层和池化层的定义通常不需要显式指定输入通道数,尤其是在使用 Keras 的 layers.Conv2D 时。例如:

model = models.Sequential([layers.Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=(28, 28, 1)),  # 第一层卷积layers.MaxPooling2D(pool_size=(2, 2)),  # 池化层layers.Conv2D(64, kernel_size=(3, 3), activation='relu'),  # 第二层卷积layers.MaxPooling2D(pool_size=(2, 2)),  # 池化层layers.Flatten(),  # 展平layers.Dense(128, activation='relu'),  # 全连接层layers.Dense(10, activation='softmax')  # 输出层
])
  • 卷积层:在第一层中需要指定 input_shape,后续层会自动推断输入通道数。
  • 池化层:定义池化操作的类型和大小。
  • 全连接层:通过 layers.Dense 添加,输入特征数会自动推断。

3. 训练的区别

PyTorch 的训练过程

在 PyTorch 中,训练过程需要手动管理梯度清零、损失计算和权重更新。例如:

for epoch in range(num_epochs):for images, labels in train_loader:optimizer.zero_grad()  # 清除梯度outputs = model(images)  # 前向传播loss = criterion(outputs, labels)  # 计算损失loss.backward()  # 反向传播optimizer.step()  # 更新权重
  • 手动控制:每一步都需要手动管理,提供了更大的灵活性,但也需要更多的代码。

TensorFlow 的训练过程

在 TensorFlow 中,训练过程通过 model.fit 方法自动处理。例如:

model.fit(x_train, y_train, batch_size=batch_size, epochs=num_epochs, verbose=1)
  • 自动管理:TensorFlow 会自动处理梯度计算、损失计算和权重更新,简化了训练过程。

torch代码

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt# 超参数
batch_size = 64
learning_rate = 0.001
num_epochs = 5# 数据预处理
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,), (0.5,))
])# 下载 MNIST 数据集
train_dataset = datasets.MNIST(root='./data', train=True, transform=transform, download=True)
test_dataset = datasets.MNIST(root='./data', train=False, transform=transform)train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False)# 定义卷积神经网络模型
class CNN(nn.Module):def __init__(self):super(CNN, self).__init__()# 第一层卷积,输入通道为1(灰度图),输出通道为32,卷积核大小为3x3self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)# 池化层,使用2x2的最大池化self.pool = nn.MaxPool2d(kernel_size=2, stride=2)# 第二层卷积,输入通道为32,输出通道为64self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)# 全连接层,输入特征数为64*7*7(经过两次池化后的特征图大小),输出特征数为128self.fc1 = nn.Linear(64 * 7 * 7, 128)# 输出层,输出特征数为10(数字0-9)self.fc2 = nn.Linear(128, 10)def forward(self, x):# 前向传播过程x = self.pool(torch.relu(self.conv1(x)))  # 通过第一层卷积和池化x = self.pool(torch.relu(self.conv2(x)))  # 通过第二层卷积和池化x = x.view(-1, 64 * 7 * 7)  # 展平特征图x = torch.relu(self.fc1(x))  # 通过全连接层x = self.fc2(x)  # 输出层return x# 实例化模型、损失函数和优化器
model = CNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=learning_rate)# 训练模型
for epoch in range(num_epochs):for images, labels in train_loader:optimizer.zero_grad()  # 清除梯度outputs = model(images)  # 前向传播loss = criterion(outputs, labels)  # 计算损失loss.backward()  # 反向传播optimizer.step()  # 更新权重print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')# 测试模型并展示结果
model.eval()  # 切换到评估模式
with torch.no_grad():# 选择几张测试图片data_iter = iter(test_loader)images, labels = next(data_iter)outputs = model(images)# 获取预测结果_, predicted = torch.max(outputs.data, 1)# 绘制结果fig, axes = plt.subplots(1, 5, figsize=(12, 4))for i in range(5):axes[i].imshow(images[i][0], cmap='gray')  # 显示灰度图像axes[i].set_title(f'Predicted: {predicted[i].item()}, Actual: {labels[i].item()}')axes[i].axis('off')plt.show()

tensorflow代码

import tensorflow as tf
from tensorflow.keras import layers, models
from tensorflow.keras.datasets import mnist
import matplotlib.pyplot as plt# 超参数
batch_size = 64
learning_rate = 0.001
num_epochs = 5# 下载 MNIST 数据集
(x_train, y_train), (x_test, y_test) = 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, 1)  # 添加通道维度
x_test = x_test.reshape(-1, 28, 28, 1)  # 添加通道维度# 定义卷积神经网络模型
model = models.Sequential([layers.Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=(28, 28, 1)),  # 第一层卷积layers.MaxPooling2D(pool_size=(2, 2)),  # 池化层layers.Conv2D(64, kernel_size=(3, 3), activation='relu'),  # 第二层卷积layers.MaxPooling2D(pool_size=(2, 2)),  # 池化层layers.Flatten(),  # 展平layers.Dense(128, activation='relu'),  # 全连接层layers.Dense(10, activation='softmax')  # 输出层
])# 编译模型
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=learning_rate),loss='sparse_categorical_crossentropy',metrics=['accuracy'])# 训练模型
model.fit(x_train, y_train, batch_size=batch_size, epochs=num_epochs, verbose=1)# 测试模型并展示结果
test_loss, test_accuracy = model.evaluate(x_test, y_test, verbose=2)
print(f'Accuracy of the model on the test images: {test_accuracy * 100:.2f}%')# 选择几张测试图片
predictions = model.predict(x_test)
predicted_classes = tf.argmax(predictions, axis=1)# 绘制结果
fig, axes = plt.subplots(1, 5, figsize=(12, 4))
for i in range(5):axes[i].imshow(x_test[i].reshape(28, 28), cmap='gray')  # 显示灰度图像axes[i].set_title(f'Predicted: {predicted_classes[i].numpy()}, Actual: {y_test[i]}')axes[i].axis('off')
plt.show()

在这里插入图片描述


http://www.ppmy.cn/server/143116.html

相关文章

MySQL Online DDL

文章目录 1. 在线DDL的优势2. 支持的DDL操作3. 在线DDL的原理4. Online DDL的操作流程1. 准备阶段(Prepare phase)2. 拷贝阶段(Copy phase)3. 应用阶段(Apply phase)4. 替换阶段(Swap phase&…

【C++动态规划】3148. 矩阵中的最大得分|1819

本文涉及知识点 C动态规划 LeetCode 3148. 矩阵中的最大得分 给你一个由 正整数 组成、大小为 m x n 的矩阵 grid。你可以从矩阵中的任一单元格移动到另一个位于正下方或正右侧的任意单元格(不必相邻)。从值为 c1 的单元格移动到值为 c2 的单元格的得…

如何配置 Flink CDC 连接 OceanBase 实现数据实时同步

在大数据处理方面,Flink CDC(Change Data Capture)是一款功能强大的工具,它能实时获取数据库中的变更数据,并将这些数据传送给其他系统进行后续处理。 Flink CDC 结合 OceanBase 分布式数据库高性能、HTAP等特性&#…

shell 接收长参数

以备份 mysql 脚本为例,如下 #!/bin/bash # 分隔符 str"-"# 定义分割线函数 FenGeLine() {## 获取屏幕宽度ScreenLen$(stty size |awk {print $2})## 标题宽度TitleLen$(echo -n $1 |wc -c)#echo $TitleLen## 左右分割线长度LineLen$(((${ScreenLen} - $…

Qt桌面应用开发 第四天(对话框 界面布局)

目录 1.对话框 1.1模拟对话框 1.2非模拟对话框 1.3消息对话框 1.3.1询问对话框 1.3.2严重错误对话框 1.3.3信息提示对话框 1.3.4警告对话框 1.4其他对话框 1.4.1颜色对话框 1.4.2文件对话框 1.4.3字体对话框 1.5界面布局 1.对话框 1.1模拟对话框 会阻塞同一应用…

安全、便捷、效率高,明达边缘计算网关助力制药装备企业远程调机

随着药厂对设备运维需求的增长,制药装备企业需要在提高运维效率的同时,降低人工及差旅成本。制药装备因其数据具有高度的保密性,要求运维工程师提供安全可靠的远程调试方式。本案例介绍了明达技术MBox20系列5口WIFI通用网关在制药装备上的应用…

【汇编语言】数据处理的两个基本问题(三) —— 汇编语言的艺术:从div,dd,dup到结构化数据的访问

文章目录 前言1. div指令1.1 使用div时的注意事项1.2 使用格式1.3 多种内存单元表示方法进行举例1.4 问题一1.5 问题一的分析与求解1.5.1 分析1.5.2 程序实现 1.6 问题二1.7 问题二的分析与求解1.7.1 分析1.7.2 程序实现 2. 伪指令 dd2.1 什么是dd?2.2 问题三2.3 问…

【头歌实训:循环调度法】

头歌实训:循环调度法 文章目录 任务描述相关知识1. 如何设计一个队列2. C STL的队列容器queue2.1 queue的定义2.2 queue容器内元素的访问输出结果:2.3 queue常用函数实例解析2.4 queue的注意事项2.5 一个完整的队列程序示例 编程要求输入:输出:限制:输入…