学习目标
- 知道YoloV3模型结构及构建方法
- 知道数据处理方法
- 能够利用yoloV3模型进行训练和预测
一部分是网络数据,可以是开源数据,也可以通过百度、Google图片爬虫得到
在接下来的课程中我们就使用标注好的数据进行模型训练,模型预测。使用的工程如下所示:
主要内容是:
1.config中是网络的配置信息:anchors,类别信息
2.core中是损失函数计算,网络预测的内容
3.dateset中是对数据的处理
4.model是对模型的构建
5.utils是一些辅助文件,包括anchor,类别信息的获取等
6.weights中保存了一个使用coco数据集训练的预训练模型
- TFRecord是Google官方推荐使用的数据格式化存储工具,为TensorFlow量身打造的。
- TFRecord规范了数据的读写方式,数据读取和处理的效率都会得到显著的提高。
首先导入工具包
from dataset.vocdata_tfrecord import load_labels,write_to_tfrecord
import os
将数据写入tfrecord中的流程是:
from matplotlib.patches import Rectangle
from utils.config_utils import read_class_names
classes = read_class_names("config/classname")
plt.figure(figsize=(15, 10))
i = 0
# 从datasets中选取3个样本,获取图像,大小,框的标注信息和类别信息
for image, width, height, boxes, boxes_category in datasets.take(3):
plt.subplot(1, 3, i+1)
plt.imshow(image)
ax = plt.gca()
for j in range(boxes.shape[0]):
# 绘制框
rect = Rectangle((boxes[j, 0], boxes[j, 1]), boxes[j, 2] -boxes[j, 0], boxes[j, 3]-boxes[j, 1], color='r', fill=False)
# 将框显示在图像上
ax.add_patch(rect)
label_id = boxes_category[j]
# 获取标准信息
label = classes.get(label_id.numpy())
ax.text(boxes[j, 0], boxes[j, 1] + 8, label,color='w', size=11, backgroundcolor="none")
# 下一个结果
i += 1
# 显示图像
plt.show()
输入:原图像及图像上的标准框 # 输出:将尺度调整后的图像,及相应的目标框 image,bbox = preprocess(oriimage,oribbox,input_shape=(416,416))
对读取的数据进行处理并绘制结果
from dataset.preprocess import preprocess as ppro
plt.figure(figsize=(15,10))
i = 0
for image,width,height,boxes,boxes_category in datasets.take(3):
image,boxes = preprocess(image,boxes)
plt.subplot(1,3,i+1)
plt.imshow(image[0])
ax = plt.gca()
for j in range(boxes.shape[0]):
rect = Rectangle((boxes[j, 0], boxes[j, 1]), boxes[j, 2] -boxes[j, 0], boxes[j, 3]-boxes[j, 1], color='r', fill=False)
ax.add_patch(rect)
label_id = boxes_category[j]
label = classes.get(label_id.numpy())
ax.text(boxes[j, 0], boxes[j, 1] + 8, label,color='w', size=11, backgroundcolor="none")
i+=1
plt.show()
# 导入工具包 from model.yoloV3 import YOLOv3
# 模型实例化:指定输入图像的大小,和类别数
yolov3 = YOLOv3((416,416,3),80)
# 获取模型架构
yolov3.summary()
在计算损失函数时使用core.loss来完成:
导入所需的工具包 from core.loss import Loss
实例化 yolov3_loss = Loss((416,416,3),80)
损失输入 yolov3_loss.inputs
损失输出 yolov3_loss.outputs
- 正样本:首先计算目标中心点落在哪个grid上,然后计算这个grid对应的3个先验框(anchor)和目标真实位置的IOU值,取IOU值最大的先验框和目标匹配。那么该anchor 就负责预测这个目标,那这个anchor就作为正样本,将其置信度设为1,其他的目标值根据标注信息设置。
- 负样本:所有不是正样本的anchor都是负样本,将其置信度设为0,参与损失计算,其它的值不参与损失计算,默认为0。
将目标值绘制在图像上
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
# 1.获取类别信息
from utils.config_utils import read_class_names
classes = read_class_names('config/classname')
plt.figure(figsize=(15,10))
for image,width,height,boxes,boxes_category in datasets.take(1):
# 4.显示图像:plt.imshow()
plt.imshow(image)
# 5.显示box,遍历所有的bbox,rectange进行绘制
ax = plt.gca()
for j in range(boxes.shape[0]):
rect = Rectangle((boxes[j, 0], boxes[j, 1]), boxes[j, 2] -boxes[j, 0], boxes[j, 3]-boxes[j, 1], color='r', fill=False)
ax.add_patch(rect)
# 6.显示类别
label_id = boxes_category[j]
label = classes.get(label_id.numpy())
ax.text(boxes[j, 0], boxes[j, 1] + 8, label,color='w', size=11, backgroundcolor="none")
# 7.绘制正样本的anchor的目标值
anchor = label1[12, 12,0,0:4].numpy()
rect2 = Rectangle((anchor[0]-anchor[2]/2, anchor[1]-anchor[3]/2), anchor[2], anchor[3],color='g', fill=False)
ax.add_patch(rect2)
plt.show()
1、加载数据集:我们在这里使用VOC数据集,所以需要从TFrecord文件中加载VOC数据集
2、模型实例化:加载yoloV3模型和损失函数的实现
3、模型训练:计算损失函数,使用反向传播算法对模型进行训练
# 导入 from dataset.preprocess import dataset
# 设置batch_size batch_size=1
# 获取训练集数据,并指定batchsize,返回训练集数据
trainset = dataset("dataset/voc_train.tfrecords",batch_size)
在yoloV3模型和损失函数的计算进行实例化
# V3模型的实例化,指定输入图像的大小,即目标检测的类别个数
yolov3 = YOLOv3((416, 416, 3,), 20)
yolov3_loss = Loss((416,416,3), 20)
模型训练也就是要使用损失函数,进行反向传播,利用优化器进行参数更新,训练的流程是:
1、指定优化器:在这里我们使用加动量的SGD方法
2、设置epoch,进行遍历获取batch数据送入网络中进行预测
3、计算损失函数,使用反向传播更新参数,我们使用tf.GradientTape实现:
# 1、定义优化方法
optimizer = tf.keras.optimizers.SGD(0.1,0.9)
for epoch in range(300):
loss_history = []
# 遍历每一个batch的图像和目标值,进行更新
for (batch, inputs) in enumerate(trainset):
images, labels = inputs
# 3.计算损失函数,使用反向传播更新参数
# 3.1 定义上下文环境
with tf.GradientTape() as tape:
outputs = yolov3(images)
loss = yolov3_loss([*outputs, *labels])
grads = tape.gradient(loss, yolov3.trainable_variables)
optimizer.apply_gradients(zip(grads, yolov3.trainable_variables))
info = 'epoch: %d, batch: %d ,loss: %f'%(epoch, batch, np.mean(loss_history))
print(info)
loss_history.append(loss.numpy())
yolov3.save('yolov3.h5')
Original: https://blog.csdn.net/weixin_53226226/article/details/122690814
Author: AI-创造美好未来
Title: YoloV3 案例
相关阅读
Title: 【平头哥RVB2601开发板试用体验】基于 HTTPClient 的云语音识别 2
作者 | 哈猪猪
在文章1中我们计划用 HTTPClient 组件帮助我们与服务器通信,上传录音文件并接收识别结果,最终实现云语音识别。经过测试后没有问题,因此接下来我们需要理解该组件提供的功能,并实现文件对服务器的上传。
首先,根据 HTTPClient 组件的示例程序 http_examples.c,我们得知了一个完整的 HTTP 请求需要调用的接口流程,大致如下。以 POST 请求为例,并直接设置 url 而非 host&path:
http_client_config_t config = {
.url = "http://httpbin.org/get",
.event_handler = _http_event_handler,
};
http_client_handle_t client = http_client_init(&config);
​
const char *post_data = "field1=value1&field2=value2";
http_client_set_method(client, HTTP_METHOD_POST);
http_client_set_post_field(client, post_data, strlen(post_data));
err = http_client_perform(client);
if (err == HTTP_CLI_OK) {
LOGI(TAG, "HTTP POST Status = %d, content_length = %d \r\n",
http_client_get_status_code(client),
http_client_get_content_length(client));
} else {
LOGE(TAG, "HTTP POST request failed: 0x%x @#@@@@@@", (err));
e_count ++;
}
整个流程主要涉及到以下几个函数:
http_client_init() 主要是基于 config 对 client 结构的各种变量赋初值,包括在请求中会用的到的各种缓存空间,以及 header 中的基本信息。其中 config 未设置的会赋缺省值。也可以用库提供的各种 set_xxx 函数来对变量赋值。
http_client_set_post_field():对于有请求体的 POST,我们需要调用这个函数将发送数据的指针以及长度赋予 client:
web_err_t http_client_set_post_field(http_client_handle_t client, const char *data, int len)
{
web_err_t err = WEB_OK;
client->post_data = (char *)data; // 待发送数据指针
client->post_len = len; // 待发送数据长度
LOGD(TAG, "set post file length = %d", len);
// 如果此前没有设置 Content-Type,则设置为 application/x-www-form-urlencoded
if (client->post_data)
{
char *value = NULL;
if ((err = http_client_get_header(client, "Content-Type", &value)) != WEB_OK)
{
return err;
}
if (value == NULL)
{
err = http_client_set_header(client, "Content-Type", "application/x-www-form-urlencoded");
}
}
else
{
client->post_len = 0;
err = http_client_set_header(client, "Content-Type", NULL);
}
return err;
}
阅读源码可见,库默认支持"Content-Type"为"application/x-www-form-urlencoded"的 POST 请求,而我们要上传音频文件是"multipart/form-data"类型的。然而浏览了整个 HTTPClient 组件发现它就支持这一种类型......POST 的具体实现也只支持这一种。我们接着往下看就知道了......
http_client_perform():无论是什么 HTTP 请求,在设置完 client 之后最后都是经由这一个函数来具体实现。该函数将根据当前所处的 HTTP 请求流程,调用对应的函数,而这些函数最终会调用 transport 组件即在传输层上读写,最终实现整个 HTTP 请求。http_client_perform() 依次主要调用了以下几个函数:
http_client_prepare();
http_client_connect();
http_client_request_send();
http_client_send_post_data();
http_client_fetch_headers();
http_check_response();
http_client_get_data();
http_client_close();
实现的功能与其函数名一致,也是我们熟知的 HTTP 请求流程。其中我们最关心的当然是http_client_send_post_data():
static web_err_t http_client_send_post_data(http_client_handle_t client)
{
// 此时请求头应发送完毕
if (client->state != HTTP_STATE_REQ_COMPLETE_HEADER)
{
LOGE(TAG, "Invalid state");
return WEB_ERR_INVALID_STATE;
}
// 没有要发送的 post_data 直接返回(包括其它请求)
if (!(client->post_data && client->post_len))
{
goto success;
}
​
// 发送 post_data
int wret = http_client_write(client, client->post_data + client->data_written_index, client->data_write_left);
if (wret < 0)
{
return wret;
}
// 在 request send 里面 data_write_left 最后被赋值为 post_len
client->data_write_left -= wret;
// 在 request send 里面 data_written_index 最后被赋值为 0
client->data_written_index += wret;
​
// 发送完毕
if (client->data_write_left <= 0) { goto success; } else return err_http_write_data; success: 更新状态 client->state = HTTP_STATE_REQ_COMPLETE_DATA;
return WEB_OK;
}</=>
可见,整个 POST 实现只会发送一次 post_data,它指向我们最初在 http_client_set_post_field() 中填入的待发送数据。然而,我们知道要发送"multipart/form-data"类型的数据,需要按照格式用 boundary 对请求体进行封装,并在请求头中提前告知 boundary。当然,HTTPClient 组件是没有实现这些的......因此如果我们要利用 HTTPClient 发送音频数据,就必须手动实现"multipart/form-data"类型请求体的封装与发送。
当我终于大致理解了 HTTPClient 组件后,我在浏览 YOC 源码时发现了一个就叫"http"的组件,它并没有出现在 YOC 文档里然而它已经实现了"multipart/form-data"类型的 POST......囿于我技术水平有限,源码缺少注释,感觉学习成本过高,遂放弃。
事实上针对本项目要实现的云语音识别,YOC 还有很多更适合的组件:麦克风服务,云音交互(AUI Cloud)......甚至后者本身就是为语音识别等应用构建的。然而由于源码没有注释,只有接口介绍文档,以及其它板子上的相关例程,感觉"移植"组件对自己难度过大,最终都没有使用,选择了基于 HTTPClient 手动实现音频数据的发送。
欢迎关注公众号: 芯片开放社区(ID:OCC_THEAD),查看更多应用实战文章。
Original: https://blog.csdn.net/OCC_THEAD/article/details/123706836
Author: 平头哥芯片开放社区
Title: 【平头哥RVB2601开发板试用体验】基于 HTTPClient 的云语音识别 2