进击J6:ResNeXt-50实战
- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊
一、实验目的:
- 阅读ResNeXt论文,了解作者的构建思路
- 对比之前介绍的ResNet50V2、DenseNet算法
- 使用ResNeXt-50算法完成猴痘病识别
二、实验环境:
- 语言环境:python 3.8
- 编译器:Jupyter notebook
- 深度学习环境:Pytorch
- torch==2.4.0+cu124
- torchvision==0.19.0+cu124
三、模型介绍
ResNeXt是由何凯明团队在2017年CVPR会议上提出来的新型图像分类网络。ResNeXt是ResNet的升级版,在ResNet的基础上,引入了cardinality的概念,类似于ResNet,ResNeXt也有ResNeXt-50,ResNeXt-101的版本。
ResNeXt论文原文:Aggregated Residual Transformations for Deep Neural Networks。
这篇文章介绍了一种用于图像分类的简单而有效的网络架构,该网络采用了VGG/ResNets的策略,通过重复层来增加深度和宽度,并利用分裂-变换-合并策略以易于扩展的方式进行转换。文章还提出了一个新的维度——“基数”,它是指转换集合的大小,可以在保持复杂性不变的情况下提高分类准确性。作者在ImageNet-1K数据集上进行了实证研究,证明了这种方法的有效性。
下图是ResNet(左)与ResNeXt(右)block的差异。在ResNet中,输入的具有256个通道的特征经过1×1卷积压缩4倍到64个通道,之后3×3的卷积核用于处理特征,经1×1卷积扩大通道数与原特征残差连接后输出。
ResNeXt也是相同的处理策略,但在ResNeXt中,输入的具有256个通道的特征被分为32个组,每组被压缩64倍到4个通道后进行处理。32个组相加后与原特征残差连接后输出。这里cardinatity指的是一个block中所具有的相同分支的数目。
分组卷积
ResNeXt中采用的分组卷机简单来说就是将特征图分为不同的组,再对每组特征图分别进行卷积,这个操作可以有效的降低计算量。
在分组卷积中,每个卷积核只处理部分通道,比如下图中,红色卷积核只处理红色的通道,绿色卷积核只处理绿色通道,黄色卷积核只处理黄色通道。此时每个卷积核有2个通道,每个卷积核生成一张特征图。


总结:ResNeXt-50网络简单讲就是在ResNet结构的基础上采用了聚合残差结构和局部连接结构,同时引入了Random Erasing和Mixup等数据增强和正则化方法。
- Random Erasing是一种数据增强技术,随机删除图像中的一些像素,并用随机值填充,从而增强模型的泛化性能。该技术可以防止模型过分关注图像中的一些细节和特定的区域,从而更好地适应新的数据。此外,Random Erasing还可以增加数据集的多样性,从而降低过拟合的风险。
- Mixup则是一种数据增强和正则化技术,将两张图像的像素按比例混合,生成一张新的图像作为输入,从而提高模型的鲁棒性和泛化性能。Mixup的基本思想是在训练过程中使用凸组合的方法,将输入的不同样本进行线性组合,从而生成一些新的数据样本。这种方法可以有效地增加数据集的多样性,从而提高模型的泛化性能。此外,Mixup还可以作为一种正则化技术,可以降低模型的过拟合风险。
四、使用Pytorch实现ResNeXt-50
设置GPU、导入数据、划分数据集等步骤同前。
1. 构建模型
class Bottleneck(nn.Module):expansion = 4def __init__(self, in_channel, out_channel, stride=1, downsample=None,groups=1, width_per_group=64):super(Bottleneck, self).__init__()width = int(out_channel * (width_per_group / 64.)) * groupsself.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=width,kernel_size=1, stride=1, bias=False) # squeeze channelsself.bn1 = nn.BatchNorm2d(width)# -----------------------------------------self.conv2 = nn.Conv2d(in_channels=width, out_channels=width, groups=groups,kernel_size=3, stride=stride, bias=False, padding=1)self.bn2 = nn.BatchNorm2d(width)# -----------------------------------------self.conv3 = nn.Conv2d(in_channels=width, out_channels=out_channel*self.expansion,kernel_size=1, stride=1, bias=False) # unsqueeze channelsself.bn3 = nn.BatchNorm2d(out_channel*self.expansion)self.relu = nn.ReLU(inplace=True)self.downsample = downsampledef forward(self, x):identity = xif self.downsample is not None:identity = self.downsample(x)out = self.conv1(x)out = self.bn1(out)out = self.relu(out)out = self.conv2(out)out = self.bn2(out)out = self.relu(out)out = self.conv3(out)out = self.bn3(out)out += identityout = self.relu(out)return out
class ResNet(nn.Module):def __init__(self,block,blocks_num,num_classes=1000,include_top=True,groups=1,width_per_group=64):super(ResNet, self).__init__()self.include_top = include_topself.in_channel = 64self.groups = groupsself.width_per_group = width_per_groupself.conv1 = nn.Conv2d(3, self.in_channel, kernel_size=7, stride=2,padding=3, bias=False)self.bn1 = nn.BatchNorm2d(self.in_channel)self.relu = nn.ReLU(inplace=True)self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)self.layer1 = self._make_layer(block, 64, blocks_num[0])self.layer2 = self._make_layer(block, 128, blocks_num[1], stride=2)self.layer3 = self._make_layer(block, 256, blocks_num[2], stride=2)self.layer4 = self._make_layer(block, 512, blocks_num[3], stride=2)if self.include_top:self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) # output size = (1, 1)self.fc = nn.Linear(512 * block.expansion, num_classes)for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')def _make_layer(self, block, channel, block_num, stride=1):downsample = Noneif stride != 1 or self.in_channel != channel * block.expansion:downsample = nn.Sequential(nn.Conv2d(self.in_channel, channel * block.expansion, kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(channel * block.expansion))layers = []layers.append(block(self.in_channel,channel,downsample=downsample,stride=stride,groups=self.groups,width_per_group=self.width_per_group))self.in_channel = channel * block.expansionfor _ in range(1, block_num):layers.append(block(self.in_channel,channel,groups=self.groups,width_per_group=self.width_per_group))return nn.Sequential(*layers)def forward(self, x):x = self.conv1(x)x = self.bn1(x)x = self.relu(x)x = self.maxpool(x)x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)if self.include_top:x = self.avgpool(x)x = torch.flatten(x, 1)x = self.fc(x)return x
def resnext50_32x4d(num_classes=1000, include_top=True):# 预训练权重:https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pthgroups = 32width_per_group = 4return ResNet(Bottleneck, [3, 4, 6, 3],num_classes=num_classes,include_top=include_top,groups=groups,width_per_group=width_per_group)model = resnext50_32x4d(num_classes=4, include_top=True)
model.to(device)# 统计模型参数量以及其他指标
import torchsummary as summary
summary.summary(model,(3,224,224))
代码输出部分截图:

2. 编写训练与测试函数
# 编写训练函数
def train(dataloader, model, loss_fn, optimizer):size = len(dataloader.dataset)num_batches = len(dataloader)train_acc, train_loss = 0, 0for X, y in dataloader:X, y = X.to(device), y.to(device)pred = model(X)loss = loss_fn(pred, y)optimizer.zero_grad()loss.backward()optimizer.step()train_loss += loss.item()train_acc += (pred.argmax(1) == y).type(torch.float).sum().item()train_loss /= num_batchestrain_acc /= sizereturn train_acc, train_loss
# 编写测试函数
def test(dataloader, model, loss_fn):size = len(dataloader.dataset) # 测试集的大小num_batches = len(dataloader) # 批次数目, (size/batch_size,向上取整)test_loss, test_acc = 0, 0# 当不进行训练时,停止梯度更新,节省计算内存消耗with torch.no_grad():for imgs, target in dataloader:imgs, target = imgs.to(device), target.to(device)# 计算losstarget_pred = model(imgs)loss = loss_fn(target_pred, target)test_loss += loss.item()test_acc += (target_pred.argmax(1) == target).type(torch.float).sum().item()test_acc /= sizetest_loss /= num_batchesreturn test_acc, test_loss
3. 设置损失函数和学习率
import copyloss_fn = nn.CrossEntropyLoss()
learn_rate = 1e-4
opt = torch.optim.Adam(model.parameters(), lr=learn_rate)scheduler = torch.optim.lr_scheduler.StepLR(opt, step_size=1, gamma=0.9) # 定义学习率高度器epochs = 100 # 设置训练模型的最大轮数为100,但可能到不了100
patience = 10 # 早停的耐心值,即如果模型连续10个周期没有准确率提升,则跳出训练train_loss = []
train_acc = []
test_loss = []
test_acc = []
best_acc = 0 # 设置一个最佳的准确率,作为最佳模型的判别指标
no_improve_epoch = 0 # 用于跟踪准确率是否提升的计数器
epoch = 0 # 用于统计最终的训练模型的轮数,这里设置初始值为0;为绘图作准备,这里的绘图范围不是epochs = 100
4. 正式训练
# 开始训练
for epoch in range(epochs):model.train()epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, opt)model.eval()epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn)if epoch_test_acc > best_acc:best_acc = epoch_test_accbest_model = copy.deepcopy(model)no_improve_epoch = 0 # 重置计数器# 保存最佳模型的检查点PATH = 'J6_best_model.pth'torch.save({'epoch': epoch,'model_state_dict': best_model.state_dict(),'optimizer_state_dict': opt.state_dict(),'loss': epoch_test_loss,}, PATH)else:no_improve_epoch += 1if no_improve_epoch >= patience:print(f"Early stop triggered at epoch {epoch + 1}")break # 早停train_acc.append(epoch_train_acc)train_loss.append(epoch_train_loss)test_acc.append(epoch_test_acc)test_loss.append(epoch_test_loss)scheduler.step() # 更新学习率lr = opt.state_dict()['param_groups'][0]['lr']template = ('Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f}, Test_acc:{:.1f}%, Test_loss:{:.3f}, Lr:{:.2E}')print(template.format(epoch + 1, epoch_train_acc * 100, epoch_train_loss, epoch_test_acc * 100, epoch_test_loss, lr))
代码输出部分截图:

5. 结果可视化
# 结果可视化
# Loss与Accuracy图import matplotlib.pyplot as plt
# 隐藏警告
import warnings
warnings.filterwarnings("ignore") # 忽略警告信息
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
plt.rcParams['figure.dpi'] = 100 # 分辨率epochs_range = range(epoch)plt.figure(figsize=(12, 3))
plt.subplot(1, 2, 1)plt.plot(epochs_range, train_acc, label='Training Accuracy')
plt.plot(epochs_range, test_acc, label='Test Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')plt.subplot(1, 2, 2)
plt.plot(epochs_range, train_loss, label='Training Loss')
plt.plot(epochs_range, test_loss, label='Test Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

6. 预测
from PIL import Imageclasses = list(total_data.class_to_idx)def predict_one_image(image_path, model, transform, classes):test_img = Image.open(image_path).convert('RGB')plt.imshow(test_img) # 展示预测的图片test_img = transform(test_img)img = test_img.to(device).unsqueeze(0)model.eval()output = model(img)_, pred = torch.max(output, 1)pred_class = classes[pred]print(f'预测结果是:{pred_class}')import os
from pathlib import Path
import random#从所有的图片的随机选择一张图片image=[]
def image_path(data_dir):file_list=os.listdir(data_dir) #列出四个分类标签data_file_dir=file_list #从四个分类标签中随机选择一个data_dir=Path(data_dir)for i in data_file_dir:i=Path(i)image_file_path=data_dir.joinpath(i) #拼接路径data_file_paths=image_file_path.iterdir() #罗列文件夹的内容data_file_paths=list(data_file_paths) #要转换为列表image.append(data_file_paths)file=random.choice(image) #从所有的图像中随机选择一类file=random.choice(file) #从选择的类中随机选择一张图片return filedata_dir='./monkeypox_photos'
image_path=image_path(data_dir)# 预测训练集中的某张照片
predict_one_image(image_path=image_path,model=model,transform=train_transforms,classes=classes)

# 模型评估
# 将参数加载到model当中
best_model.load_state_dict(torch.load(PATH,map_location=device))
epoch_test_acc,epoch_test_loss=test(test_dl,best_model,loss_fn)
epoch_test_acc,epoch_test_loss
(0.8508158508158508, 0.39013327977487017)
总结
ResNeXt是在ResNet的网络架构上,使用类似于Inception的分治思想,即split-tranform-merge策略,将模块中的网络拆开分组,与Inception不同,每组的卷积核大小一致,这样其感受野一致,但由于每组的卷积核参数不同,提取的特征自然不同。然后将每组得到的特征进行concat操作后,再与原输入特征x或者经过卷积等处理(即进行非线性变换)的特征进行Add操作。这样做的好处是,在不增加参数复杂度的前提下提高准确率,同时还能提高超参数的数量。
另外,cardinality是基的意思,将数个通道特征进行分组,不同的特征组之间可以看作是由不同基组成的子空间,每个组的核虽然一样,但参数不同,在各自的子空间中学到的特征就多种多样,这点跟transformer中的Multi-head attention不谋而合(Multi-head attention allows the model to jointly attend to information from different representation subspaces.)而且分组进行特征提取,使得学到的特征冗余度降低,获取能起到正则化的作用。

ResNeXt-50与ResNet50V2、DenseNet的对比:
- 网络结构:
- ResNeXt-50:基于ResNet结构改进而来,采用聚合残差结构和局部连接结构。它通过重复构建块来构建,每个构建块聚合了一组具有相同拓扑结构的转换。引入了分组卷积的方法,可以将不同的通道分组处理,还使用了深度可分离卷积的方法进一步减少计算量。
- ResNet50V2:是ResNet系列中的经典模型,由50层卷积层、批量归一化、激活函数和池化层构成。引入了一种全新的残差块结构,即bottleneck结构,使得网络参数量大幅度降低,同时精度也有所提升。
- DenseNet:其特点是不同于传统的网络结构,每一层的输出不仅和前一层的输出有关,还和之前所有层的输出有关,这种密集连接的结构可以有效地缓解梯度消失和参数稀疏问题,提高了模型的泛化能力和精度。它由多个denseblock和transition层组成,denseblock内部采用密集连接,相邻denseblock之间通过transition层连接并降低特征图大小。
- 精度和计算量:
- ResNeXt-50:在相同的深度下具有更高的精度,并且在参数量和计算量上都显著降低。在较深的网络结构下,优势更加明显,可以达到更高的精度。
- ResNet50V2:能在保持较低参数量的同时,实现较高的精度。
- DenseNet:在参数和计算成本更少的情形下实现比ResNet更优的性能,通过特征在channel上的连接来实现特征重用,减少了网络的参数总量,但由于密集连接方式,计算量相对较大。
- 适用范围:
- ResNeXt-50:适用于各种图像分类任务,在对精度要求较高且计算资源相对充足的场景下表现良好。
- ResNet50V2:广泛适用于各种图像分类任务,尤其在对模型复杂度和精度有一定平衡要求的场景中应用较多。
- DenseNet:适用于对特征重用和模型紧凑性要求较高的任务,例如图像分类、目标检测等,但在计算资源有限的情况下,可能需要对其进行适当的调整或优化。
它们各自的优点和创新之处如下:
- ResNeXt-50:
- 优点:在不明显增加参数量的情况下提升了准确率,具有很好的可扩展性和可适应性,超参数数量相对较少,便于模型移植。
- 创新:提出aggregated residual transformations结构,利用分组卷积构建平行堆叠相同拓扑结构的blocks,代替原来ResNet的三层卷积的block;同时引入了cardinality的概念,即通过增加分组的数量(基数),可以在不增加模型复杂度的前提下提高性能,实验表明增加基数比增加深度或宽度更有效。
- ResNet50V2:
- 优点:通过改进残差结构,先进行批量归一化和激活函数计算后再卷积,并将addition后的ReLU计算放到残差结构内部,提高了模型的精度,同时降低了参数量。
- 创新:全新的残差块结构(bottleneck结构),减少了网络参数量,使得在保持较高精度的同时,模型更容易训练和优化,这种结构上的创新为后续许多网络的设计提供了借鉴思路。
- DenseNet:
- 优点:缓解了梯度消失问题,加强了特征传播,鼓励了特征复用,极大地减少了网络的参数总量,在参数较少的情况下能取得较好的性能,而且通过密集连接方式,提升了梯度的反向传播,使得网络更容易训练,对过拟合有一定的抑制作用。
- 创新:建立了前面所有层与后面层的密集连接机制,实现了特征重用,每个层都会与前面所有层在channel维度上连接并作为下一层的输入,这一创新的连接方式充分利用了特征信息,与传统的网络结构相比,在相同性能下可以减少参数数量,提高了模型的效率和泛化能力。此外,在denseblock中使用bottleneck层来减少计算量,以及在transition层采用特定的结构来处理特征图的尺寸匹配问题,也是其重要的创新点。
相关文章:
进击J6:ResNeXt-50实战
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 一、实验目的: 阅读ResNeXt论文,了解作者的构建思路对比之前介绍的ResNet50V2、DenseNet算法使用ResNeXt-50算法完成猴痘病识别 二、实…...
新代机床采集数据
新代集團1995年成立於台灣新竹,事業版圖遍布全球,以台灣為中心向外發展,據點橫跨歐洲、美洲、亞洲三大洲。新代長期深耕於機床控制器的軟體及硬體技術研發,專注於運動控制領域,目前已成為亞太市場中深具影響力的控制器領導品牌之一。主營產品包括:機床數控系統、伺服驅動…...
景联文科技:专业数据标注公司,推动AI技术革新
数据标注作为AI技术发展的重要支撑,对于训练高质量的机器学习模型以及推动应用领域的创新具有不可替代的作用。 景联文科技作为专业的数据标注公司,致力于提供专业的数据标注服务,帮助客户解决AI链条中的数据处理难题,共同推动人工…...
k8s以及prometheus
#生成控制器文件并建立控制器 [rootk8s-master ~]# kubectl create deployment bwmis --image timinglee/myapp:v1 --replicas 2 --dry-runclient -o yaml > bwmis.yaml [rootk8s-master ~]# kubectl expose deployment bwmis --port 80 --target-port 80 --dry-runclient…...
android 权限说明
1. 权限的定义语法 注: 任何应用都可以定义权限 <permission 标签是定义权限 <uses-permission 标签是使用权限。 <permission android:description"string resource"android:icon"drawable resource"android:label"string res…...
<winsock>重叠IO模型
基于事件判断io完成 send程序 #include <stdio.h> #include <winsock2.h>#pragma comment(lib, "Ws2_32.lib") #pragma warning(disable : 4996)int main() {WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) ! 0){printf("WSAStart…...
Android Tools | 如何使用Draw.io助力Android开发:从UI设计到流程优化
Android Tools | 如何使用Draw.io助力Android开发:从UI设计到流程优化 1. 引言 在Android开发中,视觉化设计与流程管理至关重要。虽然开发工具如Android Studio强大,但它并不适用于所有设计场景。Draw.io是一款免费的在线绘图工具ÿ…...
Java 每日一刊(第5期):变量守护者
前言 这里是分享 Java 相关内容的专刊,每日一更。 本期将为大家带来以下内容: 量子数据宇宙的变量守护者第一章:能源错配与基本数据类型第二章:引用类型与通讯网络的崩溃第三章:作用域冲突与系统崩溃终章࿱…...
【C++二分查找】2517. 礼盒的最大甜蜜度
本文涉及的基础知识点 C二分查找 贪心(决策包容性) LeetCode 2517. 礼盒的最大甜蜜度 给你一个正整数数组 price ,其中 price[i] 表示第 i 类糖果的价格,另给你一个正整数 k 。 商店组合 k 类 不同 糖果打包成礼盒出售。礼盒的 甜蜜度 是礼…...
【详解】数据库E-R图——医院计算机管理系统
题目 某医院病房计算机管理中需要如下信息: 科室:科室名,科室地址,科室电话,医生姓名 病房:病房号,床位号,所属科室名 医生:工作证号,姓名,性别&a…...
分类预测|基于改进的灰狼IGWO优化支持向量机SVM的数据分类预测matlab程序 改进策略:Cat混沌与高斯变异
分类预测|基于改进的灰狼IGWO优化支持向量机SVM的数据分类预测matlab程序 改进策略:Cat混沌与高斯变异 文章目录 一、基本原理原理流程1. **定义目标函数**2. **初始化GWO**3. **评估适应度**4. **更新狼的位置**5. **更新狼的等级**6. **重复迭代**7. **选择最佳解…...
圆锥曲线练习
设 A ( x 1 , y 1 ) , B ( x 2 , y 2 ) A\left( x_{1}, y_{1} \right), B\left( x_{2}, y_{2} \right) A(x1,y1),B(x2,y2) l : y k ( x 2 ) l: y k\left( x2 \right) l:yk(x2) 显然 y 0 y0 y0符合题意 当 k ≠ 0 k\neq 0 k0 联立 l l l和 C C C ( k 2 1 2 ) x…...
STM32时钟树
1 什么是时钟 2 时钟数简图...
NX—UI界面生成的文件在VS上的设置
UI界面保存生成的三个文件 打开VS创建项目,删除自动生成的cpp文件,将生成的hpp和cpp文件拷贝到项目的目录下,并且在VS项目中添加现有项目。 修改VS的输出路径,项目右键选择属性,链接器中的常规,文件路径D:…...
Wine容器内程序执行sh脚本问题研究
问题背景 wpf程序在wine环境执行sh脚本,不能等待脚本执行完成自动退出的问题进行了研究,需求很简单,在wpf程序使用cmd,或者bat ,又或者是直接执行sh脚本,想到脚本执行完成才处理后面的逻辑。但是实际验证过…...
《深度学习》OpenCV轮廓检测 模版匹配 解析及实现
目录 一、模型匹配 1、什么是模型匹配 2、步骤 1)提取模型的特征 2)在图像中查找特征点 3)进行特征匹配 4)模型匹配 3、参数及用法 1、用法 2、参数 1)image:待搜索对象 2)templ&am…...
Java XML
1、XML文件介绍 配置文件:用来保存设置的一些东西。 拿IDEA来举例,比如设置的背景图片,字体信息,字号信息和主题信息等等。 (1)以前是用txt保存的,没有任何优点,而且不利于阅读&a…...
好用的视频压缩工具有哪些?这4款千万不要错过
视频压缩的方法有很多种,像我们手机里的视频剪辑工具,手机和电脑自带的压缩功能,在线压缩网站,专业压缩软件压缩等等。不同的场景和需求下大家可以选择不同的工具,但是如果碰到需要大量和经常压缩视频的话,…...
【Python爬虫系列】_016.关于登录和验证码
我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈 入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈 虚 拟 环 境 搭 建 :👉&…...
基于opencv实现双目立体匹配点云距离
双目相机或两个单目相机。 一、相机标定 MATLAB软件,打开双目标定app。 点击add images,弹出加载图像的窗口,分别导入左图和右图,设置黑白格长度(标定板的长度一般为20)。 点击确定,弹出加载…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
Linux部署私有文件管理系统MinIO
最近需要用到一个文件管理服务,但是又不想花钱,所以就想着自己搭建一个,刚好我们用的一个开源框架已经集成了MinIO,所以就选了这个 我这边对文件服务性能要求不是太高,单机版就可以 安装非常简单,几个命令就…...
基于鸿蒙(HarmonyOS5)的打车小程序
1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
如何在Windows本机安装Python并确保与Python.NET兼容
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...
