Python使用YOLOv5图像识别教程包成功-以识别桥墩缺陷详细步骤分享

news2024/11/15 2:03:20

前置环境资源下载

提示:要开外网才能下载的环境我都放在了网盘里,教程中用到的环境可从这里一并下载:

https://pan.quark.cn/s/f0c36aa1ef60

1. 下载YOLOv5源码

  • 官方地址:GitHub - ultralytics/yolov5: YOLOv5 🚀 in PyTorch > ONNX > CoreML > TFLite

2. 下载预训练检查点文件

  • 官方地址:GitHub - ultralytics/yolov5: YOLOv5 🚀 in PyTorch > ONNX > CoreML > TFLite
  • 页面向下拉,会看到 "Pretrained Checkpoints" 表格,任选一个进行下载(我这里使用的是 yolov5x.pt)。
  • 下载完成后,将 .pt 文件放入 YOLOv5 源码的根目录。

3. 下载CUDA

  • 要用显卡GPU训练模型,就必须下载CUDA。
  • 官方链接:CUDA Toolkit Archive | NVIDIA Developer
  • 我下载的是 12.2.0 版本,安装时选择默认路径即可。

4. 下载3个Python库:torchtorchvisiontorchaudio

  • 提示torch 是算法核心,torchvision 用于处理图像,torchaudio 处理音频/视频。这一条很关键,仔细看,因为涉及到版本匹配

  • 刚才我们下载的CUDA是12.2版本对吧,我们进入PyTorch官网往下拉可以看到一个注释为CUDA 12.1的,所以我就选择差别不大的12.1版本的命令下载,这官网里都给我们把版本匹配好了,就不要自己一个一个不指定版本去下载,ok获取到命令如下,如果下载失败,看下面第5条:

# CUDA 12.1
pip install torch==2.2.1 torchvision==0.17.1 torchaudio==2.2.1 --index-url https://download.pytorch.org/whl/cu121

 

f2b1bf56225ef42e970d2c1ee762f71d.png

5. 使用国内镜像下载库失败的解决方法

官方的命令下载这三个库很多人因为网络超时导致中途下载失败,当然也有下载顺利的人,而尝试使用国内镜像去下载这三个库时,好像是没有GPU版本的,下载下来的只有CPU版本的,因此提供如下安装这三个库的方式,包成功!!!:

下载地址:浏览器进入 PyTorch 官方站 https://download.pytorch.org/whl/torch_stable.html

使用快捷键ctrl+f搜索并下载

torch:搜索 cu121/torch-2.2.1,选择 cp39-win 的版本。

 

e372dff1de8e9c6d4b5c2ef71c47a66e.png

torchvision:搜索 cu121/torchvision-0.17.1,选择 cp39-win 的版本。

 

16d3617a33c0280b3e5a2f56da263263.png

torchaudio:搜索 cu121/torchaudio-2.2.1,选择 cp39-win 的版本。

 

23c5b97dcd2d7c55e87366823cc3d467.png

安装步骤

下载完后随便放到一个目录(如:D:\C01MyENV),然后打开CMD命令行进入这个目录,执行以下三条命令安装:

pip install "torch-2.2.1+cu121-cp39-cp39-win_amd64.whl"
pip install "torchvision-0.17.1+cu121-cp39-cp39-win_amd64.whl"
pip install "torchaudio-2.2.1+cu121-cp39-cp39-win_amd64.whl"

安装过成如图

 

7b65b0115d0efbedc7d2ea2e27bfca36.png

 

ece426392560c6d4f75665a9f4a957f3.png

 

d5d9be7ebd7f0375b763f96ff8f808e1.png

环境验证

验证CUDA是否可用

在Python中运行以下代码,查看你的CUDA是否可用:

import torch

# 检查是否有可用的 GPU
print("CUDA是否可用=>", torch.cuda.is_available())
print("pytorch版本=>"+torch.__version__)
print("是否支持CUDA=>"+str(torch.cuda.is_available()))
# 如果有 GPU 可用,打印 GPU 数量和名称
if torch.cuda.is_available():
    print("GPU设备数量=>", torch.cuda.device_count())
    print("当前使用GPU=>", torch.cuda.get_device_name(torch.cuda.current_device()))
else:
    print("没有GPU可用,当前将运行在CPU上")

运行后你会看到如下界面,表示GPU版本的Yolov5环境成功了,如图:

 

9b85443b6cc74b99ab6d39e700f96974.png

Yolov5源码用到的库一键下载

CMD命令进入yolov5源码包,执行pip install -r requirements.txt,此命令会下载requirements.txt文件中指定版本的包。只要你配置了国内的镜像,这一步必然是顺利的。

下载标注工具

1. 下载labelImg工具

  • 官方链接:https://github.com/tzutalin/labelImg
  • 下载完成后,解压到本地。

2. 安装 pyQT5 依赖

  • 由于 labelImg 依赖于 pyQT5,需要先安装它。

    安装命令

    pip install pyqt5

3. 安装 libs.resources 模块

  • 打开 CMD,进入到 labelImg 源码目录,执行以下命令安装 libs.resources 模块:

    安装命令

    pyrcc5 -o libs/resources.py resources.qrc

4. 删除预制标签

  • 为了避免初学者在标记时混淆,请删除 labelImg-master\data\predefined_classes.txt 文件中的所有内容,注意是删除内容,不是让你删除文件。

5. 启动 labelImg

  • CMD命令进入 labelImg 源码目录,运行以下命令启动标注工具:

    启动命令

    python labelImg.py
  • 之后,每次启动 labelImg 都可以直接运行此命令。

准备图片

为快速操作,我这里使用如下爬虫,快速爬取图片,然后筛选24张进行标注训练,当然实际过程中为了保证模型的准确,会需要更多的图片,不复杂的场景100张即可,复杂的场景要上千张

'''
key_word:图片名称关键词
img_num:爬取图片轮数,1轮30张
'''
import json
import math
import os.path
import sys
import time

import requests

def catch_img(key_word,rounds): #关键字、爬取轮次,一轮30张
    if not os.path.exists(key_word):
        os.mkdir(key_word)
    for count in range(rounds):
        print(str(count)+"轮")
        pn=count*30
        url = "https://images.baidu.com/search/acjson?tn=resultjson_com&logid=11514788725054802565&ipn=rj&ct=201326592&is=&fp=result&fr=&word="+str(key_word)+"&queryWord="+str(key_word)+"&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&hd=&latest=&copyright=&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=&expermode=&nojc=&isAsync=&pn="+str(pn)+"&rn=30&gsm=1e&1717479169689="
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36'}
        res = requests.get(url, headers=headers)
        if len(res.json()["data"])==1:
            print("无图片可获取了")
            sys.exit()
        json_data=res.json()["data"] #获取json数据
        json_str= json.dumps(json_data, indent=2) #json转json字符串
        list_data=json.loads(json_str) #json字符串转list/dict
        for obj in list_data:
            try:
                pic_url=obj["thumbURL"] #图像链接
            except:
                continue
            r = requests.get(pic_url,headers=headers)
            with open(str(key_word)+"\\"+str(time.time())+".jpg", mode="wb") as f:
                f.write(r.content)

if __name__ == '__main__':
    catch_img("桥梁地基冲刷照片",20)

1. 标注数据集

1.1 创建文件目录

  • yolov5 目录下创建 yoloData 目录,随后在 yoloData 目录下建立以下两个子目录:
    • txtData:用于存放标注的标签文件(.txt 格式)
    • picData:用于存放需要标注的图片文件

1.2 准备图片文件

  • 将需要标注的图片放入 yoloData/picData 目录中。

1.3 启动 labelImg 并设置参数

  1. 启动 labelImg
  2. 点击打开目录,选择 yoloData/picData 目录。
  3. 将左边的存储格式由默认的 PascalVOC 改为 YOLO
  4. 点击文件 -> 改变存放目录,将标签的存放目录设置为 yoloData/txtData
  5. 如图一定要按步骤来,不然可能会闪退

 

fdbc5e45a238e302a34d7eeeeca93d79.png

 

a278c3d4dac77fe6f84427776450203a.png

1.4 开始标注

  1. 例如,如果你要标注图片中的桥墩损坏部位,按下 W 键调出标注十字架,框选出损坏部位并保存,随后输入自定义的缺陷英文名称(如 error_pos),然后继续标注下一张图片。
  2. 可以在同一张图片中标记多个部位。
  3. 标记第一张图片时会提示你先命名标记的类别,类别可以自定义(我这里设置为 error_pos)。

1.5 常用快捷键

  • W:调出标注十字架
  • A:切换到上一张图片
  • D:切换到下一张图片
  • Del:删除标注框
  • Ctrl+U:选择标注的图片文件夹
  • Ctrl+R:选择标注好的标签文件夹

1.6 检查标注结果

  • 标记完后,检查 txtData 目录中的标签文件(.txt)与 picData 目录中的图片文件名称是否对应,数量是否一致。

2. 划分数据集

在我们创建的yoloData目录下建立SplitData.py文件,加入如下代码然后执行会将txt标签和图篇按照8:1:1的比例划分为训练集、测试集、验证集到新的目录

import os
import shutil
import random

# 设置随机种子
random.seed(0)


def split_data(file_path, xml_path, new_file_path, train_rate, val_rate, test_rate):
    '''====1.将数据集打乱===='''
    each_class_image = []
    each_class_label = []
    for image in os.listdir(file_path):
        each_class_image.append(image)
    for label in os.listdir(xml_path):
        each_class_label.append(label)
    # 将两个文件通过zip()函数绑定。
    data = list(zip(each_class_image, each_class_label))
    # 计算总长度
    total = len(each_class_image)
    # random.shuffle()函数打乱顺序
    random.shuffle(data)
    # 再将两个列表解绑
    each_class_image, each_class_label = zip(*data)

    '''====2.分别获取train、val、test这三个文件夹对应的图片和标签===='''
    train_images = each_class_image[0:int(train_rate * total)]
    val_images = each_class_image[int(train_rate * total):int((train_rate + val_rate) * total)]
    test_images = each_class_image[int((train_rate + val_rate) * total):]
    train_labels = each_class_label[0:int(train_rate * total)]
    val_labels = each_class_label[int(train_rate * total):int((train_rate + val_rate) * total)]
    test_labels = each_class_label[int((train_rate + val_rate) * total):]

    '''====3.设置相应的路径保存格式,将图片和标签对应保存下来===='''
    # train
    for image in train_images:
        print(image)
        old_path = file_path + '/' + image
        new_path1 = new_file_path + '/' + 'train' + '/' + 'images'
        if not os.path.exists(new_path1):
            os.makedirs(new_path1)
        new_path = new_path1 + '/' + image
        shutil.copy(old_path, new_path)

    for label in train_labels:
        print(label)
        old_path = xml_path + '/' + label
        new_path1 = new_file_path + '/' + 'train' + '/' + 'labels'
        if not os.path.exists(new_path1):
            os.makedirs(new_path1)
        new_path = new_path1 + '/' + label
        shutil.copy(old_path, new_path)
    # val
    for image in val_images:
        old_path = file_path + '/' + image
        new_path1 = new_file_path + '/' + 'val' + '/' + 'images'
        if not os.path.exists(new_path1):
            os.makedirs(new_path1)
        new_path = new_path1 + '/' + image
        shutil.copy(old_path, new_path)

    for label in val_labels:
        old_path = xml_path + '/' + label
        new_path1 = new_file_path + '/' + 'val' + '/' + 'labels'
        if not os.path.exists(new_path1):
            os.makedirs(new_path1)
        new_path = new_path1 + '/' + label
        shutil.copy(old_path, new_path)
    # test
    for image in test_images:
        old_path = file_path + '/' + image
        new_path1 = new_file_path + '/' + 'test' + '/' + 'images'
        if not os.path.exists(new_path1):
            os.makedirs(new_path1)
        new_path = new_path1 + '/' + image
        shutil.copy(old_path, new_path)

    for label in test_labels:
        old_path = xml_path + '/' + label
        new_path1 = new_file_path + '/' + 'test' + '/' + 'labels'
        if not os.path.exists(new_path1):
            os.makedirs(new_path1)
        new_path = new_path1 + '/' + label
        shutil.copy(old_path, new_path)


if __name__ == '__main__':
    file_path = r"D:\A03PyThonProjects395\yolov5-master\yoloData\picData" #原图片路径
    txt_path = r"D:\A03PyThonProjects395\yolov5-master\yoloData\txtData"  #.txt标签路径
    new_file_path = r"D:\A03PyThonProjects395\yolov5-master\yoloData\splitData" #划分后的目录
    # 设置划分比例
    split_data(file_path, txt_path, new_file_path, train_rate=0.8, val_rate=0.1, test_rate=0.1)

3. 训练模型

1修改VOC.yaml:

将data目录下的VOC.yaml文件修改内容为如下: download及其以下的配置不用改动,download以上的全部改掉为如下

train: D:\A03PyThonProjects395\yolov5-master\yoloData\splitData\train #训练集绝对路径
val: D:\A03PyThonProjects395\yolov5-master\yoloData\splitData\val #验证集绝对路径

# Classes
names: ['error_pos'] #这个error_pos是我们标记数据时设置的勾画物体名称,若忘记了可以在txtData目录下的classes.txt看到

nc: 1 #这里填写1的原因:在我们标记数据集之前,我们清空了labelImg-master\data\predefined_classes.txt,然后标记数据时,添加了类别名为error_pos,yolov5在索引我们的类别时是从0开始的,我们的类别只有一个error_pos,所以这里填1,如果不太明白可以简单理解为多少个类别就填几

# Download script/URL (optional) ---------------------------------------------------------------------------------------
download: |..........download这块及其一下都不用改动......

2.修改模型配置文件:

因为我们这里使用的预训练权重是yolov5x.pt,因此将models目录下的yolov5x.yaml文件改动如下:

nc: 1 # number of classes  ,只需要把这个改为1就行了

3.正式训练模型前的配置

训练模型是用train.py ,在训练之前,先定位到train.py的parse_opt方法,可以看到有很多训练参数,这里解释下可能需要修改的参数:

--weights:加载的权重文件路径,默认是根目录下的yolov5s.pt,我用的是yolov5x.pt,因此要改为yolov5x.pt
--cfg:这个要指定我们的models/yolov5x.yaml文件
--data:是指定数据集配置文件,我们这里填data/VOC.yaml
--epochs:表示训练的轮次,要训练300轮就改成300
--batch-size:表示每一批训练的批次大小,这个大小根据GPU或CPU指定,一般为16,32,64,128,256等
--workers:表示使用的核心数量,默认为8
--device:选项有0、1、2、3、cpu,0、1、2、3表示选择第几个GPU,我这里就一个显卡,填0就行了

以上是可能需要修改的参数,下面列出所有参数解释:
opt参数解析: 
• cfg:   模型配置文件,网络结构
• data:   数据集配置文件,数据集路径,类名等
• hyp:   超参数文件
• epochs:   训练总轮次
• batch-size:   批次大小
• img-size:   输入图片分辨率大小
• rect:   是否采用矩形训练,默认False
• resume:   接着打断训练上次的结果接着训练
• nosave:   不保存模型,默认False
• notest:   不进行test,默认False
• noautoanchor:   不自动调整anchor,默认False
• evolve:   是否进行超参数进化,默认False
• bucket:   谷歌云盘bucket,一般不会用到
• cache-images:   是否提前缓存图片到内存,以加快训练速度,默认False
• weights:   加载的权重文件
• name:   数据集名字,如果设置:results.txt to results_name.txt,默认无
• device:   训练的设备,cpu;0(表示一个gpu设备cuda:0);0,1,2,3(多个gpu设备)
• multi-scale:   是否进行多尺度训练,默认False
• single-cls:    数据集是否只有一个类别,默认False
• adam:   是否使用adam优化器
• sync-bn:   是否使用跨卡同步BN,在DDP模式使用
• local_rank:   gpu编号
• logdir:   存放日志的目录
• workers:   dataloader的最大worker数量

最后我修改过的parse_opt结果如下:

parser.add_argument("--weights", type=str, default=ROOT / "yolov5x.pt", help="initial weights path")
parser.add_argument("--cfg", type=str, default="models/yolov5x.yaml", help="model.yaml path")
parser.add_argument("--data", type=str, default=ROOT / "data/VOC.yaml", help="dataset.yaml path")
parser.add_argument("--hyp", type=str, default=ROOT / "data/hyps/hyp.scratch-low.yaml", help="hyperparameters path")
parser.add_argument("--epochs", type=int, default=100, help="total training epochs")
parser.add_argument("--batch-size", type=int, default=16, help="total batch size for all GPUs, -1 for autobatch")
parser.add_argument("--device", default="0", help="cuda device, i.e. 0 or 0,1,2,3 or cpu")

4.开始训练:

参数配置完后执行train.py开始训练

如图表示在训练了,不愧是GPU,3秒一轮,CPU训练非常慢

 

27cc2066f3281ab1a0caeb5025fdd987.png

5.查询训练结果

训练完后结果会保存在runs的tarin文件里,训练出的最优模型它命名为best.pt,如图

 

0de96ecf426a324d9063ce72897fddf4.png

4.验证模型

验证模型靠的是根目录下的val.py文件,进入val.py文件,定位到parse_opt方法,这里要改动几个参数为我们自己的:

--data:指定验证集的配置文件,即我们data下的VOC.yaml
 --weights:指定模型权重文件,选择我们训练模型后runs下最好的权重文件best.pt,我这里最好的是exp2目录下的best.pt

最后我改动的参数为如下(就改了两个位置):

parser.add_argument("--data", type=str, default=ROOT / "data/VOC.yaml", help="dataset.yaml path")
parser.add_argument("--weights", nargs="+", type=str, default=ROOT / "runs/train/exp2/weights/best.pt", help="model path(s)")

然后运行val.py进行验证,运行后,会在runs目录下生成val的目录,里面就是验证的结果,可能你现在还看不懂,总之可以简单理解为这些图表表示了模型的准确率,当然我这里为了快速教学,用了24张图片肯定是不够的,如图

 

3025beb1b5f94774cca48ba301a59630.png

5. 用模型检测其他图片

当我们用val.py验证后通过图标查看识别率还不错的话,就可以开始用detect.py进行检测看看效果了

先在根目录创建一个otherPics目录,然后随便网上找几张和你模型需要识别相关的图片,比如我是用来识别桥梁地基冲刷缺陷的,我就找这类图,然后放入otherPics目录

来到detect.py文件下,同样是定位到parse_opt方法,要改动几个参数,这里同验证模型改参数一样:

--weights:指定为自己的最好的训练模型,即runs/train下最好的best.pt
--source:指定要测试的图片的目录,我这里是otherPics
--data:指定数据集配置文件,即我们的data/VOC.yaml
--conf-thres:指定置信度,越小则越信任识别的内容,当然也就越不准确,默认0.25,我这里因为用的图片少,所以调的很低

最终我配置为如下

parser.add_argument("--weights", nargs="+", type=str, default=ROOT / "runs/train/exp2/weights/best.pt", help="model path or triton URL")
parser.add_argument("--source", type=str, default=ROOT / "otherPics", help="file/dir/URL/glob/screen/0(webcam)")
parser.add_argument("--data", type=str, default=ROOT / "data/VOC.yaml", help="(optional) dataset.yaml path")
parser.add_argument("--conf-thres", type=float, default=0.07, help="confidence threshold")

然后运行detect.py,执行完成后会在runs下生成detect目录,目录内便是识别后的图片,如图

 

ee50cd700f4e849d3bab86c71b4c58e7.png

至此,幽络源的图像识别教程结束

补充:如有需要,可以自行将detect改为传入照片然后就返回识别后的信息。

大牛交流QQ群:307531422

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2151795.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【源码+文档+调试讲解】微信小程序的投票系统

摘 要 伴随着我国社会的发展,人民生活质量日益提高。于是对各种需求进行规范而严格是十分有必要的,所以许许多多的微信小程序应运而生。此时单靠人力应对这些事务就显得有些力不从心了。所以本论文将设计一套微信小程序的投票系统,进行作品信…

python画图|曲线分段设置颜色基础教程

前期已经学习了大量的python画图教程,但颜色的设计一直是次要角色,今天我们就一起学习一下如何对图形分段设置颜色。 一些前期通过颜色区分图形的文章链接如下: python画图|极坐标下的3D surface_python 根据经纬度 海拔高度 绘制三维立体-…

AIDI工业AI视觉检测软件

AIDI工业AI视觉检测软件 AIDI2.4,工业AI视觉检测软件,全模块永久使用最高权限,支持8卡同时运算,提供远程测试

对接阿里asr和Azure asr

1&#xff1a;对接阿里asr 1.1&#xff1a;pom <dependency><groupId>com.alibaba.nls</groupId><artifactId>nls-sdk-recognizer</artifactId><version>2.2.1</version> </dependency>1.2&#xff1a;生成token package c…

同态加密明文矩阵乘密文向量优化:BSGS小步大步法

摘要 本文介绍如何使用小步大步&#xff08;Baby-Step-Giant-Step&#xff0c;BSGS&#xff09;优化RLWE同态加密的明文矩阵和密文向量的乘法。使用 n n n\times n nn明文矩阵的对角打包和BSGS&#xff0c;可以将密文旋转的次数降低为 O ( n ) O(\sqrt{n}) O(n ​). 明文运算…

3、无线通信系统的组成

通常把实现信息传输的系统称为通信系统&#xff0c;下图表示一个通信系统的基本组成。在通信系统中&#xff0c;一般要进行两种变换与反变换。在发送端&#xff0c;第一个变换是输入变换器&#xff0c;它把要传输的信号变为电信号&#xff0c;该信号一般是低频的&#xff0c;而…

数字英文验证码识别 API 对接说明

数字英文验证码识别 API 对接说明 本文将介绍一种 数字英文验证码识别 API 对接说明&#xff0c;它是基于深度学习技术&#xff0c;可用于识别变长英文数字验证码。输入验证码图像的内容&#xff0c;输出验证码结果。 接下来介绍下 数字英文验证码识别 API 的对接说明。 注册…

【d45】【Java】【力扣】206.反转链表

思路 解法1&#xff1a;适用于数字不多的 1.把节点的数&#xff0c;都放进一个arraylist中 2.调用Collections.reverse(list)方法&#xff0c;将list转置 3.再遍历list&#xff0c;逐个放入数字 代码 解法1 import java.util.ArrayList; import java.util.Collections;p…

window批处理脚本:将本地的三个文件通过SCP传输到Linux设备上

文件名send_file.bat&#xff1a; echo off setlocal:: 提示用户输入远程IP地址 set /p remoteIpAddressplease input IP::: 定义本地文件名 set "localFile1111" set "localFile2222" set "localFile3333":: 获取本地文件的完整路径 set "…

【AI视频】Runway:Gen-2 图文生视频与运动模式详解

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AI视频 | Runway 文章目录 &#x1f4af;前言&#x1f4af;仅图片生成视频方法一&#xff1a;通过Midjourney生成图片方法二&#xff1a;通过Runway预览生成图片注意点 &#x1f4af;图加文生成视频方式一&#xff1a;Midjourney…

百度飞浆Paddle OCR检测和识别【OCR数据收集、标注、数据集划分、检测识别模型训练、导出模型】

文章目录 前言一、OCR数据集采集二、OCR数据标注三、划分数据集四、数据训练五、导出模型 前言 1、我的电脑没有GPU&#xff0c;如果不使用AI Studio训练的话&#xff0c;第一遍我是按照CPU进行环境配置和训练的&#xff0c;可以参考这篇文章&#xff0c;我按着弄了一遍&#…

安克创新25届校招CATA北森测评:笔试攻略、真题题库、高分技巧

安克创新自适应能力CATA测评是该公司用于评估候选人认知能力的计算机自适应测评系统。该测评系统由北森题库提供支持&#xff0c;是国内唯一被国际计算机自适应测验协会(IACAT)收录的产品。测评主要评估以下几个维度&#xff1a; 言语能力&#xff1a;测试理解言语信息并基于这…

25届计算机专业毕设选题推荐-基于python+Django协调过滤的新闻推荐系统

&#x1f496;&#x1f525;作者主页&#xff1a;毕设木哥 精彩专栏推荐订阅&#xff1a;在 下方专栏&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; 实战项目 文章目录 实战项目 一、基于协调过滤的新闻推荐系统…

浅谈穷举法

穷举法 穷举法是一种通过逐一列举所有可能情况来寻找解决方案的方法。就像找到一把钥匙打开一把锁&#xff0c;我们会尝试每一把钥匙直到找到正确的那一把。比如&#xff0c;如果你忘记了自己的密码&#xff0c;可以尝试每一种可能的组合直到找到正确的密码为止 穷举法的结构 …

【计算机网络 - 基础问题】每日 3 题(十六)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…

spring boot启动报错:so that it conforms to the canonical names requirements

springboot 2.x的版本中对配置文件中的命名规范有了强制性的要求&#xff0c;如下图所示中的dataSource属性属于驼峰格式&#xff0c;但是在springboot 2.x中不允许使用驼峰形式。 根据错误提示可知将其使用 - 来分割即可 错误信息的含义&#xff1a;“Canonical names should…

51单片机-红外遥控器(NEC标准)

作者&#xff1a;Whappy 时间&#xff1a;2024.9.20 总结一下&#xff01;基础实验到这儿里就圆满结束&#xff0c;历经25天&#xff0c;将51单片机学完并亲自手敲代码近5000行&#xff0c;在手敲代码过程中&#xff0c;明显感觉的看和敲&#xff0c;明显就是不同的感觉&…

基于PHP的CRM管理系统源码/客户关系管理CRM系统源码/php源码/附安装教程

源码简介&#xff1a; 这是一款基于PHP开发的CRM管理系统源码&#xff0c;全称客户关系管理CRM系统源码&#xff0c;它是由php源码开发的&#xff0c;还附带了一整套详细的安装教程哦&#xff01; 功能亮点&#xff1a; 1、公海管理神器&#xff1a;不仅能搞定公海类型&…

阿里开源多模态大模型Ovis1.6,重塑出海电商AI格局

阿里开源Ovis1.6&#xff1a;多模态领域再夺第一 阿里再一次证明了自己在多模态领域的实力。这一次&#xff0c;阿里国际AI团队开源的多模态大模型Ovis1.6&#xff0c;不仅成功开源&#xff0c;还在多模态评测基准OpenCompass上击败了Qwen2VL-7B、InternVL2-26B和MiniCPM-V-2.…