python基于卷积神经网络实现自定义数据集训练与测试,岩心识别举例。

本文主要是介绍python基于卷积神经网络实现自定义数据集训练与测试,岩心识别举例。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

样本集取自本人在大创项目中用到的360张岩心照片。由于识别岩心是最基本的地质学工作,但这个过程往往是冗杂的,需要耗费大量时间与精力。如果用机器来划分岩心类型则会大大削减工作量!

注意:

       如何更改图像尺寸在这篇文章中,修改完之后你就可以把你自己的数据集应用到网络如果你的训练集与测试集也分别为30和5,并且样本类别也为3类,那么你只需要更改图像标签文件地址以及标签内容(如下面两图所示)。 图片名-标签文件如何生成请看这篇文章。

如果你想扩大数据集量,那么你只需要更改对应的文件内标签长度以及数据集图像量。

cc067da426844f4daba900398c3a7607.png

7b174c638eab4005a6e178bfbe92987e.png

我已经扩大了数据集的数量,展示在正文2。

正文1:

下面叙述中0指代Anhydrite_rock(膏岩),1指代Limestone(灰岩),2指代Gray Anhydrite_rock(灰质膏岩)。

原本自定义训练集与测试集是这样的:

训练集x_train: 

e4f8c95e90e148a4b92f7ce7681261b0.png

标签是这样的y_train:

ceedcdc8c80140949916e2d0443b644f.png

 测试集x_test:

f5a00e255d3144c3ba19528506ce75ed.png

标签是这样的y_test:

d8427b49811c4e6ab2a538713e2dcc00.png

但是由于图片像素为3456*5184,电脑内存不足,所以只能统一修i该为下面(256*256): 

训练集: 

897bcfe9a3c8454880d714b96642f6a8.png

  测试集:

87fc942bb5ea4fa88fef393e867484e9.png

两个数据集的标签没有更改。

#导入库
import os
import cv2
import torch
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from torchvision.io import read_image
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
from torchvision import transforms
import tensorflow.keras as ka
import datetime
import tensorflow as tf
import os
import PySide2
from tensorflow.keras.layers import Conv2D,BatchNormalization,Activation,MaxPooling2D,Dropout,Flatten,Dense
from tensorflow.keras import Model
import tensorflow as tf'''加载数据集'''
#创建自定义数据集类,参考可见:http://t.csdn.cn/gkVNC
class Custom_Dataset(Dataset):#函数,设置图像集路径索引、图像标签文件读取def __init__(self, img_dir, img_label_dir, transform=None):super().__init__()self.img_dir = img_dirself.img_labels = pd.read_csv(img_label_dir)self.transform = transform#函数,设置数据集长度def __len__(self):return len(self.img_labels)#函数,设置指定图像读取、指定图像标签索引def __getitem__(self, index):#'所在文件路径+指定图像名'img_path = os.path.join(self.img_dir + self.img_labels.iloc[index, 1])#读指定图像#image = cv2.imdecode(np.fromfile(img_path,dtype=np.uint8),-1)image=plt.imread(img_path)#height,width = image.shape[0],image.shape[1]  #获取原图像的垂直方向尺寸和水平方向尺寸。#image = image.resize((height//4,width//4))#'指定图像标签'label = self.img_labels.iloc[index, 0]return image, label'''画图函数'''
def tensorToimg(img_tensor):img=img_tensorplt.imshow(img)#python3.X必须加下行plt.show()#标签指示含义
label_dic = {0: '膏岩', 1: '灰岩', 2: '灰质膏岩'}
'''图像集及标签路径'''
label_path = "C:/Users/yeahamen/AppData/Local/Programs/Python/Python310/train_label.csv"
img_root_path = "C:/Users/yeahamen/Desktop/custom_dataset/train_revise/"
test_image_path="C:/Users/yeahamen/Desktop/custom_dataset/test_revise/"
test_label_path="C:/Users/yeahamen/AppData/Local/Programs/Python/Python310/test_label.csv"
#加载图像集与标签路径到函数
#实例化类
dataset = Custom_Dataset(img_root_path, label_path)
dataset_test = Custom_Dataset(test_image_path,test_label_path)'''查看指定图像(18)'''
#索引指定位置的图像及标签
image, label = dataset.__getitem__(18)
#展示图片及其形状(tensor)
print('单张图片(18)形状:',image.shape)
print('单张图片(18)标签:',label_dic[label])#批量输出
dataloader = DataLoader(dataset, batch_size=1, shuffle=True)
'''查看图像的形状'''
for imgs, labels in dataloader:print('一批训练为1张图片(随机)形状:',imgs.shape)#一批图像形状:torch.Size([5, 3456, 5184, 3])print('一批训练为1张图片(随机)标签:',labels)#标签:tensor([3, 2, 3, 3, 1])break#仅需要查看一批'''查看自定义数据集'''
showimages=[]
showlabels=[]
#把图片信息依次加载到列表
for imgs, labels in dataloader:c = torch.squeeze(imgs, 0)#减去一维数据形成图片固定三参数d = torch.squeeze(labels,0)showimages.append(c)showlabels.append(d)
#依次画出图片
def show_image(nrow, ncol, sharex, sharey):fig, axs = plt.subplots(nrow, ncol, sharex=sharex, sharey=sharey, figsize=(10, 10))for i in range(0,nrow):for j in range(0,ncol):axs[i,j].imshow(showimages[i*4+j])axs[i,j].set_title('Label={}'.format(showlabels[i*4+j]))plt.show()plt.tight_layout()
#给定参数
#show_image(2, 4, False, False)'''创建训练集与测试集'''
dataloader_train = DataLoader(dataset, batch_size=30, shuffle=True)
for imgs, labels in dataloader_train:x_train=imgsy_train=labels
print('训练集图像形状:',x_train.shape)
print('训练集标签形状:',y_train.shape)
dataloader_test = DataLoader(dataset_test, batch_size=5, shuffle=True)
for imgs, labels in dataloader_test:x_test=imgsy_test=labels
print('测试集图像形状:',x_test.shape)
print('测试集标签形状:',y_test.shape)'''将图像转变为网络可用的数据类型'''
x_train,x_test = tf.cast(x_train/255.0,tf.float32),tf.cast(x_test/255.0,tf.float32)
y_train,y_test = tf.cast(y_train,tf.int16),tf.cast(y_test,tf.int16)#参考:http://t.csdn.cn/eRQX2
print('注意:',x_train.shape)
'''归一化灰度值'''
x_train = x_train/255
x_test = x_test/255'''标签转为独热编码,注意:如果标签不是从0开始,独热编码会增加1位(即0)'''
y_train = ka.utils.to_categorical(y_train)
y_test = ka.utils.to_categorical(y_test)
print('独热后训练集标签形状:',y_train.shape)
print('独热后测试集标签形状:',y_test.shape)
#获取测试集特征数
num_classes = y_test.shape[1]'''CNN模型'''
#输入3456*5184*3
model = ka.Sequential([ka.layers.Conv2D(filters = 32,kernel_size=(5,5),input_shape=(256,256,3),data_format="channels_last",activation='relu'),#卷积3456*5184*32、卷积层;参量依次为:卷积核个数、卷积核尺寸、单个像素点尺寸、使用ReLu激活函数、解释可见:http://t.csdn.cn/6s3dzka.layers.MaxPooling2D(pool_size=(4,4),strides = None,padding='VALID'),#池化1—864*1296*32、最大池化层,池化核尺寸4*4、步长默认为4、无填充、解释可见:http://t.csdn.cn/sES2uka.layers.MaxPooling2D(pool_size=(2,2),strides = None,padding='VALID'),#池化2—432*648*32再加一个最大池化层,池化核尺寸为2*2、步长默认为2、无填充ka.layers.Dropout(0.2),#模型正则化防止过拟合, 只会在训练时才会起作用,随机设定输入的值x的某一维=0,这个概率为输入的百分之20,即丢掉1/5神经元不激活#在模型预测时,不生效,所有神经元均保留也就是不进行dropout。解释可见:http://t.csdn.cn/RXbmS、http://t.csdn.cn/zAIuJka.layers.Flatten(),#拉平432*648*32=8957952;拉平池化层为一个向量ka.layers.BatchNormalization(),#批标准化层,提高模型准确率ka.layers.Dense(10,activation='relu'),#全连接层1,10个神经元,激活函数为ReLuka.layers.Dense(num_classes,activation='softmax')])#全连接层2,3个神经元(对应标签0-2),激活函数为softmax,作用是把神经网络的输出转化为概率,参考可见:http://t.csdn.cn/bcWgu;http://t.csdn.cn/A1Jyn
'''模型参数展示、编译与训练'''				   
model.summary()
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])
startdate = datetime.datetime.now()
#训练轮数epochs=n,即训练n轮
model.fit(x_train,y_train,validation_data=(x_test,y_test),epochs=100,batch_size=1,verbose=2)
#训练样本、训练标签、指定验证数据为测试集、训练轮数、显示每一轮训练进程,参考可见:http://t.csdn.cn/oE46K
#获取训练结束时间
enndate=datetime.datetime.now()
print("训练用时:"+str(enndate-startdate))

程序运行结果是这样的:

2afb7c8dff904ac7bf40f94cb25725cb.png

 显然由于样本过少,模型训练精度并不高,3轮训练达到0.4;如果有时间再进一步增加样本数量并完善。

正文2

由之前的30个训练集、5个测试集扩大到320个训练集,40个测试集:

训练集:

31cb04c1b8df4fd8baa7e7d86217d045.png

测试集 :

c043a123b1034369bdbcd01a0bd85b40.png

 修改后的代码如下,你可以与上面的代码进行对比,从而修改数据集量为适合你的大小!

#导入库
import os
import cv2
import torch
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from torchvision.io import read_image
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
from torchvision import transforms
import tensorflow.keras as ka
import datetime
import tensorflow as tf
import os
import PySide2
from tensorflow.keras.layers import Conv2D,BatchNormalization,Activation,MaxPooling2D,Dropout,Flatten,Dense
from tensorflow.keras import Model
import tensorflow as tf'''加载数据集'''
#创建自定义数据集类,参考可见:http://t.csdn.cn/gkVNC
class Custom_Dataset(Dataset):#函数,设置图像集路径索引、图像标签文件读取def __init__(self, img_dir, img_label_dir, transform=None):super().__init__()self.img_dir = img_dirself.img_labels = pd.read_csv(img_label_dir)self.transform = transform#函数,设置数据集长度def __len__(self):return len(self.img_labels)#函数,设置指定图像读取、指定图像标签索引def __getitem__(self, index):#'所在文件路径+指定图像名'img_path = os.path.join(self.img_dir + self.img_labels.iloc[index, 1])#读指定图像#image = cv2.imdecode(np.fromfile(img_path,dtype=np.uint8),-1)image=plt.imread(img_path)#height,width = image.shape[0],image.shape[1]  #获取原图像的垂直方向尺寸和水平方向尺寸。#image = image.resize((height//4,width//4))#'指定图像标签'label = self.img_labels.iloc[index, 0]return image, label'''画图函数'''
def tensorToimg(img_tensor):img=img_tensorplt.imshow(img)#python3.X必须加下行plt.show()#标签指示含义
label_dic = {0: '膏岩', 1: '灰岩', 2: '灰质膏岩',3: '膏质灰岩'}
'''图像集及标签路径'''
label_path = "C:/Users/yeahamen/AppData/Local/Programs/Python/Python310/train_label.csv"
img_root_path = "C:/Users/yeahamen/Desktop/custom_dataset/train_revise/"
test_image_path="C:/Users/yeahamen/Desktop/custom_dataset/test_revise/"
test_label_path="C:/Users/yeahamen/AppData/Local/Programs/Python/Python310/test_label.csv"
#加载图像集与标签路径到函数
#实例化类
dataset = Custom_Dataset(img_root_path, label_path)
dataset_test = Custom_Dataset(test_image_path,test_label_path)'''查看指定图像(18)'''
#索引指定位置的图像及标签
image, label = dataset.__getitem__(18)
#展示图片及其形状(tensor)
print('单张图片(18)形状:',image.shape)
print('单张图片(18)标签:',label_dic[label])#批量输出
dataloader = DataLoader(dataset, batch_size=1, shuffle=True)
'''查看图像的形状'''
for imgs, labels in dataloader:print('一批训练为1张图片(随机)形状:',imgs.shape)#一批图像形状:torch.Size([5, 256, 256, 3])print('一批训练为1张图片(随机)标签:',labels)#标签:tensor([3, 2, 3, 3, 1])break#仅需要查看一批'''查看自定义数据集'''
showimages=[]
showlabels=[]
#把图片信息依次加载到列表
for imgs, labels in dataloader:c = torch.squeeze(imgs, 0)#减去一维数据形成图片固定三参数d = torch.squeeze(labels,0)showimages.append(c)showlabels.append(d)
#依次画出图片
def show_image(nrow, ncol, sharex, sharey):fig, axs = plt.subplots(nrow, ncol, sharex=sharex, sharey=sharey, figsize=(10, 10))for i in range(0,nrow):for j in range(0,ncol):axs[i,j].imshow(showimages[i*4+j])axs[i,j].set_title('Label={}'.format(showlabels[i*4+j]))plt.show()plt.tight_layout()
#给定参数
#show_image(2, 4, False, False)'''创建训练集与测试集'''
dataloader_train = DataLoader(dataset, batch_size=320, shuffle=True)
for imgs, labels in dataloader_train:x_train=imgsy_train=labels
print('训练集图像形状:',x_train.shape)
print('训练集标签形状:',y_train.shape)
dataloader_test = DataLoader(dataset_test, batch_size=40, shuffle=True)
for imgs, labels in dataloader_test:x_test=imgsy_test=labels
print('测试集图像形状:',x_test.shape)
print('测试集标签形状:',y_test.shape)'''将图像转变为网络可用的数据类型'''
X_test = x_test#这里保留是为了预测时查看原始图像
Y_test = y_test#这里保留是为了预测时查看原始标签
x_train,x_test = tf.cast(x_train/255.0,tf.float32),tf.cast(x_test/255.0,tf.float32)
y_train,y_test = tf.cast(y_train,tf.int16),tf.cast(y_test,tf.int16)#参考:http://t.csdn.cn/eRQX2
print('注意:',x_train.shape)
'''归一化灰度值'''
x_train = x_train/255
x_test = x_test/255'''标签转为独热编码,注意:如果标签不是从0开始,独热编码会增加1位(即0)'''
y_train = ka.utils.to_categorical(y_train)
y_test = ka.utils.to_categorical(y_test)
print('独热后训练集标签形状:',y_train.shape)
print('独热后测试集标签形状:',y_test.shape)
#获取测试集特征数
num_classes = y_test.shape[1]'''CNN模型'''
#输入256*256*3
model = ka.Sequential([ka.layers.Conv2D(filters = 32,kernel_size=(5,5),input_shape=(256,256,3),data_format="channels_last",activation='relu'),#卷积252*252*32、卷积层;参量依次为:卷积核个数、卷积核尺寸、单个像素点尺寸、使用ReLu激活函数、解释可见:http://t.csdn.cn/6s3dzka.layers.MaxPooling2D(pool_size=(4,4),strides = None,padding='VALID'),#池化1—63*63*32、最大池化层,池化核尺寸4*4、步长默认为4、无填充、解释可见:http://t.csdn.cn/sES2uka.layers.MaxPooling2D(pool_size=(2,2),strides = None,padding='VALID'),#池化2—31*31*32再加一个最大池化层,池化核尺寸为2*2、步长默认为2、无填充ka.layers.Dropout(0.2),#模型正则化防止过拟合, 只会在训练时才会起作用,随机设定输入的值x的某一维=0,这个概率为输入的百分之20,即丢掉1/5神经元不激活#在模型预测时,不生效,所有神经元均保留也就是不进行dropout。解释可见:http://t.csdn.cn/RXbmS、http://t.csdn.cn/zAIuJka.layers.Flatten(),#拉平432*648*32=8957952;拉平池化层为一个向量ka.layers.BatchNormalization(),#批标准化层,提高模型准确率ka.layers.Dense(50,activation='relu'),#全连接层1,10个神经元,激活函数为ReLuka.layers.Dense(num_classes,activation='softmax')])#全连接层2,4个神经元(对应标签0-3),激活函数为softmax,作用是把神经网络的输出转化为概率,参考可见:http://t.csdn.cn/bcWgu;http://t.csdn.cn/A1Jyn
'''模型参数展示、编译与训练'''				   
model.summary()
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])
startdate = datetime.datetime.now()
#训练轮数epochs=n,即训练n轮
history = model.fit(x_train,y_train,validation_data=(x_test,y_test),epochs=40,batch_size=5,verbose=2)
#训练样本、训练标签、指定验证数据为测试集、训练轮数、显示每一轮训练进程,参考可见:http://t.csdn.cn/oE46K
#获取训练结束时间
enndate=datetime.datetime.now()
print("训练用时:"+str(enndate-startdate))#模型损失值与精度画图展示
#参考http://t.csdn.cn/fUdtO
print(history.history)
loss = history.history['loss']          #训练集损失
val_loss = history.history['val_loss']  #测试集损失
acc = history.history['accuracy']            #训练集准确率
val_acc = history.history['val_accuracy']    #测试集准确率plt.figure(figsize=(10,3))
plt.subplot(121)
plt.plot(loss,color='b',label='train')
plt.plot(val_loss,color='r',label='test')
plt.ylabel('Loss')
plt.legend()plt.subplot(122)
plt.plot(acc,color='b',label='train')
plt.plot(val_acc,color='r',label='test')
plt.ylabel('Accuracy')
plt.legend()
plt.show()plt.figure(2)
'''使用模型进行预测'''
for i in range(10):#在测试集中随机选10个random_test = np.random.randint(1,40)plt.subplot(2,5,i+1)plt.axis('off')#去掉坐标轴plt.imshow(X_test[random_test])#展示要预测的图片predict_image = tf.reshape(x_test[random_test],(1,256,256,3))y_label_predict = np.argmax(model.predict(predict_image))#使用模型进行预测plt.title('R_value:'+str(Y_test[random_test])+'\nP_value:'+str(y_label_predict))#图名显示预测值与实际标签值进行对比
plt.show()

在这里我展示无论训练几轮都会有的输出面板:

a2bbd09130e24986b23e2991e6337082.png

下面展示训练5轮、10轮、20轮、40轮的结果。 

训练5轮结果:

65354c952bf440a1b6810ea83f0b109d.png

 b95a764c1323404285be107f1f72f00b.png

 b8811ed471fe4e0f80c60296ddd09ecd.png

训练10轮结果:

 bdc815236bdc4712a571bde59f4c1a46.png

722900bfaf10455b82014b99a8697c33.png

 42aad1e572cb458d949918880eee1910.png

 训练20轮结果:

 0cb7c7a5d8344bd9b405d3e193b8d8c1.png

 d6326a8b0abb46a4b6625af9a3cb6690.png

 a14138a6a5874b719ebf691a333d7db2.png

  训练40轮结果:

bc6b7ea1106b48569ca3b9fae62e1710.png

471470e25eb745bfa76c9a4e3bb1d127.png

 6e0497bd0a484d5a90a41ae3692e99ff.png

b5ffec7d3aaf41f99e24fe5d117ee59b.png 识别精度的提升是显而易见的!

 最后放上整个实践过程用到的模块:

import os

import cv2

import torch

import pylab

import PySide2

import datetime

import numpy as np

import pandas as pd

from PIL import Image

import tensorflow as tf

import tensorflow.keras as ka

from torchvision import models

import matplotlib.pyplot as plt

from tensorflow.keras import Model

from torchvision import transforms

from torch.utils.data import Dataset

from torchvision.io import read_image

from torch.utils.data import DataLoader

import tensorflow.keras.applications.vgg19 as vgg19

import tensorflow.keras.preprocessing.image as imagepre

from tensorflow.keras.layers import Conv2D,BatchNormalization,Activation,MaxPooling2D,Dropout,Flatten,Dense

这篇关于python基于卷积神经网络实现自定义数据集训练与测试,岩心识别举例。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/201816

相关文章

MyBatis-Plus逻辑删除实现过程

《MyBatis-Plus逻辑删除实现过程》本文介绍了MyBatis-Plus如何实现逻辑删除功能,包括自动填充字段、配置与实现步骤、常见应用场景,并展示了如何使用remove方法进行逻辑删除,逻辑删... 目录1. 逻辑删除的必要性编程1.1 逻辑删除的定义1.2 逻辑删php除的优点1.3 适用场景2.

Python数据验证神器Pydantic库的使用和实践中的避坑指南

《Python数据验证神器Pydantic库的使用和实践中的避坑指南》Pydantic是一个用于数据验证和设置的库,可以显著简化API接口开发,文章通过一个实际案例,展示了Pydantic如何在生产环... 目录1️⃣ 崩溃时刻:当你的API接口又双叒崩了!2️⃣ 神兵天降:3行代码解决验证难题3️⃣ 深度

C#借助Spire.XLS for .NET实现在Excel中添加文档属性

《C#借助Spire.XLSfor.NET实现在Excel中添加文档属性》在日常的数据处理和项目管理中,Excel文档扮演着举足轻重的角色,本文将深入探讨如何在C#中借助强大的第三方库Spire.... 目录为什么需要程序化添加Excel文档属性使用Spire.XLS for .NET库实现文档属性管理Sp

Python+FFmpeg实现视频自动化处理的完整指南

《Python+FFmpeg实现视频自动化处理的完整指南》本文总结了一套在Python中使用subprocess.run调用FFmpeg进行视频自动化处理的解决方案,涵盖了跨平台硬件加速、中间素材处理... 目录一、 跨平台硬件加速:统一接口设计1. 核心映射逻辑2. python 实现代码二、 中间素材处

python中的flask_sqlalchemy的使用及示例详解

《python中的flask_sqlalchemy的使用及示例详解》文章主要介绍了在使用SQLAlchemy创建模型实例时,通过元类动态创建实例的方式,并说明了如何在实例化时执行__init__方法,... 目录@orm.reconstructorSQLAlchemy的回滚关联其他模型数据库基本操作将数据添

Java数组动态扩容的实现示例

《Java数组动态扩容的实现示例》本文主要介绍了Java数组动态扩容的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1 问题2 方法3 结语1 问题实现动态的给数组添加元素效果,实现对数组扩容,原始数组使用静态分配

Python实现快速扫描目标主机的开放端口和服务

《Python实现快速扫描目标主机的开放端口和服务》这篇文章主要为大家详细介绍了如何使用Python编写一个功能强大的端口扫描器脚本,实现快速扫描目标主机的开放端口和服务,感兴趣的小伙伴可以了解下... 目录功能介绍场景应用1. 网络安全审计2. 系统管理维护3. 网络故障排查4. 合规性检查报错处理1.

Python轻松实现Word到Markdown的转换

《Python轻松实现Word到Markdown的转换》在文档管理、内容发布等场景中,将Word转换为Markdown格式是常见需求,本文将介绍如何使用FreeSpire.DocforPython实现... 目录一、工具简介二、核心转换实现1. 基础单文件转换2. 批量转换Word文件三、工具特性分析优点局

Python中4大日志记录库比较的终极PK

《Python中4大日志记录库比较的终极PK》日志记录框架是一种工具,可帮助您标准化应用程序中的日志记录过程,:本文主要介绍Python中4大日志记录库比较的相关资料,文中通过代码介绍的非常详细,... 目录一、logging库1、优点2、缺点二、LogAid库三、Loguru库四、Structlogphp

Springboot3统一返回类设计全过程(从问题到实现)

《Springboot3统一返回类设计全过程(从问题到实现)》文章介绍了如何在SpringBoot3中设计一个统一返回类,以实现前后端接口返回格式的一致性,该类包含状态码、描述信息、业务数据和时间戳,... 目录Spring Boot 3 统一返回类设计:从问题到实现一、核心需求:统一返回类要解决什么问题?