【人工智能】 用Python构建图像分类模型:从TensorFlow到PyTorch的全面指南
随着深度学习在计算机视觉领域的迅猛发展,图像分类作为其核心任务之一,受到了广泛的关注。本文旨在详细介绍如何使用Python构建图像分类模型,从TensorFlow到PyTorch两个主流深度学习框架进行全面对比与实践。文章首先回顾了图像分类的基本概念与常用数据集,然后深入探讨了TensorFlow和PyTorch的核心机制与优势。通过大量的代码示例和中文注释,读者将学习如何搭建、训练和评估一个简单的图像分类模型。此外,文章还涵盖了模型优化、性能评估以及迁移学习等高级主题,帮助读者全面掌握从数据预处理到模型部署的完整流程。通过对比分析,本文不仅展示了两大框架在实际应用中的差异与互补之处,还提供了实用的建议,助力开发者根据项目需求选择最合适的工具。无论是初学者还是有经验的开发者,本文都将成为构建高效图像分类模型的宝贵资源。
由于篇幅限制,本文将分多个部分详细展开。以下是文章的结构纲要,并在接下来的部分中逐步深入每个主题。
目录
- 引言
- 图像分类基础
- 什么是图像分类
- 常用数据集介绍
- TensorFlow简介
- TensorFlow的核心概念
- 环境搭建与配置
- 使用TensorFlow构建图像分类模型
- 数据预处理
- 模型构建
- 模型训练
- 模型评估
- PyTorch简介
- PyTorch的核心概念
- 环境搭建与配置
- 使用PyTorch构建图像分类模型
- 数据预处理
- 模型构建
- 模型训练
- 模型评估
- TensorFlow与PyTorch的对比分析
- 编程模型
- 性能与效率
- 社区与生态系统
- 模型优化与调参
- 超参数调整
- 模型正则化
- 数据增强
- 迁移学习在图像分类中的应用
- 迁移学习概述
- 使用预训练模型
- 微调策略
- 模型部署与应用
- 部署到Web服务
- 移动端部署
- 实践案例:使用CIFAR-10数据集
- 数据集介绍
- TensorFlow实现
- PyTorch实现
- 总结与展望
1. 引言
图像分类作为计算机视觉领域的基础任务之一,广泛应用于人脸识别、自动驾驶、医疗诊断等多个领域。随着深度学习技术的不断进步,构建高效的图像分类模型变得愈加便捷与高效。本文将系统性地介绍如何使用Python中的两大主流深度学习框架——TensorFlow和PyTorch,来构建、训练和评估图像分类模型。通过详细的代码示例和中文注释,读者将能够深入理解模型构建的每一个步骤,并掌握在不同框架下实现相同任务的方法与技巧。
2. 图像分类基础
2.1 什么是图像分类
图像分类是指将输入的图像分配到预定义的类别中的任务。例如,将一张动物的图片分类为“猫”、“狗”或“鸟”。这一任务在计算机视觉中具有重要的应用价值,广泛应用于安全监控、智能家居、医疗影像分析等领域。
2.2 常用数据集介绍
在构建图像分类模型时,选择合适的数据集至关重要。以下是几个常用的数据集:
- MNIST:手写数字数据集,包含60000个训练样本和10000个测试样本,适合用于入门级别的分类任务。
- CIFAR-10:包含60000张32x32的彩色图像,分为10个类别,每个类别6000张图像。
- ImageNet:大型视觉数据库,包含超过1400万张图像,分为1000个类别,是深度学习模型训练的重要基准。
3. TensorFlow简介
3.1 TensorFlow的核心概念
TensorFlow是由Google开发的开源深度学习框架,具有高度的灵活性和可扩展性。其核心概念包括:
- 张量(Tensor):数据的基本单位,类似于多维数组。
- 计算图(Computational Graph):将复杂的计算任务拆分为一系列节点和边,节点表示操作,边表示数据流。
- 会话(Session):用于执行计算图中的操作。
3.2 环境搭建与配置
要开始使用TensorFlow,首先需要安装相应的环境。以下是安装步骤:
# 使用pip安装TensorFlow
pip install tensorflow
确保你的Python版本为3.6及以上。安装完成后,可以通过以下代码验证安装是否成功:
import tensorflow as tfprint("TensorFlow版本:", tf.__version__)
4. 使用TensorFlow构建图像分类模型
本节将通过实际代码示例,展示如何使用TensorFlow构建一个简单的图像分类模型。我们将以CIFAR-10数据集为例,进行数据预处理、模型构建、训练和评估。
4.1 数据预处理
首先,加载CIFAR-10数据集,并进行必要的预处理,如归一化和独热编码。
import tensorflow as tf
from tensorflow.keras import datasets, layers, models
import matplotlib.pyplot as plt# 加载CIFAR-10数据集
(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data()# 归一化图像数据到0-1范围
train_images, test_images = train_images / 255.0, test_images / 255.0# 类别名称
class_names = ['飞机', '汽车', '鸟', '猫', '鹿','狗', '青蛙', '马', '船', '卡车']# 可视化前25张训练图像
plt.figure(figsize=(10,10))
for i in range(25):plt.subplot(5,5,i+1)plt.xticks([])plt.yticks([])plt.grid(False)plt.imshow(train_images[i])# 标签是一个数组,需要取第一个元素plt.xlabel(class_names[train_labels[i][0]])
plt.show()
4.2 模型构建
使用TensorFlow的Keras API构建一个简单的卷积神经网络(CNN)。
# 构建卷积神经网络模型
model = models.Sequential()
# 第一个卷积层,32个3x3的滤波器,激活函数为ReLU
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)))
# 第一个池化层,2x2的最大池化
model.add(layers.MaxPooling2D((2, 2)))
# 第二个卷积层,64个3x3的滤波器
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
# 第二个池化层
model.add(layers.MaxPooling2D((2, 2)))
# 第三个卷积层,64个3x3的滤波器
model.add(layers.Conv2D(64, (3, 3), activation='relu'))# 添加全连接层
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
# 输出层,10个神经元对应10个类别,激活函数为softmax
model.add(layers.Dense(10, activation='softmax'))# 输出模型结构
model.summary()
4.3 模型编译与训练
编译模型并进行训练。选择优化器、损失函数和评估指标。
# 编译模型
model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])# 训练模型,设置批次大小和训练轮数
history = model.fit(train_images, train_labels, epochs=10,validation_data=(test_images, test_labels))
4.4 模型评估
评估模型在测试集上的性能,并绘制训练过程中的准确率和损失变化曲线。
# 评估模型
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
print("\n测试准确率:", test_acc)# 绘制训练和验证的准确率和损失
plt.figure(figsize=(12, 4))# 准确率曲线
plt.subplot(1, 2, 1)
plt.plot(history.history['accuracy'], label='训练准确率')
plt.plot(history.history['val_accuracy'], label='验证准确率')
plt.xlabel('Epoch')
plt.ylabel('准确率')
plt.legend(loc='lower right')
plt.title('训练与验证准确率')# 损失曲线
plt.subplot(1, 2, 2)
plt.plot(history.history['loss'], label='训练损失')
plt.plot(history.history['val_loss'], label='验证损失')
plt.xlabel('Epoch')
plt.ylabel('损失')
plt.legend(loc='upper right')
plt.title('训练与验证损失')plt.show()
5. PyTorch简介
5.1 PyTorch的核心概念
PyTorch是由Facebook开发的开源深度学习框架,以其动态计算图和简洁的API设计而著称。其核心概念包括:
- 张量(Tensor):类似于NumPy的多维数组,支持GPU加速。
- 自动求导(Autograd):自动计算梯度,简化反向传播过程。
- 神经网络模块(nn.Module):构建复杂模型的基础单元。
5.2 环境搭建与配置
安装PyTorch可以通过以下命令完成。根据你的系统和CUDA版本选择合适的安装命令。
# 以CPU版本为例
pip install torch torchvision
安装完成后,可以通过以下代码验证安装是否成功:
import torchprint("PyTorch版本:", torch.__version__)
print("是否支持CUDA:", torch.cuda.is_available())
6. 使用PyTorch构建图像分类模型
本节将通过PyTorch实现与前述TensorFlow相同的图像分类任务,包括数据预处理、模型构建、训练和评估。
6.1 数据预处理
使用torchvision
库加载和预处理CIFAR-10数据集。
import torch
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np# 定义数据变换,包括转换为Tensor和归一化
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])# 下载并加载训练集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,shuffle=True, num_workers=2)# 下载并加载测试集
testset = torchvision.datasets.CIFAR10(root='./data', train=False,download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4,shuffle=False, num_workers=2)# 类别名称
classes = ('飞机', '汽车', '鸟', '猫','鹿', '狗', '青蛙', '马', '船', '卡车')# 函数:展示图像
def imshow(img):img = img / 2 + 0.5 # 反归一化npimg = img.numpy()plt.imshow(np.transpose(npimg, (1, 2, 0)))plt.show()# 获取一些随机训练图像
dataiter = iter(trainloader)
images, labels = dataiter.next()# 展示图像
imshow(torchvision.utils.make_grid(images))
# 打印标签
print('标签: ', ' '.join(f'{classes[labels[j]]}' for j in range(4)))
6.2 模型构建
定义一个简单的卷积神经网络,继承自nn.Module
。
import torch.nn as nn
import torch.nn.functional as F# 定义卷积神经网络
class Net(nn.Module):def __init__(self):super(Net, self).__init__()# 第一卷积层,输入3通道,输出6通道,卷积核大小5self.conv1 = nn.Conv2d(3, 6, 5)# 第二卷积层,输入6通道,输出16通道,卷积核大小5self.conv2 = nn.Conv2d(6, 16, 5)# 全连接层,16*5*5输入,120输出self.fc1 = nn.Linear(16 * 5 * 5, 120)# 全连接层,120输入,84输出self.fc2 = nn.Linear(120, 84)# 输出层,84输入,10输出self.fc3 = nn.Linear(84, 10)def forward(self, x):# 第一层卷积 + ReLU + 最大池化x = F.max_pool2d(F.relu(self.conv1(x)), 2)# 第二层卷积 + ReLU + 最大池化x = F.max_pool2d(F.relu(self.conv2(x)), 2)# 展平x = x.view(-1, 16 * 5 * 5)# 第一全连接层 + ReLUx = F.relu(self.fc1(x))# 第二全连接层 + ReLUx = F.relu(self.fc2(x))# 输出层x = self.fc3(x)return x# 实例化网络
net = Net()
print(net)
6.3 模型训练
定义损失函数和优化器,然后进行模型训练。
import torch.optim as optim# 定义损失函数为交叉熵损失
criterion = nn.CrossEntropyLoss()
# 定义优化器为随机梯度下降,学习率0.001,动量0.9
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)# 训练网络
for epoch in range(2): # 训练2个周期作为示例running_loss = 0.0for i, data in enumerate(trainloader, 0):# 获取输入数据inputs, labels = data# 梯度清零optimizer.zero_grad()# 前向传播outputs = net(inputs)# 计算损失loss = criterion(outputs, labels)# 反向传播loss.backward()# 优化optimizer.step()# 打印统计信息running_loss += loss.item()if i % 2000 == 1999: # 每2000批次打印一次print(f'[Epoch {epoch + 1}, Batch {i + 1}] 损失: {running_loss / 2000:.3f}')running_loss = 0.0print('训练完成')
6.4 模型评估
在测试集上评估模型的性能,并计算准确率。
correct = 0
total = 0
# 不需要计算梯度
with torch.no_grad():for data in testloader:images, labels = dataoutputs = net(images)# 获取最大概率的索引_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()print(f'测试集准确率: {100 * correct / total:.2f}%')
7. TensorFlow与PyTorch的对比分析
在选择构建图像分类模型的深度学习框架时,TensorFlow和PyTorch是目前最受欢迎的两大选择。尽管两者都功能强大,但在编程模型、性能与效率、社区与生态系统等方面存在显著差异。以下将对这两者进行详细对比分析,帮助开发者根据具体需求做出最佳选择。
7.1 编程模型
TensorFlow
TensorFlow最初采用的是静态计算图(Static Computational Graph)模型。这意味着在定义模型时,需要先构建整个计算图,然后再执行。这种方式在优化和部署时具有优势,因为计算图在执行前已经确定,可以进行各种优化。
然而,静态计算图的缺点在于灵活性较低,特别是在处理动态变化的数据或模型结构时。例如,在处理变长序列或需要条件控制的网络时,静态计算图可能显得笨拙和不便。
从TensorFlow 2.0开始,引入了Eager Execution(即时执行)模式,使得编程体验更接近于PyTorch的动态计算图。这大大提升了TensorFlow的灵活性和易用性,尤其对于研究和快速原型开发。
PyTorch
PyTorch采用的是动态计算图(Dynamic Computational Graph)模型,即在每次前向传播时即时构建计算图。这种方式具有高度的灵活性,特别适合需要频繁修改模型结构或处理复杂数据依赖的任务。
动态计算图的另一个优势在于调试更加方便。由于计算图是在运行时构建的,开发者可以使用标准的调试工具(如Python的调试器)逐步检查每一步的计算过程。
总体而言,PyTorch的动态计算图模型使其在研究和实验阶段更加灵活,而TensorFlow在部署和优化方面具有优势。
7.2 性能与效率
在性能和效率方面,TensorFlow和PyTorch均提供了对GPU加速的支持,但两者在具体实现上有所不同。
TensorFlow
TensorFlow在静态计算图模式下,可以进行全局优化,包括操作融合、内存优化等,从而在大规模部署时表现出色。此外,TensorFlow Serving等工具使得模型的部署和扩展更加便捷。
TensorFlow也提供了XLA(Accelerated Linear Algebra)编译器,可以对计算图进行进一步优化,提升执行效率。对于大规模分布式训练,TensorFlow的分布式策略(如MirroredStrategy、TPUStrategy)也提供了强大的支持。
PyTorch
PyTorch在动态计算图模式下,尽管灵活性高,但在某些情况下可能会导致性能略低于TensorFlow。然而,随着PyTorch的不断发展,尤其是引入了TorchScript和Just-In-Time(JIT)编译器,PyTorch在性能优化方面取得了显著进展。
TorchScript允许开发者将动态计算图转换为静态图,从而在部署时获得更高的执行效率。此外,PyTorch的分布式训练(如DistributedDataParallel)也在不断完善,逐步缩小与TensorFlow在大规模训练中的性能差距。
7.3 社区与生态系统
TensorFlow
TensorFlow拥有庞大且活跃的社区,提供了丰富的资源和工具。TensorFlow Hub、TensorFlow Extended(TFX)、TensorFlow Lite等生态系统组件覆盖了从研究到生产的各个环节。此外,TensorFlow的官方文档详尽,教程丰富,适合各种层次的开发者学习和使用。
TensorFlow在工业界的应用广泛,许多大公司(如Google、Intel)对其进行了深度优化和支持。TensorFlow的生态系统还包括Keras,这是一个高层次的神经网络API,简化了模型的构建和训练过程。
PyTorch
PyTorch同样拥有一个快速增长的社区,尤其在学术界和研究领域中备受青睐。PyTorch的文档清晰,示例丰富,易于上手。此外,PyTorch的生态系统也在不断扩展,如TorchVision、TorchText、TorchAudio等,涵盖了计算机视觉、自然语言处理和音频处理等多个领域。
近年来,PyTorch在工业界的应用也在快速增长,许多公司(如Facebook、Microsoft)对其进行了积极的支持和贡献。PyTorch的灵活性和易用性使其成为许多前沿研究和创新项目的首选框架。
7.4 总结
TensorFlow和PyTorch各有优势,选择哪一个取决于具体的项目需求和开发者的偏好。TensorFlow在部署和大规模优化方面表现出色,而PyTorch在研究和灵活性方面更具优势。随着两者的不断发展,差异正在逐渐缩小,开发者可以根据具体情况选择最适合的框架。
8. 模型优化与调参
构建初步的图像分类模型后,提升模型性能的关键在于优化和调参。本文将介绍超参数调整、模型正则化和数据增强等常用的优化方法,并通过具体代码示例加以说明。
8.1 超参数调整
超参数(Hyperparameters)是指在训练过程中需要手动设置的参数,如学习率、批次大小、优化器类型等。合理的超参数设置可以显著提升模型性能。
学习率调整
学习率是影响模型收敛速度和稳定性的关键参数。学习率过高可能导致训练不稳定,甚至发散;学习率过低则会导致训练过程缓慢,难以达到全局最优。
一种常用的方法是使用学习率调度器(Learning Rate Scheduler),根据训练轮次动态调整学习率。例如,使用学习率衰减策略,每经过一定数量的epoch后减小学习率。
TensorFlow 示例:
from tensorflow.keras.callbacks import LearningRateSchedulerdef scheduler(epoch, lr):if epoch < 10:return lrelse:return lr * 0.5# 定义学习率调度器回调
lr_scheduler = LearningRateScheduler(scheduler)# 训练模型时加入回调
history = model.fit(train_images, train_labels, epochs=20,validation_data=(test_images, test_labels),callbacks=[lr_scheduler])
PyTorch 示例:
import torch.optim.lr_scheduler as lr_scheduler# 定义优化器
optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9)# 定义学习率调度器,每10个epoch衰减一次
scheduler = lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)# 训练过程中更新学习率
for epoch in range(20):running_loss = 0.0for i, data in enumerate(trainloader, 0):inputs, labels = dataoptimizer.zero_grad()outputs = net(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item()scheduler.step()print(f'Epoch {epoch + 1} 完成')
批次大小调整
批次大小(Batch Size)影响模型训练的稳定性和内存使用。较大的批次大小可以加速训练,但可能需要更多的内存资源;较小的批次大小则有助于模型泛化能力的提升。
8.2 模型正则化
正则化技术旨在防止模型过拟合,提高模型在未见数据上的泛化能力。常见的正则化方法包括L1/L2正则化、Dropout和早停(Early Stopping)等。
L2 正则化
L2正则化通过在损失函数中添加权重的平方和,鼓励模型参数保持较小的值,防止过拟合。
TensorFlow 示例:
from tensorflow.keras import regularizers# 在卷积层和全连接层中加入L2正则化
model = models.Sequential([layers.Conv2D(32, (3, 3), activation='relu',kernel_regularizer=regularizers.l2(0.001),input_shape=(32, 32, 3)),layers.MaxPooling2D((2, 2)),layers.Conv2D(64, (3, 3), activation='relu',kernel_regularizer=regularizers.l2(0.001)),layers.MaxPooling2D((2, 2)),layers.Conv2D(64, (3, 3), activation='relu',kernel_regularizer=regularizers.l2(0.001)),layers.Flatten(),layers.Dense(64, activation='relu',kernel_regularizer=regularizers.l2(0.001)),layers.Dense(10, activation='softmax')
])
PyTorch 示例:
# 在PyTorch中,L2正则化通过优化器的weight_decay参数实现
optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9, weight_decay=1e-4)
Dropout
Dropout是一种在训练过程中随机忽略部分神经元的技术,有助于减少神经网络对特定节点的依赖,从而提升泛化能力。
TensorFlow 示例:
model = models.Sequential([layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)),layers.MaxPooling2D((2, 2)),layers.Dropout(0.25),layers.Conv2D(64, (3, 3), activation='relu'),layers.MaxPooling2D((2, 2)),layers.Dropout(0.25),layers.Conv2D(64, (3, 3), activation='relu'),layers.Flatten(),layers.Dense(64, activation='relu'),layers.Dropout(0.5),layers.Dense(10, activation='softmax')
])
PyTorch 示例:
import torch.nn.functional as Fclass Net(nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = nn.Conv2d(3, 32, 3, padding=1)self.conv2 = nn.Conv2d(32, 64, 3, padding=1)self.conv3 = nn.Conv2d(64, 128, 3, padding=1)self.pool = nn.MaxPool2d(2, 2)self.dropout1 = nn.Dropout(0.25)self.dropout2 = nn.Dropout(0.5)self.fc1 = nn.Linear(128 * 4 * 4, 512)self.fc2 = nn.Linear(512, 10)def forward(self, x):x = F.relu(self.conv1(x))x = self.pool(x)x = self.dropout1(x)x = F.relu(self.conv2(x))x = self.pool(x)x = self.dropout1(x)x = F.relu(self.conv3(x))x = self.pool(x)x = self.dropout1(x)x = x.view(-1, 128 * 4 * 4)x = F.relu(self.fc1(x))x = self.dropout2(x)x = self.fc2(x)return x
早停(Early Stopping)
早停是一种在验证集性能不再提升时提前终止训练的策略,防止模型在训练集上过拟合。
TensorFlow 示例:
from tensorflow.keras.callbacks import EarlyStopping# 定义早停回调,当验证损失在连续5个epoch内不再下降时停止训练
early_stopping = EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True)# 训练模型时加入早停回调
history = model.fit(train_images, train_labels, epochs=100,validation_data=(test_images, test_labels),callbacks=[early_stopping])
PyTorch 示例:
PyTorch没有内置的早停机制,但可以通过自定义代码实现:
best_val_loss = float('inf')
patience = 5
trigger_times = 0for epoch in range(100):# 训练过程net.train()for inputs, labels in trainloader:optimizer.zero_grad()outputs = net(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()# 验证过程net.eval()val_loss = 0.0with torch.no_grad():for inputs, labels in testloader:outputs = net(inputs)loss = criterion(outputs, labels)val_loss += loss.item()val_loss /= len(testloader)print(f'Epoch {epoch + 1}, Validation Loss: {val_loss:.4f}')# 检查是否需要早停if val_loss < best_val_loss:best_val_loss = val_losstrigger_times = 0else:trigger_times += 1if trigger_times >= patience:print('早停触发,停止训练')break
8.3 数据增强
数据增强(Data Augmentation)通过对训练数据进行随机变换,生成新的训练样本,有助于提升模型的泛化能力。常见的数据增强方法包括旋转、平移、翻转、缩放、颜色调整等。
TensorFlow 示例:
from tensorflow.keras.preprocessing.image import ImageDataGenerator# 定义数据增强生成器
datagen = ImageDataGenerator(rotation_range=15, # 随机旋转15度width_shift_range=0.1, # 水平平移10%height_shift_range=0.1, # 垂直平移10%horizontal_flip=True, # 随机水平翻转zoom_range=0.1 # 随机缩放10%
)# 拟合数据生成器
datagen.fit(train_images)# 使用数据增强进行训练
history = model.fit(datagen.flow(train_images, train_labels, batch_size=32),epochs=50, validation_data=(test_images, test_labels),callbacks=[early_stopping])
PyTorch 示例:
import torchvision.transforms as transforms# 定义数据增强变换
transform_train = transforms.Compose([transforms.RandomCrop(32, padding=4), # 随机裁剪transforms.RandomHorizontalFlip(), # 随机水平翻转transforms.RandomRotation(15), # 随机旋转15度transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])# 应用数据增强到训练集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,download=True, transform=transform_train)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,shuffle=True, num_workers=2)
通过上述优化与调参方法,可以显著提升图像分类模型的性能和泛化能力。接下来,本文将介绍如何利用迁移学习进一步提升模型效果。
9. 迁移学习在图像分类中的应用
迁移学习(Transfer Learning)是一种利用在一个任务上学到的知识来加速另一个相关任务学习的方法。在图像分类中,迁移学习通常涉及使用在大规模数据集(如ImageNet)上预训练的模型,然后在目标数据集上进行微调。这种方法不仅可以缩短训练时间,还能显著提升模型的性能,特别是在目标数据集较小的情况下。
9.1 迁移学习概述
迁移学习的核心思想是利用预训练模型的特征提取能力。预训练模型在大规模数据集上学习到了丰富的特征表示,这些特征在许多图像分类任务中都是通用的。通过在预训练模型的基础上进行微调,可以快速适应新的任务,提高模型的泛化能力。
迁移学习通常包括以下步骤:
- 选择预训练模型:选择在大规模数据集上训练好的模型,如VGG、ResNet、Inception等。
- 冻结部分层:冻结预训练模型的前几层,只训练后几层,以保留通用特征。
- 添加新层:在预训练模型的基础上添加适应目标任务的新层。
- 微调模型:在目标数据集上训练整个模型或部分层,以适应新任务。
9.2 使用预训练模型
以下将分别展示在TensorFlow和PyTorch中如何使用预训练模型进行迁移学习。
TensorFlow 示例:
from tensorflow.keras.applications import VGG16
from tensorflow.keras import layers, models# 加载预训练的VGG16模型,不包括顶部的全连接层
base_model = VGG16(weights='imagenet', include_top=False, input_shape=(32, 32, 3))# 冻结预训练模型的所有层
for layer in base_model.layers:layer.trainable = False# 构建新的模型
model = models.Sequential([base_model,layers.Flatten(),layers.Dense(256, activation='relu'),layers.Dropout(0.5),layers.Dense(10, activation='softmax')
])# 编译模型
model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])# 训练模型
history = model.fit(train_images, train_labels, epochs=20,validation_data=(test_images, test_labels))
PyTorch 示例:
import torchvision.models as models
import torch.nn as nn# 加载预训练的ResNet18模型
resnet = models.resnet18(pretrained=True)# 冻结预训练模型的所有参数
for param in resnet.parameters():param.requires_grad = False# 替换最后的全连接层以适应CIFAR-10
num_ftrs = resnet.fc.in_features
resnet.fc = nn.Linear(num_ftrs, 10)# 定义优化器,只优化最后的全连接层
optimizer = optim.SGD(resnet.fc.parameters(), lr=0.001, momentum=0.9)# 定义损失函数
criterion = nn.CrossEntropyLoss()# 训练模型
for epoch in range(10):resnet.train()running_loss = 0.0for inputs, labels in trainloader:optimizer.zero_grad()outputs = resnet(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item()print(f'Epoch {epoch + 1}, 损失: {running_loss / len(trainloader):.3f}')
9.3 微调策略
在某些情况下,仅冻结预训练模型的部分层可能不足以适应新任务。这时,可以逐步解冻更多层,并以较低的学习率进行微调,以进一步提升模型性能。
TensorFlow 示例:
# 解冻预训练模型的最后几个卷积块
for layer in base_model.layers[-4:]:layer.trainable = True# 重新编译模型,使用较低的学习率
from tensorflow.keras.optimizers import Adam
model.compile(optimizer=Adam(learning_rate=1e-5),loss='sparse_categorical_crossentropy',metrics=['accuracy'])# 继续训练模型
history_fine = model.fit(train_images, train_labels, epochs=10,validation_data=(test_images, test_labels))
PyTorch 示例:
# 解冻预训练模型的所有参数
for param in resnet.parameters():param.requires_grad = True# 重新定义优化器,使用较低的学习率
optimizer = optim.SGD(resnet.parameters(), lr=0.0001, momentum=0.9)# 继续训练模型
for epoch in range(5):resnet.train()running_loss = 0.0for inputs, labels in trainloader:optimizer.zero_grad()outputs = resnet(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item()print(f'Epoch {epoch + 1}, 损失: {running_loss / len(trainloader):.3f}')
通过迁移学习,可以在较短时间内构建出高性能的图像分类模型,尤其在目标数据集有限的情况下,效果尤为显著。
10. 模型部署与应用
构建和训练好图像分类模型后,下一步是将其部署到实际应用中。本文将介绍如何将模型部署到Web服务和移动端设备。
10.1 部署到Web服务
将图像分类模型部署为Web服务,使其能够通过HTTP请求进行访问,是许多应用场景的常见需求。以下以TensorFlow和PyTorch分别介绍如何实现这一目标。
TensorFlow 部署示例
使用TensorFlow Serving,可以轻松地将TensorFlow模型部署为高性能的Web服务。
步骤:
- 保存模型:
# 保存TensorFlow模型
model.save('saved_model/my_model')
- 安装TensorFlow Serving:
TensorFlow Serving可以通过Docker快速部署。
# 拉取TensorFlow Serving镜像
docker pull tensorflow/serving# 运行TensorFlow Serving容器
docker run -p 8501:8501 \--mount type=bind,source=$(pwd)/saved_model/my_model,target=/models/my_model \-e MODEL_NAME=my_model -t tensorflow/serving
- 发送预测请求:
使用Python的requests
库发送HTTP POST请求进行预测。
import json
import requests
import numpy as np# 加载并预处理图像
def load_image(path):from PIL import Imageimg = Image.open(path).resize((32, 32))img = np.array(img) / 255.0img = img.reshape(1, 32, 32, 3).tolist()return img# 构建请求数据
image = load_image('test_image.png')
data = json.dumps({"instances": image})# 发送请求
headers = {"content-type": "application/json"}
response = requests.post('http://localhost:8501/v1/models/my_model:predict', data=data, headers=headers)# 解析响应
predictions = json.loads(response.text)['predictions']
predicted_class = np.argmax(predictions[0])
print(f'预测类别: {predicted_class}')
PyTorch 部署示例
PyTorch模型可以使用Flask框架构建简单的Web服务。
步骤:
- 保存模型:
# 保存PyTorch模型
torch.save(resnet.state_dict(), 'resnet_cifar10.pth')
- 创建Flask应用:
from flask import Flask, request, jsonify
import torch
import torchvision.transforms as transforms
from PIL import Imageapp = Flask(__name__)# 定义模型结构
model = models.resnet18(pretrained=True)
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, 10)
model.load_state_dict(torch.load('resnet_cifar10.pth'))
model.eval()# 定义图像预处理
preprocess = transforms.Compose([transforms.Resize(256),transforms.CenterCrop(32),transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])# 定义类别
classes = ['飞机', '汽车', '鸟', '猫', '鹿', '狗', '青蛙', '马', '船', '卡车']@app.route('/predict', methods=['POST'])
def predict():if 'file' not in request.files:return jsonify({'error': 'No file provided'})file = request.files['file']img = Image.open(file.stream)img = preprocess(img)img = img.unsqueeze(0) # 添加batch维度with torch.no_grad():outputs = model(img)_, predicted = torch.max(outputs, 1)return jsonify({'prediction': classes[predicted.item()]})if __name__ == '__main__':app.run(debug=True)
- 发送预测请求:
使用requests
库发送POST请求。
import requests# 打开图像文件
files = {'file': open('test_image.png', 'rb')}# 发送请求
response = requests.post('http://localhost:5000/predict', files=files)# 解析响应
print(response.json())
10.2 移动端部署
将图像分类模型部署到移动设备,可以实现实时图像分类应用。以下分别介绍使用TensorFlow Lite和PyTorch Mobile进行部署的方法。
TensorFlow Lite 部署示例
步骤:
- 转换模型为TensorFlow Lite格式:
import tensorflow as tf# 加载已保存的模型
saved_model_dir = 'saved_model/my_model'
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)# 进行模型量化以减小模型大小
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_model = converter.convert()# 保存TensorFlow Lite模型
with open('model.tflite', 'wb') as f:f.write(tflite_model)
- 在移动端使用TensorFlow Lite模型:
以Android为例,使用TensorFlow Lite的Interpreter进行推理。
Android 代码示例(Kotlin):
import org.tensorflow.lite.Interpreter
import java.nio.MappedByteBuffer
import java.nio.ByteBuffer
import android.content.res.AssetFileDescriptor// 加载模型
fun loadModelFile(assetManager: AssetManager, modelName: String): MappedByteBuffer {val fileDescriptor: AssetFileDescriptor = assetManager.openFd(modelName)val inputStream = FileInputStream(fileDescriptor.fileDescriptor)val fileChannel = inputStream.channelval startOffset = fileDescriptor.startOffsetval declaredLength = fileDescriptor.declaredLengthreturn fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength)
}// 初始化Interpreter
val tfliteModel: MappedByteBuffer = loadModelFile(assets, "model.tflite")
val interpreter = Interpreter(tfliteModel)// 进行推理
fun classifyImage(bitmap: Bitmap): String {// 预处理图像val input = preprocessBitmap(bitmap)val output = Array(1) { FloatArray(10) }interpreter.run(input, output)val predictedIndex = output[0].indices.maxByOrNull { output[0][it] } ?: -1return classes[predictedIndex]
}
PyTorch Mobile 部署示例
步骤:
- 转换模型为TorchScript格式:
# 加载模型并转换为评估模式
model = models.resnet18(pretrained=True)
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, 10)
model.load_state_dict(torch.load('resnet_cifar10.pth'))
model.eval()# 创建示例输入
example = torch.randn(1, 3, 32, 32)# 转换为TorchScript
traced_script_module = torch.jit.trace(model, example)# 保存TorchScript模型
traced_script_module.save("resnet_cifar10.pt")
- 在移动端使用TorchScript模型:
以Android为例,使用PyTorch Mobile进行推理。
Android 代码示例(Kotlin):
import org.pytorch.IValue
import org.pytorch.Module
import org.pytorch.Tensor// 加载TorchScript模型
val module = Module.load(assetFilePath(this, "resnet_cifar10.pt"))// 进行推理
fun classifyImage(bitmap: Bitmap): String {val inputTensor = preprocessBitmap(bitmap)val outputTensor = module.forward(IValue.from(inputTensor)).toTensor()val scores = outputTensor.dataAsFloatArrayval predictedIndex = scores.indices.maxByOrNull { scores[it] } ?: -1return classes[predictedIndex]
}
通过上述方法,可以将训练好的图像分类模型部署到Web服务和移动端设备,实现实时图像分类应用。
11. 实践案例:使用CIFAR-10数据集
为了更好地理解上述概念和方法,本文将以CIFAR-10数据集为例,分别使用TensorFlow和PyTorch构建、训练和评估图像分类模型。CIFAR-10是一个包含60000张32x32彩色图像的经典数据集,分为10个类别,每个类别6000张图像。
11.1 数据集介绍
CIFAR-10数据集包含10个类别的图像,类别包括:飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船和卡车。每张图像为32x32像素的彩色图像,适合用于图像分类任务的研究和实验。
11.2 TensorFlow实现
以下是使用TensorFlow构建和训练CIFAR-10图像分类模型的完整代码示例。
import tensorflow as tf
from tensorflow.keras import datasets, layers, models
import matplotlib.pyplot as plt# 加载CIFAR-10数据集
(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data()# 归一化图像数据到0-1范围
train_images, test_images = train_images / 255.0, test_images / 255.0# 类别名称
class_names = ['飞机', '汽车', '鸟', '猫', '鹿','狗', '青蛙', '马', '船', '卡车']# 可视化前25张训练图像
plt.figure(figsize=(10,10))
for i in range(25):plt.subplot(5,5,i+1)plt.xticks([])plt.yticks([])plt.grid(False)plt.imshow(train_images[i])plt.xlabel(class_names[train_labels[i][0]])
plt.show()# 构建卷积神经网络模型
model = models.Sequential([layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)),layers.BatchNormalization(),layers.MaxPooling2D((2, 2)),layers.Dropout(0.25),layers.Conv2D(64, (3, 3), activation='relu'),layers.BatchNormalization(),layers.MaxPooling2D((2, 2)),layers.Dropout(0.25),layers.Conv2D(128, (3, 3), activation='relu'),layers.BatchNormalization(),layers.MaxPooling2D((2, 2)),layers.Dropout(0.25),layers.Flatten(),layers.Dense(512, activation='relu'),layers.BatchNormalization(),layers.Dropout(0.5),layers.Dense(10, activation='softmax')
])# 输出模型结构
model.summary()# 编译模型
model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])# 定义学习率调度器和早停回调
from tensorflow.keras.callbacks import LearningRateScheduler, EarlyStoppingdef scheduler(epoch, lr):if epoch < 20:return lrelse:return lr * 0.5lr_scheduler = LearningRateScheduler(scheduler)
early_stopping = EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True)# 定义数据增强生成器
from tensorflow.keras.preprocessing.image import ImageDataGeneratordatagen = ImageDataGenerator(rotation_range=15,width_shift_range=0.1,height_shift_range=0.1,horizontal_flip=True,zoom_range=0.1
)datagen.fit(train_images)# 训练模型
history = model.fit(datagen.flow(train_images, train_labels, batch_size=64),epochs=50,validation_data=(test_images, test_labels),callbacks=[lr_scheduler, early_stopping])# 评估模型
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
print(f'\n测试准确率: {test_acc:.4f}')# 绘制训练和验证的准确率和损失
plt.figure(figsize=(12, 4))# 准确率曲线
plt.subplot(1, 2, 1)
plt.plot(history.history['accuracy'], label='训练准确率')
plt.plot(history.history['val_accuracy'], label='验证准确率')
plt.xlabel('Epoch')
plt.ylabel('准确率')
plt.legend(loc='lower right')
plt.title('训练与验证准确率')# 损失曲线
plt.subplot(1, 2, 2)
plt.plot(history.history['loss'], label='训练损失')
plt.plot(history.history['val_loss'], label='验证损失')
plt.xlabel('Epoch')
plt.ylabel('损失')
plt.legend(loc='upper right')
plt.title('训练与验证损失')plt.show()
代码解释:
-
数据加载与预处理:
- 使用
tensorflow.keras.datasets.cifar10
加载CIFAR-10数据集。 - 对图像数据进行归一化处理,将像素值缩放到0-1范围。
- 可视化部分训练图像,帮助理解数据分布。
- 使用
-
模型构建:
- 使用
Sequential
模型构建卷积神经网络,包括多个卷积层、批归一化层、池化层和Dropout层。 - 最后通过全连接层和softmax激活函数输出10个类别的概率。
- 使用
-
模型编译与训练:
- 使用Adam优化器和交叉熵损失函数进行编译。
- 定义学习率调度器和早停回调,以优化训练过程。
- 使用数据增强生成器对训练数据进行实时增强,提升模型泛化能力。
-
模型评估与可视化:
- 在测试集上评估模型性能,输出测试准确率。
- 绘制训练和验证过程中的准确率和损失曲线,帮助分析模型训练情况。
11.3 PyTorch实现
以下是使用PyTorch构建和训练CIFAR-10图像分类模型的完整代码示例。
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np# 定义设备
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f'使用设备: {device}')# 定义数据增强和预处理
transform_train = transforms.Compose([transforms.RandomCrop(32, padding=4), # 随机裁剪transforms.RandomHorizontalFlip(), # 随机水平翻转transforms.RandomRotation(15), # 随机旋转15度transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])transform_test = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])# 加载训练集和测试集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,download=True, transform=transform_train)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=128,shuffle=True, num_workers=2)testset = torchvision.datasets.CIFAR10(root='./data', train=False,download=True, transform=transform_test)
testloader = torch.utils.data.DataLoader(testset, batch_size=100,shuffle=False, num_workers=2)# 类别名称
classes = ['飞机', '汽车', '鸟', '猫', '鹿', '狗', '青蛙', '马', '船', '卡车']# 定义卷积神经网络
class Net(nn.Module):def __init__(self):super(Net, self).__init__()# 第一卷积层,输入3通道,输出32通道,卷积核大小3self.conv1 = nn.Conv2d(3, 32, 3, padding=1)self.bn1 = nn.BatchNorm2d(32)# 第二卷积层,输出64通道self.conv2 = nn.Conv2d(32, 64, 3, padding=1)self.bn2 = nn.BatchNorm2d(64)# 第三卷积层,输出128通道self.conv3 = nn.Conv2d(64, 128, 3, padding=1)self.bn3 = nn.BatchNorm2d(128)# 池化层self.pool = nn.MaxPool2d(2, 2)# Dropout层self.dropout = nn.Dropout(0.25)# 全连接层self.fc1 = nn.Linear(128 * 4 * 4, 512)self.bn4 = nn.BatchNorm1d(512)self.fc2 = nn.Linear(512, 10)def forward(self, x):# 第一卷积块x = self.pool(F.relu(self.bn1(self.conv1(x))))# 第二卷积块x = self.pool(F.relu(self.bn2(self.conv2(x))))# 第三卷积块x = self.pool(F.relu(self.bn3(self.conv3(x))))# 展平x = x.view(-1, 128 * 4 * 4)# 全连接层x = F.relu(self.bn4(self.fc1(x)))x = self.dropout(x)x = self.fc2(x)return x# 实例化模型并移动到设备
net = Net().to(device)
print(net)# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9, weight_decay=1e-4)# 定义学习率调度器
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=20, gamma=0.1)# 训练模型
def train_model(net, trainloader, criterion, optimizer, scheduler, epochs=50):net.train()train_losses = []train_accuracies = []val_losses = []val_accuracies = []best_val_acc = 0.0trigger_times = 0patience = 10for epoch in range(epochs):running_loss = 0.0correct = 0total = 0for inputs, labels in trainloader:inputs, labels = inputs.to(device), labels.to(device)optimizer.zero_grad()outputs = net(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item()# 计算训练准确率_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()scheduler.step()train_loss = running_loss / len(trainloader)train_acc = 100 * correct / totaltrain_losses.append(train_loss)train_accuracies.append(train_acc)# 验证集评估net.eval()val_loss, val_acc = evaluate_model(net, testloader, criterion)val_losses.append(val_loss)val_accuracies.append(val_acc)net.train()print(f'Epoch {epoch + 1}/{epochs}, 'f'Train Loss: {train_loss:.4f}, Train Acc: {train_acc:.2f}%, 'f'Val Loss: {val_loss:.4f}, Val Acc: {val_acc:.2f}%')# 早停机制if val_acc > best_val_acc:best_val_acc = val_acctrigger_times = 0# 保存最佳模型torch.save(net.state_dict(), 'best_model.pth')else:trigger_times += 1if trigger_times >= patience:print('早停触发,停止训练')break# 加载最佳模型net.load_state_dict(torch.load('best_model.pth'))return train_losses, train_accuracies, val_losses, val_accuracies# 评估模型
def evaluate_model(net, dataloader, criterion):net.eval()running_loss = 0.0correct = 0total = 0with torch.no_grad():for inputs, labels in dataloader:inputs, labels = inputs.to(device), labels.to(device)outputs = net(inputs)loss = criterion(outputs, labels)running_loss += loss.item()_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()val_loss = running_loss / len(dataloader)val_acc = 100 * correct / totalreturn val_loss, val_acc# 开始训练
train_losses, train_accuracies, val_losses, val_accuracies = train_model(net, trainloader, criterion, optimizer, scheduler, epochs=50
)# 绘制训练和验证的准确率和损失
plt.figure(figsize=(12, 4))# 准确率曲线
plt.subplot(1, 2, 1)
plt.plot(train_accuracies, label='训练准确率')
plt.plot(val_accuracies, label='验证准确率')
plt.xlabel('Epoch')
plt.ylabel('准确率 (%)')
plt.legend(loc='lower right')
plt.title('训练与验证准确率')# 损失曲线
plt.subplot(1, 2, 2)
plt.plot(train_losses, label='训练损失')
plt.plot(val_losses, label='验证损失')
plt.xlabel('Epoch')
plt.ylabel('损失')
plt.legend(loc='upper right')
plt.title('训练与验证损失')plt.show()
代码解释:
-
设备设置:
- 检测是否有可用的GPU设备,若有则使用GPU加速训练。
-
数据加载与预处理:
- 使用
torchvision.transforms
定义数据增强和预处理变换。 - 加载CIFAR-10训练集和测试集,并应用相应的变换。
- 使用
-
模型构建:
- 定义一个卷积神经网络,包括多个卷积层、批归一化层、池化层和Dropout层。
- 最后通过全连接层输出10个类别的概率。
-
训练过程:
- 定义损失函数为交叉熵损失,优化器为带有L2正则化的随机梯度下降(SGD)。
- 使用学习率调度器逐步降低学习率。
- 实现早停机制,当验证准确率在连续若干个epoch内不再提升时,提前停止训练。
- 在每个epoch结束后,评估模型在验证集上的性能,并保存最佳模型。
-
模型评估与可视化:
- 绘制训练和验证过程中的准确率和损失曲线,帮助分析模型训练情况。
通过上述代码,可以使用PyTorch构建并训练一个性能优良的CIFAR-10图像分类模型。
12. 总结与展望
12.1 总结
本文全面介绍了如何使用Python中的两大主流深度学习框架——TensorFlow和PyTorch,构建、训练和评估图像分类模型。通过详细的代码示例和中文注释,展示了从数据预处理、模型构建、训练优化到模型部署的完整流程。具体内容包括:
相关文章:
【人工智能】 用Python构建图像分类模型:从TensorFlow到PyTorch的全面指南
随着深度学习在计算机视觉领域的迅猛发展,图像分类作为其核心任务之一,受到了广泛的关注。本文旨在详细介绍如何使用Python构建图像分类模型,从TensorFlow到PyTorch两个主流深度学习框架进行全面对比与实践。文章首先回顾了图像分类的基本概念…...
计算机网络 笔记 数据链路层 2
1,信道划分: (1)时分复用TDM 将时间等分为“TDM帧”,每个TDM帧内部等分为m个时隙,m个用户对应m个时隙 缺点:每个节点只分到了总带宽的1/m,如果有部分的1节点不发出数据,那么就会在这个时间信道被闲置,利用…...
2024年度漏洞态势分析报告,需要访问自取即可!(PDF版本)
2024年度漏洞态势分析报告,需要访问自取即可!(PDF版本),大家有什么好的也可以发一下看看...
Apache Hop从入门到精通 第一课 揭开Apache Hop神秘面纱
一、Apache Hop是什么? 1、Apache Hop,简称Hop,全称为Hop Orchestration Platform,即Hop 工作编排平台,是一个数据编排和数据工程平台,旨在促进数据和元数据编排的所有方面。Hop让你专注于你想要解决的问题…...
Unity 人体切片三维可视化,可任意裁切切割。查看不同断层的图像。
Unity 人体切片三维可视化,真彩色,可任意裁切切割。查看不同断层的图像。 点击查看效果: 视频效果...
ModuleNotFoundError: No module named ‘podm.metrics‘报错等解决方法
ModuleNotFoundError: No module named podm.metrics’报错等解决方法 podm.metrics 在运行时报错: ModuleNotFoundError: No module named ‘podm.metrics’ 安装了podm后还是报错 解决方法: 查看安装位置 查看podm的安装位置,并打开到该…...
Java虚拟机运行时数据区域(内存模型)
程序计数器(线程私有内存) What:程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。 程序控制流的指示器, 分支,循环,跳转,异常处理,线程…...
trf 4.10安装与使用-生信工具42
01 背景 DNA 中的串联重复(Tandem Repeat)指的是两个或多个相邻且近似的核苷酸模式的拷贝。Tandem Repeats Finder (TRF) 是一个程序,用于定位并显示 DNA 序列中的串联重复。用户只需提交一个以 FASTA 格式编写的序列,无需指定重…...
rom定制系列------小米max3安卓12 miui14批量线刷 默认开启usb功能选项 插电自启等
小米Max3是小米公司于2018年7月19日发布的机型。此机型后在没有max新型号。采用全金属一体机身设计,配备6.9英寸全面屏.八核处理器骁龙636,后置双摄像头1200万500万像素,前置800万像素.机型代码 :nitrogen.官方最终版为稳定版12.5…...
PySide6-UI界面设计
导论: PySide6和PyQt都是Python对Qt框架的绑定,允许开发者使用Qt创建平台的GUI应用程序。如果你正在开发商业项目,或者需要使用最新的QT6特性,PySide6是一个更好的选择。如果你更倾向于一个成熟的社区和丰富的资源,Py…...
Java创建线程的方式有哪些?
创建线程的方式 1. 继承 Thread 类 在 Java 中,当你启动一个线程时,实际上是调用了 Thread 类的 start() 方法。这个方法会执行以下几个步骤: 线程的状态转变:调用 start() 方法后,线程的状态从 NEW 转变为 RUNNABL…...
Ubuntu | PostgreSQL | 解决 ERROR: `xmllint` is missing on your system.
解决 sudo apt install apt-file sudo apt-file updatesudo apt-file search xmllint sudo apt install libxml2-utils执行 # postgres源码安装包解压文件夹中 make install make install问题 make -C src install make[2]: Entering directory /home/postgres/postgresql-1…...
Jenkins pipeline 发送邮件及包含附件
Jenkins pipeline 发送邮件及包含附件 设置邮箱开启SMTP服务 此处适用163 邮箱 开启POP3/SMTP服务通过短信获取TOKEN (保存TOKEN, 后面Jenkins会用到) Jenkins 邮箱设置 安装 Build Timestamp插件 设置全局凭证 Dashboard -> Manage Jenkins …...
基于深度学习的视觉检测小项目(十) 通过样式表改变界面的外观
一、创建色卡模板文件 在PS中打开之前创建的色卡文件,用吸管拾色器吸取各个色卡的色彩值: 并保存为JSON文件,color_card.json,文件保存在项目的/settings目录下: {"colors": {"RED": "#dc1…...
【Java基础】Stream流、文件File相关操作,IO的含义与运用
1. Java 流(Stream)、文件(File)和IO Java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。Java.io 包中的流支持很多种格式,比如:基本类型、对象、本地化字符集等等。 一个流可以理解为一个数据的序列。 输入流表…...
Java-日志-Slf4j-Log4j-logback
文章目录 SLF4J基础概念使用输出形式日志绑定桥接旧的框架实战 logback基础概念配置文件 Log4j概述 SLF4J 参考: https://www.cnblogs.com/shenStudy/p/15806951.html https://slf4j.org/ 基础概念 是什么?SLF4J(Simple Logging Facade fo…...
探索式测试
探索式测试是一种软件测试风格,它强调独立测试人员的个人自由和职责,为了持续优化其工作的价值,将测试学习、测试设计、测试执行和测试结果分析作为相互支持的活动,在整个项目实现过程中并行地执行。 选择合适的探索式测试方法我…...
LeetCode LCP17速算机器人
速算机器人:探索字符指令下的数字变换 在编程的奇妙世界里,我们常常会遇到各种有趣的算法问题,这些问题不仅考验我们的逻辑思维,还能让我们感受到编程解决实际问题的魅力。今天,就让我们一同探讨一个关于速算机器人的…...
Taro+Vue实现图片裁剪组件
cropper-image-taro-vue3 组件库 介绍 cropper-image-taro-vue3 是一个基于 Vue 3 和 Taro 开发的裁剪工具组件,支持图片裁剪、裁剪框拖动、缩放和输出裁剪后的图片。该组件适用于 Vue 3 和 Taro 环境,可以在网页、小程序等平台中使用。 源码 https:…...
ISP各模块功能介绍
--------声明,本文为转载整理------- ISP各个模块功能介绍: 各模块前后效果对比: 黑电平补偿(BLC) 在理想情况下,没有光照射的像素点其响应值应为0。但是,由于杂质、受热等其它原因的影响&…...
SQL-leetcode-584. 寻找用户推荐人
584. 寻找用户推荐人 表: Customer -------------------- | Column Name | Type | -------------------- | id | int | | name | varchar | | referee_id | int | -------------------- 在 SQL 中,id 是该表的主键列。 该表的每一行表示一个客户的 id、姓名以及推…...
新冠肺炎服务预约微信小程序的设计与实现ssm+论文源码调试讲解
第4章 系统设计 4.1 系统设计的原则 在系统设计过程中,也需要遵循相应的设计原则,这些设计原则可以帮助设计者在短时间内设计出符合设计规范的设计方案。设计原则主要有可靠性,安全性,可定制化,可扩展性,可…...
多模态人工智能在零售业的未来:通过GPT-4 Vision和MongoDB实现智能产品发现
多模态人工智能在零售业的未来:通过GPT-4 Vision和MongoDB实现智能产品发现 引言 想象一下,顾客在购物时只需上传一张他们所期望的服装或产品的照片,几分钟内便能收到来自他们最喜欢的商店的个性化推荐。这就是多模态人工智能在零售领域所带…...
3D目标检测数据集——kitti数据集
KITTI官网网址:The KITTI Vision Benchmark Suite 下载数据集:The KITTI Vision Benchmark Suite KITTI数据集论文:CMSY9 github可视化代码:GitHub - kuixu/kitti_object_vis: KITTI Object Visualization (Birdview, Volumetric LiDar point cloud )...
从CentOS到龙蜥:企业级Linux迁移实践记录(系统安装)
引言: 随着CentOS项目宣布停止维护CentOS 8并转向CentOS Stream,许多企业和组织面临着寻找可靠替代方案的挑战。在这个背景下,龙蜥操作系统(OpenAnolis)作为一个稳定、高性能且完全兼容的企业级Linux发行版࿰…...
Cocos二维Slider
1、可拖动区域计算 根据UI的世界坐标了宽高信息计算出handle的坐标范围 this.posMin new Vec2(this.node.worldPosition.x - this.uiSelf.contentSize.width * 0.5, this.node.worldPosition.y - this.uiSelf.contentSize.height * 0.5); this.posMax new Vec2(this.node.w…...
kubeneters-循序渐进Cilium网络(二)
文章目录 概要IP 地址配置接口配置解析结论 概要 接续前一章节,我们还是以这张图继续深入Cilium网络世界 IP 地址配置 通过检查 Kubernetes 集群的当前环境,可以获取实际的 IP 地址和配置信息。这些信息将被补充到之前的网络示意图中,以使…...
【再谈设计模式】模板方法模式 - 算法骨架的构建者
一、引言 在软件工程、软件开发过程中,我们经常会遇到一些算法或者业务逻辑具有固定的流程步骤,但其中个别步骤的实现可能会因具体情况而有所不同的情况。模板方法设计模式(Template Method Design Pattern)就为解决这类问题提供了…...
[开源]自动化定位建图系统(视频)
系统状态机: 效果展示: 1、 机器人建图定位系统-基础重定位,定位功能演示 2、 机器人建图定位系统-增量地图构建,手动回环检测演示 3、… 开源链接: https://gitee.com/li-wenhao-lwh/lifelong-backend Qt人机交互…...
Kali系统(Debian 10.3) 遇到的问题
目录 问题一:非问题 kali 基础官网与安装 问题二: 问题三: Kali系统 MySQL问题Cant connect to local MySQL server through socket /run/mysqld/mysqld.sock (2) 问题四:重新安装MySQL 也就是MariaDB(MariaDB 含 MySQL相关…...
P2249 【深基13.例1】查找
题目描述 输入 n 个不超过 109 的单调不减的(就是后面的数字不小于前面的数字)非负整数 a1,a2,…,an,然后进行 m 次询问。对于每次询问,给出一个整数 q,要求输出这个数字在序列中第一次出现的编号,如…...
【时时三省】(C语言基础)常见的动态内存错误3
山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 对同一块动态内存多次释放 示例: 解决方法就是释放完把p等于空指针就好了 动态开辟的空间忘记释放 示例: 只有p能找到这块空间 只有p知道这块动态开辟的空间起始地…...
Three.js 性能优化:打造流畅高效的3D应用
文章目录 前言一、减少几何体复杂度(Reduce Geometry Complexity)二、合并几何体(Merge Geometries)三、使用缓冲区几何体(Use BufferGeometries)四、纹理压缩与管理(Texture Compression and M…...
CancerGPT :基于大语言模型的罕见癌症药物对协同作用少样本预测研究
今天我们一起来剖析一篇发表于《npj Digital Medicine》的论文——《CancerGPT for few shot drug pair synergy prediction using large pretrained language models》。该研究聚焦于一个极具挑战性的前沿领域:如何利用大语言模型(LLMs)在数…...
Clisoft SOS与CAD系统集成
Clisoft SOS与CAD系统集成 以下内容大部分来自官方文档,目前只用到与Cadence Virtuoso集成,其他还未用到,如有问题或相关建议,可以留言。 与Keysight ADS集成 更新SOS客户端配置文件sos.cfg,以包含支持ADS的模板&am…...
基于 GEE 下载逐年 MODIS 地表温度 LST 数据
目录 1 地表温度(LST) 2 数据准备 3 代码实现 3.1 加载研究区与数据集 3.2 数据预处理与标准化 3.3 逐年批量导出 3.4 可视化结果 4 运行结果 5 完整代码 1 地表温度(LST) 在遥感领域,地表温度(L…...
ISP图像调优流程
第一步:亮度调试 AE:ae目标值,ae权重表,ae曝光策略,ae收敛速度 .ae容忍值 ae权重表:中央区域权重,均值权重等。感兴趣的区域往AE目标亮度靠近 ae目标亮度: AE 目标亮度是随着增益升高而降低的。 AE 目标亮度的调整主要是看图像的过曝区大小是否达到要求(如对比机)…...
SpringBoot多数据源架构实现
文章目录 1. 环境准备2. 创建Spring Boot项目3. 添加依赖4. 配置多数据源5. 配置MyBatis-Plus6. 使用多数据源7. 创建Mapper接口8. 实体类定义9. 测试多数据源10. 注意事项10.1 事务导致多数据源失效问题解决方案: 10.2 ClickHouse的事务支持10.3 数据源切换的性能开…...
VAxios
VAxios(或v-axios)是一个基于Axios的Vue插件,旨在让开发者在Vue项目中更方便、快捷地引入和使用Axios。以下是对VAxios的详细介绍: 一、功能与特性 VAxios作为Axios的Vue封装插件,继承了Axios的众多特性,…...
macOS安装nvm
新建一个文件夹,使用git将nvm给clone下来 git clone https://github.com/nvm-sh/nvm.git 使用vim编辑~/.bash_profile文件(没有就新建)添加以下代码 export NVM_DIR"$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] &&…...
每日算法Day14【删除二叉搜索树中的节点、修剪二叉搜索树、将有序数组转换为二叉搜索树、把二叉搜索树转换为累加树】
450.删除二叉搜索树中的节点 算法链接: 450. 删除二叉搜索树中的节点 - 力扣(LeetCode) 类型: 二叉树 难度: 中等 思路:两层判断,第一层判断节点与key大小,如果节点删除则判断其左右子节点情况;如果只有一…...
【数据分析(一)】初探 Numpy
目录 前言1. 一维 array 的生成2. 一维 array 的基本操作2.1. 查看属性2.2. 花式索引2.3. 条件筛查2.4. 数据统计 3. n 维 array 的生成4. n 维 array 的基本操作4.1. 查看属性4.2. 查询和切片4.3. 花式索引4.4. 矩阵 前言 Numpy是Python的常用开源数值计算扩展库,用…...
蓝桥杯嵌入式速通(1)
1.工程准备 创建一文件夹存放自己的代码,并在mdk中include上文件夹地址 把所有自身代码的头文件都放在headfile头文件中,之后只需要在新的文件中引用headfile即可 headfile中先提前可加入 #include "stdio.h" #include "string.h"…...
深度解析如何使用Linux中的git操作
1.如何理解版本控制 →Git&&gitee||github 多版本控制面对善变的甲方 版本控制是一种用于管理文件或代码变更的系统,帮助团队或个人追踪项目的历史记录,并支持多方协作开发。它在软件开发和文档管理中尤为重要,但也适用于其他需要追…...
青龙面板脚本开发指南:高效自动化任务的实现
青龙面板脚本开发指南:高效自动化任务的实现 青龙面板(Qinglong Panel)是一款强大的任务管理平台,支持多种语言的脚本开发和执行。通过在青龙面板中编写和管理脚本,用户可以轻松实现自动化任务,提高工作效…...
视频编辑最新SOTA!港中文Adobe等发布统一视频生成传播框架——GenProp
文章链接:https://arxiv.org/pdf/2412.19761 项目链接:https://genprop.github.io 亮点直击 定义了一个新的生成视频传播问题,目标是利用 I2V 模型的生成能力,将视频第一帧的各种变化传播到整个视频中。 精心设计了模型 GenProp&…...
ue5动画重定向,一键重定向。ue4小白人替换成ue5
这就是我们下载的 初学者动画内容包 点击设置选中列 绿色的是动画 黄色的关卡 蓝色是蓝图 ctrla 全选 ctrl鼠标左键 选中所有动画 重定向动画资产 不要选错,只要绿色 选择目标网格体 选择所有的绿色 动画 导出动画 添加前缀ycn 导出 一定要提前新建好存放的…...
C++ 枚举类型
【语法解析】 ● C 枚举类型 在C中,枚举(enumeration)类型是一种简单的数据类型,用于定义在程序中使用的常量。(1)枚举类型的定义格式:enum <类型名> {<枚举常量表>};(2…...
通过Apache、Nginx限制直接访问public下的静态文件
一、Apache 在public目录下的.htaccess文件中添加如下规则,来拒绝除了指定文件类型之外的所有请求 <FilesMatch "\.(?!(jpg|jpeg|png|gif|css|js|ico)$)[^.]$">Order Allow,DenyDeny from all </FilesMatch> 上述配置表示仅允许访问.jpg …...
Spring Boot3 配合ProxySQL实现对 MySQL 主从同步的读写分离和负载均衡
将 ProxySQL 配合 Spring Boot 使用,主要的目的是在 Spring Boot 应用程序中实现对 MySQL 主从同步的读写分离和负载均衡。这样,你可以利用 ProxySQL 自动将写操作路由到主库,而将读操作路由到从库。 1. 准备工作 确保你的 MySQL 主从同步环…...