新闻分类--多分类问题
1.加载路透社数据集
from tensorflow.keras.datasets import reuters (train_data,train_lables),(test_data,test_lables) = reuters.load_data(num_words=10000)
首次运行会自动下载数据集
2.准备数据
import numpy as np def vectorize_sequences(sequences,dimension=10000): results = np.zeros((len(sequences),dimension)) for i,sequence in enumerate(sequences): results[i,sequence]=1.0 return results x_train = vectorize_sequences(train_data) #训练数据向量化 x_test = vectorize_sequences(test_data) #测试数据向量化
标签向量化可以采用one-hot编码,标签的 one-hot 编码就是将每个标签表示为全零向量,
只有标签索引对应的元素为 1。其代码实现如下。
import numpy as np def to_one_hot(labels,dimension = 46): results = np.zeros((len(labels),dimension)) for i,label in enumerate(labels): results[i,label] = 1. return results one_hot_train_labels = to_one_hot(train_lables) one_hot_test_labels = to_one_hot(test_lables)
3.构建网络
这个主题分类问题与前面的电影评论分类问题类似,两个例子都是试图对简短的文本片段
进行分类。但这个问题有一个新的约束条件:输出类别的数量从 2 个变为 46 个。输出空间的维
度要大得多。下面将使用维度更大的层,包含 64 个单元。
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')) #对于每个输入的样本,输出一个46维向量,output[i]代表第i个类别的概率。46个概率总和为1
4.编译模型
和之前二分类不同的是损失函数的选择为分类交叉熵
model.compile(optimizer='rmsprop', loss = 'categorical_crossentropy', metrics=['accuracy'] )
5.留出验证集
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:]
6.训练模型
history = model.fit(partial_x_train, partial_y_train, epochs=20, batch_size=512, validation_data=(x_val,y_val)) # validation_data验证集
7.绘制训练损失和验证损失
import matplotlib.pyplot as plt loss = history.history['loss'] val_loss = history.history['val_loss'] epochs = range(1,len(loss)+1) plt.plot(epochs,loss,'bo',label = 'Train 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()
8.绘制训练精度和验证精度
plt.clf() acc = history.history['accuracy'] val_acc = history.history['val_accuracy'] plt.plot(epochs,acc,'bo',label = 'Train acc') plt.plot(epochs,val_acc,'b',label= 'vallidation acc') plt.title("Training and validation acc") plt.xlabel('Epochs') plt.ylabel('Accuracy') plt.legend() plt.show()
可以看到从第9轮开始过拟合,可以从新训练一个模型,训练轮数设置为9
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(result)
小结:
? 1.如果要对 N 个类别的数据点进行分类,网络的最后一层应该是大小为 N 的 Dense 层。
? 2.对于单标签、多分类问题,网络的最后一层应该使用 softmax 激活,这样可以输出在 N
个输出类别上的概率分布。这种问题的损失函数几乎总是应该使用分类交叉熵。它将网络输出的概率分布与目标的
真实分布之间的距离最小化。
? 3.处理多分类问题的标签有两种方法。
? (1)通 过 分 类 编 码( 也 叫 one-hot 编 码 ) 对 标 签 进 行 编 码, 然 后 使 用 categorical_
crossentropy 作为损失函数。
? (2)将标签编码为整数,然后使用 sparse_categorical_crossentropy 损失函数。
? 4.如果你需要将数据划分到许多类别中,应该避免使用太小的中间层,以免在网络中造成
信息瓶颈。