使用 Label Studio 建立高内容放映影像平台
对于 HCS 来说,拥有一个注释图像数据的平台是必不可少的。在这里,我将演示如何从 Broad 注释 C Elegans 图像。
几年来,我一直在寻找一个我真正喜欢的工具,使用 web 界面来注释 HCS 图像。我用过几个工具,包括一个叫做 LabelImg 的桌面应用,我终于找到了一个检查所有叫做 LabelStudio 的盒子的工具!
Label Studio 是一个用于图像、音频和文本的注释工具。在这里,我们将专注于图像作为我们选择的媒介。
我在这个视频中讲述了这个过程。
获取数据
当然,您可以使用您自己的数据,但是对于本教程,我将使用来自Broad bio image Benchmark Collection的公开可用的 C. elegans 数据集。
mkdir data
cd data
wget https://data.broadinstitute.org/bbbc/BBBC010/BBBC010_v2_images.zip
unzip BBBC010_v2_images.zip
在系统查看器中打开时,HCS 图像通常非常暗。为了将它们用于管道的其余部分,我们必须进行两步转换过程,首先使用 bftools 从 tif - > png 转换,然后使用 Imagmagick 进行色阶校正。
cd .. # be in your project root here
# Use the bftools docker image and drop into a shell
mkdir data/tif
mkdir data/png
mkdir data/corrected-png
docker run -it -v $(pwd)/data:/home/bf/data openmicroscopy/bftools bash
cd /home/bf/data
find $(pwd) -name '*tif' | sed 's/\.tif//g' | xargs -I {} bfconvert -nogroup {}.tif {}.png
# ctrl+d to exit the container
现在,我们将使用 ImageMagick 来应用自动水平校正,以便我们可以看到我们正在标记的内容!
docker run -it --rm -v $(pwd)/data:/data \
continuumio/miniconda3 bash
# On the image
conda install -c conda-forge -y imagemagick
cd /data
find $(pwd) -name '*tif' | xargs -I {} basename {} | sed 's/\.tif//g' | xargs -I {} convert -auto-level /data/{}.png /data/{}-autolevel.png
mv *.tif tif/
mv *auto*.png corrected-png/
mv *.png png/
# Ctrl+D to exit
如果你像我一样,收集 docker 图片作为避免在你的电脑上安装东西的一种方式,你需要偶尔清理它们。
# This will remove ALL DOCKER containers from your system
# Use with caution!
docker container stop $(docker container ls -aq)
docker system prune -f -a
如果您需要清理图像,请移除data/png
和data/tif
文件夹。我们不会使用它们。
启动 LabelStudio
LabelStudio 基于项目工作,每个项目都包含任务。在这种情况下,任务是标记图像。因此,我们需要做的是将它指向一个图像目录,它将为我们配置项目。
不同的标签配置
LabelStudio 可以容纳几种不同的图像注释类型。了解更多信息的最佳途径是访问他们的模板页面,开始探索他们的游乐场。
我将假设您正在使用语义分割、多边形标记或包围盒。作为一个快速的免责声明,语义分割界面在我试用时有点小故障。在撰写本文时,它被标记为“新的”,正在积极开发中。也许当你读到这封信的时候,事情已经解决了。
这对我来说不是问题,因为我个人发现我可以使用多边形标注工具来勾勒形状,从而获得相同的功能。我还发现多边形工具更容易使用,一旦你有了多边形轮廓,你就可以把它转换成一个遮罩。
语义分割与包围盒
语义分割是指将图像中的每一个像素指定为你想要标记的东西。标注更加耗时,并且需要更多的计算资源来训练模型,但是精度会更高。
使用边界框来标记和开始使用要快得多,但是你会失去准确性,特别是当你有许多重叠的对象时。
下面的例子可以更好地解释这一点:
多边形标签
语义标签
边界框
初始化并启动脚本
抓住这个,命名为init-labelproject.sh
。
#!/usr/bin/env bash
# init-labelproject.sh
docker run --rm -it \
-e PORT=${PORT} \
-v $(pwd)/${TYPE}:/label-studio/${TYPE} \
-v $(pwd)/data:/label-studio/data \
-v $(pwd)/conf:/label-studio/conf \
--name label-studio-${TYPE} \
heartexlabs/label-studio:latest label-studio \
init ${TYPE} --force \
--port ${PORT} \
--input-path=/label-studio/data/corrected-png \
--label-config=/label-studio/conf/${TYPE}-config.xml \
--input-format=image-dir
抓住这个,命名为run-labelstudio.sh
。
#!/usr/bin/env bash
# run-labelstudio.sh
docker run --rm -it \
-p ${PORT}:${PORT} \
-e PORT=${PORT} \
-v $(pwd)/${TYPE}:/label-studio/${TYPE} \
-v $(pwd)/data:/label-studio/data \
-v $(pwd)/conf:/label-studio/conf \
--name label-studio-${TYPE} \
heartexlabs/label-studio:latest label-studio \
start ./${TYPE} --port ${PORT}
一旦你有了这些运行chmod 777 *sh
,让我们来标记一些蠕虫!
设置您的项目并启动 Web 界面
在下面找到您想要的配置,并启动 web 界面。
mkdir conf
# Make sure each of the xml files are in the conf dir!
cd conf
包围盒配置
抓住这个放在conf/object-config.xml
里。
<View style="display: flex">
<View style="width: 100px">
<Header value="Pick label" />
<RectangleLabels name="tag" toName="img">
<Label value="Alive" background="blue"></Label>
<Label value="Dead" background="orange"></Label>
</RectangleLabels>
</View>
<View>
<Image name="img" value="$image" showMousePos="true" zoom="true" zoomControl="true" />
</View>
</View>
多边形配置
抓住这个,把它放在conf/polygon-config.xml
。
<View style="display: flex">
<View style="width: 100px">
<Header value="Pick label" />
<PolygonLabels name="tag" toName="img" strokewidth="2" pointstyle="circle" pointsize="small" showInline="false">
<Label value="Alive" background="blue"></Label>
<Label value="Dead" background="orange"></Label>
</PolygonLabels>
</View>
<View>
<Image name="img" value="$image" showMousePos="true" zoom="true" zoomControl="true" />
</View>
</View>
语义配置
抓住这个放在conf/semantic-config.xml
里。
<View style="display: flex">
<View style="width: 100px">
<Header value="Pick label" />
<BrushLabels name="tag" toName="img">
<Label value="Alive" background="blue" />
<Label value="Dead" background="orange" />
</BrushLabels>
</View>
<View>
<Image name="img" value="$image" showMousePos="true" zoom="true" zoomControl="true" />
</View>
</View>
包围盒
要运行边界框界面,使用以下命令-
export TYPE="object"
export PORT="8080"
mkdir $TYPE
# you only need to run the init script once for setup
./init-labelproject.sh
./run-labelstudio.sh
并在浏览器中打开localhost:8080
。
多边形
要运行多边形界面,请使用以下命令-
export TYPE="polygon"
export PORT="8081"
mkdir $TYPE
# you only need to run the init script once for setup
./init-labelproject.sh
./run-labelstudio.sh
并在浏览器中打开localhost:8081
。
语义分割(画笔)
要运行语义界面,请使用以下命令-
export TYPE="semantic"
export PORT="8082"
mkdir $TYPE
# you only need to run the init script once for setup
./init-labelproject.sh
./run-labelstudio.sh
并在浏览器中打开localhost:8082
。
定制标签界面
LabelStudio 给了你很多对标签界面的控制。您也可以使用控制标签直接通过配置添加简单的表单。
我想要的是将图像标记为完整的能力,这意味着所有的蠕虫都被标记,或者无效以将其从训练中排除。我可以用下面的配置添加它。
<View>
<!-- Begin Display the image-->
<View style="padding: 25px;
box-shadow: 2px 2px 8px #AAA;">
<Image name="img" value="$image" showMousePos="true" zoom="true" zoomControl="true"/>
</View>
<!-- End Display the image-->
<!-- Begin display labels-->
<View style=" padding: 25px;
box-shadow: 2px 2px 8px #AAA;">
<View style="">
<Header value="Choose Phenotype"/>
<PolygonLabels name="tag" toName="img" strokewidth="2" pointstyle="circle" pointsize="small"
showInline="false">
<Label value="Alive" background="blue"></Label>
<Label value="Dead" background="orange"></Label>
</PolygonLabels>
</View>
<View style="">
<Header value="Check when the image is complete. If the image is not suitable for training choose invalid instead."/>
<Choices name="complete" toName="img" choice="single">
<Choice alias="complete" value="Complete"/>
<Choice alias="invalid" value="Invalid"/>
</Choices>
</View>
</View>
<!-- End display labels-->
</View>
为了得到你想要的精确布局,你可以在这上面多下功夫。宽度、高度和其他 CSS 变量都可以通过配置进行配置。确保重新启动服务器以查看您的新配置!
每个控件都有一个名称name
,它必须是唯一的,还有一个目的地toName
。
<Choices name="complete" toName="img" choice="single">
# ...
<Image name="img" value="$image"
# ...
<PolygonLabels name="tag" toName="img"
处理标签输出
每个输出都在您的project-dir/completions
中,在那个目录中,每个图像都有一个 json 文件。你会看到路径completions
,然后会有一个results
的数组。输出格式和具体规格可能会因您的配置而异,因此请务必使用您自己的配置进行验证。
以下是一个面标注输出示例。我已经添加了注释,它不再是有效的 json,所以不要试图解析它。;-)
{
## Corresponds to the name on the Polygon Control
"from_name": "tag",
## Randomly generated ID
"id": "bUgnJpbBgC",
## Height and Width of the Image
"original_height": 520,
"original_width": 696,
## Task Variable
"source": "$image",
## The to portion of the control
"to_name": "img",
## Control Type
"type": "polygonlabels",
"value": {
## Points of the polygon
## These can be read into a matplotlib.Path object for parsing
"points": [
[
71.25434944790884,
27.052753770458885
],
[
68.9321022931952,
28.148466100859682
],
... More labels
],
"polygonlabels": [
## ITS ALIVE!
## This is one of the phenotypes
## The phenotypes were either alive or dead
"Alive"
]
}
},
这是我们用完全/无效创建的“表单”的一个示例。
{
# This is the name from the control
"from_name": "complete",
"id": "PZru1lZMeo",
"to_name": "img",
"type": "choices",
"value": {
"choices": [
## This image as marked as invalid!
## Don't use it for training!
"invalid"
]
}
}
这是事情变得有趣的时候,因为现在您有了一个带有可解析输出的可配置接口,您可以开始为训练创建健壮的管道。
进一步的想法
当您旋转界面并开始标记时,您会看到 LabelStudio 将您的数据发送到{polygon,object,semantic}/completions/*.json
。这些只是数据文件,然后您可以使用它们为 Tensorflow、PyTorch 或 Keras 训练模型。
假设您使用的是 Tensorflow MaskRCNN 模型。您可以使用 LabelStudio 来标记您的图像,将 JSON 文件转换成一个 TFRecord ,并进行训练。然后你可以拿起你不完美的模型,让它标记一个图像集,然后手动清理新的图像,冲洗并重复。
如果你有任何问题,请不要犹豫与我在 jillian@dabbleofdevops.com 联系。
引文
登录号 BBBC010 第 1 版这一选择的图像是控制选择从一个屏幕上找到新的…
data.broadinstitute.org](https://data.broadinstitute.org/bbbc/BBBC010/)
“我们使用了由 Fred Ausubel 提供的秀丽隐杆线虫感染活/死图像集版本 1,可从 Broad bio image Benchmark Collection 获得[ Ljosa 等人, Nature Methods ,2012 ]。”
最初发表于【https://www.dabbleofdevops.com】。
设置版本增量和自动发布流程
我将向您展示发布过程和版本增量的自动化有多容易
我热衷于过程自动化,并且我坚信在开发阶段对过程自动化的时间和金钱投资是首要需求,无论项目持续多长时间。当您投资于流程自动化时,您将进一步大幅降低维护费用。
我认为 ML 文章中没有适当涉及的一个主题是发布过程自动化和项目版本增量。我不想在这个帖子中讨论可能的发布选项,这不是关于它的。在这里,我们将讨论如何设置 CI/CD 工具的发布流程(Bitbucket 管道、Gitlab 管道等)。)我认为可以肯定地说,在大多数情况下,release 是一个文件或一组文件,它们将以某种方式集成到客户端现有的解决方案中(无论它是一个包含 spring boot 应用程序的 jar 文件,一组用于模型训练和预测的 python 脚本,还是一个运行核心应用程序的 docker 映像)。问题陈述:我们希望管理产品版本,我们希望能够返回到具体的版本,以便能够测试和诊断生产中发生的问题。
版本控制
首先,让我们定义版本字符串中的数字是什么意思。
版本字符串
从语义版本定义(【https://semver.org/】T4)
给定一个版本号少校。MINOR . PATCH-pre _ release-label,递增:
- 主要版本当您做出不兼容的 API 更改时
- 以向后兼容的方式添加功能时的次要版本
- 补丁版本当你做向后兼容的 bug 修正。
预发布标签是版本的占位符,在发布前保留。
这是一个最佳实践定义,但是当然,您可以选择自己的版本化方案。所以根据这个定义,我们需要定义三个任务:
- 发布并增加主要版本
- 释放并增加次要版本
- 发布并增加补丁版本
下一步是定义除了 git 标记之外,如何在 GIT 历史中表示发布。有几种技术可以实现这一点,最流行的是分离发布分支或分离提交。在本帖中,我们将讨论分离提交,因为它更容易自动化(不需要合并)。
分离提交
让我们从理论开始。分离提交不属于任何分支,只能直接指向。在不知道提交散列的情况下,如何在 git 历史中搜索它?你只需要给它分配一个 git 标签。然后,您可以在任何 VCS UI 中通过标签过滤 git 历史。
版本文件
不知何故,你必须保持实际的版本字符串。最简单的方法是将它保存在存储库根目录下的文本文件中。版本文件的策略:
- 不能手动更改文件内容
- 它不能在特征分支中改变(最佳实践是创建一个流水线步骤,它与主步骤进行比较)
- 文件仅在发布后更改,并自动直接提交到主分支。
设置 CI/CD 管道
对于您的 CI/CD 管道文件,您必须添加三个定制/手动步骤/作业,它们将执行 release 和适当的增量。并选择性地添加步骤/作业,该步骤/作业仅在功能分支上运行,并检查版本文件是否根据主文件进行了更改。
Bash 脚本检查版本文件是否相对于主文件发生了更改:
git diff --exit-code VERSION
现在是最有趣的部分:
- 我们必须创建一个脚本来管理版本文件的功能:获得版本,获得版本与占位符,增加版本主要/次要/补丁
- 我们必须定义发布分支限制策略(发布只能在主分支上进行)并创建分离的提交推送流。
- 定义 CI/CD 释放步骤(这里我们将为 Bitbucket 管道和 Gitlab 管道定义它)
我讨厌写 bash 脚本。我只使用 bash 来定义高级步骤并从中运行 python 脚本,因为我坚信 bash 脚本具有难看的符号,对于经验较少的 Linux 用户来说不可读,并且从长期角度来看不可维护。fire
库可以帮助你轻松编写好的 CLI-runnable python 脚本。查看我之前的帖子:
将机器学习应用程序包装到命令行界面的简单示例
towardsdatascience.com](/a-simple-way-to-create-python-cli-app-1a4492c164b6)
版本文件管理脚本(没什么有趣的讨论,只是文件写操作):
#!/usr/bin/env python
import os
import re
import fire
pre_release_placeholder = 'SNAPSHOT'
version_filepath = os.path.join('.', 'VERSION')
version_pattern = re.compile(fr'^\d+.\d+.\d+(-{pre_release_placeholder})?$')
def get(with_pre_release_placeholder: bool = False):
with open(version_filepath, 'r') as version_file:
version_lines = version_file.readlines()
assert len(version_lines) == 1, 'Version file is malformed'
version = version_lines[0]
assert version_pattern.match(version), 'Version string is malformed'
if with_pre_release_placeholder:
return version
else:
return version.replace(f'-{pre_release_placeholder}', '')
def write_version_file(major: int, minor: int, patch: int):
version = f'{major}.{minor}.{patch}-{pre_release_placeholder}'
with open(version_filepath, 'w') as version_file:
version_file.write(version)
def inc_patch():
version = get()
major, minor, patch = version.split('.')
write_version_file(major, minor, int(patch) + 1)
def inc_minor():
version = get()
major, minor, patch = version.split('.')
write_version_file(major, int(minor) + 1, patch)
def inc_major():
version = get()
major, minor, patch = version.split('.')
write_version_file(int(major) + 1, minor, patch)
if __name__ == "__main__":
fire.Fire({
'get': get,
'inc-patch': inc_patch,
'inc-minor': inc_minor,
'inc-major': inc_major
})
现在让我们开发发布脚本。首先,我们必须检查发布脚本是否运行在正确的分支上:
# Bitbucket
commit=${BITBUCKET_COMMIT:-$(git rev-parse HEAD)}# Gitlab
commit=${CI_COMMIT_SHA:-$(git rev-parse HEAD)}# Define ALLOWED_RELEASE_BRANCH in VCS pipelines secret variables.
branch=${ALLOWED_RELEASE_BRANCH:-master}
if ! git branch -a --contains "${commit}" | grep -e "^[* ]*remotes/origin/${branch}\$"
then
echo -e "###\n### Not on ${branch}. Only ${branch} commits can be released.\n###"
exit 1
else
echo -e "###\n### Releasing of ${commit} on ${branch}\n###"
fi
然后你必须写一些释放的东西,如:发布 docker 图像或复制到 S3 水桶或任何你需要的。不要忘记使用正确的版本文件:
version=$(./scripts/version.py get)
version_file=VERSIONecho ${version} > ${version_file}
然后,我们必须在之前的步骤版本文件中使用 modified 推送一个分离的提交:
# Define some cool release pusher to ditinguish from amnual commits :)
git config user.name "Elon Musk"
git config user.email "elon.musk@spacex.com"
echo "Pushing detached tag of new version"
git add ${version_file}
git commit -m "Release version ${version}"
git tag -a ${version} -m "Release version ${version} tag"
git push origin ${version}
取回主分支并使用预发布占位符增加版本:
echo "Pushing new version to ${branch}"
git fetch origin "${branch}:${branch}" || git pull
git checkout "${branch}"# Parameter of the script
release_type=${1}
./scripts/version.py inc-${release_type}
next_working_version=$(./scripts/version.py get --with-pre-release-placeholder)
git add ${version_file}
git commit -m "Incrementing working version to ${next_working_version} after ${version} release."
git push origin ${branch}
仅此而已。我们已经创建了一个干净的发布脚本。现在让我们开发 Bitbucket 和 Gitlab 管道步骤片段。
比特桶:
image:
name: python:3.7.6-slim-buster
pipelines:
default:
- step:
- name: Test version file not changed
- script:
- git diff --exit-code VERSION
custom:
release-inc-patch:
- step:
caches:
- pip
name: Release current version and increment patch version
script:
- apt-get update && apt-get install -y git
- pip install fire==0.2.1
- ./scripts/release.sh patch
release-inc-minor:
- step:
caches:
- pip
name: Release current version and increment minor version
script:
- apt-get update && apt-get install -y git
- pip install fire==0.2.1
- ./scripts/release.sh minor
release-inc-major:
- step:
caches:
- pip
name: Release current version and increment major version
script:
- apt-get update && apt-get install -y git
- pip install fire==0.2.1
- ./scripts/release.sh major
运行自定义管道步骤:https://confluence . atlassian . com/bit bucket/run-pipelines-manually-861242583 . html
Gitlab :
test-version-changed:
stage: test
name: Test version file not changed
script:
- git diff --exit-code VERSION
release-inc-patch:
stage: deploy
image: python:3.7.6-slim-buster
caches:
- pip
name: Release current version and increment patch version
script:
- apt-get update && apt-get install -y git
- pip install fire==0.2.1
- ./scripts/release.sh patch
when: manual
only:
- master
release-inc-minor:
stage: deploy
image: python:3.7.6-slim-buster
caches:
- pip
name: Release current version and increment minor version
script:
- apt-get update && apt-get install -y git
- pip install fire==0.2.1
- ./scripts/release.sh minor
when: manual
only:
- master
release-inc-major:
stage: deploy
image: python:3.7.6-slim-buster
caches:
- pip
name: Release current version and increment major version
script:
- apt-get update && apt-get install -y git
- pip install fire==0.2.1
- ./scripts/release.sh major
when: manual
only:
- master
运行手动作业:https://forum . git lab . com/t/git lab-ci-run-pipeline-manually/13797
就是这样!你能在我的 GitHub 上找到的所有资源:【https://github.com/mbalatsko/release-version-increment】
我希望这篇文章将是有用的和信息丰富的。期待您的反馈!
在 Visual Studio 代码中设置 Vue.js Hello World
在 Vue.js 中快速启动 Hello World 应用程序
在 Unsplash 上由 Austin Distel 拍摄的照片
目标
在设置好本地开发环境之后,启动一个简单的 Vue 应用程序。
这些是您将在本教程中安装的工具:
- Visual Studio 代码(VS 代码):这当然不是创建 Vue 应用程序的要求,但它是我推荐的文本编辑器。我相信它使软件开发变得更加愉快和高效。
- Git Bash : Git 是一个非常流行的管理源代码的工具,尤其是当你在一个大型开发团队中工作的时候。VS 代码允许您集成 Git Bash 终端,这使得将您的代码推送到 Git 存储库非常方便。此外,它允许您在模拟 Bash 环境时使用大多数标准的 UNIX 命令。
- JavaScript 运行时环境
- npm:节点包管理器。这与 Node.js 一起使用,以便我们可以轻松地共享打包的代码模块。
下载 VS 代码
从 Visual Studio 代码下载稳定版本。
这是一个非常简单的下载。微软在简化这个应用程序的安装过程方面做得很好。
在 VS 代码中使用 Git Bash
从 https://git-scm.com/downloads 的下载适用于您特定操作系统的 Git Bash。
当你点击 Git 安装程序时,我建议使用所有默认的安装设置,除非你真的知道你在做什么。
我们现在将 Git Bash 作为一个集成终端添加到 VSCode 中。
- 在 VS 代码中打开一个新的终端(Ctrl + Shift +`)或者终端→新终端。
- 打开命令选项板(Ctrl + Shift + P)或视图→命令选项板。
- 键入“终端:选择默认外壳”。
- 您应该会看到下面的选项:
- 选择 Git Bash。
- 在终端窗口中选择+按钮。
您应该会看到类似这样的内容。
检查点 : 输入下面的命令,确保已经正确安装了 Git。
git --version
根据您安装的版本,这应该会出现。
安装 Node.js
去这个链接下载: Node.js 。
我选择了“推荐给大多数用户”选项,然后使用 Node.js 设置中的所有默认设置。
检查点:安装完成后,在命令行中输入:
node -v && npm -v
它应该是这样的(你的版本可能比我的更新):
如果您成功安装了 Node 和 npm,请跳到下一节。
如果它没有出现在你的 Git Bash 中,不要烦恼!重新启动计算机。
如果这不起作用,请在 PowerShell 中键入相同的命令,或者只在 Windows 命令行中键入,您应该会在那里看到它。
要使用 Git Bash,您需要将它添加到您的路径中。该路径告诉您的操作系统在哪里寻找可执行文件,以响应来自用户的命令。下面是在 Windows 上如何做到这一点:
- 打开“查看高级系统设置”。
- 单击“环境变量”。
- 在系统变量下,选择路径,然后选择编辑按钮。
- 添加这个 C:\Program Files\nodejs\。
- 如果上述文件路径不正确,您可以通过在 Windows 命令行中键入以下命令来轻松找到它:
where node
- 在检索到节点目录的正确路径并将其添加到 path 系统变量后,选择“确定”。
- 重新启动计算机。
检查点:现在,尝试在 Git Bash 中键入以下命令:
node -v && npm -v
安装 Vue
在命令行中键入以下命令。
npm i -g @vue/cli
完成后,我们将创建我们的项目:
vue create hello-world
我选择了预设
接下来,将目录切换到新项目中,并启动它!
cd hello-world && npm run serve
导航到 localhost:8080,您应该会看到类似这样的内容:
就是这样!我们做到了。
回顾
您已经安装了以下工具,可以开始创建 Vue.js 应用程序。
- 虚拟代码
- 饭桶狂欢
- 节点. js
- npm
- Vue CLI
恭喜你。
赖安·格里森的更多故事
[## Node.js 与 Spring Boot——你该选择哪一个?
轻松点。Spring Boot。对吗?没那么快…
medium.com](https://medium.com/better-programming/node-js-vs-spring-boot-which-should-you-choose-2366c2f76587) [## 是时候忘记反应,加入苗条的潮流了吗?
一场真正的泰坦之战(苗条还能算泰坦吗?)
medium.com](https://medium.com/better-programming/is-it-time-we-forget-react-and-jump-on-the-svelte-bandwagon-4848bb5d0839) [## 我如何使用 AWS Lambda 让我的女朋友微笑
开始这个有趣的小项目来提升你周围人的精神
towardsdatascience.com](/how-i-used-aws-lambda-to-make-my-girlfriend-smile-61194596f2d)
在树莓派上设置您的家庭 JupyterHub
从家中的任何设备启动笔记本。一个家庭中心。
作为一名数据科学家,我每天都使用 Jupyter 笔记本。有时在本地我的笔记本上,有时通过 JupyterHub 在服务器上。但是为什么不把两者结合起来,在树莓派上运行 JupyterHub 呢?这样,家庭中的每个人都可以通过浏览器从每台设备启动笔记本电脑。数据总是留在家里,随着 Raspberry Pis 变得越来越强大,我们实际上可以在它上面进行真正的数据科学。
我平板电脑上的一点机器学习。旁边:树莓派和咖啡。
目录
- 准备 Python 环境
- 安装 JupyterHub
- 设置为系统服务
- 使用 JupyterLab
- 安装 Python 库
- 用户管理
准备 Python 环境
有许多文章描述了如何设置 JupyterHub,但是大多数都使用了 Anaconda。不幸的是,Anaconda 不支持像 Raspberry Pi 和 Miniconda 这样的 ARM 系统,而这两个系统通常被认为是一种替代方案,显然没有得到进一步的维护。所以让我们和皮普一起去。
我做错什么了吗?当我在新安装的 Raspbian Buster 中输入“python”时,它打开了“python2”。真的吗?不是 2020 年吗?所以让我们快速地将系统重定向到 python3:
sudo rm /usr/bin/python
sudo ln -s /usr/bin/python3 /usr/bin/python
并安装 python 包管理器 pip:
sudo apt-get update
sudo apt-get install python3-pip
sudo pip3 install --upgrade pip
安装 JupyterHub
JupyterHub 由三个组件组成:
- 一个单用户笔记本服务器,当系统上的每个用户登录时启动。这基本上就是你已经安装在笔记本电脑上的东西,从
jupyter notebook
开始。 - 管理用户账户、认证和协调单用户笔记本服务器的中枢。
- 一个代理,它将用户请求路由到集线器和笔记本服务器。
相应地,我们需要安装这三个组件。让我们从代理开始:
sudo apt-get install npm
sudo npm install -g configurable-http-proxy
现在,我们可以使用 pip 安装 JupyterHub 和 Jupyter Notebook。因为我们想让多个用户使用 JupyterHub,所以我们需要确保安装是系统范围的:
sudo -H pip3 install notebook jupyterhub
JupyterHub 是使用 python 脚本配置的。您可以使用以下命令生成模板。然后,将其移动到主目录之外的位置:
jupyterhub --generate-config
sudo mv jupyterhub_config.py /root
在下面的步骤中,当我们在配置文件中进行更改时,我们需要修改这个文件/root/jupyterhub_config.py
。由于它位于/root
,我们需要使用 sudo。
例如,默认情况下,JupyterHub 运行在端口 8000 上。可能我们已经在使用这个端口了,所以我们把它改成 8888 吧。为此,取消配置文件中以下语句的注释,并调整端口:
c.JupyterHub.bind_url = 'http://:8888'
设置为系统服务
我们的 JupyterHub 已经准备好了。我们可以从jupyterhub -f /root/jupyterhub_config.py &
开始(其中-f
指向我们刚刚创建的配置文件)。但是,集线器只能存活到下一次系统重启。第一次尝试还好,但是如果我们经常使用它,当然最好将 JupyterHub 设置为系统服务,这样它会在系统启动时自动启动。
要将 JupyterHub 注册为系统服务,创建文件/lib/systemd/system/jupyterhub.service
,并用以下内容填充它:
[Unit]
Description=JupyterHub Service
After=multi-user.target [Service]
User=root
ExecStart=/usr/local/bin/jupyterhub --config=/root/jupyterhub_config.py
Restart=on-failure [Install]
WantedBy=multi-user.target
确保以ExecStart
开头的行包含 JupyterHub 二进制文件和配置文件的正确位置,或者进行相应的调整。
然后,运行以下命令:
sudo systemctl daemon-reload
sudo systemctl start jupyterhub
sudo systemctl enable jupyterhub
sudo systemctl status jupyterhub.service
JupyterHub 将在系统启动时启动。最后一个命令显示了状态,希望是“active (running)”。
如果是这种情况,请前往http://<address of your raspi>:8888
。您应该会看到 JupyterHub 的登录页面。Raspberry Pi 的每个系统用户现在都可以登录并启动他们自己的笔记本服务器!
使用 JupyterLab
JupyterLab 是 Jupyter 项目的下一代基于网络的用户界面。它允许您以非常灵活的方式处理文档和笔记本。如果你还不相信:它甚至有一个黑暗模式…
要使用 JupyterLab 而不是传统的笔记本,我们首先必须使用 pip 安装它,然后启用扩展(使用 sudo 在系统范围内完成):
sudo -H pip3 install jupyterlab
sudo jupyter serverextension enable --py jupyterlab --system
现在,我们必须在配置文件中添加(或取消注释并调整相应的行)以下内容:
c.Spawner.default_url = '/user/:username/lab'
安装 Python 库
为了进行实际的数据科学,我们当然需要比 python 标准库更多的东西。我们基本上有两种可能性:我们可以在系统范围内安装它们。或者,每个用户都可以将它们安装在自己的主目录中。
一个合理的方法是在系统范围内安装最常用的包,让用户自己安装其他的包。下面是如何在系统范围内安装 numpy 的一个例子。要使 numpy 工作,您还必须安装以下系统软件包:
sudo apt-get install libatlas-base-dev
sudo -H pip3 install numpy
没有 sudo 权限的用户可以在他们的主目录中安装软件包,例如:
pip3 install seaborn
您实际上可以从 JupyterLab 中打开一个终端,因此没有必要为“普通”用户设置 ssh 连接。只需转到启动窗口,打开一个终端。
首先打开启动窗口。从那里,您可以打开一个新的笔记本或终端。
用户管理
在我们当前的设置中,用户由操作系统管理。这意味着每一个 Raspberry Pi 的用户也可以启动他们自己的笔记本服务器。
管理员有额外的权利。例如,他们可以访问管理面板,在那里他们可以看到哪些用户登录,并启动和停止他们的服务器。管理员权限通过组来处理。例如,如果我们想指定用户“gerold”为 admin,我们将首先创建一个组(我们也可以使用一个预先存在的组)并将用户添加到其中。这在 Unix 系统中通常是这样做的:
sudo addgroup jupyter_admin
sudo usermod -aG jupyter_admin gerold
然后,我们需要在配置文件中将该组添加为 admin-group:
c.PAMAuthenticator.admin_groups = {'jupyter_admin'}
可以在http://<address of your raspi>:8888/hub/admin
下找到管理面板。
JupyterHub 管理面板。
参考
设置您自己的深度学习沙盒:快速指南
如何使用 Google Cloud、Jupyter 和 Visual Studio 代码轻松设置一个强大的深度学习沙盒,并将成本控制在每月几美元(第一笔 300 美元在 Google 上)。
像许多数据科学爱好者一样,我投身于这一领域,利用每一分钟的空闲时间学习 DS 生态系统——即 Python、Jupyter、NumPy、Pandas、Scikit-learn、Matplotlib 和少量 Seaborn。以及所有强大的 Unix 工具——VI、less、sort、cut、grep、cat、tail、head 等。–您拥有一个极其高效的框架来获取、清理和分析数据集、设计功能、运行回归模型以及构建专业视觉效果。然而,一旦你的好奇心(或工作)将你拉向“机器学习”世界的“深度学习”一端,你会很快发现——就像我一样——即使是高端的 Macbook Pro 也没有足够的肌肉来运行哪怕是最基本的卷积神经网络模型(简称 CNN)。通过学习杰瑞米·霍华德和瑞秋·托马斯的 fast.ai 课程,我很快就明白了这一点。如果您像我一样,并且您的数据科学培训资金来自您自己的口袋,那么我有一个便宜、简单但功能强大的解决方案供您使用。
首先,我承认我喜欢在我的笔记本电脑上运行所有我能运行的东西。然而,对于一些事情,我的笔记本电脑就是不行,例如,对于我的音乐创作爱好,我在我的地下室有一个增强的英特尔 i7 盒子,它运行一个音乐库服务器。但是对于训练 DL 模型来说,i7 和大量内存对你来说没什么用。你需要 GPU。而 GPU 又很贵。但是租起来不贵。有了现在市面上可以买到的云选项自助表,我的新 MO 就变成了, 不买,租 。
通过谷歌搜索和反复试验,我建立了一个基于 Jupyter 的客户端-服务器沙箱,使用我的 Macbook Pro 和 Visual Studio 代码作为客户端,Jupyter 服务器运行在谷歌云上的高端 Linux 实例上。结果呢?我的 DL 模型训练现在可以在几秒钟内完成。在我的 Macbook Pro 上?嗯,运行 30 分钟后,风扇不停地运转,我结束了这个过程。你明白了吗?
注: 这种方式在 Google cloud 中使用完整的 Linux 服务器。还有其他成本更低的途径,例如 Google Colab 和 Kaggle 内核。然而,通过这种方法,你获得了配置的灵活性,300 美元的信用(如果节省使用将持续一段时间),以及一些使用 Google 云平台和命令行界面的经验。
安装服务器
创建 GCP 帐户并获得 300 美元
第一步是在谷歌云平台(GCP)上创建一个账户。我将假设你已经明白了这一点,并登录到 GCP 控制台。接下来,检查以确保您获得了 300 美元的信用。在左上角点击菜单,选择计费→T5总览。在概览的右下角,您应该会看到促销积分余额。应该是 300 美元。**
创建您的虚拟机服务器
GCP 现在有一项专门为运行 Jupyter 笔记本电脑配置虚拟机服务器的服务。点击 GCP 菜单(左上角)并向下滚动到人工智能部分。然后选择 AI 平台→笔记本。
从笔记本实例屏幕选择顶部的新实例。这个菜单有许多选项,包括一些测试和实验选择。我会选择 PyTorch 1.4 和一个 NVIDIA Tesla T4 GPU。
下一个屏幕显示选项。在这个练习中,我将使用默认值。自定义按钮允许您向引导驱动器添加更多磁盘空间,添加 GPUs RAM 等。默认费用为每小时 0.382 美元。Google E2 实例在使用一分钟后按秒计费。这个默认配置每小时运行 38.2 美分。那是 785 小时的免费使用。
一旦你点击 Create, Google 将花费几分钟来配置你的虚拟机实例。完成后,您将看到如下屏幕。
现在,您拥有了一个功能齐全的 Jupyter 笔记本,它具有强大的 GPU 来支持 DL 模型构建。点击实例名称旁边的打开 JUPYTERLAB 。您的浏览器中将会打开一个新标签页,并打开一个 Jupyter 笔记本。界面非常简单。您可以浏览文件系统、创建 Git 存储库或启动终端会话。
在这个阶段,你已经有了一个功能齐全、功能强大的 DL 沙箱。然而,这不是一种经济有效的工作方式。您的新虚拟机实例每秒钟都在消耗您运行该实例的 300 美元。我更喜欢在我的 macbook 上本地完成我所有的数据收集、特征工程和初始回归工作。然后,当我清理和准备好我的数据集,并且我正处于尝试和适应 DL 模型的阶段时,我启动我的虚拟机实例,连接,运行我的模型,获得我的结果,然后关闭实例。为了有效地执行这个工作流,我现在将介绍几个步骤。
停止并启动您的虚拟机实例(在继续之前执行此步骤)
返回笔记本控制台并关闭您的实例。
T ip: 转到账单部分,在 预算&提醒 下创建一个预算,当你达到 1 美元的使用量时,它会向你发送电子邮件。
为远程 HTTP/HTTPS 访问配置虚拟机实例
要打开对 VM 实例的远程访问,您需要做两件事。
第一步。打开对虚拟机实例的 HTTP 访问。从主控制台菜单中的计算部分,选择计算引擎→虚拟机实例。
然后从列表中单击您的实例。将显示您的实例的详细信息。我们需要在这里做两个改变。点击顶部的编辑,向下滚动并选中防火墙部分的两个 HTTP 框,然后滚动到底部并点击保存。
第二步。遵循下面的菜单,然后单击防火墙控制台顶部的创建防火墙规则。
在以下两个屏幕中输入注释字段。
您的防火墙规则现在应该处于活动状态。如果不是,您将在接下来的步骤中知道。
**第三步。**停止您的虚拟机实例。返回笔记本控制台,点击实例旁边的复选框,并点击停止。
使用 Google Cloud SDK 管理虚拟机实例
**步骤一。**第一步是在你的本地计算机上安装 SDK。下面是谷歌为 MacOS、Windows 和 Linux 下载和安装 SDK 的说明。确保您遵循所有步骤,包括将 SDK 放在您的路径中。
第二步。从终端运行以下命令,初始化 SDK。
> gcloud init
...> You must log in to continue. Would you like to log in (Y/n)?
系统将提示您登录。当您按下 Y 和 回车键 时,您将被重定向到一个谷歌网站以登录您的帐户。成功登录后,您应该会返回到终端会话,系统会提示您选择一个计算区域。
> Do you want to configure a default Compute Region and Zone? (Y/n)?
选择 Y 。在前面的一个屏幕截图中,我建议记下您的实例名和创建它的地区。在列表中找到显示的区域,并输入其索引号。完成后,运行以下命令。
> gcloud config list
您应该会在终端窗口中看到如下内容。
第三步。在我们离开虚拟机实例之前,我们将其关闭。现在让我们使用 SDK 重新启动它。下面是命令。用实例名替换实例名。
> gcloud compute instances start **inst_name**
现在让我们练习停止实例。下面是命令。
> gcloud compute instances stop **inst_name**
这可能需要几分钟,所以让它运行吧。在小旋转完成后,你应该得到这个结果。
一旦你看到 …done 然后再次启动你的实例,让我们继续。
**第四步。**连接到实例并完成服务器端设置的时间。输入以下命令并用您的实例替换 inst_name 。
> gcloud compute ssh **inst_name**
系统将提示您输入密码。这是您最初创建的帐户密码。接下来,您将看到如下屏幕。
好了,我们快到了。只需对 Jupyter 进行一些配置更改,然后我们将能够连接 Visual Studio 代码并运行模型。耶!😎
配置 Jupyter 笔记本服务器
**第一步。**为笔记本创建文件夹。这是 Jupyter 存储笔记本文件的地方。我还建议创建两个子文件夹,当我们运行下面的示例模型时,它们的用途就变得很清楚了。
> mkdir jnotebooks
> mkdir jnotebooks/data
> mkdir jnotebooks/pics
第二步。创建 Jupyter 配置。这就产生了一个。jupyter 文件夹下你的根目录。
> jupyter notebook --generate-config
现在是一个有点棘手的部分。我们需要在文件中配置一些 Jupyter 参数。jupyter/jupyter _ notebook _ config . py。我推荐使用 vim 。在编辑文件之前,通过执行 pwd 记下你的根路径。这是参数。所有这些参数都已经在文件中。但是,它们被注释掉了。它们需要取消注释和修改。
c.NotebookApp.ip = '*'
c.NotebookApp.port = 8888
c.NotebookApp.notebook_dir = '/home/username/jnotebooks'
c.NotebookApp.open_browser = False
记得我们创建了 jnotebooks 文件夹。输入 notebook_dir 参数的完整路径。
这里有一个简短的你需要的命令清单。
**第三步。**设置一个 Jupyter 密码。这是可选的,但是强烈推荐,因为我们刚刚打开了 HTTP 访问。从命令行输入以下内容,然后输入您的密码。你必须在每次从 VSC 访问这个服务器时输入这个,所以我建议不要在这里走极端。
> jupyter notebook password
第四步。这里是最后一步。让我们启动 Jupyter 笔记本服务器。下面是命令。
> jupyter-notebook
还有哒哒!您应该会看到如下所示的内容。
如果你的屏幕与此不太相似,那么按下 Control-c 终止这个过程,并返回检查 Jupyter 配置文件中的四个参数。
安装客户端
我是 Visual Studio 代码的忠实粉丝。微软在一段时间前开源了它,从那以后它迅速发展成为一个非常用户友好和功能强大的编辑器。我觉得很酷的是,它现在完全支持 Jupyter 笔记本。我个人不喜欢在工作模式下用浏览器运行笔记本。我更喜欢我用于 Python 和 Java 的真正的代码编辑器**(希望 Swift 很快会得到支持)**。在 VSC,我可以在笔记本上建立我的模型,然后轻松地导出到 Python 文件中,开始将我的项目生产化,所有这些都在同一个编辑器中完成。闲话少说。让我们连接到我们的服务器并训练一个模型。
第一步。安装和设置 Visual Studio 代码。如果您使用的是 Anaconda 发行版,那么您就万事俱备了。蟒蛇和 VSC 合作得很好。否则,单击此处的获取您的操作系统的最新版本。VSC 本机支持 Jupyter,所以没有什么额外的需要安装。
**第二步。**打开 VSC,创建一个新的 Jupyter 笔记本。最简单的方法是使用命令浏览器。在 MacOS 上命令是 shift+command+p 。然后输入Python: Create New Blank Jupyter Notebook
第三步。连接到您的服务器。当你启动你的服务器时,你记下你的外部 IP 地址了吗?你在这里会需要它。再次通过 shift+command+p. 进入命令浏览器,然后输入命令Python: Specify local or remote Jupyter server for connections
你接下来会看到这个。选择现有的。
这里是您需要虚拟机实例的外部 IP 地址的地方。
在上面输入你的 http 地址并按下回车键后,VSC 有可能需要重启。如果发生这种情况,则关闭 VSC,再次启动它,然后按照此步骤 3 返回至此。键入一些测试 Python 代码并执行单元。VSC 将代码发送到服务器,并显示返回的结果。然后你会在右上角看到你的 Jupyter 服务器地址,如下图所示。
成功了!现在是时候享受真正的乐趣了!
有趣的时间——训练一个 DL 模型
我相信每个数据科学黑客、程序员和专业人士都熟悉 Kaggle 的庞大数据集。这就像数据科学的“你好世界”。我也摆弄过这个数据集。我只是运用了基本的推理,比如“假设所有的人都会死”。只用几行代码就能得到一个普通的分数。为了好玩,我做了很多特性工程,然后应用了所有的 Scikit-learn 模型和 Xgboost。然后,为了真正的乐趣,我想我会应用一个 DL 模型。我的型号在 Github 上有。我建议跟随查看工作流程。
第一步。从 Github 这里获取模型。
第二步。将 VSC 切换到本地 Python 实例。 shift+command+p 后跟Python: Specify local or remote Jupyter server for connections
然后从菜单中选择默认。这将强制重新加载 VSC (希望这种重新加载的需求在未来会消失)。
第三步。在 VSC 打开文件titanic _ feature _ creation . ipynb,执行每个单元格。最后一个单元格将把文件titanic _ train _ wrangled . CSV和titanic _ test _ wrangled . CSV写出到名为 data 的子文件夹中。这两个文件必须复制到您的虚拟机实例中。
**步骤四。**将数据文件复制到虚拟机实例。在从 Github 获取的 titanic 文件夹中,执行以下命令。用实例名替换 inst_name 。
> gcloud compute scp ./data/*.csv **inst_name**:~/jnotebooks/data/
第五步。将 VSC 连接到您的服务器。sshift+command+p后跟Python: Specify local or remote Jupyter server for connections
然后从菜单中选择您的服务器。这将迫使 VSC 重装上阵。
第六步。打开文件titanic _ model _ evaluation _ CNN . ipynb。请注意,在第一个单元格中,读取的数据文件。您在本地创建了它们,然后将它们转移到您的 VM 实例。
**第七步。**执行所有单元格,生成一个 submission.csv 文件。
注意事项
*免责声明:*标题为**的单元格将特征转换为方形 PNG,**只是将两个数据文件的每一行(或记录)转换为图像的一种简单方法。有许多更好的方法来翻译 DL 模型的数据。在这次演示中,我想保持最基本的简单。所有创建的图像都存储在服务器上名为 images_titanic 的子文件夹中。
看看我们的排名吧!
**步骤 1。**现在让我们检索在下面显示的最后一个单元格中创建的文件 submissions.csv 。
下面是命令。再次用实例名替换 inst_name。
> gcloud compute scp **inst_name**:~/jnotebooks/data/submission.csv .
**第二步。**访问 Kaggle 的泰坦尼克号网站在这里提交你的作品。
我们表现如何?
78%没问题。还不错。然而,如果你是一个真正的 DS 实践者,你会对此一笑置之。这是过度工程化的一个极端例子。但这不是最佳深度学习模型工程中的一项练习。这都是关于如何建立一个沙箱,这样你然后就可以专注于构建最佳模型。
最后一件事。
让我成为更好的数据分析师的七本有趣的书
数字中有幽默,利用它
由 Unsplash 上的 CHUTTERSNAP 拍摄,作者编辑
正如历史学家尤瓦尔·诺亚·哈拉里所说,电视剧《黑镜》比杰弗里·辛顿的图灵奖获奖论文更接近公众。
上周,我向我的老板做了一个关于工厂(秘密)的一些关键见解的短小精悍的演示,他在分析领域没有经验,但在规划如何运营工厂方面有经验。
他的表情告诉我“我百分之百在听,这个曲线非常有意义,这个演示一点也不无聊”。
事实证明,分析领域不仅仅是真正擅长数学和理解数据。对于数据分析师来说,将结果归纳给非数据科学专家是很重要的,这可以让有决策权的人使用这些见解。
关于那次演讲的结构和基调的许多想法来自于我在过去几年里读过的书,这些书使得数据的许多观点更容易理解。
因此,这里有一些数据科学方面的教育和娱乐书籍,会逗得每一位分析师发笑。(订单不代表任何东西)
1.如何不犯错
乔丹·艾伦伯格
与这份名单上的其他书籍相比,《如何不犯错》讲述了许多日常生活统计数据中隐藏的数学,有时还附有合理的数学公式和定理。
政治、制造恐惧的电视和“科学杂志”起初看起来是正确的,但实际上只是愚弄你的工具。
它详细讲述了概率和可能性的各种测量方法,比较术语,统计解释中的各种偏差,大数定律,以及从各种现实生活场景中带回的数字的意义。
2.被随机性愚弄
纳西姆·尼古拉斯·塔勒布
这是一本相对难读的书,除非你想在股市上赚很多钱。纳西姆·塔勒布让你和市场上的其他人意识到他们真的很愚蠢,预测股市是傻瓜的努力。
他傲慢而又滑稽地揭示了日常世界是如何充满随机性的,以及你能真正确定的事情是多么少。塔勒布列举了大量依赖随机性失败的例子,以及一个成功的预测可能是多么微不足道,他成功地让你相信,先生,你是一个白痴。
由 Unsplash 上的 Cathal Mac an Bheatha 拍摄,作者编辑
3.真实性
作者汉斯·罗斯林
真实是一个以此为毕生事业的人的计划。汉斯·罗斯林临终时写的。这是他离开这个星球前选择做的最后一件事。
它将矛头指向所有制造恐惧的新闻频道和制造仇恨的政治,并通过显示数字证明他们是错误的,这些数字实际上表明我们作为一个星球和物种做得相当好。
有希望。事实上,不仅有希望,还有无数值得庆祝的理由。你将在这里学习如何向统计数据的观众展示完整的画面,这样人们就可以决定对发生的事情是高兴还是悲伤。在全球范围内,什么是“好”并不那么明显。
4.快速思考和慢速思考
丹尼尔·卡内曼
《思考的快与慢》是一本关于认知偏见的杰出著作,作者是诺贝尔经济学奖得主丹尼尔·卡内曼。
作为一名分析师,光知道数字是不够的,还要知道你的客户在所有选项中会选择什么,因此如何包装信息而不仅仅是报告它。
它告诉了我们作为灵长类动物的很多情感倾向,这明显超过了我们的逻辑半脑。如果这能给你一些安慰的话,你会在下一次做出不合逻辑的选择时明白,你是由进化决定这样做的,如果你足够聪明,你可能会做出不同的选择。
5.每个人都会撒谎
塞斯·史蒂文斯·达维多维茨
当人们在看和不看的时候,我们的行为是不同的。这本书的基调是直截了当的“吐槽你的饮料好笑!”。仅仅从大卫·多维茨选择写的主题来看,比如人们在谷歌上输入的非常诚实的问题。
这可能会强化一些刻板印象,比如男性还是女性更有兴趣口头取悦异性(嗯,如果你知道我的意思),我们是否像自己说的那样投票,以及不同年龄组在人生不同阶段的优先事项中表现如何。这本书纯粹是伪装成科学的幽默。
6.魔鬼经济学
史蒂芬·列维特和史蒂芬·都伯纳
莱维特是一个古怪的经济学家,而杜布纳是一个机智的记者。不用说,《魔鬼经济学》是一本充满争议但令人愉悦的书。莱维特选择了地球上最随机的主题来应用数据科学。为什么?用乔治·马洛里的话说,“因为它在那里”。
这本书谈到了毒贩子资金链的经济学,有或没有荣誉的学校对你孩子职业生涯的影响,名字的“颜色”是否对你的未来有影响,相扑运动员与美国教师的较量,以及其他你在醒着的时候做梦都不会想到的事情。如果你想知道如何问正确的问题,那就看看这个。
7.极端值
作者马尔科姆·格拉德威尔
马尔科姆·格拉德威尔从不让人失望。他是一个好记者,也是一个伟大的故事讲述者。在读完一本格拉德威尔的书后,你可能会也可能不会学到新的东西,但你肯定会为你已经知道的东西收集一些证据。
他将门外汉的数据分析应用于数十种社交场合,直到你只能点头表示同意。它让你相信你不够好,但很棒,并从地球上最随机的地方获得数据科学的证明。如果你问了正确的问题,到处都有答案。这是你将从书中学到的东西。
数据科学中必须知道的七种统计分布及其模拟
[入门](http://Getting Started)
假设、关系、模拟等等
统计分布是一个参数化的数学函数,它给出了随机变量不同结果的概率。根据它模拟的随机值,有离散分布和连续分布。本文将介绍七种最重要的统计分布,展示它们与 Numpy 库嵌入式函数或随机变量生成器的 Python 模拟,讨论不同分布之间的关系及其在数据科学中的应用。
不同的分布和模拟
1、伯努利分布
伯努利分布是一种离散分布。伯努利分布的假设包括:
1、只有两种结果;
2、只审一次。
伯努利分布描述了一个只包含两种结果的随机变量。举个例子,抛一次硬币,只能得到“头”或者“尾”。我们也可以通过将结果定义为“成功”和“失败”来概括它如果我假设当我掷骰子时,我只关心我是否得到 6,我可以将显示 6 的骰子的结果定义为“成功”,而将所有其他结果定义为“失败”尽管掷骰子有六种结果,但在我定义的这个实验中,只有两种结果,我可以用伯努利分布。
遵循伯努利分布的随机变量 x 的概率质量函数(PMF)为:
p 是这个随机变量 x 等于“成功”的概率,它是基于不同的场景定义的。有时我们有 p = 1-p,就像扔硬币一样。
从 PMF 中,我们可以根据 x 的数值计算出随机变量 x 的期望值和方差,如果“成功”时 x=1,“失败”时 x=0,则 E (x)和 Var (x)为:
通过定义一个随机变量来模拟伯努利试验是很简单的,这个随机变量只产生两个具有一定“成功”概率 p 的结果:
import numpy as np#success probability is the same as failure probability
np.random.choice([‘success’,’failure’], p=(0.5, 0.5))#probabilities are different
np.random.choice(['success','failure'], p=(0.9, 0.1))
2、二项分布
二项式分布也是离散分布,它将随机变量 x 描述为 n 次伯努利试验的成功次数。你可以把二项分布想象成 n 个相同的伯努利分布随机变量的结果分布。二项式分布的假设是:
1、每次试验只有两种结果(像扔硬币一样);
2、总共有 n 次相同的试验(抛同一个硬币 n 次);
3、每次审判都是独立于其他审判的(第一次审判得到“人头”不会影响第二次审判得到“人头”的机会);
4、p 和 1-p 对于所有试验都是相同的(在所有试验中得到“头”的机会是相同的);
分布中有两个参数,即成功概率 p 和试验次数 n。PMF 使用组合公式定义:
我们在 n 次试验中有 x 次成功的概率就像在顺序不重要的情况下从 n 次试验中选择 x。
将二项式分布视为 n 个相同的伯努利分布有助于理解其期望值和方差的计算:
如果你有兴趣得到上面这两个方程,可以看看可汗学院的这些精彩视频。
Python 的 Numpy 库内置了二项式分布函数。要模拟它,定义 n 和 p,并设置为模拟 1000 次:
n = 100
p = 0.5
size = 1000binomial = np.random.binomial(n,p,size)
plt.hist(binomial)
我们可以得到直方图:
二项式分布,平均值约为 n*p = 50
当设置 n 等于 1 时,我们可以模拟伯努利分布:
n = 1
p = 0.5
size = 10000bernoulli = np.random.binomial(n,p,size)
plt.hist(bernoulli)
伯努利试验
3、几何分布
几何分布是一种离散分布,它模拟在重复、独立的伯努利试验中首次成功之前的失败次数(x 次失败)。例如,随机变量可以是在你得到第一个“头”之前你会得到多少个“尾”它还可以模拟获得第一次成功的试验次数(x-1 次失败),比如你要折腾多少次才能得到第一个“头”这两个随机变量的唯一区别是失败的次数。几何分布假设与二项式分布相同,因为它们都来自一些相同的独立伯努利试验。
当随机变量 x 是第一次成功前的失败次数时,PMF 为:
期望值和方差为:
当随机变量 x 是获得第一次成功的试验次数时,PMF 是:
期望值和方差为:
我们需要使用几何级数来推导几何分布的期望值和方差。在可汗学院有一个很棒的教程可以解释细节。
为了模拟几何分布,我们可以使用伯努利试验,计算第一次成功之前的失败次数,然后绘制失败次数(非常感谢 Tiffany Sung 发现了这段代码中的错误):
geometric = []
failure = 0
n=0
p=0.5while n<10000:
result = np.random.choice(['success','failure'],p=(p,1-p))
if result == 'failure':
failure+=1
else:
geometric.append(failure)
failure = 0
n+=1plt.hist(geometric)
plt.axvline(np.mean(geometric),color='red')
平均值在(1-p)/p 附近的几何分布
4、均匀分布
均匀分布模型是一个随机变量,其结果发生的可能性是相等的。结果可以是离散的,就像掷骰子得到的结果,也可以是连续的,就像等车的时间。因此,根据随机变量,均匀分布可以是离散的或连续的分布。这些假设是:
1,有 n 个结果(离散的),或结果的范围(连续的);
2,结果集或范围中的所有值出现的可能性相等。
离散均匀分布很简单,很容易计算期望值和方差。对于均匀分布在[a,b]的连续均匀分布,概率密度函数(PDF)为:
使用积分,期望值和方差为:
为了模拟均匀分布,我们可以使用 Numpy 的嵌入函数并指定分布的范围。基于[0,1]处的均匀分布,我们可以生成[a,b]处的均匀分布:
#generate a random variable follows U(0,1)
np.random.uniform(0,1,size=10000)#use U(0,1) to generate U(a,b)
def uniform(a,b):
return a + (b-a) * np.random.uniform(0,1,size=10000)
在[2,3]处均匀分布
5、正态分布
正态(高斯)分布是最广泛使用的连续分布,因为它代表了大多数宇宙情况。由于中心极限理论,许多随机变量是正态分布的,或者在将它们拟合到统计模型之前假设它们是正态分布的。正态分布有一些独特的特征:
1,均值=众数=中位数=;
2,PDF 呈钟形,对称于 x =;
3,介于[ -σ,+σ]之间的值大约占数据的 68%,其中σ是标准差,并且:
图片由百科,此处=0
正态分布的 PDF 为:
当=0 且σ=1 时,我们有一个标准正态分布,其中 PDF 简化为:
期望值和方差嵌入在正态分布的 PDF 中。期望值是平均值,即,方差是标准差的平方,σ。
为了模拟正态分布,我们可以使用 Numpy 函数:
np.random.normal(mu, sigma, 1000)
或者我们也可以用中心极限理论来模拟正态分布:
def clm(N,n):
#generate a sample from any random population N
lis = np.random.random(size=N)
means = []#take a random sub sample with size n from N
for i in range(n):
lis_index = np.random.randint(0,N,n)
means.append(lis[lis_index].mean())
i+=1#plot means
return plt.hist(means)clm(10000,1000)
CLM 正态分布
6、泊松分布
将泊松分布与二项分布联系起来,有助于我们理解泊松分布的假设和 PMF。假设泊松分布为:
1、任何成功的事件都不应该影响其他成功事件的结果(前一秒观察一辆车不影响下一秒观察另一辆车的机会);
2,成功的概率 p,在所有区间都是一样的(这个小时和其他小时观察汽车经过没有区别);
3、一个区间的成功概率 p 随着区间变小而趋于零(如果我们在讨论一毫秒内会有多少辆车通过,因为时间太短所以概率接近零);
泊松分布的 PMF 可以从二项分布的 PMF 中导出:
二项分布
我们知道 x 是 n 次伯努利试验的成功次数,E(x)=np。如果我们将λ =E(x) =np 定义为 n 次伯努利试验的平均成功次数,则成功概率 p 可由λ/n 来估算。当 n 趋于无穷大时,PMF 变为:
经过的一些计算,我们可以得到一个新的 PMF,也就是泊松分布的 PMF:
泊松分布给出了在一个时间间隔内观察到一定数量事件的概率,给出了该时间间隔内事件的平均数。服从泊松分布的随机变量的期望值和方差都是λ:
为了模拟泊松分布,我们可以使用 Numpy 函数:
lam = 1poi = np.random.poisson(lam=lam,size=1000)
plt.hist(poi)
plt.axvline(x=lam,c='red')
λ为 1 的泊松分布
7、指数分布
指数分布是一种与泊松分布密切相关的连续分布。它是泊松事件之间时间间隔的概率分布。如果一个公司一小时内接到的电话数服从泊松分布,那么电话之间的时间间隔服从指数分布。由于指数分布与泊松分布密切相关,其假设遵循泊松分布的假设。
我们可以通过首先推导其累积分布函数(CDF ),然后对 CDF 求导来推导指数分布的 PDF。我们使用这个技巧是因为我们可以用泊松分布得到 CDF。假设我们还在观察同一条街上有多少辆车经过,现在我们关心的是随机变量ω,它被定义为当我们看到一辆车经过时,至少需要ω分钟才能观察到另一辆车经过。我们从头说起——观察第一辆车需要多长时间?假设用ω分钟观察第一辆车用ω分钟,有零辆车通过。我们知道,一分钟内在街上通过的汽车数量遵循泊松分布:
每分钟汽车数量
在ω分钟内,街道上通过的汽车数量如下:
ω分钟内的汽车数量
我们在ω分钟内观察到零辆车的概率是:
从指数分布的角度来看,我们现在已经知道花至少ω分钟观察第一辆车的概率,那么花少于ω分钟的概率是:
这是随机变量ω的 CDF,对ω求导,我们得到 PDF:
如果我们知道在一分钟内,平均下来,我们很可能观察到三辆车(λ=3)经过街道,那么预计每 1/3 分钟,我们就会观察到一辆车经过。因此,指数分布的期望值和方差为:
为了模拟指数分布,我们可以使用 Numpy 随机函数:
lam = 2
exp = np.random.exponential(lam, 10000)
plt.hist(exp)
plt.axvline(x=lam, c=’red’)
指数分布
或者我们可以用(0,1)的 CDF 和均匀分布来模拟它。以下等式显示了该过程:
遵循准则:
rate = 1/20
inverse_cdf=np.random.uniform(0,1,size=1000)interval = [-np.log(1-u)/rate for u in inverse_cdf]plt.hist(interval)
用 U(0,1)模拟指数分布
不同分布之间的关系
正如上面部分讨论的,这些分布以不同的方式彼此密切相关:
1、伯努利分布是二项分布在 n 等于 1 时的特例;
2,当 n 趋于无穷大,p 趋于零时,np = λ,一个有限数,二项分布逼近泊松分布;
3,当 n 趋于无穷大,p 不是无限小,λ也趋于无穷大时,二项分布接近正态分布;
4,如果长度为 t 的时间间隔内的事件总数服从参数为λ的泊松分布,则随机事件之间的时间服从速率为λ/t 的指数分布。
几何分布是唯一具有无记忆性的离散分布,指数分布是唯一具有无记忆性的连续分布。无记忆属性的数学定义是:
P( X > a + b | X> a ) = P ( X> b)
您可以在此阅读更多关于该房产的详细信息。你能想到的一个含义是,如果电池的寿命呈指数分布,那么一个用过的电池就和新的一样好,只要它没死。
数据科学中的统计分布
了解不同统计分布的假设和属性无疑有助于数据科学家的日常工作:
1,蒙特卡罗模拟从从均匀分布产生随机变量开始;
二项分布是任何二元分类模型的基础;
3,所有使用最小二乘成本函数的回归模型都假设残差遵循均值等于零的正态分布;
4、正态分布的变换分布,如学生 t 分布、标准正态分布是用于进行假设检验、计算 p 值和得到置信区间的分布;对数正态分布描述数据右偏时的所有数据样本;
5,泊松和指数分布更适合模拟具有固定时间速率(λ)的事件。例如,我们可以使用泊松分布来模拟一天中有多少客户会出现在商店中,并使用指数分布来模拟两个连续的客户进入商店所需的时间。
统计分布在日常生活中无处不在。了解统计分布对于数据科学家更透彻地了解数据、进行更好的数据分析、选择更合适的模型等有着非常重要的作用。这篇文章有帮助。感谢您的阅读。
这是我所有博客帖子的列表。如果你感兴趣的话,可以去看看!
我快乐的地方
zzhu17.medium.com](https://zzhu17.medium.com/my-blog-posts-gallery-ac6e01fe5cc3) [## 阅读朱(以及媒体上成千上万的其他作家)的每一个故事
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
zzhu17.medium.com](https://zzhu17.medium.com/membership)
你可能正在制造 ML 技术债务的七个迹象
以及你能做些什么
[7]
在线机器学习 ML 社区同意萌芽的 ML 产品面临的大多数问题都是工程挑战[1][2]。领先的 ML 研究者和实践者似乎一次又一次地证实,快速迭代和添加优秀 ML 特性的能力才是最重要的。承诺是,通过将您的资源投入到持续的 ML 交付实践中,可以从优秀的特性和大量的迭代中获得显著的收益;而不是专注于最新的前沿 ML 算法、技术或框架。
在这篇文章中,我们将假设你已经确信,你的企业是时候建立一个机器学习驱动的产品了。你可能在没有任何机器学习的情况下推出了你的 ML 服务。您可能还关注于指标设计和收集。此外,你已经做出决定,你想使用 ML,而不是你试图取代的不可维护的启发式噩梦。
如果你已经在那里,请继续阅读——否则,请点击这里查看如何超越 ML 项目的第 0 阶段。
ML 技术债务的早期迹象
1.您不关心基础设施,而是专注于启动复杂的初始模型
[8]
在最初的发布阶段,很容易认为团队面临的大多数问题都与 ML 有关。基本上,如果你的团队正在讨论像这样的事情,“哦,太糟糕了,我们不能使用 GPT-3 文本嵌入,这将真正提高 初始 *情感分析模型的性能。”。*这可能是 ML tech 债务即将到来的迹象。
如果由于关注最新的模型性能,团队不清楚如何将样本带到模型的培训阶段,或者对好的和坏的业务结果看起来有些模糊,或者团队不知道模型是离线还是在线应用,那么团队的集体意识中应该有一个红色霓虹灯闪烁的尖锐警报。
此外,在第一个计划的发布中,如果团队不能解释特性是如何流向系统的,或者模型权重是不稳定的,或者服务管道有一种复杂的方式来访问推断所必需的特性,那么不要期望后续的发布会神奇地修复这些问题。
最后,如果对 v1 模型性能的期望是正向倾斜的,那么对性能的关注将使对基础设施的关注相形见绌,基础设施建立了一个更可持续的产品市场适应学习循环。
2.您将测试 ML 组件与测试基础设施混在了一起
[9]
测试对于 ML 从业者来说是一个巨大的眼中钉。通常,ML 团队报告说没有 ML 组件就不可能测试基础设施。如果 ML 模型与基础设施的其余部分是不可分的,那么您可能会有相当多的债务需要处理。
Next ML 团队有时是外部数据源的定制消费者。很容易理解,公司里没有人希望城市代码是一次性编码的。这使得无法将从特定于 ML 的转换中获得的统计数据与任何外部数据源进行比较。
最后,另一个迹象是,当选择候选模型时,在训练模型之后,没有对模型的输出进行验证,以判断未来服务时间分数的分布是否将匹配离线训练时间分数。
成长阶段的 ML 技术债务迹象
3。你期望你正在启动的模型将是唯一的、最后的、最好的一个
[10]
一旦 ML 团队完成了第一个端到端系统,“技术现金流问题”就会开始出现。ML 团队通常发现他们自己从初始阶段就开始关注累积的债务,在初始阶段,关注的焦点是将特性添加到模型中,通过偷工减料来收集度量,以及在各种支柱上支撑服务基础设施。
在 ML Eng 行业反复报道的一个误解是,团队推出的第一个模型将是唯一的、最后的、最好的模型。有些人甚至认为,总有一天模型会停止发布。这种一劳永逸的态度通常会在团队发现所有仍将包含在模型中的特性时得到迅速纠正。虽然每天用新数据重新训练无变化的 ML 管道正在成为标准,但至少,期望在 2 年内每月或每季度发布改进的模型管道应该是 ML 团队事实上的基线。
这个阶段对于 ML 团队来说是一个激动人心的时刻;他们开始关注用新功能改进模型,调整超参数,创建新的旧功能组合,甚至重新思考他们正在优化的代理业务指标。不幸的是,这是大多数技术债务产生的地方,因为项目已经运行了一段时间,所以为了按时发布新的改进,更多的可维护性方面的问题被忽略了。
ML 管道需要一些关心和关注的迹象是团队问自己:
- 从现有模型中移除特征有多容易?
- 添加新功能或将它们与现有功能相结合有多容易?
- 拥有整个 ML 管道的副本需要什么?让黑暗启动的管道发布并比较它们与主线的性能会有多难?
- 团队是否优先考虑将昂贵的特性包含到模型中,而不是频繁地发布增量版本,并从实时用户流量中了解什么可行,什么不可行?
如果一个 ML 团队发现自己因为之前的设计和架构决定而被锁定并且不能移动,那应该是系统中技术债务增长的警告信号。
4。您将未使用的特性留在管道中,直到它们不再被使用
[11]
最有效的提高性能的方法,伟大的特性,也可以是最阴险的技术债务创造者。如果你听到你的团队说我们应该在特性转换工作中保留一个未使用的特性“以防万一”,那么这可能是 ML 技术债务正在增长的一个信号。
这种迹象与添加一个新的令人鼓舞的特性不与代码角力就无法使用的情况密切相关,因为一个未使用的特性与新特性冲突。这个标志指向了管道设计的刚性,其中特征转换可能与模型训练/服务代码过度地交织在一起。
最后,有时即使有一种干净的方法来移除未使用的功能,也没有简单的方法来区分功能的有用性,因为没有适当的过程来根据例如功能的覆盖范围和与标注的相关性来对功能的效用进行排序。
5.您正在寻找将您的笔记本电脑安排为生产流水线的方法
[12]
Jupyter 笔记本是探索和原型制作 ML 管道的神奇工具。这个社区非常棒,将来可能会有基于笔记本电脑构建可靠软件的方法,但是专家们正在慢慢反对在生产中使用笔记本电脑。
随着笔记本电脑基础技术的发展,未来可能会安排笔记本电脑并在生产中使用它们。然而,截至 2020 年[5],指导方针是从笔记本电脑中提取智能,并使用标准的集成开发环境,促进更清洁的架构、模块化、自动化测试和标准软件实践。
目前,如果您正在尝试或计划将笔记本电脑作为生产设备,这可能会工作一段时间,但您的工作效率将会遇到阻碍,因为随着时间的推移,笔记本电脑中固有的问题和技术债务会越来越多。
培训服务 ML 债务陷阱
6.在训练和服务管道之间使用两个独立的实现
[13]
这种迹象很容易发现,也很难察觉。
容易发现的一点是决定在训练和服务/评分管道之间使用不同的编程语言或者甚至不同的 ML 代码实现。这可能是一个明确的信号,表明您正在放弃任何类型的迭代,并在第一次发布后重用。让一个伞兵工程班从头开始重新实现你的分类评分系统是一个灾难。从软件的角度来看,训练代码将极大地偏离评分代码,因为他们几乎相反的关注点。培训是面向后的,错误可能会触发内部电子邮件警报,而评分最有可能是面向客户的,这将在不恰当的时候点燃你松弛的渠道。
第二个迹象特别出现在评分是在线处理操作时。虽然团队可能在训练和模型选择阶段过度优化了批处理代码,但在线处理需要系统在每个请求到达预测服务时对其进行处理。如果你没有计划如何弥合在线和离线系统处理的数据处理性质的差异,那么这也可能是潜在增长的 ML 技术债务的一个迹象,这可能会在以后困扰你。
7 .。你不能 100%确定 CI/CD 代表什么
机器学习的 CD 连续交付和 CD4ML 连续交付。
[14]
这与第三点有关。计划迭代。
连续交付[3]是一种非常适用于 ML 工程世界的软件实践。有许多迹象表明,CD 实践将帮助您发展您的 ML 产品。如果你很少在产品中发布模型,并且在等待第四季度的发布系列时,多个“改进”不断堆积,那么对新的主要发布的影响的恐惧就会不断增长。一个变更在发布系列中停留的时间越长,它是否能在产品中工作的不确定性就越大。
需要 CD 的另一个迹象是当有一个昂贵的过程来发布模型到产品中。如果项目经理正在为一个变更窗口做预算,以允许数据管道中涉及的所有团队同步,那么这个可归因于发布过程的固定成本应该被视为一个信号。
缺乏可靠的部署管道可能会导致不必要的协调,但是会降低团队成员的幸福感。他们的模型改进未被使用,未被部署,可能会消除您的 ML 工程师和最终用户之间的重要反馈循环,而大部分责任感、持续学习和有用性都来自于此。类似地,如果没有办法组织代码和部署管道,以允许频繁的 A/B 测试,那么这可能是一个信号,表明 2/3 的功能没有被用户使用[3]。
8.额外收获:你意识到 ML Eng 很像软件 Eng,但是你从来没有找到一本好书来沟通这两个世界
机器学习(ML)管道毕竟是软件管道。
我有一个独特的机会来研究这个主题,作为一个隔离项目,以便提炼和组织我多年来在这本书里学到的东西:
这本书将帮助读者应用实用的软件工程原理来防止他们在机器学习软件工艺过程中的失败。
谢谢你的支持。
伙计们,现在就这样。
我希望这篇文章对你有用。
感谢阅读。
在外面注意安全。
参考
[1]https://developers . Google . com/machine-learning/guides/rules-of-ml
https://research.google/pubs/pub43146/
https://continuousdelivery.com/
https://martinfowler.com/articles/cd4ml.html
[5]ThoughtworksTechnology Radar vol . 23 11/2020 先睹为快网络研讨会 2 — Zhamak Dehghani — 生产搁置的笔记本电脑:https://youtu.be/CUTSnAutoAM?t=2746
【6】转到 2019 年——整体结构分解模式——萨姆·纽曼https://youtu.be/9I9GdSQ1bbM?t=571
【7】Meme 模板在这里:https://img lip . com/Meme/257455447/Leonardo-Dicaprio-pointing-in-TV。迷因文本是自我创作的
[8] 模因模板在这里:https://imgflip.com/meme/155217391/Interstellar-7-years。迷因文本是自我创作的
[9] 模因模板在这里是 https://imgflip.com/i/3jqfd0
[10] Meme 模板在这里:https://img lip . com/Meme template/228603083/odd1 sout-vs-computer-chess。迷因文本是自我创作的
【https://imgflip.com/memetemplate/Two-Buttons】【11】模因模板在此:模因文字为自己创作
[12]【https://imgflip.com/meme/Drake-Hotline-Bling】模因模板在这里:模因文字均为自己创作
[13]迷因模板在这里:https://imgflip.com/memetemplate/Disaster-Girl迷因文字为自己创作
[14]模因模板 https://imgflip.com/memegenerator/Afraid-To-Ask-Andy。迷因文本是自我创作的
**免责声明:**本文表达的观点是我个人的观点,不一定代表我现在或过去雇主的观点。
严重性分数推导
解释所涉及的步骤、思考过程以及新冠肺炎严重程度评分背后的研究,以便在州和县之间进行比较
美国严重性仪表板:Tableau Public 上的新冠肺炎登录页(2020 年 9 月 9 日)
当我为新冠肺炎制作美国严重性仪表板时,有几个人问我:
“您是如何为您的新冠肺炎仪表板计算出严重性分数的?”
我解释说,这是一个相当有趣的过程,有许多尝试。在与我在 LinkedIn 上的一个密友交谈后,我意识到我所经历的过程可能会成为一篇有趣的文章。因此,我们在这里。
解决问题有很多不同的方法;数学定律、推导出的数学方程式或有用的信息表示。例如,一个 FICO 信用评分是一个有用的和有意义的代表某人偿还贷款的能力。是法律吗?不,橄榄球联盟的四分卫得分也不是。我们作为指标所依赖的许多指数,如道琼斯指数,并不是经过验证的科学事实,而是以有意义的格式表示数据的一种简明方法。
钟系列的创造者埃里克·坦普尔·贝尔说:
“抽象性,有时被当作对数学的一种指责,是它的主要荣耀,也是它最可靠的实用头衔。它也是可能从数学中产生的美的源泉”
换句话说,有时候抽象思维可以导致实践。
收集的初始数据:
可用于构建严重性分数等式的构件
COVID 仪表盘在互联网上随处可见。一个共同点是,不清楚病毒在哪里受到最严重的打击。“严重性”与死亡或感染有关吗?假设像纽约市这样的城市里的人比该国农村地区的人与他人接触更多,那么人口是否应该在决定病毒的严重程度方面发挥作用?
然后我突然想到…
“如果我能想出一种方法来表示病毒在美国每个县的严重程度,这样人们就能很容易地说出哪里的病毒对健康影响最大,那会怎么样?”
我思考了这个想法,并决定研究一下流行病学家的结论。
这项研究
对于流感爆发,公共卫生官员通常使用疫情严重程度评估框架(PSAF) 来帮助确定疫情会有多“糟糕”。它使用两个因素;临床严重性和病毒传播性。文章提到,“PSAF 是疾病预防控制中心开发的两个评估工具之一,用于指导和协调参与疫情反应的联邦、州、地方和部落实体的行动”
文章随后提到了“评估流感流行和大流行的流行病学影响的新框架” (Reed et al. 2013)。新框架详细说明了根据数据可用性、可传递性和临床严重程度指标确定疫情严重程度的 4 个方法步骤。文章还提到,在历史上,病死率(CFR)一直被使用。
另一个众所周知的疾病统计是死亡率 。
通常代表每 1 千或 10 万人
CDC 网站上的另一个链接指向流感风险评估工具(IRAT) 。文章解释说,“IRAT 使用 10 项科学标准来衡量与每种情况相关的潜在疫情风险。这 10 项标准可以分为三大类:“病毒的特性”、“人群的属性”和“病毒的生态学&流行病学”。”(Reed 等人 2019)。
我的评估
- 我知道临床严重程度指标在一段时间内不会出现,也不知道为了确定病毒如何在生物学上传播而进行的研究是否充分。
- 病死率忽略了人口规模和密度,这在不同县之间进行比较时很重要。
- 死亡率包括人口数量,但不包括感染。
似乎没有一个衡量标准可以概括这一切。现有的总体框架和评估工具似乎侧重于病毒如何传播的性质,而不一定是“每个地区有多严重”。
既然如此,我开始头脑风暴:
“我认为决定严重程度的因素是什么,我如何整合常见的流行病学计算来赋予这个等式一些合法性?
等式尝试 1:
我读过的文章中没有一篇提到增长率。感染和死亡的增长率不同。因此,我需要将它们作为单独的实体插入。这个思路让我创建了一个感染分数和一个死亡分数,其中:
我决定将死亡分数乘以 2,以说明感染人数将多于死亡人数的事实,并且我最初决定按照指数增长公式 y = ab^x 来模拟我的方程,其中 a 将是总指标, b 将是增长率,x 将被平方。除以人群进行归一化,第一个严重性评分诞生。
方程式:
严重性等式尝试 1
等式尝试 2:
坚持指数增长的概念,我添加了阳性检测百分比(PTP) 作为总感染增长率的系数,理由是一百万次检测中有 1000 次阳性结果的县应该比 1001 次检测中有 1000 次阳性结果的县不那么严重。
随着阳性检测百分比降低了总感染增长率的影响,我认为添加病死率作为总死亡增长率的降低系数将是包含在严重性分数中的适当指标。
方程式:
严重性等式尝试 2
辅助方程:
问题:这一轮方程式出现了两个主要问题,还有一个我还没有注意到的问题。
这两个问题是:
- 病死率 * 总死亡人数增长率是什么意思?
- 阳性检测百分比 * 总感染增长率是什么意思?
我没有注意到 CFR 和 PTP 都在< 1 and most of the growth rates are also < 1. Multiplying them together essentially added nothing to my score when deaths and infections could both be in the thousands.
收集反馈
抛开这些问题,我决定收集一些关于我正在做的事情的反馈。我收到的最常见的问题是
"为什么死亡总数要乘以 2?"以及“你为什么要平方增长率?”
我的教授 Vibhanshu Abhishek 告诉我,每个分数的权重不应该由我来决定,因为每个人对如何比较感染和死亡的严重程度都有自己的偏见。
在这种情况下,我决定添加两个可以由用户调整的系数,一个是死亡系数α,另一个是感染系数β,范围在 0 到 1 之间。此外,我在中加入了人口密度,理由是人口的增加应该会降低的严重程度(因为现在每个感染/死亡只占总数的一小部分),但是人口密度的增加应该会增加的严重程度,因为人们会更频繁地接触。为了实现这个行为,人口需要在分母上,而人口密度需要在分子上。为了便于阅读,可以表示如下。
方程式尝试 3:
结合这一反馈,这些方程得出:
方程式:
严重性等式尝试 3
问题:我后来才意识到分母的问题,但是
人口被取消,分母等于面积。
仪表板创建
带着一个充满了我最初没有意识到的疑问和问题的等式,我继续前进,创建了美国严重性仪表板的第一个迭代。
美国严重性仪表板:新冠肺炎登录页面—第一次迭代—(2020 年 4 月 12 日)
基于每个州和县的严重程度的国家整体视图。我对结果非常满意。我的教授告诉我,我可能应该对方程取一个对数,以便将严重性标准化,因为分布在当前状态下是高度偏斜的。
取我的严重性分数的对数,我意识到我在我的一个表示中违反了对数的第一定律。
对数第一定律指出:
log A+log B =log AB
这意味着:
log(感染分数)+ log(死亡分数)≠ log(感染分数+死亡分数)
这提出了一个新的问题,因为死亡分数和感染分数不能相乘。如果它们相乘,0(无死亡)的死亡分数将导致 0 的严重性分数,即使该州或县有数百万感染。因此,我需要将感染分数加到死亡分数上。
在对正确的对数表示进行推导之后,我终于发现了我之前提到的问题,并决定重新构建整个方程。
方程式尝试 4:
几天的实验过去了,我试着把注意力集中在为什么我首先要创建严重性分数上。
“严重性分数的意义在于能够比较县或州之间的健康影响”
我重新构建了这个等式,以说明一旦增长率为 0,意味着没有新的感染,那么产生的严重性分数将基于该县或州已达到的感染和死亡总数。
什么改变了:
- 修复了前面提到的所有问题
- 我意识到我应该用实际感染或死亡人数乘以增长率
- 我意识到阳性检测百分比使等式变得复杂,无法将其与增长率联系起来。
- 我意识到病死率包含了感染和死亡。这意味着随着感染的增加,感染分数会增加,但是死亡分数会降低,因为 CFR < 1
- 我意识到人口对严重性有着压倒性的影响。我想让人群标准化严重性分数,但我不想让它成为线性效应。我决定平方根会对更大的人口产生更小的影响,而对数会有更陡的影响。
方程式:
严重性等式尝试 4
收集反馈(第二部分)
收集了几个人的意见后,我问了一个关于严重性等式的基本问题。
“当一个县或州不再有任何感染或死亡病例时,其严重性分数应该为零还是达到最高?”
我得到了响亮的答案
“当然,如果没有更多的感染或死亡,严重性分数应该为零,这时你会说没有严重性”
思考这个答案,我意识到这很有道理。在目前的状态下,这个等式永远不会等于零,因为总死亡数和总感染数和永远不会等于零。这意味着需要做一点小小的调整。
方程式尝试 5:
我决定,如果我计算过去 7 天感染和死亡的周平均值,那么如果一个县或州停止出现新的感染或死亡,他们的严重程度得分将为零。我还必须改变增长率,使其基于过去 7 天的数据。
最终方程式:
严重性等式尝试 5
这种表现感觉就像我想在这个等式中达到的完美平衡。
- 按人口标准化的感染和死亡的包容性方程。
- 严重性的每周快照,如果没有进一步的感染或死亡,得分为 0。
- 包含增长率以揭示趋势案例的方向性。
- 一个用户可调整的参数,允许感染和死亡之间的重量感觉差异。
在启动严重性仪表板整整一个月后,我现在有了一个完整的等式和一个更新的仪表板来显示它。
媒体报道
两周后,我在 UCI 的学校写了一篇关于这个项目的文章。https://merage . UCI . edu/news/2020/05/Matthew-littman-msba-20-creates-新冠肺炎-dashboard.html
两个月后,《洛杉矶时报》刊登了这篇报道。
美国严重性控制面板:新冠肺炎登录页面(2020 年 5 月 12 日)
成品是什么样子的?
经过几个月的添加工具提示、更新、新功能、用户体验和质量检查,目前形式的美国严重性仪表板:新冠肺炎如下图所示。点击链接查看,感谢阅读!
美国严重性仪表板:Tableau Public 上的新冠肺炎登录页(2020 年 9 月 9 日)
来源:
“流感风险评估工具(IRAT)。”2019.2019 年 10 月 10 日。https://www . CDC . gov/flu/疫情-资源/国家-战略/风险-评估. htm 。
里德、凯莉、马修·比格斯达夫、林恩·费内利、丽莎·m·库宁、丹尼斯·博韦、阿姆拉·乌兹卡宁、安德鲁·普卢默、乔·布雷西、斯蒂芬·c·里德和丹尼尔·b·杰尼根。“评估流感流行和大流行的流行病学影响的新框架——第 19 卷,第 1 期——2013 年 1 月——新发传染病杂志——CDC。”2020 年 9 月 9 日接入。https://doi.org/10.3201/Eid 1901.120124
性很重要,为什么我知道
使用 Captum,综合梯度和 PyTorch 闪电的神经网络的可解释性。看着黑盒!
看看黑匣子,由大卫·拉古萨拍摄。
介绍
神经网络已经席卷了全世界。每周都有关于 GPT-3 如何自动完成另一项语言任务的好消息。或者在当前的疫情中人工智能是如何帮助医生的。
但是越来越多的人对人工智能的转变越来越怀疑。它选择这种治疗方法是因为它是正确的治疗方法吗?还是因为它恰好是训练集中另一个 5.29 岁患者的最佳选择?
整个群体都在警告我们人工智能中糟糕设计的含义,我们应该更好地倾听。毕竟,种族和性别相关的特征已经以歧视的方式在最近的招聘流程算法中使用了!
作为一个人工智能社区,我们如何,
- 确保我们建立包容性的工具。
- 确保我们的模特做我们认为他们在做的事情。
- 向他人解释我们的模型在做什么。
1、2、3 的答案是明确的可解释性!它在深度学习领域掀起了一阵风暴。让我们今天了解一下它是什么,以及如何轻松地将其集成到我们的流程中。
我们将建立一个神经网络来预测泰坦尼克号乘客的生存机会。最后,了解我们做了什么,并使用 Captum 解释我们的模型。全部使用强大的闪电框架。
Gif 总结解释了我们神经网络的学习过程。作者图片
0.进口
我们将从导入依赖项开始。
# Our ML things
import pytorch_lightning as pl
import torch
from torch.utils.data import DataLoader, Dataset
from captum.attr import IntegratedGradients
from pytorch_lightning import seed_everything
from pytorch_lightning import Trainer# Visualization
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt# Utils
from enum import Enum
import pandas as pd
from sklearn.metrics import classification_report
1.资料组
为了制作这个最小的例子,我们将使用 Titanic 数据集(一个小文件)。可以在这里下载。下载完成后,将其放入一个新文件夹“data/train.csv …”这个数据集可能是有史以来最受欢迎的 Kaggle 数据集,因此允许我们验证我们的结果。
它包含了泰坦尼克号的 890 名不同的乘客。对于每位乘客,我们将预测他们是否幸存!
为此,我们被赋予了几个特性。
PassengerId **Survived** Pclass ... Fare Cabin Embarked
0 1 0 ... 7.2500 NaN S
我们将只处理其中的一小部分,即:
**Survived** Pclass Sex Age SibSp Fare
0 0 3 male 22.0 1 7.2500
现在我们有了一个概述,让我们定义数据集。数据集是 PyTorch 中的一个类。它需要定义 3 个私有函数,init()、len()、getitem()。
如果你对此不熟悉,可以在这里 ( 1)找到一个简单的解释 。数据集)。这里的目标是做一个最小的预处理,以便稍后展示我们的解释。
**# Simple enum that helps organizing
# Not really important**
class TrainType(Enum):
train = 1
test = 2**# Our Custom Dataset class** class RMSTitanic(Dataset):
def __init__(self, type: TrainType):
file = "data/train.csv"
**# Preprocessing**
df = pd.read_csv(file)
**# Select relevant fields**
df = df[['Survived', 'Pclass',
"Sex", "Age", "SibSp",
"Fare"]]
**# Convert Sex -> 0/1**
m = {'male': 1, 'female': 0}
df['Sex'] = df['Sex'].str.lower().map(m)
**# Fix the non available vals
# Also normalize**
df = df.fillna(df.median())
df -= df.min()
df /= df.max()
**# The first 80% are Train**
if type == TrainType.train:
self.df = df.loc[:int(0.8 * len(df))]
if type == TrainType.test:
self.df = df.loc[int(0.8 * len(df)):]
**# We will use this later for interpretation**
self.base = torch.tensor(df[
['Pclass', "Sex",
"Age", "SibSp",
"Fare"]
].mean()).cuda().float()
def __len__(self):
return len(self.df)
def __getitem__(self, item):
**# This function return the i-th elem** row = self.df.iloc[item]
label = row['Survived']
features = row[['Pclass', "Sex",
"Age", "SibSp",
"Fare"]]
**# return the (label,features)** return (
torch.tensor(features).cuda().float(),
torch.tensor(label).cuda().float()
)
这已经是我们最小的数据集了。请记住,这只是一个小的助手类。它帮助 Pytorch Lightning 施展它的魔法,因此我们可以节省更多的代码。
简短解释
我们得到的特征和它们的解释是什么。
**Pclass** "What class is person traveling in? First being best"
**Sex** "Male or Female"
**Age** "How old in years?"
**SibSp** "How many Sibiling/Spouses are there onboard"
**Fare** "Amount in money spend"
2.模型
我们现在将构建一个简短但强大的模型。它将依次调用下面的层。
| Name | Type |
------------------------
0 | input | Linear |
1 | r1 | PReLU |
2 | l1 | Linear |
3 | r2 | PReLU |
4 | out | Linear |
5 | sigmoid | Sigmoid |
我们现在将定义一个名为 MyHeartWillGoOn 的 PytorchModel。基本上只有前进功能是至关重要的。
class MyHeartWillGoOn(pl.LightningModule):
def __init__(self):
**# Setting up our model** super().__init__()
**# way to fancy model** self.lr = 0.01
self.batch_size = 512
l1 = 128
**# We send our 5 features into first layer** self.input = torch.nn.Linear(5, l1)
**# PRELU is just a fancy activation function** self.r1 = torch.nn.PReLU()
**# More Layers** self.l1 = torch.nn.Linear(l1, l1)
self.r2 = torch.nn.PReLU()
self.out = torch.nn.Linear(l1, 1)
**# Befor the Output use a sigmoid** self.sigmoid = torch.nn.Sigmoid()
**# Define loss** self.criterion = torch.nn.BCELoss()
def forward(self, x):
**# Heart of our model** x = self.input(x)
x = self.l1(x)
x = self.r1(x)
x = self.out(x)
x = self.r2(x)
x = self.sigmoid(x)
return x
def train_dataloader(self):
**# Load our Dataset: TRAIN** return DataLoader(
RMSTitanic(type=TrainType.train),
batch_size=self.batch_size,
shuffle=True)
def val_dataloader(self):
**# Load our Dataset: TEST
# Simplification: TEST=VAL** return DataLoader(
RMSTitanic(type=TrainType.test),
batch_size=self.batch_size,
shuffle=False)
def configure_optimizers(self):
return torch.optim.Adam(self.parameters(), lr=self.lr)
def training_step(self, batch, batch_idx):
**# Here we just log some basics
# We can look at them later in tensorboard** x, y = batch
y_hat = self(x)
y = torch.reshape(y, (y.size()[0], 1))
loss = self.criterion(y_hat, y)
tensorboard_logs = {'loss': loss}
return {'loss': loss, 'log': tensorboard_logs}
3.火车
PyTorch Lightning 的训练是由一个不错的小训练师完成的。
if __name__ == '__main__':
**# Seed so we can reproduce** seed_everything(404)
**# Load model to GPU** device = torch.device("cuda")
model = MyHeartWillGoOn().to(device)
**# Make the Trainer do the work** trainer = Trainer(max_epochs=20, min_epochs=1, auto_lr_find=True, progress_bar_refresh_rate=10)
trainer.fit(model)
**# Accuracy #ToBeMeasured** ts = RMSTitanic(TrainType.test)
**# Bit of Hacking** x = torch.stack(
[ts.__getitem__(i)[0] for i in range(ts.__len__())]
)
y = torch.stack(
[ts.__getitem__(i)[1] for i in range(ts.__len__())]
).cpu().detach().numpy()
y_hat = model.forward(x).cpu().detach().numpy()
y_hat = (y_hat > 0.5)
**# Accuracy and other metrics** print("REPORT:\n",
classification_report(y, y_hat))
在 GPU 上训练我们的模型 20 个历元将会得到以下结果。
**SURVIVED** precision recall f1-score support**FALSE** 0.84 0.94 0.89 115
**TRUE** 0.86 0.67 0.75 64**accuracy** **0.84 ** 179
macro avg 0.85 0.81 0.82 179
weighted avg 0.85 0.84 0.84 179
正如我们所看到的,我们得到了 84%的准确率,这对于这个任务来说是可以接受的。这次我们更感兴趣的是解读。如果你想知道如何在这项任务中获得满分,可以看看 Kaggle 。
4.解释
既然 Pytorch 闪电真的很新,而 Captum 更新;)我们在这方面相当领先。
我们需要解决一些尚未妥善解决的小问题。为了做到这一点,我们需要添加一个更小的包装函数,稍后呈现给 Captum。基本上,Captum 是一个有几种可用方法的库。这些方法预测输入特征对神经模型的重要性。他们以几种方式这样做。我们将使用可能是最流行的方法集成梯度**。下面我就给出这种方法的一个直觉。**
**# Let's start with the interpretation** STEP_AMOUNT = 50
SAMPLE_DIM = 5
**# Since Captum is not directly
# made for Lightning,
# we need this wrapper**
def modified_f(in_vec):
**# Changes the shapes correctly
# X:Shape([SAMPLE_DIM*STEP_AMOUNT]=250)**
x = torch.reshape(in_vec,
(int(in_vec.size()[0] / SAMPLE_DIM), SAMPLE_DIM)
)
**# RES:Shape([50,5])
# Since we have 50ti Batches and 5 features**
res = model.forward(x)
**# Again reshape to correct dims**
res = torch.reshape(res, (res.size()[0], 1))
return res
ig = IntegratedGradients(modified_f)
现在我们可以开始学习我们的模型是如何思考的。赋予此对象 IntegratedGradients。我们可以使用它的 main 方法属性()!
attribute()是一个函数,它将一个张量作为输入,并返回给我们一个相同形状的张量
这意味着当我们告诉我们的模型,我们的案例研究对象:
**Pclass Sex Age SibSp Fare**
3 male 22.0 1 7.2500 (I am not normalized)
它将使用这 5 个特征进行预测。假设这个 22 岁的男子支付了 7.25 英镑的车费,那么这个数字就是 0.3%,也就是 0.3%的生存机会。预测后我们会发这个 30%存活率->0 %,意思是他死了。
现在积分梯度返回给我们一个张量,也有 5 个值。这些值中的每一个都会告诉我们各自的特性有多重要。这可能是 y. E .的差异
**Pclass Sex Age SibSp Fare**
0.1619, -0.1594, 0.0196, -0.0024, 0.0068
5.综合梯度
中间上了一堂理论课。集成梯度已经在中提出,用于深度网络的公理化属性综合梯度用于理解我们的神经网络是如何工作的。集成梯度是所谓的可解释性算法。
今天的人工智能社区中使用了几种可解释性算法,但 IG 是最早和最成熟的算法之一。科学界还没有明确决定哪种算法是最好的。随意测试一些其他的,比如 DeepLift 。
综合梯度—简而言之
这是一个简化的解释,更多细节请参考论文“深度网络的公理化归属
为了以神经网络的方式优化损失函数,我们建立梯度。为了了解每个输入要素对我们的损失函数的贡献大小,我们颠倒了这个过程(称为积分),因此我们对梯度进行积分。
现在,计算积分很难,答案也不清楚。这就是为什么我们必须近似它。我们用黎曼和来近似这个积分。
我们通过使用超参数 n_steps 和基线来近似该值。基线是我们与输入进行比较的对象(我们将在下面详细讨论)。n_steps 是我们反向传播以估计积分的次数。N_steps 基本上控制了我们对积分的估计有多精确。
6.资本基础
我们现在有三样东西:
- 受过训练的模特
- 测试设备
- 综合梯度
使用这些东西,我们将了解我们的模型
**# Test to understand the basics**
**# First get the 6th test example**
val = ts.__getitem__(6)[0]
print("IN X1:", val)
**# Predict the importance of the features
# for the male example**
imp_m = ig.attribute(inputs=val,
baselines=ts.base,
n_steps=STEP_AMOUNT)
print("IMPORTANCE X_m:", imp_m)
print("Probability SURVIVAl X_m:", modified_f(val))
**# Predict the importance of the features
# for the female example**
print("Let's Change the gender ->X2")
val_f = val
val_f[1] = 0
imp_f = ig.attribute(inputs=val_f,
baselines=ts.base,
n_steps=STEP_AMOUNT)
print("IMPORTANCE X_f:", imp_f)
print("Probability SURVIVAl X_f:", modified_f(val_f))
该代码将打印:
IN X1: [1.0000, 1.0000, 0.3466, 0.0000, 0.0303]
IMPORTANCE X_m:[-0.0593, -0.1121, -0.0010, 0.0019, -0.0040]
Probability SURVIVAl X_m:0.1265IMPORTANCE X_f:[-0.1178, 0.4049, -0.0020, 0.0037, -0.0080]
Probability SURVIVAl X_f:0.5817
如你所见,当我们给出 Captum,这两个相同的例子。除了性别。我们得到了截然不同的存活率。
**# MALE** Pclass Sex Age SibSp Fare
3 male 22.0 1 7.2500 (I am not normalized)
**# FEMALE** Pclass Sex Age SibSp Fare
3 female 22.0 1 7.2500 (I am not normalized)
男性的存活率是 12%,女性是 58%!我们得到的两个重要值是:
Pclass Sex Age SibSp Fare
IMPORTANCE X_m:[-0.0593, **-0.1121**, -0.0010, 0.0019, -0.0040]
IMPORTANCE X_f:[-0.1178, **0.4049**, -0.0020, 0.0037, -0.0080]
正如我们在这两种情况下所看到的,在特征性中重要性是最强的(就绝对而言)。这表明这是最重要的功能!
解读符号:我们可以把它看作是增加到预测(+)或从预测(-)中扣除的东西。即+使其更可能是(1)或更不可能是(1)。
我们可以看到,根据性别(男性\女性)的不同,产生的向量也大不相同。
7.基线的影响
基线是我们用来比较自己价值的东西。为了理解它的影响,我们将比较最明显的选择。在最初的论文中,使用了噪声和黑色图像(零)的概念。
我们将比较 4 个不同的基线。
对比:
1 .平均值!
2.噪声,与随机相比
3.全是 1
4.全是零
接下来,代码将产生期望的解释。
**# define a collection** to_be_df = []
**# Compare each element of the test set to out baselines
# we will than use this**
for i in range(0,
1): # ts.__len__()):
**# load our test example**
in_val = ts.__getitem__(i)[0]
**# compare it to the 4 baselines** att_b = ig.attribute(
inputs=in_val,
baselines=ts.base,
n_steps=STEP_AMOUNT).detach().cpu().numpy()
att_r = ig.attribute(
inputs=in_val,
baselines=torch.rand(
5).cuda(),
n_steps=STEP_AMOUNT).detach().cpu().numpy()
att_z = ig.attribute(
inputs=in_val,
baselines=torch.zeros(
5).cuda(),
n_steps=STEP_AMOUNT).detach().cpu().numpy()
att_1 = ig.attribute(
inputs=in_val,
baselines=torch.ones(
5).cuda(),
n_steps=STEP_AMOUNT).detach().cpu().numpy()
**# save result, this will produce a df
# you can skip the details**
for base_type, vals in [
("mean-base", att_b),
("random-base", att_r),
("zero-base", att_z),
('one-base', att_1),
]:
for i, name in enumerate(['Pclass',
"Sex",
"Age",
"SibSp",
"Fare"]):
to_be_df.append({
"base-type": base_type,
"feature": name,
"value": vals[i],
})
**# Convert our data to a pandas** df = pd.DataFrame(to_be_df)
df.to_csv('data/interpretation_results.csv')
print("OUR INTERPRETATION:\n\n",
df)
我们的结果看起来像这样。
**base-type feature value** 0 mean-base Pclass 0.162004
1 mean-base Sex -0.159421
2 mean-base Age 0.019652
3 mean-base SibSp -0.002433
4 mean-base Fare 0.006821
5 random-base Pclass 0.117517
现在我们找到了我们要找的东西!
8.形象化
一旦我们完成了工作,我们就可以坐下来享受它了!
**# Aggregate and Visualize
# Load Data**
df = pd.read_csv('data/interpretation_results.csv')
**# Defined the color map for our heatmap to be red to green**
cmap = sns.diverging_palette(h_neg=10, h_pos=130, s=99,
l=55, sep=3, as_cmap=True)
**# Aggregate the CSV by mean**
df = df.groupby(["base-type", 'feature', 'epoch'],
as_index=False).mean()
df = df[df['epoch'] == max_epoch]
**# Make one plot per baseline to compare**
for b in ["mean-base",
"random-base",
"zero-base",
'one-base']:
**# Let's plot them isolated**
tmp = df[df['base-type'] == b]
**# Create a pivot frame**
tmp = tmp.pivot(index='base-type', columns='feature',
values='value')
print("We will plot:\n",tmp)
枢纽数据框基本上只是对相同的数据采用不同的视图。这里我们告诉它拥有索引(基本类型上的行)和“特性”上的列这看起来像这样。
**feature Age Fare Pclass Sex SibSp**
**mean-base** 0.023202 0.004757 0.116368 0.225421 0.022177
现在剩下要做的就是用
**# Create a pivot frame**
tmp = tmp.pivot(index='base-type', columns='feature',
values='value')
**# Some code to make a heatmap using seaborn** fig, ax = plt.subplots()
fig.set_size_inches(10, 2.5)
plt.title("Feature Importance ", fontsize=15)
sns.heatmap(tmp, ax=ax, cmap=cmap, annot=True)
plt.text(0, 0,
'By Sandro Luck\nTwitter:@san_sluck',
horizontalalignment='center',
verticalalignment='bottom',
fontsize=10)
plt.savefig(f'data/{b}.png')
Mean
-基地
太好了,现在我希望最后一个怀疑者也相信性是伟大的!我们可以清楚地看到,特征性别的影响是显著的。当我们查看数据集时,我们可以注意到,作为一个男人,你的死亡几率会大大增加。毕竟,“妇女和儿童优先”是他们对待船只的方式。
一垒对零垒
一垒
零基数
这里我们看到基线之间有很大的差异。如果我们将这两个基线与平均基线进行比较,我们会注意到 SibSp 的重要性发生了巨大变化。这通常应该说明使用基线(如 1 和 0)是不可取的。这样做的原因是我们要计算预测在基线和值之间的变化量。
例如,对于图像,使用 0 基线可能是有意义的。原因是,在这种情况下,黑色方块代表没有信息。
随机基数
对我来说,这一天的惊喜来自于随机基线的成功。综合梯度的作者提到使用随机基线是明智的。但是我没有预料到它在这个例子中工作得如此之好。
显示训练时间重要性的 GIF
在某些平台上让人们关注你的数据时,gif 是至关重要的。尤其是在社交媒体上,动画可以决定点击和快速浏览的区别。
由于这篇文章已经相当长了,请参考我的文章《如何用 Python 和 Seaborn 从 Google Trends 数据制作 GIFS》以闪电般的速度学习制作上面的 GIF。
结论
我们已经了解了什么是可解释性,以及如何在 PyTorch 中使用它。我们已经看到在原型制作中使用它是多么容易,以及如何将其连接到 PyTorch Lightning。
我希望这种对可解释性世界的介绍是容易的,没有痛苦的。了解您正在构建什么可以帮助我们的客户和我们。这大大增加了他们对我们预测的信心。
如果你喜欢这篇文章,我会很高兴在 Twitter 或 LinkedIn 上联系你。
一定要看看我的 YouTube 频道,我每周都会在那里发布新视频。
整个代码