分类问题

Discrete Prediction(离散值的预测)

  • [up,left,down,right]、[dog,cat,whale,…]

ImageNet:包含1000种常见生活物体

Hand-written Digits Recignition(手写数字体识别)

MNIST数据集

Image

在这里插入图片描述

[28,28,1] 28行28列 -> [784]

每个像素点为0~255(灰度值)

彩色图片的话可能为[ 28 , 28 , 3(RGB)]

为了获得打平后的向量的值,变成一维的数值。后一行的数值放在前一行的末尾。[28,28] -> [28*28] = [784]

Input and Output

在这里插入图片描述

分类问题的输出。输入是[b,784],b理解为一共有多少张图片。

分类问题的分类

最简单的方法是 给每一个类别直接编号一个具体的数值

  • dog=0,cat=1,fish=2…

    1.1理解为cat,2.2理解为fish

    这种编码方式非常直观好理解,但是有两个致命问题

    1. 数字之间有天生的大小关系,而类别是独立的存在
    2. 我们会觉得2.2比2.3更符合2,而不是3。但是这样的解释并不符合概率论的知识概念

更好的方式是,把每种具体的类别理解为具体的node,9个类别有9个node,没有大小(顺序)的关系。还有第二,每一个node有具体的实数值,这个值会归一化为0~1的区间。

每个node为 P(y=0|x)…

并且会尽量使它们之间的和为1。因为每张图片是0~9的其中1个,它总是会属于这10个node中的一个节点,这样会使得 ∑ i = 0 − 9 P ( y = i ∣ x ) = 1 \sum_{i=0-9} P(y=i|x) = 1 i=09P(y=ix)=1。这是一种输出的编码方式,这种方式叫one-hot编码,因为每一张图片只属于输出节点中的一种。

10个类别的概率和为1,它们之间有一个最大的概率,把它理解为当前类别的置信度。去最大的概率的node的名字作为当前物体的识别种类的归类

Regression VS Classification

在这里插入图片描述

套用Regression的机制来直接处理Classification的问题

对于Regression,给出了w和b参数以后,生成了y的预测值,y属于连续的范围, R d R^d Rd(一维的线性的实数空间),不一定覆盖全部实数空间,比如温度。

对于Classification,out输出为1维的长度为10的向量,每一个元素所在的位置就是当前 P ( y = i ∣ x ) P(y=i|x) P(y=ix),每一个值属于0~1的范围。我们把输出值所在位置最大的那个值概率叫做置信度,值所在的索引,在上图也就是1把它理解为当前图片数据1号元素的概率P(y=1|x) = 0.8,理解为这张图片可能就是1了。

Computation Graph

在这里插入图片描述

具体的Classification计算。

输入是28*28,打平成784 -》[1,784],一张照片有784个像素

W和b根据相应的维度来匹配,W[784,10] b[10]。《-因为输出肯定是[1,10]的矩阵,10类的置信度,反推W和b的形状。要满足相乘规则只能W[784,10]。

[1,10] + [10]是可以直接进行运算的,经过broadencast -》 [1,10],理解为【0.1(label=0),0.8(label=1),…】,理解为属于1的概率最大

但是现在不算是完成了Classification的求解

第一个问题是这个模型是线性的。

在这里插入图片描述

对于回归问题,大部分情况都比较简单,可以用Linear模型去完成Regression问题,所以Linear Regression采用的比较多;但是对于一个高维的图片的识别,一张图片识别的逻辑是非常复杂的,光线性模型是不能完成手写图片识别的复杂任务,它有784维的输入。

因此我们需要添加进来一个非线性的因子,在原来的输出上面添加f function,它必须是非线性的,这样才能引入非线性因子在里面,我们也不希望太复杂,把f function叫做激活函数(activation),有一种非常常见的形式,叫做ReLU。ReLU是非线性的,是一条折线。使用激活函数,使得现在的整个模型就已经是非线性模型了。

第二个问题是太简单了。

在这里插入图片描述

光光一次输出还是难以满足识别。我们想到火车的模型,我们将第一次的输出当做下一个层的输入,称为隐藏层。一层层地连接。

Particularly

在这里插入图片描述

给一个输入X[1,784],进行一次计算相当于降维的过程,重复降维过程,最终降到[1,10],恰好是我们想要输出的形式,不停地挂接工序,随后转义为置信度。

[1,784] -> [1,512] -> [1,256] -> [1,10]

结果 [0,0,0.1,0.1,0.8, …]

Loss?

在这里插入图片描述

label: 0~9,out和label的维度都是[1,10]。对于三维为例,Label在坐标轴上,而out(输出值)在空间上,我们期望out越来越逼近于y,因为我们希望输出值接近于真实值。计算loss,我们可以计算MSE(欧氏距离),也就是out到y之间的欧氏距离, l o s s = ∑ ( y − o u t ) 2 loss = \sum(y-out)^2 loss=(yout)2

在这里插入图片描述

经过三道工序,得到输出。

loss函数计算是out和label之间做MSE(欧氏距离),用loss来优化参数,也就是 [ W 1 ′ , b 1 ′ , W 2 ′ , b 2 ′ , W 3 ′ , b 3 ′ ] [W_1',b_1',W_2',b_2',W_3',b_3'] [W1,b1,W2,b2,W3,b3],不停地最小化它们。

然后用这些参数来预计最新的X,获得新的out,取out概率最大的那个元素的index,它就可能属于类别index。

深度学习。三大工序的串接已经有deep learning的模型了,只不过层数更深。

Classification Procedure

在这里插入图片描述

Next下一步

在这里插入图片描述

  1. MNIST感受学习
  2. 学习TensorFlow
  3. 自己实现第1步的过程

手写数字问题初体验

在这里插入图片描述

对于MNIST,输入的节点数为0,1,2…783。

输出为0,1,2,…9

整个计算流程包含了5步:

  1. 数据集的准备
  2. 完成前面的推算,h1,h2,out。
  3. 根据实际的y计算loss
  4. 根据loss求解梯度并且更新网络中间的参数,[w1,b1,w2,b2,w3,b3]
  5. 根据数据集进行循环往复的更新,随后停止。获得[w1,b1,w2,b2,w3,b3]后就可以进行新的样本的预测了。

实际代码

import  os
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets,layers,optimizers

#自动下载或调用mnist的图片,training-60K,test-10K
(x,y),_ = datasets.mnist.load_data()
#60张图片,28*28-(60000, 28, 28)
# 每个y的label为0~9的数字这里还没有进行one-hot编码(存储不高效),运算时在onehot-(60000,)。
#在这里为1维的,长度为60K的数字
print('datasets:',x.shape,y.shape)

#上面x数据返回的是numpy的格式,需要转换为TensorFlow支持的载体格式-tensor
x = tf.convert_to_tensor(x,dtype=tf.float32) / 255
y = tf.convert_to_tensor(y, dtype=tf.int32)
#进行one hot编码
y = tf.one_hot(y, depth=10)
#(60000, 28, 28) (60000, 10)
print(x.shape, y.shape)
#转换成Dataset类型,做一次运算,比如一个样本[1,784],对GPU来说很快,
#因此可以完成多个样本,这里有b。[b,784],有batch概念。做做运算不是针对1个图,而是多个图片,高度并行化流程
train_dataset = tf.data.Dataset.from_tensor_slices((x,y))
#一次加载200张图片
train_dataset = train_dataset.batch(200)

# for step,(x,y) in enumerate(db):
#     print(step,x.shape,y.shape)

#准备网络结构和优化器
model = keras.Sequential([
    layers.Dense(512,activation='relu'),
    layers.Dense(256,activation='relu'),
    layers.Dense(10)])

#w' = w - lr*(\del loss/del w)
#代码实现的是自动更新参数
optimizer = optimizers.SGD(learning_rate=0.01)

#一个数据集迭代一次,一次数据集完成叫做一次epoch
def train_epoch(epoch):
    # Step4.loop
    #重复更新参数的循环
    #step=batch,一个batch迭代一次,一共重复300次若batch=200的话,300*200=60K
    for step, (x, y) in enumerate(train_dataset):

        with tf.GradientTape() as tape:
            # [b, 28, 28] => [b, 784]
            x = tf.reshape(x, (-1, 28 * 28))
            # Step1. compute output
            #h1 h2 out
            # [b, 784] => [b, 10]
            out = model(x)
            # Step2. compute loss
            #(1/N) \sum (y-out)^2
            loss = tf.reduce_sum(tf.square(out - y)) / x.shape[0]

        # Step3. optimize and update w1, w2, w3, b1, b2, b3
        #传统先求\del loss / \del w,h1->h2->out,知道它们可导,但是这样非常复杂和麻烦
        #下面自动求导,loss,model.trainable_variables=[w1, w2, w3, b1, b2, b3]
        #返回梯度,第一个\del loss / \del w1 ...
        grads = tape.gradient(loss, model.trainable_variables)
        # w' = w - lr * grad
        #分别更新参数[w1, w2, w3, b1, b2, b3],利用上式,w(或b)为以前的w(或b),grad为算出来的导数
        optimizer.apply_gradients(zip(grads, model.trainable_variables))

        if step % 100 == 0:
            print(epoch, step, 'loss:', loss.numpy())

def train():
    #对数据集迭代30次,30个epoch
    for epoch in range(30):
        train_epoch(epoch)

if __name__ == '__main__':
    train()

一部分结果

datasets: (60000, 28, 28) (60000,)
(60000, 28, 28) (60000, 10)
0 0 loss: 1.8705982
0 100 loss: 0.5503684
0 200 loss: 0.39639312
1 0 loss: 0.3495443
1 100 loss: 0.3756662
1 200 loss: 0.29594418
2 0 loss: 0.2724363
2 100 loss: 0.3165485
2 200 loss: 0.2512417
3 0 loss: 0.23431014
3 100 loss: 0.28171945
3 200 loss: 0.22504988
4 0 loss: 0.21070758
4 100 loss: 0.25822794
4 200 loss: 0.20751897
5 0 loss: 0.19436865
5 100 loss: 0.24138512
5 200 loss: 0.19375528
6 0 loss: 0.18220048
00 loss: 0.3165485
2 200 loss: 0.2512417
3 0 loss: 0.23431014
3 100 loss: 0.28171945
3 200 loss: 0.22504988
4 0 loss: 0.21070758
4 100 loss: 0.25822794
4 200 loss: 0.20751897
5 0 loss: 0.19436865
5 100 loss: 0.24138512
5 200 loss: 0.19375528
6 0 loss: 0.18220048
6 100 loss: 0.22804554

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐