首页 / 资讯中心 / 文章详情

基于深度学习的海上渔民捕鱼方式检测:围网、刺网、拖网分类实战

基于深度学习的海上渔民捕鱼方式检测:围网、刺网、拖网分类实战 ★ FEATURED ARTICLE
简介这份资源面向深度学习与计算机视觉方向的初学者及中级实践者围绕海上渔民捕鱼方式识别这一图像分类任务提供围网、刺网和拖网三类作业方式的检测方案可用于渔业管理、生态保护研究及课程项目实践。压缩包共14个文件约30KB以10个Python脚本为核心覆盖特征提取、模型训练、指标评估与推理分析等环节另含3个Markdown说明文档和1个Shell运行脚本便于快速理解项目结构与执行流程。资源内含配套数据集及算法实现读者可据此完成数据预处理、模型构建、训练调优与验证测试的完整链路并借助评估指标分析模型表现。目前已有264人学习下载适合希望将深度学习应用于环保与资源管理场景、积累图像分类实战经验的读者参考。1. 海上渔民捕鱼方式检测围网、刺网、拖网到底难在哪渔船在海上作业时监管方最头疼的不是“有没有船”而是“这条船在用什么网”。围网、刺网、拖网三种作业方式在雷达轨迹和可见光图像上表现完全不同围网船喜欢绕圈下网轨迹像一团乱麻刺网船基本是定点布网后漂着航速极低拖网船则是长时间匀速直线拖曳航迹拉得又长又直。问题在于靠人盯着AIS轨迹和监控画面去分辨一条船看半小时都未必敢下结论更别说同时盯几百条船。基于深度学习的海上渔民捕鱼方式检测本质是把“渔船行为识别”拆成一个三分类任务输入一段渔船作业的时序数据或图像序列输出它属于围网、刺网还是拖网。这件事能解决两个现实痛点一是渔政监管的自动化筛查二是渔船作业数据的结构化归档。适合谁做有基本Python和深度学习基础、手头能拿到AIS轨迹或渔船监控图像、想找一个有真实业务背景的检测项目练手或落地的人。数据集和算法实现是这类项目的两条腿缺一条都跑不起来。2. 数据集怎么选怎么造从AIS轨迹到图像样本的落地路径2.1 三种捕鱼方式的信号差异与数据形态选择围网、刺网、拖网在数据上的可分性决定了你该采什么数据。围网作业时渔船会围绕鱼群下网AIS轨迹呈现闭合或半闭合的环形航向变化率极高航速在2到5节之间波动。刺网船到达渔场后布网船基本静止或极慢速漂移航速长期低于1节轨迹点密集堆叠在一个小范围内。拖网船则是典型的匀速直线运动航速稳定在3到5节航向变化极小轨迹是一条长直线。这三种模式在AIS时序数据上区分度最高因为航速、航向变化率、轨迹曲率这些特征直接对应作业方式。图像数据也有用但受天气和光照影响大单独用图像做三分类围网和刺网在视觉上容易混。常见做法是AIS时序为主、图像为辅或者只用AIS做轨迹分类。如果你手头只有图像那就得靠船体外形和甲板设备差异来分难度上一个台阶。数据形态上AIS数据通常是CSV或数据库表每条记录包含MMSI、时间戳、经纬度、航速、航向。图像数据则是按渔船ID和时间段组织的文件夹。选哪种取决于你能拿到什么。渔政公开的AIS数据、科研机构共享的渔船监控数据集都是常见来源。2.2 从原始AIS到模型输入轨迹切片与特征工程拿到原始AIS数据后不能直接丢给模型。原始数据是连续的时间序列长度不一还夹杂着停泊、进出港等非作业段。第一步是切分出“作业段”。我一般用航速阈值加滑动窗口航速持续低于0.5节超过30分钟标记为疑似停泊航速在1到6节之间且持续2小时以上标记为疑似作业段。然后按固定时间窗口比如每30分钟一个样本切片每个样本包含该窗口内的轨迹点序列。import pandas as pd import numpy as np def extract_features(df, window_minutes30): df: 单条渔船的AIS记录含 timestamp, lat, lon, speed, course 返回按窗口切分后的特征列表 df df.sort_values(timestamp).reset_index(dropTrue) df[timestamp] pd.to_datetime(df[timestamp]) # 计算相邻点时间差和距离 df[dt] df[timestamp].diff().dt.total_seconds() df[dlat] df[lat].diff() df[dlon] df[lon].diff() # 航向变化率 df[course_diff] df[course].diff().abs() df[course_diff] df[course_diff].apply(lambda x: min(x, 360 - x) if pd.notna(x) else 0) # 按时间窗口切片 df[window_id] df[timestamp].dt.floor(f{window_minutes}min) features [] for wid, group in df.groupby(window_id): if len(group) 5: # 点太少跳过 continue feat { window_id: wid, speed_mean: group[speed].mean(), speed_std: group[speed].std(), course_diff_mean: group[course_diff].mean(), course_diff_std: group[course_diff].std(), lat_range: group[lat].max() - group[lat].min(), lon_range: group[lon].max() - group[lon].min(), point_count: len(group), dt_mean: group[dt].mean() } features.append(feat) return pd.DataFrame(features)这段代码做了三件事按时间排序、计算航向变化率、按30分钟窗口聚合统计量。window_minutes控制样本粒度太小则样本多但噪声大太大则样本少但特征稳。我一般从30分钟起步根据数据密度调整。course_diff处理了航向的360度环绕问题取最小夹角。point_count和dt_mean反映数据质量点太少或间隔太大的窗口直接丢弃。特征工程之后每个样本变成一个固定长度的向量。如果你用LSTM或Transformer也可以不聚合直接把窗口内的轨迹点序列作为输入让模型自己学时序模式。两种路线都行聚合特征适合快速验证序列输入适合追求更高精度。2.3 图像样本的采集与标注围网、刺网、拖网的视觉线索如果你走图像路线采集时要注意围网船在作业时甲板上有明显的起网机动作船尾可能有网具堆积刺网船船体较小甲板空旷作业时船速极低拖网船船尾有拖曳网具的缆绳船体较大。标注时每张图打一个类别标签围网、刺网、拖网三选一。标注工具用LabelImg或CVAT都行导出成YOLO格式或文件夹分类格式。图像数据最大的坑是类别不平衡。围网船数量通常少于拖网船直接训练会导致模型偏向多数类。常见做法是过采样少数类或加类别权重。另外图像里渔船可能只占几十个像素裁剪出船体区域再送模型比整图输入效果好得多。3. 算法实现从CNN基线到时序模型的选型与训练3.1 基线模型选型CNN做图像、LSTM做轨迹图像分类的基线用ResNet18或MobileNetV3就够了。渔船图像分类不是细粒度识别三种作业方式的视觉差异虽然不大但ResNet18在几千张图上微调就能到80%以上的准确率。别一上来就上ViT数据量不够时ViT容易过拟合。时序轨迹分类的基线用1D-CNN或LSTM。1D-CNN在固定长度特征向量上速度快LSTM在变长序列上更灵活。我一般先跑一个1D-CNN基线输入是前面提取的8维特征向量三层卷积加全局池化最后接全连接分类。如果准确率能到85%以上说明特征工程到位了如果只有60%多要么特征不够要么数据标签有问题。import torch import torch.nn as nn class TrajectoryCNN(nn.Module): def __init__(self, input_dim8, num_classes3): super().__init__() self.conv1 nn.Conv1d(1, 32, kernel_size3, padding1) self.conv2 nn.Conv1d(32, 64, kernel_size3, padding1) self.conv3 nn.Conv1d(64, 128, kernel_size3, padding1) self.pool nn.AdaptiveAvgPool1d(1) self.fc nn.Linear(128, num_classes) self.relu nn.ReLU() self.dropout nn.Dropout(0.3) def forward(self, x): # x: (batch, input_dim) - (batch, 1, input_dim) x x.unsqueeze(1) x self.relu(self.conv1(x)) x self.relu(self.conv2(x)) x self.relu(self.conv3(x)) x self.pool(x).squeeze(-1) x self.dropout(x) return self.fc(x)这个模型把8维特征当成一个长度为8的序列用1D卷积提取局部模式。input_dim对应特征数num_classes是3。卷积核大小3意味着每次看相邻3个特征的关系。AdaptiveAvgPool1d(1)把任意长度压成1所以输入特征数变了也不用改结构。dropout防过拟合数据少时调到0.5。训练时用交叉熵损失Adam优化器学习率1e-3batch size 32。如果类别不平衡在损失函数里加weight参数按类别频率的倒数设置。3.2 用YOLOv8做渔船目标检测再分类的两阶段方案如果你只有监控图像没有AIS那就走两阶段先用YOLOv8检测出渔船位置再裁剪船体区域送分类模型。YOLOv8训练自己的数据集流程是准备YOLO格式的标注文件每张图一个txt含类别和边界框写data.yaml指定训练集和验证集路径然后跑训练命令。yolo detect train dataship_data.yaml modelyolov8n.pt epochs100 imgsz640 batch16data指向数据集配置文件model用预训练权重epochs和batch根据显存调。训练完后用yolo detect predict跑推理把检测到的船体裁剪出来送进前面的分类模型。两阶段的好处是检测和分类解耦检测模型只管找船分类模型只管分作业方式各自可以独立优化。坏处是推理速度慢一倍实时性要求高时得权衡。3.3 训练参数怎么调学习率、窗口大小、类别权重学习率是第一个要调的。1e-3是起点如果loss震荡就降到1e-4如果loss下降太慢就升到3e-3。窗口大小影响样本数量和特征质量30分钟是经验值数据密集时可以缩到15分钟数据稀疏时拉到60分钟。类别权重按总样本数 / (类别数 * 该类样本数)算围网样本少就给它高权重。验证集要按渔船ID划分不能随机划分。同一艘船的不同时间段样本如果同时出现在训练集和验证集验证准确率会虚高。我一般按7:2:1划分训练、验证、测试且确保同一艘船只出现在一个集合里。训练过程中看验证集的F1分数比准确率更可靠因为类别不平衡时准确率会骗人。4. 避坑与排查数据泄漏、标签噪声、过拟合的典型翻车现场4.1 验证集准确率95%但上线就崩数据泄漏的排查现象训练时验证集准确率95%换一批新数据测试掉到60%。原因同一艘船的轨迹切片被随机分到了训练集和验证集模型记住了这艘船的特征而不是作业方式的特征。解决按MMSI划分数据集同一艘船的所有样本只进一个集合。排查方法很简单看验证集里的MMSI有没有在训练集里出现过有就是泄漏。4.2 围网样本被大量误判为刺网类别不平衡与特征混淆现象围网召回率只有50%大部分被分成刺网。原因围网样本少模型偏向多数类且围网低速绕圈时航速和刺网漂移有重叠。解决加类别权重同时补一个特征——轨迹曲率。围网绕圈时曲率明显高于刺网加进去后区分度提升。另外围网作业时长通常短于刺网窗口内点数也可以作为辅助特征。4.3 训练loss不降反升学习率与batch size的匹配问题现象训练loss在前几个epoch就飙到nan。原因学习率太大或者batch size太小导致梯度噪声大。解决学习率降到1e-4batch size加到64。如果显存不够用梯度累积模拟大batch。另外检查输入特征有没有归一化航速和经纬度范围差几个数量级不归一化容易梯度爆炸。4.4 图像模型把天气当特征过拟合到背景的识别现象晴天图片准确率90%阴天掉到50%。原因模型学到了天气相关的背景特征而不是渔船作业特征。解决数据增强加随机亮度、对比度、天气模拟或者裁剪船体区域再分类减少背景干扰。如果条件允许采集不同天气的样本做平衡。4.5 AIS数据缺失导致轨迹断裂窗口切分的边界处理现象某些渔船AIS上报间隔超过10分钟30分钟窗口里只有两三个点特征统计不可靠。原因AIS信号在远海不稳定数据有缺失。解决窗口内点数少于5个的直接丢弃或者用插值补点但插值会引入噪声我一般选择丢弃。如果某艘船大量窗口被丢弃说明这条船的数据质量差整体排除。5. 进阶技巧用轨迹曲率和航向熵把围网和刺网彻底分开围网和刺网的混淆是这类项目最常见的精度瓶颈。我试过加特征、换模型、调权重最后真正把两者分开的是两个手工特征轨迹曲率和航向熵。轨迹曲率的算法是对窗口内的轨迹点每隔几个点取三个连续点计算它们构成的外接圆半径半径的倒数就是曲率。围网绕圈时曲率大刺网漂移时曲率接近零。实现时用numpy的向量化操作避免逐点循环。def compute_curvature(lats, lons): 计算轨迹的平均曲率输入为等间隔采样的经纬度序列 if len(lats) 3: return 0.0 curvatures [] for i in range(1, len(lats) - 1): # 用相邻三点计算曲率 x1, y1 lons[i-1], lats[i-1] x2, y2 lons[i], lats[i] x3, y3 lons[i1], lats[i1] # 三角形面积的两倍 area abs((x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1)) # 三边长度 a np.sqrt((x2 - x1)**2 (y2 - y1)**2) b np.sqrt((x3 - x2)**2 (y3 - y2)**2) c np.sqrt((x3 - x1)**2 (y3 - y1)**2) if a * b * c 0: continue # 曲率 4 * 面积 / (a * b * c) curvatures.append(4 * area / (a * b * c)) return np.mean(curvatures) if curvatures else 0.0航向熵的计算更简单把窗口内的航向值分成36个区间每10度一个统计每个区间的频率算香农熵。围网航向变化大熵值高刺网航向基本不变熵值低拖网航向稳定但有小幅波动熵值居中。把这两个特征加进原来的8维向量变成10维重新训练1D-CNN。我的经验是围网和刺网的混淆率能从30%降到10%以内。代价是特征计算多了一点开销但相比换更复杂的模型这个投入产出比高得多。验证方法上除了看整体准确率一定要看混淆矩阵。围网和刺网的交叉项如果还是很高就继续加特征或检查标签。我一般会抽一批误判样本人工看十有八九是标签打错了或者那段轨迹确实处于两种作业方式的过渡期。最后说个习惯每次改完特征或模型固定跑一遍测试集记录F1和混淆矩阵别只看loss。loss降了但F1没动说明模型在拟合噪声。这个项目的数据集和算法实现核心不在模型多深而在特征有没有抓住三种作业方式的物理差异。抓住这一点剩下的就是调参和清洗数据的体力活。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站