尧图精选

YOLOv8在股票K线图上的实战:232张小样本数据集训练熊市/牛市检测全流程

🕒 发布时间:2026/10/1 5:42:11 📁 来源:尧图网络
简介面向YOLO系列目标检测算法实践者的股票行情形态识别数据集聚焦熊市与牛市走势图中的关键特征标注可用于金融图表自动化分析、技术指标可视化检测等场景的算法训练与效果验证。包内共465个文件包括232张jpg图像、232个配套txt标注文件及1个yaml配置文件压缩包约8.56MB解压即可直接使用。标注内容采用标准YOLO格式记录类别索引、归一化后的目标框中心点坐标与宽高比例数据集已按训练集与验证集划分妥当免去自行整理样本的环节。整体兼容yolov5、yolov7、yolov8、yolov9、yolov10及yolo11可直接将yaml路径指向本地目录进行模型训练与验证测试。目前已有56人浏览学习适合需要快速获取带标签金融图表数据以跑通完整检测流程的入门及进阶开发者是一份轻量、直接可用的数据集资源。1. 把YOLO算法用在股票K线图上232张熊市/牛市图像到底能训练出什么如果你手头正好压着一个“yolo算法-股票数据数据集-232张图像带标签-熊市_牛市-stock-data-78an1.zip”多半第一反应是丢进YOLOv8里跑一版看它能不能从K线图里区分熊市和牛市。这个数据集非常小只有232张图像和对应的标签类别就两个熊市(bear)、牛市(bull)。但恰恰是这种小样本金融图像最容易让不了解数据结构的选手翻车训练loss压得很低验证mAP却像随机猜测或者模型记住的是股票软件的背景色根本不是K线形态。这篇文章会把从解压、核查标签、写data.yaml到训练、增强、验证和踩坑的完整路径走一遍适合想用真实小数据集落地YOLO检测的算法工程师也适合搞量化的工程师快速判断这个方向值不值得投入。先说结论YOLO能跑也能收敛但232张图像决定它只能做有限趋势识别不能当稳定交易信号。真正的功夫在标签核查和数据切分上这两个环节不做好后面全是玄学。2. 拆解stock-data-78an1.zip先弄清232张图像里的熊市牛市标签是检测还是分类拿到带“带标签”三个字的压缩包我建议先花3分钟把文件结构看清楚而不是急着建环境。很多训练中途报错都源于图像和标签目录对不上、标签文件是空的、类别顺序写反这类基础问题。2.1 先解压并判断它是检测格式还是分类格式解压命令如下注意压缩包名是中文建议用双引号包住。unzip yolo算法-股票数据数据集-232张图像带标签-熊市_牛市-stock-data-78an1.zip -d stock_data cd stock_data find . -maxdepth 3 -type f | sort | head -20-d stock_data是指定解压目标目录避免文件散落到当前目录find只显示前20个文件用来快速观察目录层级。常见结果有两种情况Aimages/train/xxxx.jpg和labels/train/xxxx.txt同名文件一一对应这是标准的YOLO检测格式。情况Btrain/熊市/xxxx.jpg、val/牛市/xxxx.jpg这种按类别建子目录的结构是图像分类格式对应的是YOLOv8-cls任务不是检测任务。如果解压后看到data.yaml或classes.txt那基本可以确定数据集为YOLO训练准备过。classes.txt里通常写着两个类别名顺序决定了标签文件里数字0和1分别代表谁。2.2 用cat看一个标签文件读懂YOLO坐标含义先看类别定义文件cat classes.txt按常见命名习惯输出可能是bear和bull两行。紧接着看一个具体标签cat labels/train/00001.txt如果输出只有一行比如0 0.51 0.49 0.82 0.53这一行就是YOLO的标准标注格式第一列是类别id0对应classes.txt第一行的bear1对应bull后面四个数字分别是归一化之后的中心点x、中心点y、边界框宽度、边界框高度。归一化是指这些值全部除以图片自身的宽或高取值范围在0到1之间。所以0.51 0.49表示边界框中心大概在图片正中间0.82 0.53表示框的宽度占整张图宽度的82%高度占整张图的53%。如果这个框刚好覆盖整张K线图主体说明数据集做的是“整图趋势分类”用检测模型也能练但边界框并没有提供额外位置信息。如果一行有多个对象比如一张图里标注了多个K线形态那才是真正的目标检测任务。2.3 批量核对图像和标签是否一一对应训练前必须跑一遍对应关系检查尤其要警惕空标签文件。用一个简短脚本处理from pathlib import Path img_dir Path(stock_data/images/train) label_dir Path(stock_data/labels/train) missing [] for img in img_dir.glob(*.jpg): label label_dir / (img.stem .txt) if not label.exists(): missing.append(img.name) elif label.stat().st_size 0: missing.append(img.name (empty)) print(fmissing or empty: {len(missing)}) for name in missing[:10]: print( name)img.stem拿到的是去掉后缀的文件名比如00001.jpg变成00001再用它拼出00001.txt去检查。空标签文件会让YOLO在训练时跳过这张图偶尔一两个没影响如果跳过太多实际训练样本会缩水。缺失标签则通常会在数据加载阶段直接报错。2.4 检查图片尺寸和完整度排除破图干扰股票图表图片来源很杂有截图、有程序生成图宽度高度可能差别很大甚至存在损坏文件。用以下代码快速扫一遍from PIL import Image from pathlib import Path for p in list(Path(stock_data/images/train).glob(*.jpg))[:10]: with Image.open(p) as img: print(p.name, img.size, img.mode)img.size返回的是(宽, 高)img.mode通常是RGB或RGBA。如果大小严重不统一建议在data.yaml里统一imgsz640让YOLO训练时自动缩放。如果某张图打不开把该图和对应txt一起删掉别让一张坏图把整个训练流程带崩。2.5 把标注框画回原图一眼看出标注质量只看文本坐标很难发现问题我的习惯是把边界框画回原图检查一遍。import cv2 img cv2.imread(stock_data/images/train/00001.jpg) h, w img.shape[:2] with open(stock_data/labels/train/00001.txt) as f: for line in f: cls, xc, yc, bw, bh map(float, line.split()) x1 int((xc - bw / 2) * w) y1 int((yc - bh / 2) * h) x2 int((xc bw / 2) * w) y2 int((yc bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.imwrite(check_00001.jpg, img)这里把归一化坐标还原成像素坐标(xc - bw/2) * w是框左上角的x像素位置(xc bw/2) * w是右下角的x像素位置。cv2.rectangle最后一个参数2是线条粗细。如果框的位置偏到图片外、框住的是坐标轴而不是K线主体后面训练出来的模型就会学到错误位置信息这类问题越早发现越好。3. 用YOLOv8跑通熊市/牛市检测最小可复现训练流程确认数据格式没问题之后下一步是把它跑起来。我推荐直接用ultralytics封装好的YOLOv8训练命令短、日志清晰、验证工具也齐全。以下流程用232张图从零跑通一次完整训练。3.1 创建独立Python环境并安装ultralytics不建议直接往系统Python里装深度学习包依赖冲突会浪费大量时间。我一般用conda建独立环境conda create -n stock-yolo python3.10 -y conda activate stock-yolo pip install ultralyticspython3.10是目前比较稳妥的版本选择pip install ultralytics会连同PyTorch、OpenCV等必要依赖一起装好。装完后可以用python -c import ultralytics; print(ultralytics.__version__)验证是否成功。3.2 编写data.yaml确定类别顺序和数据集路径YOLO训练的数据集描述文件是data.yaml它不负责图像增强只告诉训练器三件事数据在哪、有几个类别、类别叫什么。# data.yaml path: /absolute/path/to/stock_data train: images/train val: images/val nc: 2 names: 0: bear 1: bullpath最好写成绝对路径避免相对路径在不同机器上解析不一致train和val是相对于path的目录路径。nc必须和标签文件里实际出现的类别数一致多余或缺少都会在训练前报错。names的索引顺序必须和标签文件第一列的数字对应如果标注文件里写的是0表示熊市那names[0]就必须是bear否则验证阶段无法看懂混淆矩阵。3.3 用预训练权重启动第一次训练最小可复现命令如下yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ patience20 \ projectstock_runs \ nameexp1 \ seed0 \ cacheTrue逐项说明参数modelyolov8n.pt是加载YOLOv8n的COCO预训练权重。首次运行会自动下载权重文件网络慢时也可以先把yolov8n.pt放到当前目录。小数据集迁移学习比从零训练稳定得多。imgsz640是训练输入尺寸。232张股票图通常不是正方形的YOLO会先按比例缩放再填充到640x640。batch16看显存决定。如果手里是V100、RTX3090这类卡16没问题如果只有8GB显存改成4更稳妥。patience20表示连续20个epoch验证指标没有改善就提前停止避免空跑时间。seed0固定随机种子保证同一条数据能复现结果。cacheTrue是将图像缓存进内存232张图很小加载速度提升明显。一个epoch大约只有232/16≈15个batch100个epoch很快就会跑完。训练过程中会看到类似下面的输出Epoch 10/100 GPU_mem: 6.2G box_loss: 1.12 cls_loss: 0.87 dfl_loss: 1.01 mAP50: 0.62 mAP50-95: 0.393.4 训练期间该看哪些数字很多人一看到loss下降就开心但小数据集上loss下降不一定是好事。需要同时看box_loss、cls_loss、dfl_loss这三个YOLO损失函数分量以及验证集的mAP50和mAP50-95。box_loss衡量边界框回归误差cls_loss衡量分类错误dfl_loss是分布焦点损失主要影响边界框边缘精度。如果三个loss都在降但mAP50不涨说明模型在训练集上记忆增强后的图像没有学到可泛化的规律。对熊市/牛市二分类任务mAP50比mAP50-95更直观因为类别少且边界框本身可能很粗糙mAP50-95偏低属于正常现象不必焦虑。4. 数据切分与增强让232张图真正用出效率小数据集最怕的不是模型不够大而是数据划分不科学和增强策略乱用。这一章直接解决这两个问题。4.1 如果压缩包未划分train/val先做分层切分很多下载来的数据打包时只有一份图像和标签目录没有train/val区分。这种情况下不能直接训练需要先切分。下面脚本把232张图按7:3切分到train和val目录import random import shutil from pathlib import Path root Path(stock_data) all_images list(root.glob(*.jpg)) if (root / images).exists() is False else list(root.glob(images/*.jpg)) labels {img.with_suffix(.txt) for img in all_images} random.Random(42).shuffle(all_images) train_imgs all_images[: int(len(all_images) * 0.7)] val_imgs all_images[int(len(all_images) * 0.7):] for phase, imgs in [(train, train_imgs), (val, val_imgs)]: img_dst root / images / phase lbl_dst root / labels / phase img_dst.mkdir(parentsTrue, exist_okTrue) lbl_dst.mkdir(parentsTrue, exist_okTrue) for img in imgs: txt img.with_suffix(.txt) if not txt.exists(): continue shutil.move(str(img), str(img_dst / img.name)) shutil.move(str(txt), str(lbl_dst / txt.name))这个脚本的关键点是标签和图像一起移动避免移动了图像漏掉标签。random.Random(42).shuffle固定伪随机种子保证每次切分结果一致。但如果文件名带有日期或者原本就是连续K线窗口我更建议按时间顺序切分而不是随机打乱。比如文件名是20240101_0001.jpg这种可以把前70%的时间区间作为train后30%作为val避免训练集和验证集来自同一段行情的相邻窗口。4.2 YOLO默认增强对股票图是危险的要显式关掉YOLOv8自带一整套数据增强默认值针对自然图像设计用在K线图上会把关键语义破坏掉。常见的增强坑如下fliplr水平翻转等于把时间轴倒过来K线图的时间顺序全乱牛市变镜像模型学到的是错误的时间关系。flipud垂直翻转等于把价格坐标倒置涨跌方向直接反转后果更严重。degrees旋转K线图的横轴是时间、纵轴是价格旋转几度就破坏了坐标语义。hsv_h、hsv_s、hsv_v颜色增强会改变K线的红绿颜色。股市里红绿就是涨跌信号把红K线变成绿K线等于把看涨样本变成看跌样本。mosaic马赛克拼接把四张图拼在一起K线的时间连续性彻底断裂模型会用碎片化的价格序列做判断增加过拟合风险。所以我训练股票类数据时会显式把这些增强关掉只保留轻微缩放yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ fliplr0.0 \ flipud0.0 \ degrees0.0 \ hsv_h0.0 \ hsv_s0.0 \ hsv_v0.0 \ scale0.1 \ mosaic0.0 \ seed0scale0.1允许图片做10%以内的缩放用来提高模型对图表缩放比例的鲁棒性。其他增强参数全部归零宁可少一点增强也不能让模型学错方向。4.3 232张图选什么模型优先YOLOv8n或YOLOv8s模型越大不代表效果越好尤其在只有232张图的数据集上。模型容量越大过拟合风险越高。各版本对比如下模型版本参数量量级232张图上的训练成本我的建议YOLOv8n约3M几分钟级别低显存友好首选YOLOv8s约11M速度稍慢精度可能略高可以对比YOLOv8m约25M以上显存和耗时明显上涨不建议YOLOv8x约60M以上极容易过拟合不要用这是模型复杂度的参数量级参考不同发布版本可能有差异。在232张图、两个类别的小任务上YOLOv8n是性价比最高的起点。先把n跑通拿到基准mAP再决定要不要用更大的模型去试而不是一上来就开大模型追求精度的玄学。5. 避坑指南232张股票数据集训练YOLO时最常见的5个问题这里记下我自己在这个数据集上反复踩过的坑每条按现象、原因、解决的顺序展开遇到类似情况可以直接对照排查。5.1 现象训练loss降到0.02验证mAP却只有0.5左右原因最典型的是数据切分泄了未来信息。如果原始图像是按K线窗口连续截取的随机打乱后相邻窗口可能训练验证各占一部分模型在训练时“见过”验证集同一段行情的延续部分验证分数虚高但loss极低而mAP不涨则是另一种情况说明模型记住了图表的背景布局而不是K线形态。解决先确认文件名是否有时间编号。如果文件名是000001.jpg、000002.jpg这类顺序号按连续块切分例如前160张作训练、后72张作验证不随机打乱。如果怀疑模型学到背景回到第2.5节把预测框画回原图看边界框落在K线区域还是落在空白区域。5.2 现象熊市类别召回率接近0预测结果几乎全是牛市原因类别不均衡。232张图里如果牛市180张、熊市52张模型对熊市的先验概率很低加上默认置信阈值是0.25低置信度的熊市预测会被直接过滤掉。解决先降低置信阈值看召回能否恢复yolo detect val \ modelstock_runs/exp1/weights/best.pt \ datadata.yaml \ conf0.1conf0.1让模型把更多低置信度的框保留下来如果熊市召回明显上升说明模型并不是完全学不会只是置信度偏低。再从训练集里对熊市类样本做重复采样或给熊市类别更高的损失权重都能缓解不均衡。5.3 现象同样的命令训练两次mAP相差十个百分点原因232张图的训练集太小模型初始化、数据增强的随机性、GPU浮点累加差异都会被放大。即使设置了seed0在多进程训练时仍可能出现微小的不一致。解决用同一个best.pt做多次验证不要多次训练后挑最高的结果当算法真实水平。我一般会在同一份数据上跑5个不同seed取mAP的中位数作为最终基准。取最大值是自欺欺人取中位数才能判断方案是否稳定。5.4 现象模型把整张图框成牛市实际K线早就走熊原因如果标签里的边界框覆盖整张K线图包括坐标轴、股票软件logo、空白区域模型很容易学到“这张图的整体配色更像牛市”这类表面特征而不是K线本身的形态变化。解决把标注范围裁到K线主体区域去掉坐标轴和图例。如果压缩包本身提供的就是整图级框最简单的做法是裁剪图片后再重新生成标签或者干脆把任务从检测改成分类见第6章的YOLOv8-cls方案。对股票趋势识别来说分类建模往往比检测建模更贴近问题本质。5.5 现象训练中途报FileNotFoundError或AssertionError: label not found原因数据集目录是中文名某些YOLO版本在Windows或旧版Linux下对中文路径处理不友好也可能图片是.png而标签脚本找的是.jpg大小写不一致导致匹配失败。解决把数据目录改成纯英文路径比如/data/stock_data/用第2.3节的脚本重新核对一次标签完整度。另一个常见问题是解压时部分文件损坏重新解压并覆盖全部文件即可。处理完再执行一次训练基本能消除这类环境性报错。6. 验证与进阶用滑窗预测跑通真实K线再决定要不要用分类模式训练结束后best.pt的mAP只是一个数字真正要看的是在连续K线上能不能给出合理判断。先用自带的验证命令导出关键图表yolo detect val \ modelstock_runs/exp1/weights/best.pt \ datadata.yaml \ imgsz640验证完成后到输出目录里打开confusion_matrix.png和PR_curve.png。混淆矩阵里各列之和不需要完全一致毕竟熊市和牛市样本数不同重点看熊市那一行的召回是否过低。PR曲线则能帮你判断置信阈值应该设在多少而不是默认的0.25。对一整根长K线图做预测建议用滑窗方式切成YOLO能接受的尺寸避免直接resize把K线压扁。import cv2 from ultralytics import YOLO model YOLO(stock_runs/exp1/weights/best.pt) img cv2.imread(long_chart.png) win_w 640 step 320 results [] for x in range(0, img.shape[1] - win_w, step): crop img[:, x:x win_w] res model.predict(crop, conf0.25, imgsz640) if len(res[0].boxes) 0: cls_id int(res[0].boxes.cls[0].item()) results.append((x, bull if cls_id 1 else bear)) print(results)step320让相邻窗口有50%重叠避免某个趋势被窗口边界切断。相邻窗口如果出现不同类别以置信度更高的一次为准。这个滑窗结果已经可以作为最原始的看多/看空信号来源但要注意它只适合作为技术分析辅助不能直接当交易决策。如果你发现数据集里的边界框本来就是整图框没有具体检测目标那我更建议换成YOLOv8-cls分类模式。只需要把图片按类别放进目录stock_data/classify/train/bear/*.jpg stock_data/classify/train/bull/*.jpg stock_data/classify/val/bear/*.jpg stock_data/classify/val/bull/*.jpg然后执行yolo classify train \ modelyolov8n-cls.pt \ datastock_data/classify \ epochs50 \ imgsz224 \ batch16分类模式不依赖边界框完全按整图语义做判断对熊市/牛市这种整体趋势问题往往更稳。232张图做二分类几十个epoch就能看到明确结果。我现在的习惯是拿到任何股票类YOLO数据集先问自己一句这到底是一个检测问题还是一个分类问题想清楚这个问题比换什么预训练模型、调什么学习率都重要。花十分钟确认标签结构和问题边界能省下后面一整天的调参时间。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →