• (PyTorch)使用 LSTM 预测时间序列(股票)

    目标

    学习使用 LSTM 来预测时间序列,本文中使用上证指数的收盘价。

    运行环境

    Python 3.5+, PyTorch 1.1.0, tushare

    数据获取与处理

    首先用 tushare 下载上证指数的K线数据,然后作标准化处理。

    import numpy as np
    import tushare as ts
    
    data_close = ts.get_k_data('000001', start='2018-01-01', index=True)['close'].values  # 获取上证指数从20180101开始的收盘价的np.ndarray
    data_close = data_close.astype('float32')  # 转换数据类型
    
    # 将价格标准化到0~1
    max_value = np.max(data_close)
    min_value = np.min(data_close)
    data_close = (data_close - min_value) / (max_value - min_value)
    原始数据:上证指数从2018-01-01到2019-05-24的收盘价(未标准化处理)

    把K线数据进行分割,每 DAYS_FOR_TRAIN 个收盘价对应 1 个未来的收盘价。例如K线为 [1,2,3,4,5], DAYS_FOR_TRAIN=3,那么将会生成2组数据:
    第1组的输入是 [1,2,3],对应输出 4;
    第2组的输入是 [2,3,4],对应输出 5。

    然后只使用前70%的数据用于训练,剩下的不用,用来与实际数据进行对比。

    DAYS_FOR_TRAIN = 10
    
    def create_dataset(data, days_for_train=5) -> (np.array, np.array):
        """
            根据给定的序列data,生成数据集
            
            数据集分为输入和输出,每一个输入的长度为days_for_train,每一个输出的长度为1。
            也就是说用days_for_train天的数据,对应下一天的数据。
    
            若给定序列的长度为d,将输出长度为(d-days_for_train+1)个输入/输出对
        """
        dataset_x, dataset_y= [], []
        for i in range(len(data)-days_for_train):
            _x = data[i:(i+days_for_train)]
            dataset_x.append(_x)
            dataset_y.append(data[i+days_for_train])
        return (np.array(dataset_x), np.array(dataset_y))
    
    dataset_x, dataset_y = create_dataset(data_close, DAYS_FOR_TRAIN)
    
    # 划分训练集和测试集,70%作为训练集
    train_size = int(len(dataset_x) * 0.7)
    
    train_x = dataset_x[:train_size]
    train_y = dataset_y[:train_size]
    
    # 将数据改变形状,RNN 读入的数据维度是 (seq_size, batch_size, feature_size)
    train_x = train_x.reshape(-1, 1, DAYS_FOR_TRAIN)
    train_y = train_y.reshape(-1, 1, 1)
    
    # 转为pytorch的tensor对象
    train_x = torch.from_numpy(train_x)
    train_y = torch.from_numpy(train_y)
    阅读更多…
  • 在 Google 云搭建深度学习平台

    大家都知道,Google有一个很方便的 Colab ,而且到目前为止,还是免费的,并且 GPU 和 TPU 也是免费的。那为什么还要自己搞呢?因为 Colab 每个 session 只能用12小时,之后环境和数据不会保留,并且也不能进一步自定义配置和性能。Google 云给新注册的用户提供了$300 USD的赠金,非常适合学生党和个人的小项目。下面就开始体验吧。

    创建用户

    如果还没有 Google Cloud 用户,前往 Google Cloud 注册一个。这里需要一张 Visa / Mastercard 信用卡,没有的话我也帮不了你..然后$300 USD额度就到手了。

    申请 GPU 额度

    一开始的用户是没有 GPU 额度的,就算创建了带 GPU 的实例,也不能启动。请参照申请提升配额的步骤提交申请,把 GPU 的 0 改为更大的数值。在此之前,平台应该会让你把用户升级为付费账号,也就是说,如果送的额度用完了,就会从你的信用卡扣钱(注意要省着用了)。申请提升配额的页面中写可能要一两天来处理申请,但是我提交之后一小时内就批了。

    阅读更多…
  • 使用 Z3 Solver 求解逻辑题

    Z3 是一个由 Microsoft Research 开发的定理求解器。它可以用在很多方面,如软/硬件的验证与测试、约束求解、混合系统的分析、安全、生物,以及求解几何等问题[1]。Z3 主要由 C++ 开发,但它支持被 .NET、C、C++、Java、Python 等语言调用。本文使用其 Python binding。

    在网上看到有不少解方程和约束条件的使用,我在此补充它在命题逻辑方面的例子。

    安装

    非Windows平台可尝试直接安装:

    pip install z3-solver

    Windows平台由于编译环境比较复杂,Pypi 中只有没这么新的版本,指定旧版本安装:

    pip install z3-solver==4.5.1.0.post2

    例题 1

    一军用仓库被窃,公安部门已掌握如下线索:①甲、乙、丙三人至少有一个是窃贼;②如甲是窃贼,则乙一定是同案犯;③盗窃发生时,乙正在影剧院看电影。由此可以推出( )。

    A.甲、乙、丙都是窃贼
    B.甲和乙都是窃贼
    C.丙是窃贼
    D.甲是窃贼

    阅读更多…
  • 一图流解释 Alpha-Beta 剪枝(Alpha-Beta Pruning)

    Alpha-Beta剪枝用于裁剪搜索树中不需要搜索的树枝,以提高运算速度。它基本的原理是:

    • 当一个 Min 节点的 β值≤任何一个父节点的α值时 ,剪掉该节点的所有子节点
    • 当一个 Max 节点的 α值≥任何一个父节点的β值时 ,剪掉该节点的所有子节点

    下面为只使用 MiniMax 和使用 Alpha-Beta 剪枝的简单对比。

    MiniMax search without alpha-beta pruning
    MiniMax search with alpha-beta pruning

    需要注意的是,剪枝的效果与树节点的访问顺序有关。

    Alpha-Beta剪枝的伪代码如下:

    Initialize MAX_VALUE(node,game,-∞,∞)
    
    function MAX_VALUE(state,game,α,β) returns the minimax value of state
        inputs: state, current state in game
                game, game description
                α, the best score for MAX along the path to state
                β, the best score for MIN along the path to state
    
        if CUTOFF_TEST(state) then return EVAL(state)
        for each s in SUCCESSORS(state) do
            α = MAX(α, MIN_VALUE(s,game,α,β))
            if α ≥ β then return β
        end
        return α
    
    function MIN_VALUE(state,game,α,β) returns the minimax value of state
        if CUTOFF-TEST(state) then return EVAL(state)
        for each s in SUCCESSORS(state) do
            β = MIN(β, MAX_VALUE(s,game,α,β))
            if α ≥ β then return α
        end
        return β

    下面用一个例子说明。规定从左节点开始展开。原搜索树为:

    阅读更多…
  • 使用 Python OpenCV 3.4.x 进行 SIFT 特征检测与匹配

    前言

    Harris算法和Shi-Tomasi 算法,由于算法原理,具有旋转不变性,在目标图片发生旋转时依然能够获得相同的角点。但是如果对图像进行缩放以后,再使用之前的算法就会检测不出来,如图:

    图像放大,窗口不变,导致检测结果发生变化

    在2004年,University of British Columbia 的 D.Lowe 在他的论文 Distinctive Image Features from Scale-Invariant Keypoints 中提出了一个新的算法,Scale Invariant Feature Transform (简称SIFT),它可以提取关键点及计算其描述符。OpenCV的文档指出这篇论文容易理解,推荐阅读。

    SIFT算法主要有4个步骤,详情请见文末的相关参考。

    流程

    1. 尺度空间极值检测(Scale-space Extrema Detection)
    2. 关键点定位(Keypoint Localization)
    3. 方向分配(Orientation Assignment)
    4. 关键点描述符(Keypoint Descriptor)
    阅读更多…
  • 霍夫变换(Hough Transform)

    简介

    霍夫变换(Hough Transform)最初用于检测图像中的直线或者圆等几何图形,主要应用在图像分析、计算机视觉和数字图像处理领域。后来经过拓展,可适用于任意图形的检测,及一些参数取值的检测。

    霍夫直线变换的基本思想

    如果两点 (xi, yi) 和 (xj, yj) 都在一条直线上,那么它们在x-y平面上有相同的斜率和y轴的截距。

    对于一个点 (xi, yi) ,经过直线 yi = axi + b,其中a为斜率,b为y轴截距。可以把该式改写为 b = (-xi)a+ yi ,使a为自变量,b为因变量,a可取[amin, amax],代入a可求出对应的b值。a和b的关系可以在参数空间(即a-b平面)上作图。把参数空间分隔为一个一个格子(累加器),然后把 (a, b) 对应的格子A(a, b) 加 1。
    也就是说,一个点可以使参数空间的一系列累加器都加 1。

    对于另外一个点 (xj, yj) ,把 yj = axj + b 改写为 b = (-xj)a+ yj ,作同样的操作,对应的一系列累加器加1。

    阅读更多…
  • Python 的 __new__() 方法与实践

    本文主要转自:http://www.cnblogs.com/ifantastic/p/3175735.html

    __new__() 是在新式类中新出现的方法,它作用在构造方法建造实例之前,可以这么理解,在 Python 中存在于类里面的构造方法 __init__() 负责将类的实例化,而在 __init__() 启动之前,__new__() 决定是否要使用该 __init__() 方法,因为__new__() 可以调用其他类的构造方法或者直接返回别的对象来作为本类的实例

    如果将类比喻为工厂,那么__init__()方法则是该工厂的生产工人,__init__()方法接受的初始化参数则是生产所需原料,__init__()方法会按照方法中的语句负责将原料加工成实例以供工厂出货。而__new__()则是生产部经理,__new__()方法可以决定是否将原料提供给该生产部工人,同时它还决定着出货产品是否为该生产部的产品,因为这名经理可以借该工厂的名义向客户出售完全不是该工厂的产品。

    __new__() 方法的特性:

    • __new__() 方法是在类准备将自身实例化时调用
    • __new__() 方法始终都是类的静态方法,即使没有被加上静态方法装饰器

    类的实例化和它的构造方法通常都是这个样子:

    class MyClass(object):
        def __init__(self, *args, **kwargs):
            pass
    
    myclass = MyClass(*args, **kwargs)  # 实例化

    正如以上所示,一个类可以有多个位置参数和多个命名参数,而在实例化开始之后,在调用 __init__() 方法之前,Python 首先调用 __new__() 方法:

    def __new__(cls, *args, **kwargs):
        pass

    第一个参数cls是当前正在实例化的类。

    如果要得到当前类的实例,应当在当前类中的 __new__() 方法语句中调用当前类的父类的 __new__() 方法。例如,如果当前类是直接继承自 object,那当前类的 __new__() 方法返回的对象应该为:

    def __new__(cls, *args, **kwargs):
        ...
        return object.__new__(cls, *args, **kwargs)  # Python 2 是这样的,但这不适用于Python 3,会报错,后文不重复提示这点

    注意:
          事实上如果(新式)类中没有重写__new__()方法,即在定义新式类时没有重新定义__new__()时,Python默认调用该类的直接父类的__new__()方法来构造该类的实例,如果该类的父类也没有重写__new__(),那么将一直按此规矩追溯至object的__new__()方法,因为object是所有新式类的基类。
          而如果新式类中重写了__new__()方法,那么你可以自由选择任意一个的其他的新式类(必定要是新式类,只有新式类必定都有__new__(),因为所有新式类都是object的后代,而经典类则没有__new__()方法)的__new__()方法来制造实例,包括这个新式类的所有前代类和后代类,只要它们不会造成递归死循环。具体看以下代码解释:

    class Foo(object):
        def __init__(self, *args, **kwargs):
            ...
        def __new__(cls, *args, **kwargs):
            return object.__new__(cls, *args, **kwargs)    
    
    # 以上return等同于 
    # return object.__new__(Foo, *args, **kwargs)
    # return Stranger.__new__(cls, *args, **kwargs)
    # return Child.__new__(cls, *args, **kwargs)
    
    class Child(Foo):
        def __new__(cls, *args, **kwargs):
            return object.__new__(cls, *args, **kwargs)
    
    class Stranger(object):  # 在制造Stranger实例时,会自动调用 object.__new__(cls)
        ...
    
    # 如果Child中没有定义__new__()方法,那么会自动调用其父类的__new__()方法来制造实例,即 Foo.__new__(cls, *args, **kwargs)。
    # 在任何新式类的__new__()方法,不能调用自身的__new__()来制造实例,因为这会造成死循环。因此必须避免类似以下的写法:
    # 在Foo中避免:return Foo.__new__(cls, *args, **kwargs) 或 return cls.__new__(cls, *args, **kwargs)。Child同理。
    # 使用object或者没有血缘关系的新式类的__new__()是安全的,但是如果是在有继承关系的两个类之间,应避免互调造成死循环,例如:(Foo)return Child.__new__(cls), (Child)return Foo.__new__(cls)。

    通常来说,新式类开始实例化时,__new__()方法会返回cls(cls指代当前类)的实例,然后该类的__init__()方法作为构造方法会接收这个实例(即self)作为自己的第一个参数,然后依次传入__new__()方法中接收的位置参数和命名参数。

    注意:如果__new__()没有返回cls(即当前类)的实例,那么当前类的__init__()方法是不会被调用的。如果__new__()返回其他类(新式类或经典类均可)的实例,那么只会调用被返回的那个类的构造方法【不包括__init__()方法】

    class Foo(object):
        def __init__(self, *args, **kwargs):
            ...
        def __new__(cls, *args, **kwargs):
            return object.__new__(Stranger, *args, **kwargs)  
    
    class Stranger(object):
        ...
    
    foo = Foo()
    print type(foo)    
    
    # 打印的结果显示foo其实是Stranger类的实例
    
    # 因此可以这么描述__new__()和__init__()的区别,在新式类中__new__()才是真正的实例化方法,为类提供外壳制造出实例框架,然后调用该框架内的构造方法__init__()使其丰满。
    # 如果以建房子做比喻,__new__()方法负责开发地皮,打下地基,并将原料存放在工地。而__init__()方法负责从工地取材料建造出地皮开发招标书中规定的大楼,__init__()负责大楼的细节设计,建造,装修使其可交付给客户。

    ================ 以上是转载的原文 =========================

    下面是我的一点使用经验。此前我也没具体使用过__new__()方法,只是大概听过有这么一个事。

    最近项目新增了一种网络协议,而API不变,希望同时适配不同的网络协议(数据包中有给出版本号可以判断)。然后就想到了在实例化的__new__()方法里面返回一个其他类的实例,进而拜读了原文……

     

    粗略阅读原文后,写出来了类似这样的代码:

    condition = None
    
    class A(object):
        def __new__(cls, *args, **kwargs):
            print('A new')
            if condition == 'A':
                return object.__new__(cls)  # cls == A
            elif condition == 'B':
                return object.__new__(B)
    
        def __init__(self, value):
            self.value = value
    
    
    class B(object):
        def __new__(cls, *args, **kwargs):
            print('B new')
            return object.__new__(B)
    
        def __init__(self, value):
            self.value = value
    
    condition = 'A'
    a = A(123)
    print(type(a))
    print(a.value)
    
    condition = 'B'
    b = A(456)
    print(type(b))
    print(b.value)

    运行结果为:

    A new
    <class '__main__.A'>
    123
    
    A new
    <class '__main__.B'>
    Traceback (most recent call last):
      File "/xxxxx/main.py", line 31, in <module>
        print(b.value)
    AttributeError: 'B' object has no attribute 'value'

    A这块是正常的,而B这块就很不正常了:没有value这个属性不说,print(‘B new’) 都没有执行!
    ——这是 return object.__new__(B) 导致的,因为object的__new__() 方法没有 print(‘B new’) 这句。

    我们把 return object.__new__(B) 改成 return B.__new__(cls) ,像这样:

    class A(object):
        def __new__(cls, *args, **kwargs):
            print('A new')
            if condition == 'A':
                return object.__new__(cls)  # cls == A
            elif condition == 'B':
                return B.__new__(cls)

    这下执行结果有显示 B new 了。然而,’B’ object has no attribute ‘value’,还是没有。
    把 return B.__new__(cls) 改为 return B.__new__(cls, *args, **kwargs) ,把参数传进去,结果还是一样。

    难道是B类的问题?把它改成:

    class B(object):
        def __new__(cls, *args, **kwargs):
            print('B new')
            return object.__new__(B, *args, **kwargs)

    依旧报错(在Python 3下还会报 TypeError: object() takes no parameters)!有点抓狂了,再去精读一下,发现了上面被我标红的一句“如果__new__()返回其他类(新式类或经典类均可)的实例,那么只会调用被返回的那个类的构造方法”。就是说,__init__()方法没有被调用啊!我来手动调用一下:

    condition = None
    
    class A(object):
        def __new__(cls, *args, **kwargs):
            print('A new')
            if condition == 'A':
                return object.__new__(cls)  # cls == A
            elif condition == 'B':
                return B.__new__(cls, *args, **kwargs)
    
        def __init__(self, value):
            self.value = value
    
    
    class B(object):
        def __new__(cls, *args, **kwargs):
            print('B new')
            self = object.__new__(B)  # 创建对象
            self.__init__(*args, **kwargs)  # 初始化对象
            return self  # 初始化之后再返回结果
    
        def __init__(self, value):
            self.value = value
    
    condition = 'A'
    a = A(123)
    print(type(a))
    print(a.value)
    
    condition = 'B'
    b = A(456)
    print(type(b))
    print(b.value)

    这次终于和期望一致了……

     

    总结:

    1. 如果__new__()返回其他类的实例,那么只会调用被返回的那个类的构造方法【不包括__init__()方法】;
    2. 如果__new__()返回当前类的实例,可以直接 return object.__new__(cls) ,不需要手动传参数;若返回其他类的参数,需 return ClassName.__new__(cls, *args, **kwargs) 手动传参数,万万不能 return object.__new__(ClassName, *args, **kwargs) 。
  • 搭建 git 本地中转站

    局域网内有多台开发机器,因为种种原因,与服务器同步代码有不便之处。于是打算在本地做一个 git 的镜像,所有机器都统一 clone 这个本地镜像库,然后由这个镜像库负责与服务器更新。

    1. 使用 –mirror 参数 clone

    cd /some/where/
    git clone --mirror git@server.com:user/someproject.git

    执行以上命令后,在本地的 /some/where/someproject.git/ 下建立了对应项目的镜像,它是一个裸版本库(不包含工作区,直接就是版本库的内容),对于我这样的新手来说不是很好懂什么是“裸版本库”,但是进去目录看一下就知道了。

    2. 本地操作

    在同一台机器上,我们这样写代码:

    cd ~/workspace/
    git clone /some/where/someproject.git

    这样 clone 出来的就是平时熟悉的、包含工作区的内容,平时怎么用就怎么用。
    阅读更多…

  • 申请 Let’s Encrypt 通配符 HTTPS 证书,并配置 Apache2

    3月中旬, Let’s Encrypt 终于正式发布通配符 HTTPS 证书了,赶紧去申请一个玩玩(然而我的网站暂时还不支持加SSL,只能先在VPS上试试了 /(ㄒoㄒ)/)。

    1. 安装 Let’s Encrypt 客户端

    系统为 Ubuntu 16.04,参照 Certbot 官网的教程,运行以下命令安装(我这里由于是用 root 用户,所以非 root 请自行加 sudo):

    # apt-get update
    # apt-get install software-properties-common
    # add-apt-repository ppa:certbot/certbot
    # apt-get update
    # apt-get install python-certbot-apache

    2. 获取通配符证书

    先查看 certbot 的版本是否 > 0.22,否则不支持通配符证书:

    # certbot --version
    certbot 0.22.2
    

    自带的 –apache 模式似乎并不能处理通配符证书的情况,所以需要手动获取。

    在对应的 support 页面[1]中,了解到还需要手动指定服务器,执行:

    # certbot -d *.xxxx.com --manual --preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory certonly

    之后按提示操作,并添加自己的域名的 TXT 记录,以通过 ACME 认证。完成后,可在 /etc/letsencrypt/live/xxxx.com/ 下看到几个 .pem 文件。

    阅读更多…