Docker实践

本文是由ICLR2019 Neural persistence论文中的项目出发接触 docker. 参考了菜鸟教程.

Docker 架构

Docker架构模式为客户端-服务器. 通过Docker镜像创建Docker容器.

ubuntu18.04 安装 docker

直接从软件源中安装

1
sudo apt install docker-ce

添加当前用户到 docker 用户组,可以不用 sudo 运行 docker

1
2
sudo groupadd docker
sudo usermod -aG docker $USER

Docker 使用

Hello World

docker run命令在容器内运行程序

1
docker run ubuntu /bin/echo "Hello world"

其中ubuntu为指定要运行的镜像.

交互式容器

1
docker run -it ubuntu /bin/bash

-i允许交互, -t新容器内制定终端

后台容器

1
docker run -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"

通过docker ps查看进程

docker logs查看输出

docker stop停止进程

Docker 镜像使用

镜像列表

docker images列出本地镜像

获取镜像

docker pull ubuntu

查找镜像

docker search ubuntu

Dockerfile 构建镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
FROM tensorflow/tensorflow:1.6.0-py3
RUN mkdir /Software
WORKDIR /Software

# Install Aleph dependencies
RUN apt-get update && apt-get install -y apt-utils
RUN apt-get install -y cmake git python3-dev
RUN pip3 install pytest
RUN git clone https://github.com/pybind/pybind11.git pybind11
RUN mkdir pybind11/build
WORKDIR pybind11/build
RUN cmake ..
#RUN make -j 4
RUN make -j 4 install

# Install Aleph python module
RUN apt-get install -y libboost-dev libboost-regex-dev
RUN git clone https://github.com/Submanifold/Aleph.git Aleph
RUN mkdir Aleph/build
WORKDIR Aleph/build
RUN git checkout 8c88506
RUN cmake ..
RUN make aleph
RUN pip3 install bindings/python/aleph

# Install python dependencies
RUN pip3 install sacred matplotlib seaborn pandas

RUN mkdir /Neuropersistence
WORKDIR /Neuropersistence
ADD . /Neuropersistence

From指定镜像源, RUN让docker在镜像内执行命令, WORKDIR指定目录. ADD将主机的文件拷贝到镜像中.

1
docker build -t neuropersistence .

-t指定目标镜像名, .为Dockerfile文件所在目录.

1
2
docker run -v $PWD/results/:/Neuropersistence/results/ neuropersistence python3 -u run_experiments.py
docker run -v $PWD/results/:/Neuropersistence/results/ neuropersistence python3 combine_runs.py results/runs/* --output results/combined_runs.csv

-v使docker容器启动时挂载主机的目录, 用:分隔.

1
docker run -v $PWD/results/:/Neuropersistence/results/ neuropersistence python3 create_plots.py results/combined_runs.csv results/combined_runs.pdf
分享到

TopologySmooth 项目 Makefile 编译

TopologySmooth 项目 Makefile 编译

最近在阅读论文Topology-based Smoothing of 2D Scarlat Fields with $C^1$-Continuity 的c++源码的过程中, 遇到了编译Makefile的一些问题. 由于我之前的一些c++项目均是用cmake工具自动生成Makefile文件, 对具体的Makefile语法不是十分熟悉. 趁此机会, 简要学习一些Makefile语法. 主要参考了CSDN陈皓博客的《跟我一起写Makefile》系列.

查看更多

分享到

TensorFlow 实现卷积神经网络

5.1 卷积神经网络简介

一般的 CNN 由多个卷积层构成, 每个卷基层中通常会进行如下操作:

  1. 图像通过多个不同的卷积核的滤波, 加上 bias, 提取局部特征, 每一个卷积核映射出一个新的图像
  2. 卷积核的滤波结果进行非线性激活函数处理, 最常见是 ReLU
  3. 进行 pooling 操作 (降采样), 一般使用 max pooling, 保留最显著特征

上面即最常见卷积层, 也可以加上 LRN (Local Response Normalization, 局部响应归一化层), 流行的 trick 有 Batch Normalization.

  • 卷积核权值共享, 不必担心隐含节点和图片大小, 参数量只和卷积核大小, 卷积核数量有关
  • 局部连接
  • 增加卷积核数量提取多种特征, 每一个卷积核滤波结果是一类特征映射 Feature Map. 使用 100 个卷积核在第一个卷积层已经很充足
  • 参数数量下降, 但隐含节点数量没有下降, 与步长有关.

CNN 要点

  1. 局部连接 (Local Connection): 减少参数, 减轻过拟合
  2. 权值共享 (Weight Sharing): 减少参数, 减轻过拟合, 对平移容忍性
  3. 池化层 (Pooling) 中的降采样 (Down-Sampling): 对轻度形变容忍性

LeNet5 是最早的 DCNN 之一, 特性:

  • 每个卷积层包括: 卷积, 池化, 非线性激活函数
  • 使用卷积提取空间特征
  • 降采样 (Subsample) 的平均池化层 (Average Pooling)
  • 双曲正切 (Tanh) 或 S 型 (Sigmoid) 激活函数
  • MLP 作为最后的分类器
  • 层与层之间稀疏连接

C1 有 6 个卷积核, 尺寸 5*5, 共 (5*5+1)*6=156 个参数, 1 代表 1 个 bias. 后面是 2*2 的平均池化层 S2 降采样. 再 Sigmoid 激活函数. 第二个卷积层 C3, 尺寸 5*5, 16 个卷积核. S4 与 S2 一致. 第三个卷积层 C5 有 120 个卷积核, 尺寸 5*5, 构成了全连接. F6 全连接, 84 个隐含节点, Sigmoid 激活函数. 最后一层由欧式 RBF 单元组成, 输出分类结果.

5.2 TensorFlow 实现简单的卷积网络

本节使用两个卷积层与一个全连接层.

1
2
3
4
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
sess = tf.InteractiveSession()
Extracting MNIST_data/train-images-idx3-ubyte.gz
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
1
2
3
4
5
6
7
8
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)

def bias_variable(shape):
# 因为使用 ReLU, bias 置小的正值避免 dead neurons
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial)

接下来定义卷积与池化函数

tf.nn.conv2d 参数 x 是输入, W 是卷积的参数, 例如 [5, 5, 1, 32], 前面两个是卷积核尺寸, 第三个是代表几个 channel, 这里只有灰度单色, 故为 1, RGB 为 3. 最后一个数字代表卷积核数量. strides 代表每一维度的步长, strides[0]=strides[3]=1. padding 代表边界处理方式. SAME 代表给边界加上 Padding 使卷积的输出与输入尺寸 SAME. 用 0 填充.

tf.nn.max_pool 是最大池化函数. 2*2 最大池化, strides 横竖方向步长为 2.

1
2
3
4
5
6
def conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

def max_pool_2x2(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1],
padding='SAME')

定义输入, 将 1 维向量转换为 2 维图像, 尺寸为 [-1,28,28,1], -1 代表样本数量不固定, 最后的 1 代表 channel 数量.

查看更多

分享到

TensorFlow 实现自编码器及多层感知机

4.1 自编码器简介

学者研究稀疏编码 (Sparse Coding) 时, 对大量黑白风景照提取许多 16*16 的图像碎片. 几乎所有的图像碎片可以由 64 种正交的边组合得到. 并且所需要的边数量是很少即稀疏的.

声音也如此, 音频有 20 种基本结构, 大多数声音可以由这些基本结构线性组合得到, 这就是特征的稀疏表达. 即用少量基本特征/基本结构 (basis) 组合成更高层抽象的特征.

特征可以不断抽象为高级特征

  • 若有很多标注数据, 则可以通过训练 DNN 抽象特征
  • 若没有标注的数据, 可以使用无监督的自编码器提取特征

自编码器 (AutoEncoder): 使用自身的高阶特征编码自己
自编码器也是神经网络, 特点:

  1. 输入和输出是一致的
  2. 目标是使用稀疏的高阶特征重新组合来重构自己, 而不只是复制像素点

自编码器输入节点和输出节点数量一致, 通常希望使用少量稀疏的高阶特征重构输入, 而不是单纯地逐个复制输入节点, 故做出以下限制:

  1. 限制隐含层节点数量, 相当于降维. 若给隐含层权重加一个 L1 正则, 则可以控制稀疏程度
  2. 给数据加入噪声, 即 Denoising AutoEncoder (去噪自编码器)

去噪自编码器常用噪声是加性高斯噪声 (Additive Gaussian Noise, AGN)

也可以用 Masking Noise, 即有随机遮挡的噪声. 即置图像中部分像素为 0.

4.2 TensorFlow 实现自编码器

开始实现去噪自编码器; Variational AutoEncoder (VAE) 相对复杂, 对中间节点分布有强假设, 拥有额外损失项, 使用 SGVB (Stochastic Gradient Variational Bayes) 算法训练. 在生成模型中发挥巨大作用.

1
2
3
4
5
6
import numpy as np
import sklearn.preprocessing as prep
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import matplotlib.pyplot as plt
%matplotlib inline

自编码器使用一种参数初始化方法 xavier initialization. 特点是根据某一层网络的输入, 输出节点数量自动调整最合适的分布. 如果深度学习权重初始化太小, 信号在层间传递时逐渐缩小难以产生作用. 初始化太大, 则造成发散. Xaivier 初始化器使权重初始化为合适值. 即 0 均值, 方差 $\frac{2}{n_{in}+n_{out}}$ 的均匀分布或高斯分布. 如

内的均匀分布

下面 fan_in 是输入节点数量, fan_out 是输出节点数量

查看更多

分享到

TensorFlow 第一步

3.1 Tensorflow 的编译及安装

3.2 Tensorflow 实现 Softmax Regression 识别手写数字

首先加载 MNIST 数据

1
2
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data/', one_hot=True)
Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.
Extracting MNIST_data/train-images-idx3-ubyte.gz
Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes.
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes.
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes.
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
1
2
3
print(mnist.train.images.shape, mnist.train.labels.shape)
print(mnist.test.images.shape, mnist.test.labels.shape)
print(mnist.validation.images.shape, mnist.validation.labels.shape)
(55000, 784) (55000, 10)
(10000, 784) (10000, 10)
(5000, 784) (5000, 10)

查看更多

分享到

TensorFlow 基础

1.1 Tensorflow 概要

1.2 Tensorflow 编程模型简介

1.2.1 核心概念

计算图: 每一个运算操作 (operation) 作为一个节点 (node)

1
2
3
4
5
6
7
8
9
10
11
import tensorflow as tf
b = tf.Variable(tf.zeros([100]))
W = tf.Variable(tf.random_uniform([784, 100], -1, 1))
x = tf.placeholder(name='x')
relu = tf.nn.relu(tf.matmul(W, x) + b)
C = [...] # 根据 ReLU 函数结果计算 Cost
s = tf.Session()
for step in range(0, 10):
input = ...construct 100-D input array...
result = s.run(C, feed_dict={x: input})
print(step, result)

1.2.2 实现原理

单机: client, master, worker 在一台机器同一进程中

分布式: client, master, worker 在不同机器的不同进程中

从一块 GPU 训练到多块 GPU 训练只需要添加一行代码 with tf.device('/gpu:%d' % d):

1
2
3
4
5
6
7
for i in range(8):
for d in range(4):
with tf.device('/gpu:%d' % d):
input = x[i] if d is 0 else m[d-1]
m[d], c[d] = LSTMCell(input, mprev[d], cprev[d])
mprev[d] = m[d]
cprev[d] = c[d]

1.2.3 拓展功能

  • 支持自动求导: tensor $C$ 在计算图中有依赖的 tensor {$X_k$}, 则自动求出$dC/dX_k$
    [db, dW, dx] = tf.gradients(C, [b, W, x])

  • 支持单独执行子图. Tensorflow 用节点名加 port 的形式指定数据: bar:0. 调用 Session 的 Run 方法执行子图, 可以选择输入数据的映射: name:port -> tensor; 同时用户必须指定一组输出数据: name[:port]. 计算图根据输入输出调整. 下图只需要执行 a, c, f

  • 支持计算图的控制流: if-condition, while-loop
    Switch, Merge 可根据布尔值跳过某子图然后再合并结果, 实现 if-else 的功能
    Enter, Leave, NextIteration 实现循环和迭代

  • 队列 (queue) 让计算图不同节点异步地执行, 例如提前从磁盘读取下一 batch 数据, 异步计算梯度

  • 容器 (Container) 是管理长期变量的机制, 允许不同计算图不同 Session 共享值

1.2.4 性能优化

  1. 数据并行: 将 mini-batch 数据放在不同设备计算实现梯度计算并行化

  2. 模型并行: 将计算图不同部分放在不同设备上计算

  3. 流水线并行: 同一设备上并行

分享到

10 分钟入门 pandas

1
2
3
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

Object Creation

1
s = pd.Series([1, 3, 5, np.nan, 6, 8])
1
s
0    1.0
1    3.0
2    5.0
3    NaN
4    6.0
5    8.0
dtype: float64
1
2
dates = pd.date_range('20130101', periods=6)
dates
DatetimeIndex(['2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04',
               '2013-01-05', '2013-01-06'],
              dtype='datetime64[ns]', freq='D')
1
2
df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=list('ABCD'))
df
























































A B C D
2013-01-01 0.579917 -1.406484 0.584294 -0.939104
2013-01-02 0.533225 -0.233655 -0.084990 0.084715
2013-01-03 0.056030 -1.618568 1.715577 1.335031
2013-01-04 0.950231 -0.370937 -0.747215 0.111698
2013-01-05 1.095598 0.577610 0.016606 -1.251764
2013-01-06 0.730875 -0.163791 -0.642668 1.419975

查看更多

分享到

scikit-learn 学习 (七) 核岭回归

核岭回归 (KRR) 结合了岭回归 (l2正则化线性最小二乘) 与核技巧. 因此它学习了由核和数据引起的空间中的线性函数. 对于非线性核, 这会在原空间生成一个非线性函数.

KernelRidge 学习的模型的形式与支持向量回归(SVR)相同。 然而,使用不同的损失函数:KRR使用平方误差损失,而支持向量回归使用 ε-不敏感损失,两者都结合了l2正则化。 与SVR相比,拟合KernelRidge可以以闭形式完成,对于中等大小的数据集通常更快。 另一方面,学习模型是非稀疏的,因此比SVR慢,SVR在预测时学习ε> 0的稀疏模型。

下图比较了KernelRidge和SVR在人造数据集上的情况,该数据集由正弦目标函数和每隔五个数据点添加的强噪声组成。 绘制了KernelRidge和SVR的学习模型,其中RBF内核的复杂度/正则化和带宽均使用网格搜索进行了优化。 学到的功能非常相似, 然而,拟合KernelRidge大约比拟合SVR快七倍(都是网格搜索)。 然而,对于10万个目标值的预测,使用SVR的速度提高了3倍以上,因为它只学习了一个稀疏模型。 100个训练数据点中的1/3作为支持向量。

下图比较了不同大小训练集的KernelRidge和SVR的拟合和预测时间。 对于中型训练集(少于1000个样本),拟合KernelRidge比SVR更快; 然而,对于较大的训练集,SVR可以更好地扩展。 关于预测时间,由于学习的稀疏解决方案,针对所有大小的训练集,SVR比KernelRidge快。 请注意,稀疏程度和预测时间取决于SVR的参数ε和C; ε = 0将对应于一个密集的模型。

分享到

scikit-learn 学习 (六) 线性和二次判别分析

线性判别分析 (discriminant_analysis.LinearDiscriminantAnalysis) 和二次判别分析 (discriminant_analysis.QuadraticDiscriminantAnalysis) 是两种经典分类器, 分别有线性和二次的决策平面.

这些分类器是吸引人的是他们有闭形式解并容易计算, 多分类并且在实际中应用好, 不需要调整超参数.

上图展示了线性判别分析和二次判别分析的决策边界. 下面一行说明线性判别分析只能学习线性边界, 二次判别分析可以学习二次边界因此更灵活.

Examples:

这个例子绘制了LDA和QDA学习的每个类别的协方差椭球和决策边界。 椭球显示每类的双重标准偏差。 对于LDA,所有类别的标准差是相同的,而每个类别与QDA有其自己的标准偏差。

使用线性判别分析降维

discriminant_analysis.LinearDiscriminantAnalysis 可以进行监督学习降维, 通过投影输入的数据到一个线性子空间包括最大化类的分隔的方向, 输出的维数少于类的数目, 所以这通常是一个相当强的维度降低,只能在多类别的环境中有意义。

通过 discriminant_analysis.LinearDiscriminantAnalysis.transform 实现. 目标维数使用 n_components 参数. 这个参数对 discriminant_analysis.LinearDiscriminantAnalysis.fit or discriminant_analysis.LinearDiscriminantAnalysis.predict 没有影响.

Examples:

应用于此数据的主成分分析(PCA)标识了占据数据差异最大的属性(主要成分或特征空间中的方向)的组合。 在这里,我们绘制了2个第一主成分上的不同样本。

线性判别分析(LDA)尝试识别占各类之间差异最大的属性。 具体而言,与PCA相比,LDA是使用已知类别标签的监督方法。

查看更多

分享到

scikit-learn 学习 (五) 广义线性模型

一般最小二乘法

1
2
3
from sklearn import linear_model
reg = linear_model.LinearRegression()
reg.fit([[0, 0], [1, 1], [2, 2]], [0, 1, 2])
LinearRegression(copy_X=True, fit_intercept=True, n_jobs=1, normalize=False)
1
reg.coef_
array([ 0.5,  0.5])

设计矩阵的列如果近似线性相关,会产生多重共线性。

查看更多

分享到