神经网络
最近在学习的过程中,对神经网络有了不同的理解,所以总结了一下自己的学习过程。很多材料都来源于李宏毅老师的ppt以及视频资料。就是自己学习了一下,总结一下,希望能记得更清楚,有更多的理解。
贝叶斯网络
在概率论中有一个很重要的公式,贝叶斯公式。有时我们也称之为全概率公式。它描述的问题是,当我们已知一些事情发生的概率,然后通过结果,我们可以反推出条件。举个例子,假设有个村子,有3个小偷,曾经发生盗窃案,是A犯罪的概率是2/3,是B犯罪的概率是1/3,是C犯罪的概率是0.现村子发生了一起盗窃案,警察介入调查,毫无疑问我们会事先怀疑A,然后再是B,最后是C。就是这么一个过程,警察在调查事情的时候往往会考虑案底,而这个就是我们先验知识。同样的道理,可以扩展到方方面面,生活中到处充满着这种情况。神经网络要解决的问题本质上是回归和分类任务,也就是所谓的预测。那如何预测?从“案底”去评价这个“事情”,似乎是一个不错的选择。
神经网络数学描述:
本质就是一个映射,而这个映射是我们训练出来的映射。回到贝叶斯:
如果第一个结果更大,我们则认为属于类1,如果第二个大我们称之为类2.那下一个问题就是我们怎么去求这些值?我们应该如何去建立这个分类器?
利用已知的样本点,我们可以得到一个模型。我们可以这么想象,任何一个我们需要分类的对象,他们都来自于一个正态分布。现在我们假设有一个数据集,他两个维度的分布如下:
、我们可以认为这些点是从一个正态分布中离散出来的点。那任何一个正态分布都有可能采样出来这些点,那要如何才能确定最有可能的哪个高斯分布呢?
这就是对应数学中的最大似然估计。所以我们就可计算出高斯分布函数。这样我们就能找到分布的边缘
在二维空间我们可以可视化的表达,但是高维空间,我们可以通过计算机直接计算得到结果。对于这个问题来说,貌似结果并不是那么理想。如果对于两个分类问题,我们就需要建立两个高斯分布,这似乎计算太过于复杂。我们能不能让两个分类共享一个 ,那我们就可以建立一下方程:
分类结果竟然从曲线边界,变成了线性?为什么呢?
我们从原始公式考察有:
这里就得到了我们常说的sigmoid function。那下面就是计算Z的问题了
逻辑回归
从上面的过程中,我们要解决这个classification,我们就是要计算出这个sigmoid函数。假设我们有一个分类,用图像表示为:
假设有个节点,输入是多个维度[x1,x2,x3….xn],输出是1,或者0.下面我们就是建立优化函数。还是考虑最大似然估计
当然,损失函数也可以用平方误差,但是这就会出现梯度消失的现象。
假设我们有多个分类器,得到多个结果,例如:
通过一个softmax分类器就可以解决多分类了。但是,问题来了,为啥是用softmax分类器呢?用普通的均值不可以么?用立方,平方,四次方不可以么?比如建立这样的分类器:
似乎也是可以的,但是用softmax肯定有原因的,下次再详细了解softmax,这个问题先放着。
现在,我们考虑另一个问题,逻辑回归似乎能够较好的解决二分类的问题,它是通过画一条直线把两个区域分开。但是,往往很多时候,一条直线似乎是没办法分开的,那怎么办?举个例:
假设我们有红色的点,蓝色的点去做分类,似乎一条直线是无论如何都没办法将他们分开的。那怎么办?我们可不可以做一个线性变换呢?我们可以记每个点到坐标0,0的距离为它的一个变换,那我们就得到了下面点的分布:
这样一条直线就很容易将他们分开了。这个和SVM中的高斯核函数的思想是一致的。那如果我们人为的去寻找这个变换,那这个就和机器学习似乎没啥关系了。所以我们建立一个让机器自动去寻找这个么个变换的模型:
我们第一步先用两个分类器把它分类到另一个空间,通过调整W,b,然后再对新的空间去做分类,似乎就解决了。那这个过程似乎变得熟悉起来,这就是一个级联的分类形式。如果我们把多个串联起来就成了:
这就引出了deep learning。
神经网络
从上述的推导过程,我们已经直到神经网络为什么会达到这个分类的结果。下面我们看看另一个问题:激活函数。
如果把上面的网络简化,去除sigmoid函数,那从前到后的传递我们可以做以下的推导:
第一层有:
这样一直下去,我们可以看到,这个本质上只是做一个线性的叠加而已,所以并没什么用。
所以有了激活函数:
第一层有:
这样就有了非线性的叠加。这也是神经网络解决非线性问题最突出的地方。那神经网络怎么连接呢?每一个节点该如何连接?其实这些都是认为定义的。比如其中一种连接方式:
每一个都和上一个所有的输入连在一起,我们称之为全连接的方式。那每个节点计算权重的方式能不能换一个方式呢?能!我们可以用同一个权重,去计算所有的输入,然后再根据结果更新权重。这就是我们所说的卷积。把卷积层和全连接层连到一起,就构成了卷积神经网络。
其实pooling层也是一种卷积,只不过pooling的作用就是减少数据量仅此而已。那为啥减少了数据量结果似乎也蛮好的,本质上我们也很难知道,唯一能想到的可能就是数据太多了,减少一点似乎也不会有啥影响。我们可以理解为,神经网络就是把一个我们再我们考虑的维度下分不出来的数据,转成更高维度可以分辨的东西,它只是对数据的一系列的运算,仅此而已。比如我们人去分类一些图片,如果我们看到这是一只狗当然能分出来。如果我给你一个抽象出来的图像矩阵,我想怎么也分辨不出来吧。如果这个图片的维度只是二维,我们似乎可以把他们画出来寻找一个边界把他们区分开,但是这个边界又不是那么容易确定,怎么办,让机器去算吧。
神经网络源码
作为CSDN咋能纯理论,不给任何代码跑跑看呢,所以就随便贴一个神经网络的代码吧
# -*- encoding: utf-8 -*-
"""
@File : tensorboard3.py
@Time : 2020/1/9 15:27
@Author : dwy
@Email :
@Software: PyCharm
"""
# coding: utf-8
# In[1]:
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
from tensorflow.contrib.tensorboard.plugins import projector
# In[2]:
# 载入数据集
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
# 运行次数
max_steps = 1001
# 图片数量
image_num = 3000
# 文件路径
DIR = "D:/MyCode/python3.6/tensorflow/day2/"
# 定义会话
sess = tf.Session()
# 载入图片
embedding = tf.Variable(tf.stack(mnist.test.images[:image_num]), trainable=False, name='embedding')
# 参数概要
def variable_summaries(var):
with tf.name_scope('summaries'):
mean = tf.reduce_mean(var)
tf.summary.scalar('mean', mean) # 平均值
with tf.name_scope('stddev'):
stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
tf.summary.scalar('stddev', stddev) # 标准差
tf.summary.scalar('max', tf.reduce_max(var)) # 最大值
tf.summary.scalar('min', tf.reduce_min(var)) # 最小值
tf.summary.histogram('histogram', var) # 直方图
# 命名空间
with tf.name_scope('input'):
# 这里的none表示第一个维度可以是任意的长度
x = tf.placeholder(tf.float32, [None, 784], name='x-input')
# 正确的标签
y = tf.placeholder(tf.float32, [None, 10], name='y-input')
# 显示图片
with tf.name_scope('input_reshape'):
image_shaped_input = tf.reshape(x, [-1, 28, 28, 1])
tf.summary.image('input', image_shaped_input, 10)
with tf.name_scope('layer'):
# 创建一个简单神经网络
with tf.name_scope('weights'):
W = tf.Variable(tf.zeros([784, 10]), name='W')
variable_summaries(W)
with tf.name_scope('biases'):
b = tf.Variable(tf.zeros([10]), name='b')
variable_summaries(b)
with tf.name_scope('wx_plus_b'):
wx_plus_b = tf.matmul(x, W) + b
with tf.name_scope('softmax'):
prediction = tf.nn.softmax(wx_plus_b)
with tf.name_scope('loss'):
# 交叉熵代价函数
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=prediction))
tf.summary.scalar('loss', loss)
with tf.name_scope('train'):
# 使用梯度下降法
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(loss)
# 初始化变量
sess.run(tf.global_variables_initializer())
with tf.name_scope('accuracy'):
with tf.name_scope('correct_prediction'):
# 结果存放在一个布尔型列表中
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(prediction, 1)) # argmax返回一维张量中最大的值所在的位置
with tf.name_scope('accuracy'):
# 求准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) # 把correct_prediction变为float32类型
tf.summary.scalar('accuracy', accuracy)
# 产生metadata文件
if tf.gfile.Exists(DIR + 'projector/projector/metadata.tsv'):
tf.gfile.DeleteRecursively(DIR + 'projector/projector/metadata.tsv')
with open(DIR + 'projector/projector/metadata.tsv', 'w') as f:
labels = sess.run(tf.argmax(mnist.test.labels[:], 1))
for i in range(image_num):
f.write(str(labels[i]) + '\n')
# 合并所有的summary
merged = tf.summary.merge_all()
projector_writer = tf.summary.FileWriter(DIR + 'projector/projector', sess.graph)
saver = tf.train.Saver()
config = projector.ProjectorConfig()
embed = config.embeddings.add()
embed.tensor_name = embedding.name
embed.metadata_path = DIR + 'projector/projector/metadata.tsv'
embed.sprite.image_path = DIR + 'projector/data/mnist_10k_sprite.png'
embed.sprite.single_image_dim.extend([28, 28])
projector.visualize_embeddings(projector_writer, config)
for i in range(max_steps):
# 每个批次100个样本
batch_xs, batch_ys = mnist.train.next_batch(100)
run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)
run_metadata = tf.RunMetadata()
summary, _ = sess.run([merged, train_step], feed_dict={x: batch_xs, y: batch_ys}, options=run_options,
run_metadata=run_metadata)
projector_writer.add_run_metadata(run_metadata, 'step%03d' % i)
projector_writer.add_summary(summary, i)
if i % 100 == 0:
acc = sess.run(accuracy, feed_dict={x: mnist.test.images, y: mnist.test.labels})
print("Iter " + str(i) + ", Testing Accuracy= " + str(acc))
saver.save(sess, DIR + 'projector/projector/a_model.ckpt', global_step=max_steps)
projector_writer.close()
sess.close()
# In[ ]:
用到的文件自己去下载吧,手写字体识别。