Contents
[TOC]
在这个项目中,你将通过第三方的开源库连接到你的微信账号,并收集基本的好友信息,如性别、城市、个性签名等。你将使用之前课程中所学习到的 Python 编程技巧,对数据进行统计与分析。
项目内容在此链接中,你需要点击右上角的Clone or download
将其下载下来,并尝试使用 Jupyter Notebook 运行它。
在本项目中,你需要完成下面完成的任务:
- 登陆微信,并发送打招呼信息
- 统计你的微信好友的男女比例
- 分析微信好友的地域分布
- 生成微信好友的签名词云图
- 对签名进行情感分析
项目模板中的主要代码都已经写好,在大多数的场合下,你只需要直接运行代码,仅有少数需要你根据提示把代码补充完整即可。
本项目主要包含2个文件:
My Wechat Friends.ipynb
: 这是主文件,你将在此完成你的项目。wechat.jpg
: 这是项目中需要用到的图片,用于迁移词云的取色,你可以用任何你喜欢的图片来替换它
在这个项目中,你将通过一些工具包与前面学习到的知识,分析自己的身体数据,包括身高、体重等。之后,你将作为一名健身教练,分析你手下会员们的健康数据。在项目中,你将使用之前课程中所学习到的 Python 编程技巧,并接触一些新的知识,你准备好了吗?
项目内容的在线版本在第三节,你可以直接进入第三课进行学习。
而项目的本地版本在此链接中,你需要点击右上角的Clone or download
将其下载下来,并尝试使用 Jupyter Notebook 运行它。
在本项目中,你需要完成下面完成的任务:
- 工具包的引入
- 数据的录入
- 数据可视化
项目模板中的主要代码都已经写好,在大多数的场合下,你只需要直接运行代码,仅有少数需要你根据提示把代码补充完整即可。
本项目主要包含1个文件:
simple_data_analysis.ipynb
: 这是主文件,你将在此完成你的项目。
控制寻宝机器人
在本项目中,你将分析一个电影数据集,然后传达你的发现。你将使用 Python 库 NumPy、Pandas 、 Matplotlib 和 Seaborn 来使你的分析工作更加轻松。
你需要安装 Python 和以下库:
- pandas
- numpy
- matplotlib
此项目将向你介绍数据分析过程,以及所有工作的相互配合。后期的纳米学位将重点关注数据分析过程的各个环节。
你将使用 Python 库 NumPy、Pandas 和 Matplotlib,这些库使你能够更加轻松地在 Python 中编写数据分析代码!不仅如此,它们也是雇主们青睐的技能!
完成此项目后,你将:
- 了解典型数据分析过程中所涉及到的所有步骤
- 轻松提出可用给定数据集回答的问题,并解答这些问题。
- 了解如何调查数据集中的问题,以及将数据整理成你可以使用的格式
- 练习传达你的分析结果
- 能够在 NumPy 和 Pandas 中使用向量化运算,以加快数据分析代码的运行速度
- 熟悉 Pandas 的 Series 和 DataFrame 对象,它们能使你访问数据更方便
- 了解如何使用 Matplotlib 生成图形,展示你的发现
该项目与数据分析入门课程相关,但根据你的知识背景,你可能无需学习全部课程即可完成该项目。
介绍
在此项目中,你需要进行数据分析,并创建一个文档分享你的发现。你应该首先了解数据集,想想它可以用来回答哪些问题。然后使用 Pandas 和 NumPy 回答你最感兴趣的问题,并编写一份报告来分享你的结论。你不需要使用推论统计或机器学习知识来完成此项目,但是你需要在报告中声明,你的结论是暂时的,可能需要进一步改进。
第一步 - 选择数据集
可以通过以下链接进行数据集下载: TMDb电影数据
第二步 - 组织
你可以使用 Jupyter Notebook,这样,你可以在同一份文档中提交编写的代码和报告你的发现。
第三步 - 分析数据
思考你可以用数据集回答哪些问题,然后开始着手回答这些问题。 试着完成项目中的任务,你应该在你的调查里分析至少一个因变量和三个自变量。在恰当的地方使用 NumPy 和 Pandas。
第四步 - 分享发现
分析完数据以后,编写一份报告,分享你觉得最有意思的发现。如果你使用 Jupyter Notebook,则与你用于执行分析的代码一起分享发现。确保你的报告文本包含在 Markdown 单元中,以清楚地将你的注释和发现与代码分开。当然你也可以使用其他工具和软件来制作最终报告,但请确保你能以 HTML 或 PDF 文件的形式提交报告,以便轻松打开。
线性代数作为数学的一个分支,广泛应用于科学和工程中,掌握好线性代数对于理解和从事机器学习算法相关工作是很有必要的,尤其对于深度学习算法而言。因此,这个项目会从浅入深更好的帮助你学习与积累一些跟人工智能强相关的线性代数的知识。
项目内容在此链接中,你需要点击右上角的Clone or download
将其下载下来,并尝试使用 Jupyter Notebook 运行它。
-
提高
Python
编程技能在此项目中,你将使用一个已经创建好的图像分类器识别狗品种。我们希望你能重点学习 Python 编程知识,而不是实际分类器(我们将在课程的后续阶段专门构建一个分类器)
-
主要目标
- 正确标识哪些宠物图像是小狗图像(即使品种分类错误),哪些宠物图像不是小狗图像。
- 针对小狗图像正确判断小狗品种。
- 判断哪个 CNN 模型架构(ResNet、AlexNet 或 VGG)最能实现目标 1 和 2。
- 思考最能实现目标 1 和 2 所需的时间,并判断对于每个算法运行所花费的时间,是否有替代解决方案能够实现不错的结果。
你所在的城市即将举行一场全市狗狗秀,你志愿帮助举办方对报名的小狗进行分类。每位参赛狗主人都必须提交一张小狗图像,并附上小狗的简介信息。报名系统会根据简介信息对图像添加标签。
有些人打算用非小狗宠物报名。
你需要使用已经开发好的 Python 分类器检查确保参赛宠物是小狗。
注意,你不需要创建分类器,我们将提供给你。你需要运用所学的 Python 工具来使用该分类器。
-
你将运用 Python 技能判断哪个图像分类算法最适合将图像分类为“小狗”或“非小狗”。
-
判断最佳分类算法在正确识别狗品种方面的表现如何。 如果你不熟悉图像分类器一词,可以将它当做由输入和输出组成的工具。输入是图像,输出判断图像描绘的内容(例如狗)。注意,图像分类器有时候无法正确分类图像。(我们将在课程的后续阶段详细讲解这些知识)。
-
计算每个算法解决分类问题花费的时间。 对于计算任务,我们经常需要在准确率和运行时间之间做出权衡。算法越准确,就越有可能运行时间更长,并消耗更多的计算资源。
要了解详情,请参阅此常见问题解答。
对于此图像分类任务,你将使用一个图像分类应用,该应用采用了称为卷积神经网络(经常简称为 CNN)的深度学习模型。CNN 尤其适合检测图像中的特征,例如颜色、纹理和边;然后利用这些特征识别出图像中的对象。你将使用已经从一个庞大的数据库(有 120 万张图像,称为 ImageNet)中学习特征的 CNN。CNN 有多种不同的结构(架构)类型,对于你的应用条件,它们的效果可能很好,也可能很差。对于此项目,你将研究三个不同的架构(AlexNet、VGG 和 ResNet),并判断哪个最适合你。
我们在 classifier.py
中提供了一个分类器函数,使你能够使用这些 CNN 分类图像。test_classifier.py
文件包含一个演示如何使用分类器函数的示例程序。对于此项目,你将重点学习使用 Python 技能通过分类器函数完成这些任务;在神经网络课程中,你将深入学习这些算法的工作原理。
注意,某些狗品种看起来非常相似。算法从越多的两种外观相似的狗品种图像中学习规律,就越能够区分这两个品种。我们发现以下品种看起来很相似:大白熊犬和白警犬、德牧和 玛伦牧羊犬、比格犬和步行猎犬等等。
要修改的代码:
此部分将帮助你编写 get_input_args.py 中的函数 get_input_args。对于此函数,你将使用 argparse 从用户那获取三个命令行参数。(借助 argparse,你可以轻松地编写用户友好型命令行界面)。
- 编写函数定义
def get_input_args():
,请在 get_input_args.py 中的#TODO: 1
所指示的位置添加代码。
预期结果
编写完毕后,这段代码将输入用户提供的三个命令行参数。
检查代码
check_images.py 中的 check_command_line_arguments 函数将检查你的代码。
测试以下内容:
- 在终端窗口里运行 check_image.py 时不输入任何命令行参数,这样应该会导致输出默认值。
- 在终端窗口里运行 check_image.py 时输入你所选的命令行参数值,这样应该会导致输出你所输入的值。
项目 Workspace - 命令行参数
- 完成
#TODO: 1
- 你可以在项目 Workspace - 命令行参数中修改 check_image.py 和 get_input_args.py。
命令行参数的目的是使程序能够获得外部输入(命令行参数),从而提高程序的灵活性。关键在于这些外部参数可以改变,从而使程序具有更高的灵活性。
例如,假设你编写了一个程序,该程序会数一数文件的行数并将该数字输出到屏幕上。要使用户能够进入_任何文件,而不用更改程序,我们需要以命令行参数的形式传入文件位置。这样的话,该程序可以用在任何_文件上,因为值在运行时作为外部输入被传入。
我们将使用 argparse 模块将以下外部输入输入到程序 check_image.py 中。我们建议编写 get_input_args函数以使用 argparse 获取命令行参数。
以下是 check_image.py 程序从用户那获取输入所需的三个外部输入以及每个输入的建议_默认_值。
-
包含宠物图像的文件夹
- pet_images/
-
要使用的 CNN 模型架构
- resnet、alexnet 或 vgg(选一个作为默认值)。你将在 classifier.py 中找到这些模型。
-
包含有效小狗名称列表的文件
- dognames.txt
get_input_args 函数需要使用 argparse.ArgumentParser 创建一个参数解析器对象,然后使用 add_argument 方法以使用户能够输入上述三个外部输入。
以下示例演示了如何创建参数解析器对象,然后使用 add_argument 添加文件夹路径参数和第二个整数参数。
# Creates Argument Parser object named parser
parser = argparse.ArgumentParser()
# Argument 1: that's a path to a folder
parser.add_argument('--dir', type = str, default = 'pet_images/',
help = 'path to the folder of pet images')
以下是对 add_argument 输入的解释。
- 参数 1:
- --dir = 参数的变量名(本例中是 dir)
- type = 参数类型(本例中是字符串)
- default = 默认值(本例中是 'pet_images/')
- help = 用户输入程序名,然后输入 -h 或 --help 时出现的文本。使用户了解期望的参数值是什么。
要通过 argparse 对象访问传入程序中的参数,你需要使用 parse_args 方法。以下代码演示了如何通过扩展上述示例的 argparse 访问参数。
首先,你需要为 parse_args 分配一个变量,然后使用该变量访问 argparse 对象的参数。如果在函数内创建 argparse 对象,需要_返回_ parse_args,而不是为它分配一个变量。同时注意,变量 in_args 指向命令行参数集合。
这意味着要访问我们在上方代码里创建的参数,我们需要引用集合变量名 in_args,然后指定命令行参数变量名 dir
。对于此示例,名称是 in_args.dir,其中 in_args 是集合变量名,dir 是命令行参数变量名。注意,你需要用点 (.) 区分这两个变量名。以下代码演示了如何将 in_args 分配给我们的解析器,然后使用输出语句访问 in_args.dir 的值。
# Assigns variable in_args to parse_args()
in_args = parser.parse_args()
# Accesses values of Argument 1 by printing it
print("Argument 1:", in_args.dir)
要运行 check_images.py 这样的程序,首先在项目 Workspace 中打开终端窗口。然后输入以下命令并按下 Enter 键以运行程序(在此示例中为 check_images.py)。因为在程序名称(在此示例中为 check_images.py)后面没有指定命令行参数,因此将使用定义的默认命令行参数。
python check_images.py
要使用命令行参数 --dir
运行 check_images.py 这样的程序,首先在项目 Workspace 中打开终端窗口。然后输入以下命令并按下 Enter 键以运行程序(在此示例中为 check_images.py)。注意,所有命令行参数都在程序名称(在此示例中为 check_images.py)后面指定,并且它们的变量名(在此示例中为 dir)前面有个 --,然后在变量名后面是值(在此示例中为字符串 pet_images/)。
python check_images.py --dir pet_images/
如果你在使用命令行参数运行 check_images.py 时遇到问题,请参阅程序第 23 行的示例程序调用。
填写 get_pet_labels() 函数以创建宠物图像标签:创建一个字典,键是文件名,值是文件标签。(之后我们将使用该字典检查分类器函数的准确率)
这部分将帮助你在 get_pet_labels.py 中编写函数 get_pet_labels。对于此函数,你将使用 pet_images 文件夹中的宠物图像的文件名为宠物图像创建标签。这些图像文件名表示图像中的宠物身份。宠物图像标签被视为表示图像分类“真实结果”的标签。你的函数将返回结果字典,其中包含宠物图像文件名和标签。
- 编写函数定义
def get_pet_labels():
,请在 get_pet_labels.py 中的#TODO: 2
所指示的位置添加代码。- 根据 get_pet_labels.py 中的注释和文档字符串实现 get_pet_labels
- 在 check_images.py 的
main()
函数中以#TODO: 2
开头的部分编写代码- 将函数调用里的 None 替换为 in_arg.dir 以指定相应的目录。
编写完毕后,这段代码将返回一个字典,键是宠物图像文件名,值是仅包含宠物图像标签的列表,并为 pet_image 文件夹中的所有 40 个宠物图像都创建了键值对。
check_images.py 中的 check_creating_pet_image_labels 函数将检查你的代码,它会输出键值对数量和前 10 个键值对。
你需要用肉眼检查确保结果符合以下要求:
- 字典包含 40 个键值对(例如字典长度为 40)。
- 宠物图像标签采用以下格式:
- 全小写
- 用一个空格区分每个单词
- 正确地标识了文件名(根据 10 个键值对)
- 完成
#TODO: 2
的 workspace - 你可以在项目 Workspace - 宠物图像标签中修改 check_image.py 和 get_pet_labels.py
Lab Workspace 中的文件夹 pet_images/ 包含 40 张用于测试分类器算法的图像。pet_images/ 中的图像文件名标识了每张图像中的动物。
要为宠物图像创建_标签_,你需要:
- 读取 pet_image/ 文件夹中的所有文件的名称
- 处理文件名以创建宠物图像标签
- 调整宠物图像标签的格式,以便与以下内容相符
- 分类器函数标签
- dognames.txt 中的小狗名称
该函数的第一个任务是从文件夹中读取文件名。要完成此任务,你只需从 os python 模块中导入 listdir 方法。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: {:>25}".format(idx + 1, filename_list[idx]) )
你应将宠物图像文件名(作为键)和包含文件名相关标签的列表(作为值)存储为 python 字典数据结构。选择此数据结构的理由如下:
- 字典的键值对是一个逻辑选择,因为需要使用分类器函数处理相同的文件名(键),并将返回的标签与宠物图像标签(值)进行比较。
- 给定输入键后,检索相关值比从其他数据结构(例如列表)中检索值的速度要快。
你在数据类型和运算符一课第一次学习了字典这个概念。以下代码演示了如何使用 python 字典。
- 创建空的字典
- 创建值为列表的字典。
- 判断字典中的条目数
- 如果某个键尚未出现在字典中,向字典添加该键值对
- 遍历字典,输出字典中的所有键值对
# Creates empty dictionary named results_dic
results_dic = dict()
# Determines number of items in dictionary
items_in_dic = len(results_dic)
print("\nEmpty Dictionary results_dic - n items=", items_in_dic)
# Adds new key-value pairs to dictionary ONLY when key doesn't already exist. This dictionary's value is
# a List that contains only one item - the pet image label
filenames = ["beagle_0239.jpg", "Boston_terrier_02259.jpg"]
pet_labels = ["beagle", "boston terrier"]
for idx in range(0, len(filenames), 1):
if filenames[idx] not in results_dic:
results_dic[filenames[idx]] = [pet_labels[idx]]
else:
print("** Warning: Key=", filenames[idx],
"already exists in results_dic with value =",
results_dic[filenames[idx]])
#Iterating through a dictionary printing all keys & their associated values
print("\nPrinting all key-value pairs in dictionary results_dic:")
for key in results_dic:
print("Filename=", key, " Pet Label=", results_dic[key][0])
(要详细了解列表字典,请参阅项目 Workspace - 宠物图像标签之后的分类图像部分)。
对于此项目,你需要判断宠物图像标签和分类器标签是否匹配。要使用函数完成此匹配任务,你需要了解两种标签的格式。下文详述了用来创建宠物图像标签的宠物图像文件名的格式。
宠物图像文件位于 workspace 的 'pet_images' 文件夹中。以下是一些文件名示例:Basenji_00963.jpg、Boston_terrier_02259.jpg、gecko_80.jpg、fox_squirrel_01.jpg
详情如下:
-
共 40 张宠物图像
- 30 张小狗图像
- 10 张非小狗动物图像
-
图像的名称(标签)(
需要用于比较
)
- 包含大小写字母
- 包含描述图像的一个或多个单词(标签)
- 单词用下划线 (_) 分隔
每个宠物图像名称的最佳格式为:
- 标签:全部由小写字母组成
- 对于由多个单词组成的标签,用空格分隔每个单词
- 删除标签前后的空格
你在数据类型和运算符一课的字符串和字符串方法部分第一次学习了字符串数据类型。根据上述宠物图像文件名格式,你可以使用字符串函数获得上述标签格式:
- 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)
实现 classify_images() 函数,以在分类器函数中使用 in_arg.arch 创建分类器标签。比较标签并创建结果字典 (result_dic)。
此方法将帮助你在 classify_images.py 中编写函数 classify_images。对于此函数,你将使用分类器函数为图像创建标签。此外,你会将这些分类器的标签与宠物图像标签进行比较。最后,你将使用 classify_images返回的复杂数据结构存储宠物图像标签、分类器生成的标签和标签比较结果。最后,你会将分类器生成的标签和标签比较结果存储在结果字典(复杂的数据结构,由 get_pet_labels 函数返回)里。
- 在 classify_images.py 中的函数
def classify_images()
中带有#TODO: 3
标记的位置编写代码- 根据 classify_images.py 中的注释和文档字符串定义 classify_images
- 在 check_images.py 中的
main()
函数中带有#TODO: 3
标记的位置编写代码- 在对 classify_images 的函数调用中,将第一个 None 替换为 in_arg.dir,并将最后一个 None 替换为 in_arg.arch
编写完毕后,这段代码将返回一个列表字典,键是宠物图像文件名,值是 pet_image 文件夹中所有 40 张宠物图像的列表。该列表将包含以下条目:
- 宠物图像标签(索引 0)
- 分类器标签(索引 1)
- 标签比较结果(索引 2)
check_images.py 中的 check_classifying_images 函数将检查你的代码。此函数将输出分类器标签和宠物图像标签匹配的所有情形,以及标签不匹配的所有情形。
肉眼检查结果后表明:
- 分类器和宠物图像标签匹配的情形的确匹配
- 分类器和宠物图像标签不匹配的情形的确不匹配
- 匹配数和不匹配数加起来为 40,正好等于 pet_images 文件夹中的图像总数 40
- 完成
#TODO: 3
的 workspace - 你可以在项目 Workspace - 分类图像中修改 check_image.py 和 classify_Images.py
测试分类器函数
测试我们将用来分类宠物图像的环境和分类器函数。此函数位于 classifier.py 程序中。通过按以下说明运行 test_classifier.py 程序,测试你的环境。你可以查看 test_classifier.py 程序,了解如何在 classify_images.py中使用分类器函数。
-
转到 Lab Workspace - 分类图像页面。
-
打开终端。
-
在命令行中输入以下命令以测试 classifier.py 程序。柯利犬 图像应该正确地分类为 柯利犬
python test_classifier.py
查看 test_classifier.py 程序后,你将发现以下信息:
-
分类器函数必须导入你的程序中(已经在 *check_images.py* 中导入了)。
-
分类器函数有两个参数:
-
完整的图像路径
(包括文件夹和文件名)。
- 文件夹和文件名存储为单独的变量,可以连接成一个字符串。
-
CNN 模型 架构
- 必须为 resnet、vgg 或 alexnet
-
要查看 test_classifier.py
的代码,请在“项目 Workspace - 分类图像”中打开该程序。
你的函数需要能够判断宠物图像标签和分类器函数返回的标签是否匹配。为了使用函数完成此匹配任务,你需要了解分类器标签的格式。下面详述了分类器标签的格式。
标签位于文件 imagenet1000_clsid_to_human.txt 中,你将在项目 workspace 中看到该文件。
标签信息:
- 共 1000 个标签
- 与 118 个不同的小狗品种相关联
- 小狗品种与 ID 相关,151:吉娃娃,到 268:墨西哥无毛狗
- 与不是小狗的 882 张图像相关
- 与 118 个不同的小狗品种相关联
- 标签格式:
- 包含大小写字母
- 用一个单词标识图像
- 例如 beagle
- 用多个单词(用空格分隔)标识图像
- 例如 German shorthaired pointer
- 用几个不同的术语(用英文逗号分隔)标识相同的图像
- 例如 cocker spaniel, English cocker spaniel, cocker
在创建宠物图像标签页面,我们将宠物图像标签的格式设为:
- 标签全小写
- 对于由多个单词组成的标签,用空格区分每个单词
- 去除标签首尾的空格
- 示例:
- beagle
- cocker spaniel
- polar bear
查看上述分类器标签格式后,你唯一需要处理的是将所有字母变成小写形式,并去除首尾的所有空格。你可以使用 in 运算符判断宠物图像标签是否与组成分类器标签的某个术语匹配。宠物图像标签始终只有一个术语(即使该术语由多个单词构成)。因此,如果你发现(使用 in 运算符)宠物图像标签与组成分类器标签的某个术语匹配,那么属于匹配情况。
你在(Python 课程的)数据类型和运算符一课第一次学习了字符串数据类型。要完成这些格式设定和匹配任务,请使用以下字符串函数:
- lower() - 使字母全变成小写形式。
- strip() - 返回删除首尾字符的字符串。如果未传入任何字符,则删除首尾的空格。
- in 运算 - 如果某个字符串存在于另一个字符串里,则返回 True,否则返回 False。
你在数据类型和运算符一课第一次学习了字典这个概念。get_pet_labels 函数返回一个字典,键为文件名,值为仅包含宠物图像标签的列表。对于 classify_images 函数,你可以使用 extend 列表函数将分类器标签和比较结果同时添加到结果字典里。
你在数据类型和运算符一课第一次学习了复合数据结构。你创建并使用嵌套字典来存储元素信息。对于此项目,我们建议使用的复合数据结构是列表(值)字典。如果你选择使用其他复合数据结构,以下检查函数将不可用:
- check_creating_pet_image_labels
- check_classifying_images
- check_classifying_labels_as_dogs
- check_calculating_results
选择该数据结构的原因是:
对于此函数,你需要输入 results_dic 字典,其中:
- 键为文件名
- 值为仅包含宠物图像标签的列表。
你将需要:
-
遍历该字典 (results_dic),使用分类器函数处理每个宠物图像(文件名),以获取分类器标签。
-
比较宠物图像和分类器标签,判断它们是否匹配。
-
将结果添加到结果字典 (results_dic) 中。
(在可变数据类型和函数部分,你发现:因为结果字典是可变数据类型,因此不需要从 classify_images 函数返回该字典)。
防止 classify_images 出现问题的编程建议:
- 对于分类器函数,确保将 images_dir 与文件名相连,表示每个宠物图像文件的完整路径。
- 使分类器标签全小写,去除标签首尾的空格。
- results_dic 格式将如下:
- 键 = 宠物图像文件名(例如 Beagle_01141.jpg)
- 值 = 满足以下条件的列表:
- 索引 0 = 宠物图像标签(例如 beagle)
- 索引 1 = 分类器标签(例如 english foxhound)
- 索引 2 = 0/1,其中 1 = 标签匹配,0 = 标签不匹配(例如 0)
- example_dictionary = {'Beagle_01141.jpg': ['beagle', 'english foxhound', 0]}
- 要初始化 results_dic 中的键,使用赋值运算符 (=) 分配列表的值。
- 要向 results_dic 中的现有键列表添加一项,请使用 += 运算符或 append 函数向该列表附加值。
- 要同时向 results_dic 中的现有键列表添加多项,请使用 extend 列表函数。
要详细了解如何使用列表字典,请参阅以下示例代码。该代码演示了初始化键值对和向现有键值对列表添加项目的区别。该代码还演示了如何遍历列表字典,以访问列表中的每个元素。
# Defining lists to populate dictionary
filenames = ["Beagle_01141.jpg", "Beagle_01125.jpg", "skunk_029.jpg" ]
pet_labels = ["beagle", "beagle", "skunk"]
classifier_labels = ["walker hound, walker foxhound", "beagle",
"skunk, polecat, wood pussy"]
pet_label_is_dog = [1, 1, 0]
classifier_label_is_dog = [1, 1, 0]
# Defining empty dictionary
results_dic = dict()
# Populates empty dictionary with both labels &indicates if they match (idx 2)
for idx in range (0, len(filenames), 1):
# If first time key is assigned initialize the list with pet &
# classifier labels
if filenames[idx] not in results_dic:
results_dic[filenames[idx]] = [ pet_labels[idx], classifier_labels[idx] ]
# Determine if pet_labels matches classifier_labels using in operator
# - so if pet label is 'in' classifier label it's a match
# ALSO since Key already exists because labels were added, append
# value to end of list for idx 2
# if pet image label was FOUND then there is a match
if pet_labels[idx] in classifier_labels[idx]:
results_dic[filenames[idx]].append(1)
# if pet image label was NOT found then there is no match
else:
results_dic[filenames[idx]].append(0)
# Populates dictionary with whether or not labels indicate a dog image (idx 3&4)
for idx in range (0, len(filenames), 1):
# Key already exists, extend values to end of list for idx 3 & 4
results_dic[filenames[idx]].extend(pet_label_is_dog[idx],
classifier_label_is_dog[idx])
# Iterates through the list to print the results for each filename
for key in results_dic:
print("\nFilename=", key, "\npet_image Label=", results_dic[key][0],
"\nClassifier Label=", results_dic[key][1], "\nmatch=",
results_dic[key][2], "\nImage is dog=", results_dic[key][3],
"\nClassifier is dog=", results_dic[key][4])
# Provides classifications of the results
if sum(results_dic[key][2:]) == 3:
print("*Breed Match*")
if sum(results_dic[key][3:]) == 2:
print("*Is-a-Dog Match*")
if sum(results_dic[key][3:]) == 0 and results_dic[key][2] == 1:
print("*NOT-a-Dog Match*")
实现 adjust_results4_isadog() 函数以调整字典 result_dic 的结果,判断分类器是否正确地将图像分类为“小狗”或“非小狗”。
此部分将帮助你在 adjust_results4_isadog.py 中编写未定义的函数 adjust_results4_isadog。
对于此函数,你将:
-
读取 dognames.txt 文件中的小狗名称并将其存储到某个数据结构(例如字典)中
-
将小狗名称与结果字典中的分类器标签和宠物图像标签进行比较
-
调整结果字典,以表明这些标签是否表示图像是“小狗”图像。
注意,adjust_results4_isadog 函数将更改结果字典,但是因为字典是可变的,因此你无需返回此字典(要了解详细原因,请复习可变数据类型和函数部分)。
-
编写函数定义
def adjust_results4_isadog():
,请在 adjust_results4_isadog.py 中的#TODO: 4
所指示的位置添加代码。- 根据 adjust_results4_isadog.py 中的注释和文档字符串定义 adjust_results4_isadog
-
在 check_images.py 中的
main()
函数中带有#TODO: 4
标记的位置编写代码- 在对 adjust_results4_isadog 的函数调用中,将 None 替换为 in_arg.dogfile。
编写完毕后,这段代码将更改结果字典,它是一个列表字典,键为宠物图像文件名,值为 pet_image 文件夹中的所有 40 个宠物图像的列表。每个键列表现在将包含另外两项:宠物图像标签是否为小狗(索引 3)和分类器标签是否为小狗(索引 4)。
check_images.py 中的 check_classifying_labels_as_dogs 函数将检查你的代码。此函数将输出分类器标签和宠物图像标签匹配的所有情形以及不匹配的所有情形。
肉眼检查结果后表明:
- 分类器标签和宠物图像标签匹配的情形都将两种标签相应地分类为“小狗”或“非小狗”。
- 分类器标签和宠物图像标签不匹配的情形分别将每个标签正确地分类为“小狗”或“非小狗”。
- 匹配数和不匹配数加起来为 40,正好等于 pet_images 文件夹中的图像总数 40。
- 完成
#TODO: 4
的 workspace - 你可以在项目 Workspace - 调整结果中修改 check_image.py 和 adjust_results4_isadog.py
- 正确标识哪些宠物图像是小狗图像(即使品种分类错误),哪些宠物图像不是小狗图像。
- 针对小狗图像正确判断小狗品种。
要实现目标 1 和 2,程序要能够判断分类器函数和宠物图像中的标签为“小狗*”或“非小狗”。要能够将标签分类为“小狗”或“*非小狗”,程序需要将标签与 workspace 中的 dognames.txt 文件包含的小狗列表进行比较。
该 dognames.txt 文件根据格式化的标签(全小写、去除首尾空格等)创建而成。因此,在将小狗名称(来自 dognames.txt)与你的标签比较时:
- 如果小狗名称与标签匹配,则标签为“是小狗”
- 如果小狗名称与标签不匹配,则标签为“不是小狗”
其中:
- 狗品种名称各占一行
- 有 223 个狗品种名称
- 来自分类器函数和宠物图像标签的所有可能狗品种
- 分类器函数标签:
- 第 1 行(吉娃娃)到第 118 行(墨西哥无毛犬),应该与分类器返回的标签匹配,只要这些标签_全_小写,并且去除了首尾的空格。
- 宠物图像标签:
- 应该匹配以下行,只要标签_全_小写,首尾空格已去除,并且如果小狗名称由多个单词组成,则用一个空格区分单词。
adjust_results4_isadog 的第一项任务是读取所有小狗名称并将它们存储在一种数据结构中。根据上述详细信息,小狗名称的最理想数据结构是字典,键是小狗名称,值是 1(任意值)。理由是字典的查询速度很快。因为我们知道如果有匹配项的话,标签应该与小狗名称完全匹配;我们可以直接将标签当做键在小狗名称字典中查询,发现为_小狗的所有标签。如果在小狗名称字典中没有找到标签键,那么我们知道该标签不是_小狗。
脚本编写一课介绍了如何打开文件和读取文件信息。如果你从 dognames.txt 中读取小狗名称时遇到问题,请复习此部分。
防止 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_dictionary = {'Beagle_01141.jpg': ['beagle', 'walker hound, walker foxhound', 0, 1, 1]}
实现 calculates_results_stats() 函数以计算运行结果并将统计信息放在结果统计字典 (results_stats_dic) 里。
此部分将帮助你在 calculates_results_stats.py 中编写未定义函数 calculates_results_stats。对于此函数,你将输入结果字典,以创建结果统计字典。此结果统计字典的键将为统计量的名称,值将为统计量的数字值。
你将在 calculates_results_stats 中创建结果统计字典,因此我们建议你在函数的第一行创建此字典,并在函数的最后一行返回字典的值。要详细了解为何函数返回了此字典,请复习可变数据类型和函数部分。
-
编写函数定义
def calculates_results_stats():
,请在 calculates_results_stats.py 中的#TODO: 5
所指示的位置添加代码。- 根据 calculates_results_stats.py 中的注释和文档字符串定义 calculates_results_stats
编写完毕后,这段代码将能够提供用于回答此 Lab 目标的计数和百分比值。results_stats 字典提供的百分比将回答目标 1 和 2。计数将用于计算百分比。
check_images.py 中的 check_calculating_results 函数将检查你的代码,它将重新计算以下结果统计信息(计数和百分比),并将这些信息与你计算并存储在结果统计字典里的统计信息进行比较。
检查结果统计信息:
-
计数:
- 图像数量
- 小狗图像数量
- 非小狗图像数量
-
百分比:
- 正确分类的小狗图像所占百分比
- 正确分类的非小狗图像所占百分比
- 品种分类正确的小狗图像所占百分比
用肉眼检查确保对于上述六个统计量,这段检查代码得出的结果与你使用 calculates_results_stats.py 中的 calculates_results_stats 计算的结果相匹配。
- 完成
#TODO: 5
的 workspace - 你可以在项目 Workspace - 计算结果中修改 check_image.py 和 calculates_results_stats.py
- 正确标识哪些宠物图像是小狗图像(即使品种分类错误),哪些宠物图像不是小狗图像。
- 针对小狗图像正确判断小狗品种。
要实现目标 1 和 2,程序需要能够根据比较结果字典中包含的标签得出的结果计算以下百分比:
结果字典将具有以下格式:
-
键 = 宠物图像文件名(例如 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_dictionary = {'Beagle_01141.jpg': ['beagle', 'walker hound, walker foxhound', 0, 1, 1]}
你需要将这些计算结果(计数和百分比)存储在结果统计字典中。我们建议在统计量的名称(键)中针对所有计数(例如 n_)和百分比(例如 pct_)使用相同的前缀,以便更轻松地针对每组输出所有条目。
结果统计字典将具有以下格式:
- 键 = 统计量的名称(例如 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:正确分类的小狗图像所占百分比
- A:正确分类的_小狗_图像数量
- B:_小狗_图像数量
- 正确分类为_小狗_的图像所占百分比:A/B * 100
- 目标 _1_b:正确分类的非小狗图像所占百分比
- C:正确分类的非小狗图像数量。
- D:非小狗图像数量
- 正确分类为非小狗的图像所占百分比:C/D * 100
- 目标 2:正确分类的小狗品种所占百分比
- E:正确分类为特定品种的_小狗_图像数量。
- B:_小狗_图像数量
- 品种正确分类的_小狗_图像所占百分比:E/B * 100
- (可选)百分比标签匹配数(无论是否为小狗)
- Y:标签匹配数量
- Z:图像数量
- 正确匹配的图像所占百分比(无论是否为小狗):Y/Z * 100
重要事项:
-
在遍历结果字典之前,你需要将所有计数初始化为 0。在遍历结果字典时,如果满足特定的条件,你需要将这些计数器加 1。
-
百分比(以及图像总数)可以通过计数生成(请参阅上述百分比和计数计算方法);因此,应该在遍历结果字典并计算计数之后计算这些值。
-
在计算正确分类的非小狗图像所占百分比时,使用条件语句检查 D(非小狗图像的数量)是否大于 0。为了避免除以 0,仅在 D 大于 0 时才计算 C/D;否则直接设为 0。
-
因为结果统计字典是在函数内创建的,并且是可变对象,因此你需要在函数结束时返回它的值(请参阅可变数据类型和函数部分)。
实现 print_results() 函数以输出结果摘要(以及根据要求输出错误的小狗和品种分类情况)。
此部分将帮助你在 print_results.py 中编写未定义的函数 print_results。对于此函数,你将输出结果字典和结果统计字典,以输出结果摘要。因为此函数使我们能够输出分类错误的小狗和分类错误的小狗品种列表,因此我们需要包含结果字典。
-
编写函数定义
def print_results():
,请在 print_results.py 中的#TODO:
所指示的位置添加代码。- 根据 print_results.py 中的注释和文档字符串定义 print_results
-
在 check_images.py 的
main()
函数中带有#TODO: 6
标记的位置添加代码。- 在对 print_results 的函数调用中,将 None 替换为 in_arg.arch
编写完毕后,这段代码将输出用于回答此项目目标 1 和 2 的结果摘要。
你需要运行完成的程序并用肉眼检查以下各项:
- 运行程序后,正确地输出了统计信息和计数并且设定了正确的格式。计算结果的代码检查部分的结果应该与 6 个统计量输出的结果匹配。
- 在对 print_results 的函数调用中保留两个默认参数,不输出分类错误的结果(这是预期的默认行为)
- 在对 print_results 的函数调用中为两个默认参数添加值 True,输出分类错误的结果(这也是预期的行为)。
当程序能正常运行并且你对程序满意时,使用批处理(请参阅下面的批处理部分)针对所有三个 CNN 模型架构运行程序。你将使用这些结果与我们在最终结果部分的结果进行比较。
- 下一页将是完成
#TODO: 6
的 workspace - 你可以在项目 Workspace - 输出结果中修改 check_image.py 和 print_results.py
首先要输出的是一个概括性语句,表示你使用的是三个 CNN 模型架构中的哪个架构。你可以在输入参数 model 中传入该信息,以便输出该信息。
接着,你需要针对三个 CNN 模型架构输出以下总体计数。可以通过在输出语句中使用相应的键来调用这些计数。
- 图像数量
- 小狗图像数量
- 非小狗图像数量
最后,你将遍历 results_stats 字典并输出统计量的名称和所有百分比的值(例如以字母“p”开头的键)。之前我们建议你为所有百分比统计量设定相同的前缀(例如 pct_),以便以一个群组的形式输出它们。
百分比计算结果:
- 正确的小狗图像所占百分比
- 正确的品种图像所占百分比
- 正确的非小狗图像所占百分比
- 匹配项所占百分比(可选 - 包括小狗图像和非小狗图像)
此函数使我们能够选择输出小狗和品种分类错误的情形。
此可选功能旨在改善代码的调试性能。此外,此功能使我们能够判断是否有一些算法很难判断的小狗品种。
函数 print_results 包含两个默认参数,用于输出分类错误的小狗和品种。(在函数一课,你第一次学习了默认参数)。
默认参数:
- print_incorrect_dogs - 默认为 False
- print_incorrect_breed - 默认为 False
默认参数的目的可能如下:
- 为函数提供范围更广的行为,无需编写多个(相似的)函数。
- 保证某些参数在函数中始终赋了值。
- 为函数提供默认行为。
如果两个标签对于图像是否为小狗的结论不一致,那么标签的小狗分类结果不正确。
在遍历结果字典以查找小狗分类错误的情形前,你必须使用条件语句检查用户是否希望输出分类错误的小狗以及出现了分类错误的小狗。
这项检查发生在满足以下条件之后:
- 用户想要输出分类错误的情形:
- print_incorrect_dogs == True
- 有一些分类错误的小狗:
- n_correct_dogs + n_correct_notdogs != n_images
如果检查结果为 True,则在以下情形时输出分类错误的小狗对应的宠物图像和分类器标签:
- 关于图像是否为“小狗”,标签不一致
- sum(results_dic[key][3:]) == 1
如果两个标签都表示图像是小狗,但是关于小狗的品种观点不一致,这种情况就属于小狗品种分类错误的情形。
在遍历结果字典以查找品种分类错误的情形前,你必须使用条件语句检查用户是否希望输出品种分类错误的情形以及出现了品种分类错误的情形。
这项检查发生在满足以下条件之后:
- 用户想要输出分类错误的情形:
- print_incorrect_breed == True
- 有一些品种分类错误了:
- n_correct_dogs != n_correct_breed
如果检查结果为 True,则在以下情形时输出分类错误的品种对应的宠物图像和分类器标签:
- 标签对图像是小狗这一观点保持一致,但是对小狗的品种保持不一致
- sum(results_dic[key][3:]) == 2 及 results_dic[key][2] == 0
你已经编写完 check_images.py,可以在所有三个模型上运行该程序了。一种方式是在终端窗口中针对其中一个模型运行该程序,直到程序运行完毕,记录结果,然后为其他两个模型重复相同的流程。
一种更简单的处理方式是使用 shell 脚本进行批处理。对于这道练习,你将在 workspace 中找到 bash 程序 run_models_batch.sh。打开该文件后,你将发现以 # 开头的注释,和 python 一样,剩余的代码和你在终端窗口中运行程序时输入的命令一样(请参阅以下代码)。
# Code from run_models_batch.sh
python check_images.py --dir pet_images/ --arch resnet --dogfile dognames.txt
> resnet_pet-images.txt
python check_images.py --dir pet_images/ --arch alexnet --dogfile dognames.txt
> alexnet_pet-images.txt
python check_images.py --dir pet_images/ --arch vgg --dogfile dognames.txt
> vgg_pet-images.txt
你还将发现,每个文件都以 > filename.txt 结束。> 是一个管道,负责将输出从控制台传输到文件中。该文件包含被使用的模型的文件名。这样的话,每次运行过后,结果会自动存储到 workspace。
要在 workspace 中运行文件 run_models_batch.sh,(在 Unix/Linux/OSX/Lab Workspace 中)打开终端窗口并输入以下命令:
sh run_models_batch.sh
如果你想在 Windows 计算机上批处理程序,则需要遵守此处提供的说明。
使用 run_models_batch.sh
(在 Windows 上使用 run_models_batch.bat
)运行所有三个模型后,将这些结果与最终结果部分的结果进行比较。
在项目的第一部分,你将利用 Jupyter notebook 通过 PyTorch 实现一个图像分类器。我们将提供一些提示和建议,但是你需要完成大部分代码。在处理该项目的过程中,请参阅此审阅标准,获取如何成功地提交项目的指导说明。
请注意,你应该自己编写代码,请勿剽窃(更多详情请参阅此处)。
在提交项目时需要包含此 notebook。完成后,确保将其下载为 HTML 文件并在项目的下个部分编写的文件中包含此文件。
我们为你提供了处理此项目所需的 GPU Workspace。如果你想在本地机器上处理项目,可以在此 GitHub [暂时处于非公开状态]上找到这些文件。