Python多进程加速大量图片数据集读取

训练机器视觉神经网络前 多进程加速数据集读取

多进程读取图片并压缩.py

import readImgMultiProcessing, os, random, gc, time
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from imutils import paths
import numpy as np
seed = 300
random.seed(seed)
coreNum = 23 
imgPath = r
dataPath = r'
dataTestPath = r
dataEncoderPath = r'babyFaceLabelEncoder.data'
config = {"epochs": 10, "batch_size": 128, 'useIDG':True, "imageResize": (600, 600), "lr": 1e-3}
if (os.path.exists(r'tmp') == False):
    os.makedirs(r'tmp')
if __name__ == '__main__':
    if os.path.exists(dataPath) and os.path.exists(dataTestPath):
        (X_train, X_val, y_train, y_val)    = readImgMultiProcessing.readFile(dataPath)
        (X_test, Y_test)                    = readImgMultiProcessing.readFile(dataTestPath)
        class_le                            = readImgMultiProcessing.readFile(dataEncoderPath)
    else:
        tst = time.time()
        class_le = LabelEncoder()
        class_le.fit(['睡', '醒'])
        # 读取所有的图片路径
        imagePaths = sorted(list(paths.list_images(imgPath)))
        # 读取婴儿醒睡的图片
        faceImagePaths = []
        for img_path in imagePaths:
            if(img_path.split(os.path.sep)[-2] == '睡' or img_path.split(os.path.sep)[-2] == '醒'):
                faceImagePaths.append(img_path)
        # 打乱顺序
        random.shuffle(faceImagePaths)
        # 这里就读取部分,内存不够
        # faceImagePaths = faceImagePaths[:234]
        # 用train_test_split划分 训练 验证 测试,注意:这里划分的是 路径 
        trainImgPaths, testImgPaths = train_test_split(faceImagePaths, test_size=0.2, random_state=seed)
        trainImgPaths, valImgPaths  = train_test_split(trainImgPaths,  test_size=0.2, random_state=seed)
        print('数据列表划分完成')
        # 图片
        X_train     = readImgMultiProcessing.readImgMultiProcessing(trainImgPaths, coreNum, config)
        print('训练集读入完成')
        X_val       = readImgMultiProcessing.readImgMultiProcessing(valImgPaths,   coreNum, config)
        print('验证集读入完成')
        X_test      = readImgMultiProcessing.readImgMultiProcessing(testImgPaths,  coreNum, config)
        print('测试集读入完成')
        X_train     = np.asarray(X_train,   dtype=np.float) / 255.0
        print('训练集处理完成')
        X_val       = np.asarray(X_val,     dtype=np.float) / 255.0
        print('验证集处理完成')
        X_test      = np.array(  X_test,    dtype=np.float) / 255.0
        print('测试集处理完成')
        # 婴儿表情的标签
        y_train = class_le.transform([x.split(os.path.sep)[-2] for x in trainImgPaths])
        y_val   = class_le.transform([x.split(os.path.sep)[-2] for x in valImgPaths])
        Y_test  = class_le.transform([x.split(os.path.sep)[-2] for x in testImgPaths])
        # 保存数据
        readImgMultiProcessing.toFile(class_le, dataEncoderPath)
        readImgMultiProcessing.toFile((X_train, X_val, y_train, y_val), dataPath)
        readImgMultiProcessing.toFile((X_test, Y_test), dataTestPath)
        print('数据集压缩成功,数据保存完毕')
        print(len(trainImgPaths), X_train.shape, len(y_train))
        print(len(valImgPaths), X_val.shape, len(y_val))
        print(len(testImgPaths), X_test.shape, len(Y_test))
        print('用时', time.time()-tst) # 934s

readImgMultiProcessing.py

from multiprocessing import Process,Queue,Pool,Pipe,Manager
import os,time,random
from imutils import paths
import numpy as np
from PIL import Image
import pickle
import cv2
def toFile(data,path):
    with open(path, 'wb') as f:
        pickle.dump(data, f, protocol = 4) #支持大于4G的文件
def readFile(path):
    f = open(path, 'rb')
    data = pickle.load(f)
    f.close()
    return data
def resize_img_keep_ratio(img_name, target_size):
    '''
    1.resize图片,先计算最长边的resize的比例,然后按照该比例resize。
    2.计算四个边需要padding的像素宽度,然后padding
    '''
    try:
        # 用cv2&numpy打开,这样可以读取中文路径
        # img = cv2.imdecode(np.fromfile(img_name, dtype=np.uint8), -1) 
        # 使用PIL读取图片,防止中文路径和png格式的报错
        im = Image.open(img_name)
        # 转化成数组的格式
        im_array = np.array(im)
    # 报错提示
    except Exception as e:
        print(img_name, e)
    old_size = im_array.shape[0:2]
    ratio = min(float(target_size[i])/(old_size[i]) for i in range(len(old_size)))
    new_size = tuple([int(i*ratio) for i in old_size])
    img = cv2.resize(im_array,(new_size[1], new_size[0]),interpolation=cv2.INTER_CUBIC)  #注意插值算法
    pad_w = target_size[1] - new_size[1]
    pad_h = target_size[0] - new_size[0]
    top,bottom = pad_h//2, pad_h-(pad_h//2)
    left,right = pad_w//2, pad_w -(pad_w//2)
    # 填充图片,黑边填充
    img_new = cv2.copyMakeBorder(img,top,bottom,left,right,cv2.BORDER_CONSTANT,None,(0,0,0))
    if(img_name.count('.png')==1 or img_new.shape[-1]==4):
        return cv2.cvtColor(img_new, cv2.COLOR_RGBA2RGB)
    return img_new  
def getData(num, paths, return_dict, config):
    Data = []
    for img_path in paths:
        img = resize_img_keep_ratio(img_path, (config["imageResize"][0], config["imageResize"][1]))
        Data.append(img)
    Data = np.array(Data, dtype=np.float)
    Data /= 255.0
    return_dict[num] = Data
    
    
def readImgMultiProcessing(imagePaths, coreNum, config):
    # 路径的划分
    lenPerSt= int(len(imagePaths)/coreNum+1)
    paths = []
    for i in range(coreNum):
        paths.append(imagePaths[i*lenPerSt:(i+1)*lenPerSt])
    # 多进程返回值接收器
    manager = Manager()
    return_dict = manager.dict()
    jobs = []
    # 执行进程
    for i in range(coreNum):
        p = Process(target=getData,args=(str(i), paths[i], return_dict, config))
        jobs.append(p)
        p.start()
    for proc in jobs:
        proc.join()
    # 合并数据
    data = np.asarray((list(return_dict['0'])))
    for i in range(1,coreNum):
        x = np.asarray((list(return_dict[str(i)])))
        if(int(x.shape[0])>0):
            data = np.concatenate((data,x))
    return data


# if __name__ == '__main__':
#     imgPath = r'E:\新的数据集\'
#     imagePaths = sorted(list(paths.list_images(imgPath)))[:100]
#     config = {"epochs": 10, "batch_size": 128, 'useIDG':True, # False True
#             "imageResize": (600, 600), "lr": 1e-3}
#     coreNum = 10
#     data = readImgMultiProcessing(imagePaths, coreNum, config)
#     print(data.shape)
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 使用进程池可以将一个任务分配给多个进程并行处理,从而加快任务完成速度。以下是一个使用Python内置模块multiprocessing实现的进程池示例: ```python import multiprocessing def process_task(task): # 处理任务的代码 pass if __name__ == '__main__': tasks = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] with multiprocessing.Pool() as pool: results = pool.map(process_task, tasks) ``` 在这个例子中,我们创建了一个包含10个任务的列表`tasks`,然后使用`multiprocessing.Pool`创建一个进程池。`map`方法将任务列表分配给进程池中的多个进程并行处理,最后将所有结果存储在列表`results`中。 需要注意的是,在调用`map`方法时,我们需要确保该代码块在`if __name__ == '__main__'`下执行,否则可能会出现进程池无法启动的问题。 另外,需要注意的是,使用进程池并不一定能够加速程序运行,因为进程间的通信和调度也需要时间。在实际使用中,需要根据具体情况选择合适的并行方案。 ### 回答2: Python进程池是一种并行计算的方式,可以利用多核CPU资源来加速代码执行,特别是在for循环中,如果需要处理大量数据或者耗时的任务,使用进程池可以显著提高程序的运行效率。 当我们使用进程池时,可以将待处理的任务分成多个子任务,并将它们分配给多个进程同时执行。这样可以实现并发执行,将任务的处理时间大大降低。与单线程的循环相比,进程池利用了多核CPU的优势,可以同时执行多个任务,从而加快整个任务的处理速度。 在使用Python的进程池时,我们可以通过`multiprocessing`模块提供的`Pool`类来创建进程池,通过调用`apply_async`或者`map_async`方法来向进程池提交任务。进程池会自动管理进程的分配和回收,不需要手动编写进程管理的代码。 当使用进程池加速for循环时,我们可以将循环中的每次迭代作为一个子任务提交给进程池。进程池会将这些子任务分配给可用的进程进行并发处理,从而提高任务的执行效率。当所有子任务完成后,我们可以通过`get`方法获取子任务的处理结果。 需要注意的是,在使用进程池时,我们需要确保每个子任务是独立的,没有依赖于其他子任务的结果。否则,任务之间可能会发生冲突或者产生错误的结果。此外,使用进程池时,还需要考虑进程之间的通信和数据同步的问题,以免造成数据不一致或者进程之间的竞争条件。 综上所述,通过使用Python的进程池,我们可以充分利用多核CPU资源,并行处理for循环中的任务,从而加快任务的执行速度。但在使用进程池时,需要注意任务的独立性和进程之间的通信问题,以保证程序的正确性和可靠性。 ### 回答3: Python的进程池是一种用于并行处理任务的工具。通过使用进程池,可以将任务分发给多个进程来并行执行,从而加快处理速度。 在使用进程池加快for循环时,首先需要将可迭代对象分成多个子任务。然后,使用进程池的map函数将这些子任务分发给多个进程进行并行处理。每个进程将独立执行一个子任务,并将结果返回给主程序。 通过利用多个进程的并行计算能力,可以显著缩短整个for循环的执行时间。进程池在处理大数据集、复杂计算或者网络请求等耗时任务时特别有用。 下面是一个简单的示例代码,演示了如何使用进程池加快for循环: ```python import multiprocessing # 定义一个函数,代表要在每个子进程中执行的任务 def process_task(item): # 执行复杂计算或者其他耗时操作 result = item * item return result if __name__ == '__main__': # 创建一个包含4个进程的进程池 pool = multiprocessing.Pool(4) # 定义一个包含10个元素的列表作为示例数据 my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 使用进程池的map函数进行并行处理 results = pool.map(process_task, my_list) # 关闭进程池,不再接受新的任务 pool.close() # 等待所有子进程执行完毕 pool.join() # 输出结果 print(results) ``` 在这个例子中,进程池会为每个元素调用`process_task`函数进行并行计算。最后,我们可以得到`[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]`这个结果列表。 需要注意的是,进程池的并行处理也有一定的开销,例如创建、维护和通信等。因此,在规模较小时,使用进程池可能不会比普通的for循环更快。但对于较大的任务或数据集,使用进程池可以显著提高处理效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值