系列文章目录
文章目录
前言
darkent是个轻量级深度学习训练框架,用c和cuda编写,支持GPU加速。你可以理解为darknet和tensorflow, pytorch, caffe, mxnet一样,是用于跑模型的底层,像resnet、yolo是模型结构,是一种训练网络
darknet是YOLO作者自己写的一个深度学习框架(见YOLO原文2.2部分),后来在YOLO9000中又提了一个基于ResNet魔改的19层卷积网络,称为Darknet-19,在YOLOv3中又提了一个更深的Darknet-53,这两个都是用于提取特征的主干网络。像yolov2、v3、v4、v7都可以在Darknet框架上实现(yolov5是用pytorch)。其主要特点就是容易安装,没有任何依赖项(OpenCV都可以不用),移植性非常好,支持CPU与GPU两种计算方式。
采用底层C语言有利于运行效率的提高,对一些算法库依赖有利于减轻体量,移植性独立性好可以多用于嵌入式等小算力小成本板子(不包括训练)。
相比于TensorFlow与pytorch这些大框架来说,darknet并没有那么强大,但darknet也有自己的优势:
1.易于安装:在makefile里面选择自己需要的附加项(cuda,cudnn,opencv等)直接make即可,几分钟完成安装;
2.没有任何依赖项:整个框架都用C语言进行编写,可以不依赖任何库,连opencv作者都编写了可以对其进行替代的函数;
3.结构明晰,源代码查看、修改方便:其框架的基础文件都在src文件夹,而定义的一些检测、分类函数则在example文件夹,可根据需要直接对源代码进行查看和修改;
4.友好python接口:虽然darknet使用c语言进行编写,但是也提供了python的接口,通过python函数,能够使用python直接对训练好的.weight格式的模型进行调用;
5.易于移植:该框架部署到机器本地十分简单,且可以根据机器情况,使用cpu和gpu,特别是检测识别任务的本地端部署,darknet会显得异常方便。
一、NoMachine、FileZilla与服务器
一些非本文重点但会用到的:
NoMachine安装与使用
NoMachine用于远程连接服务器,前提是你的服务器允许外网连接。
FileZilla安装与使用
FileZilla用于本地与服务器连接进行文件传输,前提是你的服务器允许外网连接。
服务器使用多用户,避免影响主用户。
二、安装配置darknet
1、下载
(很有暗网黑科技感的设计)
darknet官网
2、编译
- 首先你要有自己的深度学习环境,具体环境安装配置可以参考我以前的博客去配置,再根据自己的配置环境,修改Makefile值
问题一:NVCC问题
nvcc -gencode arch=compute_30,code=sm_30 -gencode arch=compute_35,code=sm_35 -gencode arch=compute_50,code=[sm_50,compute_50] -gencode arch=compute_52,code=[sm_52,compute_52] -Iinclude/ -Isrc/ -DOPENCV pkg-config --cflags opencv
-DGPU -I/usr/local/cuda/include/ -DCUDNN --compiler-options “-Wall -Wno-unused-result -Wno-unknown-pragmas -Wfatal-errors -fPIC -Ofast -DOPENCV -DGPU -DCUDNN” -c ./src/convolutional_kernels.cu -o obj/convolutional_kernels.o
/bin/sh: 1: nvcc: not found
Makefile:89: recipe for target ‘obj/convolutional_kernels.o’ failed
make: *** [obj/convolutional_kernels.o] Error 127
解决办法:
进入darknet目录,编辑Makefile,修改NVCC路径。
- 在darknet文件夹下执行命令
make
- 编译成功
问题二:yolo_console_dll.cpp:(.text.startup+0x2ec)问题
make编译darknet时,报错
在函数‘main’中: yolo_console_dll.cpp:(.text.startup+0x2ec):对‘Detector::Detector(std::__cxx11::basic_string, std::allocator >, std::__cxx11::basic_string, std::allocator >, int, int)’未定义的引用 collect2: error: ld returned 1 exit status Makefile:173: recipe for target 'uselib' failed make: *** [uselib] Error 1
解决办法:
借鉴#7654
进入Makefile文件
注释
#$(CPP) -std=c++11 $(COMMON) $(CFLAGS) -o $@ src/yolo_console_dll.cpp $(LDFLAGS) -L ./ -l:$(LIBNAMESO)
更改为
$(CPP) -std=c++11 $(COMMON) $(CFLAGS) -o $@ src/yolo_console_dll.cpp $(LDFLAGS) -L ./ $(LIBNAMESO)
三、数据集与模型准备
1、数据集下载
结构:
WisdomGuide______annotations______train_list.txt
| |___val_list.txt
| |___instance_train.json
| |___instance_val.json
|_______train________JPEGImages___图片文件
| |___labels___标签文件
|________val________JPEGImages___图片文件
|___labels___标签文件
修改数据集的分布,新建train、val、JPEGImages和labels文件夹,其中train是存放训练集,val存放测试集,JPEGImages放图片,labels放标签文件,train_list.txt是所有训练图片路径,val_list.txt是所有测试图片路径。这些文件的建立与分布是有规律有原因的,如果不想修改代码就用这个数据集格式。
注意对于图片文件夹JPEGImages和标签文件夹labels,如果想把图片和标签分开放在不同文件夹,那么对于的文件夹名称必须是JPEGImages和labels,如果想图片和标签混合放在同一个文件夹下那么就不要用这两名字。
train_list.txt、val_list.txt、标签txt文件由下面的脚本生成。
2、json转txt脚本和路径聚合脚本
json_txt.py:
更改成自己的路径
import os
import json
from tqdm import tqdm
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--json_path', default='/home/nh666/llw/ORB_FAR/WisdomGuide/annotations/instance_val.json', type=str, help="input: coco format(json)")
parser.add_argument('--save_path', default='/home/nh666/llw/ORB_FAR/WisdomGuide/annotations/val_txt', type=str, help="specify where to save the output dir of labels")
arg = parser.parse_args()
def convert(size, box):
dw = 1. / (size[0])
dh = 1. / (size[1])
x = box[0] + box[2] / 2.0
y = box[1] + box[3] / 2.0
w = box[2]
h = box[3]
x = x * dw
w = w * dw
y = y * dh
h = h * dh
return (x, y, w, h)
if __name__ == '__main__':
json_file = arg.json_path # COCO Object Instance 类型的标注
ana_txt_save_path = arg.save_path # 保存的路径
data = json.load(open(json_file, 'r'))
if not os.path.exists(ana_txt_save_path):
os.makedirs(ana_txt_save_path)
id_map = {} # coco数据集的id不连续!重新映射一下再输出!
for i, category in enumerate(data['categories']):
id_map[category['id']] = i
# 通过事先建表来降低时间复杂度
max_id = 0
for img in data['images']:
max_id = max(max_id, img['id'])
# 注意这里不能写作 [[]]*(max_id+1),否则列表内的空列表共享地址
img_ann_dict = [[] for i in range(max_id + 1)]
for i, ann in enumerate(data['annotations']):
img_ann_dict[ann['image_id']].append(i)
for img in tqdm(data['images']):
filename = img["file_name"]
img_width = img["width"]
img_height = img["height"]
img_id = img["id"]
head, tail = os.path.splitext(filename)
ana_txt_name = head + ".txt" # 对应的txt名字,与jpg一致
f_txt = open(os.path.join(ana_txt_save_path, ana_txt_name), 'w')
'''for ann in data['annotations']:
if ann['image_id'] == img_id:
box = convert((img_width, img_height), ann["bbox"])
f_txt.write("%s %s %s %s %s\n" % (id_map[ann["category_id"]], box[0], box[1], box[2], box[3]))'''
# 这里可以直接查表而无需重复遍历
for ann_id in img_ann_dict[img_id]:
ann = data['annotations'][ann_id]
box = convert((img_width, img_height), ann["bbox"])
f_txt.write("%s %s %s %s %s\n" % (id_map[ann["category_id"]], box[0], box[1], box[2], box[3]))
f_txt.close()
path_synthesis.py:
更改成自己的路径
# -*- coding: utf-8 -*-
import time
import os
import shutil
# 获取所有文件路径集合
def readFilename(path, allfile):
filelist = os.listdir(path)
for filename in filelist:
filepath = os.path.join(path, filename)
if os.path.isdir(filepath):
readFilename(filepath, allfile)
else:
allfile.append(filepath)
return allfile
if __name__ == '__main__':
# 文件夹路径
path1 = "/home/nh666/llw/ORB_FAR/WisdomGuide/val"
allfile1 = []
allfile1 = readFilename(path1, allfile1)
allname1 = []
# 文件路径
txtpath = "/home/nh666/llw/ORB_FAR/WisdomGuide/annotations/val_list.txt"
for name in allfile1:
print(name)
file_cls = name.split("/")[-1].split(".")[-1]
# 后缀名
if file_cls == 'png':
print(name.split("/")[-1])
with open(txtpath, 'a+') as fp:
fp.write("".join(name) + "\n")
3、文件修改
1. .names文件
复制一份darknet/data/voc.names文件并重命名为voc_blind.names,里面存放的是训练的类别,不过在训练时不会真的标注为什么什么东西,而是标注为01234序号,所以文件中的类别名的排序是很重要的,要对应你的标签txt文件。
2. .data文件
复制一份darknet/cfg/voc.data文件并重命名为voc_blind.data,里面存放的是classes类别数、train/valid数据集路径、names类别名路径、backup模型路径,需要根据自己的位置修改。
3. .cfg文件
前段日子yolov7发布了,发现darknet也有实现,本来打算用v7的,但是训练时发现训练不了,报错
cuDNN status Error in: file: ./src/convolutional_kernels.cu : () : line: 555 : build time: Oct 26 2022 - 16:19:38
cuDNN Error: CUDNN_STATUS_BAD_PARAM
Darknet error location: ./src/dark_cuda.c, cudnn_check_error, line #204
cuDNN Error: CUDNN_STATUS_BAD_PARAM: Resource temporarily unavailable
解决思路:
主要有三种思路
- 更改CUDA和CUDNN版本,具体是哪些版本就不清楚了
- 训练时不使用-map命令,不计算mAP
- 更改调整batch和subdivisions的值,具体是多少就不清楚了
我选择在cfg里将batch和subdivisions更改为 64 解决了这个问题,这个更改似乎与你的训练硬件相关,比如单卡、多卡、cpu、gpu等。
batch=64
subdivisions=64 # changed from 16 to 64
width=416
height=416
至于CUDA和CUDNN的话,我查了一下github里的讨论区,似乎需要改cuDNN版本,但是我是在服务器训练,不能随便改,所以退而求次用yolov4。
4. yolov4-tiny.cfg
复制一份darknet/cfg/yolov4-tiny.cfg文件并重命名为yolov4_blind.cfg,更改设置:
subdivisions为8的倍数,如果 GPU 显存大 subdivisions 可以 填 8,显存小时可以填 32。
max_batches为最大训练次数,与样本数量无直接关系,建议是样本数×2000,避免拟合问题。
steps改为 max_batches 的 80% and 90%。
subdivisions=8
max_batches = 10000
steps=8000,9000
ctrl+F搜索“yolo”关键字,有几个改几个,继续更改:
filters=30 //公式计算(5+类别数)×3
activation=linear
[yolo]
mask = 3,4,5
anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319
classes=5
四、训练与测试
1、终端训练
单卡
进入darknet文件夹,进入终端,执行以下命令:
sudo ./darknet detector train cfg/voc_blind.data cfg/yolov4_blind.cfg -map
训练结果map
多卡
先查询是否是多卡gpu
#静态查询
nvidia-smi
#动态查询 每10秒检查gpu使用情况
watch -n 10 nvidia-smi
看看那些卡是没有被占用的,被占用说明有别人在训练啥的特别是在服务器上,别乱动别人的东西。
比如说我的是四卡,其中0,1卡GPU-Util占比为0%,那么就用0,1卡空闲。
sudo ./darknet detector train cfg/voc_blind.data cfg/yolov4_blind.cfg -gpus 0,1 -map
多卡速度就是比单卡快
参数解释:
表格中会显示显卡的一些信息,第一行是版本信息,第二行是标题栏,第三行就是具体的显卡信息了,如果有多个显卡,会有多行,每一行的信息值对应标题栏对应位置的信息。
* GPU:编号,这里是0,1,2,3
* Fan:风扇转速,在0到100%之间变动,第一个是32%
* Name:显卡名,这里都是GeForce
* Temp:显卡温度,第一个是55摄氏度
* Perf:性能状态,从P0到P12,P0性能最大,P12最小
* Persistence-M:持续模式的状态开关,该模式耗能大,但是启动新GPU应用时比较快,这里是off
* Pwr:能耗
* Bus-Id:GPU总线
* Disp.A:表示GPU的显示是否初始化
* Memory-Usage:显存使用率
* GPU-Util:GPU利用率,第一个是22%,第二个6%
* Compute M.:计算模式
需要注意的一点是显存占用率和GPU占用率是两个不一样的东西,类似于内存和CPU,两个指标的占用率不一定是互相对应的。
报错1
CUDA Error: out of memory
Darknet error location: ./src/dark_cuda.c, check_error, line #69
CUDA Error: out of memory: No such file or directory
意思就是内存不足,有两种可能要么就是你的GPU内存满了,可以用nvidia-smi看看,要么就是.cfg文件的batch和subdivisions值可能太大了,可以改为64>32>16>8>1等等。
2、模型保存
best 模型是在训练过程中取得最佳性能的模型。它通常是在验证集上取得最佳性能的模型。
final 模型是在训练过程结束时保存的模型。它通常是在完成训练后保存的最后一个模型。
last 模型是在训练过程中最后一次保存的模型。它通常是在训练过程中的某个时刻保存的模型,并不一定是最佳性能的模型。
因此,这三个模型代表了训练过程中不同时间保存的模型,可以用来比较模型的性能,并选择最佳模型进行推理。
在dackup下,其中它认为best是最佳的。
3、测试
1.图片测试
sudo ./darknet detector test cfg/voc_blind.data cfg/yolov4_blind.cfg backup/yolov4_blind_best.weights
运行后还会需要你去输入图片路径。
2.val验证
sudo ./darknet detector valid cfg/voc_blind.data cfg/yolov4_blind.cfg backup/yolov4_blind_best.weights
运行后会生成验证集val的验证文件。
3.实时检测
五、cfg文件解读
以resnet50.cfg模型文件为例:
#darknet中用于定义网络结构的组件,它包含了一系列参数,用于指定网络的输入大小、batch大小、学习率等,还可以指定网络的类型和激活函数,以及指定网络的权重初始化方式。
[net]
# Training
#每次训练时,darknet将从训练数据集中抽取128个样本进行训练。
batch=128
#每次训练时,使用4个mini-batch,每个mini-batch的大小等于batch_size/4,这样可以提高训练速度和精度,训练时间可能会延长。
subdivisions=4
# Testing
# batch=1
# subdivisions=1
#样本数据设置
#输入图片的高度和宽度
height=256
width=256
#在图像预处理时,将图像裁剪为448x448像素大小。,可以提高网络的训练速度和准确率。
max_crop=448
#图像的通道数,即RGB图像的通道数
channels=3
#momentum梯度下降算法中的一个超参数,可以帮助模型更快地收敛。通过记录每次更新的梯度,在每次迭代时将其累积到当前梯度中来实现。
#每次更新梯度时,模型会将上一次梯度的90%累积到当前梯度中。
momentum=0.9
#学习率衰减系数,即每次训练后学习率会乘以衰减系数,以减小学习率,减少模型过拟合。
decay=0.0005
#训练方式设置
#在训练神经网络之前,使用1000个训练数据来初始化权重,以确保神经网络能够正确地从训练开始,前1000层的权重都将被设置为预训练的权重,而后面的层则被随机初始化。
burn_in=1000
#每次迭代模型时更新后参数与原参数之间的比例。0.1表示每次更新后参数与原参数之间的比例为10%。
learning_rate=0.1
#使用poly来调整学习率。,可以帮助模型更快地收敛。
#学习率优化策略,根据训练步骤的不同改变学习率,从而更有效地训练神经网络有效地提高模型的性能。
policy=poly
#表示使用的是ReLU激活函数,使用4倍的梯度下降加速训练。power越大,激活函数越陡峭,模型越容易收敛,但也可能会导致过拟合。
power=4
#神经网络训练的最大次数,1600000次表示训练过程将会运行1600000次
max_batches=1600000
#图像优化处理设置
#使用7个不同的角度(0°,45°,90°,135°,180°,225°,270°)来增强图像,以提高模型的鲁棒性。
angle=7
#hue=.1是图像的色调参数,表示色调偏移量为0.1,可以控制图像的色彩深浅,以及色彩组合的调整。
hue=.1
#色彩饱和度,它是影响图像色彩的一个参数,取值范围为[0,1],取值越大,图像的色彩饱和度越高。
saturation=.75
#图像的曝光度。它是一种图像增强技术,可以改变图像中每个像素的亮度,以改善模型的泛化能力。
exposure=.75
#图像的宽高比,aspect=.75表示要求输入的图像宽高比必须是0.75
aspect=.75
#卷积操作参数设置
#darknet中的一个层,它可以实现卷积操作,以提取图像的特征。卷积层是神经网络中最重要的层之一,它可以提取图像中的特征,并将它们传递给下一层。
[convolutional]
#启用batch normalization,这意味着每个卷积层都会在每次训练时进行规范化,以提高模型的准确性和效率。
batch_normalize=1
#每一次卷积过后的输出通道数,也就是卷积滤波器的数量。每一层卷积层都有一个卷积核,每个卷积核都会产生一个输出通道,filters=64表示每一层卷积层的卷积核个数和输出通道数为64。
filters=64
#卷积核尺寸
size=7
#每次卷积操作的步长为2,即每次卷积操作后,特征图的尺寸减少一半
stride=2
#在每一层卷积操作之前,先在输入图像的四周填充1个像素的边缘,这样可以避免边缘信息的损失。
pad=1
#Leaky ReLU激活函数,它允许一定程度的梯度流失,这有助于防止神经网络中出现的梯度消失问题,从而提高模型的准确性和精确性。
activation=leaky
#最大下采样池化层,用于提取图像中的最大值,以减少图像的尺寸,并保留最重要的特征,可以减少计算量,提高模型的准确性,并且可以防止过拟合。
[maxpool]
#卷积核尺寸为2
size=2
#每次卷积操作的步长为2,即每次卷积操作后,特征图的尺寸减少一半
stride=2
[convolutional]
batch_normalize=1
filters=64
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=64
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
#线性激活函数,即没有任何激活函数。这意味着神经元的输出值与输入值之间没有任何变化,这种情况通常用于输出层,因为输出层通常需要线性激活函数来计算预测结果。这种激活函数可以有效地减少网络的复杂性,并可以保证网络的稳定性。
activation=linear
#残差网络中的一种融合做加法技术,它允许在相同层之间建立一条直接的路径,从而将输入信号直接传递到输出层。这样可以减少计算量,提高网络的性能。
[shortcut]
#从第四层开始,从而实现残差网络的特征提取。
from=-4
activation=leaky
[convolutional]
batch_normalize=1
filters=64
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=64
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=linear
[shortcut]
from=-4
activation=leaky
[convolutional]
batch_normalize=1
filters=64
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=64
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=linear
[shortcut]
from=-4
activation=leaky
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=128
size=3
stride=2
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=1
stride=1
pad=1
activation=linear
[shortcut]
from=-4
activation=leaky
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=128
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=1
stride=1
pad=1
activation=linear
[shortcut]
from=-4
activation=leaky
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=128
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=1
stride=1
pad=1
activation=linear
[shortcut]
from=-4
activation=leaky
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=128
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=1
stride=1
pad=1
activation=linear
[shortcut]
from=-4
activation=leaky
# Conv 4
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=3
stride=2
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=1024
size=1
stride=1
pad=1
activation=linear
[shortcut]
from=-4
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=1024
size=1
stride=1
pad=1
activation=linear
[shortcut]
from=-4
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=1024
size=1
stride=1
pad=1
activation=linear
[shortcut]
from=-4
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=1024
size=1
stride=1
pad=1
activation=linear
[shortcut]
from=-4
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=1024
size=1
stride=1
pad=1
activation=linear
[shortcut]
from=-4
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=1024
size=1
stride=1
pad=1
activation=linear
[shortcut]
from=-4
activation=leaky
#Conv 5
[convolutional]
batch_normalize=1
filters=512
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=3
stride=2
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=2048
size=1
stride=1
pad=1
activation=linear
[shortcut]
from=-4
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=2048
size=1
stride=1
pad=1
activation=linear
[shortcut]
from=-4
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=3
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=2048
size=1
stride=1
pad=1
activation=linear
[shortcut]
from=-4
activation=leaky
[convolutional]
filters=1000
size=1
stride=1
pad=1
activation=linear
#均值池化层,它是一种特殊类型的池化层,可以将输入特征图的每个通道求均值,并将输出转换为1x1xC的特征图
[avgpool]
#激活函数,它将输入的任意实数值映射到0到1之间的概率值,用于分类问题。它可以将多个输入值映射到唯一的输出概率值,因此可以用于多类分类问题。
[softmax]
#使用的是单组卷积,即只有一个组卷积层,而不是多组卷积层。这种架构的网络在深度学习中被称为ResNet,它使用了残差连接来提升模型的准确率。
groups=1
#使用的是平方损失函数,该函数可以衡量预测值和实际值之间的差异,从而帮助模型改进。
[cost]
#使用SSE(Streaming SIMD Extensions)指令集来加速神经网络的计算。SSE是一种用于改善CPU的流水线性能的指令集,可以更有效地运行多个数学运算。
type=sse