前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Kaggle竞赛】数据准备

【Kaggle竞赛】数据准备

作者头像
嵌入式视觉
发布2022-09-05 13:33:21
1.2K0
发布2022-09-05 13:33:21
举报
文章被收录于专栏:嵌入式视觉

Contents

这篇文章的标题纠结了半天,因为在做深度学习的工作时,数据是非常重要的,第一步的工作也是准备数据,这中间我们需要做很多工作包括数据输入、数据预处理、数据增强等,我个人把这一步的工作命名为数据准备,当然也可以有其他命名。

前言:在我们做图像识别的问题时,碰到的数据集可能有多种多样的形式,常见的文件如jpg、png等还好,它可以和tensorflow框架无缝对接,但是如果图像文件是tif等tensorflow不支持解码的文件格式,这就给程序的编写带来一定麻烦。

环境准备

系统:Windows10/Linux系统

软件:Python3、TensorFlow框架、和常用的Python库,数据准备阶段主要是os、cv2、numpy、skimage、csv等。

处理流程

不同的数据集有着不同的程序设计流程,但大致都遵循以下处理流程:

  • 文件名获取(主要是获取文件地址集)
  • 读取文件数据(采用Opencv3或者skimage库读取图像文件,返回ndarray格式,或者TensorFlow读取图像,返回Tensor格式)
  • 打乱数据(随机打乱数据)
  • 划分batch(根据硬件规格,可设置相应较大的batch)

程序设计

我这里以Histopathologic Cancer Detection比赛为例,编写数据准备的程序,这个程序,我写了两个版本,前期的获取文件名函数都差不多,后面的打乱数据和划分batch部分,一个版本是采用numpy+python自带的功能完成的,后面一个版本是用TensorFlow的数据集Dataset框架完成打乱图像数据和划分batch的功能(也可采用队列形式)。

这部分,我描述的不是很好,有经验的下面的程序大致就能理解了。

数据集形式如下图所示:

第一个版本程序

纯python编写,借助了cv2、os、numpy、csv等库

数据准备程序被我命名为input_data.py,里面主要是两个函数:

  • get_files(获取文件名函数,从训练集标签获取)
  • get_batch(读取图像数据,划分batch)

get_files函数如下:

代码语言:javascript
复制
# ----------------------------获取文件名函数,从训练集标签获取-----------------------------------
def get_files(label_file):
    file_list = []
    label_list = []
    image_list = []
    i = 0
    with open(label_file,'r') as train:
    # 返回一个生成器对象,reader是可迭代的
        reader = csv.reader(train)
        for row in reader:
            i += 1
            if i > 1:
                # print(row)
                file_path = os.path.join(train_dir,row[0]+'.tif')   # 获取图像文件路径
                file_list.append(file_path)
                label_list.append(row[1])
                # image = cv2.imread(file_path)                     # ndarray
                # print(img)
                # image = cv2.resize(image,(IMG_W,IMG_H,IMG_C))     # ndarray
                # image_list.append(image)
                # print(str(file_path))
        num_files = len(file_list)                  # 获取图像名列表长度
        num_labels = len(label_list)
        if num_files == num_labels:
            print('num of files identify to num of labels and the num is %d' % num_files)
        # 打乱文件顺序
        temp = np.array([file_list,label_list])     # ndarray,把图像名序列和标签名序列做成一个二维数组
        temp = temp.transpose()                     # ndarray,对二维数组进行转置操作,(2,220025)-->(220026,5)
        np.random.shuffle(temp)                     # 打乱数组各行顺序
        file_list = list(temp[:,0])                 # list,获取打乱顺序后的图像名序列
        label_list = list(temp[:,1])                # list,获取打乱后的标签序列
        label_list = [int(i) for i in label_list]   # 把字符标签转化为整数型标签
    return i,file_list,label_list                   # 返回文件名和文件标签列表list

get_batch()函数如下:

代码语言:javascript
复制
#------------------------------读取图像数据,划分batch-----------------------------------------
# 生成相同大小的批次
def get_batch(files,labels,start,batch_size):
    images = []
    start = (start+batch_size) % len(labels)
    end = start + batch_size
    # start = start+batch_size
    files = files[start:end]
    for i,file in enumerate(files):
        #print(file)
        image = cv2.imread(file)
        image = cv2.resize(image,(IMG_W,IMG_H))  
        images.append(image)
    labels = labels[start:end]
    # 打乱一个batch的图像数据和对应标签
    temp = np.array([images,labels])            # ndarray,把图像名序列和标签名序列做成一个二维数组
    temp = temp.transpose()                     # ndarray,对二维数组进行转置操作,(2,220025)-->(220026,5)
    np.random.shuffle(temp)                     # 打乱数组各行顺序
    images = list(temp[:,0])                    # list,获取打乱顺序后的图像名序列
    labels = list(temp[:,1])                    # list,获取打乱后的标签序列
    labels = [int(i) for i in labels]           # 把字符标签转化为整数型标签
    # 返回一个batch的images和labels
    return np.array(images),np.array(labels)

全部程序如下:

代码语言:javascript
复制
# coding:utf-8
# filename:input_data.py
# Environment:windows10,python3,numpy,TensorFlow1.9,glob,matplotlib,time
# Function:负责实现读取数据,生成批次(batch)

import os
import numpy as np
from skimage import io,transform
import csv
import cv2
IMG_H = 96              # 图像高度
IMG_W = 96               # 图像宽度
IMG_C = 3               # 图像通道
batch_size = 20         # 批次大小
label_file = 'F:/Software/Python_Project/Histopathologic-Cancer-Detection2.0/train_labels.csv'
train_dir = 'F:/Software/Python_Project/Histopathologic-Cancer-Detection/train/'

# ----------------------------获取文件名函数,从训练集标签获取-----------------------------------
def get_files(label_file):
    file_list = []
    label_list = []
    image_list = []
    i = 0
    with open(label_file,'r') as train:
    # 返回一个生成器对象,reader是可迭代的
        reader = csv.reader(train)
        for row in reader:
            i += 1
            if i > 1:
                # print(row)
                file_path = os.path.join(train_dir,row[0]+'.tif')   # 获取图像文件路径
                file_list.append(file_path)
                label_list.append(row[1])
                # image = cv2.imread(file_path)                     # ndarray
                # print(img)
                # image = cv2.resize(image,(IMG_W,IMG_H,IMG_C))     # ndarray
                # image_list.append(image)
                # print(str(file_path))
        num_files = len(file_list)                  # 获取图像名列表长度
        num_labels = len(label_list)
        if num_files == num_labels:
            print('num of files identify to num of labels and the num is %d' % num_files)
        # 打乱文件顺序
        temp = np.array([file_list,label_list])     # ndarray,把图像名序列和标签名序列做成一个二维数组
        temp = temp.transpose()                     # ndarray,对二维数组进行转置操作,(2,220025)-->(220026,5)
        np.random.shuffle(temp)                     # 打乱数组各行顺序
        file_list = list(temp[:,0])                 # list,获取打乱顺序后的图像名序列
        label_list = list(temp[:,1])                # list,获取打乱后的标签序列
        label_list = [int(i) for i in label_list]   # 把字符标签转化为整数型标签
    return i,file_list,label_list                   # 返回文件名和文件标签列表list
#------------------------------读取图像数据,划分batch-----------------------------------------
# 生成相同大小的批次
def get_batch(files,labels,start,batch_size):
	images = []
	start = (start+batch_size) % len(labels)
	end = start + batch_size
	# start = start+batch_size
	files = files[start:end]
	for i,file in enumerate(files):
		# print(file)                       # 仅供测试程序时用,迭代训练模型时建议注释掉
		image = cv2.imread(file)
		image = cv2.resize(image,(IMG_W,IMG_H))  
		images.append(image)
	labels = labels[start:end]
	# 打乱一个batch的图像数据和对应标签
	temp = np.array([images,labels])            # ndarray,把图像名序列和标签名序列做成一个二维数组
	temp = temp.transpose()                     # ndarray,对二维数组进行转置操作,(2,220025)-->(220026,5)
	np.random.shuffle(temp)                     # 打乱数组各行顺序
	images = list(temp[:,0])                    # list,获取打乱顺序后的图像名序列
	labels = list(temp[:,1])                    # list,获取打乱后的标签序列
	labels = [int(i) for i in labels]           # 把字符标签转化为整数型标签
	# 返回一个batch的images和labels
	return np.array(images),np.array(labels)
#-----------------------------测试:迭代输出一个batch数据----------------------------
steps = 10
#循环迭代输出batch数据
for i in range(steps):
    data,label = get_batch(file_list, label_list, i, batch_size)
    print(data,label)
    print(type(data))
    print(label.dtype)
    print(len(data),len(label))

本程序获取文件名(文件地址集)函数,不需要列出通过训练目录下的文件,而是借助训练集标签,直接构造文件路径,实测这样速度快了很多,如果是通过os.listdir()+os.path.join的方式获取文件路径,还需要和训练集标签去一一对应相应文件名和标签,这样速度非常慢!训练集少还好点,训练集大的话,光获取文件名路径这个部分,就花很多时间了。

为了加快程序的速度,本程序的读取图像数据是按照一个批次来读取的,先随机打乱文件名数据之后,然后划分文件名batch,再开始读取图像数据,这样就得到了一个batch的图像数据,shape为(batch,img_w,img_h,img_c)。一个batch一个batch的去读取图像,比一次性读取所有图像数据再划分batch要快很多。

输出结果

无图无真相,我这里设置batch_size的是20。输出data的shape为(20,96,96,3),label的shape为(20,)

第二个版本程序

这个版本使用的是TensorFlow的Dataset框架读取处理数据,我在网上没找到使用的程序,在参考了些资料和查阅api之后,自己写了这个实用的程序,但是在训练的时候,出现了训练到1000左右epoch时,程序突然报错了,这让我很懵逼,目前没有找到问题。

其实正常测试读取训练集图像是没问题,主要是在训练模型的时候出了问题,还不清楚是模型训练程序还是数据准备程序的问题,所以这个版本程序仅供参考。

纯python编写,借助了cv2、os、numpy、csv、TensorFlow等库。

数据准备程序被我命名为input_data.py,里面主要是两个函数:

  • get_files(获取文件名函数,从训练集标签获取)
  • read_batch_image(读取一个batch图像,返回图像和标签数据ndarray)
  • get_batch(生成一个batch的文件名地址集和标签)

程序如下:

代码语言:javascript
复制
# coding:utf-8
# filename:input_data.py
# Environment:windows10,python3,numpy,TensorFlow1.9,glob,matplotlib,time
# Function:负责实现读取数据,生成批次(batch)

from skimage import io,transform
import tensorflow as tf
import numpy as np
import os
import matplotlib.pyplot as plt
import csv
import cv2

# 本地电脑训练数据读取对应地址
train_dir = "F:/Software/Python_Project/Histopathologic-Cancer-Detection/train/"
label_file = 'F:/Software/Python_Project/Histopathologic-Cancer-Detection/train_labels.csv'
# 云服务器训练数据读取对应地址
# train_dir = '/data/Histopathologic-Cancer-Detection/train/'
# label_file = '/data/Histopathologic-Cancer-Detection/train_labels.csv'

#-------------------------------------图像数据及标签获取并打乱----------------------------------
# 获取数据集图像文件路径和标签
def get_files(file_dir,label_file):
    # file_dir: 文件夹路径
    # label_file: 训练数据标签文件
    # return: 乱序后的图片和标签

    # 定义存放图像数据和标签列表
    image_list = []
    label_list = []
    len_file = len(os.listdir(file_dir))                #统计指定文件夹中图像文件个数
    len_label = len(open(label_file).readlines())-1     # 统计label_file文件有多少行
    if len_file == len_label:
        print('num of images identify to num of labels.')
        print('The number of images is %d.' % len_file)

    # csv_file = open(label_file,'r')
    train_files = [file_dir+i for i in os.listdir(file_dir)] # use this for full datas
    train_files = train_files[0:300]
    # 循环列出文件夹下的所有图像文件,获取文件路径和文件标签列表
    # for file in os.listdir(file_dir):
    for i,file in enumerate(train_files):
        file_name = file.split('/')[-1].split(sep='.')[0]
        # i += 1
        print(i,'files load success','filename is',file_name)
        # print(file,'load success')
        # image_list.append(file_dir+file)
        image_list.append(file)
        with open(label_file,'r') as train:
            # 返回一个生成器对象,reader是可迭代的
            reader = csv.reader(train)
            for row in reader:
                if row[0] == file_name:
                    label_list.append(row[1])
                    print('The label is',row[1])

    print('There are %d images\nThere are %d labels' % (len(image_list),len(label_list)))

    # 打乱文件顺序
    temp = np.array([image_list,label_list])    # ndarray,把图像名序列和标签名序列做成一个二维数组
    temp = temp.transpose()                     # ndarray,对二维数组进行转置操作,(2,220025)-->(220026,5)
    np.random.shuffle(temp)                     # 打乱数组各行顺序
    image_list = list(temp[:,0])                # list,获取打乱顺序后的图像名序列
    label_list = list(temp[:,1])                # list,获取打乱后的标签序列
    label_list = [int(i) for i in label_list]   # 把字符标签转化为整数型标签
    return image_list,label_list                # list,shape:(220025,) (220025,)

#-----------------------读取一个batch图像,返回图像和标签数据ndarray------------------------------------
# 读取image file name,裁剪图像尺寸后,返回ndarray格式的数据(3*D)
def read_batch_image(file_batch,label_batch):
    # file_batch = file_batch.eval()
    # label_batch = label_batch.eval()
    image_batch = []
    # batch_label = []
    for i,file in enumerate(file_batch):
        file = str(file)
        file = file.strip('b')
        # print(file)
        image = io.imread(eval(file))
        image = transform.resize(image, (96,96))
        image_batch.append(image)
        # image = tf.image.resize_images(image, [96, 96])
    # 返回一个batch图像数据,shape:(batch_size,96,96,3)
    return np.array(image_batch),np.array(label_batch)

#----------------------------生成一个batch的文件名地址集和标签-----------------------------------
# 生成相同大小的批次
def get_batch(filenames, labels, batch_size):
    # 此时dataset中的一个元素是(filename, label)
    dataset = tf.data.Dataset.from_tensor_slices((filenames,labels))
    # 此时dataset中的一个元素是(file_batch, label_batch)
    dataset = dataset.shuffle(buffer_size=1000).batch(batch_size).repeat()
    # 从dataset中实例化了一个Iterator,只能从头到尾读取一次元素
    iterator = dataset.make_one_shot_iterator()
    # file_batch,label_batch是返回的一维张量
    file_batch,label_batch = iterator.get_next()
    # 返回一个batch的file和label
    return file_batch,label_batch

#------------------------开始从数据集读取文件名和图像数据---------------------------------------
filenames,labels = get_files(train_dir,label_file)
#------------------------创建会话,开始测试迭代读取图像-----------------------------------------

with tf.Session() as sess:

    for i in range(10):
        print('Start Iterator')
        file_batch,label_batch = get_batch(filenames,labels,20)
        # 打印一个人batch的图像数据和标签
        file_batch = sess.run(file_batch)
        label_batch  = sess.run(label_batch)
        print(file_batch,label_batch)
        data,label = read_batch_image(file_batch,label_batch)
        print(data)
        print(label)

总结

数据准备的程序真的没有模板去套,需要我们再下载分析好数据之后,设计相应的文件名获取、数据读取(打乱、划分batch)、数据预处理、数据增强等功能函数。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-11-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 环境准备
  • 处理流程
  • 程序设计
    • 第一个版本程序
      • 输出结果
        • 第二个版本程序
        • 总结
        相关产品与服务
        文件存储
        文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档