3、神经网络入门

2021-04-20  本文已影响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 声明:

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 多分类问题

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

以下是一个新闻分类的例子,将新闻划分为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]))
上一篇下一篇

猜你喜欢

热点阅读