前言
在R和Python之间如何进行选择一直是一个热议的话题。机器学习世界也被不同语言偏好所划分。但是随着深度学习的盛行,天平逐渐向Python倾斜,因为截至目前为止Python具有大量R所没有的深度学习的资源库和框架。
但是随着Keras在R中的实现,语言选择的斗争又重新回到舞台中央。Python几乎已经慢慢变成深度学习建模的默认语言,但是随着在R中以TensorFlow(CPU和GPU均兼容)为后端的Keras框架的发行, 即便是在深度学习领域,R与Python抢占舞台的战争也再一次打响。
以下是以R语言为基础,调用Keras包的一个深度学习练习。
电影评论分类:二分类问题
1. 问题描述
二分类问题可能是应用最广泛的机器学习问题,在本例中,我们将根据电影评论的内容文字将其划分为正面或负面。
我们将使用IMDB数据集,它包含来自互联网电影数据库(IMDB) 的50000条严重两级分化的评论。数据被分为用于训练的25000条评论与用于测试的25000条评论,训练集和测试集都包含50%的正面评论和50%的负面评论。
2. 加载Keras,以及一些其他必需的库。
library(keras)
library(dplyr)
library(ggplot2)
library(purrr)
3. 下载IMDB数据集
IMDB数据集与Keras一起打包。它已经被预处理,使得评论(单词序列)已经被转换为整数序列,其中每个整数表示字典中的特定单词。
以下代码将IMDB数据集下载到您的计算机(如果您已经下载了它,则使用缓存副本):
imdb <- dataset_imdb(num_words = 10000)
c(train_data, train_labels) %<-% imdb$train
c(test_data, test_labels) %<-% imdb$test
该参数num_words = 10000保留了训练数据中最常出现的10,000个单词。丢弃罕见的单词以保持数据的大小可管理。
方便地,数据集附带一个索引映射单词到整数,必须单独下载:
word_index <- dataset_imdb_word_index()
我们已经在word_index上面下载了一个列表,其中单词为键,整数为值。如果我们从中创建数据框,我们可以方便地在两个方向上使用它。
word_index_df <- data.frame(
word = names(word_index),
idx = unlist(word_index, use.names = FALSE),
stringsAsFactors = FALSE
)
# The first indices are reserved
word_index_df <- word_index_df %>% mutate(idx = idx + 3)
word_index_df <- word_index_df %>%
add_row(word = "<PAD>", idx = 0)%>%
add_row(word = "<START>", idx = 1)%>%
add_row(word = "<UNK>", idx = 2)%>%
add_row(word = "<UNUSED>", idx = 3)
word_index_df <- word_index_df %>% arrange(idx)
4. 准备数据
train_data <- pad_sequences(
train_data,
value = word_index_df %>% filter(word == "<PAD>") %>% select(idx) %>% pull(),
padding = "post",
maxlen = 256
)
test_data <- pad_sequences(
test_data,
value = word_index_df %>% filter(word == "<PAD>") %>% select(idx) %>% pull(),
padding = "post",
maxlen = 256
)
5. 构建模型
# input shape is the vocabulary count used for the movie reviews (10,000 words)
vocab_size <- 10000
model <- keras_model_sequential()
model %>%
layer_embedding(input_dim = vocab_size, output_dim = 16) %>%
layer_global_average_pooling_1d() %>%
layer_dense(units = 16, activation = "relu") %>%
layer_dense(units = 1, activation = "sigmoid")
model %>% summary()
损失函数和优化器
model %>% compile(
optimizer = 'adam',
loss = 'binary_crossentropy',
metrics = list('accuracy')
)
创建验证集
x_val <- train_data[1:10000, ]
partial_x_train <- train_data[10001:nrow(train_data), ]
y_val <- train_labels[1:10000]
partial_y_train <- train_labels[10001:length(train_labels)]
6. 训练模型
history <- model %>% fit(
partial_x_train,
partial_y_train,
epochs = 40,
batch_size = 512,
validation_data = list(x_val, y_val),
verbose=1
)
7. 评估模型
results <- model %>% evaluate(test_data, test_labels)
results
小结
1)通常需要对原始数据进行大量预处理,以便将其转换为张量输入到神经网络中。单词序列可以编码为二进制向量,但也有其他编码方式。
2)带有relu激活的Dense层堆叠,可以解决很多问题(包括情感分类)。
3)对于二分类问题(两个输出类别),网络的最后一层应该是只有一个单元并使用sigmoid激活的dense层,网络输出应该是0~1范围内的标量,表示概率值。
4)对于二分类问题的sigmoid标量输出,应该使用binary_crossentropy损失函数。
5)无论问题是什么,rmsprop优化器通常都是足够好的选择。
6)随着神经网络在训练数据集上的表现越来越好,模型最终都会过拟合,并在前所未见的数据上得到越来越差的结果。一定要一直监控模型在训练集之外的数据上的性能。
参考:Tutorial: Text Classification
R语言滴水穿石系列文章(一):dplyr-高效的数据变换与整理工具
R语言绘图之ggplot2包