基于Python的图像分类 项目实践——图像分类项目https://blog.csdn.net/aiqq136/article/details/114597818
一、采用百度aistudio在线环境(基于Notebook的python环境)
网址:https://aistudio.baidu.com/
实验环境
启动环境后,选择基础版。高级版的只需要在迁移训练项目时使用
启动环境后的notebook
操作参考解说视频和操作指南
https://ai.baidu.com/ai-doc/AISTUDIO/sk3e2z8sb
第一部分 预训练模型比较(狗狗图像分类)
描述:根据实践指导,选择paddlepaddle中使用Imagenet训练好的预训练模型,对狗狗的类别做分类测试,并比较3个预训练模型的各项指标(指导里有指标项)
第二部分 迁移训练
描述:使用第一部分选出的模型做finetune迁移训练,并使用自己搜集的50张图片作测试,记录模型准确率
第三部分 数据集增强
描述:对数据集每张图片做矩阵运算,然后再次重新选择X模型使用增强的数据集做训练,再测试自己搜集的50张图片的准确率,和第二部分任务做比较)
有40张大部分是狗狗图像文件,已经有人为其做了类别命名,但是存在错误。我们需要使用已经训练好的神经网络,对图片进行识别后,将图片进行正确的分类。
最终实践目标
• 通过使用 Python 从计算方面解决复杂的问题,提高编程技能。
• 学会使用深度学习模型(已经训练好的模型)。
◆ 除了编程任务之外,还需要同学们画出每个任务的详细流程图
◆ 合作方式:三人一组,终期汇报(4分钟),合作完成项目报告
◆ 提交方式:百度平台(程序内容和项目报告,报告模板后期上传)
资源文件解释
• 主程序名称: classify_dog_project
• 需要识别的图像文件夹: pet_image(有小狗的和非小狗的)
• 调用的CNN模型可识别的1000种种类(有小狗及其他种类)名称:
imagenet1000_clsid_to_human.txt,共有 1000 个标签,其中有118 个
不同的小狗品种标签:151:吉娃娃到 268:墨西哥无毛狗
• 210种小狗品种:dognames.txt。这个文件包含了分类器函数和宠物图像标签的所有可能狗品种
第一部分的实践项目的需要做的六个编程任务:
• 任务一:计算代码的运行时间(在项目中标记为TODO1的部分)
• 任务二:为宠物图像创建图像标签
• 任务三:使用CNN模型输出的结果为40张图像分类
• 任务四:通过提取的标签识别图像为小狗或者非小狗
• 任务五:统计图像情况
• 任务六:统计模型分类效果
同时完成任务一到任务四的流程图
• 任务的主体代码在check_images模块里,在此模块:添加计算程序运行时间的相应代码(也就是标记为TODO1的地方)。
编写完毕后,该代码将计算程序的总运行时间。后续该代码将衡量三个算法中的每个算法对pet_images 文件夹中的所有图像进行分类所需的时间。
• 编写完运行时间计算的代码后,通过使用sleep()函数测试计算运行时间的代码是否运行正确。
• 时间模块的测试包括以下内容:在 sleep() 函数中设置不同的值(秒),检查时长和时间格式。
导入 Time 模块
要在 python 中计算代码运行时间,需要从 python time 模块 导入 time() 函数。
为了模拟程序运行一段特定的时间,我们将使用 time 模块的 sleep() 函数。它将使程序暂停执行一定的秒数。
因为我们只需使用 time() 和 sleep() 函数,我们将仅导入这两个函数,而不是导入整个 time 模块。
仅从模块中导入所需的函数可以节省程序运行所需的内存 (RAM)。
此类导入如下所示:from time import time, sleep
使用 Time 和 Sleep 函数 要计算代码运行时间,需要:
• 首先,创建一个变量来记录开始时间 (start_time),即你要开始记录代码运行时间的点
• 接着,创建一个变量来记录结束时间 (end_time),即你要停止记录代码运行时间的点
• 最后,计算总运行时间 (tot_time):将 end_time 减去 start_time。tot_time 是指代码的总运行时间(以秒记)
以下代码演示了如何使用 time() 和 sleep()。 sleep(75)用来使程序暂停 75 秒。要
计算实际代码的运行时间,请将 sleep(75) 替换为要计算运行时间的代码。
#Sets start time
start_time = time()
#Replace sleep(75) below with code you want to time
sleep(75)
#Sets end time
end_time = time()
#Computes overall runtime in seconds
tot_time = end_time - start_time
#Prints overall runtime in seconds
print("\nTotal Elapsed Runtime : ", tot_time,"in seconds.")
• 计算时间后,还需要将运行时间设置成时间格式,例如hh:mm:ss,其中hh 表示两位数的小时数 mm 表示两位数的分钟数 ss 表示两位数的秒数
• 确定总运行时间(即tot_time)的格式
hours = int( (tot_time / 3600) )
minutes = int( ( (tot_time % 3600)/ 60 ) )
seconds = int ( ( (tot_time % 3600)% 60 ) )
下面的代码将以 hh:mm:ss 格式输出运行时间
print("\nTotal Elapsed Runtime:", str( int( (tot_time / 3600)) ) + ":"+
str( int( ( (tot_time % 3600)/ 60 ) ) ) +":"+
str( int(( (tot_time % 3600)% 60 ) ) ) )
注意 代码使用 int() 函数并截断秒数的值,而不是四舍五入到最近的秒数。也就是说,如果总运行时间为 4.519087974567,则格式变成总运行时间: 0:0:4。
如果你想四舍五入到最近的秒数,在计算上面的秒数时,需要将 int() 函数替换为 round() 函数。
任务2(TODO 2)的主要内容
• 需要编写完成模块get_pet_labels。
•在这个函数里,需要使用 pet_images 文件夹中的宠物图像的文件名为宠物图像创建名字标签。这些宠物图像标签是前期标示,用于展示宠物图像中的动物品种;因此,它们代表了“真实结果”的标签。
• 编写完毕后,需要函数返回一个字典,字典里包含了pet_image 文件夹中的所有40个宠物图像的键值对:键是宠物图像文件名,值是宠物图像标签。
• 然后回到主程序模块,调用get_pet_labels
主程序模块:
# 此处是主程序模块,任务一的内容在此模块中编写
# 另外五个任务的内容,需要在这段主程序代码中调用不同的任务函数完成
# Python不会像C语言一样,标示出MAIN程序来代表主程序。
# 可以直接理解这段代码是我们分类项目的主程序
# classify_dog_project
from time import time, sleep
from os import listdir
# TODO: 1.
#definition,主要是定义宠物图像文件夹,模型名称(后面要比较不同的模型,所以模型名称会被修改),小狗名称定义文件的名称
classify_dir='pet_images/'
arch='vgg'
dogfile='dognames.txt'
#Sets start time
start_time = time()
#Replace sleep(75) below with code you want to time
sleep(2)
#Sets end time
end_time = time()
#Computes overall runtime in seconds
tot_time = end_time - start_time
#Prints overall runtime in seconds
print("\nTotal Elapsed Runtime : ", tot_time,"in seconds.")
hours = int( (tot_time / 3600) )
minutes = int( ( (tot_time % 3600)/ 60 ) )
seconds = int ( ( (tot_time % 3600)% 60 ) )
print("\nTotal Elapsed Runtime:", str( int( (tot_time / 3600)) ) + ":"+
str( int( ( (tot_time % 3600)/ 60 ) ) ) +":"+
str( int(( (tot_time % 3600)% 60 ) ) ) )
# TODO: 2.
answers_dic = get_pet_labels()
# TODO: 3.
result_dic = classify_images()
# TODO: 4.
adjust_results4_isadog()
# TODO: 5.
results_stats_dic = calculates_results_stats()
# TODO: 6.
print_results()
# TODO: 1. 输出最终运行时长格式为 hh:mm:ss
get_pet_labels函数模块:
# 任务2的内容:TODO 2
def get_pet_labels():
"""
这个函数需要最终返回一个基于狗狗图像文件名字的字典。
需要将宠物图像文件名读取后并提取当前宠物图像类别标签。
这个标签最后的作用是用于和我们网络分类结果进行比较,并确定网络分类的正确率。
函数参数Parameters:
image_dir - 完整的文件夹路径,文件夹内存放的所有的待CNN模型识别的狗狗的图像。
函数返回值Returns:
petlabels_dic - 一个存储了图片文件名作为字典KEY,和宠物当前文件名标签作为Value的字典。
"""
pass
如何读取文件夹中的文件
文件夹 pet_images/ 包含 40 个用于测试神经网络的图像。pet_images/ 中的图像
文件名标识了每张图像的动物。要为宠物图像创建标签,需要:
1. 读取 pet_image/ 文件夹中的所有文件的名称
2. 处理文件名以创建宠物图像标签
3. 根据分类器函数的标签和dognames.txt中小狗的名称,调整宠物图像标签的格式该函数的第一个任务是从文件夹中读取文件名。
要完成此任务,只需从 os 这个python 模块中导入 listdir 方法。listdir 方法会从文件夹中的文件中检索所有文件名,然后将这些文件名当做列表返回。以下代码演示了如何进行此导入和检索操作。
#Imports only listdir function from oS module
from os import listdir
# Retrieve the filenames from folder pet_images/
filename_list = listdir("pet_images/")
#Print 10 of the filenames from folder pet_images/
print(" \nPrints 10 filenames from folder pet_images/")
for idx in range(0,10,1):
print("%2d file: %-25s" % (idx + 1, filename_list[idx]))
字典知识回顾
• 任务2最终需要构建的是以宠物图像文件名(作为键)和相关标签(作为值)的字典数据结构。
• 字典的键值对是一个逻辑选择,我们后面需要使用分类器函数处理相同的文件名(键),并将返回的标签与宠物图像标签(值)进行对比。
如果我们使用字典,给定输入键后,检索相关值比从其他数据结构(例如列表)中检索值的速度要快
以下代码演示了使用python字典可以完成的操作,可以在编写此函数时作为参考
#Creates empty dictionary named pet_dic
pet_dic = dict()
# Determines number of items in dictionary
items_in_dic = len(pet_dic)
print("\nEmpty Dictionary pet_dic - n items=", items_in_dic)
# Adds new key-value pairs to dictionary ONLY when key doesn't already existkeys = ["beagle_0239.jpg", "Boston_terrier_02259.jpg"]
values = ["beagle", "boston terrier"]
for idx in range(0, len(keys),1):
if keys[idx] not in pet_dic:
pet_dic[keys[idx]] = values[idx]
else:
print("** Warning: Key=", keys[idx],
"already exists in pet_dic with value =", pet_dic[keys[idx]])
#Iterating through a dictionary printing all keys & their associated values
print("\nPrinting all key-value pairs in dictionary pet_dic:")
for key in pet_dic:
print("Key=", key," Value=", pet_dic[key])
宠物图像文件夹内容解释:
• 打开pet_images 文件夹,可以看到关于宠物图像的详情。宠物图像的文件名通常以图像名称_编号.jpg组成。以下是一些文件名示例:Basenji_00963.jpg、Boston_terrier_02259.jpg、gecko_80.jpg、fox_squirrel_01.jpg
• 在这个文件夹中共 40 张宠物图像,其中包含了30 张小狗图像和10 张非小狗动物图像,它们的文件名中,我们分析发现里面的信息有:
a) 图像的名称(标签)(需要用于比较),包含大小写字母和描述图像的一个或多个单词(标签),多个单词会用下划线 (_) 分隔
b) 数字值(不需要),以下划线 (_) 开头,以一系列数字 (0-9) 结束
c) 文件扩展名(不需要)以点 (.) 开始和以 jpg 结尾,项目只需要其中图像名称信息
宠物标签提取方案:
根据上述宠物图像文件名的详细信息,每个宠物图像名称的最佳格式为:
• 标签全部由小写字母组成
• 对于由多个单词组成的标签,用空格分隔每个单词
• 删除标签前后的空格
根据上述宠物图像文件名格式,我们可以使用字符串函数获得上述标签格式:
• lower() - 使字母全变成小写形式。
• split() - 返回字符串中的单词类别,单词按照提供给 split 函数的分隔符分离(划分)。如果没有提供分隔符,则用空格分离。
• strip() - 返回删除首尾字符的字符串。如果未传入任何字符,则删除首尾的空格。
• isalpha() - 如果字符串仅包含字母字符,则返回 true,否则返回 false。
宠物标签提取方案:
代码演示方案:
#Sets pet_image variable to a filename
pet_image = "Boston_terrier_02259.jpg"
#Sets string to lower case letters
low_pet_image = pet_image.lower()
#Splits lower case string by _ to break into words
word_list_pet_image = low_pet_image.split("_")
#Create pet_name starting as empty string
pet_name =""
#Loops to check if word in pet name is only
#alphabetic characters - if true append word
# to pet_name separated by trailing space
for word in word_list_pet_image:
if word.isalpha() :
pet_name += word + ""
# Strip off starting/trailing whitespace characters
pet_name = pet_name.strip(
#Prints resulting pet_name
print("\nFilename=", pet_image," Label=", pet_name)
如何读取文件夹中的文件
以下代码演示了如何进行此导入和检索操作。
# Imports only listdir function from oS module
from os import listdir
# Retrieve the filenames from folder pet_images/
filename_list = listdir("pet_images/")
#Print 10 of the filenames from folder pet_images/
print("\nPrints 10 filenames from folder pet_images/")
for idx in range(0,10,1):
print("%2d file: %-25s"% (idx + 1, filename_list[idx]))
对函数代码效果的测试:
现在已经可以开始任务2的内容了,回到上面的函数和代码模块,修改标记为TODO2的地方,然后画出该函数模块的流程图。并运行Check_image主体部分,
使得结果能够展示出以下测试内容:
• 添加一个临时输出语句,输出 get_pet_labels 函数返回的字典的前 10 个键值对,并输出该字典的长度。
• 字典包含 40 个键值对(例如字典长度为 40)。
• 宠物图像标签全小写,多个单词构成的宠物标签用一个空格区分每个单词,并且正确地标识了文件名
• 这个任务将要完成两个函数:
• 创建classifier函数,在该函数里调用CNN模型
• 在classify_images函数里使用classifier函数为宠物图像创建标签。
• 然后将分类器计算的标签与原始的宠物图像标签进行比较。
• 最后,使用 classify_images 返回数据结构存储宠物图像标签、分类器生成的标签和标签比较结果(列表字典结构)。
这个列表字典结构:键是宠物图像文件名,每个值是针对 pet_image 文件夹中所有 40 张宠物图像的列表。这个列表将包含以下条目:宠物图像标签(索引 0)、分类器标签(索引 1),以及标签比较结果(索引 2)。
了解CNN分类器¶
• 首先我们要了解的是这个任务中需要用到CNN分类器,也就是classifier这段代码。这段代码基本要求需要使用到paddlepaddle库里PaddleHub中已经训练好的的三个cnn模型:resnet18/alexnet/vgg16。
• 有了这段代码,就可以先参数选择的模型(resnet18/alexnet/vgg16三者中的某一个),传入一张图像,
然后将其识别为imagenet1000_clsid_to_human.txt这个文件标识出的某个类别(注意:这个文件是CNN模型可识别的1000个种类的标签文件)
分类器标签
imagenet1000_clsid_to_human.txt共有 1000 个标签,其中有118 个不同的小狗品种标签:151:吉娃娃到 268:墨西哥无毛狗
打开这个文件,我们可以看下里面小狗品种的标签格式,通常包含大小写字母,标签内容有三种情况:
• 只用一个单词标识图像,例如 beagle
• 用多个单词(以空格分隔)标识图像 例如 German shorthaired pointer
• 用几个不同的单词组(用英文逗号分隔)标识相同的图像 例如:
cocker spaniel, English cocker spaniel, cocker
Classifier函数如何编写?
1. 首先参考
https://aistudio.baidu.com/aistudio/projectdetail/361892里
提供的图像分类预训练模型的示例使用方案
2. 设计classifier函数,使其可以正确的传入图片,根据参数调用不同的CNN模型,然后返回识别结果
classify_images函数如何编写?
1. 获得classifier的标签
2. 处理两类标签
3. 比较两类标签并存储结果
如何对两个标签进行比较?并非简单的字符串判断,需要处理标签
处理分类器标签:
为了能够让分类器标签能够和我们的原始宠物标签进行比较,我们需要处理分类器返回给我们的宠物标签,将其处理为:
1. 标签全小写,且对于由多个单词组成的标签,用空格区分每个单词。
2. 去除标签首位的空格
处理分类器标签:
所以,对于分类器标签的处理包括以下步骤:
1. 将所有字母变成小写形式,并去除首尾的所有空格。
2. 如果标签是由一系列用逗号分隔的单词构成的,则需要使用find() 函数。宠物图像标签始终只有一个术语(即使该术语由多个单词构成);因此,如果在术语列表中发现构成分类器标签的一个术语,那么存在匹配项。
但是有时候 find 函数会出现完全不存在的标签匹配项。例如宠物图像标签是一个很短的字符串(例如cat),属于另一个术语(例如catamount)的一部分时,就会发生这种情况。
例如find() >= 0 也就是find函数找到了字符串,但不是匹配项的示例:
• cat_07.jpg 具有标签 cat,它可以匹配以下分类器标签:skunk, polecat,wood pussy and lynx catamount,但是实际上它们并不匹配。
• fox 匹配以下分类器标签:Walker hound, Walker foxhound and English
foxhound -- 但是它们也并不匹配。
所以需要增加一个条件语句,筛选出真正匹配的情形。
下面提供了两种真正匹配情形的伪代码。可以参考此伪代码的过程完成实现:
◼ 如果标签是一个单词组:
• 发现的单词组索引为0
• 宠物图像标签的长度与分类器标签的长度相符
• 伪代码:found_idx == 0 and len(pet_label) == len(classifier_label)
◼ 如果标签是多个单词组:
• 发现的单词组从索引 0 处开始,或者在开始之前具有空值
• 发现的单词组在分类器标签的结尾处结束,或者在发现的单词组的最后一个字母之
后具有空格或逗号
• 伪代码
((found_idx == 0) or (classifier_label[found_idx - 1] == " ") ) and( found_idx + len(pet_label) == len(classifier_label) ) or
classifier_label[found_idx + len(pet_label) :found_idx + len(pet_label)+1]in(" ",",")))
下面是分类器标签匹配可能会用到的字符串函数:
• lower() - 使字母全变成小写形式。
• strip() - 返回删除首尾字符的字符串。如果未传入任何字符,则删除首尾的空格。
• find() - 返回从字符串中找到子字符串(作为输入提供给函数)的最小索引。如果未发现该子字符串,返回值 -1。
• len() - 返回字符串的长度。
• string slicing - 例如: str[1:3]使其能够返回字符串的某个部分。
处理分类结果和比较结果
• 根据前面的描述,已经了解到,我们需要通过访问宠物图片,将图片文件地址传入分类器函数,
然后分类器函数会返回给我们一个分类的结果(也就是分类标签),然后我们需要处理这个分类标签之后,再将其和宠物的图片标签进行比较。
• 此后,将分类结果标签、图像标签、比较结果都存储进一个复合数据字典,然后将这个字典返回。前面已经编写完成的get_pet_labels 函数,返回是一个普通字典,键为文件名,值为宠物图像标签。
对于任务三的classify_image函数,接收的输入为petlabel_dic字典,也就是get_pet_labels 函数返回的字典(其中键为文件名,值为宠物图像标签)。
• 需要遍历该字典,使用分类器函数处理每个宠物图像(文件名),以获取分类器标签。
• 接着需要比较宠物图像和分类器标签,判断它们是否匹配。最后,需要将结果添加到此函数返回的字典 (results_dic) 中。
• (results_dic) 是一个列表字典
(results_dic) 列表字典格式将如下:
• 键 = 宠物图像文件名(例如 Beagle_01141.jpg)
• 值 = 满足以下条件的列表:
• 索引 0 = 宠物图像标签(例如 beagle)
• 索引 1 = 分类器标签(例如 english foxhound)
• 索引 2 = 0/1,其中 1 = 标签匹配,0 = 标签不匹配(例如 0)
例:example= {'Beagle_01141.jpg': ['beagle', 'english foxhound', 0]}
• 要初始化 results_dic 中的键,使用赋值运算符 ( = ) 分配列表的值。
• 要在 results_dic 中向该列表添加现有的键,使用 += 运算符或 append 函数向该列表附加值。
对任务三的函数classify_images 的编程建议:
• 在函数的开头(在遍历 petlabels_dic 之前)将结果字典 (results_dic) 创建为空字典
• 对于分类器函数,确保将 images_dir 与文件名相连,表示每个宠物图像文件的完整路径。
• 使分类器标签小写,去除标签首尾的空格。
• 最后检查后,确保找到的是正确的匹配项。
那么,现在已经可以开始任务3的内容了,回到上面的函数和代码模块,修改标记为TODO3的地方,然后画出该函数模块的流程图。并运行Check_image主体部分,然后进行以下测试内容:
• 添加输出语句,使用 classify_images 返回的字典输出分类器标签和宠物标签匹配(也就是索引2处值为1的情况)的所有情形。
• 此外,添加另一个输出语句,使用 classify_images 返回的字典输出分类器标签和宠物标签不匹配(也就是索引2处值为0)的所有情形。
建议遍历字典两次,用两个不同的群组输出匹配和不匹配的情形,这样检查起来更简单。需要检查以下内容:
• 分类器和宠物图像标签匹配的情形的确匹配
• 分类器和宠物图像标签不匹配的情形的确不匹配
• 匹配数和不匹配数加起来为 40,正好等于 pet_images 文件夹中的图像总数 40
任务四(todo4):通过标签识别图像为小狗或者非小狗-1
• 任务4的内容将要编写上面TODO4处的adjust_results4_isadog。此函数首先读取dognames.txt 文件,然后创建一个数据结构(字典)来存储从文件中获
取的有效的小狗名称,将小狗名称与任务3返回的字典 (resutlts_dic)中的分类器标签和宠物图像标签同时进行比较,然后调整结果字典,需要计算出这张图像是“小狗”或“非小狗”。
• **注意,adjust_results4_isadog 函数需要更改结果字典(results_dic),但是因为字典可变的,因此函数无需返回此字典。
通过标签识别图像为小狗或者非小狗-2
编写完毕后,这段代码将更改结果字典(results_dic,一个列表字典),列表字典中,每个宠物图像的列表现在将增加另外两项:宠物图像标签是小狗(索引 3)和分类器标签是小狗(索引 4)。
如何通过dognames.txt 判断是否是小狗-1
• 我们的任务是要标识出哪些图像是小狗图像,哪些图像不是小狗图像。有些小狗图像,还有可能将它的品种分类错误,但是它依旧是一张小狗图像。对于只要是小狗图像的文件,我们需要对其进行判断,找出这张图像的小狗品种是什么。dognames.txt文件由格式化的标签(全小写、去除首尾空格等)创建而成。可以打开该文件看下该文件的内容,示例:
chihuahua
japanese spaniel
maltese dog,maltese terrier,maltesepekinese,pekingese,peke
shih-tzu
blenheim spanielpapillon
toy terrier
rhodesian ridgeback
........
如何通过dognames.txt 判断是否是小狗-2
这个文件一共有210行,其中每行只包含一个狗品种名称。在我们的实验里,这个文件包含了分类器函数和宠物图像标签的所有可能狗品种将来自 dognames.txt小狗名称与之前我们标签比较时:
• 如果小狗名称与标签匹配,则标签为“是小狗”,设置为1
• 如果小狗名称与标签不匹配,则标签为“不是小狗,设置为0
读取 Dogsname.txt的方式
• 首先需要读取所有小狗名称并将它们存储在字典中,键是小狗名称,值是 1(任意值)。这里使用字典的原因:还是因为字典的查询速度很快。
• 我们可以直接将标签当做键在小狗名称字典中查询,发现为狗狗的所有标签。
• 如果有匹配项的话,标签应该与小狗名称完全匹配;
• 如果在狗狗名称字典中没有找到标签键,那么我们知道该标签不是狗狗。
• 前面已经学习过如何打开文件和读取文件信息,请复习此部分。
防止 adjust_results4_isadog 出现问题的编程建议:
• 在打开以读取 dognames.txt 文件之前定义 dognames_dic
• 使用 rstrip() 去除从 dognames.txt 读取的每行中的换行符
• 如果某个小狗名称已经存在于 dognames_dic 中,输出一条警告语句,因为不应在 dognames.txt 中发现任何重复的小狗名称
调整结果字典
• 将小狗名称读取到 dognames_dic 中后,下一步要做的是调整结果
字典 (results_dic),考虑标签何时正确/错误地分类为小狗。
• 借鉴前一个任务中的如何遍历结果字典,然后把值附加到结果字典中每个键的值列表中。
• 如果希望同时附加两种值,则需要使用 extend 同时将索引 3 和索引4 添加到 results_dic 中。
调整结果字典
results_dic 调整后的格式为:
• 键 = 宠物图像文件名(例如 Beagle_01141.jpg)
• 值 = 满足以下条件的列表(现在变为有四个值的列表):
• 索引 0 = 宠物图像标签(例如 beagle)
• 索引 1 = 分类器标签(例如 english foxhound)
• 索引 2 = 0/1,其中 1 = 标签匹配,0 = 标签不匹配(例如 0)
• 索引 3 = 0/1,其中 1= 宠物图像标签是小狗,0 = 宠物图像标签不是小狗(例如 1)
• 索引 4 = 0/1,其中 1= 分类器标签是小狗,0 = 分类器标签不是小狗(例如 1)
example= {'Beagle_01141.jpg': ['beagle', 'walker hound, walker foxhound', 0, 1, 1]}
那么,现在已经可以开始模块4的内容了,回到上面的函数和代码模块,修改标记为TODO4的
地方,然后画出该函数模块的流程图。并运行Check_image主体部分,然后进行测试内容:
测试内容
使用输出语句检查(建议遍历字典两次,用两个不同的群组输出匹配和不匹配的情形,这样检查
起来更简单):
• 使用 adjust_results4_isadog 返回的字典输出分类器标签和宠物图像标签匹配的情形。
• 使用 adjust_results4_isadog 返回的字典输出分类器标签和宠物标签不匹配的所有情形。
检查结果应该为:
• 分类器标签和宠物图像标签匹配的情形都将两种标签相应地分类为“小狗”或“非小狗”
• 分类器标签和宠物图像标签不匹配的情形分别将每个标签正确地分类为“小狗”或“非小狗”
• 匹配数和不匹配数加起来为 40,正好等于 pet_images 文件夹中的图像总数 40。
任务5:统计狗狗图像情况
这个部分将会涉及各项百分比计算结果。 即将编写的模块函数是:
calculates_results_stats。对于此函数:
• 接收的输入为results_dic(来自 adjust_results4_isadog 的列表字典),
• 返回该函数创建的结果统计信息字典 (results_stats)。
• 此结果字典将仅包含统计量的名称作为键,值将为统计量的数字值。
建议:在函数的第一行创建此字典,并在函数的最后一行返回值。
统计的内容包括:哪些是小狗图像,哪些不是小狗图像,同时针对小狗图像,能
够分辨其品种,我们的程序的准确率应该是多少等等数据?
需统计的内容:
回忆results_dic :{'Beagle_01141.jpg': ['beagle', 'walker hound, walker foxhound', 0, 1, 1]}
现在我们需要将results_dic这些计数和百分比统计出来,所有计数(例如 n_)
和百分比(例如 pct_)使用相同的前缀,统计的内容至少包括(可以扩展更多计数项):
• n_correct_dogs 图像是小狗的数量
• pct_correct_dogs 图像是小狗的比例
• n_correct_breed 品种分类正确的数量
• pct_correct_breed 品种分类正确的比例
函数最终生成的字典results_stats :
• 键 = 统计量的名称(例如 n_correct_dogs、pct_correct_dogs、n_correct_breed、pct_correct_breed)
• 值 = 统计量的值(例如 30、100%、24、80%)
• 例如:example_dictionary = {'n_correct_dogs': 30,'pct_correct_dogs': 100.0, 'n_correct_breed': 24,'pct_correct_breed': 80.0}
涉及到的计算变量包括:
• Z 图像数量:这是results_dic 的长度,因为文件名 = 键
• A 小狗匹配正确的数量:两个标签都是小狗:
results_dic[key][3] = 1 及 results_dic[key][4] = 1
• B 小狗图像的数量:宠物标签是小狗:results_dic[key][3] = 1
• C 正确非小狗匹配项的数量 两个标签都不是小狗:
results_dic[key][3] = 0 及 results_dic[key][4] = 0
• D 非小狗图像的数量
• 图像数量减去小狗图像数量 或者
• 宠物标签不是小狗:results_dic[key][3] = 0
• E 正确品种匹配项的数量 宠物标签是小狗并且标签匹配:
results_dic[key][3] = 1 及 results_dic[key][2] = 1
• Y 标签匹配项的数量 标签匹配:results_dic[key][2] = 1
需要计算的百分比有(对应前面统计量的字母标号)-1
• 正确分类的小狗图像所占百分比
• A:正确分类的小狗图像数量
• B:小狗图像数量
• 正确分类为小狗的图像所占百分比:A/B * 100
• 正确分类的非小狗图像所占百分比
• C:正确分类的非小狗图像数量。
• D:非小狗图像数量
• 正确分类为非小狗的图像所占百分比:C/D * 100
需要计算的百分比有(对应前面统计量的字母标号)-2
正确分类的小狗品种所占百分比
• E:正确分类为特定品种的_小狗_图像数量。
• B:_小狗_图像数量
• 正确分类的_小狗_品种图像所占百分比:E/B * 100
百分比标签匹配数(无论是否为小狗)
• Y:标签匹配数量
• Z:图像数量
• 正确匹配的图像所占百分比(无论是否为小狗):Y/Z * 10
重要事项:
• 计算前需要将所有计数初始化为 0。
• 使用条件语句检查被除数,防止除以 0的情况,
• 因为 results_stats 是在函数内创建的,并且是可变对象,所以需要在函数结束时返回它的值。
那么,现在已经可以开始模块5的内容了,回到上面的函数和代码
模块,修改标记为TODO5的地方,然后画出该函数模块的流程图。
并运行Check_image主体部分,然后进行以下测试内容:
• 测试内容
• 通过自己计数检查模块5的计算结果是否正确。
任务6:比较模型输出并显示结果¶
最后一个任务需要编写函数 print_results。此函数将输出 results_dic
(adjust_results4_isadog 中的列表字典)和结果统计字典(来自
calculates_results_stats 的 results_stats)。
输出结果
• 首先要输出语句,表示针对三个CNN模型架构中的哪个架构以及传入的哪个输
入参数 model。
• 接着,需要针对三个 CNN 模型架构都输出以下三项的计数。
• 图像数量+小狗图像数量+非小狗图像数量
任务6:比较模型输出并显示结果
最后,遍历 results_stats 字典并输出统计量的名称和所有百分比的值(例如以
字母“p”开头的键)。
• 百分比计算结果:
• 正确的小狗图像所占百分比
• 正确的品种图像所占百分比
• 正确的非小狗图像所占百分比
• 匹配项所占百分比(可选 - 包括小狗图像和非小狗图像)
• (可选)输出分类错误的项
• 可选功能旨在改善代码的调试性能。此外,可以使我们能够判断是否存在一些
每种算法都很难判断的小狗品种。
分类错误函数的默认参数
• 函数 print_results 包含两个默认参数,用于输出分类错误的小狗和品种。
默认参数:
• print_incorrect_dogs - 默认为 False
• print_incorrect_breed - 默认为 False
默认参数的目的是为函数提供范围更广的行为,无需编写多个(相似的)函
数。同时保证某些参数在函数中始终赋值。也为函数提供默认行为。
默认参数内容参考Python训练中函数部分
图像分类错误的小狗
• 如果两个标签对于图像是否为小狗的结论不一致,那么小狗分类结果不正确。
品种分类错误的小狗
• 当两个标签都表示图像是小狗,但是关于小狗的品种观点不一致,这种情况就属于小狗品种分类错误的情形。
• 在遍历 results_dic 以查找品种分类错误的情形前,需要使用条件语句检查用户是否希望输出品种分类错误的情形以及出现了品种分类错误的情形。
比较三个模型的效果
通过输出三个模型的百分比计算结果,可以比较得出,哪个模型在识别小狗图像和品种上表现的更好。可以从前面我们提出的任务目标的以下两个方面考虑:
• 正确标识哪些宠物图像是小狗图像(即使品种分类错误),哪些宠物图像不是小狗图像(无论图像是否分类正确)。
• 针对小狗图像正确判断小狗品种。
判断哪个 CNN 模型架构(ResNet、AlexNet 或 VGG)最合适实现以上两个目标,同时考虑三个模型所需的时间,并判断对于每个算法运行所花费的时间。
比较三个模型的效果
下面的表格给出了几个网络的比较示意,可以参考:
比较三个模型的效果
或者可以以统计图示的方式展示各个模型的不同比较参数:
• Seaborn
• Matplotlib
• Pygal
• Pyecharts
• ……
本图只是一个示意
这个任务不需要流程图,但是需要检查:
• 运行程序后,正确地输出了统计量和计数并且设定了正确的格式。计算结果的代码检查部分的结果应该与6个统计量输出的结果匹配。
• 在函数调用中保留两个默认参数,不输出分类错误的结果
• 在函数调用中为两个默认参数添加值 True,输出分类错误的结果(预期的行为)