美文网首页
3、神经网络入门

3、神经网络入门

作者: 丁功春 | 来源:发表于2021-04-20 15:29 被阅读0次

    3.1 神经网络剖析

    image.png
    层、输入函数和目标、损失函数、优化器的关系

    神经网络的基本数据结构是层,可以把层看做一个过滤器,输入张量,输出处理后更有价值的张量
    构建深度学习模型就是将相互兼容的多个层拼接在一起
    层兼容性
    举个例子:
    layer = layer.Dense(32,input_shape(784,))  #Dense是处理层与层之间连接的类
    

    这里创建了一个层,接受第一个维度大小为784的2D张量作为输入,输出第一个维度大小为32的张量,那么这个层后面只能连接一个接受第一个维度大小为32的张量作为输入的层。

    3.2 Keras、TensorFlow、Theano和CNTK

    Keras是Google开发的一个模型级(model-level)的库,为开发深度学习模型提供了高层次的构建模块,但它不处理运算,依赖于专门的张量运算库,也就是Keras的后端引擎。
    在Keras v2.3.0及以前,它支持TensorFlow、Theano和CNTK作为后端,但谷歌在 2019 年 6 月发布 TensorFlow 2.0,并在此后宣布 Keras 现在是 TensorFlow 的官方高级 API,随着 Keras 2.3.0 的发布,Francois 声明:

    • 这是 Keras 首个与 tf.keras 同步的版本;
    • 这也是 Keras 支持多个后端(即 Theano,CNTK 等)的最终版本。
    • 最重要的是,所有深度学习从业人员都应将其代码转换成 TensorFlow 2.0 和 tf.keras 软件包。
    • 原始的 keras 软件包仍会接收 bug 并修复,但请向前看,你应该开始使用 tf.keras 了。
      因此我们现在在代码中引入keras的模块应该这么写:
    from tensorflow.keras.datasets import mnist
    

    在CPU上运行时,TensorFlow本身封装了一个低层次的张量运算库,叫Eigen;
    在GPU上运行时,TensorFlow封装了一个高度优化的深度学习运算库,叫做NVIDIA CUDA深度神经网络库(cuDNN)
    强烈建议在NVIDIA CUDA上进行深度学习实验

    下面是一个定义模型的例子

    from keras import models
    from keras import layers
    from keras import optimizers
    model=models.Sequential()  # Sequential类定义模型,仅用于层的线性堆叠
    model.add(layers.Dense(32, activation='relu', input_shape=(784, )))  # 当使用激活层作为第一层时,要指定input_shape
    model.add(layers.Dense(10, activation='softmax'))
    
    # 配置学习过程、编译
    model.compile(optimizer=optimizers.RMSprop(lr=0.001),
                          loss='mse',
                          metrics=['accuracy'])  # 第一个参数指定模型使用的优化器,第二个参数指定损失函数
    
    # 最后,学习过程就是通过fit()方法把输入数据的Numpy数组(和对应的目标数据)传入模型
    model.fit(input_tensor, target_tensor, batch_size=128, epochs=10) # batch_size=128:每个小批量包含128个样本,epochs=10:共迭代十次
    

    3.3 二分类问题(应用最广泛的机器学习问题)

    目标:根据电影评论文字内容将其分为正面或负面
    数据集来自IMDB(互联网电影数据库)的50000条严重两极分化的评论,数据集被分为用于训练的25000条评论与用于测试的25000条评论,它们都包含50%的正面评论和50%的负面评论。
    将训练集和测试集分开的目的:观察模型在新数据上的表现和性能

    3.3.1 加载数据集

    from tensorflow.keras.datasets import imdb
    
    #train_labels是0和1组成的列表,0表示负面,1表示正面
    (train_data, train_labels), (test_data, test_labels) = imdb.load_data(
        num_words=10000)  # num_words=10000表示仅保留训练数据中前10000个最常出现的单词
    print(train_data[0])  # [1, 14, 22, 16, ... 178, 32]  # 数字代表单词在word_index字典里的索引
    
    # 下面是把评论还原,找到索引对应的单词并组成句子
    word_index = imdb.get_word_index()
    print(list(word_index.items())[:50])  # [('fawn', 34701), ('tsukino', 52006), ('nunnery', 52007), ('sonja', 16816)...]
    reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])  # 键值颠倒,将整数作为索引
    print(list(reverse_word_index.items())[:50])  # [(34701, 'fawn'), (52006, 'tsukino'), (52007, 'nunnery'), (16816, 'sonja')...]
    decoded_review = ' '.join([reverse_word_index.get(i - 3, '?') for i in train_data[0]])  # get第二个参数?:如果键不在字典中返回默认值?。  i-3:因为0、1、2是填充
    print(decoded_review)  # ? this film was just brilliant casting location scenery story direction everyone's really suited the part they played and you could ...
    
    

    3.3.2 准备数据

    不能将整数序列直接输入神经网络,需要转化为张量

    def vectorize_sequences(sequences, dimension=10000):
        results = np.zeros((len(sequences), dimension))  # 25000*10000的0矩阵
        for i, sequence in enumerate(sequences):
            results[i, sequence] = 1 # 例如传入train_data,i=0时sequence=[1, 14, 22, 16, ... 178, 32],则如下图所示,索引为1,14,22,16...的元素是1,其它全为0
        return results
    
    
    x_train = vectorize_sequences(train_data)
    x_test = vectorize_sequences(test_data)
    print(x_train[0])  # [ 0.,  1.,  1., ...,  0.,  0.,  0.]
    
    # 标签也要向量化
    y_train=np.asarray(train_labels).astype('float32')
    y_test=np.asarray(test_labels).astype('float32')
    
    image.png

    3.3.3 构建网络

    先了解几个概念:
    激活函数:激活函数对输入信息进行非线性变换。 然后将变换后的输出信息作为输入信息传给下一层神经元。
    relu是一个常用的激活函数,每个带有relu激活的Dense层都做了如下张量运算:
    output=relu(dot(W, input)+b)输入张量与W之间的点积运算,得到的2D张量与向量b之间的加法运算,最后的relu运算,relu(x)是max(x,0)
    为什么要引入激活函数?
    这里举一个雕刻的例子,比如雕刻一个勺子,把每一个步骤比作一个Dense,切割的角度、力度比作dot(W, input)+b)中的参数W(权重)、b(偏移量),如果仅仅使用锯子(线性函数)来切割,我们始终组合不出勺子的凹面,所以引入“圆弧刀”(非线性函数/激活函数)来雕刻,通过这样的多个步骤,不断地调整角度、力度,就能够“组合”出勺子的形状。

    from tensorflow.keras import models
    from tensorflow.keras import layers
    
    model = models.Sequential()
    model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
    model.add(layers.Dense(16, activation='relu'))
    model.add(layers.Dense(1, activation='sigmoid'))
    model.compile(optimizer='rmsprop',
                  loss='binary_crossentropy',
                  metrics=['accuracy'])
    

    3.3.4 训练模型

    # 为了在训练过程中监控模型在前所未见数据上的精度,在训练数据中留出10000个样本作为验证集
    x_val = x_train[:10000]
    partial_x_train = x_train[10000:]
    
    y_val = y_train[:10000]
    partial_y_train = y_train[10000:]
    
    model.compile(optimizer='rmsprop',
                  loss='binary_crossentropy',
                  metrics=['acc'])
    # 使用512个样本组成的小批量,将模型训练20个轮次,同时监控留出10000个样本的损失和精度
    history = model.fit(partial_x_train,
                        partial_y_train,
                        epochs=20,
                        batch_size=512,
                        validation_data=(x_val, y_val))
    
    # model.fit()返回一个history对象,该对象有个history成员,为字典类型,包含训练过程中所有数据
    history_dict = history.history
    for key, value in history_dict.items():
        print(key, "  ", value)
    '''
    训练过程和验证过程的损失和精度
    loss    [0.4944482445716858, 0.2939164936542511, 0.21653617918491364, 0.1675998419523239, 0.1391567885875702, 0.1121390238404274, 0.0940573662519455, 0.07581488788127899, 0.06289112567901611, 0.04842514172196388, 0.03991876542568207, 0.03023112751543522, 0.028684576973319054, 0.02050687000155449, 0.017534885555505753, 0.009153992868959904, 0.012883363291621208, 0.0051835221238434315, 0.007177847903221846, 0.0029263326432555914]
    acc    [0.7936000227928162, 0.9048666954040527, 0.9290000200271606, 0.9461333155632019, 0.9549999833106995, 0.9666666388511658, 0.972000002861023, 0.9786666631698608, 0.9835333228111267, 0.9890000224113464, 0.9904000163078308, 0.9944666624069214, 0.9936000108718872, 0.9965999722480774, 0.9967333078384399, 0.9995333552360535, 0.9972000122070312, 0.9998666644096375, 0.9990000128746033, 0.9998666644096375]
    val_loss    [0.3680858612060547, 0.30189377069473267, 0.2835635840892792, 0.2780053913593292, 0.2871691882610321, 0.29967495799064636, 0.3137110471725464, 0.33734071254730225, 0.3654106557369232, 0.4056454002857208, 0.44047337770462036, 0.46097812056541443, 0.47493788599967957, 0.5053985118865967, 0.5342071652412415, 0.5724620819091797, 0.6008302569389343, 0.6400908827781677, 0.6695500612258911, 0.7380909323692322]
    val_acc    [0.8766000270843506, 0.8876000046730042, 0.8866999745368958, 0.8898000121116638, 0.8873000144958496, 0.8849999904632568, 0.8815000057220459, 0.8817999958992004, 0.879800021648407, 0.8758999705314636, 0.8726999759674072, 0.8673999905586243, 0.8733999729156494, 0.8737000226974487, 0.8711000084877014, 0.8664000034332275, 0.8687000274658203, 0.8676000237464905, 0.8672999739646912, 0.859499990940094]
    '''
    

    观察以上数据,可见训练损失每轮都在降低,精度每轮都在提高,而验证损失和精度却并非如此,似乎在第四轮达到最佳值,这就是过拟合
    为了防止过拟合,我们可以尝试只训练4轮

    model.fit(x_train, y_train, epochs=4, batch_size=512)
    results=model.evaluate(x_test, y_test)  # [0.2929924130630493, 0.88327999999999995]
    

    利用这种简单的方法得到88%的精度,利用更先进的方法可以将精度提高到95%

    3.3.5 开始预测

    通过上述步骤我们训练出了一个简单的网络,现在开始在新数据上生成预测结果

    model.predict(x_test) # 评论为正面的可能性大小
    """
    array([[2.4727285e-03],
           [1.0000000e+00],
           [9.9972254e-01],
           ...,
           [9.5087290e-04],
           [4.7330856e-03],
           [9.2653298e-01]], dtype=float32)
    """
    

    3.4 多分类问题

    对于多分类问题,即类别不止两个,应该怎么处理?
    步骤与二分类类似,需要注意的几个地方:

    • 如果要对N个类别的数据进行分类,网络的最后一层应该是大小为N的Dense层
    • 对于单标签、多分类问题,网络的最后一层应该用softmax激活,这样可以输出在N个类别上的概率分布
    • 处理多分类问题的标签:
      1、通过one-shot编码,使用categorical_crossentropy作为损失函数
      2、将标签编码为整数,使用sparse_categorical_crossentropy损失函数
    • 如果要将数据划分到很多类别中,应避免使用太小的中间层

    以下是一个新闻分类的例子,将新闻划分为46个不同的主题

    from tensorflow.keras.datasets import reuters
    import numpy as np
    (train_data, train_labels), (test_data, test_labels)=reuters.load_data(num_words=10000)
    
    print(len(train_data))
    print(train_labels[:10])
    
    from tensorflow.keras.utils import to_categorical
    
    def vectorize_sequences(sequences, dimension=10000):
        results = np.zeros((len(sequences), dimension))  # 25000*10000的0矩阵
        for i, sequence in enumerate(sequences):
            results[i, sequence] = 1
        return results
    
    x_train = vectorize_sequences(train_data)
    x_test = vectorize_sequences(test_data)
    
    one_hot_train_labels=to_categorical(train_labels)
    one_hot_test_labels=to_categorical(test_labels)
    
    
    from tensorflow.keras import models
    from tensorflow.keras import layers
    
    model=models.Sequential()
    model.add(layers.Dense(64, activation='relu', input_shape=(10000, )))
    model.add(layers.Dense(64, activation='relu'))
    model.add(layers.Dense(46, activation='softmax'))
    
    model.compile(optimizer='rmsprop',
                          loss='categorical_crossentropy',
                          metrics=['accuracy'])
    
    x_val=x_train[:1000]
    partial_x_train=x_train[1000:]
    y_val=one_hot_train_labels[:1000]
    partial_y_train=one_hot_train_labels[1000:]
    
    history=model.fit(partial_x_train,
                        partial_y_train,
                        epochs=20,
                        batch_size=512,
                        validation_data=(x_val, y_val))
    
    # 绘制损失曲线和精度曲线
    import matplotlib.pyplot as plt
    
    loss=history.history['loss']
    val_loss=history.history['val_loss']
    
    # for key in history.history.items():
    #     print(key)
    
    epochs=range(1, len(loss)+1)
    
    plt.figure()
    plt.plot(epochs, loss, 'bo', label='Training loss')
    plt.plot(epochs, val_loss, 'b', label='Validation loss')
    plt.title('Training and validation loss')
    plt.xlabel('Epochs')
    plt.ylabel('Loss')
    plt.legend()
    plt.show()
    
    plt.clf()
    acc = history.history['accuracy']
    val_acc = history.history['val_accuracy']
    plt.plot(epochs,acc,'bo',label='Training acc')
    plt.plot(epochs,val_acc,'b',label='Validation acc')
    plt.title('Training and validation accuracy')
    plt.xlabel('Epochs')
    plt.ylabel('Accuracy')
    plt.legend()
    plt.show()
    
    model=models.Sequential()
    model.add(layers.Dense(64, activation='relu', input_shape=(10000, )))
    model.add(layers.Dense(64, activation='relu'))
    model.add(layers.Dense(46, activation='softmax'))
    
    
    model.compile(optimizer='rmsprop',
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])
    model.fit(partial_x_train,
              partial_y_train,
              epochs=9,
              batch_size=512,
              validation_data=(x_val, y_val))
    results=model.evaluate(x_test, one_hot_test_labels)
    print(results)
    
    predictions=model.predict(x_test)
    print(predictions[0])
    print(np.argmax(predictions[0]))
    

    相关文章

      网友评论

          本文标题:3、神经网络入门

          本文链接:https://www.haomeiwen.com/subject/xsfwlltx.html