神经网络

神经网络基础与原理

神经网络
  1. 人工神经网络( Artificial Neural Network, 简写为ANN)也简称为神经网络(NN)。
    1. 是一种模仿生物神经网络(动物的中枢神经系统,特别是大脑)结构和功能的 计算模型。经典的神经网络结构包含三个层次的神经网络。分别输入层,输出层以及隐藏层
    2. 其中每层的圆圈代表一个神经元,隐藏层和输出层的神经元有输入的数据计算后输出,输入层的神经元只是输入
  2. 神经网络的特点
    1. 每个连接都有个权值
    2. 同一层神经元之间没有连接
    3. 最后的输出结果对应的层也称之为全连接层
  3. 神经网络是深度学习的重要算法,用途在图像(如图像的分类、检测)和自然语言处理(如文本分类、聊天等)
感知机(PLA: Perceptron Learning Algorithm)
  1. 感知机就是模拟这样的大脑神经网络处理数据的过程

  2. 感知机是一种最基础的分类模型,前半部分类似于回归模型。感知机最基础是这样的函数,而逻辑回归用的sigmoid。这个感知机具有连接的权重和偏置

  3. 公式

    \[u=\sum^n_{i=1}w_ix_i+b\\y=sign(u)=\begin{cases} +1& u>0\\ -1& u \leq 0 \end{cases}\]

playground使用
  1. http://playground.tensorflow.org/
  2. 要区分一个数据点是橙色的还是蓝色的,你该如何编写代码?也许你会像下面一样任意画一条对角线来分隔两组数据点,定义一个阈值以确定每个数据点属于哪一个组
    1. 其中 b 是确定线的位置的阈值。通过分别为 x1 和 x2 赋予权重 w1 和 w2,你可以使你的代码的复用性更强
    2. \(w_1x_1+w_2x_2>b\)
    3. 此外,如果你调整 w1 和 w2 的值,你可以按你喜欢的方式调整线的角度。你也可以调整 b 的值来移动线的位置。所以你可以重复使用这个条件来分类任何可以被一条直线分类的数据集。但问题的关键是程序员必须为 w1、w2 和 b 找到合适的值——即所谓的参数值,然后指示计算机如何分类这些数据点
  3. playground简单两类分类结果
    1. 但是这种结构的线性的二分类器,但不能对非线性的数据并不能进行有效的分类
  4. 感知机结构,能够很好去解决与、或等问题,但是并不能很好的解决异或等问题
  5. 单神经元复杂的两类-playground演示
  6. 多个神经元效果演示
  7. 神经网络解决多分类问题最常用的方法是设置n个输出节点,其中n为类别的个数
softmax回归
  1. Softmax回归将神经网络输出转换成概率结果

  2. 公式

    \[softmax(y)_i=\frac{e^{y_i}}{\sum^n_{j=1}e^{y_i}}\]

  3. softmax特点

    #如何理解这个公式的作用呢?看一下计算案例
    #假设输出结果为:2.3, 4.1, 5.6
    #softmax的计算输出结果为:
    #y1_p = e^2.3/(e^2.3+e^4.1+e^5.6)
    #y1_p = e^4.1/(e^2.3+e^4.1+e^5.6)
    #y1_p = e^5.6/(e^2.3+e^4.1+e^5.6)
  4. 这样就把神经网络的输出也变成了一个概率输出

    1. 如何去衡量神经网络预测的概率分布和真实答案的概率分布之间的距离
交叉熵损失
  1. 公式

    \[H_{y'}=-\sum_iy_i'\log(y_i)\]

  2. 为了能够衡量距离,目标值需要进行one-hot编码,能与概率值一一对应

  3. 损失如何计算

    0log(0.10)+0log(0.05)+0log(0.15)+0log(0.10)+0log(0.05)+0log(0.20)+1log(0.10)+0log(0.05)+0log(0.10)+0log(0.10)
    
  4. 上述的结果为1log(0.10),那么为了减少这一个样本的损失。神经网络应该怎么做?所以会提高对应目标值为1的位置输出概率大小,由于softmax公式影响,其它的概率必定会减少。只要这样进行调整这样是不是就预测成功了!

  5. 提高对应目标值为1的位置输出概率大小

  6. 损失大小

    1. 神经网络最后的损失为平均每个样本的损失大小。对所有样本的损失求和取其平均值
梯度下降法
  1. 目的:使损失函数的值找到最小值

  2. 方式:梯度下降

    1. 函数的梯度(gradient)指出了函数的最陡增长方向。梯度的方向走,函数增长得就越快。那么按梯度的负方向走,函数值自然就降低得最快了。模型的训练目标即是寻找合适的 w 与 b 以最小化代价函数值。假设 w 与 b 都是一维实数,那么可以得到J 关于 w 与 b 的图

    2. 公式

      \[w:=w-\alpha\frac{dJ(w,b)}{dw},b:=b-\alpha\frac{dJ(w,b)}{db}\]

    3. 其中 α 表示学习速率,即每次更新的 w 的步伐长度。当 w 大于最优解 w′ 时,导数大于 0,那么 w 就会向更小的方向更新。反之当 w 小于最优解 w′ 时,导数小于 0,那么 w 就会向更大的方向更新。迭代直到收敛

网络原理总结
  1. 我们不会详细地讨论可以如何使用反向传播和梯度下降等算法训练参数。训练过程中的计算机会尝试一点点增大或减小每个参数,看其能如何减少相比于训练数据集的误差,以望能找到最优的权重、偏置参数组合
Sequential构建简单单层神经网络模型
  1. Sequential模型是层的线性堆栈。我们可以Sequential通过将层实例列表传递给构造函数来创建模型

  2. 代码

    from keras.models import Sequential
    from keras.layers import Dense, Activation
    model = Sequential([
    Dense(32, input_shape=(784,)),
    ])
    #同样可以用add方法来添加模型
    model = Sequential()
    model.add(Dense(32, input_dim=784))

案例:DNN进行分类

数据集介绍
  1. 对鸢尾花进行分类:概览
  2. 本文档中的示例程序构建并测试了一个模型,此模型根据鸢尾花的花萼和花瓣大小将其分为三种不同的品种
  3. 从左到右:山鸢尾(提供者:Radomil,依据 CC BY-SA 3.0 使用)、变色鸢尾(提供者:Dlanglois,依据 CC BY-SA 3.0 使用)和维吉尼亚鸢尾(提供者:Frank Mayfield,依据 CC BY-SA 2.0 使用)
  4. 数据集
    1. 鸢尾花数据集包含四个特征和一个目标值。这四个特征确定了单株鸢尾花的下列植物学特征
      1. 花萼长度
      2. 花萼宽度
      3. 花瓣长度
      4. 花瓣宽度
    2. 该标签确定了鸢尾花品种,品种必须是下列任意一种
      1. 山鸢尾 (0)
      2. 变色鸢尾 (1)
      3. 维吉尼亚鸢尾 (2)
构建模型
  1. 该程序会训练一个具有以下拓扑结构的深度神经网络分类器模型
    1. 2 个隐藏层。
    2. 每个隐藏层包含 10 个节点
  2. Estimator 是从 tf.estimator.Estimator衍生而来的任何类。要根据预创建的 Estimator 编写 TensorFlow 程序,您必须执行下列任务
    1. 创建一个或多个输入函数
    2. 定义模型的特征列
    3. 实例化 Estimator,指定特征列和各种超参数
    4. 在 Estimator 对象上调用一个或多个方法,传递适当的输入函数作为数据的来源
数据获取与输入函数
  1. 在iris_data文件中通过

    # 获取数据
    def load_data(y_name='Species'):
    """获取训练测试数据"""
    train_path, test_path = maybe_download()
    train = pd.read_csv(train_path, names=CSV_COLUMN_NAMES, header=0)
    train_x, train_y = train, train.pop(y_name)
    test = pd.read_csv(test_path, names=CSV_COLUMN_NAMES, header=0)
    test_x, test_y = test, test.pop(y_name)
    return (train_x, train_y), (test_x, test_y)
    (train_x, train_y), (test_x, test_y) = iris_data.load_data()
  2. 输入函数是返回 tf.data.Dataset对象的函数,此对象会输出下列含有两个元素的元组

    1. features:Python 字典,其中

      1. 每个键都是特征的名称
      2. 每个值都是包含此特征所有值的数组
    2. label - 包含每个样本的标签值的数组

    3. 代码

      def input_evaluation_set():
        features = {'SepalLength': np.array([6.4, 5.0]),
      'SepalWidth': np.array([2.8, 2.3]),
      'PetalLength': np.array([5.6, 3.3]),
      'PetalWidth': np.array([2.2, 1.0])}
      labels = np.array([2, 1])
      return features, labels
    4. 输入函数可以以您需要的任何方式生成 features 字典和 label 列表。不过,我们建议使用 TensorFlow 的 Dataset API,它可以解析各种数据。概括来讲,Dataset API 包含下列类

      1. Dataset - 包含创建和转换数据集的方法的基类。您还可以通过该类从内存中的数据或 Python 生成器初始化数据集
      2. TextLineDataset - 从文本文件中读取行
      3. TFRecordDataset - 从 TFRecord 文件中读取记录
      4. FixedLengthRecordDataset - 从二进制文件中读取具有固定大小的记录
      5. Iterator - 提供一次访问一个数据集元素的方法
    5. 代码

      def train_input_fn(features, labels, batch_size):
        """
      """
      dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels))
      dataset = dataset.shuffle(1000).repeat().batch(batch_size)
      return dataset
      def eval_input_fn(features, labels, batch_size):
      """
      """
      features = dict(features)
      if labels is None:
      inputs = features
      else:
      inputs = (features, labels)
      dataset = tf.data.Dataset.from_tensor_slices(inputs)
      dataset = dataset.batch(batch_size)
      return dataset
      dataset.make_one_shot_iterator().get_next()
特征处理tf.feature_colum
  1. 特征处理tf.feature_column

    1. Estimator 的 feature_columns 参数来指定模型的输入。特征列在输入数据(由input_fn返回)与模型之间架起了桥梁。要创建特征列,请调用 tf.feature_column 模块的函数。本文档介绍了该模块中的 9 个函数。如下图所示,除了 bucketized_column 外的函数要么返回一个 Categorical Column 对象,要么返回一个 Dense Column 对象

    2. 要创建特征列,请调用 tf.feature_column模块的函数。本文档介绍了该模块中的 9 个函数。如下图所示,除了 bucketized_column 外的函数要么返回一个 Categorical Column 对象,要么返回一个 Dense Column 对象

    3. Numeric column(数值列)

      #Iris 分类器对所有输入特徵调用 tf.feature_column.numeric_column 函数:SepalLength、SepalWidth、PetalLength、PetalWidth
      #tf.feature_column 有许多可选参数。如果不指定可选参数,将默认指定该特征列的数值类型为 tf.float32
      numeric_feature_column = tf.feature_column.numeric_column(key="SepalLength")
    4. Bucketized column(分桶列)

      #通常,我们不直接将一个数值直接传给模型,而是根据数值范围将其值分为不同的 categories。上述功能可以通过 tf.feature_column.bucketized_column 实现。以表示房屋建造年份的原始数据为例。我们并非以标量数值列表示年份,而是将年份分成下列四个分桶
      # 首先,将原始输入转换为一个numeric column
      numeric_feature_column = tf.feature_column.numeric_column("Year")
      # 然后,按照边界[1960,1980,2000]将numeric column进行bucket
      bucketized_feature_column = tf.feature_column.bucketized_column(
      source_column = numeric_feature_column,
      boundaries = [1960, 1980, 2000])
    5. Categorical identity column(类别标识列)

      #输入的列数据就是为固定的离散值,假设您想要表示整数范围 [0, 4)。在这种情况下,分类标识映射如下所示
      identity_feature_column = tf.feature_column.categorical_column_with_identity(
      key='my_feature_b',
      num_buckets=4) # Values [0, 4)
    6. Categorical vocabulary column(类别词汇表)

      #我们不能直接向模型中输入字符串。我们必须首先将字符串映射为数值或类别值。Categorical vocabulary column 可以将字符串表示为one_hot格式的向量
      vocabulary_feature_column =
      tf.feature_column.categorical_column_with_vocabulary_list(
      key=feature_name_from_input_fn,
      vocabulary_list=["kitchenware", "electronics", "sports"])
    7. Hashed Column(哈希列)

      #处理的示例都包含很少的类别。但当类别的数量特别大时,我们不可能为每个词汇或整数设置单独的类别,因为这将会消耗非常大的内存。对于此类情况,我们可以反问自己:“我愿意为我的输入设置多少类别?
      hashed_feature_column =
      tf.feature_column.categorical_column_with_hash_bucket(
      key = "some_feature",
      hash_bucket_size = 100) # The number of categories
    8. Crossed column(组合列)

实例化 Estimator
  1. 鸢尾花分类本身问题不复杂,一般算法也能够解决。这里我么你选用DNN做测试tf.estimator.DNNClassifier 我们将如下所示地实例化此 Estimator

  2. 我们已经有一个 Estimator 对象,现在可以调用方法来执行下列操作

    1. 训练模型
    2. 评估经过训练的模型
    3. 使用经过训练的模型进行预测
  3. 训练模型

    #通过调用 Estimator 的 train 方法训练模型,如下所示
    # Train the Model.
    classifier.train(
    input_fn=lambda:iris_data.train_input_fn(train_x, train_y, args.batch_size),
    steps=args.train_steps)
    #我们将 input_fn 调用封装在 lambda 中以获取参数,同时提供一个不采用任何参数的输入函数,正如 Estimator 预计的那样。steps 参数告知方法在训练多步后停止训练
  4. 评估经过训练的模型

    #模型已经过训练,现在我们可以获取一些关于其效果的统计信息。以下代码块会评估经过训练的模型对测试数据进行预测的准确率
    # Evaluate the model.
    eval_result = classifier.evaluate(
    input_fn=lambda:iris_data.eval_input_fn(test_x, test_y, args.batch_size))
    print('\nTest set accuracy: {accuracy:0.3f}\n'.format(**eval_result))
    #与我们对 train 方法的调用不同,我们没有传递 steps 参数来进行评估。我们的 eval_input_fn 只生成一个周期的数据
    #运行此代码会生成以下输出(或类似输出)
    #Test set accuracy: 0.967
posted on 2021-04-12 21:00  Darren_la  阅读(642)  评论(0)    收藏  举报