基本操作
图片读取展示
1 | import cv2 # 引入OpenCV |
cv.imread 过程:1文件读取 2封装格式解析 3数据解码 4数据加载
读写操作
图片读写
1 | import cv2 |
操作像素
1 | import cv2 |
OpenCv
OpenCv模块结构
1 | to be continued |
Tensotflow
基本操作
概况
1 | import tensorflow as tf |
类型
1 | # tensorflow运算的每个类型都要是tensor |
创建tensor
1 | a.convert_to_tensor() |
索引与切片
1 | # 索引 |
维度变换
1 | # a.shape = [4,28,28,3] |
Broadcasting
- expand without copying data:扩张了一个数据,但实际上并没有复制出来多份
1 | tf.broadcast_to |
数学运算
1 | # element-wise: +-*/ |
手写数字识别,你可能用到
1 | import tensorflow as tf |
合并与拼接
1 | c =tf.concat([a,b],axis=0) # a和b第0维度合并 |
数据统计
- 范数
- 二范数
$${||x||}_2 = [\sum_k{x^2_k}]^\frac{1}{2}$$ - 无穷范数
- 一范数..等等
$${||x||}_1 = \sum_k{|x_k|}$$
- 二范数
1 | ### 这里讨论的都是向量的范数(非矩阵) |
张量排序
1 | tf.sort(a,direction='DESCENDING') # 降序, direction='ASCENDING'就能升序 |
填充与复制
1 | # 填充 pad |
张量的限幅
1 | # 限制最小值 |
高级操作
1 | # 筛选 mask = [True,False,True] |
神经网络与全连接层
数据集的加载(小型)
1 | # 数据集准备 |
全连接层
1 | # 每个节点跟每个节点连接——Dense |
输出方式
1 | # 输出范围压缩 |
损失函数的计算
- MSE
$$loss=\frac{1}{N}\sum(y-out)^2$$1
2
3loss1 = tf.reduce_mean(tf.square(y-out))
loss2 = tf.reduce_mean(tf.losses.MSE(y,out))
# loss1 = loss2 等价
标差熵
- 熵 $Entropy = -\sum P(i)\log_2{P(i)}$
- 不确定度 Uncertainty
- 惊奇度 measure of surprise
- lower entropy -> more info
交叉熵 Cross Entropy
描述两个集合p,q的惊奇度
- $H(p,q) = -\sum{p(x) \log_2{q(x)}}$
- $H(p,g) = H(p) + D(p|q)$
- $D(p|q)$ 表示p和q的离散度
- 当p=q时$D(p|q)=0$
for p:one_hot encoding
- $h(p:[0,1,0]) = -1\log_2{1}=0$
- $H([0,1,0],[q_1,q_2,q_3]) = 0+D(p|q)=-1\log{q_1}$
- 即要使p逼近与q用交叉熵的方法的可行的
具体解法
设一组分类的one_hot encoding是$P_1[1,0,0,0,0]$;
一组输出为$Q_1[0.4,0.3,0.05,0.05,0.5]$;
则:
$$\begin{aligned}
loss &= H(p,q) \
&= -\sum{P_1(x) \log_2{Q_1(x)}} \
&= -\log_2{0.4} \
&= 0.916
\end{aligned}
$$
然后lr,w1,b2…,多次学习后发现loss越来越小,即q = p
- 在tensorflow中的使用
1 | tf.losses.categorical_crossentropy(p,q) # 函数的形式 |
梯度下降 Gradient Descent
- 梯度:向量grad
- 用梯度下降来逼近
$$ w_n = w - lr \times \frac{\partial{loss}}{\partial{w}} $$
- 用梯度下降来逼近
- 在tensorflow中的使用
1 | with tf.GradientTape() as tape: # 把计算过程包在里面 |
激活函数 Activation Function
科学家在研究青蛙神经是发现,当刺激到达一定程度是青蛙才会做出相应的反应,是个离散的过程
因此在深度学习中就可模仿设点,设计神经网络,因此有了激活函数
连续的光滑的激活函数
- sigmoid(logistic)
- $f(x)=\delta(x)=\frac{1}{1+e^{-x}}$
y = tf.sigmoid(a)
- 可以将范围压缩到[0,1]
- 但当x接近无穷时,导数几乎为零,导致梯度离散,使得长期得不到更新
- Tanh
- $f(x)=tanh(x)=\frac{(e^x-e^{-x})}{e^x+e^{-x}}=2sigmoid(2x)-1$
y = tf.tanh(a)
- ReLU(Rectified Linear Unit)
- $
f(x) = \begin{cases}
0, & \text{if } x < 0 \
x, & \text{if } x \geq 0
\end{cases}
$ tf.nn.relu()
- 深度学习最常用的
- 优势
- 求导简单
- 不会放大或缩小梯度(reLU的导数为1)
- $
- Softmax
- $S(y_i)=\frac{e^{y_i}}{\sum_j{e^{y_i}}}$
- 常用于多分类问题,因为它把logits转换为prob
- 区别于一般的转换成prob的方法,Softmax会把大的放大,小的缩小;拉大差距(sotf version of max)
- 求导:把先把分子分母看做整体
f(x)和g(x)
然后相当于$\frac{\partial p_i}{\partial a_j}=\frac{f’(x)g(x)-f(x)g’(x)}{g(x)^2}$;注意i和j不同的情况要分开讨论- $$
\frac{\partial p_i}{\partial a_j} = \begin{cases}
p_i(1-p_1), & \text{if } i=j \
-p_jp_i, & \text{if } i\neq j
\end{cases}
$$
- $$
Loss函数的梯度
经典的loss函数
- Mean Squared Error(MSE,均方差)
- $loss=\frac{1}{N}\sum(y-out)^2$
loss1 = tf.reduce_mean(tf.square(y-out))
loss2 = tf.reduce_mean(tf.losses.MSE(y,out))
- Cross Entropy Loss
- Softmax
链式法则
$\frac{\partial y}{\partial x} = \frac{\partial y}{\partial u}\frac{\partial u}{\partial x}$
感知机梯度传导
利用链式法则从输出往输入退就可以知道梯度信息,然后更新
可视化
- tensorboard
pip install tensorboard
- 在代码中写入
summary_writer = tf.summary.create_file_writer(DIR)
- 拿到
summary_writer
后就可以忘里面喂数据
1 | # 1,喂数据点 |
- visdom
Keras高层API
优化
在计算loss,accuracy的时候经常会发现数据忽高忽低,所以可借助keras的api来优化
- metrics测量
- keras会将数据放在一个list,然后取平均值来优化?
- 如
loss_meter = metrics.Mean()
,acc_meter = metrics.Accuracy()
- update_state更新数据
loss_meter.update_state(loss)
,acc_meter.update_state(y, pred)
- result().numpy()获取结果,转换成numpy输出
loss_meter.result().numpy()
result得到tensor,再转换成numpy
- reset_states释放数据
- 当要废弃旧的数据时
loss_meter.reset_states()
- 当要废弃旧的数据时
Compile&Fit
- Compile,类似装载弹药,可以指定loss,优化器,评估指标
- Fix,完成标准创立
- Evaluate,测试
- Predic,拿创建好的模型来预测
1 | ### 一般的流程 |
自定义网络
- keras.Sequential(layer1, layer2, …)
- 参数要继承自
keras.layers.Layer()
- 建立好网络后variable(w和b)是没有的
- 法1:指定输入shape
network.build(input_shape=(None, 28*28))
- 法2:自动识别
network(x)
- 这个的原理是调用了类中的call()方法,相当于network.call(x)。同理自定义类中也可如此
- 法1:指定输入shape
- 参数要继承自
- keras.layers.Layer()
- 任何要自定义的层要继承自它
- keras.Model()
- compile/fit/evaluate
- Sequential也是继承自该类,所以自定义的网络应该继承这个
1 | class MyDense(layers.Layer): # 自定义层继承 |
模型的加载与保持
- save/load weights
- 只保存模型参数
- 缺点是没有源代码,网络不得而知
- save/load entire model
- 简单粗暴的
- saved_model
- 通用的保存格式
save/load weights
1 | # save |
save/load entire model
1 | # save |
saved model
1 | # save |
过拟合和欠拟合
现实情况是我们并不知道模型的符合什么分布
- model capacity,模型的学习能力
- 显然项越多越高
- underfitting
- 模型的表达能力弱于真实数据,如用直线拟合双曲线
- overfitting
- 模型的表达能力大于真实数据,把不必要的噪声也拟合进来了
- 最常见
检查overfitting
交叉验证
检查欠拟合和过拟合的方法
一般情况下会把数据集切分(splitting)成三份,作用分别是train set,val set,test set
数据集一部分用来训练,一部分用来验证accuracy这是是显然的,那为什么有第三份呢?
因为在真实的需求中,是不是有取巧的人会把test用的数据集也用来训练,从而过拟合来达到很高的准确度(但实际它们已经过拟合了)
所以第三份是用来防止这种情况发生的,不参与训练的,最终检验模型的数据集
1 | network.compile( |
K-fold cross-validation
由上面知,test set是完全不能动的,所以在切分的时候train set和val set可以随机的切分,可以防止网络记忆特性
1 | # 在tensorflow中可以表现为 |
减轻overfitting
Regularization
- L1-regularization
- loss加上lambda约束的一范式
- $j(\theta) = -\sum^m_1{y_i\log_e{\bar y_i} + (1-y_i)\log_e{(1-\bar y_i)}} + \lambda \sum_i^n{|\theta_i|}$
- L2-regularization
- loss加上lambda约束的一范式
- $J(W;x,y)+\frac{1}{2} \times ||W||^2$
1 | # 法一:在一层网络中添加kernel_regularizer参数 |
动量与学习率
Momentum 动量
由于梯度的更新,会有大幅的反复跳跃的现象,动量就是在更新方向的基础上结合上一阶段的方向进行梯度更新,从而使得更平缓,像踩刹车一样
1 | optimizer = SGD(learing_rate=0.02, momentum=0.9) # momentum 就在超参数lambda |
Learning rate 学习率
学习率动态调整来优化网络
1 | optimizer = SGD(learing_rate=0.02) |
Early Stopping & Dropout
Early Stopping
很多情况下虽然training accuracy还在上升,但是validation accuracy以及达到最优甚至开始下降了,这是就需要以前终止
Dropout
和overfitting的情况一样,为减少噪声的干扰,可以减少节点数(?矩阵里面的?),learning less to learning better
1 | network = Sequential([layers.Dense(256, activation='relu'), |
因为training和test的策略不同(training时为得到更好的w,b,而使用dropout的方法来减小overfitting,所以开启dropout,test是测试模型,所以不用开)
1 | # training |
Stochastic
Deterministic
卷积神经网络
在处理图像问题时,使用全连接的方式会导致大量的资源占用.
于是由生物学上眼睛可视域的启发,我们采用局部连接,然后滑动直至扫描全部输入。特点在于对于相同的层如(RGB),每次扫描的观察方式(卷积核)是一样的(weight sharing)
所以学习的时候就大大减少了参数量
卷积
信号的叠加叫做卷积,得到的结果叫做feature map
$$
y(t)=x(t) * h(t)=\int^\infty _ {-\infty} x(\tau)h(t-\tau)\mathrm{d}x
$$
* 表示卷积操作,x就相当于输入,h就相当于观察方式(卷积核),t就相当偏移量,扫过整个图片t发生改变x和h卷积出信号输出y
Padding & Stride
- Padding
- 把输入层扩大(虚的)然后扫描后就能得到维度与输入相等的输出
- Stride
- 把扫描的步长加大,就能减少输出的维度
1 | layers.Conv2D(4, kernel_size=5, stride=1, padding='samd') # 卷积核个数,5*5,步长,'same'可以保证输入维度等于输出 |
Channels
- 设输入是[1, 32, 32, 3],32*32的图片,3个通道
- 那我们的一个卷积核可以是[3, 5, 5] 3表示输入通道的数量(RGB)
- 最后可以得到一个[b, 30, 30, 1]的输出
- 如果使用多个核如[N, 3, 5, 5]那就能得到N个[b, 30, 30, 1]即[b, 30, 30, N]
多通道输出,多通道输入
Gradient
$$
O _ {mn} = \sum {x _ {ij} * w _ {ij}} + b \
\frac{\delta Loss}{\delta w _ {ij}}
$$
Classic Network
GoogLeNet
When the network get deeper, above 20, is get harder to training, even make trains revoke.
ResNet
Residual
Sequence
Signal with time order
- sequence embed
- turn digital signal into a sequence
Many sets can be like a sequence. mnist for example[b, 28, 28]. can expand like [b, time, 28] or [time, b, 28] and so on.
But a sequence better to expand like a time orde things [time, b, 28] is much better. It depend on how you expand.
Here are some rules:
- semantic similarity
- trainable
Cycle network
Two question:
Long sentence
- weight sharing
- We can do like a conv_net
Context information
- It is a pertinence bettween word and word
- Here is the example formulation
$$\begin{aligned}
h_t &= f_w(h_{t-1}, x_t) \
h_t &= tanh(W_{hh}h_{t-1} + W{xh}x_t) \
y_t &= W_{hy}h_t \
\end{aligned}$$
RNNlayer
SimpleRNN
$$
\begin{aligned}
call &= xw_{xh} + h_tw_{hh}, (for\ each\ item\ in\ timeline) \
out_1, h_1 &= call(x, h_0) \
out_2, h_2 &= call(x, h_1) \
out_t, h_t &= call(x, h_{t-1})
\end{aligned}
$$
$h_t$ and $out_t$ is the same thing(id) but have difference meaning
Optimize
- Step 1:Gradient Exploding
- Gradient Clipping
- $grad = \frac{|grad|}{grad}$ ,shrink to 1 and mult $15\times{lr}$
grads = [tf.clipe_by_norm(g, 15) for g in grads]
- Step 2:Gradient Vanishing
- LSTM \ GRU
LSTM
Compare with RNN(short term memory), which can only remenber nearly sentence.LSTM is long short term memory.
LSTM use three gates(sigmoid) to contral the signal.
- Forget gate
- $f_t = \sigma(W_f\cdot[h_{t-1}, x_t]+b_f)$
- Input gate
- $$
\begin{aligned}
i_t &= \sigma(W_i\cdot[h{t-1}, x_t] + b_i) \
\widetilde{C_t} &= tanh(W_C\cdot[h_{t-1}, x_t] + b_C)
\end{aligned}
$$
- $$
- Cell state
- $C_t = f_f * C_{t-1} + i_t * \widetilde{C_t}$
- Output gate
- $$
\begin{aligned}
O_t &= \sigma(W_o[h_{t-1}, x_t] + b_o) \
h_t &= O_t * tanh(C_t)
\end{aligned}$$
- $$
GRU
Auto-Encoder
Why we need:
- Dimension reduction
- Visualization
- Take advantages of unsupervised date
- Unsupervise
- Reconstruct itself
Denoising AutoEncoder
Add some noise and can still reconstruct well. Means model can dig out information from a mass data.
Dropout AutoEncoder
Use dropout to autoencoder. It the hard dropouted network can than the disdropout network do better.
Adversarial AutoEncoder
Variational AutoEncoder
Gen
- Painter or Generator
- Critic or Discriminator
$$
\begin{aligned}
min_G\ max_D\ L(D,G) &= E_{xp_r(x)}[\log{D(x)}] + E_{zp_r(z)}[\log{1-D(G(z))}] \
&= E_{xp_r(x)}[\log{D(x)}] + E_{xp_r(x)}[\log{1-D(x)}] \
\end{aligned}
$$
Both of they want to maximum and than get a nash equilibrium
Nash Equilibrium
- Q1.Where will D converge, given fixed G
- Q2.Where will G converge, after optimal D
tensorflow运行机制
1 | # 本质 tf = tensor + 计算图 |
四则运算
1 | # 如果是变量的话要先init |
矩阵运算
1 | # 数据装载 |
Loss Function
loss function:
$$loss = \sum_i(w\times x_i+b-y_i)^2 \tag{1}$$
loss 累加会很大,所以一般会除以元素个数n,结果还是一样的
$$w^= w - lr \times \frac{\partial{loss}}{\partial{w}} \tag{2}$$
$$b^
= b - lr \times \frac{\partial{loss}}{\partial{b}}$$
这样就会得到新的w b,再返回第(1)步,如此循环就能得到最回事的w b
对loss的求导其实有规律可循:
$$\frac{\partial{loss}}{\partial{w}} = \frac{2}{n}\sum(wx + b - y)x$$
$$\frac{\partial{loss}}{\partial{b}} = \frac{2}{n}\sum(wx + b - y)$$
Discrete Prediction
离散值预测
Classification (分类)为例
显然的离散的问题,那我们要怎么解决离散的问题呢?
激活函数 activation
常见的有ReLU和sigmoid
目的是为了把线性的值离散化,然后才能套用上面的公式
但是就算用一个函数把线性模型离散化了,但还是太简单
所以引入隐藏层概念
input -> h1 -> h2 -> out
经过多层隐藏层问题就更加离散了
$$h1 = relu(x@w_1 + b_1)$$
$$h2 = relu(h1@w_2 + b_2)$$
$$out = relu(h2@w_3 + b_3)$$
@表示矩阵乘法, 每道工序都有自己的参数
那参数w和b怎么确定呢?
若我们想要识别0~9,那我们是不是应该希望最后输出是有10类(一个[1,10]的矩阵,每个元素可以代表一个数字)
那么根据矩阵运算的规则(nm*mt = nt),所以我们只要控制每层运算符合矩阵乘法规则且最后输出是我们想要的规模就好
最后再用out来计算loss(这里是欧氏距离(n维空间两点的距离)的loss)
然后就可以反复更新w` b`了
Numpy
tensorflow的弟弟版,因为他不能GPU计算
基本操作
1 | x1 = np.array([第一行],[第二行]...) |
Matplotlib
import matplotlib as plt
基本操作
1 | x = np.array([1,2,3,4,5,6,7,8]) |