在 MongoDB 中创建云数据库
如何使用 MongoDB Atlas 创建免费的云 NoSQL 数据库
在 Unsplash 上由 Daniel Páscoa 拍照
NoSQL 数据库近年来大受欢迎。NoSQL 数据库提供了更多的灵活性,而不是将所有内容存储在行和列值中。有相当多的面向文档的 NoSQL 数据库可用,如 AWS SimpleDB、MongoDB 等。MongoDB 提供了比其他 NoSQL 云数据库更多的灵活性和操作性。这将是一系列文章,包含如何为云数据库创建 MongoDB 集群,如何创建集合,以及通过 MongoDB compass (GUI)或 Python (pyMongo)执行创建、读取、更新和删除(CRUD)操作的信息。此外,以后的文章还将包含一些高级操作。如果您已经知道如何创建一个 MongoDB 集群并通过 MongoDB compass GUI 连接到它,那么您可以忽略这篇文章,转到下一篇文章。
首先,你需要在 MongoDB 中创建一个帐户,它是完全免费的,不需要信用卡信息就可以获得 MongoDB atlas。您可以通过这里报名。MongoDB Atlas 提供了云数据库。注册后,您可以选择想要的集群。有三个选项可用,我们将使用的是共享集群,因为它非常适合小型项目和学习目的,而且是免费的。顾名思义,它将是一个共享集群,而其他集群提供更高级和专用的服务。
选择共享集群
下一步是选择云提供商,有三个选项——AWS、Google Cloud 和微软 Azure。此外,基于云提供商,您可以选择您的集群的区域。我选择 AWS 和地区为新加坡。
选择云提供商和地区
现在,下一步将是选择群集层,有多个选项可用,但由于我们更多地将数据库用作学习项目,因此将继续使用 M0 沙盒,该沙盒提供共享 RAM 和 vCPU 以及 512 MB 存储。我们还可以在部署后随时纵向扩展集群层。
选择集群层
因为我们使用的是免费的共享集群,所以没有选择任何备份选项,我们可以根据需要更改集群名称。请记住,集群只能命名一次,之后就不能再更改了。
集群名称
完成上述步骤后,MongoDB 将继续供应和引导您的集群。部署群集只需几分钟。
集群创建
创建并部署集群后,您可以看到如下所示的状态:
创建的集群
现在,您可以选择“连接”选项来设置连接配置。您可以选择设备的 IP 地址或允许从任何地方访问。另外,您需要设置一个用户名和密码来访问您的 MongoDB 数据库。
连接设置
接下来,您需要选择一种连接方法,我通过 MongoDB compass 选择了,您也可以选择 MongoDB shell。MongoDB Compass 基本上是一个更容易操作的图形用户界面。但它的限制很少,看到集合并熟悉 MongoDB 很好,但它缺乏一些可以通过 shell 命令或 python 脚本完成的高级功能。
获取 MongoDB 指南针
如果您的机器上没有安装 MongoDB compass,您可以下载并安装该应用程序。在您安装了 MongoDB compass 并打开应用程序之后,您将看到一个字段,您可以在其中粘贴您将在上面的阶段中获得的连接字符串。
MongoDB 指南针 GUI
输入密码并完成身份验证后,您将会看到如下内容。
MongoDB 集群
如果您按照目前为止的步骤,一直到达最后一个图像,这意味着现在您可以通过 MongoDB compass 访问您的 MongoDB 集群。现在,您可以创建多个数据库,在每个数据库中,您可以创建多个集合。所有这些都将在下一篇文章中讨论。
希望本文能帮助您创建一个免费的 MongoDB 集群。
在 SQL 查询中创建条件语句
IF、CASE 和 IFNULL 语句快速指南
尽管 SQL 不是一种通用语言,但它包含了与其他语言结构相似的条件语句。经典的 IF 和 CASE 语句允许在查询级别更改数据,而不是在另一个环境(如工作表或数据框)中修改它们。
虽然这些语句都不难掌握,特别是在以前接触过编程语言的情况下,但是它们提供了修改查询结果的强大功能和灵活性。为了演示如何使用这些语句,将创建一个简单的表,详细说明销售 ID、周、部门和收入。
CREATE TABLE SALES_2021(
sales_id INTEGER PRIMARY KEY AUTOINCREMENT,
week INTEGER,
department VARCHAR(255),
revenue INTEGER
);
IF 语句
SQL 中最基本形式的 IF 语句与大多数工作表软件中的条件语句非常相似。
IF(*condition*, True, False) from *table*;
IF 语句简单地引入一些条件,然后根据条件是真还是假返回一个结果。当条件为真时,返回第二个参数,当条件为假时,返回第三个参数。注意,代替 IF 语句,一些实现使用了 IIF 语句,但是它的操作完全相同。
举一个更具体的例子,假设一个利益相关者请求对每周是否达到 5000 美元收入的部门目标进行细分。他们不一定关心该部门的收入。他们只关心是否达到了目标。
此外,他们不想要一个经过筛选的实现目标的周列表。他们想要所有 52 周的完整列表以及他们的收入目标状态。
SELECT department, week,
IF(revenue > 5000, 'Met', 'Not Met') as 'Goal'
FROM SALES_2021;
SELECT 语句按预期返回部门和星期,但还包括一个 IF 语句。第一个参数引入了收入是否大于$5,000 的条件。当实现收入目标时,返回第二个参数“已达到”,当未达到时返回“未达到”。为了使结果查询更具可读性,在 IF 语句中添加了一个别名。
查询的前五个结果
结果查询返回部门、周以及目标是否达到,如涉众所指定的。
案例陈述
虽然 IF 语句提供了一个基本的条件语句,但它不支持多个条件。在这种情况下,必须使用一个 CASE 语句。
CASE *field*
WHEN *expression_1* THEN *statement_1*
WHEN *expression_2* THEN *statement_2*
ELSE *statement_3*
END
FROM *table*;
案例从指定表中的字段开始。WHEN…THEN 语句随后创建一个特定的条件和返回语句。当表达式 _1 为真时,则返回语句 _1 。这同样适用于 expression_2 和 statement_2 。
如果没有一种情况得到满足,可选的 ELSE 语句(有时称为默认情况)将返回 statement_3 。请注意,CASE 语句必须以结尾结束。
假设一个涉众喜欢用部门代码而不是部门名称来查看数据。在这种情况下,他们希望看到法律作为腿,财产作为亲,管理作为人。
SELECT week, revenue,
CASE department
WHEN 'Legal' THEN 'LEG'
WHEN 'Property' THEN 'PRO'
WHEN 'Management' THEN 'MAN'
END as 'department code'
FROM SALES_2021;
考虑到这些查询会很快变得复杂,通常建议使用可选的空格来使其更具可读性。
SELECT week, revenue,
CASE department
WHEN 'Legal' THEN 'LEG'
WHEN 'Property' THEN 'PRO'
WHEN 'Management' THEN 'MAN'
END as 'department code'
FROM SALES_2021;
注意,CASE 语句指定了 department 字段。在下面的 WHEN…THEN 子句中,该条件因此也适用于 department 字段中的条目。当部门等于“合法”时,则返回“LEG”。同样适用于“财产”和“亲”,“管理”和“人”。END 关闭 CASE 语句,并包含一个别名以使结果更具可读性。
查询的截断结果
因此,查询返回部门代码,而不是部门名称。
虽然这个例子为具有精确等式的数据提供了一个简单的例子,但是假设一个利益相关者想要将一个部门的收入分为高、中或低。
SELECT week, revenue,
CASE
WHEN revenue > 6000 THEN 'High'
WHEN revenue < 3000 THEN 'Low'
ELSE 'Medium'
END as 'Revenue Rating'
FROM SALES_2021;
该查询遵循相同的基本模式,只是 CASE 语句没有明确声明它适用于收入字段。相反,在每个 WHEN…THEN…语句中,该表达式都包含对 revenue 字段的显式比较。
在这种情况下,当收入高于 6,000 美元时,查询返回“高”,低于 3,000 美元时,查询返回“低”。ELSE 将任何其他数量作为“中等”返回,因为它应该在$3,000 和$6,000 之间,包括这两个值。
查询的前五个结果
IFNULL 语句
当数据中出现空值时,数据专业人员通常会很担心。它们通常代表在数据清理时必须解决的不完整信息或错误。
考虑到对确认空值的高需求,SQL 提供了 IFNULL 语句来标记出现的空值。
IFNULL(*field*, *expression*) FROM *table*;
IFNULL 有两个参数。第一个参数指定表中的字段,如果条目为空,第二个参数给出返回值。
假设添加了一个新部门,Tax,但是其数据的初始条目省略了名称,使其为空。一个简单的 IFNULL 语句将在查询数据时填充这些信息。
SELECT week, IFNULL(department, 'Tax') as 'department', revenue
FROM SALES_2021;
SELECT 语句包含 IFNULL 函数,该函数确定部门字段中的条目是否为空值。如果是,则返回“税”。此外,还添加了一个别名,以提高可读性。
查询的截断结果
最后一行最初省略了任何部门,但是查询添加了税务部门,使得数据清理过程更加简单。
结论
SQL 使得向查询添加条件语句变得很简单。有了它们,数据专业人员可以开始将逻辑注入到他们的查询中。它们构成了增加复杂性的基础,允许更复杂的技术来改变和查看数据库中的信息。
使用 Argo 创建容器化的工作流
Kubernetes 上的 Argo 工作流入门
探索 Argo 工作流的核心概念
在的上一篇文章中,我探索了 Kubeflow 管道,并完成了创建和执行一个简单的机器学习管道的过程。在本文中,我将仔细研究 Argo,这是一个开源的工作流编排引擎,它被用作 Kubeflow 管道的默认编排平台。
建立 Kubernetes 集群
为了开始玩 Argo,我们首先需要一个正在运行的 Kubernetes 集群。我将使用 EKS,AWS 上的托管 Kubernetes 服务,并通过所需的步骤让 Argo 在 EKS 上运行。只要部署了 Argo 并且拥有在集群上运行工作流所需的权限,任何 Kubernetes 集群都可以工作。
开始使用 EKS 最简单的方法是使用 eksctl 命令行工具。安装 eksctl 的说明可以在这里找到:https://github.com/weaveworks/eksctl/blob/main/README.md
一旦安装了 eksctl,我们将通过运行以下命令来创建 Kubernetes 集群:
eksctl create cluster
注意:上面的命令创建了 AWS 资源,这将在您的账户上产生费用。默认情况下,eksctl create cluster
命令创建一个包含 2 个 m5.large 类型 EC2 实例的 Kubernetes 集群,在撰写本文时,每个实例的成本约为每小时 0.10 美元。
此命令可能需要 15–20 分钟来完成群集资源调配。一旦完成,我们要做的第一件事就是创建一个命名空间来存放我们的 Argo 资源。我们将使用kubectl
来做到这一点:
kubectl create namespace argo
接下来,我们将从 Argo GitHub 库下载 Argo 安装清单:
wget [https://raw.githubusercontent.com/argoproj/argo-workflows/stable/manifests/install.yaml](https://raw.githubusercontent.com/argoproj/argo-workflows/master/manifests/install.yaml) .
这将下载一个名为 install.yaml 的 YAML 清单文件,它描述了我们启动和运行 Argo 所需的所有 Kubernetes 资源。
为了访问 Argo 服务器用户界面,我们必须对这个文件做一些修改。
- 将 argo-server 服务更新为*负载平衡器类型。*这将在 AWS 中提供一个网络负载平衡器,将请求路由到 argo-server 服务。生成的资源定义应该如下所示:
2.更新 argo-server 部署,添加一个名为 BASE_HREF 的环境变量,其值为“/”。结果应该如下所示(为简洁起见,资源定义被截断):
完成这些修改后,我们可以创建清单中定义的资源:
kubectl apply -n argo -f install.yaml
接下来,我们需要创建一个入口资源:
最后,为了让 Argo 能够访问其他 Kubernetes 资源,我们需要为 Argo 服务帐户分配一个角色。在实际的生产集群中,我们希望将这个服务帐户分配给一个具有特定有限权限的角色,但是现在,我们只授予这个帐户 admin 访问权限。我们可以使用以下命令来实现这一点:
kubectl -n argo create rolebinding default-admin --clusterrole=admin --serviceaccount=argo:default
这就是我们开始之前需要完成的所有设置。现在,我们将通过运行以下命令来获取 Argo 服务器 UI 的公共 URL:
kubectl get svc argo-server -n argo
该命令将在 EXTERNAL-IP 列中返回公共 URL。应该以*. elb . Amazon AWS . com*结尾
现在打开浏览器,导航到:https://{ YOUR _ EXTERNAL _ IP }:2746
注意:如果你在 MacOS 上使用 Chrome,并且在导航到 Argo 服务器 UI 时很难绕过浏览器发出的安全警告,Chrome 中有一个隐藏的解决方法:只需单击浏览器窗口中的任意位置以确保窗口处于焦点状态,然后键入*this insural。*有关此变通办法的更多详细信息,请参见这是不安全的——绕过谷歌浏览器的“您的连接不是私人的”警告
如果一切正常,您应该会看到一个 Argo 服务器登录页面,如下所示:
Argo 服务器用户界面登录页面
执行您的第一个工作流程
设置完成后,让我们执行 Argo 的第一个工作流。
导航至工作流(这是侧边栏中的顶部图标)> 提交新工作流>使用完整工作流选项编辑
这将打开工作流创建体验,其中包括一个填充了基本工作流 YAML 清单的文本编辑器,以及工作流参数和元数据的附加选项卡。
Argo 工作流创建
让我们用一个运行如下所示的 Whalesay 容器的简单工作流来替换这个默认工作流清单,然后单击 Create 来运行工作流:
一旦您开始工作流程,您将看到一个工作流程图,它将随着工作流程的进展而更新(在这种情况下,它只是一个单独的步骤)。在此页面中,您将能够查看工作流的详细信息、输入、输出和日志。在我们的准系统 Hello World 工作流程中,这里没有太多可看的,但是你可以导航到主日志来确认 Whalesay ASCII 艺术被记录。
简单的 Argo 工作流程图
了解工作流清单
现在我们知道了如何执行工作流,让我们仔细看看我们用来定义工作流的 YAML 清单。
[计]元数据
清单的前几行定义了工作流元数据,特别是 generateName 字段,它将与一个随机生成的字符串组合起来形成我们工作流的名称(我们也可以使用 name 字段来显式定义名称,但是这个名称必须是唯一的),以及 namespace 字段,它定义了工作流将在其中执行的 Kubernetes 名称空间。
工作流规范
清单的其余部分定义了工作流规范,这是定义实际工作流逻辑的地方。在上例中,工作流规范有两个顶级字段:
- 入口点:指定首先执行的模板。
- 模板:定义工作流程中使用的所有模板。正如我们将很快看到的,模板在 Argo 中是一个加载的术语,但在这里模板只是表示工作流执行的一个单元。在我们的 Whalesay 工作流中,我们只有一个名为 whalesay 的类型为**的容器模板。**由于这个模板定义了一个要执行的容器,我们指定了要使用的容器图像、要执行的命令和要传入的参数。
创建多步骤工作流
现在让我们介绍一个更复杂的工作流,它按顺序执行几个不同的步骤。这个工作流将接受 2 个参数、一个称呼和一个用户名,它将通过使用提供的参数执行 Whalesay 容器来创建一个问候消息来结束。
虽然我们可以很容易地用 Whalesay 容器来实现这一点,但是为了展示 Argo 提供的其他一些特性,我们将采取一种更迂回的方法。
这是我们新工作流程的 YAML 清单:
让我们来分解一下:
- 您会注意到的第一个区别是在第 6 行添加了参数字段。这是我们定义将被传递到我们的工作流中的称呼和用户名参数的地方。
- 这个工作流中定义的第一个模板在第 14 行。这个模板名为问候语,接受名为问候语的参数,类型为 Script。脚本模板类似于容器模板,因为它们需要容器图像和命令;然而,脚本模板允许我们传入一个内联脚本来在容器上执行。该模板执行一个简单的 Python 脚本,该脚本检索 salutation 参数的值,然后将其打印出来。
- 下一个模板叫做用户,也是脚本类型。这个模板就像 salutation 模板一样,只是这个模板使用了一个 shell 脚本而不是 Python 脚本(这里没有特别的理由不使用 Python;这只是为了说明我们并不局限于 Python 作为我们的脚本语言)。
- 第三个模板与我们之前使用的 Whalesay 容器模板相同,只是现在它接受两个参数,问候语和用户名,并使用这些参数创建问候语。
- 第四个模板是一个步骤模板。步骤模板允许我们将一系列其他模板链接在一起,创建一个多步骤工作流,其中一个模板的输出可以用作另一个模板的输入。第一步使用问候语模板并传入工作流参数问候语,第二步使用用户模板并传入工作流参数用户名,最终模板使用 whalesay 模板并传入前两步的输出。
以下是此工作流程的工作流程图:
多步骤工作流程图
注意:如果你执行了这个工作流程(或者只是仔细看了一下这个图),你可能已经注意到获取标题和获取问候步骤是并行执行的,然后在两个步骤都完成之后,再运行步骤。这是因为步骤模板实际上接受步骤列表的列表。内部列表中的步骤将并行运行,外部列表中的步骤将按顺序运行。例如,上面工作流的列表结构如下所示:
[[get-title, get-greeting], [whalesay]]
这就是为什么 get-title 和 get-greeting 并行运行,而 whalesay 在两者完成后运行。
重用工作流步骤
工作流编排平台最重要的特性之一是能够跨多个工作流共享常用步骤。这允许平台的用户通过使用其他用户已经实施的通用步骤库来快速开始创建工作流。例如,您可以为常见的数据转换或与外部服务的集成创建可重用的步骤。
Argo 中表示可重用步骤(或一组步骤)的结构称为工作流模板。这不要与我们之前在定义工作流 YAML 清单时讨论的模板相混淆。为清楚起见,区别如下:
- 模板:表示工作流中的单个执行单元。有许多不同类型的模板,包括容器、脚本和步骤。
- 工作流模板:保存在集群中的工作流定义,可以作为独立工作流或任何其他工作流的一部分执行。
让我们创建一个工作流模板来看看它是如何工作的。我们的工作流模板将是一个随机数生成器,它接受最小值和最大值,并返回指定范围内的随机整数。
Argo 服务器 UI 中的工作流模板选项卡是我们可以查看和创建工作流模板的地方。
Argo 用户界面-工作流模板
创建工作流模板与创建工作流非常相似,只是当我们创建工作流模板时,它会被保存以供以后使用,而不是像工作流那样立即执行。
以下是我们将使用的工作流模板的 YAML 清单:
工作流模板清单
正如您所看到的,这个清单就像我们之前创建的工作流清单一样:它接受两个参数, min 和 max ,并且有一个 Python 脚本模板,该模板在指定的范围内生成一个随机数。
创建此工作流模板后,我们将能够从 UI 中的“工作流模板”选项卡查看它,并通过选择它并单击提交将其作为独立工作流提交
将工作流模板作为独立工作流提交
我们也可以在其他工作流中使用此工作流模板。让我们看看这是如何工作的。我们将返回工作流选项卡,选择提交新工作流,然后输入以下 YAML 清单:
这个工作流很像我们已经讨论过的多步骤工作流,只是这次步骤模板不仅仅是将在这个工作流中直接定义的模板链接在一起。步骤模板中的第一步(上面的第 19 行)使用templateRef
字段而不是template
字段来引用工作流模板中定义的模板。在这个特殊的例子中,我们引用了在random-number-generator
工作流模板中定义的generator
模板。
如果这仍然有点混乱,下面的图表说明了本例中工作流、工作流模板和模板之间的关系:
当我们执行这个工作流时,call-random-number-generator步骤将像它是一个直接在工作流中定义的模板一样运行,而实际上它的实现被封装在random-number-generator工作流模板中。
从工作流中引用工作流模板
这意味着我们可以创建许多其他工作流(或其他工作流模板)来使用该功能,而无需考虑其实现的细节,如果我们需要修改该功能(例如,当前随机范围不包括 max 值,这可能是也可能不是期望的行为;或者,我们可能希望将它重构到一个容器映像中,而不是一个内联脚本中,以便更容易地测试该功能),我们可以在工作流模板中这样做,因为我们知道所有的消费者都将开始使用这些修改,而无需在他们端做任何额外的工作。
结论
在本文中,我们看到了如何通过创建几个简单的工作流来开始使用 Argo 工作流。我们研究了如何在工作流中的多个模板之间传递参数,以及如何使用工作流模板封装共享逻辑。
虽然我们在这里探索的例子非常简单,但是这些相同的核心概念可以用来在 Kubernetes 上构建和执行强大的容器化工作流,如果您决定继续探索 Argo 必须提供的其他功能,它们将成为一个强大的基础。
你可以在【https://github.com/gnovack/argo-workflows-getting-started】的Argo-workflows-getting-started库中找到我们创建的所有 YAML 清单
参考资料:
- https://argoproj.github.io/argo-workflows/quick-start/
- https://www.eksworkshop.com/advanced/410_batch/
感谢阅读。如有任何问题或意见,请随时联系我们。
从头开始创建卷积神经网络
在 Graviti 数据平台上使用 CNN 建立图像分类模型
艾莉娜·格鲁布尼亚克在 Unsplash 上的照片
图像分类基本上帮助我们将图像分类到不同的标签中。这就像将不同的图像放入它们所属的桶中。例如,被训练来识别猫和狗的图像的模型将有助于分别分离不同的猫和狗的图像。有多种深度学习框架,如 Tensorflow、Keras、Theano 等,可用于创建图像分类模型。今天我们将使用 Keras 和 Tensorflow 从头开始创建一个图像分类模型。
用于创建图像的相关建模可以使用 CNN 来完成。卷积神经网络主要用于图像相关的建模。它是执行图像分类、图像检测、图像分割等的最简单的方法之一。它包含不同类型的卷积层,有助于使用不同大小的内核过滤掉图像中最重要的特征。一些最重要的层是:
- Conv2D
它用于创建卷积核,卷积核与输入层卷积以产生输出张量。
2。MaxPooling2D
这是一种缩减采样技术,根据池大小取最大值。
3.展平
它使输入变平并创建一维输出。
有多个超参数可以用来相应地提高模型性能。这些超参数可以包括神经元的数量、内核大小、池大小、激活函数等。
在本文中,我们将从头开始使用 CNN 创建一个网络。我将向您展示如何从在线数据源加载数据,预处理数据并为建模做好准备,最后设计模型架构。
让我们开始吧…
安装所需的库
我们将从安装所有需要的库开始。我们将安装 Keras、TensorFlow,还将安装用于加载数据集的 TensorBay (在 Graviti 数据平台上的 SDK)。下面给出的命令可以做到这一点。
!pip install tensorflow
!pip install tensorbay
!pip install keras
导入所需的库
在这一步中,我们将导入所有必需的库和函数来加载数据、预处理数据并创建模型。
# Library imports
from tensorbay import GAS
from PIL import Image
import matplotlib.pyplot as plt
from tensorbay.dataset import Data, Dataset
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.image import imread
import cv2
import random
from os import listdir
from sklearn.preprocessing import LabelBinarizer
from keras.preprocessing import image
from keras.preprocessing.image import img_to_array, array_to_img
from tensorflow.keras.optimizers import Adam
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Activation, Flatten, Dropout, Dense
from sklearn.model_selection import train_test_split
加载数据集
这是第一步,我们将从 TensorBay 加载数据。为了从 TensorBay 下载数据集,我们需要创建一个帐户,并派生出一个我们想要处理的数据集,它包含大量不同的图像数据集。为了在我们的 Jupyter 笔记本中加载数据集,我们需要有 TensorBay 的访问密钥,我们可以从我们的帐户中的开发者工具下载该密钥。
gas = GAS("<Your Key>")
dataset = Dataset("Flower17–1", gas)
segment = dataset[1]
对于这篇文章,我使用的是 Flower 17 数据集,你可以看到我已经用 TensorBay 加载了它。
预处理数据集
在这一步,我们将预处理数据,并为建模做好准备。我们将从创建图像和标签列表并向其中加载数据开始。
image_list, label_list = [], []
for data in segment:
with data.open() as fp:
image_list.append(img_to_array(Image.open(fp).resize((500, 500))))
label_list.append(data.label.classification.category)
接下来,让我们直观地看到这个数据集中的类的数量。
# Visualize the number of classes count
label_counts = pd.DataFrame(label_list).value_counts()
label_counts
数据标签(来源:作者)
接下来,我们将分割数据集,对其进行规范化,并对标签进行二值化。
# Splitting dataset
x_train, x_test, y_train, y_test = train_test_split(image_list, label_list, test_size=0.2, random_state = 10)
# Normalize and reshape data
x_train = np.array(x_train, dtype=np.float16) / 225.0
x_train = x_train.reshape( -1,500,500,3)
x_test = np.array(x_test, dtype=np.float16) / 225.0
x_test = x_test.reshape( -1,500,500,3)
# Label binarizing
lb = LabelBinarizer()
y_train = lb.fit_transform(y_train)
y_test = lb.fit_transform(y_test)
print(lb.classes_)
标签二进制化(来源:作者)
创建模型
这是最后一步,我们将创建模型架构,编译模型并训练它。在创建模型架构之前,让我们将训练数据分为训练和验证。
# Splitting the training data set into training and validation data sets
x_train, x_val, y_train, y_val = train_test_split(x_train, y_train, test_size = 0.2)
# Building model architecture
model = Sequential()
model.add(Conv2D(8, (3, 3), padding="same",input_shape=(500,500,3), activation="relu"))
model.add(MaxPooling2D(pool_size=(3, 3)))
model.add(Conv2D(16, (3, 3), padding="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(32, (3, 3), padding="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(32, activation="relu"))
model.add(Dense(num_classes, activation="softmax"))
model.summary()
模型架构(来源:作者)
# Compiling model
model.compile(loss = 'categorical_crossentropy', optimizer = Adam(0.0005),metrics=['accuracy'])
# Training the model
epochs = 20
batch_size = 128
history = model.fit(x_train, y_train, batch_size = batch_size, epochs = epochs, validation_data = (x_val, y_val))
培训(来源:作者)
正如您在上面看到的,我们已经使用一些超参数创建并训练了模型,模型精度不是很好,但您可以随时调整超参数以提高性能。我们也可以使用下面给出的命令保存模型。
# Saving model
model.save("/content/flower_species.h5")
Let's visualize the model training and loss history.
#Plot the training history
plt.figure(figsize=(12, 5))
plt.plot(history.history['accuracy'], color='r')
plt.plot(history.history['val_accuracy'], color='b')
plt.title('Model Accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epochs')
plt.legend(['train', 'val'])
plt.show()
准确性(来源:作者)
#Plot the loss history
plt.figure(figsize=(12, 5))
plt.plot(history.history['loss'], color='r')
plt.plot(history.history['val_loss'], color='b')
plt.title('Model Loss')
plt.ylabel('Loss')
plt.xlabel('Epochs')
plt.legend(['train', 'val'])
plt.show()
损失(来源:作者)
最后,让我们也使用该模型创建一些预测。
# Storing predictions
y_pred = model.predict(x_test)
Let's verify one of the predictions.
# Plotting image to compare
img = array_to_img(x_test[4])
img
花卉图像(来源:作者)
# Finding max value from prediction list and comparing original value vs predicted
labels = lb.classes_
print(labels)
print("Originally : ",labels[np.argmax(y_test[4])])
print("Predicted : ",labels[np.argmax(y_pred[4])])
预测(来源:作者)
继续,使用不同的数据集尝试这种方法,并按照本文轻松创建 CNN 模型。如果您发现任何困难,请在回复部分告诉我。
在你走之前
感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的LinkedIn 个人资料 。可以查看我的Github简介针对不同的数据科学项目和包教程。还有,随意探索 我的简介 阅读我写过的与数据科学相关的不同文章。
在 TensorFlow 2 中使用 Lambda 层创建自定义激活函数
学习在 TensorFlow 2 中使用 lambda 层创建一个简单的自定义 ReLU 激活函数
之前我们已经看到了如何创建自定义损失函数— 使用 TensorFlow 2 创建自定义损失函数
自定义 ReLU 函数(来源:图片由作者创建)
简介
在本文中,我们看看如何创建自定义激活函数。虽然 TensorFlow 已经包含了一系列内置的激活函数,但仍有方法可以创建您自己的自定义激活函数或编辑现有的激活函数。
ReLU(整流线性单元)仍然是任何神经网络结构的隐藏层中最常用的激活函数。ReLU 也可以表示为函数 f(x ),其中,
f(x) = 0,当 x<0,
and, f(x) = x, when x ≥ 0.
Thus the function takes into consideration only the positive part, and is written as,
f(x)= max(0,x)
或者在代码表示中,
**if input > 0:
return input
else:
return 0**
但是这个 ReLU 函数是预定义的。如果我们想自定义这个函数或者创建自己的 ReLU 激活怎么办?在 TensorFlow 中有一个非常简单的方法来做到这一点——我们只需使用 Lambda 层。
ReLU 和 GeLU 激活功能(资料来源:由 Ringdongdang —自己的作品,CC BY-SA 4.0,https://commons.wikimedia.org/w/index.php?curid=95947821)
如何使用 lambda 图层?
**tf.keras.layers.Lambda(lambda x: tf.abs(x))**
Lambda 只是另一个可以在 TensorFlow 中直接调用的层。在 lambda 层中,首先指定参数。在上面的代码片段中,这个值是‘x’(λx)。在这种情况下,我们希望找到 x 的绝对值,所以我们使用 tf.abs(x)。所以如果 x 的值为-1,这个 lambda 层会将 x 的值更改为 1。
如何使用 lambda 图层创建自定义 ReLU?
**def custom_relu(x):
return K.maximum(0.0,x)****model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(128,128)),
tf.keras.layers.Dense(512),
tf.keras.layers.Lambda(custom_relu),
tf.keras.layers.Dense(5, activation = 'softmax')
])**
上面的代码片段展示了如何在 TensorFlow 模型中实现自定义 ReLU。我们创建一个函数 custom_relu,并返回最大值 0 或 x(与 relu 函数一样)。
在下面的顺序模型中,在密集层之后,我们创建一个 Lambda 层,并在自定义激活函数中传递它。但是这段代码仍然没有做任何与 ReLU 激活函数不同的事情。
当我们开始摆弄自定义函数的返回值时,乐趣就开始了。假设我们取 0.5 和 x 的最大值,而不是 0 和 x 的最大值。然后可以根据需要更改这些值。
def custom _ relu(x):
return k . maximum(0.5,x)
**def custom_relu(x):
return K.maximum(0.5,x)****model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(128,128)),
tf.keras.layers.Dense(512),
tf.keras.layers.Lambda(custom_relu),
tf.keras.layers.Dense(5, activation = 'softmax')
])**
在 mnist 数据集上使用 lambda 激活的示例
***#using absolute value (Lambda layer example 1)*****import tensorflow as tf
from tensorflow.keras import backend as K****mnist = tf.keras.datasets.mnist****(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0****model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(128),
tf.keras.layers.Lambda(lambda x: tf.abs(x)),
tf.keras.layers.Dense(10, activation='softmax')
])****model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])****model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)**
用 mnist 数据集上的绝对值替换 ReLU 激活给出了 97.384%的测试准确度。
***#using custom ReLU activation (Lambda layer example 2)*****import tensorflow as tf
from tensorflow.keras import backend as K****mnist = tf.keras.datasets.mnist****(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0****def my_relu(x):
return K.maximum(-0.1, x)****model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(128),
tf.keras.layers.Lambda(my_relu),
tf.keras.layers.Dense(10, activation='softmax')
])****model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])****model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)**
在 mnist 数据集上,用定制的 ReLU 激活替换 ReLU 激活,取最大值-0.1 或 x,给出 97.778%的测试准确度。
结论
尽管 lambda 层使用起来非常简单,但它们有许多限制。在下一篇文章中,我将讲述如何在 TensorFlow 中创建完全自定义的层,这些层也是可训练的。
在 Python 中创建自定义列表
探索 OOP 基础,尝试 Python 中的自定义数据类型
克里斯里德在 Unsplash 上的照片
在本文中,我们将了解面向对象编程的基础,以及如何使用 Python 类来创建我们自己的定制列表。我们将在不使用任何包的情况下这样做(没有导入语句!).
假设我们想要创建一个新的数据容器类型,它将充当一个列表(例如,我们可以对它进行索引和切片),但同时可以包含来自多个来源的数据,我们可以像在字典中一样提取这些数据。
比方说,我们有一个列表字典:
d ={‘key1’ : [‘val11’, ‘val12’, ‘val13’],
‘key2’ : [‘val21’, ‘val22’, ‘val23’],
‘key3’ : [‘val31’, ‘val32’, ‘val33’]}
但是我们希望能够轻松地处理 d.values()中的所有列表,就像它是一个大列表一样:
l = [‘val11’, ‘val12’, ‘val13’,
‘val21’, ‘val22’, ‘val23’,
‘val31’, ‘val32’, ‘val33’]
但同时,我们不想失去字典的键值绑定。想象一个具有这些特征的物体:
作者截图
因此,它是一个充当列表的对象,但在后台为每个元素保留键。姑且称之为 dinx 。
首先,我们知道要初始化这个对象,我们需要一个列表字典。让我们也允许元组,并说它们将表示静态元素,如果我们改变 dinx 'list ',它们将不会改变。因此,我们需要断言输入(姑且称之为 comp,【components)是一个字典,并且包含列表或元组。后者可以用 isinstance 第二个自变量中的【list,tuple】或 (list,tuple) 来实现。我们还应该在字典键中只允许字符串,以避免在调用数字索引时产生混淆。
我们将把 comp 赋值给 self,并加上一个下划线前缀,表示它是供类内部使用的。
作者截图
我们还需要定义一个函数来获得一个映射变量,我们可以用它来获得字典的列表表示中元素的顺序,我们将调用 _comp_map (稍后会用到):
作者截图
所以,自我。_comp_map 看起来像这样:
[(‘key1’, ‘val11’),
(‘key1’, ‘val12’),
(‘key1’, ‘val13’),
(‘key2’, ‘val21’),
(‘key2’, ‘val22’),
(‘key2’, ‘val23’),
(‘key3’, ‘val31’),
(‘key3’, ‘val32’),
(‘key3’, ‘val33’)]
这已经是一个键-值元组的列表,但是我们想让它看起来更漂亮。
我们现在需要做的是编写一个 dinx 的 dunder 方法,名为 repr ,它会在我们每次调用时显示 dinx 的表示。因为我们想让我们的 dinx 在调用时看起来像一个列表,我们将从 _sum_lists 和 _getall 方法开始,我们可以用它们来展平 _comp 中的列表字典。
作者截图
然后我们可以使用 repr 中的 _getall 输出来指定当我们在控制台中调用 dinx 时它的样子:
作者截图
现在,我们可以初始化并调用我们的 dinx:
作者截图
索引和切片
太好了!让我们实现通过索引和切片调用值的能力。这个想法是我们想要结合字典和列表索引。所以,假设上面例子中的一个项 l[0]应该是一个 dinx(1) ,即有一个值 1 和一个键*‘A’。一个切片 l[:5] 应该是一个 dinx(1,2,3,0,1) ,分别带有关键字‘A’和‘B’*。
由于我们只允许在 _comp 中使用字符串字典键,我们可以假设如果它看到字符串索引输入,它应该返回底层 _comp 键的值。因此,我们可以在 dinx 中结合列表和字典类型的索引。
首先,当我们通过索引获取 dinx 的值时,我们希望返回一个 dinx 。因此,我们需要将 cls 变量定义为 type(self) ,然后我们可以使用它在 return 语句中启动一个新的 dinx :
如果传递的索引(ind)是一个字符串,则返回一个以 ind 为关键字的新 dinx(s作者捕获的屏幕截图)
为了从 int 或 slice 类型生成 dinx ,我们需要定义一个方法,将我们的 _comp_map 元组列表转换成一个字典,我们可以使用它在 return 语句中启动一个新的 dinx :
作者截图
回到 getitem:
作者截图
让我们做几个测试:
在上面的例子中,我们是用 struct 方法单独定义的。它返回 dinx 的字典表示。在文章的最后将提供关于 dinx 类的完整代码。(作者截图)
将 dinxs 相加
在 Python 中,实现加法运算最常用的 dunder 方法有两种: add (+) 和 iadd (+=)。我们将从后者开始:
作者截图
这里我们取两个输入, self 和 other ,其中 other 是另一个 dinx ,我们迭代 other 中的每个元素。_comp 并将其添加到 self。_comp 如果密钥存在,或者在 self 中创建一个新密钥。_comp 否则。我们只对列表这样做,从而保持元组不变,这允许我们在我们的 dinx 中定义我们不想变异的元素。
定义了原地加法方法(x+=y)之后,我们现在可以用它来定义 x+y 类型的加法。这个想法很简单,我们将使用 dinx 的一个临时深度副本,在它上面做一个 other 的就地添加,并返回结果:
作者截图
让我们测试一下,看看它是如何工作的:
作者截图
分类索引
列表的另一个重要特性是排序的能力。我们也可以使用排序方法中的键参数,根据自己的功能对列表进行排序。在本节中,我们将为 dinx 创建排序方法
首先要记住的是,我们已经有了一个键-值元组列表,我们用它来获得 dinx 元素( self)的顺序。_comp_map 。因此,我们对 dinx 应用的任何排序函数都可以简单地传递给 self。_comp_map 。唯一的问题是,我们需要按照元组的第二个元素进行排序。这可以使用 lambda x: x[1] 作为密钥来完成。然后,如果我们想将键应用于 dinx ,我们可以通过λx:key(x[1])在内部将其应用于 x[1] 。最后,我们可以对应用排序或者让它返回一个新的 dinx :
作者截图
让我们测试一下新的排序方法:
在最后两个例子中,我们先排列偶数,然后排列奇数(作者截图)
结论
本文的目的是展示 Python 提供了相当简单易用的工具,我们可以利用这些工具来配置项目以满足我们的需求。上面的自定义数据容器的例子不一定适用于真实世界的场景,但仍然证明了我们可以构建自己的基本数据结构,以便更好地控制和管理正在处理的数据。
我还实现了一些更小的东西,比如 contains 向 dinx 中的 x 返回一个布尔值, len 获取 dinx 的长度, count 返回传递给它的变量的计数,以及 update、values 和 keys 字典方法。以下是完整的代码:
为 sklearn 管道创建自定义转换器
了解如何创建适合并转换数据的自定义转换器
照片由伊克拉姆-奥-道拉·沙文在 Unsplash 上拍摄
在我之前的文章中,我谈到了如何使用 sklearn 中的Pipeline
类来简化您的机器学习工作流程。特别是,我谈到了如何使用各种转换器类(比如SimpleImputer
、StandardScaler
和OneHotEncoder
)来转换管道中的数据。
有些时候 sklearn 没有提供你需要的变压器。所以在这种情况下,你必须写你自己的 transformer 类,sklearn 的Pipeline
类可以使用。
定义我们的定制转换器
让我们从您能想到的最简单的转换器开始——一个过滤熊猫数据帧中的列的定制转换器。这是为 transformer 类结构奠定基础的好机会:
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.utils.validation import check_is_fitted# The ColumnsSelector class inherits from the sklearn.base classes
# (BaseEstimator, TransformerMixin). This makes it compatible with
# scikit-learn’s Pipelinesclass ColumnsSelector(BaseEstimator, TransformerMixin):
# initializer
def __init__(self, columns):
# save the features list internally in the class
self.columns = columns
def fit(self, X, y = None):
return self def transform(self, X, y = None):
# return the dataframe with the specified features
return X[self.columns]
上面定义了一个名为ColumnsSelector
的 Python 类,它继承了sklearn.base
类— BaseEstimator
和TransformerMixin
。它具有以下功能:
- 初始化器—
__init__
。在这里,您将传递到这个定制转换器中的列的名称保存为一个内部变量—self.columns
。该内部变量的名称必须与参数名称相匹配(即columns
)。 - 一个拟合函数—
fit()
。此函数用于计算自定义变压器的参数。在这个例子中,我们不需要做任何事情,因为我们的转换只是过滤列。在其他转换器(如StandardScalar
)中,fit()
函数将计算数据集中各列的平均值和标准偏差值,以便transform()
函数稍后执行转换。同样,我将在后面的部分用另一个例子来说明这一点。 - 一个变换函数—
transform()
。这个函数用于将实际的转换应用到您的自定义转换器打算执行的数据帧。在我们的示例中,您希望根据用户传入的列列表来过滤 dataframe。
注意,fit()
和transform()
函数都接受两个参数— X
和y
(可选;值None
的默认参数)。
使用我们的定制变压器
定义了自定义转换器后,让我们使用我在上一篇文章中使用的相同数据集来尝试一下:
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_splitdf = pd.read_csv('train.csv')
df = df[['Survived','Pclass','Sex','Age','Fare','Embarked']]X = df.iloc[:,1:]
y = df.iloc[:,0]
X_train, X_test, y_train, y_test = train_test_split(X, y,
test_size = 0.3,
stratify = y,
random_state = 0)
X_train
数据来源 :本文数据来源来自https://www.kaggle.com/c/titanic/data.
下面是我们将在本文中使用的数据框架:
作者图片
要使用ColumnsSelector
转换器,让我们创建一个Pipeline
对象,并将我们的ColumnsSelector
转换器添加到其中:
from sklearn.pipeline import Pipelinenumeric_transformer = Pipeline(steps=[
**('columns selector', ColumnsSelector(['Age','Fare'])),**
])
在上面的语句中,我想从 dataframe 中提取出Age
和Fare
列,稍后我将使用fit()
函数传递给它。
现在,我可以通过调用Pipeline
对象上的fit()
函数并向其传递X_train
dataframe 来调用自定义转换器中的fit()
函数:
numeric_transformer.**fit**(X_train)
您将看到以下输出:
Pipeline(steps=[('columns selector', ColumnsSelector(columns=['Age', 'Fare']))])
回想一下,我们的
fit()
函数在这里没有做任何有用的事情。因此在这里调用fit()
并不会真正在类内部做任何事情。
transform()
功能怎么样?现在让我们使用X_train
数据帧从Pipeline
对象调用transform()
函数:
numeric_transformer.**transform**(X_train)
您将看到以下输出:
作者图片
您可以使用fit_transform()
功能合并对fit()
和transform()
的调用:
numeric_transformer.fit_transform(X_train, y_train)
fit_transform()
函数调用fit()
,然后在您的自定义转换器中调用transform()
。
很多变形金刚里,需要先调用
fit()
,才能调用transform()
。但是在我们的例子中,由于我们的fit()
不做任何事情,所以您是否调用fit()
并不重要。
基于您目前所看到的,值得记住以下fit_transform()
和transform()
函数的用例:
- 您在训练数据集上使用
fit_transform()
来拟合和转换数据 - 您使用
transform()
来应用您在测试集合上的训练数据集上使用的转换
继续我们的讨论,让我们将SimpleImputer
转换器添加到Pipeline
对象中:
from sklearn.pipeline import Pipeline
**from sklearn.impute import SimpleImputer**numeric_transformer = Pipeline(steps=[
('columns selector', ColumnsSelector(['Age','Fare'])),
** ('imputer', SimpleImputer(strategy='median')),**
])
如果您现在尝试在Pipeline
对象上调用transform()
:
numeric_transformer.transform(X_train)
您将得到一个错误:
NotFittedError: This SimpleImputer instance is not fitted yet. Call 'fit' with appropriate arguments before using this estimator.
如前所述,对于某些变压器,您需要调用fit()
或fit_transform()
函数来确保数据首先被拟合。在本例中,SimpleImputer
对象需要计算指定列的中值(在fit()
函数中),然后才能替换transform()
函数中列的所有NaNs
。
要解决这个问题,用X_train
数据帧调用fit_transform()
函数:
numeric_transformer.**fit_transform**(X_train)
您将看到如下所示的结果:
作者图片
您可以通过以下方式可视化工作流:
作者图片
现在让我们继续添加StandardScaler
转换器到Pipeline
对象:
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
**from sklearn.preprocessing import StandardScaler**numeric_transformer = Pipeline(steps=[
('columns selector', ColumnsSelector(['Age','Fare'])),
('imputer', SimpleImputer(strategy='median')),
**('scaler', StandardScaler())**
])numeric_transformer.fit_transform(X_train)
现在,您应该可以看到标准化的Age
和Fare
列中的值:
作者图片
使用标准化的训练集合中的值,您现在可以使用transform()
函数将转换应用到测试集合:
numeric_transformer.**transform**(X_test)
您应该会看到以下结果:
array([[-0.65142052, -0.47989005],
[-1.97483693, 0.09842973],
[ 3.20205667, -0.47958116],
[-0.41787645, 0.91519704],
[-0.06756034, -0.48921406],
[-0.80711657, -0.06803741],
[-0.04809833, -0.47958116],
创建我们自己的定制标准转换器
既然您已经看到了如何创建定制转换器的简单示例,那么让我们来看看另一个示例。这一次,让我们试着自己实现StandardScaler
变压器。
首先,让我们声明一个类调用MyStandardScaler
:
class MyStandardScaler(BaseEstimator, TransformerMixin):
def __init__(self):
return None
def fit(self, X, y = None):
print(type(X))
# the type of X might be a DataFrame or a NumPy array
# depending on the previous transformer object that
# you use in the pipeline
self.means = np.mean(X, axis=0) # calculate the mean
self.stds = np.std(X, axis=0) # calculate the
# standard deviation
return self def transform(self, X, y = None):
return (X - self.means) / self.stds
像前面的例子一样,MyStandardScaler
类实现了fit()
和transform()
函数:
- 在
fit()
函数中,您计算 2D 矩阵中每一列的平均值和标准偏差(作为 NumPy 数组或 Pandas 数据帧) - 在
transform()
函数中,您使用以下公式计算标准化值:
作者图片
其中 X 为列中的当前值, μ 为数列的平均值,【σ为数列的标准差,Z 为新的标准化值。
在fit()
函数中,我特意打印了X
的类型,向您展示您的管道中使用的前一个转换器如何影响您在当前转换器中接收的数据类型。
为了使用MyStandardScaler
转换器,让我们修改一下之前的管道:
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScalernumeric_transformer = Pipeline(steps=[
('columns selector', ColumnsSelector(['Age','Fare'])),
**('my scaler', MyStandardScaler())**
])numeric_transformer.fit_transform(X_train)
对于我们的
MyStandardScaler
变压器,您需要直接调用fit_transform()
或者同时调用fit()
和transform()
。如果您简单地调用transform()
函数,它将不起作用,因为该类没有每列的平均值和标准偏差来计算每列的标准化值。
当管道运行时,您将看到以下输出:
<class 'pandas.core.frame.DataFrame'>
这意味着从ColumnsSelector
传入的数据是熊猫数据帧。fit_transform()
功能的输出为以下数据帧:
作者图片
现在,让我们在管道中的MyStandardScaler
变压器之前添加一个SimpleImputer
变压器:
numeric_transformer = Pipeline(steps=[
('columns selector', ColumnsSelector(['Age','Fare'])),
**('imputer', SimpleImputer(strategy='median')),**
('my scaler', MyStandardScaler())
])numeric_transformer.fit_transform(X_train)
这一次,当您运行代码时,您将看到以下内容:
<class 'numpy.ndarray'>
这表明SimpleImputer
将转换后的数据作为 NumPy 数组返回。
Pipeline
对象的fit_transform()
函数的输出将是一个数组:
array([[-0.02863633, -0.47911875],
[-0.65142052, -0.46270324],
[-0.04809833, -0.32513665],
...,
[ 0.20490775, 0.42203815],
[-0.04809833, -0.22194182],
[-0.5735725 , -0.45646073]])
输出中的值与使用StandardScaler
时的值相同。
确保变压器已经安装
还记得我之前说过,对于MyStandardScaler
转换器,您需要在转换发生之前调用fit()
函数吗?如果用户没有拟合就调用transform()
函数会怎么样?在这种情况下,重要的是向用户返回正确的错误消息,告诉他们首先拟合数据。您可以通过check_is_fitted()
功能这样做,就像这样:
**from sklearn.utils.validation import check_is_fitted**class MyStandardScaler(BaseEstimator, TransformerMixin):
def __init__(self):
return None
def fit(self, X, y = None):
print(type(X))
# the type of X might be a DataFrame or a NumPy array
# it depends on the previous transformer object that
# you use in the pipeline
self.means = np.mean(X, axis=0)
self.stds = np.std(X, axis=0)
return self def transform( self, X, y = None ):
**check_is_fitted(self, ['means','stds'])**
return (X - self.means) / self.stds
在check_is_fitted()
函数中,您只需要传入一个字符串(或字符串列表),指定需要出现在类中的对象属性(如果用户跳过fit()
函数,将不会创建means
和stds
属性,因此该函数将引发NotFittedError
异常)。
为了测试这一点,让我们使用transform()
函数调用Pipeline
对象:
numeric_transformer = Pipeline(steps=[
('columns selector', ColumnsSelector(['Age','Fare'])),
('imputer', SimpleImputer(strategy='median')),
('my scaler', MyStandardScaler())
])numeric_transformer.**transform**(X_train)
正如所料,您将看到错误消息:
NotFittedError: This SimpleImputer instance is not fitted yet. Call 'fit' with appropriate arguments before using this estimator.
摘要
我希望这篇文章能揭示出变形金刚在幕后是如何工作的。特别是,我希望你现在理解fit()
、transform()
和fit_transform()
功能之间的区别以及它们是如何工作的。更具体地说,我还希望您现在已经掌握了创建自己的自定义转换器的知识,它可以与Pipeline
对象一起工作。
https://weimenglee.medium.com/membership
使用 Scikit-Learn 创建自定义变压器
本文讨论了使用 Scikit-Learn 创建定制转换器的两种方法,以及它们在 Pipeline 和 GridSearchCV 中的实现。
阿瑟尼·托古列夫在 Unsplash 上的照片
转换器是在为机器学习预处理数据时实现数据转换的类。Scikit-Learn 中的转换器示例有 SimpleImputer、MinMaxScaler、OrdinalEncoder、PowerTransformer 等等。有时,我们可能需要执行流行的 Python 包中没有预定义的数据转换。在这种情况下,定制变压器来拯救。在本文中,我们将讨论使用 Scikit-Learn 在 Python 中定义定制转换器的两种方法。我们将使用 Scikit-Learn 中的“虹膜数据集”,并使用 IQR 方法定义一个用于异常值消除的自定义转换器。
方法 1
该方法通过继承 Scikit-Learn 的 BaseEstimator 和 TransformerMixin 类来定义自定义转换器。Scikit-Learn 的“BaseEstimator”类通过添加“set_params”和“get_params”方法来启用超参数调优。而“TransformerMixin”类添加了“fit_transform”方法,但没有显式定义它。在下面的代码片段中,我们将导入所需的包和数据集。
作者图片
在上面的代码片段中,我们定义了一个名为“OutlierRemover”的类,这是我们的自定义转换器,用于删除异常值,即使用 NaN 替换异常值。该类有一个名为“factor”的属性,它是一个超参数,用于控制异常值移除过程。“因子”越高,极端值将被移除。默认情况下,“因子”初始化为 1.5。该类有三个方法,即“离群值移除”、“拟合”和“转换”。继承 BaseEstimator 和 TransformerMixin 类增加了另外三个方法,即,’ fit_transform ‘,’ get_params ‘和’ set_params '。我们还创建了一个名为“OutlierRemover”类的“outlier_remover”实例。
init '是创建该类的实例/对象时调用的第一个方法。这用于初始化类属性。我们将用 1.5(默认值)初始化 IQR 方法的因子。“异常值移除”方法用 NaN 替换系列中的异常值。“fit”方法总是返回 self。“transform”方法接受一个数组/数据帧作为输入,并将 outlier_removal 方法应用于数据帧/数组的所有列并返回它。
作者图片
我们将使用“OutlierRemover”通过创建一个名为“test”的包含三列和四条记录的数据框来应用异常值移除转换。
作者图片
我们可以看到“col1”有一个异常值(999),而“col3”也有一个异常值(-10)。我们将首先使“OutlierRemover”适合“test”数据框(使用已经创建的实例“outlier_remover”),并对其应用变换。
outlier_remover.fit(test)
作者图片
outlier_remover.transform(test)
作者图片
我们可以看到,“列 1”(999)中的异常值被替换为 NaN,“列 3”(10)中的异常值被替换为 NaN。我们可以使用如下所示的一个“fit_transform”方法来应用转换。这与上面的结果相同。
outlier_remover.fit_transform(test)
作者图片
我们将通过将“因子”设置为 100 来创建“OutlierRemover”类的一个名为“outlier_remover_100”的实例。如前所述,“因子”越高,极端值将被剔除。
作者图片
我们可以看到,“列 1”中的“999”和“列 2”中的“-10”这次没有被视为异常值,因为“因子”属性很高。现在,我们将离群点去除器变换应用于虹膜数据集。在此之前,我们将使用箱线图显示 Iris 数据集的四列中的异常值。
作者图片
在上面的方框图中,我们可以看到列“SepalWidthCm”有几个异常值,准确地说是四个。其他三列没有异常值。我们将创建一个 ColumnTransformer,将“OutlierRemover”应用于 Iris 数据集的所有变量,并使用箱线图可视化离群点移除后的变量。
作者图片
在上面的方框图中,我们可以看到“SepalWidthCm”列中的异常值已被移除,即替换为 NaN。我们将找出从每一列中删除了多少个异常值以及哪些异常值。
作者图片
作者图片
我们可以看到,大于 4 且小于或等于 2 的“SepalWidthCm”的值被移除,因为它们是异常值。在前面显示异常值的箱线图中也可以看到同样的情况。现在,我们将创建一个移除异常值的管道,估算移除的异常值并拟合逻辑回归模型。我们将使用 GridSearchCV 调优超参数。
作者图片
方法 2
创建自定义转换器的第二种方法是使用 Scikit-Learn 的“FunctionTransformer”类。这是一种更简单的方法,不需要定义类,但是,我们需要定义一个函数来执行所需的转换。类似于方法 1,我们将创建一个定制的转换器来删除离群值。下面的函数将数组/数据框以及“因子”作为输入,并用 NaN 替换每列中的异常值。
在上面的代码片段中,我们还创建了一个名为“FunctionTransformer”类的“outlier_remover”的实例,方法是传递我们为异常值删除定义的自定义函数(“outlier_removal”)以及参数“factor”。在此方法中,我们需要使用“FunctionTransformer”的“kw_args”参数将附加参数(而不是输入数组/数据帧)作为字典传递给“Functiontransformer”中的函数。我们还创建了方法 1 中使用的“测试”数据框。
作者图片
我们可以看到“col1”有一个异常值(999),而“col3”也有一个异常值(-10)。我们将使用已经创建的实例“outlier_remover”对数据进行拟合和应用“OutlierRemover”转换。
outlier_remover.fit_transform(test)
我们可以看到,“列 1”(999)中的异常值被替换为 NaN,“列 3”(10)中的异常值被替换为 NaN。使用“FunctionTransformer”创建一个自定义转换器为我们提供了一些额外的方法,如下所示。
[i for i in dir(outlier_remover) if i.startswith('_') == False]
作者图片
现在,我们将创建一个移除异常值的管道,估算移除的异常值并拟合逻辑回归模型。我们将使用 GridSearchCV 调优超参数。
作者图片
方法 2 的主要区别在于,我们需要调整“kw_args”超参数,这与其他变压器(包括方法 1 中讨论的变压器)不同。在上面的代码片段中,我们使用值列表[{‘factor’:0}、{‘factor’:1}、{‘factor’:2}、{‘factor’:3}、{‘factor’:4}]调整了’ kw_args '超参数。这可能使得难以调整定制变压器的多个超参数。
这是使用 Scikit-Learn 定义定制转换器的两种方法。定义自定义转换器并将它们包含在管道中简化了模型开发,还防止了使用 k-fold 交叉验证时的数据泄漏问题。
创建定制的 ML Web 应用程序
使用 Gradio 创建基于 UI 的应用程序
来源:作者
如果你曾经创建过一个 web 应用程序,那么你应该知道构建一个需要付出的努力。创建 web 应用程序需要花费大量时间,因为我们需要寻找 UI 组件,创建机器学习模型,创建管道以在应用程序中呈现它,等等。这需要一点经验和知识来使它工作。
Gradio 是一个开源 python 库,用于创建漂亮的 web 应用程序。我们可以围绕 ML 模型创建一个 UI 包装器,并将其呈现给期望的受众。它易于使用,只用几行代码就能创建应用程序。
在本文中,我们将探索 Gradio 的基础知识,并通过应用不同的过滤器创建一个图像编辑应用程序。
让我们开始吧…
安装所需的库
我们将从使用 pip 安装 Gradio 开始。下面给出的命令可以做到这一点。
!pip install gradio
导入所需的库
在这一步中,我们将导入所需的 Gradio & Numpy 库。
import gradio as gr
import numpy as np
创建 Web 应用程序
在这里,我们将创建 web 应用程序,其中我们将使用 NumPy 数组创建不同的过滤器进行图像编辑,并使用 Gradio 渲染该应用程序,以创建一个漂亮的界面,我们将上传任何图像并在其上应用过滤器。
def sepia(img):
sepia_filter1 = np.array([[.99, .99, .9],
[.29, .19, .9],
[.98, .345, .234]])
sepia_img1 = img.dot(sepia_filter1.T)
sepia_img1 /= sepia_img1.max()
return sepia_img1iface = gr.Interface(sepia, gr.inputs.Image(shape=(200, 200)), "image")
iface.launch()
来源:作者
你可以看到我们使用 Gradio 用一行代码创建了一个多么漂亮的界面。在接下来的文章中,我将向您展示如何为您的机器学习、深度学习和 NLP 应用程序创建 UI 界面。
继续尝试不同的图像和过滤器。如果您发现任何困难,请在回复部分告诉我。
本文是与 Piyush Ingale 合作完成的。
在你走之前
感谢 的阅读!如果你想与我取得联系,请随时联系我在 hmix13@gmail.com 或我的 LinkedIn 简介 。可以查看我的Github简介针对不同的数据科学项目和包教程。还有,随意探索 我的简介 ,阅读我写过的与数据科学相关的不同文章。
使用 Jupyter Notebook 创建数据科学 Python 包
了解面向对象编程如何帮助您使用 Jupyter notebook 构建第一个 Python 包。
图片作者|元素作者 katemangostar
介绍
你想知道像 Scikit-learn、pandas 和 NumPy 这样的 Python 包是如何构建的吗?它们都基于面向对象编程(OOP)来创建复杂且易于使用的包。对于一个数据科学家来说,学习 OOP 是必要的,这样他们就可以在生产就绪产品的开发中使用它。
我们将使用 cloud Jupyter 笔记本来简化环境的设置,并完全专注于创建一个包。该项目包括面向对象的基础知识,如继承,对象,类和神奇的功能。这个项目受 AWS 机器学习基础课程的影响很大,一旦我知道如何构建它,我花了 10 分钟来重新创建这个包。
分布
父类
让我们深入编码并讨论我们的父类“分布**”**,它将被高斯和二项式类使用。我们将使用 Jupyter 笔记本的神奇功能%%witefile
来创建 python 文件。
%%writefile distributions/general.py
上面的代码将在发行版文件夹中创建一个 python 文件,为了简单起见,您需要创建一个包含测试文件的测试文件夹,一个包含所有软件包文件的发行版文件夹,以及一个包含.txt
的数据文件夹。
分布类有两个参数,表示和标准差,它还包含用于访问数据文件的read_data_file()
函数。
__init__
函数初始化变量。
测试分布类
这个班的一切都很顺利。我们添加了均值、标准差,并加载了random.txt
文件来测试我们的Distribution
类。
高斯分布
高斯分布在统计学中很重要,在社会科学中常用来表示分布未知的真实随机变量。 —维基百科
图 1 | 维基百科
平均
一列数字的平均值是所有数字的总和除以样本数。意思是——维基百科
标准偏差
这是对数据变化的一种度量。BMJ
概率密度函数
参数mu
是均值,而参数 sigma 是标准差。x
是一个列表中的值。
高斯类
我们将从父类Distribution
继承值和函数,并使用 python 这个神奇的函数。
- 初始化父类分配
- 创建
plot_histogram_pdf
函数→ 数据的归一化直方图,并可视化 概率密度函数。 - 创建魔法函数
__add__
→ 将两个高斯分布对象相加。 - 创建魔法函数
__repr__
→ 输出高斯实例的特征。
做实验
测试__repr__
魔法功能。
用 25 个平均值和 2 个标准偏差初始化gaussian1
对象,然后从数据文件夹中读取random.txt
文件。
计算数据上 25 means 和 2 Stdev 的概率函数。然后,计算random.txt
的均值和标准差。新的均值是 125.1 和 Stdev 到 210.77 ,这使得我们的概率密度函数值从 0.19947 变为 0.00169 。
绘制概率密度函数的直方图和线图。
单元测试
unittest 是一个测试框架,最初受 JUnit 的启发,与其他语言中的主要单元测试框架有相似的风格。它支持测试自动化,共享测试的设置和关闭代码,将测试聚合到集合中,以及测试独立于报告框架,参见文档。
创建高斯类测试文件
测试优先是一个很好的工具。它在团队中创造了更好的理解和生产力。结果是高质量的代码——无论是在早期成功发现错误还是正确实现功能方面。— 吉尔·齐伯菲德
我们将使用 unittest 库来测试我们所有的函数,以便将来如果我们做了任何更改,我们可以在几秒钟内检测到错误。
创建包含所有函数的TestGaussianClass
来测试Gaussian
类中的函数。我们使用了assertEqual
方法来破解函数的有效性。
我自己测试了这些值,然后将它们逐个添加,以测试每种可能性。
试探性试验
让我们使用!python
运行测试文件夹中的测试文件。
如你所见,所有测试都通过了。一开始我得到了多个,调试这些问题帮助我更好地理解了Gaussian
类是如何在每一级工作的。
二项分布
带参数n
和p
的二项式分布是一系列n
独立实验中成功次数的离散概率分布,每个实验都提出是或否的问题,并且每个实验都有自己的布尔值结果:成功(概率为 p)或失败(概率为 q = 1p)。二项式分布—维基百科
平均
差异
标准偏差
概率密度函数
二项式类
我们将使用上面提到的数学函数来创建均值、标准差和概率密度函数。我们已经在上一个类中完成了具有挑战性的工作,现在我们将使用类似的模式来编写Binomial
类。
- 初始化概率和大小变量→ p,n
- 初始化父类分布→ 计算
**mean**
和**Stdev**
并将其添加到父类中。 - 创建
replace_stats_with_data
函数 → ,从导入的数据中计算概率、大小。新的平均值和标准偏差将被更新。 - 使用 matplotlib 库创建
*plot_bar*
函数→ 显示条形图。 - 创建
*pdf*
函数→ 使用均值和标准差计算数据的概率密度函数。 - 创建
*plot_bar_pdf*
函数→ 绘制二项分布的 pdf。 - 创建魔法函数
*__add__*
→ 用两个**Binomial**
分配对象相加。 - 创建魔法函数
*__repr__*
→ 输出**Binomial**
实例的特征
做实验
测试__repr__
魔法功能
测试Binomial
对象和read_data_file
功能。
测试 p 0.4 和 n 20 的初始值的 pdf。我们将使用replace_stats_with_data
来计算数据的 p 和 n ,然后重新计算 PDF。
测试条形图
测试概率密度函数柱状图。
二项式类别测试函数
我们将使用 unittest 库来测试我们所有的函数,以便将来如果我们做了任何更改,我们可以在几秒钟内检测到错误。
创建TestBinomialClass
,它具有测试Binomial
类的所有函数。
试探性试验
运行 test_binomial.py 显示在测试过程中没有发现错误。
正在创建 init。py 函数
我们需要在 distributions 文件夹中创建__init__.py
文件来初始化 python 文件中的类。这将帮助我们直接调用特定的类。
我们已经启动了二项式和高斯类。
创建 setup.py 函数
这个setuptools
是构建 python 包所必需的。设置功能需要软件包信息、版本、描述、作者姓名和电子邮件。
目录
下图显示了包含所有必需文件的包目录。
安装分发包
(venv) [[email protected]](https://www.analyticsvidhya.com/cdn-cgi/l/email-protection):~/work # pip install -U .
使用pip install .
或pip install -U .
来安装我们可以在任何项目中使用的 python 包。正如我们所看到的,我们的分发包已经成功安装。
**Processing /work**
Building wheels for collected packages: distributions
Building wheel for distributions (setup.py) ... done
Created wheel for distributions: filename=distributions-0.2-py3-none-any.whl size=4800 sha256=39bc76cbf407b2870caea42b684b05efc15641c0583f195f36a315b3bc4476da
Stored in directory: /tmp/pip-ephem-wheel-cache-ef8q6wh9/wheels/95/55/fb/4ee852231f420991169c6c5d3eb5b02c36aea6b6f444965b4b
**Successfully built distributions**
Installing collected packages: distributions
Attempting uninstall: distributions
Found existing installation: distributions 0.2
Uninstalling distributions-0.2:
Successfully uninstalled distributions-0.2
Successfully installed distributions-0.2
测试我们的包
我们将在 Linius 终端中运行 Python 内核,然后测试这两个类。
做得好,你已经创建了你的第一个 Python 包。
>>> from distributions import Gaussian
>>> from distributions import Binomial
>>>
>>> print(Gaussian(20,6))
**mean 20, standard deviation 6**
>>> print(Binomial(0.4,50))
**mean 20.0, standard deviation 3.4641016151377544, p 0.4, n 50**
>>>
https://github.com/kingabzpro/Creating-Python-Package-using-Jupyter-Notebook
如果还面临问题,可以去看看我的GitHubrepo或者**Deepnote项目。******
你可以关注我的领英和 T21,我每周都会在那里发表文章。
本文中显示的媒体不归 Analytics Vidhya 所有,由作者自行决定使用。
原载于 2021 年 7 月 30 日 https://www.analyticsvidhya.comhttps://www.analyticsvidhya.com/blog/2021/07/creating-data-science-python-package-using-jupyter-notebook。****
用 3 到 5 行代码创建深度神经网络
思想和理论
我们可以通过改变已经提出的模型的很少几行代码来创建新的深度神经网络。
图片作者。
当在深度学习中处理监督学习时,我们可以说有一些经典的方法可以遵循。第一种解决方案是所谓的“英雄”策略,其中从零开始创建一个全新的深度神经网络(DNN ),并对其进行训练/评估。实际上,这种解决方案可能不是很有趣,因为现在有无数的 dnn 可用,如许多深度卷积神经网络(CNN),可以重复使用。第二条路是简单地考虑一个可部署的 DNN,为某个环境训练,并在另一个环境中观察它的操作。尽管深度学习取得了诸多进步,但如果环境过于多样化,模型可能会表现不佳。
今天最著名的方法之一被称为迁移学习,它用于通过转移相关领域的信息来改进一个领域(上下文)的模型。依赖迁移学习的动机是当我们面临训练数据集中没有那么多样本的情况时。造成这种情况的一些原因是,收集和标记这些数据并不便宜,或者这些数据很少。
但是,迁移学习也有缺点。通常,模型是在大型数据集上训练的,因此这种预训练的模型可以在另一个上下文中重用。因此,我们不是从零开始训练,而是基于预训练模型中嵌入的后天“智能”。然而,即使我们有大量的图像要训练,训练数据集也必须足够通用,以处理不同的上下文。有许多有趣的基准映像集,如 ImageNet 和 COCO,旨在解决这个问题。但是,最终,我们可能会在一个具有挑战性的领域(例如自动驾驶、遥感)工作,其中基于这些经典数据集的迁移学习可能是不够的。
即使我们多次尝试增加训练样本,例如数据增加、生成对抗网络(GANs),我们也可以通过重用和/或进行一些修改和/或组合其他已提出模型的不同特征来创建新模型。这种策略的一个最重要的例子是著名的对象检测 DNNs,称为 YOLO 。这些模型,尤其是版本 4,是基于许多其他解决方案开发的。这种网络是一种不同概念的折衷混合,以获得一种新的模型,它们在检测图像和视频中的对象方面非常成功。请注意, YOLOX 是 YOLO 网络的最新版本。
这篇文章的方向是通过在以前提出的方法中完成一些变化来创建新的模型。它展示了通过改变先前提出的模型的很少几行代码来创建“新的”dnn 是多么容易。请注意,由于我们所做的更改基本上与原始模型的层数有关,因此我们将下面介绍的网络称为“新”网络,这是对它的一点推动。但是,重点是鼓励实践者考虑这一点,并最终在实际环境中使用 DNNs 时重用/修改以前的想法以产生新的方法。
VGG12BN
在 2014 年 ImageNet 大规模视觉识别挑战赛(ils vrc)中,VGG 是一个经典的 DNN,今天仍有一些用途,尽管一些作者认为它是一个过时的网络。在最初的文章中,作者提出了具有 11、13、16 和 19 层的 vgg。在这里,我们展示了如何创建一个“新的”VGG 组成的 12 层和批量规格化(BN)只是通过增加/改变 5 行代码:VGG12BN。
我们依赖 PyTorch 团队的实现,并修改它来创建我们的模型。VGG 修改后的代码是这里是,使用它的笔记本是这里是。此外,我们考虑了 fastai 的 imagenette 320 px 数据集的一个稍微修改的版本。不同之处在于,原始验证数据集被分成两部分:包含原始验证集的 1/3 图像的验证数据集,以及组成测试数据集的 2/3 图像。因此,在训练中有 9,469 幅图像(70.7%),在验证中有 1,309 幅图像(9.78%),在测试集中有 2,616 幅图像(19.53%)。这是一个有 10 个类别的多类别分类问题。我们将数据集称为 imagenettetvt320 。
我们现在展示我们在 PyTorch 团队的 VGG 实现中所做的修改:
- 首先,我们注释掉了
from .._internally_replaced_utils import load_state_dict_from_url
以避免依赖其他 PyTorch 模块。此外,为了完全确定我们不会使用预训练模型(默认情况下 pretrained = False),我们注释掉了model_urls
。这只是为了强调这一点,并不是真的有必要这样做; - 第一个修改是增加了我们车型的名称:
"vgg12_bn”
;
图片作者。
- 由于我们有 10 个类,所以我们把
num_classes
从 1000 改成了 10;
图片作者。
- 因此,我们创建一个新的配置,
"V"
,具有以下卷积层(每层的信道数量按顺序显示):64、64、128、128、256、256、512、512、512。请注意,下面的"M"
表示最大池。因为 VGG 默认有 3 个全连接(FC)层,所以我们总共有 12 个层;
图片作者。
- 最后,我们创建一个函数
vgg12_bn
,其中只有一行代码调用另一个函数。请注意,我们看到参数"vgg12_bn"
(网络名称)、"V"
(配置)和True
的值,其中后者激活批量标准化。
图片作者。
就是这样。通过添加/修改 5 行代码,我们创建了我们的模型。在笔记本中,我们需要导入vggmodified
文件来使用 VGG12BN。
图片作者。
下图(表)显示了基于 10 个时期训练后的测试数据集的准确度(Acc)结果。我们比较了原始的 VGG16BN、VGG19BN 和提议的 VGG12BN 模型。列 # Train Param (M) 、 # Param Mem (MB) 、 Time (s) 表示每个模型的百万个可训练参数的数量,仅由模型参数决定的兆字节大小,以及使用 Google Colab 执行它们的时间。我们的“新”VGG12BN 获得了更高的精度。
VGG:结果。图片作者。
DenseNet-83 和 ResNet-14
在 DenseNet 模型中,每一层都以前馈方式与其他层相连,旨在最大化层间的信息流。2015 年 ILSVRC 的另一个获奖者, ResNet 是最受欢迎的 CNN 之一,其中已经提出了它的几个变体(ResNeXt、Wide ResNet、…),它也作为其他 dnn 的一部分得到了重用。这是一种残差学习方法,其中堆叠层拟合残差映射,而不是直接拟合期望的底层映射。我们遵循了与刚才介绍的 VGG12BN 类似的过程,但现在我们只需更改 3 行代码,就可以创建 DenseNet-83 (83 层)和 ResNet-14 (14 层)。
访问此处dense net 修改后的代码及其对应的笔记本是此处。ResNet 修改后的代码在这里是,笔记本与 VGG12BN 相同,但现在我们通过运行 ResNet-14 来显示的输出。由于创建这两个网络的修改是相似的,下面我们将只显示创建 DenseNet-83 的修改。因此,这就是我们所做的:
- 如前所述,我们注释掉了
from .._internally_replaced_utils import load_state_dict_from_url
以避免依赖其他 PyTorch 模块。但是注意,我们现在没有评论出models_url
; - 我们添加了我们模型的名称:
"densenet83"
;
图片作者。
- 我们创建一个函数
densenet83
,它只有一行代码调用另一个函数。注意,我们看到参数"densenet83"
(网络的名字),和(3,6,18,12)的值分别是密集块 1,2,3,4 的重复次数。
图片作者。
下图显示了 ImageNet 的 DenseNet 架构。我们将 DenseNet-161 作为参照,并将嵌段的重复次数减半以得到 DenseNet-83。
图片(表格)来自 DenseNet 的文章。
总共添加/修改了 3 行代码。对于 DenseNet,下图(表)显示了基于 10 个时期训练后的测试数据集的准确度(Acc)结果。我们比较了最初的 DenseNet-121、DenseNet-161 和提议的 DenseNet-83 型号。我们基本上看到了 DenseNet-161 和我们的“新”DenseNet-83 在性能方面的差距,DenseNet-161 略胜一筹。
DenseNet:结果。图片作者。
关于 ResNet,比较 ResNet-18、ResNet-34 和“新”ResNet-14,ResNet-18 最好,ResNet-14 次之,如下图(表)所示。
ResNet:结果。图片作者。
结论
在本帖中,我们展示了通过修改先前提议的网络的几行代码来创建新的 dnn 是多么容易。我们声称重用以前的想法并通过适当的修改衍生出新的模型是一个很好的途径。
创建、编辑和合并 ONNX 管道。
可视化一个简单的图像处理管道。
ONNX 是一种非常有用的存储数据科学/人工智能工件的格式,用于版本控制和部署。我们很高兴分享[sclblonnx](https://pypi.org/project/sclblonnx/)
,这是一个 python 包,可以轻松编辑和扩充 ONNX 图形。
在过去的一年里,在 Scailable ,我们大量使用 ONNX 作为存储数据科学/人工智能工件的工具:ONNX 图有效地指定了对输入数据执行的所有必要操作,以生成所需的输出。因此,ONNX 不仅可以用于存储复杂的人工智能/人工智能模型(像 TensorFlow 和 PyTorch 这样的流行的人工智能框架将允许您开箱即用),而且还可以在某些特定的上下文中部署经过训练的模型所必需的所有预处理和后处理。因此,我们使用 ONNX 作为 DS / AI 模型和管道的版本控制工具。此外,一旦 ONNX 中的管道可用,就可以很容易地高效部署。
因为在 Scailable,我们经常使用 ONNX,并且因为我们对 ONNX 模型/管道的使用几乎总是(远远)超出简单地将一个合适的模型存储在一个环境中,以便以后在完全相同的环境中使用它,我们经常发现自己处于这样的情况,我们想要检查、改变、测试或合并现有的 ONNX 图。例如,我们经常将图像大小调整添加到现有的视觉模型中,这样所得到的 ONNX 管道就可以用于不同分辨率的相机。然而,在我们看来,现有的onnx.helper
API 使用起来有点困难。因此,在内部,我们正在开发(并不断尝试改进)一个用于操作 ONNX 图形的高级 API。今天,我们正在开源我们当前的版本;请下载、探索、追加或提交问题/功能请求。
在本文的剩余部分,我将提供一个sclblonnx
python 包的概述,该包旨在使手动操作 ONNX 图变得容易。
基本用法
简单地说,sclblonnx
包提供了许多高级实用函数来处理 ONNX 图。我们尝试使用一致的语法,如下所示:
# Import the package
import sclblonnx as so# Assuming we have a graph object g:
g = so.FUNCTION(g, ...)
因此,我们提供了许多函数来操作一个图(并且经常改变该图),这导致了该图的更新版本。常见的功能有:
add_node(g, node)
:向现有的图中添加一个节点(是的,显然你也可以delete_node(g, node)
)。add_input(g, input)
:向现有图形添加新输入。您也可以删除或更改输入。add_output(g, output)
:向现有图形添加新输出。add_constant(g, constant)
:给图形添加一个常数。clean(g)
:清理图形;这一点非常重要,因为导出的图形经常会臃肿或者不完全一致。check(g)
:检查图形是否有效,是否可以运行,是否可以使用 Scailable 部署(后者可以关闭)display(g)
:使用 Netron 目视检查图形。merge(g1, g2, outputs, inputs)
:将两个(子)图形合并成一个图形。例如对训练好的模型添加预处理。
请注意, ONNX 图形是而不是当您将模型从您最喜欢的培训工具导出到 ONNX 时,存储的唯一内容是一个 ONNX 模型(.onnx
文件的内容),它包含图形、和用于生成图形的软件/版本的描述。因此,一旦你使用sclblonnx
打开一个模型,该包将提取图形,并且,如果你使用该包存储打开的图形到.onnx
——同样,即使没有编辑该模型——存储的模型将不同于原始模型,因为现在它将由sclblonnx
包生成。
一个简单的例子:从头开始创建一个图
介绍软件包的最简单方法是通过示例;我们已经向其中一些人提供了包装本身。第一个例子创建了一个超级简单的 ONNX 图,将两个数相加。
首先,让我们创建一个空图:
g = so.empty_graph()
现在我们有了空图g
,我们可以开始向它添加节点、输入和输出:
# Add a node to the graph.
n1 = so.node('Add', inputs=['x1', 'x2'], outputs=['sum'])
g = so.add_node(g, n1) # Add inputs:
g = so.add_input(g, 'x1', "FLOAT", [1])
g = so.add_input(g, 'x2', "FLOAT", [1]) # And, add an output.
g = so.add_output(g, 'sum', "FLOAT", [1])
就这样,我们刚刚创建了第一个正常工作的 ONNX 图。但是,我们可能想清理、检查和尝试它:
# First, let's clean the graph (not really necessary here)
g = so.clean(g) # Next, lets see if it passes all checks:
so.check(g)# Display the graph
display(g) # Evaluate the graph:
example = {
"x1": np.array([1.2]).astype(np.float32),
"x2": np.array([2.5]).astype(np.float32)
}result = so.run(g,
inputs=example,
outputs=["sum"])print(result)
最后一行打印3.7
,合理。
最后,我们可以存储模型:
so.graph_to_file(g, "filename.onnx")
另一个例子:合并两个现有的图形
也许比创建 ONNX 图来从零开始添加两个数字更有用的是合并两个现有的——可能很复杂——ONNX 图;两个或多个图形的合并就是创建管道的方式。
使用sclblonnx
合并相对容易(尽管不可否认可能有我们还没有考虑的边缘情况;我们打开这个包的动机之一是让它在我们自己的用例之外接受测试:如果您发现任何问题,请提交一个问题,并随时提交更改)。这里有一个例子:
# Open the graphs.
sg1 = so.graph_from_file("resize-image-450x600-300x400.onnx")
sg2 = so.graph_from_file("check-container.onnx")# Merge the two graphs
g = so.merge(sg1, sg2, outputs=["small_image"], inputs=["in"])
上面的代码打开了两个现有的图形。第一个有small_image
作为输出,而第二个有in
作为输入。这两个图形 a) 共同调整大小和图像, b) 检查图像中的容器是否为空。你可以在这里找到工作示例。
包裹
sclblonnx
软件包使编辑、修改、检查和合并 ONNX 图形变得容易。该包仍在开发中;如果您发现任何问题,请分享它们,并提交任何改进。同样,我们认为 ONNX 是存储和管理需要跨设备/平台使用的数据处理管道的好工具。我们希望sclblonnx
包有助于提高 ONNX 的实用性。
尽情享受吧!
放弃
值得注意的是我自己的参与:我是 Jheronimus 数据科学院 的数据科学教授,也是scaliable的联合创始人之一。因此,毫无疑问,我对 Scailable 有既得利益;我有兴趣让它成长,这样我们就可以最终将人工智能投入生产并兑现它的承诺。这里表达的观点是我自己的。
使用 Python Streamlit 创建财务规划计算器
照片由 Unsplash 上的 recha oktaviani 拍摄
财务规划在我们的生活中是必不可少的。除了跟踪我们每月的收入和支出,我们能为未来存多少钱以应对多年来的通货膨胀是另一个重要方面。传统的计算器允许我们进行所有需要的计算,并显示数字。但是,如果我们能够在一个图表中直观地显示我们的预测费用和多年来的节省,那就更好了。好消息是 Streamlit 让我们能够构建自己的财务规划计算器,满足所有需求。
在本文中,我们将一步一步地介绍如何使用 Streamlit*,一个基于 Python 的开源数据科学应用框架*,来创建一个财务规划计算器。Streamlit 是一款简单易学、高度可定制的工具,使我们能够根据自己的需求构建数据应用。
可以使用以下链接访问财务规划计算器的部署版本:
https://share . streamlit . io/teobeeguan/financialplanningcalculator/main/budgetapp . py
如果您希望使用我的代码来跟踪这篇文章,您可以在我的 GitHub Repo 获得完整的源代码。
必备 Python 库
在开始开发过程之前,我们需要确保以下库在我们的机器中可用:
计算器应用的开发
1.导入库
首先,我们尝试在程序中导入所有需要的库。
2.设置页面标题
接下来,我们为计算器应用程序创建页面标题(如财务规划计算器)。
**第 1–2 行:**在 set_page_config 方法中设置浏览器标签标题。
**第 3 行:**在我们的应用程序主体中创建一个一级标题。
此时,我们可以尝试运行 Streamlit 应用程序来可视化输出。为此,我们在终端/命令提示符下键入以下命令。
streamlit run YourPythonFileName.py
(注意: 在运行应用程序之前,请确保您已经导航到保存脚本文件的目录。)
我们将看到如下输出:
作者准备的图像
3.创建收入部分
在这里,我们希望获得用户对收入的输入。为此,我们需要一个工资输入字段和另一个税率输入字段。
**第 1–2 行:**创建一个标题(如月收入)和一个副标题(如工资)。
**第 3 行:**创建两列,并列放置我们的工资和税率输入字段。 colAnnualSal 和 colTax 是我们定义的列名。
**第 5–6 行:**在第一列( colAnnualSal ,使用 Streamlit number_input 方法创建年薪的数值输入字段。我们可以设置最小值为 0.0,格式为一个小数点数字,“ %f ”。
**第 7–8 行:**在第二列( colTax ),使用 Streamlit number_input 方法创建另一个税率数值输入字段。
**第 10–12 行:**计算每月实得工资的公式。核心思想是按照进项税率从对我们收入征收的税中扣除工资。接下来,扣除税款后的工资除以 12,这将得出每月的实得工资。
作者准备的图像
4.创建费用部分
现在,我们将转到费用部分。我们将为月租金、每日食物预算、水电费等创建几个输入字段。(您可以根据自己的需要灵活地更改或添加任何相关字段)。
**第 1–2 行:**创建一个标题,并定义两列来放置我们的输入字段。
第 4 行:-13: 在第一列中,创建三个数字输入字段,分别用于每月租金、每日食物预算和不可预见费用及其相应的子标题。
**第 15–23 行:**在第二列中,创建另外三个数字输入字段,分别用于每月交通费、每月水电费和每月娱乐预算及其相应的子标题。
**第 25–26 行:**计算每月 _ 费用和每月储蓄的公式。基本上,我们合计所有的月支出项目,然后从每月的实得工资中减去它们,以获得我们每月的储蓄。
作者准备的图像
5.显示计算的节省
这里,我们希望显示根据我们在脚本中定义的公式计算出的节省。
**第 1–4 行:**创建一个标题(如储蓄),然后将计算出的实得工资、每月开支和储蓄显示为三个不同的副标题。
作者准备的图像
6.预测节约
此时,我们已经完成了根据当前收入和支出计算储蓄的部分。虽然我们可以选择多年保持我们的生活方式,但这并不意味着我们的开支和储蓄金额在未来几年将保持不变。由于通货膨胀的因素和我们工资/收入的增加,储蓄金额会随着时间的推移而变化。假设我们的生活方式在未来几年保持不变,预测通货膨胀和我们的增量收入如何相互交织以影响我们的财务计划是一件有趣的事情。
我们可以将这一部分分成两部分:
(a)为通货膨胀率和工资增长率创建输入字段,
(b)创建一个图表,显示预测工资、费用和储蓄的趋势
6.1。为通货膨胀率和工资增长率创建输入字段
这里我们将创建几个用户输入字段,以获得他们每年的估计通货膨胀率和工资增长率。为了简化我们的计算,我们假设通货膨胀和工资/收入增长将遵循相同的预计增长率。
**第一行:**在我们的计算应用程序中创建一条水平线。
**第 3–4 行:**创建一个标题并定义两列来放置我们的输入字段。
**第 5–14 行:**在第一列中,使用 number_input 方法创建预测年和通货膨胀率的数字输入字段及其相应的子标题。
每月通货膨胀的计算遵循以下公式:
作者准备的图像
一旦计算出每月的通货膨胀率,我们就开始计算每月的预测累积通货膨胀率。Numpy 为我们提供了两个非常有用的内置方法, np.cumprod 和 np.repeat ,让我们免于重复计算几个月的累计通胀。 np.cumprod 和 np.repeat 将给我们一系列按月的通货膨胀率,我们把它赋给一个变量cumulative _ inflation _ forecast。通过将每月费用乘以预测的累积通货膨胀率,我们可以得到一系列从这个月到另一个月的预测费用。
**第 15–20 行:**在第二列中,使用 number_input 方法为预期年薪增长创建数字输入字段。
每月工资增长的计算如下:
作者准备的图像
几个月内预测的累积工资增长的计算类似于上文详述的通货膨胀。
**第 22–23 行:**通过从预测工资中减去预测费用来计算每月的预测节省。接下来,使用 NumPy cumsum 方法来计算过去几个月累计的预测储蓄。请注意,我们假设没有额外的储蓄支出。
6.2 创建一个图表,显示预测工资、费用&节省的趋势
上一节已经给出了几个数字序列中所有计算出的预测工资、费用和储蓄。每一个数字序列的图表会给我们一个更清晰的画面,让我们检查我们目前的储蓄是否足以应对未来的通货膨胀。
我们将使用 Python Plotly 库在单个图表中创建三个线图,以根据用户输入的预测年数显示预测的工资、费用和储蓄的趋势。
**第 1 行:**按预测年数设置 x 轴数值。
**第 3–10 行:创建一个图形对象。使用 Plotly go 为预测工资创建一个线图。分散物体。将预测薪金设置为 y 轴值。使用add _ trace方法将该图添加到图形对象。
***第 12–26 行:*以类似的方式,使用 go 创建预测费用和预测节省的折线图。分散对象并将它们添加到同一个图表中。
第 27–29 行:使用 update_layout 方法设置整个图表的标题,以及 x 轴和 y 轴的标题。
***第 31 行:*使用 Streamlit plotly_chart 方法渲染图表。
作者准备的图像
目前,图表显示为空,因为我们还没有在前面创建的输入字段中输入任何输入值。
7.示范
现在,计算器应用程序已经准备好了,我们可以通过输入所有必需的工资和费用条目值来测试它。
作者准备的图像
通过输入上述所有收入和支出的输入值,我们的应用程序将计算并显示当前每月的税后工资、支出和储蓄,如下所示。
现在,让我们开始输入预测年数、预计通货膨胀率和工资增长率。
作者准备的图像
输入上述值后,我们将看到图表中显示的线图。
作者准备的图像
图表显示了未来 5 年的健康储蓄计划。假设年通货膨胀率为 5%,预测工资/收入将远远高于预测费用。预计累计储蓄将逐年稳步增长。
现在,让我们尝试调整年薪增长和通货膨胀率的输入值。
作者准备的图像
这次我们试图假设通货膨胀率是工资增长的两倍。对于我们的储蓄计划,我们将得到一个非常不同的图景。
作者准备的图像
在大约 4 到 5 年的时间里,我们的支出将超过我们的收入,从那时起,我们开始花我们的积蓄。如果我们将预测年份的数量延长至 10 年,则从第 8 年开始,预测节约将变为负值。
作者准备的图像
如果我们多年来有额外的支出或承诺(如抵押贷款、孩子等),我们可以想象更糟糕的情况。这就是为什么在作出任何额外的财务承诺之前,一个适当和仔细的财务规划是至关重要的。
结论
这里介绍的财务规划计算器给我们一个未来收入、支出和累积储蓄的粗略预测。我们可以选择根据我们的需求定制计算器,通过输入更多的输入字段来捕捉用户的收入来源和支出领域。这将导致更精确的投影。从上面的样本结果中,我们还可以了解到,额外的投资计划或额外的收入来源可能对保持健康的财务状况非常有帮助。
另一方面,本文还旨在展示 Streamlit 在开发金融数据应用程序中的一个可能用例。Streamlit 在我们的技术市场中的存在为我们提供了一个简单的平台,可以快速构建和部署任何类型的数据应用程序。
我希望你喜欢阅读这篇文章。
Github
这篇文章的所有源代码都在我的 Github Repo 中。
参考
https://numpy . org/doc/stable/reference/generated/numpy . cum prod . html
https://numpy . org/doc/stable/reference/generated/numpy . cumsum . html
https://numpy . org/doc/stable/reference/generated/numpy . repeat . html
从基因组数据创建生殖艺术 NFT
作者图片
在这篇文章中,我概述了我和 IPFS 在区块链以太坊创建动态 NFT 的旅程,并讨论了科学数据可能的用例。我不讨论静态图像的算法生成(你应该阅读 Albert Sanchez Lafuente 的 neat 一步一步的),而是演示当从浏览器查看 NFT 时,我如何使用 Cytoscape.js、Anime.js 和基因组特征数据在运行时动态生成可视化/艺术。我也不会提供区块链的概述,但我强烈推荐阅读黄一飞最近的帖子:为什么每个数据科学家都应该关注加密。
疫情期间,我被困在家里,我是在我们位于布鲁克林的小公寓阳台上尝试园艺的 1000 万 T4 人之一。日本黄瓜很受我们邻居的欢迎,西红柿很受松鼠的欢迎,但我最喜欢看辣椒生长。这就是我的第一个 NFT 的目标:描绘一个随着时间而成熟的辣椒。
有多少描绘是视觉化的,多少是艺术?这是旁观者的看法。当你花时间仔细检查数据点,崇拜最佳实践,优化从内存使用到午餐订单的一切时,采取一些艺术许可,仅仅因为你喜欢就做出一些东西,这是很好的,这正是我在这里所做的。该描述真实地产生于基因组数据特征,但显然这不应被视为任何种类的严肃的生物学分析。
如果你正在寻找最终的实况结果,你可以在这里查看它,在这里查看 GitHub 上的源代码。
准备基因组数据
这里没有什么新的东西,但为了完整起见,我将快速浏览一遍。我的第一站是访问 NCBI 装配页面,搜索辣椒。我很惊讶地发现了 8 个结果,我想我也许可以创造 8 种不同的辣椒,但在进一步挖掘后,我发现并非所有的数据集都有注释,同一物种有一些重叠。在对那些既有注释又有独特物种的进行过滤后,我得到了 3 个可行的数据集:
我发现 Dubey 等人[3]的这篇论文 T14 列出了 11 个怀疑与辣椒果实成熟有关的基因组区域,并从补充材料中复制了引物核苷酸序列和长度。
来自 NCBI 的 gff 文件是简单的 tsv 文本文件,列出了一个特征(如基因、mRNA、外显子等)以及开始和结束坐标以及任何其他元数据——参见下面的示例。我们的目标是将这些文件分成子集,只包含那些属于 Dubey 研究中成熟过程所涉及的区域的特征。
NC_029977.1 Gnomon gene 590985 592488 . - . ID=gene-LOC10...
NC_029977.1 Gnomon mRNA 619017 620755 . + . ID=rna-XM_016...
NC_029977.1 Gnomon exon 619829 620755 . + . ID=exon-XM_01...
为了只从那些感兴趣的区域提取 gff 特征,我们需要相应的坐标,这是通过 NCBI 基本局部比对搜索工具( BLAST )实现的。使用这个工具,我们获得了 Dubey 研究中发现的每一个核苷酸序列(例如 GGCATCGT…),并在每种植物的整个基因组序列中查找它——类似于在一本非常大的书中查找特定的短语。
BLAST 确实有一个 web 界面,但我想编写这个步骤的脚本,以便它可以在三个数据集上一致地重复,所以接下来我下载了他们的命令行应用程序。我首先试图通过传递-remote
标志来使用 NCBI 服务器进行处理。结果以令人怀疑的速度返回,我没有得到任何点击,但是我发现你还需要通过短序列的-task blastn-short
,这似乎在任何地方都没有记录。
blastn -db “GPIPE/4072/100/GCF_000710875.1_top_level” -query dubey.fsa -out results.out -task “blastn-short” -remote
这现在产生了相反的效果——远程进程运行了很长时间,而我得到了Error: [blastn] Failed to fetch sequences in batch mode
。此时,我决定对子弹进行字节化处理,并创建自己的 BLAST 数据库来本地运行这个过程。我从同一个 NCBI 页面下载了所有 fna 文件,并编写了一个类似如下的命令:
for g in "${genome_ids[@]}"; do
for ((i=1;i<=12;i++)); do
makeblastdb -in datasets/ncbi_dataset/data/${g}/chr${i}.fna
-dbtype nucl -parse_seqids -out blast/dbs/${g}/chr${i}.blast
done
done
这被证明是值得的:我重复了 blastn 命令,但没有使用-remote
标志,不久后就有了一个坐标列表,报告了成熟过程中涉及的每个基因序列的完美匹配。最后一步是使用一堆 bash 命令(参见源代码)来修剪和格式化数据,因此我为 3 个物种中的每一个留下了一个简单的 3 列 tsv,如下所示——第一列是 Dubey 研究中用于识别该区域的基因位置 ID(总共 11 个不同的 loc ),第二和第三列是 gff 文件中该区域的基因组坐标和特征(有误差)。
LOC107843860 213978278 gene
LOC107843860 213989346 mRNA
LOC107843860 213991885 exon
...
用 Cytoscape.js 生成可视化
几年前,我摆弄过 Cytoscape 桌面应用程序,我一直觉得它生成的网络图形很有美感。显然,我在这里准备的数据绝不是网络,所以这不是一个典型的用例,但我接受了那个创造性的许可并选择了它,因为我喜欢它的外观。
不足为奇的是,Cytoscape.js 需要 JSON 格式的数据,而是什么呢有点令人惊讶的是,它不能像桌面版本那样读取表格(2D 数组)并推断节点和边。相反,我们需要明确地将每个节点和边定义为一个数据对象,如下例所示。
const dataAnnuum = [{
"data": {
"id": "6679599"
}
},{
"data": {
"id": "gene"
}
},{
"data": {
"id": "6679599-gene",
"source": "6679599",
"target": "gene"
}
},
...
jq 来拯救:
for g in "${genome_ids[@]}"; do
for loc in "${loc_ids[@]}"; do
cat graph/$g-$loc.txt | jq --raw-input --slurp 'split("\n") | map(split(" ")) | .[0:-1] | map( { "data": { "id": .[1] } }, { "data": { "id": .[2] } }, { "data": { "id": (.[1] + "-" + .[2]), "source": .[1], "target": .[2] } } )' >> json/$g.js
cat graph/$g-$loc.txt | jq --raw-input --slurp 'split("\n") | map(split(" ")) | .[0:-1] | map( { "data": { "id": .[0] } }, { "data": { "id": .[1] } }, { "data": { "id": (.[0] + "-" + .[1]), "source": .[0], "target": .[1] } } )' >> json/$g.js
done
done
一旦你格式化了你的数据,对我来说唯一的另一个问题是,我需要将构造函数包装在一个DOMContentLoaded
监听器中(见下文),但是除此之外,他们的入门例子很好地工作了。
document.addEventListener("DOMContentLoaded", function () {
cyto1 = cytoscape({
container: document.getElementById("target"),
elements: dataAnnuum,
style: [...],
layout: {
name: "circle",
},
});
});
Cytoscape.js 为动画提供了一个令人印象深刻的 API,可用于动态设置节点和边的样式(见下文),但也值得注意的是,它有一个完整的视口操作特性集,如缩放和平移,这对于需要单步执行和叙述图表的正确通信可视化来说非常方便。作为一个简单的动画示例,在下面的代码中,我找到了与一种基因特征(基因、外显子等)相关的所有边缘,并改变了颜色,将线条的宽度加倍。
cyto1
.nodes("#" + geneFeature)[0]
.connectedEdges()
.animate({
style: {
lineColor: RIPE_COLOR[seqNum],
width: SKELETAL_WIDTH[seqNum] * 2
},
});
用 Anime.js 制作动画
我想让图片更生动一些,但是 Cytoscape.js 的平移和缩放并不是我真正想要的效果。我过去曾和 p5.js 一起玩,这似乎在生成艺术界很流行,但我想借此机会给 anime.js 一个机会,好家伙,我很高兴我这么做了。只需几行代码,我就能拿起包含细胞图的div
,并流畅地前后旋转它,轻松地开始和停止。
anime({
targets: #graph1,
rotate: [45, -45],
duration: 10000,
easing: "easeInOutSine",
direction: "alternate",
loop: true,
});
我还使用了倾斜效果,在页面第一次加载时将图形放大。当你需要开始对效果进行计时和排序时,事情会变得稍微复杂一些,anime.js 为此提供了一个时间线特性。当我将所有的动画移动到时间线上时,我发现还有一个简单的complete:
选项,可以在每个动画完成时触发一个功能,这被证明是一个对这个简单的动画进行排序的更优雅的解决方案。
在 IPFS 部署
不可替代是一个经济术语,用来描述独一无二且不能与其他同类事物互换的事物。不可替代令牌背后的概念是,它们不仅是唯一的,而且其唯一性可以很容易地通过区块链上的公共记录来验证。当一个数字资产,比如一个静态的“photo.jpg”文件,作为一个 NFT 被添加到以太坊区块链时,一个常见的误解是文件“photo.jpg”的实际字节码被写入一个区块。仅交易和链上数据,以太坊区块链今天就超过了 1TB 的大关,所以你可以想象,如果每个 NFT 的 jpeg、gif 和电影文件都被添加进去,它会迅速膨胀到 Pb 级的数据。鉴于区块链的主要动机是去中心化,如果链增长到这种规模,对于大多数节点来说,维护起来会非常大,留下一个更集中的大盒子网络。
NFT 没有将 NFT 数据文件存储在链上,而是有一个不可变的tokenURI
记录指向一个文件。如果这个tokenURI
使用位置寻址,例如传统的 web 服务器,例如http://myserver.com/photo.jpg,那么拥有不可撤销的tokenURI
记录是没有意义的,如果地址目的地的文件可以被切换出去,这就是一些不高兴的 NFT 所有者所发生的事情。
作者图片
这就是 IPFS 的用武之地。星际文件系统是一个点对点的分布式存储网络,与 BitTorrent 不同,它由遍布全球的计算机组成,存储和共享数据。IPFS 还使用一种名为 FileCoin 的加密货币作为激励层,这样用户就可以因为在电脑上存储数据而获得奖励。这里的关键区别是,IPFS 不像传统的网站那样使用位置寻址,而是使用内容寻址,这涉及到生成文件或目录的散列(“CID”)并使用它进行检索。
Location addressing: [http://myserver.com/photo.jpg](http://myserver.com/photo.jpg)
Content addressing: ipfs://QmP7u9UzoUtfpiNkj3Sa...
要从 web 浏览器访问 IPFS 内容,您需要使用网关,如 Cloudflare 提供的 ipfs.io ,例如:
https://ipfs . io/ipfs/qmp 7 u 9 uzoutpinkj 3 sal 5 tly m2 ngrufvsinhf 21 uff 3 l 1
对 NFT 数据使用 IPFS 的好处在于,它不仅是分散的和始终在线的,而且如果文件中的一个字节发生变化,CID 也会发生变化。这意味着 NFT 记录的不可变tokenURI
总是保证返回完全相同的数据。
在开始将数据上传到 IPFS 之前,还有一个额外的考虑事项:用于显示 NFT 的元数据。与其将 NFT 的tokenURI
设置为直接指向 IPFS 上的文件,不如将它指向 IPFS 上的一个元数据 JSON 文件,该文件包含 NFT 的信息,并依次指向源文件以及任何其他文件,如预览图像。因为这个元数据文件也存储在 IPFS 上,所以可以保证它也没有被修改。没有官方的以太坊规范,但是 OpenSea 描述的格式已经成为标准。
作者图片
要将文件上传到 IPFS,你可以下载桌面应用,并使用它上传完整的源目录,包括 index.html、基因组数据、javascript、支持库和预览图像。请注意,index.html 中的文件路径不需要使用内容寻址(IPFS 网关可以在目录级别解析位置寻址),但由于这个原因,它们需要是相对的。
作者图片
现在有了 IPFS 上的数据,然后复制目录和图像预览文件的 CID,并完成 metadata.json 文件中的条目。最后,上传元数据文件并复制将用于 NFT 的 CID。请注意,传递给index.html
的tokenId=1001
参数只是用作一个序列号,以便单个源代码目录可以根据元数据中引用的 URL 生成 3 个不同的变体(种类)。
{
"token_id": 1001,
"name": "Capcicum annuum",
"description": "This red pepper depiction is generated...",
"image": "ipfs://QmYpZF5D95THTiF4gVuUuze46eA4SHjwWEZBvFXSn7GE2k/annuum-preview.png",
"background_color": "fcf5e5",
"external_url": "[https://nicetotouch.eth.link/peppers](https://nicetotouch.eth.link/peppers)",
"animation_url": "ipfs://QmYpZF5D95THTiF4gVuUuze46eA4SHjwWEZBvFXSn7GE2k/index.html?tokenId=1001",
"attributes": [
{ "trait_type": "Species", "value": "Capsicum annuum" },
...
]
}
IPFS 桌面应用程序实际上是向全世界提供你的文件,所以它们只有在你的电脑运行时才可用。为了确保文件始终在线并复制到其他对等点(而不仅仅是临时缓存),我们需要“固定”它们。有一些不同的锁定服务,但我选择了 Pinata ,它给你 1GB 的免费空间,而且非常简单易用。只需注册,点击上传/添加并粘贴您想要 pin 的 cid。
作者图片
以太坊区块链上的造币
最后一步是通过在区块链上创建一个公共的、可验证的记录来主张你的数据的所有权。有很多像 OpenSea 这样的 NFT 聚合器提供造币服务,但不幸的是,它们只支持创建简单的单文件 NFT,如图像和电影。BeyondNFT 是我发现的唯一一个允许你通过上传 zip 文件来创建动态 NFT 的网站,但在撰写本文时,还不支持创建你自己的智能合约,相反,你必须使用他们的通用总括合约。
为了概念化契约的角色,NFT 的“令牌”部分可以被认为是一个对象类的实例,该对象类是 ERC721 智能契约的实现。智能合约存在于区块链上,并具有一个 mint 函数,该函数使用一组不可变的变量(例如一个tokenId
和tokenURI
)创建一个唯一的令牌。由于这个原因,从同一个契约创建的所有令牌都被视为一个“集合”并被分组在一起,因此当创建一组 NFT(如本例所示)时,您确实希望使用自己的契约,而不是加入一些您无法控制的现有大型通用集合。
创建你自己的智能合同,然后铸造一个 NFT 需要几个步骤,幸运的是,阿米尔·索雷玛尼在这本精彩的指南中完美地概述了这些步骤。我以前没有使用 Solidity 或部署智能合同的经验,但在这篇文章之后,我在大约半小时内完成了 3 个 NFT。
科学数据的用例
当我在生物信息学领域工作时,我似乎花了大量的时间来检查、再三检查我认为我正在存储、移动或处理的文件是否确实是正确的文件。带有相应文件名、服务器位置和目录路径的样本名称的电子表格,以及“新的”、“最新的”或“已修复的”这些词困扰着我。
如果你混淆了 Word 文档、电子表格或 JavaScript 源文件的命名,你可以很快确定你打开的文件是错误的,但科学数据通常不是这样。样本数据可能是如此密集和同质,以至于除了结果之外,没有简单可靠的方法来区分文件内容,这就是分析,这意味着文件名混淆可能是灾难性的。
这就是内容寻址数据非常有意义的地方。是的,当你有校验和的时候,它们是很棒的,但是要想有用,它们真的需要从数据的来源产生,并携带到数据去的任何地方。然而,通过校验和寻址给了我们一石二鸟的机会:我们可以保证我们下载的是正确的、原始的、未修改的文件,我们还可以在我们这边对它进行校验和,以确保我们已经完全传输了它。
IPFS 的分散性质也非常适合科学数据。学术界很少拥有与企业同等的资源来提供高度可用、高度冗余的数据,具有讽刺意味的是,大多数学术数据都是公开的,是为了公众利益。如果 NCBI 网站今天离线,虽然他们可能会将数据镜像到其他服务器上并备份到磁带上,但如果我无法访问他们的网站,我就无法访问我需要的数据。有了内容地址,我可以直接从 IPFS 下载数据,独立于任何 URL,也不管 NCBI 节点或网关是否关闭。除此之外,点对点组件的操作就像一个内容交付服务,所以当我在处理一个巨大的基因组参考文件时,如果我隔壁的同事想下载相同的数据,他们会自动从我这里直接获得,而不是跨越全球。
IPFS 不太适合科学数据的地方是起源和血统方面,这是区块链和非功能性测试的方向。在最基本的层面上,在高度可访问、完全冗余、安全、分散的服务上拥有不可变的记录来描述一个数据集或多个数据集,为数据科学带来了巨大的价值。当负责拥有数据的实体改变时,可以处理 NFT,并且永久记录历史,并且如果需要更新记录,可以发布具有更新的元数据的新令牌,该元数据包括对旧令牌和旧数据的引用。
在一个更高的层次上,是对一个记录引用和知识产权的新系统的可能应用。我不是一个学者,但在今天的信息时代,期刊出版和引用系统似乎过时和笨重。几年前,理查德·福达·伯利发表了一篇论文,提议建立一个受比特币启发的分散式共享引用分类账。他指出,集中式分类账(如 Scopus 和 Web of Science)是一项大业务,通常“……关于什么被索引和不被索引的重要决定在许多方面都基于经济考虑”,这对于传播科学知识来说是一个问题。想象一下,如果一篇研究论文,连同所有附带的补充材料、数据集和软件被存放在区块链和 IPFS,归作者所有,任何人都可以阅读和复制。索引呢?像 The Graph 这样的项目已经发明了 Dapps(去中心化应用程序)来索引区块链数据,许多人认为我们像今天使用谷歌一样搜索和浏览 Web3(去中心化 Web)只是时间问题。
最后,区块链是记录知识产权的明显匹配,正如去年世界知识产权组织指出的。虽然他们的讨论集中在设计和商标上,但我也设想了一个与这个例子相关的专利申请。再一次,从我对化学实用专利的有限理解来看,专利的很大一部分是描述这项工作,以及它是如何制作的,以及如何重复或复制(“实现”)。想象一下,如果数据在一个去中心化的区块链上被很好地打包并打上时间戳,这个包用于发布和引用,没有利益冲突或国际政治干预,那么专利当局可以简单地指向这个记录让世界看到。
我希望这为如何将动态可视化作为 NFTs 添加到以太坊区块链提供了一些见解,也让你思考 Web3 在数据科学中可能的未来用例。你可以在这里查看最终结果,在这里查看 GitHub 上的源码。
剪贴画
以上所有剪贴画均来自 un draw(https://undraw.co)并在 unDraw 开源许可下使用。
参考文献
[1] Jo,Y. D .,Park,j .,Kim,j .,Song,w .,Hur,C. G .,Lee,Y. H .,& Kang,B. C .,辣椒质体基因组的完整测序和比较分析揭示了辣椒质体基因组上串联重复和大插入/缺失的高频率(2011),植物细胞报告, 30 (2),217–229。https://doi.org/10.1007/s00299-010-0929-2
[2] Kim S,Park J,Yeom SI 等,辣椒新的参考基因组序列揭示了植物抗病基因的大量进化(2017), Genome Biol 。2017;18(1):210.发布于 2017 年 11 月 1 日。https://doi.org/10.1186/s13059–017–1341–9
[3] Meenakshi Dubey,Vandana Jaiswal,Abdul Rawoof,Ajay Kumar,Mukesh Nitin,Sushil Satish Chhapekar,Nitin Kumar,易勒雅斯·艾哈迈德,Khushbu Islam,Vijaya Brahma,Nirala Ramchiary,辣椒果实发育/成熟相关基因的鉴定和功能标记的开发(2019 年),基因组学,第 111 卷,第 6 期,2019 年,https://doi.org/10.1016/j.ygeno.2019.01.002.
[4]伯利·理查德·福特,稳定而分散?共享引用账本的承诺与挑战(2018),信息服务&使用,第 38 卷,第 3 期,第 141–148 页,2018,https://doi.org/10.3233/ISU-180017
使用 Plotly 创建地理图
使用 plotly 可视化地理数据
来源:作者
Plotly 是一个创建高级交互图形的开源库,可用于轻松绘制各种类型的图形和图表。
在 plotly 之前,创建地理图从未如此容易。Plotly 在后端使用 JS 来呈现图形。这使得它们具有视觉吸引力和高度交互性。
在本文中,我们将使用 plotly 来创建地理图,并使用其他功能。
让我们开始吧…
安装所需的库
我们将从使用 pip 安装 plotly 开始。下面给出的命令将安装它。
pip install plotly
导入所需的库
在这一步中,我们将导入一些创建图表所需的库,加载数据所需的库等等。
import pandas as pd
from urllib.request import urlopen
import json
import plotly.express as pximport plotly.graph_objects as go
创建地理图表
这是最后一步,我们将使用不同的在线数据集创建不同的地理地图。我们将从创建一个简单的图表开始。
with urlopen('https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json') as response:
counties = json.load(response)df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/fips-unemp-16.csv",
dtype={"fips": str})fig = px.choropleth_mapbox(df, geojson=counties, locations='fips', color='unemp',
color_continuous_scale="Viridis",
range_color=(0, 12),
mapbox_style="carto-positron",
zoom=3, center = {"lat": 37.0902, "lon": -95.7129},
opacity=0.5,
labels={'unemp':'unemployment rate'}
)
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()
地理图(来源:作者)
同样,让我们看看其他类型的图表,我们可以使用 Plotly 创建。
df = px.data.election()
geojson = px.data.election_geojson()fig = px.choropleth_mapbox(df, geojson=geojson, color="winner",
locations="district", featureidkey="properties.district",
center={"lat": 45.5517, "lon": -73.7073},
mapbox_style="carto-positron", zoom=9)
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()
地理图(来源:作者)
us_cities = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/us-cities-top-1k.csv")
us_cities = us_cities.query("State in ['New York', 'Ohio']")import plotly.express as pxfig = px.line_mapbox(us_cities, lat="lat", lon="lon", color="State", zoom=3, height=300)fig.update_layout(mapbox_style="stamen-terrain", mapbox_zoom=4, mapbox_center_lat = 41,
margin={"r":0,"t":0,"l":0,"b":0})fig.show()
线条地图框(来源:作者)
fig = go.Figure(go.Scattermapbox(
mode = "markers+lines",
lon = [10, 20, 30],
lat = [10, 20,30],
marker = {'size': 10}))
fig.add_trace(go.Scattermapbox(
mode = "markers+lines",
lon = [-50, -60,40],
lat = [30, 10, -20],
marker = {'size': 10}))
fig.update_layout(
margin ={'l':0,'t':0,'b':0,'r':0},
mapbox = {
'center': {'lon': 10, 'lat': 10},
'style': "stamen-terrain",
'center': {'lon': -20, 'lat': -20},
'zoom': 1})
fig.show()
散点图框(来源:作者)
这就是你如何使用 plotly 创建不同的地理图。继续在不同的数据集上尝试,并让我知道您在回复部分的评论。
本文与 皮尤什英加尔 合作。
在你走之前
感谢 的阅读!如果您想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github简介针对不同的数据科学项目和包教程。还有,随意探索 我的简介 ,阅读我写过的与数据科学相关的不同文章。