太阳能和房地产可持续发展商机
数据科学找到一种有利可图的行善方式
世界人口正在从今天的 78 亿增加到预计未来 50 年的 120 亿。这相当于地球上新增 42 亿人口,大约是美国的 13 倍。
数据来自联合国 population.un.org 办事处
为了维持这种增长,我们需要生产更多的能源。但是为了维持地球,我们需要可持续的能源。那么问题就变成了:有没有一种方法可以在创造利润的同时解决这些问题?
你觉得什么最突出?图片来自维基百科。
上图是太阳辐照度图,即单位面积从太阳接收的功率(瓦特每平方米,W/m2)。
商业案例:澳大利亚是地球上最大的陆地之一,拥有最高的太阳辐射量,但它的土地价格是否考虑了阳光照射的价值?机会在于找到大量暴露在阳光下的被低估的土地,并将这些土地主要转化为太阳能农场——太阳能套利的商业案例。
这种商业模式来自于将电力销售回电网,并创造 B2C 和 B2B 能源解决方案。这可能是将电力返销到澳大利亚、新加坡,为消费者提供更便宜的电力,并创造 B2B 能源解决方案,如特斯拉的 Powerpack & Megapack。
图片来自 Tesla.com
利用数据科学,让我们探索一下这个机会是否存在。我们正在寻找:澳大利亚的一个位置,那里有最高的阳光照射率和廉价的土地。
澳大利亚太阳辐照度。图片来自维基百科。
这方面没有公开可用的数据(因此是“秘密”机会),所以我们必须手动将拼图拼在一起。感兴趣的关键变量:位置、土地面积、价格、年日照量。数据来源:
- 土地面积和价格数据来自:domain.com.au/rural
- 阳光照射数据来自:bom.gov.au/climate/data/index.shtml?书签=203
大部分工作是在收集数据和计算太阳能与土地的价格比率,这已经在这个数据集中完成。我们正在寻找大量的土地,如农村和农场土地。
# Import data
import pandas as pd
solar = pd.read_csv('data/land_and_solar.csv')
solar.head()
这里的关键一栏是“太阳能/每平方米价格”,这是这块土地每 1 美元得到的阳光照射量。数字越高,获利机会越好。
solar.tail()
让我们来看看目前价格/平方米和阳光照射之间是否存在关联?换句话说,目前的房地产市场价格是否考虑了阳光照射?
# Plot to see if there is a correlation
solar.plot.scatter(x='Price / Sq Metre', y='Solar Exposure 2019 (MJ m-2)')
如果已经有了相关性,我们会期望看到一个线性模式。
目前的房地产价格似乎没有反映阳光照射。这也许就是机会所在!接下来,让我们将位置可视化。这就是 Python 打败 Excel 的地方。我们将绘制位置图,并根据太阳能/每平方米价格比率对每个位置进行加权。
# Use street address to find latitude and longitude and add to datafrom geopy.geocoders import Nominatim
from geopy.extra.rate_limiter import RateLimiter
geolocator = Nominatim(user_agent="application")
geocode = RateLimiter(geolocator.geocode, min_delay_seconds=1)
solar['location'] = solar['Address Two'].apply(geocode)
solar['point'] = solar['location'].apply(lambda loc: tuple(loc.point) if loc else None)
solar[['latitude', 'longitude', 'altitude']] = pd.DataFrame(solar['point'].tolist(), index=solar.index)# Create base map in Australia
import folium
def generateBaseMap(default_location=[37.76, -122.45], default_zoom_start=4):
'''
Create a base map
'''
base_map = folium.Map(
location = default_location
, control_scale = True
, zoom_start = default_zoom_start
)
return base_map
base_map = generateBaseMap(default_location=[-24.003064,134.629882])
display(base_map)
leav 生成的地图。
# Plot land locations from dataset
for i in range(0,len(solar)):
folium.Marker(
location=[solar.iloc[i]['latitude'], solar.iloc[i]['longitude']],
popup=solar.iloc[i]['Solar / PSM']
).add_to(base_map)display(base_map)
这些标记代表可供出售的土地。
# Plot Solar / Price Per Sq Metre ratio and give them weightings
for i in range(0,len(solar)):
folium.Circle(
location=[solar.iloc[i]['latitude'], solar.iloc[i]['longitude']],
popup=solar.iloc[i]['Solar / PSM'],
radius=solar.iloc[i]['Solar / PSM']*3000,
color='crimson',
fill=True,
fill_color='crimson'
).add_to(base_map)display(base_map)
绿色圆圈代表“太阳能/每平方米价格”比率。圈子越大,土地越值钱。它标志着你以更低的土地成本获得更多的阳光照射。
秘诀:离澳大利亚昆士兰州的大堡礁不太远的地方,将是建立一个有利可图的太阳能发电厂的理想地点。
截至 2020 年 5 月的农村待售土地。图片来自 domain.com.au 农村土地出售清单。
下一步:
这一初步探索显示了潜在的房地产和清洁能源的机会及其价值,为更深入的分析。下一步将是将数据集扩展为完整的位置列表,并探索建立太阳能发电厂的商业模式。一些问题包括:建造和维护一个大型太阳能发电厂的成本是多少,可以产生多少能量,利润率是多少,土地利用还有哪些其他机会?世界上还有哪些地方也存在这种机会?
像食物一样,能源是人类生活的重要组成部分。对能源的需求将永远存在,并且在未来,对能源的需求将继续增加。这是一个以有利可图的方式行善的真正机会。
如果这引发了一些好奇,让我们连接。我很想进一步探索这个问题。
太阳图像分析:几毫秒内 50 亿行
GPU 供电的工作站节省了 NASA 数年的计算时间!
穆罕默德·诺哈西在 Unsplash 上的照片
自从 2010 年发射太阳动力学观测站(SDO) 任务以来,美国宇航局拍摄了超过 1 . 5 亿张太阳图像。这为航天局存储、管理和分析了超过 18pb 的数据。直到最近,NASA 还面临着一场计算噩梦。
关于太阳的工作,我们可以学到什么?GPU 驱动的数据科学工作站如何缓解 NASA 的计算挑战?让我们快速浏览一下!
太阳物理学是研究太阳如何工作并影响地球上的生命。美国宇航局的研究科学家正在以每 1.3 秒一张的速度收集太阳图像,希望从这颗发光的恒星上的各种太阳活动中获得洞察力。
能够使用带有 CPU 的传统计算平台来处理这些图像,处理它们并识别特征,这需要研究人员花费数年甚至数十年的时间来回答一个问题或在一个问题上取得进展。
基于 NVIDIA 的数据科学工作站
据 NASA 的研究科学家 Michael Kirk 称,由 Quadro RTX GPU 驱动的数据科学站执行计算的速度比更老、更传统的 CPU 驱动的数据科学站快 150 倍。
Jonas Svidras 在 Unsplash 上拍摄的照片
美国国家航空航天局的高度精确的算法,用于拾取“坏”像素并将其从太阳图像中移除,相当于该任务的大量计算挑战。自 2010 年以来拍摄的惊人的 1.5 亿张图像包含数十亿个这样的“坏”像素!
新工作站通过过滤数十亿坏像素,使分析和查找假阴性的过程变得更加容易和快速。事实上,美国宇航局的研究人员仍在研究这一过程。他们对未来的计划也是经历假阳性;即被算法挑选为“好”像素的坏像素。
NVIDIA 驱动的数据科学工作站为美国宇航局的研究科学家和天体物理学家提供了一个完美的平台,开始使用和应用一些来自人工智能(AI)和机器学习(ML)的更现代和更先进的技术。
“现在许多太阳物理学工作的圣杯是能够做出预测;对太阳耀斑何时爆发、太阳活动何时活跃以及活跃程度的预测。如果我们能够做出这些预测,任何在轨道上拥有卫星的公司都将能够采取预防措施来保护他们的卫星。”——迈克尔·柯克,美国国家航空航天局的研究科学家。
惠普将其 Z 数据科学工作站营销为“世界上最强大的工作站”,能够在几毫秒内通过一次点击与多达 50 亿个数据集行进行交互。
如果这不令人兴奋,我不知道什么才是。
如果你喜欢这篇快速的新闻般的文章,并且想更深入地了解用于太阳图像分析的算法,请让我知道并关注更多!
解决方案架构师与开发人员:AWS 认证细分
哪个适合你?
几个月前,当我第一次开始 AWS 之旅时,我只知道我想获得认证。
我知道信息技术中的一切都围绕着云。那么,我为什么不想成为 it 专家呢?
据全球知识报道,我知道 AWS 认证工人的平均收入超过 13 万美元。
但我不知道的是,我应该追求哪种认证。解决方案架构师还是开发人员?
通过在互联网上进行研究,我发现解决方案架构师的平均工资更高(只是非常低)。所以很自然地,我被吸引了。
然而,一旦我看了每个考试的目标,我觉得我会从开发人员认证中获得更多(因为我自己就是一名开发人员)。
我不知道,这两者之间有巨大的重叠,一旦你得到一个,很容易得到另一个。所以我两样都买了。
那么哪个适合你呢?让我们来了解一下!
目标
了解 AWS 解决方案架构师和开发人员认证之间的差异,并最终决定您应该选择哪一个。
开发者
这次考试包括什么?
以下是 AWS 云开发者(DVA-C01)考试的目标:
- 部署
- 安全性
- 使用 AWS 服务进行开发
- 重构
- 监控和故障排除
对于在 AWS 上开发的最佳实践有很大的关注(这并不奇怪)。我发现这些内容更适用于我的日常工作,所以自然地,它更吸引我。
AWS 开发人员考试深入探讨了无服务器计算,因为这是 AWS 希望开发人员接受的实践。
焦点服务是 Lambda、DynamoDB、Step Functions、X-Ray、API Gateway、ECS、CloudFront、SQS、SNS 和 Kinesis。
旧版本的考试对 EC2 进行了更深入的探索,如果你复习 2018 年或之前的考试材料,你会注意到这一点。现在情况不再是这样了。这是一个无服务器的计算重点考试。
我不是说 EC2 不会出现在你的考试中。会的。但是请将注意力集中在无服务器服务上。
这个考试是为了谁?
对于学习如何使用 AWS 进行构建的开发人员来说,这个考试非常好。无论是个人使用还是工作,你在准备考试时获得的知识将为你提供成功所需的一切。
你不一定要有高超的技术才能成功。考试创建者不会让你在考试中写代码。他们会问你“哪个是正确的 API”类型的问题,但是不需要背景编码知识。
让我换个说法。背景编码知识可能对你有帮助,但不是必须的。
下面是一个示例问题:您的 web 应用程序每隔几分钟就向 S3 存储桶上传一个 10GB 的文件,您希望最大限度地缩短每次上传所需的时间。你如何实现这一点?
答:使用多部分上传 API。
这个问题的答案有很多种学习方法,像这样的问题。您可以拥有 S3 铲斗的实际操作经验,通读 API 文档,或者从在线课程中学习。
这里的想法是如果我将 AWS 带到我的公司,我可以使用哪些最佳实践来利用 AWS 的最新和最棒的技术?
或者,如果我从头开始创建自己的公司,我该如何在云环境中开发我的应用程序?
如果这些问题中的任何一个适用于你,这个考试就适合你。
如果你想知道如何准备这次考试,我写了下面这篇关于我的经历的文章:
我是如何在只有很少 AWS 经验的情况下在短短六周内获得认证的
medium.com](https://medium.com/better-programming/how-to-become-aws-cloud-developer-certified-7318a67f7085)
解决方案架构师
这次考试包括什么?
以下是 AWS 解决方案架构师(SAA-C02)考试的目标:
- 设计弹性架构
- 设计高性能架构
- 设计安全的应用和架构
- 设计成本优化的架构
如果您可以从目标中得到启发的话,这一认证的主要焦点是为您的系统设计最佳架构。
重点关注以下服务:EC2、VPC、ECS、弹性负载平衡器、CloudWatch、EFS、EBS、FSx 和 CI/CD 工具。
这个考试是为了谁?
该认证面向那些执行某种类型的解决方案架构师角色的人员。
该考试将测试您设计安全、可靠且使用 AWS 技术的架构的能力。
很多问题将基于场景。这里有一个例子:您正在为一家大型航空航天工程公司工作,您需要您的 NoSQL 数据库具有高度的可伸缩性,并且能够处理频繁的模式更改。你应该使用哪种 AWS 服务?
答案:DynamoDB。
在成为解决方案架构师的培训中,您将了解所有的 AWS 服务产品,以及如何让它们以最佳方式协同工作。像这样的问题对你来说会变得轻而易举。
这里的想法是如果我把 AWS 带到我的公司,我如何最好地设计我的应用程序架构,使它安全、高性能、有弹性并且成本最优?
或者,如果我从零开始创办自己的公司,我如何才能最好地使用 AWS 设计我的应用程序?
如果您是开发人员或扮演不同的非解决方案架构师角色,您仍将从该认证中获益。
作为一名开发人员,我发现这些概念非常有价值。此外,这也给了我信心,让我可以在未来一跃成为技术主管或解决方案架构师。
如果你想知道如何准备这次考试,我写了下面这篇关于我的经历的文章:
柠檬榨汁机
towardsdatascience.com](/the-ultimate-aws-solutions-architect-certification-guide-56c21d4078ed)
两种考试都包括什么?
我注意到这两个认证有很多重叠的地方。因此,当我完成 AWS 开发人员认证后,我立即将解决方案架构师考试安排在了两周之后。没有更多的准备,我成功地通过了第二次考试。
我从开发人员认证中获得的知识使得迈出这一步变得相当容易。让我们来看看你从两者中学到了什么。
重叠知识
核心的 AWS 服务将会无处不在,你参加的每一次认证考试都会对它们进行测试。
我说的核心 AWS 服务是什么意思?
EC2、VPC、S3、RDS、Lambda、53 号公路、SNS、SQS、ELB、DynamoDB、亚马逊极光和 CloudFront。
这些服务涵盖 AWS 上的计算、安全、数据库、监控、部署和无服务器。
绝大多数问题都围绕着这些服务,所以你对每一项服务了解得越多越好。
此外,对安全性有一个坚实的理解也是值得的。理解 VPC 氏症、认知、STS、子网、安全组和 NACLs 将使你在这两个考试中轻松很多。
为什么仅仅停留在开发人员和解决方案架构师认证上呢?一旦你掌握了这些基础知识,你就可以获得任何你想要的证书!以下是你可以获得的认证的完整列表: AWS 认证。
同样值得一提的是,准备这些考试还可以让你更容易地获得谷歌云平台或微软 Azure 认证。许多概念和原理是相同的,只是名称不同。
结论
对于一些最后的想法,我强烈建议参加这两个考试。然而,如果你必须选择一个,希望这将帮助你决定:
开发人员:如果你是一名开发人员或试图从开发人员的角度学习 AWS 的人,请参加这个考试。您在本次培训中获得的知识将为您在 AWS 上创造真正不可思议的东西奠定基础。
它还可以让你参与 AWS 开发相关的讨论,我觉得这很有趣。
解决方案架构师:如果你是某种类型的技术架构师,或者试图了解架构师在 AWS 环境中是如何思考的,请参加这个考试。
不管您的角色是什么,拥有一个解决方案架构师的视角只会让您受益。
无论您选择哪种认证,您都将获得无限的机会。驾驭 AWS 的力量,将你的梦想变成现实。你将有能力建造任何你能想象的东西。
你所要做的就是迈出第一步,开始行动。
赖安·格里森的更多故事
开始这个有趣的小项目来提升你周围人的精神
towardsdatascience.com](/how-i-used-aws-lambda-to-make-my-girlfriend-smile-61194596f2d) [## 分解 AWS 的身份访问管理(IAM)
开始使用 IAM 需要知道的一切
medium.com](https://medium.com/better-programming/breaking-down-awss-identity-access-management-iam-cb51c9195e4f) [## 使用 Gatsby.js、Ghost 和 AWS Amplify 部署独立博客
从头开始创建博客从未如此容易
medium.com](https://medium.com/swlh/deploy-an-independent-blog-using-gatsby-js-ghost-and-aws-amplify-713577af0fde)
模式编程面试问题解答
用 python 解决公司面试中提出的各种模式编程问题
照片由 Maranda Vandergriff 在 Unsplash 上拍摄
编码面试通常会要求一个模式程序来测试候选人。
通常,在持续四轮的面试过程中,第一轮往往是一个编程轮,并且有可能所问的问题之一可能是模式程序。
模式编程是指经常给你一个特定的模式设计问题,带有星号(*)或数字或字母,你要在迭代循环语句的帮助下对该设计进行编程。
在本文中,我们将揭示解决这些问题的方法,并理解这些编程模式背后的理论。
几年前,我曾用 Java 编程来解决我的大部分模式程序,但 python 同样简单,甚至可能更简单。因此,python 将是本文选择的语言。
然而,使用的语言并不重要,只有解决这些问题背后的有趣逻辑才是重要的。今天,我们将探讨一些基本问题。
所以,事不宜迟,让我们动手开始编码吧!
模式-1:数字变化的半金字塔-1
作者截图
上述模式是我们将在本文中解决的第一类问题。大多数模式类型的问题可以很容易地通过两到三次迭代操作来解决。
仔细观察,您会发现在打印第一个数字后,光标会跳到下一行,然后在打印两个数字后,光标又会移到下一行,依此类推。
我们解决这种模式的逻辑非常简单。我们将有 5 行,然后在打印出与行数相等的数字后,我们将移动光标。
我的意思是,对于第一行,将打印 1 个数字,第二行将打印 2 个数字,依此类推。
**注意:**本文中提到的问题有多种解决方案。这些是我选择的代码和方法。你可以用任何你觉得更适合你的编程风格的方式来解决它们。
代码:
通过定义如下用户定义的变量,可以根据用户的输入选择行数:
我之前建议的逻辑在代码块中实现。要记住的最关键的一点是,内部循环总是首先实现的。之后,执行外部循环。range 函数总是包括指定的第一个数字,而忽略最后一个数字,取而代之的是 n-1 值。(其中 n 是最后一位数字,在本例中是 6)。
在这个程序中,我们指定了将要相应解释的行数。之后,我们运行内部循环,它根据我们拥有的行数执行。我们打印“j ”,因为每次值被重置为 1 时,它都会按照行的升序打印相应的值。
**注意:**对于本文的其余部分,我将使用缺省的 5 行。你可以选择你喜欢的两种方法之一。
模式 2:数字变化的半金字塔-2
作者截图
我们要解决的第二个模式程序与第一个半金字塔问题非常相似。这里唯一的区别是,我们需要打印与行数相等的数字,数字需要根据各自的值进行解释。
这意味着数字“1”将首先被解释,并且只被打印一次。数字“2”将被第二次执行并打印两次,以此类推。
代码:
在这个程序中,我们指定了将要相应解释的行数。之后,我们运行内部循环,它根据我们拥有的行数执行。
此后,我们将在每次执行完成时打印“I”。“I”指定了第 I 行和数字“I”,必须在每次连续迭代中打印出来。这意味着数字“1”将首先被解释,并且只被打印一次。数字“2”将被第二次执行并打印两次,以此类推。
模式 3:带星号’ * '的半金字塔
作者截图
下一个模式程序应该很简单,因为我们之前已经解决了两个类似的问题。事实上,这可以通过两种方法来实现。
这两种解决方法都是前面两个问题中提到的。唯一的替换是使用星号“*”代替数字“I”或“j”。请注意,也可以使用其他符号,如哈希“#”,但方法保持不变。
代码:
方法 1:
方法 2:
上面显示的两个代码块都是解决这个模式程序的有效方法。
我们正在计算范围,直到行数,然后执行所需的星号值,相当于行数。光标移动到下一行之后,是代码块的内部“j”循环所建议的代码。
模式 4:反半金字塔变体 1
作者截图
我们将遇到的下一个模式程序是数字的逆半金字塔。这里,我们有五行类似于前面的问题。我们必须从提到的最大行数开始,一直到只包含一个数字的底部。
对于接下来的几个模式程序,我们将使用使用 range(N,-1,-1)的反向迭代逻辑,它表示迭代数的反向实现。
代码:
上面的代码块显示了两个连续的 for 循环,以相反的方式执行外部和内部迭代。这里,我们从第一行开始,反向打印五个数字。这种实现将导致行数递减,直到达到循环数的可持续极限。
模式 5:反半金字塔变体 2
作者截图
这个模式程序是先前解决的反半金字塔问题的第二个变体。逻辑很简单。共有 5 行,我们打印的行数与每一行的行数相反。
即使对于这个模式程序,我们也将使用使用 range(N,-1,-1)的反向迭代逻辑,这表示迭代数字的反向实现。
代码:
上面的代码块显示了两个连续的 for 循环,以相反的方式执行外部和内部迭代。这里,我们从第一行开始,反向打印五个数字。
在这个实现中打印的数字将导致行数的降序,直到我们达到循环数的可持续结尾,并且每个打印的数字等于循环的逆序。
模式-6:带星号“*”的反半金字塔变异
作者截图
即使对于这个模式程序,我们也将使用使用 range(N,-1,-1)的反向迭代逻辑,这表示迭代数字的反向实现。逻辑类似于前面两个相应解释的模式程序。
代码:
解释类似于前两个反半金字塔模式程序。我们只是打印符号,而不是行号或列号。
模式 7:数字变化的半金字塔-3
作者截图
这是本文的最后一个半金字塔实现。我们按照升序打印每个数字。如前面的模式程序所示,行和列将递增。但是,我们将使用增量计数来计算增加的数字。
代码:
这里,在上面的代码块中,我们用变量“num”指定了一个计数,该计数从 1 开始,并相应地递增。行数和列数将分别用’ ith ‘和’ jth’ for 循环处理。对于同一个问题,我建议尝试相反的实现。
模式 8:带星号’ * '的完整金字塔
作者截图
我们今天要分析的最后一个模式程序是带星号的全金字塔。为了更好地从概念上理解,您也可以自由地尝试使用数字。
我们将根据问题使用一个额外的变量来计算所需的空间。行和列的计算将与前面的模式编程问题中处理的几乎相同。
代码:
在这个模式程序中,我们使用数字“n”来表示用户的输入。“k”变量用于计算相应的空格数。一旦计算出空格的数量,我们将减去剩余的空格。第 I 行和第 j 列的计算类似于所有其他模式程序。
Artem Sapegin 在 Unsplash 上拍摄的照片
结论:
在本文中,我们设法涵盖了面试中可能会问到的大多数基本模式编程问题,以及如何系统地解决这些问题。
在编程的世界中有许多可能的模式,并且通过使用您选择的编程语言,您可以构建更多的模式。
如果你们对这些感兴趣,那么我也会制作第二部分,涵盖更多类似的模式编程问题,这些问题可能会在面试中被问到。
此外,如果您对我们今天解决的问题有任何疑问,观众可以随时告诉我。此外,请随意建议更多您认为我应该在未来涵盖的问题模式。
看看我的其他一些文章,你可能会喜欢读!
打破人工智能领域和它的未来。
towardsdatascience.com](/demystifying-artificial-intelligence-d2887879aaf1) [## 用代码和例子简化函数的 args 和 kwargs!
理解 python 编程和机器学习的args 和kwargs 的完整概念。
towardsdatascience.com](/simplifying-args-and-kwargs-for-functions-with-codes-and-examples-b785a289c2c2) [## 简单有趣的万圣节 Python 项目!
这是一个有趣的“不给糖就捣蛋”的游戏,让你在万圣节愉快地学习 python 编程
towardsdatascience.com](/simple-fun-python-project-for-halloween-ff93bbd072ad) [## 5+独特的 Python 模块,用于创建脱颖而出的机器学习和数据科学项目!
超过 5 个酷 Python 库模块的指南,用于创建令人敬畏的机器学习和数据科学项目。
towardsdatascience.com](/5-unique-python-modules-for-creating-machine-learning-and-data-science-projects-that-stand-out-a890519de3ae)
谢谢你们坚持到最后。我希望你们喜欢阅读这篇文章。我希望你们都有美好的一天!
Edge TPU 问题的解决方案
了解如何解决使用 TPU USB 加速器时的常见问题
在这篇文章中,我将分享我在 Edge TPU USB 加速器上制作深度学习模型时遇到的一些常见错误以及对我有效的解决方案。
来源:https://coral.ai/products/accelerator/
Coral USB 加速器是一种专用集成芯片(ASIC ),可为您的机器增加 TPU 计算能力。额外的 TPU 计算使深度学习模型的边缘推断更快更容易。
把 USB 加速器插在 USB 3.0 口,复制 TFLite Edge 模型,连同做推论的脚本,就可以开始了。它可以在 Mac、Windows 和 Linux 操作系统上运行。
要创建 Edge TFLite 模型并使用 USB 加速器在边缘进行推理,您将使用以下步骤。
- 创建模型
- 训练模型
- 保存模型
- 应用培训后量化
- 将模型转换为 TensorFlow Lite 版本
- 使用 edge TPU 编译器编译 tflite 模型,用于 Coral Dev board 等 Edge TPU 设备到 TPU USB 加速器
- 在边缘部署模型并进行推理
问题 1:使用 edgetpu_compiler 编译 TfLite 模型时,出现错误“内部编译器错误。中止!”
出错的代码
**test_dir='dataset'**
**def representative_data_gen():
dataset_list = tf.data.Dataset.list_files(test_dir + '\\*')
for i in range(100):
image = next(iter(dataset_list))
image = tf.io.read_file(image)
image = tf.io.decode_jpeg(image, channels=3)
* image = tf.image.resize(image, (500,500))*
image = tf.cast(image / 255., tf.float32)
image = tf.expand_dims(image, 0)**# Model has only one input so each data point has one element
**yield [image]****keras_model='Intel_1.h5'**#For loading the saved model and tf.compat.v1 is for compatibility with TF1.15 **converter=tf.compat.v1.lite.TFLiteConverter.from_keras_model_file(keras_model)**# This enables quantization
**converter.optimizations = [tf.lite.Optimize.DEFAULT]**# This ensures that if any ops can't be quantized, the converter throws an error
**converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]**# Set the input and output tensors to uint8
**converter.inference_input_type = tf.uint8
converter.inference_output_type = tf.uint8**# set the representative dataset for the converter so we can quantize the activations
**converter.representative_dataset = representative_data_gen
tflite_model = converter.convert()**#write the quantized tflite model to a file
**with open('Intel_1.tflite', 'wb') as f:
f.write(tflite_model)****with open('Intel_1.tflite', 'wb') as f:
f.write(tflite_model)
print("TFLite conversion complete")**
将模型转换为 Tflite 后,为 Edge TPU 编译模型
这个错误没有描述,您被留在黑暗中解决这个问题。
对我有效的解决方案
我创建了两个定制模型,它们具有相同的架构,但不同的数据集,不同的类数量,并使用相同的步骤来编译这两个 tflite 模型。
一个模型编译成功,而另一个模型给出了“内部编译器错误”
现在我知道这不是创建边缘 TPU 模型的模型或步骤,而是与数据相关的东西。
关于这个问题的讨论:https://github.com/tensorflow/tensorflow/issues/32319帮助我尝试不同的选择。
我的解决方案是缩小图像尺寸,瞧,它成功了!!!
这个解决方案为什么有效?
减小图像尺寸可能有助于用于创建代表性数据集的激活范围。
代表性数据集有助于精确的激活动态范围,用于量化模型。
当我们量化模型时,我们将用于表示 TensorFlow 模型的权重、激活和偏差的数字的精度从 32 位浮点降低到 8 位整数,这有助于使模型变得轻量。
TFLite 和 EdgeTPU 模型是轻量级的,因此我们具有更低的延迟、更快的推理时间和更低的功耗。
下图显示了以 H5 格式、TFlite 模型和 EdgeTPU 保存的模型的大小差异。
我又尝试了一件事来固化我的理解;我试图在 Edge TPU 运行时版本的较低版本中编译具有更高图像维度(500,500)的相同错误模型。
它编译了,但是整个模型将在 CPU 而不是 TPU 上运行,这表明量化模型仍然有一些浮点运算。
我用图像尺寸(100,100)而不是(500,500)重新训练模型
有效的代码。
**keras_model='Intel_epoch50_batch16.h5'**#For loading the saved model and tf.compat.v1 is for compatibility with TF1.15 **converter=tf.compat.v1.lite.TFLiteConverter.from_keras_model_file(keras_model)**# This enables quantization
**converter.optimizations = [tf.lite.Optimize.DEFAULT]**# This ensures that if any ops can't be quantized, the converter throws an error
**converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]**# Set the input and output tensors to uint8
**converter.inference_input_type = tf.uint8
converter.inference_output_type = tf.uint8**# set the representative dataset for the converter so we can quantize the activations
**converter.representative_dataset = representative_data_gen
tflite_model = converter.convert()**#write the quantized tflite model to a file
**with open('Intel_class.tflite', 'wb') as f:
f.write(tflite_model)**with open('Intel_epoch50_batch16.tflite', 'wb') as f:
f.write(tflite_model)
现在该模型用最新版本的 Edge TPU 编译器编译。
随着维度的变化,现在大部分操作将在 TPU 上运行。
Edgetpu 日志文件
问题 2: ValueError:在操作“reshape”的输入数组中发现过多维度
在 tflite 模型成功编译 edgetpu_compiler 之后,我们实例化了用于推理的解释器。遇到错误“ValueError:在操作“reshape”的输入数组中发现过多维度。
我在这个帖子里回复了关于我的解决方案的讨论:【https://github.com/google-coral/edgetpu/issues/74
对我有效的解决方案
问题在于我用于训练后量化的代表性数据集。用于创建代表性数据集的数据集比我在 images 文件夹中提供的图像更多。
我的 test_dir 有 99 个图像,我将范围设置为 100。当我将用于代表性数据集的数据集与文件夹中的图像数量进行匹配时,问题就解决了。
**def representative_data_gen():
dataset_list = tf.data.Dataset.list_files(test_dir + '\\*')
for i in range(99):
image = next(iter(dataset_list))
image = tf.io.read_file(image)
image = tf.io.decode_jpeg(image, channels=3)
image = tf.image.resize(image, (100,100))
image = tf.cast(image / 255., tf.float32)
image = tf.expand_dims(image, 0)**# Model has only one input so each data point has one element
**yield [image]**
结论:
一步一步,排除变量会引导你找到根本原因。我使用 5W 和 1H 技术,其中 5W 代表谁、什么、哪里、何时、为什么,而 1 H 代表如何。
使用深度学习和人工智能解决现实世界的问题
由 Unsplash 上的Carlos“Grury”Santos拍摄的照片
变更数据
不是你通常的物体检测博客
每一项新技术的引入都有一个目的(几乎总是如此)。通常,它是由它的创建者在头脑风暴时确定的某个问题的解决方案。但当我们谈论人工智能时,这是一个很大程度上未经探索但不断发展的计算领域,我们经常被打扮得漂漂亮亮的对象检测项目分散注意力。
我们都知道,正确分类手写数字或区分动物并不是 Geoffrey Hinton 和 Alexey Ivakhnenko 等研究人员在将他们的生命奉献给该领域时所想的应用。人工智能有可能改变我们的生活方式。证据就在你的口袋里。从你最喜欢的视频流媒体平台到你的在线出租车服务,人工智能的基本原则正被到处使用。
但是对于那些口袋里没有 20 世纪的超级计算机或者口袋里没有任何东西的人来说呢?那些每天晚上饿着肚子睡觉,醒来发现生活中的怪物的人呢?
我们需要明白,人工智能及其子集不仅仅是数学或算法,它们可以神奇地预测一些事情。数据是真实的交易。这些没有数据的算法就像你的手机没有互联网一样。绝对没用。(除非你安装了离线游戏)
但问题就出在这里。如果我们想使用人工智能来诊断/治疗疾病,防止气候变化的剧烈影响或跟踪即将到来的流行病,我们需要真实的私人数据。除非有办法在工程师无法检索或查看的数据上训练深度学习模型。
近年来,已经有相当多的研究来保护用户的隐私,以解决需要私人用户数据的现实世界的问题。谷歌和苹果等公司一直在大力投资去中心化的隐私保护工具和方法,以提取新的“石油”,而不是从所有者那里“提取”。我们将在下面探讨其中的一些方法。
联合学习
从本质上来说,联合学习是一种利用驻留在世界各地(不同设备上)的用户的数据来回答问题的方法。安全多方计算(SMPC)是一种加密协议,不同的工作人员(或数据生产者)使用它在分散的数据集上进行训练,同时保护用户的隐私。该协议用于联合学习方法中,以确保驻留在用户处的私有数据不会被试图获得洞察力和解决全球问题的深度学习实践者看到。
然而,这种技术容易发生逆向工程,正如一个名为 OpenMined 的组织成员在这篇论文 中所述。他们一直试图通过在研究人员和从业者日常使用的常用工具上开发这样的框架来普及人工智能中的隐私概念。
联合学习最好的例子是你的 Gboard(如果你用的是 android 设备)。简单来说,它接受你键入句子的方式,试图分析你使用的是什么样的单词,然后试图预测你可能键入的下一个单词。有趣的事实是,训练发生在设备本身(边缘设备)上,而不会向设计算法的工程师透露数据。复杂又时髦,是吧?
差异隐私
想象一下,你有一个包含某些条目的数据集,可能是像一个人在患有新冠肺炎时是否有遗传劣势这样的东西。现在,不用实际查看数据携带了关于每个个体的什么信息,您可以尝试理解单个条目对整个数据集的输出结果有什么意义。一旦我们做到了这一点,我们就能对这个结果是如何形成的有所了解。
正如《差分隐私的算法基础》一书中所述,差分隐私解决了这样一个悖论:在学习关于一个群体的有用信息的同时,却对一个个体一无所知。引用 Cyntia Dwork 对差分隐私的准确定义,
“差异隐私”描述了数据持有人或管理人对数据主体做出的承诺,该承诺如下:
“您不会因为允许您的数据用于任何研究或分析而受到不利或其他方面的影响,无论其他研究、数据集或信息来源是否可用”
然而,差分隐私有很多缺点,因为它高度依赖于数据集的性质。如果单个条目过于多样化(这是很有可能的),整体结果将偏向某些条目,这可能导致关于这些多样化条目的信息泄漏。如果数据中有太多的噪音,就有可能无助于获得有用的见解。
从头开始实现差分隐私方案是非常困难的。就像密码学一样,按照预期的方式构建这些方案既复杂又困难。因此,在训练你的深度学习模型时,最好使用一些流行的隐私保护库,如 TF Privacy 和 Google 的 Differential Privacy 。
差分隐私可以用在很多情况下,我们希望保护用户的隐私,数据集不是太多样化。一个示例用例可以是基因组学,其中机器学习可以用于根据患者的遗传特征为其确定独特的治疗计划。有许多建议的解决方案来实现这个应用与k-匿名,但数据的匿名化并不是保护用户隐私的最佳方式,因为它容易受到链接攻击。差分隐私在训练数据的“过程”中增加了一定程度的不确定性,这使得攻击者的日子不好过,从而确保了隐私。
同态加密
数据加密是当今组织的基本安全标准,如果没有数据加密,他们甚至会被列入黑名单,尤其是在处理私人用户数据时。但是,如果这些组织想要使用这些加密数据,可能是为了增强他们提供的产品的用户体验,我们首先必须解密它,以便能够操作它。这引起了严重的关注,因为信息可能在解密过程中泄露。
同态加密基本上是一种加密,我们可以对加密数据执行某些操作,以获得相关的见解并回答真正重要的问题,而不会损害用户的隐私。即使是量子计算机也无法破解这种类型的加密。
现在,这看起来非常方便,因为数据是加密的,不需要工程师查看数据提供的信息。但同样,它需要大量的计算能力,并且肯定需要大量的时间来执行这些计算。
同态加密有两种类型,具体取决于使用它们可以执行的计算类型,即部分同态加密和完全同态加密。前者仅支持基本运算,如加、减等。而后者理论上可以执行任意操作,但是开销很大。
同态加密的一个假设但非常重要的用例可以在不同国家的大选期间使用,这样投票系统就不会被篡改。许多重要的(事实上正确的)见解也可以从同态加密数据中导出,而不会泄露任何信息。
这些仅仅是在不损害用户隐私的情况下获得解决全球危机的有用见解的许多方法中的几个。我将探索不同的框架和工具来利用这些概念,这样我们就可以建立一些对人们的生活有实际影响的东西。我将在接下来的文章中分享我的见解,敬请关注!
参考
[1] OpenMined:什么是同态加密?https://www.youtube.com/watch?v=2TVqFGu1vhw&feature = emb _ titleT2
[2]隐私保护人工智能(Andrew Trask) |麻省理工学院深度学习系列【https://www.youtube.com/watch?v=4zrU54VIK6k T4
[3]谷歌联邦学习:https://federated.withgoogle.com/
[4]差分隐私的算法基础:https://www.cis.upenn.edu/~aaroth/Papers/privacybook.pdf
【5】什么是同态加密?为什么它如此具有变革性?:https://www . Forbes . com/sites/bernardmarr/2019/11/15/what-is-homo morphic-encryption-and-why-it-so-transformation/# 3f 69895 b7e 93
【6】为什么差分隐私很牛逼?Ted 正在写东西:https://desfontain . es/privacy/differential-privacy-awesome ness . html
[7]tensor flow 隐私介绍:训练数据的差分隐私学习:https://blog . tensor flow . org/2019/03/Introducing-tensor flow-Privacy-Learning . html
[8] Azencott C.-A. 2018 机器学习与基因组学:精准医疗与患者隐私菲尔。反式。R. Soc。 37620170350
用 Python 中的 Crook 算法更优雅地解数独
不再胡乱猜测玩数独了
数独过去是(现在对我来说仍然是)一种消磨时间和训练大脑的令人上瘾的数字游戏。即使现在,我仍然在书店里看到提供数独练习的书,当然还有许多应用程序在应用程序商店里提供练习。
但是,当任何一个挑战落到程序员手里,他马上会想到的是如何用一个脚本来解决。数独也不例外。一个常见的解决数独的方法是使用回溯(又名蛮力)。此方法是深度优先搜索,测试的整个分支,直到该分支违反规则或该分支是解决方案。
虽然这几乎可以保证找到解决方案,但蛮力并不享受我不太喜欢的数独之美。因此,我正在寻找一种更优雅的方式来解决数独。确实有一个。
索引
克鲁克算法
温斯罗普大学计算机科学教授詹姆斯·克鲁克(James Crook)发表了一篇名为“解决数独难题的纸笔算法”(链接)的论文。他创造了一种解决数独的算法,他说这种算法可以在物理上应用。该算法应用数独中的所有规则,并使用更数学的方法来解决数独。不涉及复杂的规则。所以我把这个算法转换成一个 Python 脚本
在介绍这个算法之前,我想提两点:
- 在论文中,克鲁克提到,如果没有进一步的可能步骤,猜测是必要的。我不包括对剧本的猜测。所以你用这个算法解数独的时候,有可能得不到解。
我们开始吧。
(PS:我假设你已经知道数独的规则,因此我不会详细解释这些规则。如果你不知道,请去维基百科查一下。
步骤
第一步:标记
第一步很简单,在每个单元格中列出所有可能的数字。
如果你用一个应用程序玩数独,应该已经有一个功能允许你在一个单元格中写下一些可能的数字。在算法的第一步,对于每个单元格,你按照规则,写下所有可能的数字。
第二步:寻找单身者
团队“单身”看起来很复杂。然而,这个概念很简单,找到是否有一个行、列或框在整个行、列或框中只有一个可能的值。由于每一行、列和框中有且只有一个数字,如果行、列或框中只有一个具有相应数字的单元格,则该数字必须在该单元格中。因此,您用这个数字填充这个单元格,然后更新受影响的行、列或框中的标记。
第三步:寻找抢占式集合
这一步很难,因为我花了很多时间来理解这一部分。下面是克鲁克论文中抢占式集合的定义。
抢占式集合由集合[1,2,.]中的数组成。。。,9]并且是大小为 m 的集合,2 ≤ m ≤9,其数是 m 个单元的唯一潜在占有者,其中唯一意味着集合[1,2,.。。,9]是这 m 个小区的潜在居住者。
先占式集合由{[n₁、n₂表示。。。,nₘ],[c (i₁,j₁),c(i₂,j₂]。。。,c(iₘ,jₘ)]},那里[n₁,n₂,。。。,nₘ],对于 i = 1,2,.,1≤ nᵢ ≤9。。。m 表示先占集合中的数的集合,而[c (i₁,j₁),c(i₂,j₂],。。。,c(iₘ,jₘ)]表示 m 个单元的集合,其中集合[n₁,n₂,.。。nₘ]及其子集专门出现。
抢占式集合的范围是抢占式集合的所有单元格所在的行、列或框。当 m = 2 或 3 时,范围可以是集合[行,框]或[列,框]中的一个。
简而言之,如果 m 个数字是一行、一列、一个框、[行、框]或[列、框]内 m 个单元格的标记的集合或超集,那么这个数字和单元格的组合就是一个抢占式集合。
步骤 4:排除抢占式集合之外的可能数字
这一步是算法中最重要的部分,有助于减少可能的单元数量。
设 X 是数独难题标记中的一个先占集合。那么 X 中出现在 X 范围内不在 X 中的单元格的标记中的每个数字都不可能是难题解答的一部分。
在此步骤中,对于抢占式集合中的所有数字,它们不可能是抢占式集合之外的单元的可能数字。这里的原因很简单,因为每个数字在每一行、列或框中只能出现一次。如果这个数在抢占式集合中,这个数必须放在集合中的那些单元格中。因此,同一行、列和框中的所有单元格都不能将此数字作为标记中的可能数字。
Python 程序
项目链接:https://github.com/wyfok/sudoku
需要一个 excel 来存储单元格 A1 到 I9 中的数独问题。缺少的单元格用 0 填充。在 main.py 中,在提供 excel 文件的文件路径和问题的工作表名称后,程序将运行基本的数独规则和 Crook 算法,直到结果不再更新。然后程序会打印出结果,不管这个结果是不是解。
问题
解决办法
基本上,整个 Python 程序循环每个规则,并更新标记和解决方案。例如,下面是检查每一行的函数。如果一个可能的数字只出现在一个单元格中,那么这个数字就是这个单元格的解。
下面是应用克鲁克算法的功能。该函数将尝试从最大的可能数字集合到最小的数字集合中找到一个抢占式集合。如果一个单元格中的可能数字的大小与其中的可能数字是该单元格的子集的单元格的数量相匹配,则该函数将消除抢先集之外的单元格的所有可能数字。
请随意使用我的程序来解决你的数独问题。如果您有任何问题,请随时留下您的评论。下次见。
参考:
http://pi . math . Cornell . edu/~ mec/summer 2009/meerkamp/Site/Solving _ any _ Sudoku _ ii . html【http://www.ams.org/notices/200904/rtx090400460p.pdf】T2
自动解决数独
通过用 Python 实现数独求解算法,并用 PyAutoGUI 自动化人机交互
在这篇文章中,我将介绍如何制作自己的脚本来解决数独难题。此外,PyAutoGUI 增强了这个脚本,使数独求解相当自动化(您只需执行代码)。
我把这篇文章分成以下几部分:
- 数独入门——这个简短的部分涵盖了必须牢记的基本规则;
- 数独解决算法——这部分从定义必要的数据结构开始,我们将创建一个算法来解决任何给定的难题;
- 自动化——如果你的脚本知道一个谜题的一步一步的解决方法,那就太酷了。如果你的代码与网页交互并自动解决数独,那就更酷了。
我希望您已经安装了 Python、Pillow 和 PyAutoGUI 模块。如果你还没有 PyAutoGUI,那么你应该按照这里的安装。
数独规则
数独术语解释。来源:https://www.pinterest.com/pin/468796642443225725/
重要的事情先来。如果你不熟悉数独游戏的规则,不要害怕。它们非常简单:
您必须用 1 到 9 的数字填充 9x9 网格的方框,以使每行、每列和 3x3 块中没有重复出现的数字。
如果你看一下这张图片,左上角的框中唯一合适的数字是 2,因为它是唯一一个没有出现在这一行、列和框中的数字。
数独和数据结构示例
来自互联网的随机难题
我们从网上随便拿一个数独谜题,试着用 Python 来解。我建议我们将这个难题作为一个二维 Python 数组来处理,其中空盒子用零表示,其他盒子用相应的数字表示。我们应该获得以下内容:
sudoku = [[8, 1, 0, 0, 3, 0, 0, 2, 7],
[0, 6, 2, 0, 5, 0, 0, 9, 0],
[0, 7, 0, 0, 0, 0, 0, 0, 0],
[0, 9, 0, 6, 0, 0, 1, 0, 0],
[1, 0, 0, 0, 2, 0, 0, 0, 4],
[0, 0, 8, 0, 0, 5, 0, 7, 0],
[0, 0, 0, 0, 0, 0, 0, 8, 0],
[0, 2, 0, 0, 1, 0, 7, 5, 0],
[3, 8, 0, 0, 7, 0, 0, 4, 2]]
当试图从第 i 行和第 j 列访问某个元素时,只需调用
sudoku[i][j]
让它看起来更像一个真正的数独游戏
当然,这个二维 python 数组看起来不像没有任何网格线的真正的数独。因此,最好能打印出谜题的当前状态。下面是代码示例及其输出。
def printsudoku():
print("\n\n\n\n\n")
for i in range(len(sudoku)):
line = ""
if i == 3 or i == 6:
print("---------------------")
for j in range(len(sudoku[i])):
if j == 3 or j == 6:
line += "| "
line += str(sudoku[i][j])+" "
print(line)
一个 printsudoku 函数的示例输出
我们开始吧!现在我们已经准备好一步一步地创建算法。
免责声明:我没有完全自己创造这个数独解决算法。想法和实现都是从麻省理工学院 open 课件 Youtube 频道抄袭来的,更具体的说是从这个 视频 。然而,它被-NC-SA 许可为知识共享,这给我的共享开了绿灯。
第一步。寻找未填充的单元格
要求解某个单元格,我们必须首先找到空单元格的行号和列号。下面的函数完成了这个任务。
def findNextCellToFill(sudoku):
for x in range(9):
for y in range(9):
if sudoku[x][y] == 0:
return x, y
return -1, -1
这将遍历第一行中的所有列,然后是第二行,依此类推。每当遇到空单元格时,该函数都会返回相应的索引。简单!
第二步。验证条目
假设我们有一个条目。我们需要一个函数来检查当放置到第 i 行和第 j 列时是否违反了数独的三个主要规则。如果没有违反这三个规则,下面的函数返回 True 。否则,该函数将返回假。
def isValid(sudoku, i, j, e):
rowOk = all([e != sudoku[i][x] for x in range(9)])
if rowOk:
columnOk = all([e != sudoku[x][j] for x in range(9)])
if columnOk:
secTopX, secTopY = 3*(i//3), 3*(j//3)
for x in range(secTopX, secTopX+3):
for y in range(secTopY, secTopY+3):
if sudoku[x][y] == e:
return False
return True
return False
检查了三个规则:
- rowOk:这个检查第 i 行是否没有重复的数字;
- columnOk:这个函数确保第 j 列中没有重复的数字;
- 如果 rowOk 和 columnOk 都为真,那么第 6–10 行检查该条目是否适合某个块。
第三步。解开谜题
现在一切都是为了解决给定的数独。我们将使用以下函数来实现:
def solveSudoku(sudoku, i=0, j=0):
i, j = findNextCellToFill(sudoku)
if i == -1:
return True for e in range(1, 10):
if isValid(sudoku, i, j, e):
sudoku[i][j] = e
if solveSudoku(sudoku, i, j):
return True
sudoku[i][j] = 0
return False
该函数的前三行确保我们的拼图中有一个空单元格。如果 I = 1,那么我们就完成了解谜。
如果在第 i 行和第 j 列有一个空单元格,那么它会尝试将 1 到 9 的所有可能条目放入这个框中。如果条目有效(由 isValid 函数验证),则尝试在假设这是正确条目的情况下递归求解数独。
如果我们的假设是错误的,那么第 9 行将返回假,这将把第 i 行和第 j 列中的单元格的值设置为零。
要解决我们的数独,进行以下函数调用:
solveSudoku(sudoku)
printsudoku()
第一个解决了我们的难题,后者给出了解决方案。太好了!
从解决方案到自动化
自动化部分分为两个部分:
- 在数独网格上定位数字。这样我们可以解决任何数独,而不必手动填充数独变量。
- 用数字填充空白单元格。
我们通过使用 PyAutoGUI 模块来实现自动化。请在您的代码中导入它。
import pyautogui as pag
从我们的显示器上读取数独
准备
我们将要解决来自 网络数独 的随机数独难题。打开一个随机拼图,保存每个数字的图像片段。它们都应该保存到与 Python 脚本相同的文件夹中。确保文件格式为. png。
保存每个号码的图像片段
这些片段可以有不同的尺寸,只要它们都只在白色背景上显示一个数字。我们先把它们命名为“1.png”、“2.png”等。
定位号码
PyAutoGUI 模块有一个在屏幕上定位给定图像的功能。就我而言
for pos in pag.locateOnScreen("3.png"):
print(pos)
返回屏幕上第三个位置的所有信息:
Box(left=1124, top=510, width=32, height=33)
Box(left=959, top=845, width=32, height=33)
前两个参数(left 和 top)给出了图像左上角的像素坐标。第三个和第四个给了我们图像的尺寸,但是现在我们不需要它们。
要获取所有数字的位置,请使用以下命令:
for i in range(1, 10):
for pos in pag.locateAllOnScreen(str(i)+'.png'):
print(pos)
填充数独数组
因为我们不打算使用之前的数独数组,所以让我们把这个数组中的所有数字都变为零:
sudoku = [[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0]]
现在让我们定义拼图上两个单元格的像素坐标:左上和右下。在我的案例中,数字是:
topleftx = 975
toplefty = 507
bottomrightx = 1307
bottomrighty = 846
现在我们有了它们,让我们定义一个盒子的宽度和高度:
boxwidth = (bottomrightx - topleftx)/8
boxheight = (bottomrighty - toplefty)/8
解释:看一行单元格时,最左边的单元格到最右边的单元格的距离是 8 个框宽。这同样适用于列。因此,我们必须将坐标差除以 8。
现在我们必须定义一个函数,用正确的数字替换数独数组中的零。
def fillsudoku(nr, pos):
global sudoku
indexlocx = int((pos[0] - topleftx + boxwidth/2)//boxwidth)
indexlocy = int((pos[1] - toplefty + boxheight/2)//boxwidth)
sudoku[indexlocy][indexlocx] = nr
我不打算解释数学,但它需要一个 Box 对象,并找到我们的数字的“索引坐标”。如果到目前为止你已经正确地做了每件事,那么它将完美地工作。
最后,让我们用屏幕上的信息填充数组:
for i in range(1, 10):
for pos in pag.locateAllOnScreen(str(i)+'.png'):
fillsudoku(i, pos)
如果您从 IDE 跳转到 web 浏览器的速度不够快,请在代码的开头添加以下延迟方法:
import timetime.sleep(5) #this makes a 5 second delay to executing the script
填充空单元格
太好了!现在我们有了一个使用屏幕信息填充我们的数独数组的方法。既然我们有了求解算法,那么我们可以立即求解。为此,我们只需要以下函数:
def fillcell(nr, x, y):
xcoord = topleftx + boxwidth * x
ycoord = toplefty + boxheight * y
pag.click(xcoord, ycoord)
pag.press(str(nr))
这里我们有三个输入参数:
- nr :这是我们要插入的号码;
- x :我们要插入的单元格的列索引NR;**
- y :我们要插入的单元格的行索引NR;**
第 2–3 行找到单元格中点的近似坐标,我们必须插入数字。第 4-5 行单击该单元格并写下该数字。
哦是的!还有一件事。在解数独之前,请创建一个数独数组的副本。稍后我会解释。
import copysudokucopy = copy.deepcopy(sudoku)
将碎片拼在一起
为了保持一致,我将在下面嵌入一个 Github 要点:
到目前为止,我们从屏幕上读取了数独并解决了它。在试图解决它之前,我们也有两个相同的数独数组: sudoku 和 sudokucopy 。
制作数独游戏是为了比较我们拼图的初始和最终状态,并填充空白单元格。
for x in range(9):
for y in range(9):
if sudokucopy[x][y] == 0:
fillcell(sudoku[x][y], y, x)
接下来呢?
现在可以执行了,如果您的配置是正确的,它应该是这样的:
当然,可以做一些改进:
- 我花了大约 20 秒将数据从屏幕加载到数独数组。您可以使用一些不同的模块(或创建自己的模块)来加快速度。
- 修改数独求解算法,使自动求解部分看起来更像人类的思维。现实生活中没有人能解决上面动画中显示的难题。
请随意修改这个实现,并在不同的谜题上测试它(甚至是最极端的谜题)。
如果你读完整篇文章,我想感谢你。如果你有任何想法或者修改了代码,让我在评论区知道。😃
解决 MNIST 图像分类问题
“你好,世界!”深度学习和 Keras
求解 MNIST 是机器学习模型的一个基准。这也是你进入深度学习领域时首先会遇到的问题之一。
在本文中,我们将设计一个神经网络,它使用 Python 库 Keras 来学习对 MNIST 数据集的手写数字进行分类。
解决 MNIST 问题的疯狂之处在于,它根本不消耗资源。你不需要 GPU 。我们在这里建立的模型可以在不到一分钟的时间内在任何现代 CPU 上快速训练。
手写数字的 MNIST 数据集
关于 MNIST 数据集
MNIST 数据集是一组 60,000 幅训练图像加上 10,000 幅测试图像,由美国国家标准与技术研究所(NIST)在 20 世纪 80 年代汇编而成。这些图像被编码为 NumPy 数组,标签是一个数字数组,范围从 0 到 9。图像和标签是一一对应的。
设置 Keras 和相关性
假设您已经安装了 Anaconda ,我们将简要讨论安装 Keras 和其他依赖项。
虽然 Anaconda 在默认情况下捆绑了很多好东西,但它没有预装 Keras。然而,Anaconda Cloud 的好人们在这里有一个定制的 Keras 包。
您可以使用命令行从conda-forge
通道安装它。
$ conda install --channel conda-forge keras
深度学习教育学
- 绘制训练样本和相应目标的映射,即加载数据。
- 创建网络架构。
- 选择一个损失函数、一个优化器和度量标准,以便在测试和培训期间进行监控。
- 根据需要对数据进行预处理。
- 对训练样本运行网络,即正向传递以获得预测。
- 计算批次上的网络损耗。
- 更新网络的所有权重,减少批次损失。
解决 MNIST 图像分类问题
MNIST 图像分类问题是一个多类分类问题。让我们实施上面讨论过的教学方法。
采用的工作流程简单。我们将把训练数据输入神经网络。然后,网络将学习关联图像和标签。最后,网络将对测试数据和达到的准确度进行预测。
步骤 1:加载数据
MNIST 数据集以一组四个 NumPy 数组的形式预装在 Keras 中。我们将使用load_data()
函数加载数据集。
加载用于训练和测试的数据
步骤 2:网络架构
我们将使用密集连接的(也称为完全连接的 ) 顺序神经层来构建网络。*层是神经网络的核心构建块。它们是基本的张量运算,实现了渐进式的“数据提炼”
(前面混乱的句子,仔细阅读*)*
层将它之前的层的输出作为输入。
-
- *因此,层的输入的“形状必须与前一层的输出的“形状相匹配。”
-
- 连续层根据前一层的输出动态调整输入到该层的形状,从而减少程序员的工作量。
为了创建我们的网络,
包括两个密集连接的顺序神经层的网络体系结构
我们的网络由两个完全连接的层组成。第二层(也是最后一层)是一个 10 路 softmax 层,它返回 10 个概率得分的数组。每个分数是当前数字图像属于我们的 10 个数字类之一的概率。
第三步:编译
现在让我们选择一个优化器,一个用于评估模型性能的损失函数&指标。
选择三连胜。这个步骤对网络的准确性有最大的影响
步骤 4:预处理图像数据
我们将通过将整形为网络期望的形状,并通过缩放使所有值都在[0,1]区间内,来预处理图像数据。
以前,我们的训练图像存储在类型为uint8
的 shape (60000,28,28)数组中,其值在[0,255]范围内。我们将把它转换成一个形状为(60000,28 * 28)的float32
数组,其值在 0 和 1 之间。
预处理输入数据
然后我们将使用keras.utils
中的to_categorical
函数对标签进行分类编码
编码目标
现在,我们准备训练我们的网络。
第五步:开始训练
Keras 通过调用网络的fit()
方法来训练网络。我们使模型符合它的训练数据。
训练神经网络
随着网络的训练,你会看到它的准确性增加,损失减少。您在这里看到的时间是与 i7 CPU 相对应的训练时间。
Epoch 1/5
469/469 [==============================] - 5s 10ms/step -
loss: 0.2596 - accuracy: 0.9255
Epoch 2/5
469/469 [==============================] - 5s 10ms/step -
loss: 0.1047 - accuracy: 0.9693
Epoch 3/5
469/469 [==============================] - 5s 11ms/step -
loss: 0.0684 - accuracy: 0.9791
Epoch 4/5
469/469 [==============================] - 5s 10ms/step -
loss: 0.0496 - accuracy: 0.9851
Epoch 5/5
469/469 [==============================] - 5s 11ms/step -
loss: 0.0379 - accuracy: 0.9887
我们已经获得了98.87%
的训练精度。这个度量告诉我们,我们的网络正确地分类了测试数据中 98.87%的图像。
步骤 6:评估网络性能
MNIST 数据集保留了 10,000 张图像,我们将通过在这个以前从未见过的数据集上测试来评估我们网络的性能。
评估模型性能
313/313 [==============================] - 1s 3ms/step - loss: 0.0774 - accuracy: 0.9775
Test Loss: 0.07742435485124588
Test Accuracy : 97.75000214576721 %
我们获得了测试精度97.75%
,由于过度拟合,与训练精度相比,这是可以理解的。
可视化网络
为了可视化我们的神经网络,我们需要几个额外的依赖项。您可以使用安装它们
$ $HOME/anaconda/bin/pip install graphviz$ pip3 install ann-visualizer
我们将使用ann-visualizer
将我们的神经网络可视化为一个图形。这一步是可选的;您可以选择不可视化您的网络。然而,看图表无疑更有趣。
graphviz
是对ann-visualizer
的依赖
使用 ann-visualizer 可视化网络。
这是你的神经网络。
MNIST 神经网络。输入层由 786(28×28)个节点组成。所有节点都连接到第一层上的每个其他节点,即全连接或密集连接的网络。
关于可视化神经网络的更多信息,请查看您刚刚使用的ann-visualizer
的 GitHub 库。
一个很棒的可视化 python 库曾经与 Keras 一起工作。它使用 python 的 graphviz 库来创建一个可展示的…
github.com](https://github.com/Prodicode/ann-visualizer)
结论
恭喜你!你已经成功跨过了深度学习的门槛。如果这是你第一次涉足神经网络,我希望你喜欢它。
我建议你配合这篇文章。你可以在十分钟之内解决 MNIST 图像分类问题。确保对我们之前讨论的教学法给予足够的重视。这是全面解决和实现神经网络的基础。
我假设读者对诸如优化器、分类编码、损失函数和度量标准之类的技术细节已经有了很好的理解。你可以在这里找到我关于这些概念的练习笔记。
更多内容,请查看 Francois Chollet 的《用 Python 进行深度学习》一书。
感谢阅读!
期望最大化算法:解决一个先有鸡还是先有蛋的问题
作者照片。
流行的期望值最大化算法背后的直觉和示例代码
著名的 1977 年出版的期望最大化(EM)算法[1]是 20 世纪后期最重要的统计论文之一。EM 的目标不是简单地将分布模型拟合到数据,而是将模型拟合到数据的高级(即潜在)表示。本文的目的是描述 em 算法如何迭代计算两个相互依赖的未知数,这很像一个先有鸡还是先有蛋的问题。
EM 算法的主要优势是它能够在无监督的任务中处理未标记的数据,以及正确性证明,这保证了最终将达到局部最大值或“足够好”的解决方案。它的实用性得到了各种应用的支持,包括无标签图像分割、无监督数据聚类、修复缺失数据(即插补)或发现原始数据的更高级(潜在)表示。
为了理解 EM 算法,我们将在无监督图像分割的环境中使用它。在这个例子中,我们的数据集是由像素集合组成的单个图像。每个基准点或像素都有三个特征,即 R、G 和 B 通道。例如,我们可以将图 1 中的 321 x 481 x 3 图像表示为 154401 x 3 数据矩阵。我们的任务是聚集相关的像素。为了简单起见,让我们考虑一个聚类,其中 k = 2 ,这意味着我们希望将每个像素分配到类 1 或类 2。我们的最终结果将看起来像图 1(右)的**。**
图一。来自 Berkeley 分割数据集[3]的原始图像(左)和使用基于 EM 算法的高斯混合模型(GMM)的聚类分配(右)。**来源:**作者照片。
在这项任务中,EM 算法将用于拟合高斯混合模型(GMM ),以将图像分为两个部分。我们的 GMM 将使用两个(k=2)多元高斯分布的加权和来描述每个数据点,并将其分配给最可能的分布。本例中使用 EM 算法来计算多元高斯分布的参数以及混合权重。
第一节。期望最大化背后的核心思想——概率潜在表征
期望最大化(EM)算法的主要目标是计算数据的潜在表示,它捕捉数据的有用的、潜在的特征。使用概率方法,EM 算法计算数据的“软”或概率潜在空间表示。比如在**图 1 中。**每个像素被分配一个属于类 0 和类 1 的概率。正如我们将在后面看到的,这些潜在空间表示反过来帮助我们提高对潜在统计模型的理解,这反过来帮助我们重新计算潜在空间表示,等等。
EM 算法的核心目标是在改进底层统计模型和更新数据的潜在表示之间交替进行,直到满足收敛标准。
通常,在描述 EM 算法和其他相关概率模型时,使用以下符号。
- X: 原始数据集其中| X | = (#数据点,#特征)。x 可以是连续的或离散的(例如,原始 RGB 值在范围[0,255]内是连续的)。
- P(X|Z,θ): 由 Z where| P(X|Z,θ) | = *(#数据点,#潜变量)指定的底层统计模型 θ 下的完全似然。*潜变量 Z 是离散的,规定了 X 属于哪个统计分布。在我们的示例中, X|Z,θ 属于多元高斯模型,每个像素 x 可以属于 x|z=1,μ1,σ1或 x|z=2,μ2,σ2
- P(Z=k): 我们的潜在表示的先验概率 Z 或者随机采样数据点承担特定潜在分配的概率。Z 通常属于多项分布,或者在我们的例子中是更简单的二项分布。
- θ: 我们底层统计模型的参数。如果我们假设一个底层的多元高斯混合模型,那么 θ 既包括σ和 μ ,也包括混合系数 π ,其中 |π| =( *#潜在变量)。*混合系数代表将潜在表示随机分配给数据点的概率,并且与 P(Z=k) 是相同的精确量。
更清楚地说,在我们的例子中(假设一个 GMM 模型) X 是154401×3像素矩阵, Z 是154401×1聚类赋值,统计模型参数 θ = {μ1,σ1,μ2,σ2,π1,π2} 其中 |μ_i| = 3
第二节。理解期望最大化
现在我们有了一个具体的例子,让我们把 EM 算法的定义分解为*“更新未观察到的潜在空间变量以找到统计模型参数的局部最大似然估计的迭代方法”[2]。*
第一部分。设置:“迭代方法…”
EM 算法有三个主要步骤:初始化步骤、期望值步骤和最大化步骤。在第一步中,统计模型参数 θ 被随机初始化或者通过使用 k 均值方法初始化。初始化后,EM 算法在 E 和 M 步之间迭代,直到收敛。
第二部分。…即更新未观察到的潜在空间变量…
E-step 用于更新未观察到的潜在空间变量 Z 并为更新统计模型的参数 θ 设置阶段。电子步骤可以分为两个部分。第一部分更新我们的条件分布 P(Z|X,θ) ,它代表我们数据的软潜在分配(计算见附录“软潜在分配】)。E 步的第二部分计算 Q(θ,θ) 其中 θ 代表统计模型的先前参数 θ 代表潜在的新参数。
我们统计模型 θ* 的当前值和数据 X 用于计算软潜在赋值 P(Z|X,θ)。*
Q(θ,θ)* 背后的直觉大概是 EM 算法中最令人困惑的部分。它的包含最终导致计算时间和最优性之间的折衷。解释一下,EM 算法的缺点是它只能保证找到 θ 的估计,该估计找到了似然 P(X|θ) 的局部最大值,而不一定是绝对最大值。在理想情况下,真正的最大似然估计可以通过最大化似然 P(X,Z|θ) 来找到;然而,最大化这个值是困难的,因为我们需要对 Z 进行边缘化,以便获得可能性 P(X|θ) (有关更多详细信息,请参见附录“对数可能性的棘手性”)。相反,EM 算法使 Q(θ,θ)* 最大化,这与 P(X|θ) 相关,但更容易优化。
更具体地说 Q(θ,θ)* 是完全对数似然 **log[ P(X|Z,θ)】*相对于 Z 的当前分布给定 X 和 的当前估计 换句话说,它是相对于先前计算的软分配 Z|X,θ 的完全对数似然的期望。
要理解我们为什么需要 Q(θ,θ)* ,想想这个。我们需要找到最佳的 θ 来最大化 P(X,Z |θ);然而,我们无法合理地对每个数据点的所有 Z 求和。然而,假设 Z 被神奇地知道了。那么这个问题可以完全避免,因为 P(X,Z|θ) 会变成 P(X|Z,θ) 。但是,明显的问题是 Z 一开始并不知道。为了解决这个问题,我们计算 P(Z|X,θ) 以提供对 Z 的软估计,并以 Z|X,θ 为条件,取完整对数似然的期望,填入Z。**换句话说,我们以 P(X|Z,θ) 为条件
Q(θ,θ)* 的简化版如下图所示(详见*附录“计算 Q(θ,θ)”)。
E-step 用于寻找 Q(θ,θ*),这是在先前的统计模型参数 θ* 和数据 X 的条件下,相对于 Z 的完全对数似然的期望。
第 3 部分:“… 求统计模型参数的局部极大似然估计(MLE)。
与 E-step 相比,M-step 非常简单,用于更新我们统计模型的参数 θ 。一旦我们计算出 Q(θ,θ)* 我们可以通过计算以下表达式来改进统计模型参数的 MLE:
更新统计模型的 M 步操作。
第四部分。收敛!
收敛标准很简单——将每个新计算的 Q(θ,θ)* 与之前的进行比较,如果差值小于某个阈值ϵ(例如,ϵ= 1e-4 ), em 算法终止。在实践中,您可能希望使用各种初始化 θ 来运行该算法几次,以找到最大化 P(X|Z,θ) 的参数,因为每次 EM 算法执行时,您只能保证找到局部最大似然估计。
第三节。使用 EM 参数化高斯混合模型的 Python 示例
**代码片段:**高斯混合模型(GMM)的一个例子,它使用期望最大化来聚类图像。
**图二。**使用 EM 参数化高斯混合模型(k=2)对来自伯克利分割数据集[3]的图像进行示例分割。**来源:**作者照片。
第四节。EM 的三个重要直觉
总之,在 Q(θ,θ)* 和最终的 EM 算法*背后有三个重要的直觉。首先,完全对数似然 P(X|Z,θ) 比对数似然 P(X,Z|θ) 更快最大化,因为没有超过 Z 的边缘化。但是,这就引入了一个问题,因为我们不知道 Z 。因此,第二个直觉是,我们可以改为最大化 Q(θ,θ) 或 P(X,|Z,θ) 的对数的期望值,其中通过调节对 Z|X,θ 的期望来填充 Z 。最后的直觉是,通过找到最大化 Q(θ,θ) 的参数 θ ,我们将更接近最大化可能性 **P(X,Z|θ)的解决方案。*虽然并非微不足道,但对这种正确性的证明表明,提高 Q(θ,θ) 会导致 P(X,Z|θ) 提高至少一样多,如果不是更多的话。因此,EM 算法将总是收敛到局部最大值。
第五节。最近的工作和结论
最初由 Dempster、Laird 和 Rubin [1]描述的期望最大化(EM)算法提供了一种有保证的方法来计算依赖于未知或未观测数据的统计模型的局部最大似然估计(MLE)。尽管当数据集很大时,它的执行速度会很慢;收敛的保证和算法以无人监督的方式工作的能力使它在各种任务中有用。最近,人们开始使用神经网络,主要是编码器-解码器架构,其中编码器用于将 X 重新参数化为高级变量 X*,解码器封装统计参数θ*,产生每像素的软分配 P(Z|X*,θ*)。使用典型的编码器-解码器的损失函数来训练网络,但是用 P(Z|X*,θ*)来加权。这种方法被称为神经期望最大化(N-EM) [4],虽然有用,但它失去了 EM 的收敛保证。此外,还不清楚这种方法是否从图像中提取了更多相似颜色的特征,为改进和进一步研究留下了足够的空间。
人工智能领域的一个令人兴奋的挑战将是开发从原始感觉数据中可靠地提取离散实体的方法,这是人类感知和组合概括的核心[5]。期望最大化,虽然不是什么新东西,但它提供了一个镜头,未来寻求解决这个问题的技术应该通过这个镜头来审视。
附录
A.软潜在分配计算
在期望步骤(E-step)中计算软分配,以更新我们的潜在空间表示。
补充 1: 使用贝叶斯法则和全概率法则导出的潜在空间变量计算的软赋值。
B .解释对数似然法的难解性
通常,统计模型的最佳参数通过找到使对数似然最大化的 θ 或 log[P(X|θ)] 来拟合数据。假设是独立的,这通常如下所示:
等式 1: 典型的最大似然估计(MLE)设置。
然而,由于对 Z 的依赖性,我们只能计算 P(X,Z|θ) ,因此,为了计算 P(X|θ) ,我们必须忽略 Z 并最大化以下内容:
**方程式 2。**对数似然法。
这个数量更难以最大化,因为我们必须对所有的 n 个数据点的潜在变量 Z 进行边缘化或求和。
计算 Q(θ,θ)*
不是最大化等式 2 中的对数似然,而是最大化完整数据的对数似然,首先假设对于每个数据点 x_i ,我们有一个已知的离散潜在分配 z_i 。
**方程式 3。**完全对数似然
好消息是,不像**等式 2。我们不再需要在等式 3 中对 Z 求和。然而,坏消息是我们不知道 z_i 。为了解决这个问题,我们尝试通过最大化 Q(θ,θ) 或相对于 Z|X,θ 的完全对数似然的期望来猜测 z_i ,这允许我们填充 z_i. 的值
**方程式 4。*关于当前条件分布的完全对数似然的期望值 Z|X,θ。
等式 4 可以简化为
其中 I 是指标函数,可以用来评估期望值,因为我们假设 z_i 是离散的。最终,上面的等式可以简化为
**方程式 5。*简化版的 Q(θ,θ)
*方程式 5。最后显示了 Q(θ,θ) 的有用性,因为与等式 3 不同,**求和中没有任何一项以 Z 和 **θ为条件。**在上面的等式中,最左边的项是软潜在分配,最右边的项是 Z 的先验和条件概率密度函数的对数乘积。最右边的项可以分成两项,以最大化混合权重( Z 的先验)和概率密度函数的分布参数
回到具体的 GMM 例子,虽然在上面的等式 5 中可能不明显。、 {μ1,σ1 }、{μ2,σ2 }和{π1,π2} 出现在不同的项中,可以使用各自分布的已知最大似然估计独立地最大化。例如,当更新 *{μ1,σ1 }*和 *{μ2,σ2 }时,可以使用高斯分布的最大似然估计,而对于 {π1,π2} 可以使用二项式分布的最大似然估计。这些更新与经典 MLE 方程的唯一区别是包含了加权项 P(Z|X,θ) 。
引文
[1]登普斯特,A.P 新墨西哥州莱尔德;鲁宾博士(1977 年)。“通过 EM 算法不完整数据的最大可能性”。皇家统计学会杂志,B 辑。39: 1–38.
[2]“期望最大化算法”,维基百科文章,https://en . Wikipedia . org/wiki/Expectation % E2 % 80% 93 最大化 _ 算法
[3]李辉,蔡剑飞,阮氏一青,.语义图像分割的基准。IEEE ICME 2013。
[4]格雷夫、克劳斯、斯约尔德·范·斯廷基斯特和于尔根·施密德胡伯。“神经期望最大化。”神经信息处理系统的进展。2017.
[5]巴塔格利亚、彼得·w 等,“关系归纳偏差、深度学习和图形网络” arXiv 预印本 arXiv:1806.01261 (2018)。
在开源线性求解器中求解二次问题(QP)
如何线性化二次函数以在线性解算器中使用它,(也就是说,我没有钱支付 Gurobi)使用零售示例
所以,我上大学的时候用了很多花哨的优化软件(有学生许可证),比如 AMPL、CPLEX 和 Gurobi,我非常兴奋,因为“给我模型”和“我会解决它”。唯一的问题是,这些超级牛逼的解决方案是 f̶*̶ ̶e̶x̶p̶e̶n̶s̶i̶v̶e̶不便宜,许多小公司没有钱购买许可证,或者也许他们不愿意支付,除非他们看到的价值。
来源:funny-memes.org,转自:梅丽莎·伊莱亚斯
所以,像我一样,你发现有许多开源线性解算器可用,但是它们没有你的学生授权的奇妙解算器那么快和先进,当然,它们有局限性。我最怀念的一个功能是解决 QP 模型的能力。
因此,如果你正在寻找一种在开源线性求解器(比如 COIN-CBC )中求解 QP 模型的方法,这篇文章可能适合你。
如果你熟悉什么是 QP 车型 你可以跳过下一节。如果你想知道我为什么要关心二次函数? 保持阅读。
我为什么要关心二次函数?
(又名不应该是求解一个 线性 模型?).我认为介绍 QP 模型重要性的最简单的方法是通过一个例子。
让我们假设你要计划一整季从仓库到零售店的 t 恤发货(姑且称之为 i ∈ I a 店和 e{i,t} 在 *t(第 t 天)*期间到店的发货 i )。让我们想象一下,通过某种超级酷的机器学习算法,你对每个商店和时间段进行了预测(让我们称之为 d{i,t} 需求预测 i ∈ I,t ∈ T )。
比方说,在这个例子中,我们对 t 恤衫的需求激增(因为夏天),我们可能无法满足所有需求。如果我们为三家商店(1、2、4)绘制预测图,我们将得到:
现在,让我们建立一个线性模型来最小化每个商店上的未履行订单( u{i,t} )。
好的,这里没有什么特别的,只是一个标准的线性模型。我们用 python 实现了我们最喜欢的线性建模库( python-mip ❤️)
完整代码在https://github.com/pabloazurduy/qp-mip
有了模型结果,我们就可以按商店绘制未完成订单,只关注两家商店 (1,4) 。在此图中,虚线表示已完成的订单,实线表示预测的需求,这两条线之间的差距就是未完成的数量。
需求(实线)和满足的需求(虚线)之间的差距
我们可以从上图中观察到一些有趣的事情:
- 在第 20 天之后差距才开始出现。这意味着,在第一阶段,我可能能够完成所有订单,但在第二阶段(旺季),我开始有大量未完成的订单。
- 给定商店的未履行订单数量与实际数量相差甚远。如果我们关注商店 1(蓝线),我们可以看到第 20 天我们有 0 个订单,第二天我们完成了所有订单,第三天又有 0 个订单。
- 店铺间未成交订单数量也不一致。我们可以看到,在第 20 天到第 25 天之间,有些日子我们履行了商店 4 的所有订单,但没有履行商店 1 的任何订单,第二天情况正好相反。
然后,我们有一个问题… 解决方案在商店之间不“公平”。如果我手动解决这个问题,并且只有 120 个单位在不同地点之间分配,我会“更平均地”分割它们,因为我知道我将有未完成的订单。但是,至少我会在每家商店实现 60%的填充率,而不是让一些商店 100%填充率,另一些商店 0%填充率,保持更好的跨商店服务水平。
这个问题从何而来?问题是我们的模型只关心未履行订单总量 (min ∑ u{i,t})因此对于模型来说相当于一家店有 100 个未履行订单,另一家店有 0 个,或者每家店有 50 个未履行订单,因为成本是相同的(100 个单位)。那么我们如何解决这个问题呢?U 唱一个二次函数。
现在,有了*“二次惩罚”*,成本在商店和期间之间不是线性的,因此,最好有一个更平均分布的未完成订单数(100 + 0 > 50 + 50)。这是二次函数最常见的应用之一。那么,我们如何在线性求解器中实现它呢?
(二次函数的)线性化问题
解决 QP 模型有许多可能的解决方案,但是我们将实现可能是最简单的一个,继续使用我们的线性解算器,线性化。如果我们绘制二次函数,我们将得到类似左图的结果:
线性化概念图
我们要做的是将这条曲线变换成一系列( k )线,这些线可以是原始曲线的近似。我们只对近似值 x 的一定精度感兴趣,因此我们可以在域的边界之间选择有限数量的点( x{k} 点)。更多的点将导致原始函数的更好的近似。那些点 x{k} 被称为兴趣点。使用泰勒展开式的第一项,我们将找到每个感兴趣点的线性化。
线的定义(L=ax+b)
为了说明这一点,我们假设我们有 6 个兴趣点。绘制原始曲线和六条线,我们得到下图:
我们可以观察到,我们添加的点越多,近似结果就越精确。但是,正如我们将很快观察到的,更多的行将增加模型的复杂性。
将此线性化添加到线性模型中
我们可以利用 x 函数是凸的事实。有了那个性质,我们可以假设所有的线 L(x) 总是 f(x) 的一个“下盖”。记住这一点,我们可以使用 max 函数得到曲线~f(x)的离散近似,因为是所有直线的最大值( L(x) )。因此使用一个已知编码我们可以将其添加到模型中
线性化的编码
我们可以看到,对于我们添加到线性化中的每个离散点,我们也向模型添加了一个新的二元变量( bk ),因此, 更精细的近似将导致更高的执行时间。
Python 实现
我构建了一个助手,它可以将我们从这种近似中抽象出来:
完整代码在https://github.com/pabloazurduy/qp-mip
然后我们可以简单地将它添加到我们之前的模型实现中
让我们运行它,看看新的结果:
OptimizationStatus.FEASIBLE
Objective value: 23390.00000000
Lower bound: 18454.285
Gap: 0.27
Enumerated nodes: 35926
Total iterations: 7133610
Time (CPU seconds): 1939.06
Time (Wallclock seconds): 2001.06
需求(实线)和满足需求(虚线)之间的差距,二次模型
我们可以从情节中观察到一些有趣的东西
- 门店日间未完成订单数比较稳定:我们可以观察到,旺季没有缺货的日子,第二天也没有积压的日子。即使是库存较少的商店(如 4 号店),我们也看到我们总是完成一定数量的订单。
- 门店间未完成订单数量更加一致。我们可以看到,差距的数量也得到更好的分配,特别是在这一时期结束时。我们注意到,在第一个周期中,商店 4 比商店 1 有更多的短缺,这是因为实例中还有其他商店(总共 5 个),这也可能是由于离散化点的数量少造成的,如果间隙更小,函数是常数。
- **该解决方案在各门店间的服务水平较高。**该解决方案不仅提高了客户体验,因为店与店之间以及不同日子同一店内的可靠性更高。
我们找到了。现在,我们可以看到,结果更加一致。按店铺/天计算,使用 5 个兴趣点的时间会稍微长一点,但是,如果我们要在一个季度内解决一次这个问题,那也没什么大不了的
感谢您的阅读!!,这是我写的第一篇文章,所以请随意给我任何反馈。A 本项目所有源代码均可用 此处为 ,任何问题请留在回购中。
用交叉熵方法解决一个强化学习问题
深度强化学习讲解— 06
使用深度神经网络的代理创建
在介绍深度学习和 Pytorch 基础知识的三篇文章之后,在这篇文章中,我们将重点放回合并强化学习和深度学习。
在以前的帖子中,我们提出了一个智能体在不确定的情况下做出决策来解决复杂的决策问题。为此目的,代理采用了一个**策略𝜋,作为基于当前状态确定下一个动作的策略。从这篇文章开始,我们将探索不同的方法来获得一个允许代理人做决定的策略。
在这篇文章中,我们将从交叉熵方法开始,这将有助于读者在融合深度学习和强化学习时热身。这是一种用于参数化政策优化的进化算法,John Schulman 声称这种算法在复杂的 RL 问题上“令人尴尬的好”。
1.交叉熵方法
交叉熵被认为是一种进化算法:从一个群体中抽取一些个体,只有“精英”控制着后代的特征。
本质上,交叉熵方法所做的是获取一堆输入,查看产生的输出,选择产生最佳输出的输入,并调整代理,直到我们对看到的输出满意为止。
1.1 概述
记住一个策略**,用 𝜋(𝑎|𝑠表示,表示代理应该对每个观察到的状态采取什么动作。在这篇文章中,我们将认为我们代理的核心是一个产生政策的神经网络。**
我们将解决这类问题的方法称为基于策略的方法,它训练产生策略的神经网络。在未来的文章中,我们将会更深入地探讨这种方法。
在实践中,策略通常被表示为动作(代理在给定状态下可以采取的动作)的概率分布,这使得它非常类似于之前提出的分类问题(深度学习文章中的),类的数量等于我们可以执行的动作的数量。在我们的例子中,神经网络的输出是一个动作向量,它表示一个概率分布,如下图所示:****
在这种情况下,我们称之为随机策略,因为它返回行动的概率分布,而不是返回确定性的单个行动。
我们想要一个策略,一个概率分布,我们随机初始化它。然后我们通过播放几集来改进我们的策略,然后以更有效的方式调整我们的策略(神经网络的参数)。然后重复这个过程,以便我们的政策逐渐变好。这是交叉熵方法的基础。
1.2 训练数据集
由于我们将神经网络视为第一个代理的核心,因此我们需要找到一些方法来获取可以作为训练数据集吸收的数据,其中包括输入数据及其各自的标签。
我们要做的是将这个问题视为一个监督学习问题,其中观察到的状态被视为特征(输入数据),而动作构成标签。
在特工的一生中,其经历被呈现为集**。每一集都是对代理从环境中获得的状态、它发出的动作以及对这些动作的奖励的一系列观察。交叉熵方法的核心是扔掉不好的剧集,对更好的进行训练,那么我们如何找到更好的呢?。想象一下,我们的经纪人演了好几集这样的戏。对于每一集,我们都可以计算出代理商已经认领的回报(总回报)。请记住,代理人试图通过与环境的互动来积累尽可能多的总报酬。**
同样,为了简单起见,我们将使用冰湖的例子。为了理解发生了什么,我们需要更深入地了解冰湖环境的奖励结构。只有当我们达到目标时,我们才会得到1.0
的奖励,这个奖励并不能说明每集有多好。它是快速有效的吗?还是我们在湖上转了很多圈才随机踏入最后一个牢房?我们不知道;只是1.0
奖励仅此而已。
让我们想象一下,我们已经有了代理程序,我们用它来制作 4 集,我们可以用.render()
方法来可视化:
请注意,由于环境的随机性和代理选择采取行动的方式,每集有不同的长度,也显示了不同的奖励。显然一集的奖励是1.0
比一集的奖励是0.0
要好。结局都是一样的奖励的剧集呢?
很明显,我们可以认为某些集比其他集“更好”,例如,第三集比第二集短。对于这一点,贴现因子γ是很有帮助的。我们可以用 𝛾 = 0,9 。在这种情况下,贴现回报将等于在时间步长 t 的剧集结束时获得的奖励 r ( 1.0
或0.0
)γ到 t 。
让我们用一个图表来说明这四集,其中每个单元格代表代理人的步骤,一个转换**,以及相应的贴现回报:**
我们可以看到,较短剧集的折现回报将高于较长剧集。
1.3 交叉熵算法
交叉熵方法的核心很简单。基本上,它生成一批集,在一批集中丢弃不好的集,以在更好的集上训练代理的神经网络。为了决定丢弃哪些,我们在示例中使用了第 70 个百分位数,这意味着我们只保留了比其他 70%做得更好的 30%。****
因此,随着我们使用新一批精英剧集,神经网络学会重复导致神经网络决策结果变得越来越好的动作。必须训练代理,直到达到该批剧集阈值的某个平均回报。
因此,该方法的伪代码可以通过以下步骤来描述:
0.初始化代理神经网络模型
- 使用我们当前的代理模型创建一个批次剧集在环境中播放。
- 计算每集的预期回报,并使用所有奖励的百分比来决定一个回报边界**。**
- 扔掉所有回报低于回报界限的剧集。
- 使用情节步骤训练代理的神经网络,这意味着剩余“精英”情节中的过渡 < s 、 a 、 r > ),使用状态 s 作为输入,发出动作 a 作为标签。
- 从第 1 步开始重复,直到我们对该批剧集的平均奖励感到满意。
我们将在下一篇文章中讨论这种方法的一种变体,即我们可以将“精华”剧集保留更长时间。我的意思是,该算法的默认版本从环境中采样剧集,对最佳剧集进行训练,然后将它们丢弃。然而,当成功剧集的数量很少时,可以将“精英”剧集保持更长时间,将它们保持几个迭代以在其上进行训练。
2.环境
环境是数据的来源,我们将从其中创建数据集,该数据集将用于训练我们代理的神经网络。
2.1 情节步骤
代理将从随机策略开始,其中所有动作的概率是一致的,并且在训练时,代理将有希望从从环境中获得的数据中学习,以优化其策略,从而达到最优策略。
来自环境的数据是情节步骤,应该用形式为 < s,a,r > (状态、动作和回报)的元组来表示,这些元组在每个时间步骤中获得,如以下方案所示:
2.2 环境编码
这篇文章的 全部代码可以在 GitHub 和 上找到,使用这个链接 可以作为一个 Colab 谷歌笔记本运行。
正如我们在本系列的其他帖子中所做的那样,这篇帖子中的代码受到了 Maxim Lapan 的代码的启发,他写了一本关于这个主题的优秀实用书籍。
我们来编码吧。我们必须首先导入几个包:
**import numpy as npimport torch
import torch.nn as nnimport gym
import gym.spaces**
我们将从使用不光滑** FrozenLake 环境开始(在下一篇文章中,我们将讨论更多关于光滑版本的内容)😗*
**env = gym.make(‘FrozenLake-v0’, is_slippery=False)**
我们的状态空间是离散的,这意味着它只是一个从 0 到 15(包括 0 和 15)的数字(我们在网格中的当前位置)。动作空间也是离散的,从零到三。
我们的神经网络需要一个数字向量。为此,我们可以应用离散输入的传统 onehot 编码(前一篇文章中介绍的,这意味着我们网络的输入将有 16 个数字,除了我们将编码的索引之外,其他地方都是零。为了简化代码,我们可以使用 Gym 的ObservationWrapper
类并实现我们的OneHotWrapper
类:
**class OneHotWrapper(gym.ObservationWrapper):def __init__(self, env):
super(OneHotWrapper, self).__init__(env)
self.observation_space = gym.spaces.Box(0.0, 1.0,
(env.observation_space.n, ), dtype=np.float32)def observation(self, observation):
r = np.copy(self.observation_space.low)
r[observation] = 1.0
return r env = OneHotWrapper(env)**
总的来说,我们在env
有一个不滑的冰湖环境,我们将利用这个环境来获取剧集,以便获得数据来训练我们的经纪人。
3.代理人
我们已经提出,我们的代理是基于神经网络。让我们来看看如何编码这个神经网络,以及如何使用它来执行代理所做的动作选择。
3.1 模型
我们的模型的核心是一个使用 Sigmoid 激活函数的 32 个神经元的单隐层神经网络。我们的神经网络没有什么特别的。我们从任意数量的层和神经元开始。
**obs_size = env.observation_space.shape[0]
n_actions = env.action_space.n
HIDDEN_SIZE = 32net= nn.Sequential(
nn.Linear(obs_size, HIDDEN_SIZE),
nn.Sigmoid(),
nn.Linear(HIDDEN_SIZE, n_actions)
)**
神经网络将来自环境的单个观察作为输入向量,并为我们可以执行的每个动作输出一个数字,即动作的概率分布。一种简单的方法是在最后一层之后加入 softmax 非线性。然而,请记住在之前的帖子中,我们试图避免应用 softmax 来增加训练过程的数值稳定性。在本例中,我们使用 PyTorch 类nn.CrossEntropyLoss
,而不是先计算 softmax,然后再计算交叉熵损失,它将 softmax 和交叉熵组合在一个更稳定的表达式中。CrossEntropyLoss 需要来自神经网络的原始的、未标准化的值(也称为 logits)。
3.2 优化器和损失函数
其他“超参数”如损失函数和优化器也是使用以下代码为该示例设置的:
**objective = nn.CrossEntropyLoss()
optimizer = optim.SGD(params=net.parameters(), lr=0.001)**
3.3 采取行动
这种抽象使我们的代理非常简单:它需要将从环境接收的观察到的状态传递给神经网络模型,并使用概率分布执行随机采样,以获得要执行的动作**😗*
**sm = nn.Softmax(dim=1) def select_action(state):
**1:** state_t = torch.FloatTensor([state])
**2:** act_probs_t = sm(net(state_t))
**3:** act_probs = act_probs_t.data.numpy()[0]
**4:** action = np.random.choice(len(act_probs), p=act_probs)
return action**
让我们详细解释一下这段代码:
****第 1 行:该函数要求第一步将状态转换为张量,以将其摄入我们的神经网络。在每次迭代中,我们将当前的观察值(16 个位置的 Numpy 数组)转换为 PyTorch 张量,并将其传递给模型以获得行动概率。记住我们的神经网络模型需要张量作为输入数据(为了阐明代码我们用后缀_t
表示变量是张量)。
****第 2 行:使用nn.CrossEntropyLoss
的结果我们需要记住,每次我们需要从我们的神经网络输出中获得概率时,都要应用 softmax。
****第 3 行:我们需要将输出张量(记住 model 和 softmax 函数返回张量)转换成一个 NumPy 数组。该数组将具有与输入相同的 2D 结构,批次维度在轴 0 上,因此我们需要获取第一个批次元素来获得动作概率的 1D 向量。
****第 4 行:有了动作的概率分布,我们可以通过使用 NumPy 函数random.choice()
对该分布进行采样,从而获得当前步骤的实际动作。
4.培训代理
在下图中,我们展示了训练循环的屏幕截图,显示了交叉熵算法的一般步骤:
为了不使这篇文章太长,特别是因为这种方法是作为 DRL 编码的热身而引入的,我们将这种算法的详细解释留到下一篇文章中。通过这种方式,我们能够在进入培训过程的细节之前直接测试模型并熟悉它。
现在,我只是建议运行这个循环的代码,看看结果。只是提一下,我们认为在 80%的情况下有奖励是好的结果。记住这篇文章的全部代码可以在 GitHub 上找到。
5.测试代理
现在剩下的就是看代理人是否真的做出好的决策。为了检查这一点,我们可以创建一个新的环境(test_env
,并检查我们的代理在接受培训后是否能够到达目标单元。下面的代码会做到这一点:
**test_env = OneHotWrapper(gym.make(‘FrozenLake-v0’,
is_slippery=False))
state= test_env.reset()
test_env.render()is_done = Falsewhile not is_done:
action = select_action(state)
new_state, reward, is_done, _ = test_env.step(action)
test_env.render()
state = new_stateprint(“reward = “, reward)**
代码是一个简单的循环,它通过.step()
方法与环境交互,直到剧集结束(is_done
)。感谢.render()
方法,我们可以更直观地看到代理的行为:
如果我们试几次,就会发现它做得足够好。
6.下一步是什么?
在下一篇文章中,我们将详细描述训练循环(在这篇文章中我们已经跳过了),并看看我们如何在考虑更好的神经网络(具有更多神经元或不同的激活函数)的情况下改善代理的学习。此外,我们将考虑该方法的变体,该方法为训练过程的多次迭代保留“精英”片段。后文见。
这篇文章的全部代码可以在 GitHub 上找到,可以通过这个链接作为一个谷歌笔记本运行。
深度强化学习讲解系列
由 UPC 巴塞罗那理工 和 巴塞罗那超级计算中心
一个轻松的介绍性系列以一种实用的方式逐渐向读者介绍这项令人兴奋的技术,它是人工智能领域最新突破性进展的真正推动者。
本系列的内容](https://torres.ai/deep-reinforcement-learning-explained-series/)
关于这个系列
我在 5 月份开始写这个系列,那是在巴塞罗那的封锁期。老实说,由于封锁,在业余时间写这些帖子帮助了我。感谢您当年阅读这份刊物;它证明了我所做的努力。
免责声明 —这些帖子是在巴塞罗纳封锁期间写的,目的是分散个人注意力和传播科学知识,以防对某人有所帮助,但不是为了成为 DRL 地区的学术参考文献。如果读者需要更严谨的文档,本系列的最后一篇文章提供了大量的学术资源和书籍供读者参考。作者意识到这一系列的帖子可能包含一些错误,如果目的是一个学术文件,则需要对英文文本进行修订以改进它。但是,尽管作者想提高内容的数量和质量,他的职业承诺并没有留给他这样做的自由时间。然而,作者同意提炼所有那些读者可以尽快报告的错误。**
用遗传算法解决社会距离问题
使用 DEAP python 包的遗传算法应用示例。
来源:https://en . Wikipedia . org/wiki/File:Plasma _ fractal _ the art problem _ 1935 . jpg
“社交距离”如今变得非常流行,但这些规则如何适应我们的日常生活并不总是显而易见的。在这个故事中,我们将研究一个社会距离问题,并用遗传算法找到解决方案。在设定了问题及其约束条件之后,在将这些原则应用于我们的问题之前,我将总结一下遗传算法(GA)的原则。
问题是
今年夏天(2020 年 8 月),来自 Neo4j (图形数据库)的人们提出了要用图形解决的每周挑战。第一周的高级烧烤挑战包括一项社交距离任务,其规则如下:
- 来自 11 个家庭的 20 名客人被邀请参加一次烧烤(用婚礼、感恩节晚餐、任何派对,取决于一年中的时间来代替烧烤)。数据是 CSV 文件,格式为:
Guest,Family # headers added for clarity
Host,A
Jane,B
Jun,C
Oliver,C
....
- 你可以把它们放在 6 张桌子上,每张桌子有 6 个座位,其中两个连续的座位相距 1 米(我们认为桌子是圆形的)
- 每张桌子必须包含来自至少两个不同家庭的客人
- 每桌不得有两个以上来自同一家庭的客人
- 来自不同家庭的客人必须坐在相距至少两米的地方
虽然这个问题可以用图来解决(参见这里提出的解决方案:https://medium . com/neo4j/summer-of-nodes-week-1-the-barbecue-EAD 98d 441 a 91),但在我看来,这像是一个可以用其他技术解决的约束问题。在这篇文章中,我研究了使用遗传算法来解决这个特定的问题。
谈到遗传算法,让我们把重点放在这项技术背后的主要原则,以及这种算法如何帮助解决上述问题。
简而言之,遗传算法原理
与一般的方法不同,遗传算法不考虑单一的解,而是根据某些条件(梯度等)进行更新。).取而代之的是,GA 会考虑一个解群体,并基于偏向“最佳”个体的选择过程,在几个代中进化它们。这包括能够通过适应度函数来确定一个解决方案“有多好”,或者它离最佳解决方案有多远。因此,算法的步骤是:
- 对于群体中的每个个体,一个适应度函数决定了该个体离解有多近
- 一个选择过程产生下一代可能的解决方案,偏向于“最佳个体”,意思是具有最高适应性的个体
- 个体被突变,这意味着解基于一些规则而改变(例如:交换两个位置)并且交换发生,这基本上是将一个个体的某个部分与另一个交换(突变和交换的区别在这里解释)。
- 迭代过程从步骤 1 重新开始,直到满足停止标准(迭代次数、适应度函数达到给定阈值……)
现在让我们回到我们的社交距离问题。
问题定式化
对我们来说,一个解决方案是列出分配给每位客人的座位。座位是一个整数,其值等于
table_number * 10 + seat_number
例如,表 4 中的座位 2 对应于整数 42。
只要我们每张桌子的座位少于 10 个,这种方法就很好。
因此,一个解可以写成:
[10, 31, 19, 20, 23, 35, 22, 5, 6, 13, 3, 17, 33, 8, 1, 28, 27, 24, 25, 15]
索引为 0 的来宾(主机)被分配到表 1(基于 0 的索引)和座位 4。相应的表格转载如下:
[[-1, 'Ren', -1, 'Mohamed', -1, 'Jeremy'],
['Avery', -1, 'Rowan', -1, 'Host', -1],
[-1, 'Hugo', -1, 'Isabella', -1, 'Maria'],
[-1, 'Jun', 'Oliver', -1, 'Milan', 'Mia'],
['Fatima', 'Marc', -1, 'Hannah', 'Ali', -1],
[-1, 'Jane', -1, 'Aarav', -1, 'Sophie']]
-1
是空座位的默认值。
现在我们有了每个解的表示,让我们定义它的适合度,即它与满意解的“接近度”。
适合度定义
为了定义适合度,我们必须考虑问题定义部分中定义的三个约束中的每一个,再加上每个座位只能分配一次的事实。每次违反一个约束,适应度将相应地增加。
每个座位分配给一个客人
为了统计座位被分配的次数,我们使用了collections.Counter
python 对象,并检查每个值出现的次数是否少于一次。否则,我们返回一个高适应值:
c = Counter(solution)
if any( v > 1 for v in c.values()):
return 100
之后,我们可以创建表,一个 2D 矩阵,它的 ij 元素包含表 i 的座位 j 的客人家庭。例如:
[[-1, 'I', -1, 'G', -1, 'D'],
['E', -1, 'I', -1, 'A', -1],
[-1, 'F', -1, 'K', -1, 'H'],
[-1, 'C', 'C', -1, 'D', 'D'],
['K', 'K', -1, 'J', 'J', -1],
[-1, 'B', -1, 'H', -1, 'D']]
每桌必须包含来自至少两个家庭的客人
对于每个表(行),我们可以计算代表了多少个族,如果该表上的族少于两个,则将该表的违规数增加 1:
c = Counter([k for k in table if k != -1])
if len(c) < 2: # allow for empty tables (extra rule)
v += 1
来自同一家庭的每桌客人不得超过 2 人
使用同一个计数器,我们可以计算同一个家庭中有多少人坐在同一张桌子上,如果太多的人在场,就可以提高健康程度:
s = sum(v > 2 for k, v in c.items())
v += s
最后是最复杂的部分:来自不同家庭的客人之间的社交距离。
来自不同家庭的人必须至少相隔两个座位
为了计算这个约束,我们将使用带有实用的.rotate()
方法的collections.deque
对象。实际是因为我们为坐在同一张桌子的 0 号和 5 号座位上的客人设置了边界条件,这两个座位相距仅 1 米(而不是 5 米)。首先,我们创造了deque
:
td = deque(table)
然后,我们用相同的输入列表创建另一个实例,但是这个deque
是循环的:
tdr = deque(table) # table rotated
tdr.rotate()
例如,从表格开始:
table = [-1, 'I', -1, 'G', -1, 'D']
td
和tdr
变量将包含:
deque([-1, 'I', -1, 'G', -1, 'D']) # td
deque(['D', -1, 'I', -1, 'G', -1]) # tdr
从那里,我们可以迭代两个deque
。如果这两个值等于-1
(意味着没有客人被分配到那个座位),我们什么也不做。否则,我们检查坐在彼此旁边的两个客人是否来自同一个家庭,否则我们增加适合度:
for seat, prev_seat in zip(td, tdr):
if seat == -1 or prev_seat == -1:
continue
if seat != prev_seat:
v += 1
开始了,我们的健身功能终于准备好了!
虽然我们只完成了一半的工作,因为我们需要配置遗传算法的参数。希望我们不必自己编写所有的代码,因为非常聪明的人已经为我们做了(谢谢!).
完整代码和解决方案
为了实现我们问题的 GA 部分,我们将依赖于 DEAP(Python 中的分布式进化算法)Python 包。
主要步骤如下:
# start algorithm configuration
toolbox = base.Toolbox()# our objective is to minimize the fitness
creator.create("FitnessMin", base.Fitness, weights=(-1.0,))# create the Individual class (list of integers)
creator.create("Individual", list, typecode='i', fitness=creator.FitnessMin)# create an operator that generates randomly shuffled indices
toolbox.register("randomOrder", lambda : random.sample(range(NUM_TABLES * NUM_SEATS_PER_TABLE), k=len(GUESTS)))
# create the 'individual creation' operator to fill up an Individual instance with shuffled indices
toolbox.register("individualCreator", tools.initIterate, creator.Individual, toolbox.randomOrder)
# create the 'initial population creation' operator to generate a list of individuals
toolbox.register("populationCreator", tools.initRepeat, list, toolbox.individualCreator)# fitness calculation - compute the total distance of the list of cities represented by indices
# 'get_fitness' is our own fitness function containing the rules defined above
toolbox.register("evaluate", get_fitness)
# Genetic operators
toolbox.register("select", tools.selTournament, tournsize=10)
toolbox.register("mate", tools.cxTwoPoint)
toolbox.register("mutate", tools.mutShuffleIndexes, indpb=1.0/len(GUESTS))# create initial population (generation 0):
population = toolbox.populationCreator(n=POPULATION_SIZE)
更多细节:
- 初始种群生成,随机选择
NB_GUESTS
个席位(在 0 和NUM_TABLES * NUM_SEATS_PER_TABLE
之间) - 使用上面定义的函数进行适应性计算
- 选择锦标赛:两个两个地比较解决方案,将适应性最低的方案留给下一代(另请查看:维基百科)
- 交叉: cxTwoPoint :从两个随机选择的解决方案中交换零件,如下图所示:
来源:https://commons . wikimedia . org/wiki/File:two point crossover . SVG
- 变异: mutShuffleIndexes :以概率
P_MUTATION
对每个解中的索引进行混洗
算法的核心被封装成:
population, logbook = algorithms.eaSimple(
population, # initial population
toolbox, # above defined rules
# extra parameters:
cxpb=P_CROSSOVER,
mutpb=P_MUTATION,
ngen=MAX_GENERATIONS,
# results:
stats=stats,
**halloffame=hof,**
verbose=False
)
名人堂包括表现最好的个人,不管他们属于哪一代。它们是我们感兴趣的解决方案。
在运行完整的代码(在 GitHub 上有)后,我们可以看到名人堂中 10 个表现最好的个人都有一个 0 适应度,这意味着没有违反约束。其中一个被复制在这里:
来自名人堂的第一个解决方案
你可以看到:
- 表 1 包含来自 3 个家庭的客人,每个家庭只有一个客人,他们都被至少一个空座位隔开。
- 对表 2、3 和 6 的观察结果相同
- 4 号桌有来自两个家庭(C 和 D)的客人,每个家庭两个客人。六月和奥利弗坐在彼此旁边,但是他们来自同一个家庭(C ),所以这很好,来自 D 家庭的米兰和米娅也一样。没有来自 C 的客人直接坐在来自 D 的客人旁边,所以最后一个约束也得到满足。
- 这同样适用于具有来自家族 K 和 j 的成员的表 5。
在这里,我们用遗传算法的力量解决了一个社会距离问题。你将能够在烤肉时遇见你的朋友,同时限制与新冠肺炎相关的风险!
您可以下载此代码,尝试修改参数,并查看求解器的行为。输入参数(客人、桌子数量……)和模型参数(群体大小、突变概率、交换类型……)都可以改变。
进一步阅读
喜欢这篇文章吗?查看以下相关阅读以了解更多信息。
- https://deap.readthedocs.io/en/master/DEAP 文档
- Eyal Wiransky,"动手遗传算法 " (2020), Packt :这本书提供了许多可以用遗传算法解决的问题的例子,从组合问题到机器学习。从中我学到了很多,只能推荐!
解决人工智能的卡珊德拉问题
使用可解释的人工智能来说服你的用户
燃烧的特洛伊城前的卡珊德拉。伊芙琳·德·摩根(1898 年,伦敦)
人工智能社区有一个严重的问题:我们 87%的项目从未投入生产。如果另一个领域有这样的失败率,我们可能根本称不上科学。我们到底遗漏了什么?
我们不缺乏数据:我们在 2020 年每人每秒产生 1.7 MB!)
我们并不缺乏理论上的进展:新的人工智能论文就在今天发表在 Arxiv 上
我们并不缺乏投资:预计到 2025 年投资将超过 1500 亿美元
我们不缺乏性能:人工智能计算性能每 3.4 个月翻一番
我们缺少的是信任。现代 AI/ML 技术,如深度学习和基于树的方法,可以提供很高的准确性,但也比基于回归的旧方法更难解释。我们的模型可能会非常准确地预测未来,但如果我们服务的专家将它视为一个黑匣子,它将无法走出实验室。如果最终用户不信任我们的模型,他们会忽略它,就像古希腊人忽略了卡珊德拉的准确预言一样。
可解释的人工智能 (XAI)是一套寻求让复杂模型变得可理解和可信的技术。在过去的两年里,人们的兴趣迅速增长:
来源:谷歌趋势。作者图片
你可以找到很多介绍 XAI 的文章。我在下面的脚注中加入了一些我最喜欢的。然而,他们大多关注于如何 而忽略了为什么 ,而轻于现实数据和领域专业知识。
本文将通过一个案例研究来说明 XAI 是如何融入人工智能/人工智能工作流程的:一个我作为 Kaggle 家庭信贷竞赛的一部分开发的信贷模型。训练数据集包括来自潜在借款人的 397,511 份贷款申请。该模型试图预测哪些借款人将会违约。它是用基于树的算法 LightGBM 构建的。
在我们在 Genpact 的咨询实践中,我们看到了三个主要的 XAI 用例。让我们逐一查看。
作者图片
1.开发人员:提高模型性能
模型开发人员希望使用 XAI 来
消除没有增加多少价值的特征,使模型更轻,训练更快,不太可能过度拟合
确保模型依赖于从领域角度来看有意义的特性。例如,我们不希望模型使用借款人的名字来预测贷款违约
大多数基于树的库包括一个基本的特征重要性报告,可以帮助完成这些任务。这是我们的信用模型:
我们应该如何阅读这个图表?
最重要的功能在最上面
特征重要性由模型树使用它的频率(通过分割)或它添加了多少信号(通过增益)来定义
它告诉我们什么?
最重要的特性是 NEW_EXT_SOURCES_MEAN。这代表借款人的信用评分,类似于美国的 FICO 评分。从技术上讲,它是外部信用机构三次评分的平均值
平均信用分数比任何个人分数都重要(EXT_SOURCE_1,2,3)
第二个最重要的特征是申请人的年龄、出生日期等。
那又怎样?
我们可以利用这一点来提高模型性能。例如,我们看到所有三个信用评分都很重要(EXT_SOURCE 1、2 和 3),但平均值是最重要的。因此,模型试图学习的分数之间存在一些差异。我们可以通过工程特征来明确这种差异,例如 EXT_SOURCE_1 — EXT_SOURCE_2。
我们可以利用这一点在有限的程度上验证模型逻辑。例如,我们对借款人的年龄如此依赖会舒服吗?这很难回答,因为我们仍然不知道模型是如何使用借款人年龄的。
将此与 XAI 一个名为 SHAP 的软件包生成的类似报告进行比较:
两个图表都在顶部显示了模型最“重要”的特征,尽管它们在顺序上并不完全一致。许多人认为 SHAP 订单更准确。无论如何,SHAP 图表提供了更多的细节。
我们应该如何解读这张图表?
让我们放大顶部的功能:
**自上而下位置:**这是模型输出最“动针”的特征。是最有冲击力的。
**颜色:**在特性标签的右边,我们看到一个小提琴形状的点状图。在我们的数据集中,每个点代表一个借款人。蓝点代表信用评分低(有风险)的借款人。红点是高信用分(安全)。同样的蓝红标度适用于所有的数量特征。
**左右位置:**中心线左侧的点代表其信用评分降低模型输出的借款人,即降低预测的违约概率。右边的点是那些信用评分增加模型输出的人。
它告诉我们什么?
左边的点大多是红色的,这意味着高信用分数(红色)往往会降低违约概率(左)。
那又怎样?
我们可以用它来调试模型。例如,如果一个信用机构报告了一个分数,其中高值是有风险的,低值是安全的,或者如果我们混淆了违约概率和还款概率,这个图表将显示问题并允许我们解决它。这种情况比人们想象的更经常发生。
让我们进一步关注最后一点。这张图表显示了信用评分如何影响违约的预测概率。
我们应该如何阅读这个图表?
和以前一样,每个点代表一个借款人。
横轴是信用评分,从 0 到 1。
纵轴是而不是违约的预测概率,而是信用评分对该概率的贡献。它是以对数比而不是概率单位来衡量的,与我们的逻辑模型的原始输出相同。请参阅脚注,了解将对数几率转换为概率的公式。
它告诉我们什么?
这个散点图从左上向右下倾斜,因为低信用评分(左)会增加违约的预测概率(上),高信用评分(右)会降低违约概率(下)。
那又怎样?
如果我们的模型是线性的,那么这些点会以完美的直线向下倾斜。
相反,我们会看到一个更厚的散点图,因为我们的模型包括了特征交互。同样的信用评分(垂直线)可以对两个借款人产生不同的影响,这取决于另一个特征的价值。
让我们向图表中添加一些交互数据:
我们应该如何阅读这个图表?
请注意,坐标轴没有改变,圆点也没有移动。
我们只添加了一个基于第二个(交互)特征的色标,即 NEW_CREDIT_TO_ANNUITY_RATIO。这是申请贷款额和每年贷款支付额之间的比率。比率越低(蓝色),贷款被认为越安全,因为它应该用更少的时间还清。
它在告诉我们什么?
不幸的是,颜色并没有告诉我们太多:蓝色和红色的点似乎是随机分散的。这意味着我们绘制的两个特征之间没有明显的相互作用。然而,考虑下面的交互图:
我们应该如何阅读这个图表?
色标代表与之前相同的特征,但现在我们将横轴从信用评分切换到借款人的年龄,表示为从今天算起到出生的天数,因此是负数。
年龄范围从右边的 21 岁(7500/365 = 20.5)到左边的 68 岁(25000/365 = 68.5)。
纵轴显示了借款人年龄对预测违约概率的影响,以对数比表示。
这张图表告诉我们什么?
总体情况是,年长的借款人通常比年轻的借款人更安全(低)。这种情况一直持续到你 65 岁左右(-23000 天)。过了那个年龄,就有很大的分散。老年人信贷质量到处都是,但新的信贷与年金比率起着很大的作用,越低越好。
更微妙的是:有趣的事情发生在 45 岁左右(-16250 天)。对于 45 岁以下的借款人(右图),蓝点一般高于红点。在信贷方面,要求短期贷款的年轻借款人(低信贷对年度付款=蓝色)风险更大。对于年纪较大的借款人(左),这种关系正好相反,长期贷款的风险越来越大。
那又怎样?
我不确定为什么家庭信用数据显示出这种模式。这可能是贷款政策、产品特性的结果,也可能是偶然的。如果这是一个真实的信用模型,我会和一个领域专家(在这种情况下是一个承保人)讨论这个模式。
如果我们确定该模式基于信用基本面,我会设计一些特征,以便模型可以利用它。例如,一个这样的特征可能是 abs(年龄-45 岁)。
2.最终用户:了解产出并建立信任
Joshua Hoehne 在 Unsplash 上拍摄的照片
如前所述,ML 模型没有走出实验室进入生产的最大原因之一是最终用户不信任它们。假设我们的最终用户,一个信贷员,正在对一个借款人(数据集中的借款人#4)运行我们的模型。该模型预测该借款人违约的可能性为 94.9%。非常冒险。在拒绝申请之前,信贷员想知道为什么模型如此不喜欢这个借款人。使用 XAI,我们可以将预测分解成它的组成部分。有几种方法可以将这些组件可视化。我最喜欢的是决策情节,也来自 SHAP 包:
我们应该如何解读这张图表?
在该图中,我们显示了前 20 个最重要的特征对借款人#4 的模型预测的影响。
预测是红线。模型的输出是线条与图表顶部的色带相交的地方,94.9%的可能性是默认的。
将借款人标记为风险高于平均水平的特征会将线向右移动。将借款人标记为比平均水平更安全的特征将线向左移动。
借款人#4 的特征值在线旁边显示为灰色。
尽管从图表中可能很难看出,但并非所有的特征都以相同的程度移动线条。顶部的功能使它更加动感。
它告诉我们什么?
借款人的信用评分在我们这一批人中处于平均水平,但是
关于这个借款人的几乎所有其他事情都是一个危险信号。这不是一件事:这是一切。
那又怎样?
这应该给信贷员一些信心的预测。即使模型在一两个特征上是错误的,结论也不会有太大变化。
如果这是一个生产模型,功能标签将更加用户友好,贷款官员将能够点击它们以获得附加信息,例如借款人#4 在任何给定功能上与其他人相比如何,或者前面显示的功能依赖图。
唯一的问题是,这个图没有显示我们的完整模型,只有前 20 个特征。下面是基本数据:
我们应该如何阅读这张图表?
每行代表一个模型特征,总共 704 个。
中间一列显示了借款人#4 的特性值。
右栏显示了特征的对模型预测借款人#4 的贡献,以对数优势单位表示。数据按该列的绝对值排序。这将最重要的功能放在最上面,就像以前的情节一样。
如果我们将右边的列加到模型对所有借款人的平均预测上,我们得到模型对借款人#4 的预测。数学是这样的:
它告诉我们什么?
从右栏往下看,这个借款人的信用评分很重要,但几乎所有其他特征都对风险标签有所贡献。很多风险因素,没有缓解措施。
看看列表的底部,我们的 704 个特征中的 336 个没有贡献,这意味着它们根本不影响我们的模型对借款人#4 的预测。
那又怎样?
如果这是所有借款人的共同模式(不仅仅是借款人#4),我们会希望从模型中删除这些零影响特征。
3.审计师:管理风险、公平和偏见
在模型投入生产之前,通常需要由一个单独的团队进行验证。组织用不同的名字称呼这些团队:模型验证、模型风险、人工智能治理或类似的东西。为简单起见,我们称他们为审计员。
审计师不关心上述任何一个预测。他们关心模型的整体。例如,他们可能想确认我们的(候选)模型对受保护群体没有偏见,这将违反《平等信贷机会法》(如果这一模型服务于美国借款人)。以性别为例:
我们的数据集包括的女性和男性一样多,显示女性违约的频率更低。我们希望确保我们的模型不会因为预测女性比男性更有可能违约而不公平地对待女性。这很容易做到:我们简单地比较男性和女性的预测,并使用 t 检验来看差异是否显著。
该图表显示,该模型倾向于预测女性违约的频率更低,并且组间差异显著。这与上面总结的我们的训练数据是一致的。我们可以更进一步,分别测试每个特性:
我们应该如何阅读这个图表?
我们再一次看看前 10 个最重要的特性。
延伸到垂直线左侧的特征“偏爱”女性,延伸到垂直线右侧的特征“偏爱”男性。
该图还显示了置信区间。
这张图表告诉我们什么?
大多数特征有利于女性,与潜在分布一致。这很好,因为我们的模型没有扭曲事实。
一些特征仍然有利于男性,例如每年的贷款支付和收入之间的比率。这可能是因为我们数据集中的男性收入更高。
我们根据样本制作了这张图表。如果我们使用更大的样本,我们可能会得到更好(更紧)的置信区间。
那又怎样?
在这一点上,审核员将考虑这些证据来决定一个模型是否应该进入生产阶段。不同的贷方会以不同的方式对证据做出反应。有些人可能会剔除有利于男性的特征,尽管这可能会降低模型的准确性。其他人将接受所有特征,只要它们不超过某个显著性阈值。还有一些人可能只关注总体预测。
同样的分析将对其他受保护的群体重复进行——按种族、年龄、性取向、残疾状况等。
结论
可解释人工智能(XAI)是人工智能中最令人兴奋的发展领域之一,因为它可以促进建模者和领域专家之间的对话,否则这种对话不会发生。这些对话非常有价值,因为它们让技术和业务利益相关者达成了共识。一起,我们可以确保模型“出于正确的原因是正确的”,甚至可能解决我们的卡珊德拉问题。
脚注:
我们只是触及了 XAI 的皮毛。我希望我激起了你的食欲。以下是一些附加资源
克里斯·莫尔纳尔(Chris Molnar)的可解释 ML 图书
下面是将对数赔率转换为概率的公式:
用 Kydavra ChiSquaredSelector 解决分类特征选择问题
由 Sigmoid 创建的图像
所以我们在之前关于 Kydavra 库的文章中是怎么说的,特征选择是机器学习模型开发中非常重要的一部分。不幸的是,获得理想模型的方法并不只有一种,主要是因为数据几乎每次都有不同的形式,但这也意味着不同的方法。在本文中,我将分享一种使用 Sigmoid 创建的 Kydavra ChiSquaredSelector 选择分类特征的方法。
使用 Kydavra 图书馆的 ChiSquaredSelector。
和往常一样,对于那些主要是为了解决问题的人来说,他们需要的是命令和代码:
要安装 kydavra,只需在终端中写入以下命令:
pip install kydavra
现在,您可以导入选择器并将其应用于数据集,如下所示:
from kydavra import ChiSquaredSelectorselector = ChiSquaredSelector()new_columns = selector.select(df, ‘target’)
为了测试它,让我们对心脏病 UCI 数据集稍加修改后应用它。我们将删除数字列,而不是保留所有特征。因此,我们的新数据集将只包含以下要素:
sex, cp, fbs, restecg, exang, slope, ca and thal
我选择的算法是 SVC,在选择特征之前,它的 cross_val_score 是:
0.6691582491582491
但是在应用 ChiSquaredSelector 之后,cross_val_score 变成:
0.8452525252525251
保持下一个特征:性别,cp,exang,斜率,ca,thal。
那么它是如何工作的呢?
所以,和其他选择者一样,ChiSquaredSelector 的灵感来自统计学,当然是来自 Chi2-test。作为 p 值,Chi2 检验用于证明或反驳零假设。只是提醒一下:
零假设是对两个被测现象之间没有关系的一般性陈述(或者也称特征)。
所以为了发现特征是否相关,我们需要看看我们是否能拒绝零假设。从技术上说,ChiSquaredSelector 采用计算 chi2-s 时获得的 p 值。只是概括一下。
P 值 —是给定统计模型的概率值,如果零假设为真,一组统计观测值在数量级上大于或等于观测结果。
因此,通过设置显著性水平(ChiSquaredSelector 的参数),我们可以反复消除具有最高 p 值的要素。
奖金!
如果你感兴趣的是为什么选择器选择了一些特性而忽略了另一些,你可以画出选择特性的过程。ChiSquaredSelector 有两个绘图函数,一个用于 Chi2,另一个用于 p 值:
selector .plot_chi2()
对于 p 值:
selector.plot_p_value()
每个函数都有以下参数:
- 标题 —剧情标题。
- 保存 —布尔值,True 表示将保存剧情,False 表示不保存。默认情况下,它被设置为 false。
- 文件路径 —新创建的图的文件路径。
如果您想更深入地了解零假设、Chi2 检验和 p 值等概念,或者这个特征选择是如何工作的,下面有一个链接列表。
如果你想深入了解卡方如何工作,我强烈推荐文章末尾的链接。如果你尝试过 kydavra,我邀请你留下一些反馈,并分享你使用它的经验。
西格蒙德用❤做的。
有用的链接:
- https://en.wikipedia.org/wiki/Null_hypothesis
- 【https://en.wikipedia.org/wiki/P-value
- https://en.wikipedia.org/wiki/Chi-squared_test