教你如何用Python上传日志并监控告警

在我们的日常生活工作中,经常会遇到需要上传日志的场景,比如多台机器运行同一个程序,并且需要记录每台机器程序产生的日志,根据相关关键词告警,或者进行无数据告警,如果自己搭建这套系统需要耗费不少时间,因此如果能使用市面上现成的系统会很方便。

本文将教你如何通过阿里云日志服务搭建一套通过Python上传日志、配置日志告警的监控服务。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install aliyun-log-python-sdk

接下来,登陆阿里云控制台,进入日志应用,通过下面的步骤创建日志Project和Logstore:

点击Python – SDK 写入,再根据你的需要创建Project和Logstore:

随后会进入这个页面,直接点击确定即可:

2.使用阿里云SDK上传Python日志

为了使用阿里云SDK上传日志,我们需要先获取Access Token, 将鼠标移动到右上角头像上点击AccessKey管理:

然后点击创建AccessKey,输入相关验证信息就能获取 accessKeyId 和 accessKey:

编写Python代码,配置AccessKey和你在第一步骤创建的Project及logstore名称:

from aliyun.log import LogClient, PutLogsRequest, LogItem, GetLogsRequest, IndexConfig
import time

# 配置AccessKey、服务入口、Project名称、Logstore名称等相关信息。
# 阿里云访问密钥AccessKey。更多信息,请参见访问密钥。
# 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维。
accessKeyId = "你的AccessKey ID"
accessKey = "你的AccessKey"
# 日志服务的域名。更多信息,请参见服务入口。此处以广州为例,其它地域请根据实际情况填写。
endpoint = "cn-guangzhou.log.aliyuncs.com"

# 创建日志服务Client。
client = LogClient(endpoint, accessKeyId, accessKey)

# Project名称。
project_name = "aliyun-test-project"
#Logstore名称
logstore_name = "aliyun-test-logstore"
# 查询语句。
query = "*| select dev,id from " + logstore_name
# from_time和to_time表示查询日志的时间范围,Unix时间戳格式。
from_time = int(time.time()) - 3600
to_time = time.time() + 3600

然后我们就可以编写Python代码创建索引(日志的索引可以理解为MySQL中的数据库)和插入日志了:

# 向Logstore写入数据。
def put_logs():
    print("ready to put logs for %s" % logstore_name)
    log_group = []
    for i in range(0, 100):
        log_item = LogItem()
        contents = [
            ('dev', 'test_put'),
            ('id', str(i))
        ]
        log_item.set_contents(contents)
        log_group.append(log_item)
    request = PutLogsRequest(project_name, logstore_name, "", "", log_group, compress=False)
    client.put_logs(request)
    print("put logs for %s success " % logstore_name)
    time.sleep(5)

if __name__ == '__main__':
    # 向Logstore写入数据。
    put_logs()

运行程序后出现对应的提示,说明日志上传成功:

python test.py
# ready to put logs for tradingview
# put logs for tradingview success 

进入控制台对应的Project,你会看到刚刚上传的日志已经显示在上面:

3.配置日志告警

日志告警的配置也非常简单,输入你的查询条件,获得输出后点击上方另存为告警:

在查询统计中添加你需要监控并触发告警的条件,比如我设置出现一次该日志的时候触发告警:

效果如下,我这里文本配置得太简单了,你也可以在标注中配置复杂一点的文本:

用起来挺方便的,如果你有类似的多机器日志监控服务,比如分布式模型训练监控、交易服务监控等等,可以考虑使用这个日志服务。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

Pyintervals 解决你的阈值判断问题

Pyintervals 是一个用于数值区间计算的模块,比如我们想要判断一个数值是否处于一个、或者一系列区间范围内,就可以使用Pyintervals模块取缔IF-ELSE语句以达到简化代码的目的。

如果你想一次性生成上千个区间阈值并进行数值区间判断,比如根据数值生成成百上千个分类,那么这个模块就是你的最佳选择。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install pyinterval

2.基本使用

使用Pyinterval做区间判断是非常简单的:

from interval import interval
a = interval[1,5]
# interval([1.0, 5.0])
print(3 in a)
# True

此外,你还可以构建一个多区间:

from interval import interval
a = interval([0, 1], [2, 3], [10, 15])
print(2.5 in a)
# True

interval.hall 方法还可以将多个区间合并,取其最小及最大值为边界:

from interval import interval
a = interval.hull((interval[1, 3], interval[10, 15], interval[16, 2222]))
# interval([1.0, 2222.0])
print(1231 in a)
# True

区间并集计算:

from interval import interval
a = interval.union([interval([1, 3], [4, 6]), interval([2, 5], 9)])
# interval([1.0, 6.0], [9.0])
print(5 in a)
# True
print(8 in a)
# False

3.生成多个阈值区间

如果你在做深度学习训练分类任务,你的分类数量比较多,达到了上百个,请不要傻傻地使用IF-ELSE, 下面教你使用四行代码生成上百个阈值区间。

假设你的值区间分布在0,1之间,每个阈值范围为0.005,并有正负两个方向。下面这4行代码就能非常简单地实现你想要的区间阈值:

from interval import interval
import numpy as np
threshold_list = np.arange(0.0, 1.0, 0.005)
intervals = [interval([threshold_list[i - 1], threshold_list[i]]) for i in range(1, len(threshold_list))]
intervals += [interval([-threshold_list[i], -threshold_list[i - 1]]) for i in range(len(threshold_list) - 1, 0, -1)]
print(len(intervals))
# 398
print(intervals[0], intervals[-1])
# interval([0.0, 0.005]) interval([-0.005, -0.0])

有了这个阈值,区间,你想要画分类就非常简单了,下面是一个简单示例,实际工作中要因不同应用场景改变使用方式。

target = 0.023
class_labels = {}
for index, interval_ in enumerate(intervals):
    if target in interval_:
        class_labels[target] = index

Pyintervals对于正在做大规模分类任务的同学而言是非常好用的模块,建议有需要的朋友可以试一试。其他同学也可以收藏点赞记录一下,说不定未来也会有应用场景呢!

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

程序员延寿指南

原文:https://github.com/geekan/HowToLiveLonger

术语

  • ACM: All-Cause Mortality / 全因死亡率

目标

  • 稳健的活得更久

关键结果

  • 降低66.67%全因死亡率
  • 增加~20年预期寿命
  • 维持多巴胺于中轴

分析

  • 主要参考:对ACM的学术文献相对较多,可以作为主要参考
  • 增加寿命与ACM关系非线性:显然增加寿命与ACM关系是非线性函数,这里假设 DeltaLifeSpan=(1/(1-ACM)-1)*10
  • 变量无法简单叠加:显然各个变量之间并不符合独立同分布假设,变量之间的实际影响也并不明确
  • 存在矛盾观点:所有的证据都有文献/研究对应,但注意到:有些文献之间有显著矛盾的观点(如对于碳水摄入比例的矛盾);有些文献存在较大争议(如认为22点前睡觉会提升43%全因死亡率)
  • 研究仅表达相关:所有文献表明的更多是相关而非因果,在阅读时要考虑文献是否充分证明了因果 —— 如某文献表明了日均>=7000步的人有显著低的全因死亡率。但步数少的人可能包含更多长期病患,如果没有合理的排除这块数据,那此文献调查失真

行动

  • 输入
    • 固体:吃白肉(-3%~-11% ACM)、蔬果为主(-17%~-26% ACM),多吃辣(-23% ACM),多吃坚果(-4%~-27% ACM),少吃蛋黄(否则+7% ACM/0.5颗/天),中量碳水、多吃植物蛋白(-10% ACM)
    • 液体:喝咖啡(-12%~-22% ACM),喝牛奶(-10%~-17% ACM),喝茶(-8%~15% ACM),少喝或不喝甜味饮料(否则每天一杯+7% ACM,+多巴胺),戒酒或每周100g(纯酒精量(g)=饮酒量(ml)×酒精浓度(%)×酒精密度0.8g/ml)内(否则+~50% ACM,无上限)
    • 气体:不吸烟(否则+~50% ACM,-11~-12年寿命)
    • 光照:晒太阳(-~40% ACM)
    • 药物:二甲双胍(糖尿病人相比正常人可以+3年)、复合维生素(-8%癌症风险)、亚精胺(-30%~-60% ACM)、葡萄糖胺(-39% ACM)
  • 输出
    • 运动:每周3次45分钟挥拍运动(-47% ACM)
    • 日常:刷牙(-25% ACM)
    • 睡眠:每天睡7小时全因死亡率最低;且22-24点间最好,早睡+43% ACM,晚睡+15% ACM
  • 上下文
    • 体重:减肥(-54% ACM)

证据

输入

固体
  • 热量限制
    • 怎么看待BBC《进食、断食与长寿》?
      • 限制卡路里动物实验:CR(热量限制,即少吃)延迟了恒河猴的多种疾病发病和死亡率,与CR动物相比,正常喂养的猴子的各种疾病患病风险增加2.9倍,死亡风险增加3.0倍。
  • 综合
    • 最强营养搭配!BMJ:这么吃,心血管疾病和死亡风险更低
      • 通过对这些参与者的数据进行分析,研究人员发现碳水化合物(糖、淀粉和纤维)和蛋白质的摄入与全因死亡率呈非线性关系,而脂肪则与全因死亡率呈线性相关。其中,较高的糖分摄入与全因死亡风险和患心血管疾病的风险较高均有关联,而较高的饱和脂肪酸摄入与全因死亡风险较高有关。
      • 图1:各种营养元素与全因死亡之间的关系
  • 图2:各种营养元素与心血管疾病之间的关系
    • 进一步研究表明,在所有的饮食模式中,全因死亡率风险最低的饮食方式为:10-30g高纤维、14-30%蛋白质、10-25%单不饱和脂肪酸、5%-7%多不饱和脂肪酸以及20%-30%淀粉摄入。
    • 最优能量来源配比:<24%淀粉,15%-17%蛋白质,>15%单不饱和脂肪酸,<15%糖,6%饱和脂肪酸,6%多不饱和脂肪酸,30g+高纤维
液体

气体
  • 吸烟
    • 即使是低强度吸烟,也增加死亡风险!
      • 研究发现:在42 416名男性和86 735名女性(年龄在35-89岁之间,以前没有患病)中,18 985名男性(45%)和18 072名女性(21%)目前吸烟,其中33%的男性吸烟者和39%的女性吸烟者并不每天吸烟。8866名男性(21%)和53 912名女性(62%)从不吸烟。在随访期间,与从不吸烟相比,每天<10支烟或每天≥10支烟的全因死亡率危险比分别为1.17(95%置信区间1.10-1.25)和1.54(1.42-1.67)。无论年龄或性别,危险比相似。与每日吸烟关系最密切的疾病是呼吸道癌症、慢性阻塞性肺病和胃肠道及血管疾病。在招募时已经戒烟的人的死亡率低于现在每天吸烟者。
      • 吸烟者平均减少寿命11-12年
    • 吸烟让人过瘾是什么原理?有节制的吸烟依旧有害吗?
光照
药物
  • 复合维生素
  • 葡萄糖胺
    • 神奇!氨糖降低心血管死亡率65%,与定期运动效果相当
    • 美国西弗吉尼亚大学最新研究发现 氨糖(软骨素) 可以降低心血管死亡率65%,降低总体死亡率39%,效果与坚持定期运动相对
    • 该研究使用1999年至2010年,16,686名成年人的国家健康和营养检查(NHANES)数据,参与者的中位追踪时间为107个月,而其中有648位参与者定期且每服用日500-1000毫克的葡萄糖胺/软骨素一年以上。
  • 亚精胺
    • Science:科学背书!从精液中发现的亚精胺,竟然有着抗衰老、抗癌、保护心血管和神经、改善肥胖和2型糖尿病等逆天神效
    • 亚精胺是最容易从人体肠道吸收的多胺。许多的食物中都含有大量的亚精胺,例如新鲜的青椒、小麦胚芽、花椰菜、西兰花、蘑菇和各种奶酪,尤其在纳豆等大豆制品、香菇和榴莲中含量更高。在本实验中,研究人员选择了829位年龄在45-84岁之间的参与者进行了为期20年的随访,分析了饮食中亚精胺摄入量与人类死亡率之间的潜在关联。
    • 研究发现,女性的亚精胺摄入量高于男性,并且摄入量都会随着年龄的增长而下降。亚精胺的主要来源是全谷物(占13.4%)、苹果和梨(占13.3%)、沙拉(占9.8%)、芽菜(占7.3%)和马铃薯(占6.4%)。研究根据亚精胺摄入量将人群分为三组,低摄入量组(<62.2 µmol / d)、中摄入量组(62.2–79.8 µmol / d)和高摄入量组(> 79.8 µmol / d)。随访期间共记录了341例死亡,其中血管疾病137例,癌症94例,其他原因110例。经计算低中高三组的粗略死亡率分别为40.5%、23.7%和15.1%,这些数据表明亚精胺摄入量与全因死亡率之间的负相关关系显著。随着逐步对年龄、性别和热量的比例进行调整,这种相关关系依然显著。
  • 综合

输出

挥拍运动
走路
刷牙
泡澡
  • 定期洗澡降低心血管疾病发作风险
    • 与每周一至两次泡澡或根本不泡澡相比,每天洗热水澡可以降低28%的心血管疾病总风险,降低26%的中风总风险,脑出血风险下降46%。而浴缸浴的频率与心源性猝死的风险增加无关。
做家务(老年男性)
  • Housework Reduces All-Cause and Cancer Mortality in Chinese Men
    • 72岁之后男性每周做重型家务可以减少29%平均死亡率
    • 重型家务:吸尘、擦地板、拖地、擦洗窗户、洗车、搬动家具、搬煤气罐等等。
    • 轻型家务:掸灰尘、洗碗、手洗衣服、熨烫、晾衣服、做饭、买日用品等等。
睡眠

上下文

情绪
  • 悲观情绪与更高的全因死亡率和心血管疾病死亡率有关,但乐观情绪并不能起到保护作用
    • 在1993-1995年间,一项针对50岁以上澳大利亚人健康的双胞胎研究中包括了生活取向测试(LOT),其中包含乐观和悲观的项目。平均20年后,参与者与来自澳大利亚国家死亡指数的死亡信息相匹配。在2,978名具有很多可用分数的参与者中,有1,068人死亡。生存分析测试了各种乐观因素和悲观情绪分数与任何原因,癌症,心血管疾病或其他已知原因的死亡率之间的关联。年龄调整后的悲观量表上的核心与全因和心血管疾病死亡率相关(每1个标准差单位的危险比,95%置信区间和p值1.134、1.065–1.207、8.85×10 –5和1.196、1.045–1.368、0.0093 ),但不会因癌症死亡。乐观得分与悲观得分之间的相关性很弱(年龄调整后的等级相关系数= − 0.176),但与总死亡率或特定原因死亡率没有显着相关性。反向因果关系(引起悲观情绪的疾病)是不可能的,因为在那种情况下,心血管疾病和癌症都会导致悲观情绪。
贫富
  • JAMA子刊:贫富差距真能影响寿命?这可能是真的!
    • 该研究使用1994-1996年第一次收集的数据,并通过生存模型来分析净资产和长寿之间的关联。结果显示,共收纳5414 名参与者,平均年龄为 46.7岁,包括 2766 名女性。较高的净资产与较低的死亡风险相关。特别是在兄弟姐妹和双胞胎中(n = 2490),在较高的净资产和较低的死亡率之间观察到类似的关联,表明拥有更多财富的兄弟姐妹或双胞胎比拥有更少财富的兄弟姐妹/双胞胎活得更久。
体重
  • JAMA子刊:减肥要趁早,才能有效降低死亡率风险
    • 对体重减轻的死亡率风险评估发现,体重从肥胖减轻到超重的成年人与稳定肥胖人群相比,全因死亡率降低了54%(危险比为0.46),然而从成年初期的超重减轻到中年以前的正常体重的人群的死亡率风险并未降低(风险比为1.12)。
新冠

这个神奇的库,可以将数据平滑化并找到异常点

在处理数据的时候,我们经常会遇到一些非连续的散点时间序列数据:

有些时候,这样的散点数据是不利于我们进行数据的聚类和预测的。因此我们需要把它们平滑化,如下图所示:

将散点都去除,平滑后的效果如下:

​这样的时序数据是不是看起来舒服多了?​此外,使用平滑后的时序数据去做聚类或预测或许有令人惊艳的效果,因为它去除了一些偏差值并细化了数据的分布范围。

如果我们自己开发一个这样的平滑工具,会耗费不少的时间。​因为平滑的技术有很多种,你需要一个个地去研究,找到最合适的技术并编写代码,这是一个非常耗时的过程。平滑技术包括但不限于:

  • 指数平滑
  • 具有各种窗口类型(常数、汉宁、汉明、巴特利特、布莱克曼)的卷积平滑
  • 傅立叶变换的频谱平滑
  • 多项式平滑
  • 各种样条平滑(线性、三次、自然三次)
  • 高斯平滑
  • 二进制平滑

所幸,有大佬已经为我们实现好了时间序列的这些平滑技术,并在GitHub上开源了这份模块的代码——它就是 tsmoothie。

下面就让我们来试一下 tsmoothie.

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install tsmoothie

PS, Tsmoothie仅支持Python 3.6 及以上的版本。

2.Tsmoothie 基本使用

为了尝试Tsmoothie的效果,我们需要生成随机数据:

import numpy as np
import matplotlib.pyplot as plt
from tsmoothie.utils_func import sim_randomwalk
from tsmoothie.smoother import LowessSmoother

# 生成 3 个长度为200的随机数据组
np.random.seed(123)
data = sim_randomwalk(n_series=3, timesteps=200, 
                      process_noise=10, measure_noise=30)

然后使用Tsmoothie执行平滑化:

# 平滑
smoother = LowessSmoother(smooth_fraction=0.1, iterations=1)
smoother.smooth(data)

通过 smoother.smooth_data 你就可以获取平滑后的数据:

print(smoother.smooth_data)
# [[   5.21462928    3.07898076    0.93933646   -1.19847767   -3.32294934 
#     -5.40678762   -7.42425709   -9.36150892  -11.23591897  -13.05271523 
#      .......       .......       .......      .......       .......   ]]

绘制效果图:

# 生成范围区间
low, up = smoother.get_intervals('prediction_interval')

plt.figure(figsize=(18,5))

for i in range(3):
    
    plt.subplot(1,3,i+1)
    plt.plot(smoother.smooth_data[i], linewidth=3, color='blue')
    plt.plot(smoother.data[i], '.k')
    plt.title(f"timeseries {i+1}"); plt.xlabel('time')

    plt.fill_between(range(len(smoother.data[i])), low[i], up[i], alpha=0.3)

3.基于Tsmoothie的极端异常值检测

事实上,基于smoother生成的范围区域,我们可以进行异常值的检测:

可以看到,在蓝色范围以外的点,都属于异常值。我们可以轻易地将这些异常值标红或记录,以便后续的处理。

_low, _up = smoother.get_intervals('sigma_interval', n_sigma=2)
series['low'] = np.hstack([series['low'], _low[:,[-1]]])
series['up'] = np.hstack([series['up'], _up[:,[-1]]])
is_anomaly = np.logical_or(
    series['original'][:,-1] > series['up'][:,-1], 
    series['original'][:,-1] < series['low'][:,-1]
).reshape(-1,1)

假设蓝色范围interval的最大值为up、最小值为low,如果存在 data > up 或 data < low 则表明此数据是异常点。

使用以下代码通过滚动数据点进行平滑化和异常检测,就能保存得到上方的GIF动图。

# https://github.com/cerlymarco/MEDIUM_NoteBook/blob/master/Anomaly_Detection_RealTime/Anomaly_Detection_RealTime.ipynb

import numpy as np
import matplotlib.pyplot as plt
from celluloid import Camera
from collections import defaultdict
from functools import partial
from tqdm import tqdm

from tsmoothie.utils_func import sim_randomwalk, sim_seasonal_data
from tsmoothie.smoother import *


def plot_history(ax, i, is_anomaly, window_len, color='blue', **pltargs):
    
    posrange = np.arange(0,i)
    
    ax.fill_between(posrange[window_len:], 
                    pltargs['low'][1:], pltargs['up'][1:], 
                    color=color, alpha=0.2)
    if is_anomaly:
        ax.scatter(i-1, pltargs['original'][-1], c='red')
    else:
        ax.scatter(i-1, pltargs['original'][-1], c='black')
    ax.scatter(i-1, pltargs['smooth'][-1], c=color)
    
    ax.plot(posrange, pltargs['original'][1:], '.k')
    ax.plot(posrange[window_len:], 
            pltargs['smooth'][1:], color=color, linewidth=3)
    
    if 'ano_id' in pltargs.keys():
        if pltargs['ano_id'].sum()>0:
            not_zeros = pltargs['ano_id'][pltargs['ano_id']!=0] -1
            ax.scatter(not_zeros, pltargs['original'][1:][not_zeros], 
                       c='red', alpha=1.)

np.random.seed(42)

n_series, timesteps = 3, 200

data = sim_randomwalk(n_series=n_series, timesteps=timesteps, 
                      process_noise=10, measure_noise=30)

window_len = 20

fig = plt.figure(figsize=(18,10))
camera = Camera(fig)

axes = [plt.subplot(n_series,1,ax+1) for ax in range(n_series)]
series = defaultdict(partial(np.ndarray, shape=(n_series,1), dtype='float32'))

for i in tqdm(range(timesteps+1), total=(timesteps+1)):
    
    if i>window_len:
    
        smoother = ConvolutionSmoother(window_len=window_len, window_type='ones')
        smoother.smooth(series['original'][:,-window_len:])

        series['smooth'] = np.hstack([series['smooth'], smoother.smooth_data[:,[-1]]]) 

        _low, _up = smoother.get_intervals('sigma_interval', n_sigma=2)
        series['low'] = np.hstack([series['low'], _low[:,[-1]]])
        series['up'] = np.hstack([series['up'], _up[:,[-1]]])

        is_anomaly = np.logical_or(
            series['original'][:,-1] > series['up'][:,-1], 
            series['original'][:,-1] < series['low'][:,-1]
        ).reshape(-1,1)
        
        if is_anomaly.any():
            series['ano_id'] = np.hstack([series['ano_id'], is_anomaly*i]).astype(int)
            
        for s in range(n_series):
            pltargs = {k:v[s,:] for k,v in series.items()}
            plot_history(axes[s], i, is_anomaly[s], window_len, 
                         **pltargs)

        camera.snap()
        
    if i>=timesteps:
        continue
    
    series['original'] = np.hstack([series['original'], data[:,[i]]])

    
print('CREATING GIF...')  # it may take a few seconds
camera._photos = [camera._photos[-1]] + camera._photos
animation = camera.animate()
animation.save('animation1.gif', codec="gif", writer='imagemagick')
plt.close(fig)
print('DONE')

注意,异常点并非都是负面作用,在不同的应用场景下,它们可能代表了不同的意义。

比如在股票中,它或许可以代表着震荡行情中某种趋势反转的信号。

或者在家庭用电量分析中,它可能代表着某个时刻的用电峰值,根据这个峰值我们可以此时此刻开启了什么样的电器。

所以异常点的作用需要根据不同应用场景进行不同的分析,才能找到它真正的价值。

总而言之,Tsmoothie 不仅可以使用多种平滑技术平滑化我们的时序数据,还可以根据平滑结果找出数据中的离群点,是我们做数据分析和研究的一个好帮手,非常有价值。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

教你用Python计算对量化交易至关重要的VWAP指标

成交量加权平均价格 (VWAP) 在金融业中是指特定时间范围内交易价值与交易总数量的比率。它具有三个重要的特点和优势,为交易者提供了对价格趋势的洞察方法。机构和交易者使用 VWAP 来识别买卖区域,并帮助衡量市场情绪。

1.为什么要用VWAP?

VWAP有三个重要的特点:

1. VWAP可以帮助我们了解市场情绪。当证券价格高于VWAP线时,市场对它是乐观看涨的。当价格低于VWAP线时,市场是悲观看跌的。这一点我们可以从下图直观地了解。

2. 许多日内交易者和大型机构投资者以及养老金计划都使用VWAP来作为衡量自己的交易是否会影响市场的重要指标。 比如机构交易者想要卖出自己重要的头寸时,他们的目标是以VWAP或更高的价格卖出。他们会用几种VWAP盘中策略来确定三件事(趋势、谁在影响价格、确定支撑位和压力位)。

3. VWAP及其与证券价格平均值(HLC)的1个标准差可以作为潜在的支撑和阻力,如下图所示。

2 如何用Python计算VWAP

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install pandas

VWAP的计算公式如下:

TP =(最高价+最低价+收盘价)/3

V = 成交量

VWAP = (TP_1 * V_1 + TP_2 * V_2 + TP_n * V_n)/n

例如,如果一只股票以 10 美元交易 1000 股,然后以 11 美元交易 100 股,则最终交易价格为 11 美元;但是,VWAP 将更接近 10:

(1000 * 10 + 100 * 11)/(1000 + 100)) = 10.09

接下来,我们制造一些假数据来准备计算VWAP:

# Get imports
import datetime
import pandas as pd

# Create example dataframe
df = pd.DataFrame(
index=[datetime.datetime(2021,1,1,1),
datetime.datetime(2021,1,1,2),
datetime.datetime(2021,1,1,3),
datetime.datetime(2021,1,1,4)],
data={
  'low':[9,10,11,12],
  'close':[10,11,12,13],
  'high':[11,12,13,14],
  'volume':[1000,750,500,250]
  }
)
df.index.rename('date', inplace=True)

数据如下:

                    low  close  high  volume
date
2021-01-01 01:00:00    9     10    11    1000
2021-01-01 02:00:00   10     11    12     750
2021-01-01 03:00:00   11     12    13     500
2021-01-01 04:00:00   12     13    14     250

VWAP的计算方法如下,这里采用了HLC(open、low、close)的平均值作为基准计算对象:

# Create VWAP function
def vwap(df):
    v = df['volume'].values
    tp = (df['low'] + df['close'] + df['high']).div(3).values
    return df.assign(vwap=(tp * v).cumsum() / v.cumsum())

vwap(df)

计算完成后会在原来的数据上添加一列vwap列:

                     low  close  high  volume       vwap
date
2021-01-01 01:00:00    9     10    11    1000  10.000000
2021-01-01 02:00:00   10     11    12     750  10.428571
2021-01-01 03:00:00   11     12    13     500  10.777778
2021-01-01 04:00:00   12     13    14     250  11.000000

验证一下:

# Verify VWAP
## 以第二行为例
(10*1000 + 11*750) / (1000+750)
10.428571 # 正确

3.VWAP的缺点

没有全能的指标,VWAP也有其自身的缺点。

1.滞后性。和其他的移动平均线一样,VWAP也是一个滞后的指标,而且随着日内交易量的累计,滞后性会越来越严重。

2.仅适用于短期图表,如秒级、分钟级。

4.VWAP 策略

我们已经知道VWAP的运行特点,那么如何利用这些特点进行交易呢?

利用其回调的特点。当股价在一天内显着超过 VWAP 和移动平均线时,它们可能会回调。你可以选择在股价大幅度上涨时卖空股票,也可以选择在回调时等待入场。

Fade策略。这个策略是一个逆势策略,它在强劲势头的运动后采取相反的立场。利用VWAP发的支撑和压力作为其入场和出场的信号。

午后走高策略。这是一个油管老哥(Tim Bohen)观察出来的策略,他发现热门股票早盘走高,并且价格持续保持在vwap上方的股票,午后走高突破的几率非常大。

当然,所有策略都应该被回测后再确定是否有效。以上策略只是一个根据VWAP做交易的思路,你还可以结合其他指标进行策略的开发和回测,有兴趣的同学可以试试看。

本文参考文章:https://analyzingalpha.com/blog/vwap

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

超美!教你用Python拍摄游戏延时摄影

这个时代,随着游戏引擎技术的快速发展,游戏画面越来越精美,许多人迷上了游戏内的角色、场景。

尤其是端游,显卡技术能够支撑精美的游戏画面,最有名的莫过于《地平线》系列游戏。

很多玩家希望拍摄这些精美游戏中的画面,尤其是希望能拍摄到游戏内不同时刻的画面,为了满足这个需求,我们就需要用上延时摄影。游戏内的时间过得比现实世界更快,一个小时内可能你就能经历白天的夜晚的变化,这也为延时摄影提供了很好的环境。

那么究竟怎么在拍摄中实现延时的效果呢?方法大致有两种,最简单的可以先录制视频,然后用后期剪辑软件或者特效软件通过丢帧的方法实现,但这样一来便造成了巨大的浪费。拍几个小时的视频,如果通过丢帧实现延时效果,最后转换为几十分钟的片段,那么被丢掉的帧就要比最后留下的多得多。如果要实现更高速的画面运动,这种浪费无疑将会被更加扩大。

本篇教程介绍第二种方法,定时截图的形式,我们将结合前面Python实用宝典使用过的三个模块——moviepy、win32gui 及 PIL 为大家讲解如何使用Python在游戏中实现延时摄影,我还将教你如何将图片拼接成视频、添加背景音乐一条龙操作。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install moviepy
pip install pypiwin32
pip install pillow

本文所有代码均开源在:https://github.com/Ckend/python-time-lapse-photo 仓库,如果你无法访问GitHub,也可以在Python实用宝典后台回复 延时摄影 下载。

2.定时”拍摄”

为了实现定时拍摄的逻辑,我们需要用到pypiwin32模块和pillow模块,在之前的这篇文章中有介绍过:

超方便的 Python 唤醒窗口自动截图脚本

分为三个步骤:

1. 获得游戏窗口界面

2. 获得游戏界面大小

3. 截图

每隔N秒定时循环执行以上三个步骤,代码如下:

# main.py
# Python实用宝典
# 2022-03-25
import time
import win32gui
from PIL import ImageGrab


def get_window_pos(name):
    name = name
    handle = win32gui.FindWindow(0, name)
    if handle == 0:
        return None
    else:
        return win32gui.GetWindowRect(handle), handle

while True:
    try:
        (x1, y1, x2, y2), handle = get_window_pos('极限竞速:地平线 4')
        win32gui.SetForegroundWindow(handle)
        img_ready = ImageGrab.grab((x1, y1, x2, y2))
        img_ready.save(f"./result/{time.time()}.jpg")
        time.sleep(5)
    except Exception as e:
        print(e)

请注意,”极限竞速:地平线 4″ 要改成你对应拍摄的游戏名称,这样,运行程序后就会自动在result文件夹下定时生成截图:

成功截取你想要的时间段的场景图片后,就可以进行下面的拼接和补充背景音乐部分。

3.拼接延时摄影视频

为了达到延时摄影的效果,我们在这一部分中将使用moviepy模块,拼接所有图片到一个视频中。

当然还要补充背景音乐,代码其实非常简单:

# jointer.py
# Python实用宝典
# 2022-03-25
import os
import moviepy
import moviepy.video.io.ImageSequenceClip
from moviepy.editor import *

def pics2video(frames_dir, video_dst, music, fps=10):
    """
    图片合成MP4

    Args:
        frames_dir (str): 图片目录
        video_dst (str): 目标目录
        fps (int, optional): 帧数. Defaults to 25.
    """
    frames_name = sorted(os.listdir(frames_dir))
    frames_path = [frames_dir+frame_name for frame_name in frames_name]
    clip = moviepy.video.io.ImageSequenceClip.ImageSequenceClip(frames_path, fps=fps)
    
    audio_clip = AudioFileClip(music).volumex(0.5)
    audio = afx.audio_loop( audio_clip, duration=clip.duration)
    final_video = clip.set_audio(audio)

    final_video.write_videofile(video_dst, codec='libx264')

music = '打上花火.mp3'
frames_dir = './result/'
video_dst = 'screenshots.mp4'
pics2video(frames_dir, video_dst, music)

1.将你的音乐放在当前目录下,修改music变量为对应的文件名。

2.调整你想要的fps参数—帧数,这个值越低,画面越顺畅。

运行此文件后就会在当前文件夹下生成 ‘screenshots.mp4’. 这个就是我们的处理结果了,双击打开试试吧。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

大规模深度学习框架 DeepSpeed 使用指南

最常见的深度学习框架应该是TensorFlow、Pytorch、Keras,但是这些框架在面向大规模模型的时候都不是很方便。

比如Pytorch的分布式并行计算框架(Distributed Data Parallel,简称DDP),它也仅仅是能将数据并行,放到各个GPU的模型上进行训练。

也就是说,DDP的应用场景在你的模型大小大于显卡显存大小时,它就很难继续使用了,除非你自己再将模型参数拆散分散到各个GPU上。

今天要给大家介绍的DeepSpeed,它就能实现这个拆散功能,它通过将模型参数拆散分布到各个GPU上,以实现大型模型的计算,弥补了DDP的缺点,非常方便,这也就意味着我们能用更少的GPU训练更大的模型,而且不受限于显存。

DeepSpeed入门并不简单,尽管是微软开源的框架,文档却写的一般,缺少条理性,也没有从零到一的使用示例。下面我就简单介绍一下怎么使用DeepSpeed这个框架。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install deepspeed

此外,你还需要下载 Pytorch,在官网选择自己对应的系统版本和环境,按照指示安装即可:

https://pytorch.org/get-started/locally/

2.使用 DeepSpeed

使用DeepSpeed其实和写一个pytorch模型只有部分区别,一开始的流程是一样的。

2.1 载入数据集:

import torch
import torchvision
import torchvision.transforms as transforms

trainset = torchvision.datasets.CIFAR10(root='./data',
                                        train=True,
                                        download=True,
                                        transform=transform)
trainloader = torch.utils.data.DataLoader(trainset,
                                          batch_size=16,
                                          shuffle=True,
                                          num_workers=2)
testset = torchvision.datasets.CIFAR10(root='./data',
                                       train=False,
                                       download=True,
                                       transform=transform)
testloader = torch.utils.data.DataLoader(testset,
                                         batch_size=4,
                                         shuffle=False,
                                         num_workers=2)

2.2 编写模型:

import torch.nn as nn
import torch.nn.functional as F


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

net = Net()
criterion = nn.CrossEntropyLoss()

这里我写了一个非常简单的模型作测试。

2.3 初始化Deepspeed

DeepSpeed 通过输入参数来启动训练,因此需要使用argparse解析参数:

import argparse


def add_argument():
    parser = argparse.ArgumentParser(description='CIFAR')
    parser.add_argument('-b',
                        '--batch_size',
                        default=32,
                        type=int,
                        help='mini-batch size (default: 32)')
    parser.add_argument('-e',
                        '--epochs',
                        default=30,
                        type=int,
                        help='number of total epochs (default: 30)')
    parser.add_argument('--local_rank',
                        type=int,
                        default=-1,
                        help='local rank passed from distributed launcher')

    parser.add_argument('--log-interval',
                        type=int,
                        default=2000,
                        help="output logging information at a given interval")

    parser = deepspeed.add_config_arguments(parser)
    args = parser.parse_args()
    return args

此外,模型初始化的时候除了参数,还需要model及其parameters,还有训练集:

args = add_argument()
net = Net()
parameters = filter(lambda p: p.requires_grad, net.parameters())
model_engine, optimizer, trainloader, __ = deepspeed.initialize(
    args=args, model=net, model_parameters=parameters, training_data=trainset)

2.4 训练逻辑

下面的部分和我们平时训练模型是几乎一样的代码,请注意 local_rank 是你不需要管的参数,在后面启动模型训练的时候,DeepSpeed会自动给这个参数赋值。

for epoch in range(2):
    running_loss = 0.0
    for i, data in enumerate(trainloader):
        inputs, labels = data[0].to(model_engine.local_rank), data[1].to(
            model_engine.local_rank)
        outputs = model_engine(inputs)
        loss = criterion(outputs, labels)
        model_engine.backward(loss)
        model_engine.step()

        # print statistics
        running_loss += loss.item()
        if i % args.log_interval == (args.log_interval - 1):
            print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / args.log_interval))
            running_loss = 0.0

2.5 测试逻辑

模型测试和模型训练的逻辑类似:

correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data
        outputs = net(images.to(model_engine.local_rank))
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels.to(
            model_engine.local_rank)).sum().item()

print('Accuracy of the network on the 10000 test images: %d %%' %
      (100 * correct / total))

2.6 编写模型参数

在当前目录下新建一个 config.json 里面写好我们的调优器、训练batch等参数:

 {
   "train_batch_size": 4,
   "steps_per_print": 2000,
   "optimizer": {
     "type": "Adam",
     "params": {
       "lr": 0.001,
       "betas": [
         0.8,
         0.999
       ],
       "eps": 1e-8,
       "weight_decay": 3e-7
     }
   },
   "scheduler": {
     "type": "WarmupLR",
     "params": {
       "warmup_min_lr": 0,
       "warmup_max_lr": 0.001,
       "warmup_num_steps": 1000
     }
   },
   "wall_clock_breakdown": false
 }

完整的开发流程就结束了,可以看到其实和我们平时使用pytorch开发模型的区别不大,就是在初始化的时候使用 DeepSpeed,并以输入参数的形式初始化。完整代码可以在Python实用宝典后台回复 Deepspeed 下载。

3. 测试代码

现在就来测试我们上面的代码能不能正常运行。

在这里,我们需要用环境变量控制使用的GPU,比如我的机器有10张GPU,我只使用6, 7, 8, 9号GPU,输入命令:

export CUDA_VISIBLE_DEVICES="6,7,8,9"

然后开始运行代码:

deepspeed test.py --deepspeed_config config.json

看到下面的输出说明开始正常运行,在下载数据了:

开始训练的时候 DeepSpeed 通常会打印更多的训练细节供用户监控,包括训练设置、性能统计和损失趋势,效果类似于:

worker-0: [INFO 2020-02-06 20:35:23] 0/24550, SamplesPerSec=1284.4954513975558
worker-0: [INFO 2020-02-06 20:35:23] 0/24600, SamplesPerSec=1284.384033658866
worker-0: [INFO 2020-02-06 20:35:23] 0/24650, SamplesPerSec=1284.4433482972925
worker-0: [INFO 2020-02-06 20:35:23] 0/24700, SamplesPerSec=1284.4664449792422
worker-0: [INFO 2020-02-06 20:35:23] 0/24750, SamplesPerSec=1284.4950124403447
worker-0: [INFO 2020-02-06 20:35:23] 0/24800, SamplesPerSec=1284.4756105952233
worker-0: [INFO 2020-02-06 20:35:24] 0/24850, SamplesPerSec=1284.5251526215386
worker-0: [INFO 2020-02-06 20:35:24] 0/24900, SamplesPerSec=1284.531217073863
worker-0: [INFO 2020-02-06 20:35:24] 0/24950, SamplesPerSec=1284.5125323220368
worker-0: [INFO 2020-02-06 20:35:24] 0/25000, SamplesPerSec=1284.5698818883018
worker-0: Finished Training
worker-0: GroundTruth:    cat  ship  ship plane
worker-0: Predicted:    cat   car   car plane
worker-0: Accuracy of the network on the 10000 test images: 57 %

当你运行到最后,出现了这样的输出,恭喜你,完成了你的第一个 DeepSpeed 模型,可以开始你的大规模训练之路了。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

Asciinema – 终端日志记录神器,机器学习开发者的福音

我们在做机器学习/深度学习开发的时候,经常会产生如下所示的大量日志:

这些日志如果不保存,转瞬即逝,当我们想要回去翻看某一轮训练日志的时候,会很遗憾的发现找不到了。

现在有了这个 Asciinema 这个神器,我们不仅能找到当时的终端日志导出,还能够“重播日志”并“分享日志”。非常牛逼:

Asciinema 是使用Python开发的工具,请按下面的流程安装并使用。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install asciinema

2.使用

终端输入如下命令,记录你的第一个终端日志:

asciinema rec first.cast

输入完成后会显示如下的提示:

(gs3_9) zjr@sgd-linux-1:~/cnn_test$ asciinema rec first.cast
  
asciinema: recording asciicast to first.cast
asciinema: press <ctrl-d> or type "exit" when you're done

意思就是日志会被保存在当前文件夹下的first.cast,如果你想结束录制,按 Ctrl + D 即可。

记录完毕后,以双倍速度重播该日志:

asciinema play -s 2 first.cast

或以正常速度但空闲时间限制为 2 秒:

asciinema play -i 2 first.cast

你也可以在启动终端日志录制时传递 -i 2 asciinema rec,将其永久设置在录制中:

asciinema rec first.cast -i 2

空闲时间的限制使录制更有趣。试试吧。

如果你想在网络上观看和分享,请上传:

asciinema upload first.cast

这个命令会将日志记录上传到 asciinema.org,此外,它会打印一个秘密链接,你可以使用该链接在网络浏览器中观看你录制的终端日志:

你可以通过省略文件名一步录制和上传终端的日志:

asciinema rec

录制完成后,系统会要求你确认上传。未经你的同意,不会向任何地方发送任何内容。

3.播放日志

查看日志有四种方式,最普通的是通过本地文件进行终端重播:

asciinema play /path/to/asciicast.cast

以下键盘快捷键可用:

  • Space– 暂停,
  • .– 按帧步进(暂停时),
  • Ctrl+C– 退出

第二种方式是通过url播放:

asciinema play https://asciinema.org/a/22124.cast
asciinema play http://example.com/demo.cast

这个方式需要你的日志已经上传到asciinema.org中。

第三种方式是通过你自己生成的html页面访问(需要<link rel="alternate" type="application/x-asciicast" href="/my/ascii.cast">在页面的 HTML 中):

asciinema play http://your_html_path/post.html

第四种方式是通过标准输入输出播放:

cat /path/to/asciicast.cast | asciinema play -
ssh user@host cat asciicast.cast | asciinema play -

可用选项:

  • -i, --idle-time-limit=<sec>– 将重播的终端空闲不动时间闲置为最大<sec>秒数
  • -s, --speed=<factor>– 播放速度

4.导出日志

导出终端日志到文本文件非常简单:

asciinema cat existing.cast > terminal_output.txt

所有的终端日志都会被导出到 terminal_output.txt 中,非常方便好用。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

NNI 一个帮你自动做机器学习调参的神器

NNI 自动机器学习调参,是微软开源的又一个神器,它能帮助你找到最好的神经网络架构或超参数,支持各种训练环境

它常用的使用场景如下:

  • 想要在自己的代码、模型中试验不同的机器学习算法
  • 想要在不同的环境中加速运行机器学习。
  • 想要更容易实现或试验新的机器学习算法的研究员或数据科学家,包括:超参调优算法,神经网络搜索算法以及模型压缩算法。

它支持的框架有:

  • PyTorch
  • Keras
  • TensorFlow
  • MXNet
  • Caffe2
  • Scikit-learn
  • XGBoost
  • LightGBM

基本上市面上所有的深度学习和机器学习的框架它都支持。

下面就来看看怎么使用这个工具。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install --upgrade nni

2.运行示例

让我们运行一个示例来验证是否安装成功,首先克隆项目:

git clone -b v2.6 https://github.com/Microsoft/nni.git

(如果你无法成功克隆项目,请在Python实用宝典后台回复nni下载项目)

运行 MNIST-PYTORCH 示例,Linux/macOS:

nnictl create --config nni/examples/trials/mnist-pytorch/config.yml

Windows:

nnictl create --config nni\examples\trials\mnist-pytorch\config_windows.yml

出现这样的界面就说明安装成功,示例运行正常:

访问 http://127.0.0.1:8080 可以配置运行时间、实验次数等:

3.模型自动调参配置

那么如何让它和我们自己的模型适配呢?

观察 config_windows.yaml 会发现:

searchSpaceFile: search_space.json
trialCommand: python mnist.py
trialGpuNumber: 0
trialConcurrency: 1
tuner:
  name: TPE
  classArgs:
    optimize_mode: maximize
trainingService:
  platform: local

我们先看看 trialCommand, 这很明显是训练使用的命令,训练代码位于 mnist.py,其中有部分代码如下:

def get_params():
    # Training settings
    parser = argparse.ArgumentParser(description='PyTorch MNIST Example')
    parser.add_argument("--data_dir", type=str,
                        default='./data', help="data directory")
    parser.add_argument('--batch_size', type=int, default=64, metavar='N',
                        help='input batch size for training (default: 64)')
    parser.add_argument("--batch_num", type=int, default=None)
    parser.add_argument("--hidden_size", type=int, default=512, metavar='N',
                        help='hidden layer size (default: 512)')
    parser.add_argument('--lr', type=float, default=0.01, metavar='LR',
                        help='learning rate (default: 0.01)')
    parser.add_argument('--momentum', type=float, default=0.5, metavar='M',
                        help='SGD momentum (default: 0.5)')
    parser.add_argument('--epochs', type=int, default=10, metavar='N',
                        help='number of epochs to train (default: 10)')
    parser.add_argument('--seed', type=int, default=1, metavar='S',
                        help='random seed (default: 1)')
    parser.add_argument('--no_cuda', action='store_true', default=False,
                        help='disables CUDA training')
    parser.add_argument('--log_interval', type=int, default=1000, metavar='N',
                        help='how many batches to wait before logging training status')


    args, _ = parser.parse_known_args()
    return args

如上所示,这个模型里提供了 10 个参数选择。也就是说 NNI 可以帮我们自动测试这10个参数。

那么这些参数在哪里设定?答案是在 searchSpaceFile 中,对应的值也就是 search_space.json:

{
    "batch_size": {"_type":"choice", "_value": [16, 32, 64, 128]},
    "hidden_size":{"_type":"choice","_value":[128, 256, 512, 1024]},
    "lr":{"_type":"choice","_value":[0.0001, 0.001, 0.01, 0.1]},
    "momentum":{"_type":"uniform","_value":[0, 1]}
}

这里有4个选项,NNI 是怎么组合这些参数的呢?这就是tuner参数干的事,为了让机器学习和深度学习模型适应不同的任务和问题,我们需要进行超参数调优,而自动化调优依赖于优秀的调优算法。NNI 内置了先进的调优算法,并且提供了易于使用的 API。

在 NNI 中,调优算法被称为“tuner”。Tuner 向 trial 发送超参数,接收运行结果从而评估这组超参的性能,然后将下一组超参发送给新的 trial。

下表简要介绍了 NNI 内置的调优算法。

Tuner算法简介
TPETree-structured Parzen Estimator (TPE) 是一种基于序列模型的优化方法 (sequential model-based optimization, SMBO)。SMBO方法根据历史数据来顺序地构造模型,从而预估超参性能,并基于此模型来选择新的超参。参考论文
Random Search (随机搜索)随机搜索在超算优化中表现出了令人意外的性能。如果没有对超参分布的先验知识,我们推荐使用随机搜索作为基线方法。参考论文
Anneal (退火)朴素退火算法首先基于先验进行采样,然后逐渐逼近实际性能较好的采样点。该算法是随即搜索的变体,利用了反应曲面的平滑性。该实现中退火率不是自适应的。
Naive Evolution(朴素进化)朴素进化算法来自于 Large-Scale Evolution of Image Classifiers。它基于搜索空间随机生成一个种群,在每一代中选择较好的结果,并对其下一代进行变异。朴素进化算法需要很多 Trial 才能取得最优效果,但它也非常简单,易于扩展。参考论文
SMACSMAC 是基于序列模型的优化方法 (SMBO)。它利用使用过的最突出的模型(高斯随机过程模型),并将随机森林引入到SMBO中,来处理分类参数。NNI 的 SMAC tuner 封装了 GitHub 上的 SMAC3参考论文注意:SMAC 算法需要使用 pip install nni[SMAC] 安装依赖,暂不支持 Windows 操作系统。
Batch(批处理)批处理允许用户直接提供若干组配置,为每种配置运行一个 trial。
Grid Search(网格遍历)网格遍历会穷举搜索空间中的所有超参组合。
HyperbandHyperband 试图用有限的资源探索尽可能多的超参组合。该算法的思路是,首先生成大量超参配置,将每组超参运行较短的一段时间,随后抛弃其中效果较差的一半,让较好的超参继续运行,如此重复多轮。参考论文
Metis大多数调参工具仅仅预测最优配置,而 Metis 的优势在于它有两个输出:(a) 最优配置的当前预测结果, 以及 (b) 下一次 trial 的建议。大多数工具假设训练集没有噪声数据,但 Metis 会知道是否需要对某个超参重新采样。参考论文
BOHBBOHB 是 Hyperband 算法的后续工作。 Hyperband 在生成新的配置时,没有利用已有的 trial 结果,而本算法利用了 trial 结果。BOHB 中,HB 表示 Hyperband,BO 表示贝叶斯优化(Byesian Optimization)。 BOHB 会建立多个 TPE 模型,从而利用已完成的 Trial 生成新的配置。参考论文
GP (高斯过程)GP Tuner 是基于序列模型的优化方法 (SMBO),使用高斯过程进行 surrogate。参考论文
PBTPBT Tuner 是一种简单的异步优化算法,在固定的计算资源下,它能有效的联合优化一组模型及其超参来最优化性能。参考论文
DNGODNGO 是基于序列模型的优化方法 (SMBO),该算法使用神经网络(而不是高斯过程)去建模贝叶斯优化中所需要的函数分布。

可以看到示例中,选择的是TPE tuner.

其他的参数比如 trialGpuNumber,指的是使用的gpu数量,trialConcurrency 指的是并发数。trainingService 中 platform 为 local,指的是本地训练。

当然,还有许多参数可以选,比如:

trialConcurrency: 2                 # 同时运行 2 个 trial
maxTrialNumber: 10                  # 最多生成 10 个 trial
maxExperimentDuration: 1h           # 1 小时后停止生成 trial

不过这些参数在调优开始时的web页面上是可以进行调整的。

所以其实NNI干的事情就很清楚了,也很简单。你只需要在你的模型训练文件中增加你想要调优的参数作为输入,就能使用NNI内置的调优算法对不同的参数进行调优,而且允许从页面UI上观察调优的整个过程,相对而言还是很方便的。

不过,NNI可能不太适用一些数据量极大或模型比较复杂的情况。比如基于DDP开发的模型,在NNI中可能无法实现大型的分布式计算。

当然,绝大多数情况下的训练任务,NNI都可以用得上。大家有兴趣深入使用的可以阅读NNI官方文档:https://nni.readthedocs.io/

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

超级安全!Python 合成多张图片到PDF格式

在日常生活中,经常会遇到需要提交身份证正反面证明资料的情况,而且这些网站大部分只接受pdf格式,这时候我们就需要把身份证正反面两张图片合成为一个pdf文件。

在macOS系统下,预览软件可以轻松做到这一点,同时打开图片到一个预览窗口下,点击导出PDF就能成功导出。但是Windows系统就没有这么方便的软件可以实现这一点,网上有很多合成PDF的网站,但是这些网站无一例外需要上传PDF进行合成,个人认为非常地不安全。

因此,最安全的方法,还是我们自己写一个Python脚本实现合成功能。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install pillow

2.合成原理

Pillow模块,即PIL:Python Imaging Library,已经是Python平台事实上的图像处理标准库了。PIL功能非常强大,但API却非常简单易用。通过它,我们能很轻松地操作图像,并导出为不同格式。

首先来一个简单的示例,我们将打开一张图片,并将其保存为pdf格式:

from PIL import Image
import os


def convert_img_pdf(filepath, output_path):
    """
    转换图片为pdf格式

    Args:
        filepath (str): 文件路径
        output_path (str): 输出路径
    """
    output = Image.open(filepath)
    output.save(output_path, "pdf", save_all=True)
    
    
if __name__ == "__main__":
    convert_img_pdf("1.jpeg", "./test.pdf")

随便使用一张图片测试一下:

在运行代码后,它便成功地转化为了PDF文件:

几行代码便完成了这个转换,这个可比那些把照片上传到云端的网站安全多了。

3.多张照片合成PDF

有了前面照片转化PDF的基础知识,想要理解下面的多图合成PDF的代码就非常简单了。

其实就是使用了.save的一个特殊参数 append_images:

output.save(pdfFilePath, "pdf", save_all=True, append_images=sources)

通过把图片都存入到一个”sources”数组中,我们就能很轻易地合成这些图像到PDF中。

from PIL import Image
import os

def combine_imgs_pdf(folder_path, pdf_file_path):
    """
    合成文件夹下的所有图片为pdf

    Args:
        folder_path (str): 源文件夹
        pdf_file_path (str): 输出路径
    """
    files = os.listdir(folder_path)
    png_files = []
    sources = []
    for file in files:
        if 'png' in file or 'jpg' in file:
            png_files.append(folder_path + file)
    png_files.sort()

    output = Image.open(png_files[0])
    png_files.pop(0)
    for file in png_files:
        png_file = Image.open(file)
        if png_file.mode == "RGB":
            png_file = png_file.convert("RGB")
        sources.append(png_file)
    output.save(pdf_file_path, "pdf", save_all=True, append_images=sources)

if __name__ == "__main__":
    folder = r"G:\证件\\"
    pdfFile = r"G:\证件\身份证.pdf"
    combine_imgs_pdf(folder, pdfFile)

这样,只要将你的证件照都放在一个文件夹中,运行这个Python代码,它就能自动将这些证件合成到一个PDF中,并输出到你指定的路径。非常简单方便。

有需要的小伙伴,刚开那这份代码去试一下吧!在Python实用宝典后台回复 合成pdf 就能下载啦!

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

有趣好用的Python教程

退出移动版