深度学习————海洋生物识别

编程入门 行业动态 更新时间:2024-10-25 02:20:25

深度学习————<a href=https://www.elefans.com/category/jswz/34/1722752.html style=海洋生物识别"/>

深度学习————海洋生物识别

前言:

海洋中的鱼类资源不仅有一定的食用价值,而且有很高的药用价值,近年来,世界各国对于海洋鱼类资源的重视程度与日俱增。在鱼类资源的开发利用中,必须对鱼类进行识别,从而了解其分布情况。但是由于鱼的种类繁多,形状大小相似,同时考虑到海底拍摄环境亮度低、场景模糊的实际情况,对鱼类资源的识别较为困难。

针对海洋鱼类识别难的问题,本实践使用卷积神经网络(Convolutional Neural Network,CNN)构建深度学习模型,自动提取高质量的特征,从而解决海洋鱼类识别的问题。接下来,我将分享如何使用百度深度学习框架飞桨来搭建卷积神经网络,实现海洋鱼类资源的识别。

01. 卷积神经网络

卷积神经网络主要由卷积层、池化层和全联接层三种网络层构成,在卷积层与全联接层后通常会接激活函数。

卷积层

卷积层会对输入的特征图(或原始数据)进行卷积操作,输出卷积后产生的特征图。卷积层是卷积神经网络的核心部分。输入到卷积层的特征图是一个三维数据,不仅有宽、高两个维度,还有通道维度上的数据,因此输入特征图和卷积核可用三维特征图表示。如下图所示,对于一个(3,6,6)的输入特征图,卷积核大小为(3,3,3),输出大小为(1,4,4),当卷积核窗口滑过输入时,卷积核与窗口内的输入元素作乘加运算,并将结果保存到输出相应的位置。

上图中卷积操作输出了一张特征图,即通道数为1的特征图,而一张特征图包含的特征数太少,在大多数计算机视觉任务中是不够的,所以需要构造多张特征图,而输入特征图的通道数又与卷积核通道数相等,一个卷积核只能产生一张特征图,因此需要构造多个卷积核。在RGB彩色图像上使用多个卷积核进行多个不同特征的提取,示意图如下:

池化层

池化层的作用是对网络中的特征进行选择,降低特征数量,从而减少参数数量和计算开销。池化层降低了特征维的宽度和高度,也能起到防止过拟合的作用。最常见的池化操作为最大池化或平均池化。如下图所示,采用了最大池化操作,对邻域内特征点取最大值作为最后的特征值。

最常见的池化层使用大小为2×2,步长为2的滑窗操作,有时窗口尺寸为3,更大的窗口尺寸比较罕见,因为过大的滑窗会急剧减少特征的数量,造成过多的信息损失。

批归一化层

批归一化层是由Google的DeepMind团队提出的在深度网络各层之间进行数据批量归一化的算法,以解决深度神经网络内部协方差偏移问题,使用网络训练过程中各层梯度的变化趋于稳定,并使网络在训练时能更快地收敛。

02. 基于飞桨的海洋鱼类识别

飞桨是以百度多年的深度学习技术研究和业务应用为基础,集深度学习核心框架、基础模型库、端到端开发套件、工具组件和服务平台于一体,2016 年正式开源,是全面开源开放、技术领先、功能完备的产业级深度学习平台。

下面我将为大家展示如何用 PaddlePaddle API 编程并搭建一个简单的卷积神经网络,解决海洋鱼类识别问题。主要分为五个步骤,数据准备、模型配置、模型训练、模型评估以及最后使用训练好的模型进行预测。

本实践代码运行的环境配置如下:Python版本3.7,飞桨版本为1.6.2,操作系统为Windows64位操作系统。

步骤1:数据准备

本次实践所使用的是台湾电力公司、台湾海洋研究所和垦丁国家公园在2010年10月1日至2013年9月30日期间,在台湾南湾海峡、兰屿岛和胡比湖的水下观景台收集的鱼类图像数据集。

该数据集包括23类鱼种,共27370张鱼的图像。

本实践选取5种鱼类数据作为数据集进行训练,被划分为两个子集,训练集和测试集比例为9:1

1 #导入必要的包
import zipfile
import os
import random
import paddle
import matplotlib.pyplot as plt
from paddle.fluid.dygraph import Pool2D,Conv2D,BatchNorm
from paddle.fluid.dygraph import Linear
import sys
import numpy as np
from PIL import Image
from PIL import ImageEnhance
import paddle.fluid as fluid
from multiprocessing import cpu_count
import matplotlib.pyplot as plt
import json #解压原始数据集,将fish_image.zip解压至data目录下
src_path="/home/aistudio/data/data14492/fish_image23.zip"
target_path="/home/aistudio/data/fish_image"
if(not os.path.isdir(target_path)):z = zipfile.ZipFile(src_path, 'r')z.extractall(path=target_path)z.close()
#存放所有类别的信息
class_detail = []
#获取所有类别保存的文件夹名称
class_dirs = os.listdir(target_path+"/fish_image")data_list_path="/home/aistudio/data/"TRAIN_LIST_PATH=data_list_path + "train.txt"
EVAL_LIST_PATH=data_list_path + "eval.txt"#每次执行代码,首先清空train.txt和eval.txt
with open(TRAIN_LIST_PATH, 'w') as f: pass
with open(EVAL_LIST_PATH, 'w') as f: pass

首先创建了一个空的class_detail列表和一个class_dirs列表,用于存储所有类别的信息和文件夹名称。接下来,你定义了'TRAIN_LIST_PATH和'EVALEVAL_LIST_PATH两个文件路径,这些文件用于存储训练集和测试集的图像文件路径信息。

然后,使用with open语句清空'train.txttrain.txt和'eval.txteval.txt文件,以确保每次执行代码时这两个文件都是空的,这是为了准备存储新的训练和测试数据的文件。

#总的图像数量
all_class_images = 0
#存放类别标签
class_label=0
# 设置要生成文件的路径
data_root_path="/home/aistudio/data/fish_image/fish_image"
#存储要写进test.txt和train.txt中的内容
trainer_list=[]
eval_list=[]
#读取每个类别,['fish_01', 'fish_02', 'fish_03']
for class_dir in class_dirs:   #每个类别的信息class_detail_list = {}eval_sum = 0trainer_sum = 0#统计每个类别有多少张图片class_sum = 0#获取类别路径 path = data_root_path + "/" + class_dir# 获取所有图片img_paths = os.listdir(path)for img_path in img_paths:                                  # 遍历文件夹下的每个图片name_path = path + '/' + img_path                       # 每张图片的路径if class_sum % 10 == 0:                                 # 每10张图片取一个做验证数据eval_sum += 1                                       # test_sum为测试数据的数目eval_list.append(name_path + "\t%d" % class_label + "\n")else:trainer_sum += 1 trainer_list.append(name_path + "\t%d" % class_label + "\n")#trainer_sum测试数据的数目class_sum += 1                                          #每类图片的数目all_class_images += 1                                   #所有类图片的数目class_label += 1  # 说明的json文件的class_detail数据class_detail_list['class_name'] = class_dir             #类别名称,如jiangwenclass_detail_list['class_label'] = class_label          #类别标签class_detail_list['class_eval_images'] = eval_sum       #该类数据的测试集数目class_detail_list['class_trainer_images'] = trainer_sum #该类数据的训练集数目class_detail.append(class_detail_list)         random.shuffle(eval_list)
with open(data_list_path + "eval.txt", 'a') as f:for eval_image in eval_list:f.write(eval_image) random.shuffle(trainer_list)
with open(data_list_path + "train.txt", 'a') as f2:for train_image in trainer_list:f2.write(train_image) # 说明的json文件信息
readjson = {}
readjson['all_class_name'] = data_root_path                  #文件父目录
readjson['all_class_sum'] = class_sum 
readjson['all_class_images'] = all_class_images
readjson['class_detail'] = class_detail
jsons = json.dumps(readjson, sort_keys=True, indent=4, separators=(',', ': '))
with open(data_list_path + "readme.json",'w') as f:f.write(jsons)
print ('生成数据列表完成!')

这部分代码的主要功能是循环遍历每个类别的图像数据,并根据每张图像的类别,将其文件路径和类别标签写入eval.txttrain.txt文件中,以创建训练集和测试集的数据列表。最终,还会生成一个readme.json文件,包含所有类别的信息和数据集的统计信息。

这样,就成功创建了训练集和测试集的数据列表,并为后续的模型训练和评估做好了准备。

步骤2:模型配置

数据准备的工作完成之后,接下来我们将动手来搭建一个CNN网络,进行图片特征的提取,从而实现海洋鱼类的识别。

(1)模型定义

#定义CNN网络
class MyCNN(fluid.dygraph.Layer):def __init__(self):super(MyCNN,self).__init__()self.conv1 = Conv2D(num_channels=3, num_filters=20, filter_size=5, padding=0, act='relu')self.pool1 = Pool2D(pool_size=2, pool_stride=2, pool_type='max')self._batch_norm_1 = BatchNorm(num_channels=20, act=None)self.conv2 = Conv2D(num_channels=20, num_filters=50, filter_size=5, padding=0, act='relu')self.pool2 = Pool2D(pool_size=2, pool_stride=2, pool_type='max')self._batch_norm_2 = BatchNorm(num_channels=50, act=None)self.conv3 = Conv2D(num_channels=50, num_filters=50, filter_size=5, padding=0, act='relu')self.pool3 = Pool2D(pool_size=2, pool_stride=2, pool_type='max')self.fc1 = Linear(input_dim=200, output_dim=23, act="softmax")def forward(self, input):x = self.conv1(input)x = self.pool1(x)x = self._batch_norm_1(x)x = self.conv2(x)x = self.pool2(x)x = self._batch_norm_2(x)x = self.conv3(x)x = self.pool3(x)x = fluid.layers.reshape(x, [x.shape[0], -1])y = self.fc1(x)return y

在这段代码中,定义了一个名为 'MyCNN_batch_norm_1,_batch_norm_2)。最后,通过全连接层 ('fc1) 输出23个类别的分类结果。

  • Conv2D层定义了卷积层,num_channels指定输入通道数(这里是3,表示彩色图像),num_filters是输出通道数,filter_size是卷积核大小,padding是填充大小, 是激活函数。act
  • BatchNorm层用于批量归一化,有两个批量归一化层 '_batch_norm_1_batch_norm_1和 。_batch_norm_2
  • Linear层定义了全连接层,input_dim是输入维度, 是输出维output_dimact是激活函数。

在 方法中,定义了模型的前向传播逻辑,即数据从输入经过各个层传播,最终输出分类结果。forward

这个 CNN 模型用于图像分类,其中输入图像的大小为 47x47 像素,有3个通道(RGB图像)。模型中的卷积和池化层有助于提取图像特征,最后的全连接层将这些特征映射到23个类别的概率分布。

(2)损失函数

在深度学习中,损失函数用于度量模型的预测输出与实际标签之间的差异。在海洋鱼类识别任务中,可以使用交叉熵损失作为损失函数,它在分类问题中非常常见。

定义交叉熵损失函数

loss = fluid.layers.cross_entropy(predict, label)
avg_loss = fluid.layers.mean(loss)

(3)优化方法

opt = fluid.optimizer.Adam(learning_rate=fluid.dygraph.ExponentialDecay(learning_rate=0.002,decay_steps=3000,decay_rate=0.1,staircase=True),parameter_list=model.parameters()
)

这里我们使用了Adam优化器来进行模型的优化,这段代码创建了一个Adam优化器,其中学习率采用指数衰减的方式进行调整。学习率初始值为0.002,每隔3000个步骤进行衰减,衰减率为0.1,staircase参数设置为True表示采用分段衰减。模型的参数由model.parameters()返回。

这个优化方法会在训练过程中自动调整学习率,有助于提高模型的训练效果。

步骤3:模型训练

with fluid.dygraph.guard():model=MyCNN() #模型实例化model.train() #训练模式opt=fluid.optimizer.Adam(learning_rate=fluid.dygraph.ExponentialDecay(learning_rate=0.002,decay_steps=3000,decay_rate=0.1,staircase=True), parameter_list=model.parameters())epochs_num=35 #迭代次数for pass_num in range(epochs_num):lr = opt.current_step_lr()print("learning-rate:", lr)for batch_id,data in enumerate(train_reader()):images=np.array([x[0].reshape(3,47,47) for x in data],np.float32)labels = np.array([x[1] for x in data]).astype('int64')labels = labels[:, np.newaxis]image=fluid.dygraph.to_variable(images)label=fluid.dygraph.to_variable(labels)predict=model(image)loss=fluid.layers.cross_entropy(predict,label)avg_loss=fluid.layers.mean(loss)acc=fluid.layers.accuracy(predict,label)avg_loss.backward()opt.minimize(avg_loss)model.clear_gradients()if batch_id!=0 and batch_id%50==0:print("train_pass:{},batch_id:{},train_loss:{},train_acc:{}".format(pass_num,batch_id,avg_loss.numpy(),acc.numpy()))with fluid.dygraph.guard():accs = []model.eval() #评估模式for batch_id, data in enumerate(eval_reader):images = np.array([x[0].reshape(3, 47, 47) for x in data], np.float32)labels = np.array([x[1] for x in data]).astype('int64')labels = labels[:, np.newaxis]image = fluid.dygraph.to_variable(images)label = fluid.dygraph.to_variable(labels)predict = model(image)acc = fluid.layers.accuracy(predict, label)accs.append(acc.numpy()[0])avg_acc = np.mean(accs)if avg_acc >= best_test_acc:best_test_acc = avg_accif pass_num > 10:fluid.save_dygraph(model.state_dict(), model_save_dir)print('Test:%d, Accuracy:%0.5f, Best: %0.5f' % (pass_num, avg_acc, best_test_acc))

这段代码使用了飞桨的动态图模式进行训练。首先,创建一个CNN模型实例,并切换到训练模式。然后,配置Adam优化器,学习率采用指数衰减。接下来,执行了多个训练迭代,每个迭代中加载训练数据,计算损失函数,执行反向传播,更新模型参数,并记录训练损失和准确率。

在每个训练迭代的结束,切换到评估模式,用测试数据计算模型的准确率,并更新最佳测试准确率。如果测试准确率提高,保存模型参数。这个循环将在指定的训练迭代次数内运行,完成模型的训练。

步骤4:模型评估

通过观察训练过程中误差和准确率随着迭代次数的变化趋势,可以对网络训练结果进行评估。

通过上图可以观察到,在训练和验证过程中平均误差是在逐步降低的,与此同时,训练与验证的准确率逐步趋近于100%。

步骤5:模型预测

接下来使用训练好的模型对经过预处理的图片进行预测。首先从指定目录中加载训练好的模型,然后喂入要预测的图片向量,返回模型的输出结果,即为预测概率,这些概率的总和为1。

with fluid.dygraph.guard():model = MyCNN() # 创建一个CNN模型实例model_dict, _ = fluid.load_dygraph(model_save_dir) # 加载训练好的模型参数model.load_dict(model_dict) # 加载模型参数infer_img = load_image(infer_path) # 加载并预处理要预测的图片infer_img = np.array(infer_img).astype('float32')infer_img = fluid.dygraph.to_variable(infer_img)results = model(infer_img) # 使用模型进行预测label_list = ["fish_21", "fish_19", "fish_15", "fish_20", "fish_1", "fish_5", "fish13", "fish2", "fish4", "fish_14", "fish_16", "fish_6", "fish_18", "fish_17","fish_22", "fish_8", "fish_3", "fish_23", "fish_9", "fish_7", "fish_12", "fish_11", "fish_10"]print("infer results: %s" % label_list[np.argmax(results[0])]) # 打印预测结果

此外,我们研究方向的经典算法有以下三种,其中各有优缺点:

以下是其中一些经典算法,以及它们的优缺点、适用情况和特殊限制条件:

1. 支持向量机 (Support Vector Machine, SVM):

- 优点: - SVM 在处理线性和非线性分类问题时表现出色,尤其在高维空间中非常强大。 - 它通过最大化分类边界的间隔来提高模型的泛化能力。

- 在小样本数据集上表现良好,对于数据的分布没有特别的假设。

- 缺点: - SVM 对大规模数据集和高维度数据的计算复杂度较高,训练时间可能较长。 - 对于噪声数据敏感,需要仔细调整超参数。

- 不直接提供概率估计,需要额外处理来获取类别概率。

2. 决策树(Decision Tree):

- 优点: - 决策树易于理解和可视化,具有直观性。

- 可以处理混合数据类型,包括分类和回归问题。

- 在特征选择和数据预处理方面具有灵活性。

- 缺点:

- 决策树容易过拟合,可能会创建过于复杂的树,需要剪枝来提高泛化性能。

- 对数据中的小变化敏感,容易受到噪声的影响。

- 不擅长处理异或问题(非线性问题)。

3. 深度神经网络 (Deep Neural Networks, DNN):

- 优点: - DNN 可以学习和表示高度复杂的非线性关系,适用于大规模数据和高维特征。 - 在图像处理、自然语言处理和语音识别等领域取得了出色的性能。

- 可以通过堆叠多个隐藏层来提高模型的表达能力。

- 缺点: - DNN 需要大量的标记数据来训练,因此对于小数据集的性能有限。

- 训练深度网络需要大量的计算资源,包括高性能 GPU。

- 对于模型的超参数选择和调整非常敏感,需要谨慎处理。

这些经典算法各自具有一些独特的特点和适用范围,选择哪种算法通常依赖于具体的问题和数据特征。对于小样本数据,SVM可能是一个不错的选择;对于具有明显决策路径的问题,决策树非常合适;而对于复杂非线性问题,深度神经网络通常能提供出色的性能。然而,选择算法时需要注意算法的限制和适用条件,以便合理选择并调整算法以获得最佳结果。

至此,已经成功使用飞桨核心框架搭建了一个简单的卷积神经网络并实现了海洋生物的识别。

更多推荐

深度学习————海洋生物识别

本文发布于:2024-02-25 20:02:12,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1700136.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:海洋生物   深度

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!