机器学习的工具、文档以及资料记录

工具

keras [中文]
Tushare Pro
plt
gym(openAI)

可能有用的网站

Colaboratory(墙)
Google的免费AI训练网站,有账号就能够在上面使用一定的资源进行计算
嗯……有TPU
PaperWeekly
可以看到许多不错的论文推荐之类的东西
不过似乎没有在更新了,最新的一篇也只是2017年的东西了
但是里面的东西对个人还是挺有学习价值的
修正:PaperWeekly新地址,似乎在这边更新了,似乎要注册才能看
fastAI
据说是个好东西?不过还没看

相关教程及文档

gym

https://www.jianshu.com/p/cb0839a4d1d3

plt

http://www.cnblogs.com/wei-li/archive/2012/05/23/2506940.html#pyplot

Python

菜鸟基础教程
如果忽然忘了一些Python的基础操作可以在这里找
《利用Python进行数据分析·第2版》
前几章详细地介绍了numpy等工具的利用,可以用于参考

Keras

中文文档
LSTM详解
因为是中文所以看着比较轻松,但是和英文相比有许多不全的地方
找不到或者不详尽的地方还是要看英文的文档
英文文档
英文,相对中文文档来说资料更全更新一些,在中文文档不够用的时候就要上了
tensorflow
含有基于keras的高级API教程和一些文档API
也有一些对基本模型的讨论和讲述
以后想要自定义keras的训练层的时候可能会需要在这里找文档
对于tensorflow的新功能也可以在这里多看看了解一下
官方例子
很棒的例子,代码简洁,有助于理解keras的使用和对部分网络结构的熟悉
不过建议只用来理解,真正做的时候看一下文档,因为部分例子里没有文档里的一些更方便的东西
(比如说在我写这篇的时候,seq2seq就没有使用embedding层,也没有忽略0数据
(不过更新似乎一直在继续,也许之后会看到更有效率的做法吧

基础概念

损失函数

https://zhuanlan.zhihu.com/p/34667893
https://blog.csdn.net/u010312436/article/details/78449632

模型

零基础入门深度学习

RNN

简要介绍

seq2seq

Sequence to Sequence Learning with Neural Networks
关于seq2seq的介绍

Learning Phrase Representations using RNN Encoder–Decoder for Statistical Machine Translation
里面涉及到的原论文中给出了GRU单元的算法以及概率的计算,可以较为清楚地了解GRU这个东西,还有seq2seq的原理

attention-is-all-you-need-keras
含有自定义程度较高的keras的seq2seq实现

attention

NEURAL MACHINE TRANSLATION BY JOINTLY LEARNING TO ALIGN AND TRANSLATE
关于注意力模型的论文
知乎上对论文的中文介绍和理解

自然语言处理中的Attention Model:是什么及为什么
将引入注意力模型的原因和详细的解释一步步的说了出来,很清晰

attention模型方法综述

deep-learning-nlp-best-practices
比较全面的介绍

以Attention Model为例谈谈两种研究创新模式
对注意力模型的总结回顾和拓展

深度学习笔记——Attention Model(注意力模型)学习总结

CDRextraction
似乎含有keras的attentionLayer实现

AttentionIsAllYouNeed
不含有RNN和CNN的纯粹注意力模型论文
keras实践:attention-is-all-you-need-keras
可能需要的参考:
Layer Normalization
你是怎样看待刚刚出炉的 Layer Normalisation 的?

GAN

待填

知识图谱

《知识图谱》专题论文解读
还没看,之后评价

无脑邮件服务器

参考资料:
利用Docker自建多功能加密邮件服务器
docker-mailserver git网址
Installation-Examples

安装

(安装docker的指令不太确定,如果不行的话上网找吧)

1
2
3
4
5
6
7
8
9
sudo apt-get update && \
sudo apt install docker -y && \
sudo apt install docker-compose -y && \
sudo apt install dovecot-core -y && \
sudo apt-get install software-properties-common -y && \
sudo add-apt-repository ppa:certbot/certbot

sudo apt-get update && \
sudo apt-get install certbot -y

拉取配置文件

1
2
3
curl -o setup.sh https://raw.githubusercontent.com/tomav/docker-mailserver/master/setup.sh; chmod a+x ./setup.sh
curl -o docker-compose.yml https://raw.githubusercontent.com/tomav/docker-mailserver/master/docker-compose.yml.dist
curl -o .env https://raw.githubusercontent.com/tomav/docker-mailserver/master/.env.dist

hostname和domainname最终要拼成主机名
port加入465
修改拉取后的.env文件进行配置,配置属性详情见此
docker-compose中也需要修改volume的映射位置,包括文件存储位置和证书位置(如加入’/etc/letsencrypt:/etc/letsencrypt’)

启动容器进行初始化

docker-compose up -d mail

可能出现的错误:Couldn't connect to Docker daemon at http+docker://localunixsocket - is it running?
若存在上述错误,尝试将用户加入docker组,然后重启终端
sudo gpasswd -a ${USER} docker)

DNS域名解析:

sudo ./setup.sh config dkim
如果未出现config文件夹,可能需要先添加一个账户后重试
生成的字符串长度可以在dkim后面增加参数(如sudo ./setup.sh config dkim 200)进行限制

复制config/opendkim/keys/domain.tld/mail.txt下内容,将引号内字符串拼接后用于设置DNS
类型为TXT,记录名为mail._domainkey,记录值为拼接后字符串
类型为MX,记录名为@,记录值”mail.(你的域名)”(如”mail.abc.cn”,下面的域名以此为例)
类型为A,记录名为mail,记录值为(服务器的IP)

证书(域名以”mail.abc.cn”,为例)

certbot certonly --standalone -d mail.abc.cn
之后会要求你输入邮箱来获取安全信息等,填入邮箱即可。还会问你是否接受推送,这个看个人意愿选择吧。

证书续期
crontab -e打开定时任务设置面板,按i进入编辑模式,粘贴进这段代码即:
0 5 * * 1 /usr/bin/certbot renew --quiet
可每周一凌晨5点0分给证书续期

注册邮箱(邮箱名字以”wuny@abc.cn“为例,密码以yourpassword为例)

sudo ./setup.sh email add wuny@abc.cn yourpassword

C# COM组件编写,并在C++上运行

前言

本篇文章使用的是VS2017,故以下内容操作均以VS2017版本为例子
部分代码在写本篇文章时与测试时所用代码略有不同,所以不保证能够生效
参考资料:
C++调用C# com组件:一个完整的的小例子
ClassInterface


新建并配置项目

新建一个Visual C#/类库(.NET FrameWork)项目,此处以ComTest作为项目名为例
解决方案资源管理器中找到ComTest/Properties/AssemblyInfo.cs,将内部的[assembly: ComVisible(false)]由false改为true
打开项目 - 属性,在生成 - 输出中勾选”生成序列化程序集”

可选:勾选签名 - 为程序集签名然后选择强名称密钥文件(方面起见本人测试时使用的是新建的,未勾选”使用密码保护密钥文件”的)


编写注意事项

##1、C++调用com组件中所有的功能只能通过接口来调用
因此我们需要为暴露出来的类写一个public接口(通常接口名为”类名加上I前缀”)
该接口需要有属性[ComVisible(true)]

##3、需要为类和上述接口添加GUID.aspx)
GUI的生成可以在VS的工具 - 创建GUID栏中生成,格式为[GUID(“xxxxxxx-xxxx … xxxx”)]

生产环境卸下,建议

##1、接口的方法有属性[DispId(X)]//X为不重复的整数

##2、类有属性[ClassInterface(ClassInterfaceType.None)]

代码例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System;
using System.Runtime.InteropServices;

namespace ComTest
{
[ComVisible(true)]
[Guid("80EB95B3-62C5-4469-B897-81BFA9D33447")]
public interface ITestClass
{
[DispId(1)]
int Add(int x, int y);
}

[Guid("8FEBFADA-8442-4C50-A7FE-B788633EED8B")]
[ClassInterface(ClassInterfaceType.None)]
public class TestClass : ITestClass
{
public int Add(int x, int y)
{
return x + y;
}
}
}


#编译和注册COM组件
通过生成 - 生成ComTest即可编译生成dll、tlb、pdb文件
由于VS在生成dll是会自动将代码注册至编译电脑,故COM组件的注册忽略,详情可见上方参考资料

#在C++中使用
将生成的dll、tlb、pdb全部导入C++项目中(导入后可能需要重新生成解决方案来更新引用,解决报错问题)
使用#import ".\ComTest.tlb" named_guids raw_interfaces_only进行引用,引用路径取决于三个文件在项目文件夹中的位置
通过CoInitialize(NULL)初始化COM组件
通过ComTest::ITestClassPtr ptr;创建一个类的类似指针的东西,注意类型是”接口名+Ptr”
通过ptr.CreateInstance(ComTest::CLSID_TestClass)实例化一个类
(也可以通过using namespace ComTest省略前面的命名空间,此处的命名空间和COM组件在C#中定义的一致
通过ptr->Add(a,b,&c)来调用类的方法,注意此处类型在C++中为long,而非C#中声明的int,且不是通过return返回值,而是在末尾将值赋值给一个指针
(不过为什么这样资料上似乎也不太清楚)

调用示例如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "stdafx.h"
#import ".\\ComTest.tlb" named_guids raw_interfaces_only

using namespace ComTest;

int main()
{
long a, b = 2, c = 3;

CoInitialize(NULL);
ITestClassPtr ptr;
ptr.CreateInstance(CLSID_TestClass);
ptr->Add(1, 2, &a);

printf_s("%ld", a);
return 0;
}

构架演变(大概)

引用自某乎

作者:得闲野鹤
链接:https://www.zhihu.com/question/25536695/answer/154614906
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

我们在做一个访问量不大的项目的时候,一台服务器部署上一个应用+数据库也就够了.
那么访问量稍微大一点之后呢,为了解决用户反馈的卡,反应慢的情况,我们就上集群.架设nginx,部署多个服务,由nginx负责把请求转发到其他服务上,这样就解决了用户说的卡慢问题.
过了一段时间之后呢,我们发现数据库已经扛不住了,应用服务完好,数据库有时候宕机. 那这个时候呢,我们就上数据库读写分离,再架设几台数据库服务器,做主从,做分库分表. 然后数据库也不宕机了,服务又恢复了流畅.
又过了一段时间,公司事业增增日上,服务访问量越来越高,且大部分都是查询, 吸取之前宕机且为了办证数据库的健壮性,我们这个时候又加上了缓存, 把用户高频次访问的数据放到缓存里.
后来,项目功能越来越多,整个项目也愈发庞大,修改一个类就需要全盘上传,切换nginx重启,这样的发布流程越来越长,越来越繁杂.然后我们开始把模块拆分,用户信息分个项目,订单系统分一个项目.这样就达到了,用户模块代码修改的时候,只需要更新用户信息服务就好了.但是还是需要切换顶层的nginx.把要重启的服务的流量切到可用服务上. 这个时候我们就想到了RPC
那么RPC解决了什么呢? 所有的服务在启动的时候注册到一个注册机里面,然后顶层处理在接收到nginx的请求时,去注册机找一个可用的服务,并调用接口. 这样子呢,在不加新功能的时候,顶层处理服务我们就不需要动了? 那修改了用户信息项目的时候,我们只需要一个个更新用户信息项目的服务群就好了?
这样的话,无论是扩展还是服务的健壮性都妥妥的了?

卷积网络笔记以及WaveNet理解相关资料

来自知乎的原文
下面是自己的一些理解?
对于图像的操作可以写成矩阵的形式,作为滤波器
这些滤波器(filter)会对特定的模式有高的激活(识别特定的曲线或者其它的模式)
训练卷积神经网络的时候,我们实际上是在训练每一格卷积层一系列的滤波器
第二层的滤波器会将第一层的输出作为它的输出,来检测低阶特征的组合等情况
随着卷积层数的增加,组合的累计让神经网络能够检测的特征更加的复杂
这种方式与人类大脑的视觉信息处理模式相仿,都是由简单到复杂抽象

构建滤波器(训练)的方式是修改滤波器矩阵的值(权重Weight),使其能识别特定的特征
修改依据是损失函数的输出,尽可能的让损失函数的值最小
使其变为一个最优化问题

WaveNet理解用相关资料
(卷积变种)[https://www.cnblogs.com/yangperasd/p/7071657.html]
(优化方法)[https://zhuanlan.zhihu.com/p/22252270]
(卷积训练公式推导)[https://zybuluo.com/hanbingtao/note/485480]

go gin框架的一些坑

我们可以使用c.Bind(&abc)来将传入的数据(json,xml,form等格式)赋值到abc这个struct中
但是要注意abc这个struct类型里,字母变量一定要首字母大写
不然的话外部包无法访问这个变量,然后就无法对其赋值了
排查了4小时BUG的血的教训

关于整数为什么不能用对角线来证明不可数

如题,存点连接
来自知乎

实数的一种构造是「有理数列的极限」。

这里的数列是柯西数列,但我就不重复高等数学教材上的定义了。如果你学过或者手上有书,请翻书。如果没学过,那就随便看看吧。反正,柯西数列的定义中需要一种「距离」的概念。有了这个「距离」,柯西数列就是直观上越来越近的一系列点。在实数的定义中,这个距离很简单,就是两个有理数之前的差的绝对值。比如 3.14 和 3.1 之间的「距离」就是 0.04,而 3, 3.1, 3.14, 3.141, 3.1415, … 就是一个柯西数列。柯西有理数列的极限们就叫做实数。

开头提到的题目中,题主在纠结:如果整数往左一直写下去是什么呢?在初等数学中,这仅仅是一个无穷整数数列,而且这个数列没有定义极限.
但是,我们现在来引入一个新的「距离」。如果一个有理数可以写成的形式,其中 p 和 q 不能被 2 整除,那么我们记 n 的「绝对值」为. 也就是说,如果 n 里包含一个 2 的次幂,那么幂次越高 n 就越「小」,幂次越低 n 就越「大」。在这个「绝对值」下,我们定义两个数的「距离」为.
我知道这个定义很让人纠结。如果你接受这个定义,那么将数字向左无穷写下去,即 这种形式,就有意义了。在新的「距离」下,比如 1, 01, 101, 1101, 01101, 101101 … 这样的数列就成了一个柯西数列。这个数列在新的「距离」下是收敛的。这些无穷数列的极限叫「2-进数」。比如 1, 11, 111, 1111, 11111 … 这个无穷数列,其极限是 -1.(我只是随便举个例子,请勿用初等数学来解释这个例子)。这样的做法自然适用于所有素数 p,相应的我们就有了 p-进数。
如题主所期望的,因为对给定的 p-进数,其位数是无限的,即每个 p-进数都对应一个无穷数列,所以可以用对角线方法证明,p-进数是不可数的。

go 关于mysql

检验连接正确性,需要使用sql.Ping()

来自阿里云

执行sql.Open()并未实际建立起到数据库的连接,也不会验证驱动参数。第一个实际的连接会惰性求值,延迟到第一次需要时建立。用户应该通过db.Ping()来检查数据库是否实际可用。

被坑过一次的坑……

用Query的话记得读取数据

同样的语句使用Exec和Query执行有巨大的差别。如上文所述,Query会返回结果集Rows,而存在未读取数据的Rows其实会占用底层连接直到rows.Close()为止。因此,使用Query但不读取返回结果,会导致底层连接永远无法释放。database/sql期望用户能够用完就把连接还回来,所以这样的用法很快就会导致资源耗尽(连接过多)。所以,应该用Exec的语句绝不可用Query来执行。

需要注意的地方

sql中,不需要每次调用Open,可以只有一个全局

来自知乎 - 作者:汪亚军

sql.Open 不会创建连接 ,只会创建一个DB实例,同时会创建一个go程来管理该DB实例的一个连接池(是长连接,但不是在Open的时候创建)。 在调用Begin()取一个连接,回滚或者提交得时候归还。如果你直接使用时Exec()执行,则每次会从连接池里面取出一个连接,到Exec执行完毕的时候归还。可以通过参数来调节连接池的大小。
golang sql包已经做了并发处理,自己通过channel的方式维护了一个连接池,所以没有必要在go程中加锁共享。
关于每次sql.Open,我觉得应该是一个不恰当的做法,这会导致连接得不到重用,并产生过多的短时间关闭的连接,给数据库造成没必要的压力。
来自阿里云
sql.DB对象是为了长连接而设计的,不要频繁Open()和Close()数据库。而应该为每个待访问的数据库创建一个sql.DB实例,并在用完前一直保留它。需要时可将其作为参数传递,或注册为全局对象。
这一抽象让用户不必考虑如何管理并发访问底层数据库的问题。当一个连接在执行任务时会被标记为正在使用。用完之后会放回连接池中。不过用户如果用完连接后忘记释放,就会产生大量的连接,极可能导致资源耗尽(建立太多连接,打开太多文件,缺少可用网络端口)。

找到的许多资料都这么说,那么大概可以放心用了?

重复调用Close()不会出现错误

来自阿里云

rows.Close方法是幂等的,重复调用不会产生副作用,因此建议使用 defer rows.Close()来关闭结果集。

安心用函数系列+1

事务中第二次查询之前先将第一次查询结果读取完毕

因为事务保证在它上面执行的查询都由同一个连接来执行,因此事务中的语句必需按顺序一条一条执行。对于返回结果集的查询,结果集必须Close()之后才能进行下一次查询。用户如果尝试在前一条语句的结果还没读完前就执行新的查询,连接就会失去同步。这意味着事务中返回结果集的语句都会占用一次单独的网络往返。

Scan实参的方法

不定参数的时候可以使用rows.Columns()来获取列名列表,不定类型的时候,可以使用sql.RawBytes()来获取类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cols, err := rows.Columns()
if err != nil {
// handle this....
}

// 目标列是一个动态生成的数组
dest := []interface{}{
new(string),
new(uint32),
new(sql.RawBytes),
}

// 将数组作为可变参数传入Scan中。
err = rows.Scan(dest...)
// ...

关于prepare的详情

(还没有看的资料)[http://go-database-sql.org/prepared.html]
疑问在于,prepare什么时候用?全局注册后重复使用还是用的时候注册,用完销毁的使用?

提高SQL执行效率的方法

来自StackOverflow

It’s an old question but still - better late than never; you’re in for a treat:
put all your data into a bytes.Buffer as tab-separated, newline terminated and unquoted lines (if the text causes problems, it has to be escaped first). NULL has to be encoded as \N.
Use http://godoc.org/github.com/go-sql-driver/mysql#RegisterReaderHandler and register a function returning that buffer under “instream”. Next, call LOAD DATA LOCAL INFILE “Reader::instream” INTO TABLE … - that’s a very fast way to pump data into MySQL (I measured about 19 MB/sec with Go from a file piped from stdin compared to 18 MB/sec for the MySQL command line client when uploading data from stdin).
As far as I know, that very driver is the only way to LOAD DATA LOCAL INFILE without the need of a file.

避免Null值带来的麻烦,可以使用sql.NullString,sql.NullInt64等含null的类型

来自github mysql官方插件说明

Ignoring NULL values
Note: This might cause problems in Go 1.0 since the conversion from integer types to []byte is missing. The Issue is fixed in Go 1.1+
Maybe you already encountered this error: sql: Scan error on column index 1: unsupported driver -> Scan pair: -> string
Normally you would use sql.NullString in such a case. But sometimes you don’t care if the value is NULL, you just want to treat it as an empty string.
You can do this with a small workaround, which takes advantage of the fact, that a nil-[]byte gets converted to an empty string. Instead of using
string as a rows.Scan(…) destination, you simple use []byte (or sql.RawBytes), which can take the nil value:

|