1 数据集的准备以及处置惩罚操作
1.1 数据集
在练习模型之前的时间我们需要提前准备数据集
数据集下载链接
1.2 文件解压操作(python)
- # 第一步,把原数据解压
- import zipfile
- import os
- import shutil
- def unzipFile(source_file, target_dir):
- ''' 解压单个文件到目标文件夹。
- '''
- zf = zipfile.ZipFile(source_file)
- try:
- zf.extractall(path=target_dir)
- except RuntimeError as e:
- print(e)
- zf.close()
- sour = 'data/data20541/dogs-vs-cats.zip'
- targ = ''
- if not os.path.exists('data/dogCat/dog'): #用os.path.exists来判断'data/dogCat/dog'路径存不存在
- unzipFile(source_file = sour, target_dir = targ)
- os.remove('sample_submission.csv')
复制代码 首先:我们需要制定一个函数来解压zip文件。
然后:通过python中的库中的文件操作函数ZipFile()来解压
末了:把解压好的文件在通过extractall()函数放在target_dir目录下
第二步:原数据解压之后是 形成 train.zip 和 test.zip 文件还需要解压一遍,让他们解压之后形成练习集和测试集。
- if not os.path.exists('data/dogCat/dog'):
- # 先解压训练集
- train_file = 'train.zip'
- train_targetdir = 'data'
- unzipFile(source_file = train_file, target_dir = train_targetdir)
- os.remove(train_file)
-
- # 再解压测试集
- test_file = 'test.zip'
- test_targetdir = 'data'
- unzipFile(source_file = test_file, target_dir = test_targetdir)
- os.remove(test_file)
复制代码 1.3 数据的分类
在练习盘算机辨认动物之前,我们需要进行区分,比如:你要让盘算机进行猫狗的区分那么你的数据集中有其他的动物的图片,这样的话在练习过程中在辨认关键信息的时间就出错!!!。因此我们需要排除干扰选项。
排除干扰项思路:把文件的所有图片都遍历一遍然后进行筛选出猫和狗的图片。
执行代码:
- dataRootPath = 'data/dogCat'
- def copyFiles(fileDirs, targetDir):
- for fileDir in fileDirs:
- shutil.copy(fileDir, targetDir)
-
- def divideData():
- global dataRootPath
- classDirs = os.listdir('data/train')
- dogDirs = [os.path.join('data/train',x) for x in classDirs if x.find('dog')>=0]
- catDirs = [os.path.join('data/train',x) for x in classDirs if x.find('cat')>=0]
- print('总图片数量为:%d'%len(classDirs))
- print('\t猫的图片数量为:%d'%len(catDirs))
- print('\t狗的图片数量为:%d'%len(dogDirs))
- # 遍历图片,转移数据集
- dogPath = os.path.join(dataRootPath, 'dog')
- if not os.path.exists(dogPath):
- os.makedirs(dogPath)
- copyFiles(dogDirs, dogPath)
-
- catPath = os.path.join(dataRootPath, 'cat')
- if not os.path.exists(catPath):
- os.makedirs(catPath)
- copyFiles(catDirs, catPath)
-
- if not os.path.exists('data/dogCat/dog'):
- divideData()
复制代码 接下来我们来介绍以上提到的函数:
1 os.listdir(路径) ==== 这是把路径中的目录展开 。就是把目录展开了,然后就是目录中的子文件或者文件了。这里就是指的是图片!!!
2 os.path.join(路径,路径1)==== 这里就是列表的初始化 ,先是判断你的x有没有dog或者cat的笔墨(这一步就是先筛选图片名称为dog和cat)。 如果符合那么就把路径1链接到路劲之后。 如:os.path.join(‘data/dogcat/’,dog1.jpg) -> 结果:data/dogcat/dog1.jpg
3 os.path.exists(路径) 就是判断路径存不存在
4 os.mkdir(名称) 就是创建名称目录
5 shutil.copy(dest,source) 就是把文件进行复制
总结:以上代码就是为了把干扰选项给去掉,为了更好的练习出大模型!!!
1.4 创建练习集和测试集
在经过以上操作后:我们就可以开始进行对数据进行划分和创建数据集合测试集了
- #Python os标准库,用于文件操作、 random随机数生成、 JSON解析和系统参数访问。
- import os
- import random
- import json
- import sys
- #Paddle.fluid,paddle框架的核心模块,用于构建和训练深度学习模型。
- import paddle
- import paddle.fluid as fluid
- #数值计算库,用于处理数组和矩阵.
- import numpy
- from multiprocessing import cpu_count
- from visualdl import LogWriter
- #matplotlib.pyplot用于绘图和数据可视化
- import matplotlib.pyplot as plt
- import numpy as np
- #PIL 用于打开和处理图像
- from PIL import Image
- import paddle
- paddle.enable_static()
- #定义长度,和宽度
- IMG_H =64
- IMG_W =64
- #缓冲区大小,用来读取数据处理和预处理
- BUFFER_SIZE = 1024
- #一次批量处理的个数
- BATCH_SIZE =64
- #是否使用gpu
- USE_CUDA = True
- #训练次数
- TRAIN_NUM = 150
- #学习率
- LEARNING_RATE = 0.005
- DATA_TRAIN = 0.75 #训练集在数据集中占多少数据 # 表示在训练模型时,使用多大规模的数据
- #每执行玩一个模型就放在work/model 中,这样方便模型的拿取
- model_save_dir = "work/model"
- def genDataList(dataRootPath, trainPercent=0.8):
- # 函数会自动检测dataRootPath下的所有文件夹,每一个文件夹为1个类别的图片
- # 然后生成图片的list,即paddlepaddle能获取信息的形式
- # 默认随机抽取20%作为测试集(验证集)
- # random.seed(42) #设置随机种子。
-
- classDirs = os.listdir(dataRootPath)#os.listdir用来获取dataRootPath的所有文件和文件夹
- #os.isdir 判断是否为目录 #os.path.join 拼接
- classDirs = [x for x in classDirs if os.path.isdir(os.path.join(dataRootPath,x))]
- listDirTest = os.path.join(dataRootPath, "test.list")
- listDirTrain = os.path.join(dataRootPath, "train.list")
- # 清空原来的数据,当一‘w’模式打开文件夹时,1:文件已存在,那么就会清空数据 2:文件不存在,就会新建一个文件
- #避免旧数据干扰
- # with open(listDirTest, 'w') as f:
- # pass
- # with open(listDirTrain, 'w') as f:
- # pass
- with open(listDirTest, 'w') as f:
- pass # 清空测试集文件
- with open(listDirTrain, 'w') as f:
- pass # 清空训练集文件
-
- # 随机划分训练集与测试集
- classLabel = 0 # 初始化类别标签,从0开始
- class_detail = [] # 记录每个类别的描述
- classList = [] # 记录所有的类别名
- num_images = 0 # 统计图片的总数量
- for classDir in classDirs:
- classPath = os.path.join(dataRootPath,classDir) # 获取类别为classDir的图片所在的目录,拼接子目录 如:data/DogCat/dog
- imgPaths = os.listdir(classPath) # 获取类别为classDir的所有图片名
- # 从中取trainPercent(默认80%)作为训练集
- imgIndex = list(range(len(imgPaths))) #生成图片索引列表
- random.shuffle(imgIndex) #打乱图片索引
- imgIndexTrain = imgIndex[:int(len(imgIndex)*trainPercent)]#划分训练集与测试集
- imgIndexTest = imgIndex[int(len(imgIndex)*trainPercent):]
- #把代码追加到listDirTest 与 listDirTrain 目录下
- with open(listDirTest,'a') as f:
- for i in imgIndexTest:
- imgPath = os.path.join(classPath,imgPaths[i]) #打开目录listDirTest 把刚刚定义的imgIndexTest写入到该目录下 路劲大致如:data/DogCat/dog/dog.1jpg
- f.write(imgPath + '\t%d' % classLabel + '\n') # 写入格式图片路劲\t类别标签\n
- with open(listDirTrain,'a') as f:
- for i in imgIndexTrain:
- imgPath = os.path.join(classPath,imgPaths[i])
- f.write(imgPath + '\t%d' % classLabel + '\n')
- num_images += len(imgPaths)
-
- classList.append(classDir) #将类别名称添加到classList中
- class_detail_list = {} #记录该类别的名称、标签、测试集图片数量和训练集图片数量
- class_detail_list['class_name'] = classDir #类别名称,如dog
- class_detail_list['class_label'] = classLabel #类别标签,如cat 的标签是 0 dog的标签是 1
- class_detail_list['class_test_images'] = len(imgIndexTest) #该类数据的测试集数目
- class_detail_list['class_trainer_images'] = len(imgIndexTrain) #该类数据的训练集数目
- class_detail.append(class_detail_list)
- classLabel += 1
- # 说明的json文件信息
- readjson = {} #包含所有类别的名称、总类别数量、总图片数量以及每个类别的详细信息。
- readjson['all_class_name'] = classList # 文件父目录
- readjson['all_class_sum'] = len(classDirs) # 总类别数量
- readjson['all_class_images'] = num_images # 总图片数量
- readjson['class_detail'] = class_detail # 每种类别的情况
- jsons = json.dumps(readjson, sort_keys=True, indent=4, separators=(',', ': '))#json.dumps的作用是将Python对象转换成JSON格式的字符串。这里的参数看起来是用于格式化输出的。
- #sort_keys对字典的键(Key)按字母顺序排序。设置缩进为4个空格,使JSON字符串具有层次结构
- with open(os.path.join(dataRootPath,"readme.json"),'w') as f:#把jsons字符串写入到dataRootPath/readme.json中用于保存数据集的元信息(如类别名称、标签、图片数量等)
- f.write(jsons)
- print ('生成数据列表完成!')
- return readjson['all_class_sum']
- classNumber = genDataList(dataRootPath)#返回类别数量
- print(classNumber)
复制代码 我们照旧一步一步来:
1 变量:
- #定义长度,和宽度
- IMG_H =64
- IMG_W =64
- #缓冲区大小,用来读取数据处理和预处理
- BUFFER_SIZE = 1024
- #一次批量处理的个数
- BATCH_SIZE =64
- #是否使用gpu
- USE_CUDA = True
- #训练次数
- TRAIN_NUM = 150
- #学习率
- LEARNING_RATE = 0.005
- DATA_TRAIN = 0.75 #训练集在数据集中占多少数据 # 表示在训练模型时,使用多大规模的数据
- #每执行玩一个模型就放在work/model 中,这样方便模型的拿取
- model_save_dir = "work/model"
复制代码 这是我们在练习时进行定义的全局变量:
IMG_H IMG_W 定义的输出图像的长宽高度
BUFFER_SIZE 就是缓冲区的大小用于读取数据处置惩罚和预处置惩罚
BATCH_SIZE 就是在练习时一次读取的个数
USE_CUDA = True 这是使用GPU来进行练习,因为你使用CPU的话这个程序会练习的很慢或者练习不出来。
TRAIN_NUM 练习次数
LEARNING_RATE 学习率
DATA_TRAIN 练习集在数据集中占多少数据 表现在练习模型时,使用多大规模的数据
model_save_dir 每执行玩一个模型就放在work/model 中,这样方便模型的拿取
然后就是我们的genDataList函数:
- def genDataList(dataRootPath, trainPercent=0.8):
- # 函数会自动检测dataRootPath下的所有文件夹,每一个文件夹为1个类别的图片
- # 然后生成图片的list,即paddlepaddle能获取信息的形式
- # 默认随机抽取20%作为测试集(验证集)
- # random.seed(42) #设置随机种子。
-
- classDirs = os.listdir(dataRootPath)#os.listdir用来获取dataRootPath的所有文件和文件夹
- #os.isdir 判断是否为目录 #os.path.join 拼接
- classDirs = [x for x in classDirs if os.path.isdir(os.path.join(dataRootPath,x))]
- listDirTest = os.path.join(dataRootPath, "test.list")
- listDirTrain = os.path.join(dataRootPath, "train.list")
- # 清空原来的数据,当一‘w’模式打开文件夹时,1:文件已存在,那么就会清空数据 2:文件不存在,就会新建一个文件
- #避免旧数据干扰
- # with open(listDirTest, 'w') as f:
- # pass
- # with open(listDirTrain, 'w') as f:
- # pass
- with open(listDirTest, 'w') as f:
- pass # 清空测试集文件
- with open(listDirTrain, 'w') as f:
- pass # 清空训练集文件
-
- # 随机划分训练集与测试集
- classLabel = 0 # 初始化类别标签,从0开始
- class_detail = [] # 记录每个类别的描述
- classList = [] # 记录所有的类别名
- num_images = 0 # 统计图片的总数量
- for classDir in classDirs:
- classPath = os.path.join(dataRootPath,classDir) # 获取类别为classDir的图片所在的目录,拼接子目录 如:data/DogCat/dog
- imgPaths = os.listdir(classPath) # 获取类别为classDir的所有图片名
- # 从中取trainPercent(默认80%)作为训练集
- imgIndex = list(range(len(imgPaths))) #生成图片索引列表
- random.shuffle(imgIndex) #打乱图片索引
- imgIndexTrain = imgIndex[:int(len(imgIndex)*trainPercent)]#划分训练集与测试集
- imgIndexTest = imgIndex[int(len(imgIndex)*trainPercent):]
- #把代码追加到listDirTest 与 listDirTrain 目录下
- with open(listDirTest,'a') as f:
- for i in imgIndexTest:
- imgPath = os.path.join(classPath,imgPaths[i]) #打开目录listDirTest 把刚刚定义的imgIndexTest写入到该目录下 路劲大致如:data/DogCat/dog/dog.1jpg
- f.write(imgPath + '\t%d' % classLabel + '\n') # 写入格式图片路劲\t类别标签\n
- with open(listDirTrain,'a') as f:
- for i in imgIndexTrain:
- imgPath = os.path.join(classPath,imgPaths[i])
- f.write(imgPath + '\t%d' % classLabel + '\n')
- num_images += len(imgPaths)
-
- classList.append(classDir) #将类别名称添加到classList中
- class_detail_list = {} #记录该类别的名称、标签、测试集图片数量和训练集图片数量
- class_detail_list['class_name'] = classDir #类别名称,如dog
- class_detail_list['class_label'] = classLabel #类别标签,如cat 的标签是 0 dog的标签是 1
- class_detail_list['class_test_images'] = len(imgIndexTest) #该类数据的测试集数目
- class_detail_list['class_trainer_images'] = len(imgIndexTrain) #该类数据的训练集数目
- class_detail.append(class_detail_list)
- classLabel += 1
复制代码 根据我的解释可以得出:
这个函数第一步就是创建出数据集和测试集:
- imgIndex = list(range(len(imgPaths))) #生成图片索引列表
- random.shuffle(imgIndex) #打乱图片索引
- imgIndexTrain = imgIndex[:int(len(imgIndex)*trainPercent)]#划分训练集与测试集
- imgIndexTest = imgIndex[int(len(imgIndex)*trainPercent):]
- ......之后就是把文件写入操作
复制代码 第二步就是记录属性
- classLabel = 0 # 初始化类别标签,从0开始
- class_detail = [] # 记录每个类别的描述
- classList = [] # 记录所有的类别名
- num_images = 0 # 统计图片的总数量
复制代码 他们把记录出来的这些属性,用json进行连接。
得出:


把狗做标记:为1 (class_label= 1)
然后圈红圈的分别是练习集的个数,和测试集的个数
猫同理。
1.5 数据处置惩罚和创建数据处置惩罚器
- def trainMapper(sample):
- global IMG_H, IMG_W
- img, label = sample
-
- # 图像加载(兼容老版本)
- img = paddle.dataset.image.load_image(img) # 所有版本通用
-
- # 图像变换(老版本无水平翻转,需手动添加)
- img = paddle.dataset.image.simple_transform(
- im=img,
- resize_size=IMG_H,
- crop_size=IMG_W,
- is_color=True,
- is_train=True # 在1.x版本中此参数可能不触发翻转
- )
- img = img.flatten().astype('float32') / 255.0
- return img, label
- # 对自定义数据集创建训练集train的reader
- def trainReader(train_list, buffered_size=1024):
- global DATA_TRAIN
- def reader():
- with open(train_list, 'r') as f:
- # 将train.list里面的标签和图片的地址放在一个list列表里面,中间用\t隔开'
- # 如data/dogCat/Cat_/1.jpg\t0'
- lines = [line.strip() for line in f]# 读取所有行并去除首尾空格
- np.random.shuffle(lines)#打乱数据顺序增强随机性
- lines = lines[:int(len(lines)*DATA_TRAIN)]
- for line in lines:
- # 图像的路径和标签是以\t来分割的,所以我们在生成这个列表的时候,使用\t就可以了
- img_path, lab = line.strip().split('\t')# 分割路径与标签
- yield img_path, int(lab) # 生成数据元组(路径, 标签)
- # 创建自定义数据训练集的train_reader
- return paddle.reader.xmap_readers(trainMapper, reader, cpu_count(), buffered_size)
- def testMapper(sample):
- global IMG_H
- global IMG_W
- img, label = sample
- img = paddle.dataset.image.load_image(img)
- img = paddle.dataset.image.simple_transform(im=img,
- resize_size=IMG_H, crop_size=IMG_W,
- is_color=True, is_train=False)
- img= img.flatten().astype('float32')/255.0
- return img, label
- # 对自定义数据集创建验证集test的reader
- def testReader(test_list, buffered_size=1024):
- global DATA_TRAIN
- def reader():
- with open(test_list, 'r') as f:
- lines = [line.strip() for line in f]
- np.random.shuffle(lines)
- lines = lines[int(len(lines)*DATA_TRAIN):]
- for line in lines:
- #图像的路径和标签是以\t来分割的,所以我们在生成这个列表的时候,使用\t就可以了
- img_path, lab = line.strip().split('\t')
- yield img_path, int(lab)
- return paddle.reader.xmap_readers(testMapper, reader, cpu_count(), buffered_size)
复制代码 在这里呢,我们就解说一下怎么处置惩罚数据的:
- img = paddle.dataset.image.simple_transform(
- im=img,
- resize_size=IMG_H,
- crop_size=IMG_W,
- is_color=True,
- is_train=True # 在1.x版本中此参数可能不触发翻转
- )
- img = img.flatten().astype('float32') / 255.0
复制代码 通过simple_transform 这个类成员函数进行处置惩罚数据:
resize_size=IMG_H 这里代表的是缩放,就比如:本来3232的照片 缩放成1616。
crop_size=IMG_W 这里代表着中心裁剪
is_color = True 这里就是代表有颜色额图片
is_train=True 如果是True的话,这里的函数有大概对图片进行随机裁剪(增强数据)
末了img = img.flatten().astype(‘float32’) / 255.0 代表这归一化 按(0,1)处置惩罚
而在测试的时间is_train=False 这就是不采用随机裁剪
创建数据集Reader
- def createDataReader(BatchSize = 128):
- global BUFFER_SIZE
- # 把图片数据生成reader
- trainer_reader = trainReader(train_list = os.path.join(dataRootPath,"train.list"))
- train_reader = paddle.batch(
- paddle.reader.shuffle(reader=trainer_reader, buf_size=BUFFER_SIZE),
- batch_size=BatchSize)
-
- tester_reader = testReader(test_list = os.path.join(dataRootPath,"test.list"))
- test_reader = paddle.batch(tester_reader, batch_size=BatchSize)
- print('train_reader, test_reader创建完成!')
- return train_reader, test_reader
复制代码 这里不做解释
2 网络构建
CNN版本–
- def convolutional_neural_network(image, classNumber):
- # 第一个卷积-池化层 #修改第一步就是先是卷积池化->bn->激活 查找论文中 可以得出BN在激活前:在激活函数前进行 BN,能更有效地约束激活前的输入分布,
- #使网络更容易学习到合适的参数,ReLU 对负值输入会直接截断(输出0),如果激活后再 BN,可能丢失部分信息;而先 BN 再激活,可以确保激活函数的输入是归一化的正值,梯度更稳定。
- #论文《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》建议将 BN 放在激活前,以最大化其规范化效果。
- conv_pool_1 = fluid.nets.simple_img_conv_pool(
- input=image, # 输入图像
- filter_size=5, # 滤波器的大小
- num_filters=20, # filter 的数量
- pool_size=2, # 池化核大小
- pool_stride=2, # 池化步长
- act=None # 先不激活
- )
- conv_pool_1 = fluid.layers.batch_norm(conv_pool_1) # BN
- conv_pool_1 = fluid.layers.relu(conv_pool_1) # 激活
- # 第二个卷积-池化层
- conv_pool_2 = fluid.nets.simple_img_conv_pool(
- input=conv_pool_1,
- filter_size=5,
- num_filters=50,
- pool_size=2,
- pool_stride=2,
- act=None
- )
- conv_pool_2 = fluid.layers.batch_norm(conv_pool_2) # BN
- conv_pool_2 = fluid.layers.relu(conv_pool_2) # 激活
- # 第三个卷积-池化层
- conv_pool_3 = fluid.nets.simple_img_conv_pool(
- input=conv_pool_2,
- filter_size=5,
- num_filters=50,
- pool_size=2,
- pool_stride=2,
- act=None
- )
- conv_pool_3 = fluid.layers.batch_norm(conv_pool_3) # BN
- conv_pool_3 = fluid.layers.relu(conv_pool_3) # 激活
- # 全连接输出层
- prediction = fluid.layers.fc(input=conv_pool_3, size=classNumber, act='softmax')
- print('神经网络创建完成!')
- return prediction
复制代码 ~卷积层:nn.Conv2d用于提取特征,参数包罗输入通道数、输出通道数、卷积核大小等。
~池化层:nn.MaxPool2d用于降维,通常使用最大池化。
~全连接层:nn.Linear用于将特征映射到终极输出空间。
~激活函数:F.relu是ReLU激活函数,增加非线性。
~展平操作:x.view将特征图展平为一维向量,以便输入全连接层。
这里就需要我们进行深度学习了!!!
如果是网络构建的话选择CNN就OK了!!!
DeepID 人脸辨认网络结构
- def DeepID(images, classNumber):
- # 第一个卷积-池化层
- conv_pool_1 = fluid.nets.simple_img_conv_pool(
- input=images,
- filter_size=5,
- num_filters=32,
- pool_size=2,
- pool_stride=2,
- act=None # 先不激活
- )
- conv_pool_1 = fluid.layers.batch_norm(conv_pool_1) # BN
- conv_pool_1 = fluid.layers.relu(conv_pool_1) # 激活
- # 第二个卷积-池化层
- conv_pool_2 = fluid.nets.simple_img_conv_pool(
- input=conv_pool_1,
- filter_size=3,
- num_filters=40,
- pool_size=2,
- pool_stride=1,
- act=None
- )
- conv_pool_2 = fluid.layers.batch_norm(conv_pool_2) # BN
- conv_pool_2 = fluid.layers.relu(conv_pool_2) # 激活
- # 第三个卷积-池化层
- conv_pool_3 = fluid.nets.simple_img_conv_pool(
- input=conv_pool_2,
- filter_size=3,
- num_filters=60,
- pool_size=2,
- pool_stride=2,
- act=None
- )
- conv_pool_3 = fluid.layers.batch_norm(conv_pool_3) # BN
- conv_pool_3 = fluid.layers.relu(conv_pool_3) # 激活
- # 全连接层 fc160_1
- fc160_1 = fluid.layers.fc(input=conv_pool_3, size=160)
- # 第四个卷积层(无池化)
- conv_4 = fluid.layers.conv2d(
- input=conv_pool_3,
- num_filters=128,
- filter_size=3,
- act=None # 先不激活
- )
- conv_4 = fluid.layers.batch_norm(conv_4) # BN
- conv_4 = fluid.layers.relu(conv_4) # 激活
- # 全连接层 fc160_2
- fc160_2 = fluid.layers.fc(input=conv_4, size=160)
- # 合并全连接层
- fc160 = fluid.layers.elementwise_add(fc160_1, fc160_2, act="relu") # 必须保留
- # 全连接输出层
- prediction = fluid.layers.fc(input=fc160, size=classNumber, act='softmax')
- return prediction
复制代码 卷积层:提取人脸的局部特征。
池化层:降维并增强特征的鲁棒性。
全连接层:将高维特征映射到种别空间。
末了一层无激活函数:输出的是人脸特征向量,而不是直接的分类结果。
DeepID 与 CNN 网络结构的差异
特性CNNDeepID网络结构通用结构,适用于多种视觉任务专为人脸辨认筹划,提取高维特征输入数据通用图像数据(如分类任务中的物体图像)固定大小的人脸图像(如 112x112 或 128x128)输出种别概率(分类任务)高维特征向量(用于相似性盘算)练习目标最大化正确种别的概率(交叉熵丧失等)学习高维、鉴别性强的人脸特征,联合团结贝叶斯模型优化特征空间后续处置惩罚直接输出结果(如分类标签)特征向量用于人脸验证或聚类,通常联合团结贝叶斯模型应用场景图像分类、目标检测、语义分割等人脸辨认、人脸验证、人脸聚类等 总结:
CNN 是一种通用框架,适用于多种视觉任务,网络结构和练习目标灵活多样。
DeepID 是一种专用网络,专注于人脸辨认任务,通过网络提取高维特征并联合团结贝叶斯模型优化特征空间。
3 深度学习模型练习和推理的焦点设置
- def setPredictor(learning_rate =0.0001):
-
- image = fluid.layers.data(name='image', shape=[3, IMG_H, IMG_W], dtype='float32')#接收形状为 【3,H,W】 的输入图像
- label = fluid.layers.data(name='label', shape=[1], dtype='int64')#接收形状为 1 的标签
-
- # 建立网络
- # predict = convolutional_neural_network(image, classNumber)
- predict = DeepID(image, classNumber)
-
-
- ###################################################################################
-
- # 获取损失函数和准确率
- cost = fluid.layers.cross_entropy(input=predict, label=label) # 交叉熵
- avg_cost = fluid.layers.mean(cost) # 计算cost中所有元素的平均值
- acc = fluid.layers.accuracy(input=predict, label=label) #使用输入和标签计算准确率
-
- # 定义优化方法
- # optimizer =fluid.optimizer.Adam(learning_rate=learning_rate)
- # optimizer.minimize(avg_cost)
- # 定义带动量的 SGD 优化器
- optimizer = fluid.optimizer.Momentum(
- learning_rate=learning_rate,
- momentum=0.9,
- regularization=fluid.regularizer.L2Decay(regularization_coeff=1e-4)
- )
- optimizer.minimize(avg_cost)
-
-
- # 定义优化器时添加梯度裁剪 正则:原le-4 改成 le-3
- # optimizer = fluid.optimizer.Momentum(
- # learning_rate=learning_rate,
- # momentum=0.9,
- # regularization=fluid.regularizer.L2Decay(1e-4),
- # grad_clip=fluid.clip.GradientClipByGlobalNorm(clip_norm=5.0) # 全局范数裁剪
- # )
- # optimizer.minimize(avg_cost)
-
- # 定义使用CPU还是GPU,使用CPU时USE_CUDA = False,使用GPU时USE_CUDA = True
- place = fluid.CUDAPlace(0) if USE_CUDA else fluid.CPUPlace()
-
- # 创建执行器,初始化参数
- exe = fluid.Executor(place) #就像请一个厨师(执行器)按照菜谱(模型结构)在指定的厨房(CPU或GPU)里做菜。
- exe.run(fluid.default_startup_program()) #运行模型的“启动程序”,初始化所有参数(比如神经网络的权重和偏置)
- feeder = fluid.DataFeeder( feed_list=[image, label],place=place)#创建一个“数据喂入器”,负责将输入数据(如图像和标签)传递给模型
-
- # 获取测试程序
- test_program = fluid.default_main_program().clone(for_test=True)
-
- return image, label, predict, avg_cost, acc, exe, feeder, test_program
- ###################################################################################
- image, label, predict, avg_cost, acc, exe, feeder, test_program = setPredictor(LEARNING_RATE)
复制代码 4 制图
- import matplotlib.pyplot as plt
- import numpy as np
- def draw_figure(dictCostAccdictCostAcc, xlabel, ylabel_1, ylabel_2):
- plt.xlabel(xlabel, fontsize=20)
- plt.plot(dictCostAcc[xlabel], dictCostAcc[ylabel_1],color='red',label=ylabel_1)
- plt.plot(dictCostAcc[xlabel], dictCostAcc[ylabel_2],color='green',label=ylabel_2)
- plt.legend()
- plt.grid()
- def draw_train_process(epoch, dictCostAcc):
- # train的cost与accuray的变化
- plt.figure(figsize=(10, 3))
- plt.title('epoch - ' + str(epoch), fontsize=24)
- plt.subplot(1,3,1)
- draw_figure(dictCostAcc, 'iteration', 'iter_cost', 'iter_acc')
- plt.subplot(1,3,2)
- draw_figure(dictCostAcc, 'epoch', 'cost_train', 'cost_test')
- plt.subplot(1,3,3)
- draw_figure(dictCostAcc, 'epoch', 'acc_train', 'acc_test')
- plt.show()
复制代码 draw_figure() 功能:
绘制单个子图,展示两个指标的变化曲线。
通过 dictCostAcc 提供的数据绘制曲线,dictCostAcc 是一个字典,包罗练习过程中的各种指标(如丧失和准确率)
参数:
dictCostAcc
一个字典,包罗练习过程中的数据。
键是指标名称(如 ‘iteration’、‘iter_cost’ 等),值是对应的数值列表
xlabel
X 轴的标签(如 ‘iteration’ 或 ‘epoch’)。
两个 Y 轴的指标名称(如 ‘iter_cost’ 和 ‘iter_acc’)。
draw_train_process()
功能
绘制整个练习过程的指标变化,包罗:
每个迭代的丧失和准确率。
每个 epoch 的练习和测试丧失。
每个 epoch 的练习和测试准确率。
使用 matplotlib 的子图功能,将三个指标绘制在同一张图中。
5 练习
- all_train_iter=0
- all_train_iters=[]
- all_train_costs=[]
- all_train_accs=[]
- # 记录迭代过程中,每一个epoch的平均cost与accuracy
- epoch_train_costs = []
- epoch_test_costs = []
- epoch_train_accs = []
- epoch_test_accs = []
- train_reader, test_reader = createDataReader(BATCH_SIZE)
- if not os.path.exists(model_save_dir):
- os.makedirs(model_save_dir)
- print('开始训练...')
- for pass_id in range(TRAIN_NUM):
- # train_reader, test_reader = createDataReader(BATCH_SIZE)
- print("epoch %d -------------" % pass_id)
- train_accs = [] #训练的损失值
- train_costs = [] #训练的准确率
- for batch_id, data in enumerate(train_reader()): #遍历train_reader的迭代器,并为数据加上索引batch_id
- train_cost, train_acc = exe.run(
- program=fluid.default_main_program(), #运行主程序
- feed=feeder.feed(data), #喂入一个batch的数据
- fetch_list=[avg_cost, acc]) #fetch均方误差和准确率
- all_train_iter=all_train_iter+BATCH_SIZE
- all_train_iters.append(all_train_iter)
- all_train_costs.append(train_cost[0])
- all_train_accs.append(train_acc[0])
- train_costs.append(train_cost[0])
- train_accs.append(train_acc[0])
- if batch_id % 50 == 0: #每10次batch打印一次训练、进行一次测试
- print("\tPass %d, Step %d, Cost %f, Acc %f" %
- (pass_id, batch_id, train_cost[0], train_acc[0]))
-
- epoch_train_costs.append(sum(train_costs) / len(train_costs)) #每个epoch的cost
- epoch_train_accs.append(sum(train_accs)/len(train_accs)) #每个epoch的acc
- print('\t\tTrain:%d, Cost:%0.5f, ACC:%0.5f' % (pass_id, epoch_train_costs[-1], epoch_train_accs[-1]))
-
- # 开始测试
- test_accs = [] #测试的损失值
- test_costs = [] #测试的准确率
- # 每训练一轮 进行一次测试
-
- for batch_id, data in enumerate(test_reader()): # 遍历test_reader
- test_cost, test_acc = exe.run(program=test_program, # #运行测试主程序
- feed=feeder.feed(data), #喂入一个batch的数据
- fetch_list=[avg_cost, acc]) #fetch均方误差、准确率
- test_accs.append(test_acc[0]) #记录每个batch的误差
- test_costs.append(test_cost[0]) #记录每个batch的准确率
- epoch_test_costs.append(sum(test_costs) / len(test_costs))
- epoch_test_accs.append(sum(test_accs) / len(test_accs))
- print('\t\tTest:%d, Cost:%0.5f, ACC:%0.5f' % (pass_id, epoch_test_costs[-1], epoch_test_accs[-1]))
- if pass_id < 3:
- continue
- else:
- dictCostAcc = {}
- dictCostAcc['iteration'] = all_train_iters
- dictCostAcc['iter_cost'] = all_train_costs
- dictCostAcc['iter_acc'] = all_train_accs
- dictCostAcc['epoch'] = list(range(pass_id+1))
- dictCostAcc['cost_train'] = epoch_train_costs
- dictCostAcc['cost_test'] = epoch_test_costs
- dictCostAcc['acc_train'] = epoch_train_accs
- dictCostAcc['acc_test'] = epoch_test_accs
- draw_train_process(pass_id, dictCostAcc)
- # draw_train_process("training",all_train_iters,all_train_costs,all_train_accs,"trainning cost","trainning acc","iter",'cost/acc')
- print('\n')
-
- if pass_id % 5 == 0:
- # 每5个epoch保存一个模型
- model_dir = os.path.join(model_save_dir,str(pass_id))
- if not os.path.exists(model_dir):
- os.makedirs(model_dir)
- fluid.io.save_inference_model(model_dir, ['image'], [predict], exe)
- print('第%d个epoch的训练模型保存完成!'%pass_id)
复制代码 1 变量初始化
- all_train_iter = 0
- all_train_iters = []
- all_train_costs = []
- all_train_accs = []
- epoch_train_costs = []
- epoch_test_costs = []
- epoch_train_accs = []
- epoch_test_accs = []
复制代码 功能:初始化变量,用于记录练习和测试过程中的丧失和准确率。
变量分析:
all_train_iter:记录总的迭代次数。
all_train_iters:记录所有练习迭代的索引(累积的 batch 数)。
all_train_costs:记录每个 batch 的练习丧失。
all_train_accs:记录每个 batch 的练习准确率。
epoch_train_costs:记录每个 epoch 的平均练习丧失。
epoch_test_costs:记录每个 epoch 的平均测试丧失。
epoch_train_accs:记录每个 epoch 的平均练习准确率。
epoch_test_accs:记录每个 epoch 的平均测试准确率。
2 数据读取器
- train_reader, test_reader = createDataReader(BATCH_SIZE)
复制代码 功能:创建练习和测试数据读取器。
createDataReader(BATCH_SIZE):
自定义函数,返回练习和测试数据的迭代器。
BATCH_SIZE:每个 batch 的样本数量。
3. 模型保存目录
- if not os.path.exists(model_save_dir):
- os.makedirs(model_save_dir)
复制代码 功能:查抄模型保存目录是否存在,如果不存在则创建。 model_save_dir:模型保存的路径。
4. 练习过程
- for pass_id in range(TRAIN_NUM):
- print("epoch %d -------------" % pass_id)
- train_accs = []
- train_costs = []
复制代码 功能:开始练习过程,TRAIN_NUM 是总的练习轮数(epoch)。
变量分析:
pass_id:当前是第几个 epoch。
train_accs:记录当前 epoch 的所有 batch 的练习准确率。
train_costs:记录当前 epoch 的所有 batch 的练习丧失。
4.1 遍历练习数据
- for batch_id, data in enumerate(train_reader()):
- train_cost, train_acc = exe.run(
- program=fluid.default_main_program(),
- feed=feeder.feed(data),
- fetch_list=[avg_cost, acc]
- )
复制代码 功能:遍历练习数据读取器,逐 batch 进行练习。
train_reader():
返回练习数据的迭代器,每次迭代返回一个 batch 的数据。
exe.run:
运行主程序,执行前向流传和反向流传。
program=fluid.default_main_program():指定运行的程序。
feed=feeder.feed(data):将当前 batch 的数据喂入模型。
fetch_list=[avg_cost, acc]:获取练习的丧失和准确率。
train_cost 和 train_acc:
train_cost:当前 batch 的练习丧失。
train_acc:当前 batch 的练习准确率。
4.2 记录练习数据
- all_train_iter += BATCH_SIZE
- all_train_iters.append(all_train_iter)
- all_train_costs.append(train_cost[0])
- all_train_accs.append(train_acc[0])
- train_costs.append(train_cost[0])
- train_accs.append(train_acc[0])
复制代码 功能:记录每个 batch 的练习数据。
all_train_iter:累积迭代次数,每次增加一个 batch 的样本数(BATCH_SIZE)。
all_train_iters:记录总的迭代次数。
all_train_costs 和 all_train_accs:记录所有 batch 的练习丧失和准确率。
train_costs 和 train_accs:记录当前 epoch 的所有 batch 的练习丧失和准确率。
4.3 打印练习信息
- if batch_id % 50 == 0:
- print("\tPass %d, Step %d, Cost %f, Acc %f" %
- (pass_id, batch_id, train_cost[0], train_acc[0]))
复制代码 功能:每 50 个 batch 打印一次练习信息。
打印内容:
当前 epoch (pass_id)。
当前 batch 的索引 (batch_id)。
当前 batch 的练习丧失 (train_cost[0])。
当前 batch 的练习准确率 (train_acc[0])。
4.4 盘算并记录每个 epoch 的平均丧失和准确率
- epoch_train_costs.append(sum(train_costs) / len(train_costs))
- epoch_train_accs.append(sum(train_accs) / len(train_accs))
复制代码 功能:盘算当前 epoch 的平均练习丧失和准确率,并记录下来。
5. 测试过程
- for batch_id, data in enumerate(test_reader()):
- test_cost, test_acc = exe.run(
- program=test_program,
- feed=feeder.feed(data),
- fetch_list=[avg_cost, acc]
- )
- test_accs.append(test_acc[0])
- test_costs.append(test_cost[0])
复制代码 功能:遍历测试数据读取器,逐 batch 进行测试。
test_reader():返回测试数据的迭代器,每次迭代返回一个 batch 的数据。
exe.run:运行测试程序,获取测试的丧失和准确率。
test_cost 和 test_acc:当前 batch 的测试丧失和准确率。
test_costs 和 test_accs:记录所有 batch 的测试丧失和准确率。
5.1 盘算并记录每个 epoch 的平均测试丧失和准确率
- epoch_test_costs.append(sum(test_costs) / len(test_costs))
- epoch_test_accs.append(sum(test_accs) / len(test_accs))
复制代码 功能:盘算当前 epoch 的平均测试丧失和准确率,并记录下来。
6 打印练习和测试信息
- print('\t\tTrain:%d, Cost:%0.5f, ACC:%0.5f' % (pass_id, epoch_train_costs[-1], epoch_train_accs[-1]))
- print('\t\tTest:%d, Cost:%0.5f, ACC:%0.5f' % (pass_id, epoch_test_costs[-1], epoch_test_accs[-1]))
复制代码 功能:打印当前 epoch 的平均练习丧失和准确率,以及测试丧失和准确率。
7. 可视化练习过程
- if pass_id < 3:
- continue
- else:
- dictCostAcc = {
- 'iteration': all_train_iters,
- 'iter_cost': all_train_costs,
- 'iter_acc': all_train_accs,
- 'epoch': list(range(pass_id+1)),
- 'cost_train': epoch_train_costs,
- 'cost_test': epoch_test_costs,
- 'acc_train': epoch_train_accs,
- 'acc_test': epoch_test_accs
- }
- draw_train_process(pass_id, dictCostAcc)
复制代码 功能:从第 4 个 epoch 开始,定期可视化练习过程。
dictCostAcc:
构造一个字典,包罗练习和测试的所有数据。
键值对:
‘iteration’:总的迭代次数。
‘iter_cost’:每个 batch 的练习丧失。
‘iter_acc’:每个 batch 的练习准确率。
‘epoch’:当前的 epoch 数。
‘cost_train’:每个 epoch 的平均练习丧失。
‘cost_test’:每个 epoch 的平均测试丧失。
‘acc_train’:每个 epoch 的平均练习准确率。
‘acc_test’:每个 epoch 的平均测试准确率。
2.draw_train_process:
调用可视化函数,绘制练习过程的曲线。
8. 定期保存模型
- if pass_id % 5 == 0:
- model_dir = os.path.join(model_save_dir, str(pass_id))
- if not os.path.exists(model_dir):
- os.makedirs(model_dir)
- fluid.io.save_inference_model(model_dir, ['image'], [predict], exe)
- print('第%d个epoch的训练模型保存完成!' % pass_id)
复制代码 功能:每 5 个 epoch 保存一次模型。
model_dir:
模型保存的路径,包罗当前 epoch 的编号。
fluid.io.save_inference_model:
保存推理模型,供后续推理使用。
参数:
model_dir:模型保存的路径。
[‘image’]:输入数据的名称。
[predict]:需要保存的模型变量。
exe:执行器。
打印信息:
打印模型保存完成的提示。
6 预测+结果
- def createInfer():
- global USE_CUDA
- place = fluid.CUDAPlace(0) if USE_CUDA else fluid.CPUPlace()
- infer_exe = fluid.Executor(place)
- inference_scope = fluid.core.Scope()
- return infer_exe, inference_scope
-
- def load_image(path):
- global IMG_H, IMG_W
- img = paddle.dataset.image.load_and_transform(path,IMG_H,IMG_W, False).astype('float32')
- img = img / 255.0
- img = np.expand_dims(img, axis=0)
- return img
- def getClassList(path):
- with open(path,'r') as load_f:
- new_dict = json.load(load_f)
- return new_dict['all_class_name']
-
- def predImgs(pathImgList, optimalEpoch):
- pred_label_list = []
- pred_class_list = []
- modelpath = os.path.join(model_save_dir, str(optimalEpoch))
- for pathImg in pathImgList:
- infer_exe, inference_scope = createInfer()
- with fluid.scope_guard(inference_scope):
- #从指定目录中加载 推理model(inference model)
- [inference_program, # 预测用的program
- feed_target_names, # 是一个str列表,它包含需要在推理 Program 中提供数据的变量的名称。
- fetch_targets] = fluid.io.load_inference_model(modelpath,#fetch_targets:是一个 Variable 列表,从中我们可以得到推断结果。
- infer_exe) #infer_exe: 运行 inference model的 executor
-
- img = Image.open(pathImg)
- plt.imshow(img)
- plt.show()
-
- img = load_image(pathImg)
-
- results = infer_exe.run(inference_program, #运行预测程序
- feed={feed_target_names[0]: img}, #喂入要预测的img
- fetch_list=fetch_targets) #得到推测结果
- # print('results',results)
- # print('results[0]',np.argmax(results[0]))
- label_list = getClassList(os.path.join(dataRootPath,'readme.json'))
- pred_label = np.argmax(results[0])
- pred_class = label_list[np.argmax(results[0])]
- print("infer results: %s" % label_list[np.argmax(results[0])])
- pred_label_list.append(pred_label)
- pred_class_list.append(pred_class)
- return pred_label_list, pred_class_list
- pathcat = 'data/test/100.jpg'
- pathdog = 'data/test/1000.jpg'
- predImgList = ['data/test/'+str(x)+'.jpg' for x in range(1,29)]
- predImgs(predImgList,95)
复制代码 练习时间的图像:



好啦根本的就介绍到这里啦!!!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |