TensorFlow 深度学习第二版:6~10(3)

简介: TensorFlow 深度学习第二版:6~10(3)

TensorFlow 深度学习第二版:6~10(2)https://developer.aliyun.com/article/1426802

八、TFLearn

TFLearn 是一个库,它使用漂亮且熟悉的 scikit-learn API 包装了许多新的 TensorFlow API。

TensorFlow 是关于构建和执行图的全部内容。这是一个非常强大的概念,但从一开始就很麻烦。

在 TFLearn 的引擎盖下,我们只使用了三个部分:

  • 层:一组高级 TensorFlow 函数,允许我们轻松构建复杂的图,从完全连接的层,卷积和批量规范到损失和优化。
  • graph_actions:一组工具,用于对 TensorFlow 图进行训练,评估和运行推理。
  • 估计器:将所有内容打包成一个遵循 scikit-learn 接口的类,并提供了一种轻松构建和训练自定义 TensorFlow 模型的方法。

安装

要安装 TFLearn, 最简单的方法是运行以下命令:

pip install git+https://github.com/tflearn/tflearn.git

对于最新的稳定版本,请使用以下命令:

pip install tflearn

否则,您也可以通过运行以下命令(从源文件夹)从源安装它:

python setup.py install

泰坦尼克号生存预测器

在本教程中,我们将学习使用 TFLearn 和 TensorFlow,使用他们的个人信息(如性别和年龄)模拟泰坦尼克号乘客的生存机会。为了解决这个经典的 ML 任务,我们将构建一个 DNN 分类器。

我们来看看数据集(TFLearn 将自动为您下载)。

对于每位乘客,提供以下信息:

survived       Survived (0 = No; 1 = Yes)
pclass            Passenger Class (1 = st; 2 = nd; 3 = rd)
name             Name
sex                  Sex
age                 Age
sibsp              Number of Siblings/Spouses Aboard
parch             Number of Parents/Children Aboard
ticket             Ticket Number
fare               Passenger Fare

以下是数据集中的一些示例:

sibsp parch ticket fare
1 1 Aubart, Mme. Leontine Pauline female
0 2 Bowenur, Mr. Solomon male
1 3 Baclini, Miss. Marie Catherine female
0 3 Youseff, Mr. Gerious male

我们的任务有两个类:没有幸存(class = 0)和幸存(class = 1)。乘客数据有 8 个特征。泰坦尼克号数据集存储在 CSV 文件中,因此我们可以使用TFLearn load_csv()函数将文件中的数据加载到 Python 列表中。我们指定target_column参数以指示我们的标签(幸存与否)位于第一列(ID:0)。这些函数将返回一个元组:(数据,标签)。

让我们从导入 NumPy 和 TFLearn 库开始:

import numpy as np
import tflearn as tfl

下载泰坦尼克号数据集:

from tflearn.datasets import titanic
titanic.download_dataset('titanic_dataset.csv')

加载 CSV 文件,并指出第一列代表labels

from tflearn.data_utils import load_csv
data, labels = load_csv('titanic_dataset.csv', target_column=0,
                        categorical_labels=True, n_classes=2)

在准备好在我们的 DNN 分类器中使用之前,数据需要一些预处理。我们必须删除无法帮助我们进行分析的列字段。我们丢弃名称和票据字段,因为我们估计乘客的姓名和票证与他们的幸存机会无关:

def preprocess(data, columns_to_ignore):

预处理阶段从降序 ID 和删除列开始:

for id in sorted(columns_to_ignore, reverse=True):
        [r.pop(id) for r in data]
    for i in range(len(data)):

性别场转换为浮动(待操纵):

data[i][1] = 1\. if data[i][1] == 'female' else 0.
    return np.array(data, dtype=np.float32)

如前所述,分析将忽略名称和故障单字段:

to_ignore=[1, 6]

然后我们调用preprocess程序:

data = preprocess(data, to_ignore)

接下来,我们指定输入数据的形状。输入样本总共有6特征,我们将分批量样本以节省内存,因此我们的数据输入形状为[None, 6]None参数表示未知维度,因此我们可以更改批量中处理的样本总数:

net = tfl.input_data(shape=[None, 6])

最后,我们用这个简单的语句序列构建了一个 3 层神经网络:

net = tfl.fully_connected(net, 32)
net = tfl.fully_connected(net, 32)
net = tfl.fully_connected(net, 2, activation='softmax')
net = tfl.regression(net)

TFLearn 提供了一个模型包装器DNN,它自动执行神经网络分类器任务:

model = tfl.DNN(net)

我们将为批量大小为1610周期运行它:

model.fit(data, labels, n_epoch=10, batch_size=16, show_metric=True)

当我们运行模型时,我们应该得到以下输出:

Training samples: 1309
Validation samples: 0
--
Training Step: 82  | total loss: 0.64003
| Adam | epoch: 001 | loss: 0.64003 - acc: 0.6620 -- iter: 1309/1309
--
Training Step: 164  | total loss: 0.61915
| Adam | epoch: 002 | loss: 0.61915 - acc: 0.6614 -- iter: 1309/1309
--
Training Step: 246  | total loss: 0.56067
| Adam | epoch: 003 | loss: 0.56067 - acc: 0.7171 -- iter: 1309/1309
--
Training Step: 328  | total loss: 0.51807
| Adam | epoch: 004 | loss: 0.51807 - acc: 0.7799 -- iter: 1309/1309
--
Training Step: 410  | total loss: 0.47475
| Adam | epoch: 005 | loss: 0.47475 - acc: 0.7962 -- iter: 1309/1309
--
Training Step: 574  | total loss: 0.48988
| Adam | epoch: 007 | loss: 0.48988 - acc: 0.7891 -- iter: 1309/1309
--
Training Step: 656  | total loss: 0.55073
| Adam | epoch: 008 | loss: 0.55073 - acc: 0.7427 -- iter: 1309/1309
--
Training Step: 738  | total loss: 0.50242
| Adam | epoch: 009 | loss: 0.50242 - acc: 0.7854 -- iter: 1309/1309
--
Training Step: 820  | total loss: 0.41557
| Adam | epoch: 010 | loss: 0.41557 - acc: 0.8110 -- iter: 1309/1309
--

模型准确率约为 81%,这意味着它可以预测 81% 乘客的正确结果(即乘客是否幸存)。

PrettyTensor

PrettyTensor 允许开发人员包装 TensorFlow 操作,以快速链接任意数量的层来定义神经网络。即将推出的是 PrettyTensor 功能的简单示例:我们将一个标准的 TensorFlow 对象包装成一个与库兼容的对象;然后我们通过三个完全连接的层提供它,我们最终输出 softmax 分布:

pretty = tf.placeholder([None, 784], tf.float32)
softmax = (prettytensor.wrap(examples)
 .fully_connected(256, tf.nn.relu)
 .fully_connected(128, tf.sigmoid)
 .fully_connected(64, tf.tanh)
 .softmax(10))

PrettyTensor 安装非常简单。您只需使用pip安装程序:

sudo pip install prettytensor

链接层

PrettyTensor 具有三种操作模式,共享链式方法的能力。

正常模式

在正常模式下,每调用一次,就会创建一个新的 PrettyTensor。这样可以轻松链接,您仍然可以多次使用任何特定对象。这样可以轻松分支网络。

顺序模式

在顺序模式下, 内部变量 - 头部 - 跟踪最近的输出张量,从而允许将调用链分解为多个语句。

这是一个简单的例子:

seq = pretty_tensor.wrap(input_data).sequential()
seq.flatten()
seq.fully_connected(200, activation_fn=tf.nn.relu)
seq.fully_connected(10, activation_fn=None)
result = seq.softmax(labels, name=softmax_name))

分支和连接

可以使用一流branchjoin方法构建复杂网络:

  • branch创建一个单独的 PrettyTensor 对象,该对象在调用时指向当前头部,这允许用户定义一个单独的塔,该塔以回归目标结束,以输出结束或重新连接网络。重新连接允许用户定义复合层,如初始。
  • join用于连接多个输入或重新连接复合层。

数字分类器

在这个例子中,我们将定义和训练一个两层模型和一个 LeNet 5 风格的卷积模型:

import tensorflow as tf
import prettytensor as pt
from prettytensor.tutorial import data_utils
tf.app.flags.DEFINE_string('save_path',\
                           None, \
                           'Where to save the model checkpoints.')
FLAGS = tf.app.flags.FLAGS
BATCH_SIZE = 50
EPOCH_SIZE = 60000
TEST_SIZE = 10000

由于我们将数据作为 NumPy 数组提供,因此我们需要在图中创建占位符。这些然后必须使用进料dict语句馈送:

image_placeholder = tf.placeholder\
                    (tf.float32, [BATCH_SIZE, 28, 28, 1])
labels_placeholder = tf.placeholder\
                     (tf.float32, [BATCH_SIZE, 10])

接下来,我们创建multilayer_fully_connected函数。前两层是完全连接的(100神经元),最后一层是softmax结果层。如您所见,链接层是一个非常简单的操作:

def multilayer_fully_connected(images, labels):
  images = pt.wrap(images)
  with pt.defaults_scope\
          (activation_fn=tf.nn.relu,l2loss=0.00001):
    return (images.flatten().\
            fully_connected(100).\
            fully_connected(100).\
            softmax_classifier(10, labels))

现在我们将构建一个多层卷积网络:该架构类似于 LeNet5。请更改此设置,以便您可以尝试其他架构:

def lenet5(images, labels):
  images = pt.wrap(images)
  with pt.defaults_scope\
            (activation_fn=tf.nn.relu, l2loss=0.00001):
    return (images.conv2d(5, 20).\
            max_pool(2, 2).\
            conv2d(5, 50).\
            max_pool(2, 2).\
            flatten().\
            fully_connected(500).\
            softmax_classifier(10, labels))

根据所选模型,我们可能有一个 2 层分类器(multilayer_fully_connected)或卷积分类器(lenet5):

def make_choice():
    var = int(input('(1) = multy layer model   (2) = LeNet5 '))
    print(var)
    if var == 1:
        result = multilayer_fully_connected\
                 (image_placeholder,labels_placeholder)
        run_model(result)
    elif var == 2:
        result = lenet5\
                 (image_placeholder,labels_placeholder)
        run_model(result) 
    else:
        print ('incorrect input value')

最后,我们将为所选模型定义accuracy

def run_model(result):
    accuracy = result.softmax.evaluate_classifier\
                   (labels_placeholder,phase=pt.Phase.test)

接下来,我们构建训练和测试集:

train_images, train_labels = data_utils.mnist(training=True)
  test_images, test_labels = data_utils.mnist(training=False)

我们将使用梯度下降优化程序并将其应用于图。pt.apply_optimizer函数增加了正则化损失并设置了一个步进计数器:

optimizer = tf.train.GradientDescentOptimizer(0.01)
  train_op = pt.apply_optimizer\
                   (optimizer,losses=[result.loss])

我们可以在正在运行的会话中设置save_path,以便每隔一段时间自动保存进度。否则,模型将在会话结束时丢失:

runner = pt.train.Runner(save_path=FLAGS.save_path)
with tf.Session():
    for epoch in range(0,10)

随机展示训练数据:

train_images, train_labels = \
                      data_utils.permute_data\
                      ((train_images, train_labels))
        runner.train_model(train_op,result.\
                           loss,EPOCH_SIZE,\
                           feed_vars=(image_placeholder,\
                                      labels_placeholder),\
                           feed_data=pt.train.\
                           feed_numpy(BATCH_SIZE,\
                                      train_images,\
                                      train_labels),\
                           print_every=100)
        classification_accuracy = runner.evaluate_model\
                                  (accuracy,\
                                   TEST_SIZE,\
                                   feed_vars=(image_placeholder,\
                                              labels_placeholder),\
                                   feed_data=pt.train.\
                                   feed_numpy(BATCH_SIZE,\
                                              test_images,\
                                              test_labels))      
    print("epoch" , epoch + 1)
    print("accuracy", classification_accuracy )
if __name__ == '__main__':
    make_choice()

运行示例,我们必须选择要训练的模型:

(1) = multylayer model   (2) = LeNet5

通过选择multylayer model,我们应该具有 95.5% 的准确率:

Extracting /tmp/data\train-images-idx3-ubyte.gz
Extracting /tmp/data\train-labels-idx1-ubyte.gz
Extracting /tmp/data\t10k-images-idx3-ubyte.gz
Extracting /tmp/data\t10k-labels-idx1-ubyte.gz
epoch 1
accuracy [0.8969]
epoch 2
accuracy [0.914]
epoch 3
accuracy [0.9188]
epoch 4
accuracy [0.9306]
epoch 5
accuracy [0.9353]
epoch 6
accuracy [0.9384]
epoch 7
accuracy [0.9445]
epoch 8
accuracy [0.9472]
epoch 9
accuracy [0.9531]
epoch 10
accuracy [0.9552]

而对于 Lenet5,我们应该具有 98.8% 的准确率:

Extracting /tmp/data\train-images-idx3-ubyte.gz
Extracting /tmp/data\train-labels-idx1-ubyte.gz
Extracting /tmp/data\t10k-images-idx3-ubyte.gz
Extracting /tmp/data\t10k-labels-idx1-ubyte.gz
epoch 1
accuracy [0.9686]
epoch 2
accuracy [0.9755]
epoch 3
accuracy [0.983]
epoch 4
accuracy [0.9841]
epoch 5
accuracy [0.9844]
epoch 6
accuracy [0.9863]
epoch 7
accuracy [0.9862]
epoch 8
accuracy [0.9877]
epoch 9
accuracy [0.9855]
epoch 10
accuracy [0.9886]

Keras

Keras 是一个用 Python 编写的开源神经网络库。它专注于最小化,模块化和可扩展性,旨在实现 DNN 的快速实验。

该库的主要作者和维护者是名为 FrançoisChollet 的 Google 工程师,该库是项目 ONEIROS(开放式神经电子智能机器人操作系统)研究工作的一部分。

Keras 是按照以下设计原则开发的:

  • 模块化:模型被理解为独立,完全可配置的模块序列或图,可以通过尽可能少的限制插入到一起。神经层,成本函数,优化器,初始化方案和激活函数都是独立的模块,可以组合起来创建新模型。
  • 极简主义:每个模块必须简短(几行代码)并且简单。在肮脏的读取之上,源代码应该是透明的。
  • 可扩展性:新模块易于添加(如新类和函数),现有模块提供了基于新模块的示例。能够轻松创建新模块可以实现完全表现力,使 Keras 适合高级研究。

Keras 既可以作为 TensorFlow API 在嵌入式版本中使用,也可以作为库使用:

  • tf.keras来自此链接
  • Keras v2.1.4(更新和安装指南请参见此链接
    在以下部分中,我们将了解如何使用第一个和第二个实现。

Keras 编程模型

Keras 的核心数据结构是一个模型,它是一种组织层的方法。有两种类型的模型:

  • 顺序:这只是用于实现简单模型的线性层叠
  • 函数式 API:用于更复杂的架构,例如具有多个输出和有向无环图的模型

顺序模型

在本节中,我们将快速通过向您展示代码来解释顺序模型的工作原理。让我们首先使用 TensorFlow API 导入和构建 Keras Sequential模型:

import tensorflow as tf
from tensorflow.python.keras.models import Sequential
model = Sequential()

一旦我们定义了模型,我们就可以添加一个或多个层。堆叠操作由add()语句提供:

from keras.layers import Dense, Activation

例如,让我们添加第一个完全连接的神经网络层和激活函数:

model.add(Dense(output_dim=64, input_dim=100))
model.add(Activation("relu"))

然后我们添加第二个softmax层:

model.add(Dense(output_dim=10))
model.add(Activation("softmax"))

如果模型看起来很好,我们必须compile()模型,指定损失函数和要使用的优化器:

model.compile(loss='categorical_crossentropy',\
              optimizer='sgd',\
              metrics=['accuracy'])

我们现在可以配置我们的优化器。 Keras 尝试使编程变得相当简单,允许用户在需要时完全控制。

编译完成后,模型必须符合以下数据:

model.fit(X_train, Y_train, nb_epoch=5, batch_size=32)

或者,我们可以手动将批次提供给我们的模型:

model.train_on_batch(X_batch, Y_batch)

一旦训练完成,我们就可以使用我们的模型对新数据进行预测:

classes = model.predict_classes(X_test, batch_size=32)
proba = model.predict_proba(X_test, batch_size=32)
电影评论的情感分类

在这个例子中,我们将 Keras 序列模型应用于情感分析问题。情感分析是破译书面或口头文本中包含的观点的行为。这种技术的主要目的是识别词汇表达的情感(或极性),这可能具有中性,正面或负面的含义。我们想要解决的问题是 IMDB 电影评论情感分类问题:每个电影评论是一个可变的单词序列,每个电影评论的情感(正面或负面)必须分类。

问题非常复杂,因为序列的长度可能不同,并且包含大量的输入符号词汇。该解决方案要求模型学习输入序列中符号之间的长期依赖关系。

IMDB 数据集包含 25,000 个极地电影评论(好的或坏的)用于训练,并且相同的数量再次用于测试。这些数据由斯坦福大学的研究人员收集,并用于 2011 年的一篇论文中,其中五五开的数据被用于训练和测试。在本文中,实现了 88.89% 的准确率。

一旦我们定义了问题,我们就可以开发一个顺序 LSTM 模型来对电影评论的情感进行分类。我们可以快速开发用于 IMDB 问题的 LSTM 并获得良好的准确率。让我们首先导入此模型所需的类和函数,并将随机数生成器初始化为常量值,以确保我们可以轻松地重现结果。

在此示例中,我们在 TensorFlow API 中使用嵌入式 Keras:

import numpy
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.datasets import imdb
from tensorflow.python.keras.layers import Dense
from tensorflow.python.keras.layers import LSTM
from tensorflow.python.keras.layers import Embedding
from tensorflow.python.keras.preprocessing import sequence
numpy.random.seed(7)

我们加载 IMDB 数据集。我们将数据集限制为前 5,000 个单词。我们还将数据集分为训练(50%)和测试(50%)集。

Keras 提供对 IMDB 数据集的内置访问。imdb.load_data()函数允许您以准备好在神经网络和 DL 模型中使用的格式加载数据集。单词已被整数替换,这些整数表示数据集中每个单词的有序频率。因此,每个评论中的句子包括一系列整数。

这是代码:

top_words = 5000
(X_train, y_train), (X_test, y_test) = \
                          imdb.load_data(num_words=top_words)

接下来,我们需要截断并填充输入序列,以便它们具有相同的建模长度。该模型将学习不携带信息的零值,因此序列在内容方面的长度不同,但是向量需要在 Keras 中计算相同的长度。每个评论中的序列长度各不相同,因此我们将每个评论限制为500单词,截断长评论并用零值填充较短评论:

让我们来看看:

max_review_length = 500
X_train = sequence.pad_sequences\
                  (X_train, maxlen=max_review_length)
X_test = sequence.pad_sequences\
                  (X_test, maxlen=max_review_length)

我们现在可以定义,编译和调整我们的 LSTM 模型。

要解决情感分类问题,我们将使用单词嵌入技术。它包括在连续向量空间中表示单词,该向量空间是语义相似的单词被映射到相邻点的区域。单词嵌入基于分布式假设,该假设指出出现在给定上下文中的单词必须具有相同的语义含义。然后将每个电影评论映射到真实的向量域,其中在意义方面的单词之间的相似性转换为向量空间中的接近度。 Keras 提供了一种通过使用嵌入层将单词的正整数表示转换为单词嵌入的便捷方式。

在这里,我们定义嵌入向量和模型的长度:

embedding_vector_length = 32
model = Sequential()

第一层是嵌入层。它使用 32 个长度向量来表示每个单词:

model.add(Embedding(top_words, \
                    embedding_vector_length,\
                      input_length=max_review_length))

下一层是具有100存储单元的 LSTM 层。最后,因为这是一个分类问题,我们使用具有单个神经元的密集输出层和sigmoid激活函数来预测问题中的类(好的和坏的):

model.add(LSTM(100))
model.add(Dense(1, activation='sigmoid'))

因为它是二元分类问题,我们使用binary_crossentropy作为损失函数,而这里使用的优化器是adam优化算法(我们在之前的 TensorFlow 实现中遇到过它):

model.compile(loss='binary_crossentropy',\
              optimizer='adam',\
                metrics=['accuracy'])
print(model.summary())

我们只适合三个周期,因为模型很快就会适应。批量大小为 64 的评论用于分隔权重更新:

model.fit(X_train, y_train, \
           validation_data=(X_test, y_test),\
              num_epochs=3, \
                batch_size=64)

然后,我们估计模型在看不见的评论中的表现:

scores = model.evaluate(X_test, y_test, verbose=0)
print("Accuracy: %.2f%%" % (scores[1]*100))

运行此示例将生成以下输出:

Epoch 1/3
16750/16750 [==============================] - 107s - loss: 0.5570 - acc: 0.7149
Epoch 2/3
16750/16750 [==============================] - 107s - loss: 0.3530 - acc: 0.8577
Epoch 3/3
16750/16750 [==============================] - 107s - loss: 0.2559 - acc: 0.9019
Accuracy: 86.79%

您可以看到,这个简单的 LSTM 几乎没有调整,可以在 IMDB 问题上获得最接近最先进的结果。重要的是,这是一个模板,您可以使用该模板将 LSTM 网络应用于您自己的序列分类问题。

函数式 API

为了构建复杂的网络,我们将在这里描述的函数式方法非常有用。如第 4 章,卷积神经网络上的 TensorFlow 所示,最流行的神经网络(AlexNET,VGG 等)由一个或多个重复多次的神经迷你网络组成。函数式 API 包括将神经网络视为我们可以多次调用的函数。这种方法在计算上是有利的,因为为了构建神经网络,即使是复杂的神经网络,也只需要几行代码。

在以下示例中,我们使用来自此链接的 Keras v2.1.4 。

让我们看看它是如何工作的。首先,您需要导入Model模块:

from keras.models import Model

首先要做的是指定模型的输入。让我们使用Input()函数声明一个28×28×1的张量:

from keras.layers import Input
digit_input = Input(shape=(28, 28,1))

这是顺序模型和函数式 API 之间的显着差异之一。因此,使用Conv2DMaxPooling2D API,我们构建卷积层:

x = Conv2D(64, (3, 3))(digit_input)
x = Conv2D(64, (3, 3))(x)
x = MaxPooling2D((2, 2))(x)
out = Flatten()(x)

请注意,变量x指定应用层的变量。最后,我们通过指定输入和输出来定义模型:

vision_model = Model(digit_input, out)

当然,我们还需要使用fitcompile方法指定损失,优化器等,就像我们对顺序模型一样。

SqueezeNet

在这个例子中,我们引入了一个名为 SqueezeNet 的小型 CNN 架构,它在 ImageNet 上实现了 AlexNet 级精度,参数减少了 50 倍。这个架构的灵感来自 GoogleNet 的初始模块,发表在论文中:SqueezeNet:AlexNet 级准确率,参数减少 50 倍,模型小于 1MB,可从此链接下载

SqueezeNet 背后的想法是减少使用压缩方案处理的参数数量。此策略使用较少的过滤器减少参数数量。这是通过将挤压层送入它们所称的扩展层来完成的。这两层组成了所谓的 Fire Module,如下图所示:

图 2:SqueezeNet 消防模块

fire_module1×1卷积滤波器组成,然后是 ReLU 操作:

x = Convolution2D(squeeze,(1,1),padding='valid', name='fire2/squeeze1x1')(x)
x = Activation('relu', name='fire2/relu_squeeze1x1')(x)

expand部分有两部分:leftright

left部分使用1×1卷积,称为扩展1×1

left = Conv2D(expand, (1, 1), padding='valid', name=s_id + exp1x1)(x)
left = Activation('relu', name=s_id + relu + exp1x1)(left)

right部分使用3×3卷积,称为expand3x3。这两个部分后面都是 ReLU 层:

right = Conv2D(expand, (3, 3), padding='same', name=s_id + exp3x3)(x)
right = Activation('relu', name=s_id + relu + exp3x3)(right)

消防模块的最终输出是左右连接:

x = concatenate([left, right], axis=channel_axis, name=s_id + 'concat')

然后,重复使用fire_module构建完整的网络,如下所示:

x = Convolution2D(64,(3,3),strides=(2,2), padding='valid',\ 
                                             name='conv1')(img_input)
x = Activation('relu', name='relu_conv1')(x)
x = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), name='pool1')(x)
x = fire_module(x, fire_id=2, squeeze=16, expand=64)
x = fire_module(x, fire_id=3, squeeze=16, expand=64)
x = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), name='pool3')(x)
x = fire_module(x, fire_id=4, squeeze=32, expand=128)
x = fire_module(x, fire_id=5, squeeze=32, expand=128)
x = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), name='pool5')(x)
x = fire_module(x, fire_id=6, squeeze=48, expand=192)
x = fire_module(x, fire_id=7, squeeze=48, expand=192)
x = fire_module(x, fire_id=8, squeeze=64, expand=256)
x = fire_module(x, fire_id=9, squeeze=64, expand=256)
x = Dropout(0.5, name='drop9')(x)
x = Convolution2D(classes, (1, 1), padding='valid', name='conv10')(x)
x = Activation('relu', name='relu_conv10')(x)
x = GlobalAveragePooling2D()(x)
x = Activation('softmax', name='loss')(x)
model = Model(inputs, x, name='squeezenet')

下图显示了 SqueezeNet 架构:

图 3:SqueezeNet 架构

您可以从下面的链接执行 Keras 的 SqueezeNet(在squeezenet.py文件):

然后我们在以下squeeze_test.jpg227×227)图像上测试模型:

图 4:SqueezeNet 测试图像

我们只需使用以下几行代码即可:

import os
import numpy as np
import squeezenet as sq
from keras.applications.imagenet_utils import preprocess_input
from keras.applications.imagenet_utils import preprocess_input, decode_predictions
from keras.preprocessing import image
model = sq.SqueezeNet()
img = image.load_img('squeeze_test.jpg', target_size=(227, 227))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
preds = model.predict(x)
print('Predicted:', decode_predictions(preds))

如您所见,结果非常有趣:

Predicted: [[('n02504013', 'Indian_elephant', 0.64139527), ('n02504458', 'African_elephant', 0.22846894), ('n01871265', 'tusker', 0.12922771), ('n02397096', 'warthog', 0.00037213496), ('n02408429', 'water_buffalo', 0.00032306617)]]

总结

在本章中,我们研究了一些基于 TensorFlow 的 DL 研究和开发库。我们引入了tf.estimator,它是 DL/ML 的简化接口,现在是 TensorFlow 和高级 ML API 的一部分,可以轻松训练,配置和评估各种 ML 模型。我们使用估计器函数为鸢尾花数据集实现分类器。

我们还看了一下 TFLearn 库,它包含了很多 TensorFlow API。在这个例子中,我们使用 TFLearn 来估计泰坦尼克号上乘客的生存机会。为了解决这个问题,我们构建了一个 DNN 分类器。

然后,我们介绍了 PrettyTensor,它允许 TensorFlow 操作被包装以链接任意数量的层。我们以 LeNet 的风格实现了卷积模型,以快速解决手写分类模型。

然后我们快速浏览了 Keras,它设计用于极简主义和模块化,允许用户快速定义 DL 模型。使用 Keras,我们学习了如何为 IMDB 电影评论情感分类问题开发一个简单的单层 LSTM 模型。在最后一个例子中,我们使用 Keras 的函数从预训练的初始模型开始构建 SqueezeNet 神经网络。

下一章将介绍强化学习。我们将探讨强化学习的基本原理和算法。我们还将看到一些使用 TensorFlow 和 OpenAI Gym 框架的示例,这是一个用于开发和比较强化学习算法的强大工具包。

九、协同过滤和电影推荐

在这一部分,我们将看到如何利用协同过滤来开发推荐引擎。然而,在此之前让我们讨论偏好的效用矩阵。

效用矩阵

在基于协同过滤的推荐系统中,存在实体的维度:用户和项目(项目指的是诸如电影,游戏和歌曲的产品)。作为用户,您可能对某些项目有首选项。因此,必须从有关项目,用户或评级的数据中提取这些首选项。该数据通常表示为效用矩阵,例如用户 - 项目对。这种类型的值可以表示关于用户对特定项目的偏好程度的已知信息。

矩阵中的条目可以来自有序集。例如,整数 1-5 可用于表示用户在评价项目时给出的星数。我们已经提到用户可能不会经常评价项目,因此大多数条目都是未知的。因此,将 0 分配给未知项将失败,这也意味着矩阵可能是稀疏的。未知评级意味着我们没有关于用户对项目的偏好的明确信息。

表 1 显示示例效用矩阵。矩阵表示用户以 1-5 分为单位给予电影的评级,其中 5 为最高评级。空白条目表示特定用户未为该特定电影提供任何评级的事实。 HP1,HP2 和 HP3 是 Harry Potter I,II 和 III 的首字母缩略词,TW 代表 Twilight,SW1,SW2 和 SW3 代表星球大战的第 1,2 和 3 集。字母 A,B,C 和 D 代表用户:

表 1:效用矩阵(用户与电影矩阵)

用户电影对有许多空白条目。这意味着用户尚未对这些电影进行评级。在现实生活中,矩阵可能更稀疏,典型的用户评级只是所有可用电影的一小部分。使用此矩阵,目标是预测效用矩阵中的空白。现在,让我们看一个例子。假设我们很想知道用户 A 是否想要 SW2。很难解决这个问题,因为表 1 中的矩阵内没有太多数据可供使用。

因此,在实践中,我们可能会开发一个电影推荐引擎来考虑电影的其他属性,例如制片人,导演,主要演员,甚至是他们名字的相似性。这样,我们可以计算电影 SW1 和 SW2 的相似度。这种相似性会让我们得出结论,因为 A 不喜欢 SW1,所以他们也不太可能喜欢 SW2。

但是,这可能不适用于更大的数据集。因此,有了更多的数据,我们可能会发现,对 SW1 和 SW2 进行评级的人都倾向于给予他们相似的评级。最后,我们可以得出结论,A 也会给 SW2 一个低评级,类似于 A 的 SW1 评级。

在下一节中,我们将看到如何使用协同过滤方法开发电影推荐引擎。我们将看到如何利用这种类型的矩阵。

注意

如何使用代码库:此代码库中有八个 Python 脚本(即使用TensorFlow_09_Codes/CollaborativeFiltering进行深度学习)。首先,执行执行数据集探索性分析的eda.py。然后,调用train.py脚本执行训练。最后,Test.py可用于模型推理和评估。

以下是每个脚本的简要功能:

  • eda.py:这用于 MovieLens1M 数据集的探索性分析。
  • train.py:它执行训练和验证。然后它打印验证误差。最后,它创建了用户项密集表。
  • Test.py:恢复训练中生成的用户与项目表。然后评估所有模型。
  • run.py:用于模型推理并进行预测。
  • kmean.py:它集中了类似的电影。
  • main.py:它计算前 K 个电影,创建用户评级,找到前 K 个相似项目,计算用户相似度,计算项目相关性并计算用户 Pearson 相关性。
  • readers.py:它读取评级和电影数据并执行一些预处理。最后,它为批量训练准备数据集。
  • model.py:它创建模型并计算训练/验证损失。

工作流程可以描述如下:

  1. 首先,我们将使用可用的评级来训练模型。
  2. 然后我们使用训练的模型来预测用户与电影矩阵中的缺失评级。
  3. 然后,利用所有预测的评级,将构建新用户与电影矩阵并以.pkl文件的形式保存。
  4. 然后,我们使用此矩阵来预测特定用户的评级。
  5. 最后,我们将训练 K 均值模型来聚类相关电影。

数据集的描述

在我们开始实现电影 RE 之前,让我们看一下将要使用的数据集。 MovieLens1M 数据集从 MovieLens 网站下载。

我真诚地感谢 F. Maxwell Harper 和 Joseph A. Konstan 使数据集可供使用。数据集发布在 MovieLens 数据集:历史和上下文中。 ACM 交互式智能系统交易(TiiS)5,4,第 19 条(2015 年 12 月),共 19 页。

数据集中有三个文件,它们与电影,评级和用户有关。这些文件包含 1,000,209 个匿名评级,约有 3,900 部电影,由 2000 年加入 MovieLens 的 6,040 名 MovieLens 用户制作。

评级数据

所有评级都包含在ratings.dat文件中,格式如下 - UserID :: MovieID :: Rating :: Timestamp

  • UserID的范围在 1 到 6,040 之间
  • MovieID的范围在 1 到 3,952 之间
  • Rating为五星级
  • Timestamp以秒表示

请注意,每位用户至少评了 20 部电影。

电影数据

电影信息是movies.dat文件中的 ,格式如下 - MovieID :: Title :: Genres

  • 标题与 IMDb 提供的标题相同(发布年份)
  • 流派是分开的,每部电影分为动作,冒险,动画,儿童,喜剧,犯罪,戏剧,战争,纪录片,幻想,电影黑色,恐怖,音乐,神秘,浪漫,科幻菲律宾,惊悚片和西部片

用户数据

用户信息位于users.dat文件中,格式如下:UserID :: Gender :: Age :: Occupation :: Zip-code

所有人口统计信息均由用户自愿提供,不会检查其准确率。此数据集中仅包含已提供某些人口统计信息的用户。男性 M 和女性 F 表示性别。

年龄选自以下范围:

  • 1:18 岁以下
  • 18:18-24
  • 25:25-34
  • 35:35-44
  • 45:45-49
  • 50:50-55
  • 56:56+

职业选自以下选项:

0:其他,或未指定

1:学术/教育者

2:艺术家

3:文员/管理员

4:大学/研究生

5:客户服务

6:医生/保健

7:执行/管理

8:农民

9:主妇

10:K-12 学生

11:律师

12:程序员

13:退休了

14:销售/营销

15:科学家

16:自雇人士

17:技师/工程师

18:匠人/工匠

19:失业

20:作家

对 MovieLens 数据集的探索性分析

在这里,在我们开始开发 RE 之前,我们将看到数据集的探索性描述。我假设读者已经从此链接下载了 MovieLens1m 数据集并将其解压缩到此代码库中的输入目录。现在,为此,在终端上执行$ python3 eda.py命令:

  1. 首先,让我们导入所需的库和包:
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
  1. 现在让我们加载用户,评级和电影数据集并创建一个 pandas DataFrame
ratings_list = [i.strip().split("::") for i in open('Input/ratings.dat', 'r').readlines()]
users_list = [i.strip().split("::") for i in open('Input/users.dat', 'r').readlines()]
movies_list = [i.strip().split("::") for i in open('Input/movies.dat', 'r',encoding='latin-1').readlines()]
ratings_df = pd.DataFrame(ratings_list, columns = ['UserID', 'MovieID', 'Rating', 'Timestamp'], dtype = int)
movies_df = pd.DataFrame(movies_list, columns = ['MovieID', 'Title', 'Genres'])
user_df=pd.DataFrame(users_list, columns=['UserID','Gender','Age','Occupation','ZipCode'])
  1. 接下来的任务是使用内置的to_numeric() pandas 函数将分类列(如MovieIDUserIDAge)转换为数值:
movies_df['MovieID'] = movies_df['MovieID'].apply(pd.to_numeric)
user_df['UserID'] = user_df['UserID'].apply(pd.to_numeric)
user_df['Age'] = user_df['Age'].apply(pd.to_numeric)
  1. 让我们看一下用户表中的一些例子:
print("User table description:")
print(user_df.head())
print(user_df.describe())
>>>
User table description:
UserID Gender  Age      Occupation ZipCode
   1            F         1         10                48067
   2            M        56       16                70072
   3           M         25       15                 55117
   4           M         45       7                  02460
   5           M        25       20                 55455
            UserID          Age
count  6040.000000  6040.000000
mean   3020.500000    30.639238
std    1743.742145    12.895962
min       1.000000     1.000000
25%    1510.750000    25.000000
50%    3020.500000    25.000000
75%    4530.250000    35.000000
max    6040.000000    56.000000
  1. 让我们看一下来自评级数据集的一些信息:
print("Rating table description:")
print(ratings_df.head())
print(ratings_df.describe())
>>>
Rating table description:
UserID  MovieID  Rating  Timestamp
     1     1193              5           978300760
     1      661               3           978302109
     1      914               3           978301968
     1     3408              4           978300275
     1     2355              5           978824291
             UserID       MovieID        Rating     Timestamp
count  1.000209e+06  1.000209e+06  1.000209e+06  1.000209e+06
mean   3.024512e+03  1.865540e+03  3.581564e+00  9.722437e+08
std    1.728413e+03  1.096041e+03  1.117102e+00  1.215256e+07
min    1.000000e+00  1.000000e+00  1.000000e+00  9.567039e+08
25%    1.506000e+03  1.030000e+03  3.000000e+00  9.653026e+08
50%    3.070000e+03  1.835000e+03  4.000000e+00  9.730180e+08
75%    4.476000e+03  2.770000e+03  4.000000e+00  9.752209e+08
max    6.040000e+03  3.952000e+03  5.000000e+00  1.046455e+09
  1. 让我们看看电影数据集中的一些信息:
>>>
print("Movies table description:")
print(movies_df.head())
print(movies_df.describe())
>>>
Movies table description:
   MovieID                Title                                               Genres
0        1             Toy Story (1995)                   Animation|Children's|Comedy
1        2             Jumanji (1995)                      Adventure|Children's|Fantasy
2        3             Grumpier Old Men (1995)                Comedy|Romance
3        4            Waiting to Exhale (1995)                  Comedy|Drama
4        5            Father of the Bride Part II (1995)            Comedy
            MovieID
count  3883.000000
mean   1986.049446
std    1146.778349
min       1.000000
25%     982.500000
50%    2010.000000
75%    2980.500000
max    3952.000000
  1. 现在让我们看看评级最高的五部电影:
print("Top ten most rated movies:")
print(ratings_df['MovieID'].value_counts().head())
>>>
Top 10 most rated movies with title and rating count:
American Beauty (1999)                                                      3428
Star Wars: Episode IV - A New Hope (1977)                      2991
Star Wars: Episode V - The Empire Strikes Back (1980)    2990
Star Wars: Episode VI - Return of the Jedi (1983)              2883
Jurassic Park (1993)                                                             2672
Saving Private Ryan (1998)                                                 2653
Terminator 2: Judgment Day (1991)                                    2649
Matrix, The (1999)                                                               2590
Back to the Future (1985)                                                    2583
Silence of the Lambs, The (1991)                                        2578
  1. 现在,让我们看一下电影评级分布。 为此,让我们使用直方图,该图演示了一个重要的模式,票数呈正态分布:
plt.hist(ratings_df.groupby(['MovieID'])['Rating'].mean().sort_values(axis=0, ascending=False))
plt.title("Movie rating Distribution")
plt.ylabel('Count of movies')
plt.xlabel('Rating');
plt.show()
>>>

  1. 图 3:电影评级分布
  2. 让我们看看评级如何分布在不同年龄段:
user_df.Age.plot.hist()
plt.title("Distribution of users (by ages)")
plt.ylabel('Count of users')
plt.xlabel('Age');
plt.show()
>>>

  1. 图 4:按年龄分布的用户
  2. 现在让我们看看收视率最高的电影,评级至少为 150:
```py
movie_stats = df.groupby('Title').agg({'Rating': [np.size, np.mean]})
print("Highest rated movie with minimum 150 ratings")
print(movie_stats.Rating[movie_stats.Rating['size'] > 150].sort_values(['mean'],ascending=[0]).head())
>>>
Top 5 and a highest rated movie with a minimum of 150 ratings-----------------------------------------------------------
Title                                                               size    mean                                      
Seven Samurai (The Magnificent Seven)    628   4.560510
Shawshank Redemption, The (1994)           2227  4.554558
Godfather, The (1972)                                 2223  4.524966
Close Shave, A (1995)                                 657    4.520548
Usual Suspects, The (1995)                         1783   4.517106
```
  1. 让我们看看在电影评级中的性别偏置,即电影评级如何按评论者的性别进行比较:
```py
>>>
pivoted = df.pivot_table(index=['MovieID', 'Title'], columns=['Gender'], values='Rating', fill_value=0)
print("Gender biasing towards movie rating")
print(pivoted.head())
```
  1. 我们现在可以看看电影收视率的性别偏置及它们之间的差异,即男性和女性对电影的评价方式不同:
```py
pivoted['diff'] = pivoted.M - pivoted.F
print(pivoted.head())
>>>
Gender                                                   F                       M                      diff
MovieID Title                                                           
1  Toy Story (1995)                            4.87817        4.130552                -0.057265
2  Jumanji (1995)                               3.278409      3.175238                -0.103171
3  Grumpier Old Men (1995)             3.073529      2.994152               -0.079377
4  Waiting to Exhale (1995)              2.976471        2.482353              -0.494118
5  Father of the Bride Part II (1995)  3.212963       2.888298               -0.324665
```
  1. 从前面的输出中可以清楚地看出,在大多数情况下,男性的收视率高于女性。现在我们已经看到了有关数据集的一些信息和统计数据,现在是构建我们的 TensorFlow 推荐模型的时候了。

实现电影 RE

在这个例子中,我们将看到如何推荐前 K 部电影(其中 K 是电影数量),预测用户评级并推荐前 K 个类似项目(其中 K 是项目数)。然后我们将看到如何计算用户相似度。

然后我们将使用 Pearson 的相关算法看到项目项相关性和用户 - 用户相关性。最后,我们将看到如何使用 K 均值算法对类似的电影进行聚类。

换句话说,我们将使用协同过滤方法制作电影推荐引擎,并使用 K 均值来聚类类似的电影。

距离计算:还有其他计算距离的方法。例如:

  1. 通过仅考虑最显着的尺寸,可以使用切比雪夫距离来测量距离。
  2. 汉明距离算法可以识别两个字符串之间的差异。
  3. 马哈拉诺比斯距离可用于归一化协方差矩阵。
  4. 曼哈顿距离用于通过仅考虑轴对齐方向来测量距离。
  5. Haversine 距离用于测量球体上两个点之间的大圆距离。

考虑到这些距离测量算法,很明显欧几里德距离算法最适合解决 K 均值算法中距离计算的目的。

总之,以下是用于开发此模型的工作流程:

  1. 首先,使用可用的评级来训练模型。
  2. 使用该训练模型来预测用户与电影矩阵中的缺失评级。
  3. 利用所有预测的评级,用户与电影矩阵成为受训用户与电影矩阵,我们以.pkl文件的形式保存。
  4. 然后,我们使用用户与电影矩阵,或训练用户与电影矩阵的训练参数,进行进一步处理。

在训练模型之前,第一项工作是利用所有可用的数据集来准备训练集。

使用可用的评级训练模型

对于这一部分,请使用train.py脚本,该脚本依赖于其他脚本。我们将看到依赖项:

  1. 首先,让我们导入必要的包和模块:
from collections import deque
from six import next
import readers
import os
import tensorflow as tf
import numpy as np
import model as md
import pandas as pd
import time
import matplotlib.pyplot as plt
  1. 然后我们设置随机种子的复现性:
np.random.seed(12345)
  1. 下一个任务是定义训练参数。让我们定义所需的数据参数,例如评级数据集的位置,批量大小,SVD 的维度,最大周期和检查点目录:
data_file ="Input/ratings.dat"# Input user-movie-rating information file
batch_size = 100 #Batch Size (default: 100)
dims =15 #Dimensions of SVD (default: 15)
max_epochs = 50 # Maximum epoch (default: 25)
checkpoint_dir ="save/" #Checkpoint directory from training run
 val = True #True if Folders with files and False if single file
is_gpu = True # Want to train model with GPU
  1. 我们还需要一些其他参数,例如允许软放置和日志设备放置:
allow_soft_placement = True #Allow device soft device placement
log_device_placement=False #Log placement of ops on devices
  1. 我们不想用旧的元数据或检查点和模型文件污染我们的新训练 ,所以如果有的话,让我们删除它们:
print("Start removing previous Files ...")
if os.path.isfile("model/user_item_table.pkl"):
    os.remove("model/user_item_table.pkl")
if os.path.isfile("model/user_item_table_train.pkl"):
    os.remove("model/user_item_table_train.pkl")
if os.path.isfile("model/item_item_corr.pkl"):
    os.remove("model/item_item_corr.pkl")
if os.path.isfile("model/item_item_corr_train.pkl"):
    os.remove("model/item_item_corr_train.pkl")
if os.path.isfile("model/user_user_corr.pkl"):
    os.remove("model/user_user_corr.pkl")
if os.path.isfile("model/user_user_corr_train.pkl"):
    os.remove("model/user_user_corr_train.pkl")
if os.path.isfile("model/clusters.csv"):
    os.remove("model/clusters.csv")
if os.path.isfile("model/val_error.pkl"):
    os.remove("model/val_error.pkl")
print("Done ...")
>>>
Start removing previous Files...
Done...
  1. 然后让我们定义检查点目录。 TensorFlow 假设此目录已存在,因此我们需要创建它:
checkpoint_prefix = os.path.join(checkpoint_dir, "model")
if not os.path.exists(checkpoint_dir):
    os.makedirs(checkpoint_dir)
  1. 在进入数据之前,让我们设置每批的样本数量,数据的维度以及网络看到所有训练数据的次数 :
batch_size =batch_size
dims =dims
max_epochs =max_epochs
  1. 现在让我们指定用于所有 TensorFlow 计算,CPU 或 GPU 的设备:
if is_gpu:
    place_device = "/gpu:0"
else:
    place_device="/cpu:0"
  1. 现在我们通过get_data()函数读取带有分隔符::的评级文件。示例列包含用户 ID,项 ID,评级和时间戳,例如3 :: 1196 :: 4 :: 978297539。然后,上面的代码执行纯粹基于整数位置的索引,以便按位置进行选择。之后,它将数据分为训练和测试,75% 用于训练,25% 用于测试。最后,它使用索引来分离数据并返回用于训练的数据帧:
def get_data():
    print("Inside get data ...")
    df = readers.read_file(data_file, sep="::")
    rows = len(df)
    df = df.iloc[np.random.permutation(rows)].reset_index(drop=True)
    split_index = int(rows * 0.75)
    df_train = df[0:split_index]
    df_test = df[split_index:].reset_index(drop=True)
    print("Done !!!")
    print(df.shape)
    return df_train, df_test,df['user'].max(),df['item'].max()
  1. 然后,我们在数组中剪切值的限制:给定一个间隔,将间隔外的值剪切到间隔的边缘。例如,如果指定[0,1]间隔,则小于 0 的值变为 0,大于 1 的值变为 1:
```py
def clip(x):
    return np.clip(x, 1.0, 5.0)
```

然后,我们调用read_data()方法从评级文件中读取数据以构建 TensorFlow 模型:

df_train, df_test,u_num,i_num = get_data()
>>>
Inside get data...
Done!!!
  1. 然后,我们定义数据集中评级电影的用户数量,以及数据集中的电影数量:
u_num = 6040 # Number of users in the dataset
i_num = 3952 # Number of movies in the dataset
  1. 现在让我们生成每批样本数量:
samples_per_batch = len(df_train) // batch_size
print("Number of train samples %d, test samples %d, samples per batch %d" % (len(df_train), len(df_test), samples_per_batch))
>>>
Number of train samples 750156, test samples 250053, samples per batch 7501
  1. 现在,使用ShuffleIterator,我们生成随机批次。在训练中,这有助于防止偏差结果以及过拟合:
iter_train = readers.ShuffleIterator([df_train["user"], df_train["item"],df_train["rate"]], batch_size=batch_size)
  1. 有关此类的更多信息,请参阅readers.py脚本。为方便起见,以下是此类的来源:
class ShuffleIterator(object):
    def __init__(self, inputs, batch_size=10):
        self.inputs = inputs
        self.batch_size = batch_size
        self.num_cols = len(self.inputs)
        self.len = len(self.inputs[0])
        self.inputs = np.transpose(np.vstack([np.array(self.inputs[i]) for i in range(self.num_cols)]))
    def __len__(self):
        return self.len
    def __iter__(self):
        return self
   def __next__(self):
        return self.next()
    def next(self):
        ids = np.random.randint(0, self.len, (self.batch_size,))
        out = self.inputs[ids, :]
        return [out[:, i] for i in range(self.num_cols)]
  1. 然后我们依次生成一个周期的批次进行测试(参见train.py):
iter_test = readers.OneEpochIterator([df_test["user"], df_test["item"], df_test["rate"]], batch_size=-1)
  1. 有关此类的更多信息,请参阅readers.py脚本。为了方便,这里是这个类的源码:
class OneEpochIterator(ShuffleIterator):
    def __init__(self, inputs, batch_size=10):
        super(OneEpochIterator, self).__init__(inputs, batch_size=batch_size)
        if batch_size > 0:
            self.idx_group = np.array_split(np.arange(self.len), np.ceil(self.len / batch_size))
        else:
            self.idx_group = [np.arange(self.len)]
        self.group_id = 0
     def next(self):
        if self.group_id >= len(self.idx_group):
            self.group_id = 0
            raise StopIteration
        out = self.inputs[self.idx_group[self.group_id], :]
        self.group_id += 1
        return [out[:, i] for i in range(self.num_cols)]
  1. 现在是创建 TensorFlow 占位符的时间:
user_batch = tf.placeholder(tf.int32, shape=[None], name="id_user")
item_batch = tf.placeholder(tf.int32, shape=[None], name="id_item")
rate_batch = tf.placeholder(tf.float32, shape=[None])
  1. 现在我们的训练集和占位符已准备好容纳训练值的批次,现在该实例化模型了。 为此,我们使用model()方法并使用 l2 正则化来避免过拟合(请参见model.py脚本):
infer, regularizer = md.model(user_batch, item_batch, user_num=u_num, item_num=i_num, dim=dims, device=place_device)
  1. model()方法如下:
def model(user_batch, item_batch, user_num, item_num, dim=5, device="/cpu:0"):
    with tf.device("/cpu:0"):
        # Using a global bias term
        bias_global = tf.get_variable("bias_global", shape=[])
        # User and item bias variables: get_variable: Prefixes the name with the current variable 
        # scope and performs reuse checks.
        w_bias_user = tf.get_variable("embd_bias_user", shape=[user_num])
        w_bias_item = tf.get_variable("embd_bias_item", shape=[item_num])
        # embedding_lookup: Looks up 'ids' in a list of embedding tensors
        # Bias embeddings for user and items, given a batch
        bias_user = tf.nn.embedding_lookup(w_bias_user, user_batch, name="bias_user")
        bias_item = tf.nn.embedding_lookup(w_bias_item, item_batch, name="bias_item")
        # User and item weight variables
        w_user = tf.get_variable("embd_user", shape=[user_num, dim],
                                 initializer=tf.truncated_normal_initializer(stddev=0.02))
        w_item = tf.get_variable("embd_item", shape=[item_num, dim],
                                 initializer=tf.truncated_normal_initializer(stddev=0.02))
        # Weight embeddings for user and items, given a batch
        embd_user = tf.nn.embedding_lookup(w_user, user_batch, name="embedding_user")
        embd_item = tf.nn.embedding_lookup(w_item, item_batch, name="embedding_item")
        # reduce_sum: Computes the sum of elements across dimensions of a tensor
        infer = tf.reduce_sum(tf.multiply(embd_user, embd_item), 1)
        infer = tf.add(infer, bias_global)
        infer = tf.add(infer, bias_user)
        infer = tf.add(infer, bias_item, name="svd_inference")
        # l2_loss: Computes half the L2 norm of a tensor without the sqrt
        regularizer = tf.add(tf.nn.l2_loss(embd_user), tf.nn.l2_loss(embd_item), name="svd_regularizer")
    return infer, regularizer
  1. 现在让我们定义训练操作(参见models.py脚本中的更多内容):
_, train_op = md.loss(infer, regularizer, rate_batch, learning_rate=0.001, reg=0.05, device=place_device)

loss()方法如下:

def loss(infer, regularizer, rate_batch, learning_rate=0.1, reg=0.1, device="/cpu:0"):
    with tf.device(device):
        cost_l2 = tf.nn.l2_loss(tf.subtract(infer, rate_batch))
        penalty = tf.constant(reg, dtype=tf.float32, shape=[], name="l2")
        cost = tf.add(cost_l2, tf.multiply(regularizer, penalty))
        train_op = tf.train.FtrlOptimizer(learning_rate).minimize(cost)
    return cost, train_op
  1. 一旦我们实例化了模型和训练操作,我们就可以保存模型以备将来使用:
saver = tf.train.Saver()
init_op = tf.global_variables_initializer()
session_conf = tf.ConfigProto(
  allow_soft_placement=allow_soft_placement, log_device_placement=log_device_placement)
  1. 现在我们开始训练模型:
with tf.Session(config = session_conf) as sess:
    sess.run(init_op)
    print("%s\t%s\t%s\t%s" % ("Epoch", "Train err", "Validation err", "Elapsed Time"))
    errors = deque(maxlen=samples_per_batch)
    train_error=[]
    val_error=[]
    start = time.time()
    for i in range(max_epochs * samples_per_batch):
        users, items, rates = next(iter_train)
        _, pred_batch = sess.run([train_op, infer], feed_dict={user_batch: users, item_batch: items, rate_batch: rates})
        pred_batch = clip(pred_batch)
        errors.append(np.power(pred_batch - rates, 2))
        if i % samples_per_batch == 0:
            train_err = np.sqrt(np.mean(errors))
            test_err2 = np.array([])
            for users, items, rates in iter_test:
                pred_batch = sess.run(infer, feed_dict={user_batch: users, item_batch: items})
                pred_batch = clip(pred_batch)
                test_err2 = np.append(test_err2, np.power(pred_batch - rates, 2))
            end = time.time()
            print("%02d\t%.3f\t\t%.3f\t\t%.3f secs" % (i // samples_per_batch, train_err, np.sqrt(np.mean(test_err2)), end - start))
            train_error.append(train_err)
            val_error.append(np.sqrt(np.mean(test_err2)))
            start = end
    saver.save(sess, checkpoint_prefix)
    pd.DataFrame({'training error':train_error,'validation error':val_error}).to_pickle("val_error.pkl")
    print("Training Done !!!")
sess.close()
  1. 前面的代码执行训练并将误差保存在 PKL 文件中。最后,它打印了训练和验证误差以及所花费的时间:
>>>
Epoch    Train err    Validation err    Elapsed Time
00          2.816          2.812                0.118 secs
01          2.813          2.812                4.898 secs
…          …               …                     …
48          2.770          2.767                1.618 secs
49          2.765          2.760                1.678 secs

完成训练!!!

结果是删节,只显示了几个步骤。现在让我们以图形方式看到这些误差:

error = pd.read_pickle("val_error.pkl")
error.plot(title="Training vs validation error (per epoch)")
plt.ylabel('Error/loss')
plt.xlabel('Epoch');
plt.show()
>>>

图 5:每个周期的训练与验证误差

该图表明,随着时间的推移,训练和验证误差都会减少,这意味着我们正朝着正确的方向行走。尽管如此,您仍然可以尝试增加步骤,看看这两个值是否可以进一步降低,这意味着更高的准确率。

使用已保存的模型执行推断

以下代码使用保存的模型执行模型推理,并打印整体验证误差:

if val:
    print("Validation ...")
    init_op = tf.global_variables_initializer()
    session_conf = tf.ConfigProto(
      allow_soft_placement=allow_soft_placement,
      log_device_placement=log_device_placement)
    with tf.Session(config = session_conf) as sess:
        new_saver = tf.train.import_meta_graph("{}.meta".format(checkpoint_prefix))
        new_saver.restore(sess, tf.train.latest_checkpoint(checkpoint_dir))
        test_err2 = np.array([])
        for users, items, rates in iter_test:
            pred_batch = sess.run(infer, feed_dict={user_batch: users, item_batch: items})
            pred_batch = clip(pred_batch)
            test_err2 = np.append(test_err2, np.power(pred_batch - rates, 2))
            print("Validation Error: ",np.sqrt(np.mean(test_err2)))
    print("Done !!!")
sess.close()
>>>
Validation Error:  2.14626890224
Done!!!

生成用户项表

以下方法创建用户项数据帧。它用于创建训练有素的DataFrame。使用 SVD 训练模型在此处填写用户项表中的所有缺失值。它采用评级数据帧并存储所有电影的所有用户评级。最后,它会生成一个填充的评级数据帧,其中行是用户,列是项:

def create_df(ratings_df=readers.read_file(data_file, sep="::")):
    if os.path.isfile("model/user_item_table.pkl"):
        df=pd.read_pickle("user_item_table.pkl")
    else:
        df = ratings_df.pivot(index = 'user', columns ='item', values = 'rate').fillna(0)
        df.to_pickle("user_item_table.pkl")
    df=df.T
    users=[]
    items=[]
    start = time.time()
    print("Start creating user-item dense table")
    total_movies=list(ratings_df.item.unique())
    for index in df.columns.tolist():
        #rated_movies=ratings_df[ratings_df['user']==index].drop(['st', 'user'], axis=1)
        rated_movie=[]
        rated_movie=list(ratings_df[ratings_df['user']==index].drop(['st', 'user'], axis=1)['item'].values)
        unseen_movies=[]
        unseen_movies=list(set(total_movies) - set(rated_movie))
        for movie in unseen_movies:
            users.append(index)
            items.append(movie)
    end = time.time()
    print(("Found in %.2f seconds" % (end-start)))
    del df
    rated_list = []
    init_op = tf.global_variables_initializer()
    session_conf = tf.ConfigProto(
      allow_soft_placement=allow_soft_placement,
      log_device_placement=log_device_placement)
    with tf.Session(config = session_conf) as sess:
        #sess.run(init_op)
        print("prediction started ...")
        new_saver = tf.train.import_meta_graph("{}.meta".format(checkpoint_prefix))
        new_saver.restore(sess, tf.train.latest_checkpoint(checkpoint_dir))
        test_err2 = np.array([])
        rated_list = sess.run(infer, feed_dict={user_batch: users, item_batch: items})
        rated_list = clip(rated_list)
        print("Done !!!")
    sess.close()
    df_dict={'user':users,'item':items,'rate':rated_list}
    df = ratings_df.drop(['st'],axis=1).append(pd.DataFrame(df_dict)).pivot(index = 'user', columns ='item', values = 'rate').fillna(0)
    df.to_pickle("user_item_table_train.pkl")
    return df

现在让我们调用前面的方法来生成用户项表作为 pandas 数据帧:

create_df(ratings_df = readers.read_file(data_file, sep="::"))

此行将为训练集创建用户与项目表,并将数据帧保存为指定目录中的user_item_table_train.pkl文件。

聚类类似的电影

对于这一部分,请参阅kmean.py脚本。此脚本将评级数据文件作为输入,并返回电影及其各自的簇。

从技术上讲,本节的目的是找到类似的电影;例如,用户 1 喜欢电影 1,并且因为电影 1 和电影 2 相似,所以用户想要电影 2.让我们开始导入所需的包和模块:

import tensorflow as tf 
import numpy as np
import pandas as pd
import time
import readers
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.decomposition import PCA

现在让我们定义要使用的数据参数:评级数据文件的路径,簇的数量,K 和最大迭代次数。此外,我们还定义了是否要使用经过训练的用户与项目矩阵:

data_file = "Input/ratings.dat" #Data source for the positive data
 K = 5 # Number of clusters
 MAX_ITERS =1000 # Maximum number of iterations
 TRAINED = False # Use TRAINED user vs item matrix

然后定义k_mean_clustering ()方法。它返回电影及其各自的群集。它采用评级数据集ratings_df,这是一个评级数据帧。然后它存储各个电影的所有用户评级,K是簇的数量,MAX_ITERS是推荐的最大数量,TRAINED是一种布尔类型,表示是否使用受过训练的用户与电影表或未经训练的人。

提示

如何找到最佳 K 值

在这里,我们朴素地设定 K 的值。但是,为了微调聚类表现,我们可以使用一种称为 Elbow 方法的启发式方法。我们从K = 2开始,然后,我们通过增加 K 来运行 K 均值算法并使用 WCSS 观察成本函数(CF)的值。在某些时候,CF 会大幅下降。然而,随着 K 值的增加,这种改善变得微不足道。总之,我们可以在 WCSS 的最后一次大跌之后选择 K 作为最佳值。

最后,k_mean_clustering()函数返回一个电影/项目列表和一个簇列表:

def k_mean_clustering(ratings_df,K,MAX_ITERS,TRAINED=False):
    if TRAINED:
        df=pd.read_pickle("user_item_table_train.pkl")
    else:
        df=pd.read_pickle("user_item_table.pkl")
    df = df.T
    start = time.time()
    N=df.shape[0]
    points = tf.Variable(df.as_matrix())
    cluster_assignments = tf.Variable(tf.zeros([N], dtype=tf.int64))
    centroids = tf.Variable(tf.slice(points.initialized_value(), [0,0], [K,df.shape[1]]))
    rep_centroids = tf.reshape(tf.tile(centroids, [N, 1]), [N, K, df.shape[1]])
    rep_points = tf.reshape(tf.tile(points, [1, K]), [N, K, df.shape[1]])
    sum_squares = tf.reduce_sum(tf.square(rep_points - rep_centroids),reduction_indices=2)
    best_centroids = tf.argmin(sum_squares, 1)    did_assignments_change = tf.reduce_any(tf.not_equal(best_centroids, cluster_assignments))
    means = bucket_mean(points, best_centroids, K)
    with tf.control_dependencies([did_assignments_change]):
        do_updates = tf.group(
            centroids.assign(means),
            cluster_assignments.assign(best_centroids))
    init = tf.global_variables_initializer()
    sess = tf.Session()
    sess.run(init)
    changed = True
    iters = 0
    while changed and iters < MAX_ITERS:
        iters += 1
        [changed, _] = sess.run([did_assignments_change, do_updates])
    [centers, assignments] = sess.run([centroids, cluster_assignments])
    end = time.time()
    print (("Found in %.2f seconds" % (end-start)), iters, "iterations")
    cluster_df=pd.DataFrame({'movies':df.index.values,'clusters':assignments})
    cluster_df.to_csv("clusters.csv",index=True)
    return assignments,df.index.values

在前面的代码中,我们有一个愚蠢的初始化,在某种意义上我们使用前 K 个点作为起始质心。在现实世界中,它可以进一步改进。

在前面的代码块中,我们复制每个质心的 N 个副本和每个数据点的 K 个副本。然后我们减去并计算平方距离的总和。然后我们使用argmin选择最低距离点。但是,在计算分配是否已更改之前,我们不会编写已分配的群集变量,因此具有依赖性。

如果仔细查看前面的代码,有一个名为bucket_mean()的函数。它获取数据点,最佳质心和暂定簇的数量 K,并计算在簇计算中使用的平均值:

def bucket_mean(data, bucket_ids, num_buckets):
    total = tf.unsorted_segment_sum(data, bucket_ids, num_buckets)
    count = tf.unsorted_segment_sum(tf.ones_like(data), bucket_ids, num_buckets)
    return total / count

一旦我们训练了我们的 K 均值模型,下一个任务就是可视化代表类似电影的那些簇。为此,我们有一个名为showClusters()的函数,它接受用户项表,CSV 文件(clusters.csv)中写入的聚簇数据,主成分数(默认为 2)和 SVD 求解器(可能的值是随机的和完整的)。

问题是,在 2D 空间中,很难绘制代表电影簇的所有数据点。出于这个原因,我们应用主成分分析(PCA)来降低维数而不会牺牲质量:

user_item=pd.read_pickle(user_item_table)
    cluster=pd.read_csv(clustered_data, index_col=False)
    user_item=user_item.T
    pcs = PCA(number_of_PCA_components, svd_solver) 
    cluster['x']=pcs.fit_transform(user_item)[:,0]
    cluster['y']=pcs.fit_transform(user_item)[:,1]
    fig = plt.figure()
    ax = plt.subplot(111)
    ax.scatter(cluster[cluster['clusters']==0]['x'].values,cluster[cluster['clusters']==0]['y'].values,color="r", label='cluster 0')
    ax.scatter(cluster[cluster['clusters']==1]['x'].values,cluster[cluster['clusters']==1]['y'].values,color="g", label='cluster 1')
    ax.scatter(cluster[cluster['clusters']==2]['x'].values,cluster[cluster['clusters']==2]['y'].values,color="b", label='cluster 2')
    ax.scatter(cluster[cluster['clusters']==3]['x'].values,cluster[cluster['clusters']==3]['y'].values,color="k", label='cluster 3')
    ax.scatter(cluster[cluster['clusters']==4]['x'].values,cluster[cluster['clusters']==4]['y'].values,color="c", label='cluster 4')
    ax.legend()
    plt.title("Clusters of similar movies using K-means")
    plt.ylabel('PC2')
    plt.xlabel('PC1');
    plt.show()

做得好。我们将评估我们的模型并在评估步骤中绘制簇。

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
相关文章
|
11天前
|
机器学习/深度学习 TensorFlow 算法框架/工具
深度学习之格式转换笔记(三):keras(.hdf5)模型转TensorFlow(.pb) 转TensorRT(.uff)格式
将Keras训练好的.hdf5模型转换为TensorFlow的.pb模型,然后再转换为TensorRT支持的.uff格式,并提供了转换代码和测试步骤。
42 3
深度学习之格式转换笔记(三):keras(.hdf5)模型转TensorFlow(.pb) 转TensorRT(.uff)格式
|
1月前
|
机器学习/深度学习 人工智能 算法
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
鸟类识别系统。本系统采用Python作为主要开发语言,通过使用加利福利亚大学开源的200种鸟类图像作为数据集。使用TensorFlow搭建ResNet50卷积神经网络算法模型,然后进行模型的迭代训练,得到一个识别精度较高的模型,然后在保存为本地的H5格式文件。在使用Django开发Web网页端操作界面,实现用户上传一张鸟类图像,识别其名称。
86 12
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
|
8天前
|
机器学习/深度学习 人工智能 算法
【玉米病害识别】Python+卷积神经网络算法+人工智能+深度学习+计算机课设项目+TensorFlow+模型训练
玉米病害识别系统,本系统使用Python作为主要开发语言,通过收集了8种常见的玉米叶部病害图片数据集('矮花叶病', '健康', '灰斑病一般', '灰斑病严重', '锈病一般', '锈病严重', '叶斑病一般', '叶斑病严重'),然后基于TensorFlow搭建卷积神经网络算法模型,通过对数据集进行多轮迭代训练,最后得到一个识别精度较高的模型文件。再使用Django搭建Web网页操作平台,实现用户上传一张玉米病害图片识别其名称。
23 0
【玉米病害识别】Python+卷积神经网络算法+人工智能+深度学习+计算机课设项目+TensorFlow+模型训练
|
1月前
|
机器学习/深度学习 算法 TensorFlow
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
交通标志识别系统。本系统使用Python作为主要编程语言,在交通标志图像识别功能实现中,基于TensorFlow搭建卷积神经网络算法模型,通过对收集到的58种常见的交通标志图像作为数据集,进行迭代训练最后得到一个识别精度较高的模型文件,然后保存为本地的h5格式文件。再使用Django开发Web网页端操作界面,实现用户上传一张交通标志图片,识别其名称。
74 6
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
|
11天前
|
机器学习/深度学习 移动开发 TensorFlow
深度学习之格式转换笔记(四):Keras(.h5)模型转化为TensorFlow(.pb)模型
本文介绍了如何使用Python脚本将Keras模型转换为TensorFlow的.pb格式模型,包括加载模型、重命名输出节点和量化等步骤,以便在TensorFlow中进行部署和推理。
45 0
|
1月前
|
机器学习/深度学习 供应链 TensorFlow
深度学习实战营:TensorFlow+Python,打造你的数据驱动决策引擎
【9月更文挑战第13天】在数据爆炸时代,企业日益依赖精准分析进行决策。深度学习凭借其卓越的特征提取与模式识别能力,成为构建数据驱动决策引擎的关键技术。本项目通过TensorFlow和Python,利用LSTM构建零售业销量预测模型,优化库存管理和营销策略。首先确保安装TensorFlow,然后使用Keras API搭建模型,并通过训练、评估和部署流程,展示深度学习在数据驱动决策中的强大应用潜力,助力企业提升经营效率。
38 3
|
1月前
|
机器学习/深度学习 数据挖掘 TensorFlow
解锁Python数据分析新技能,TensorFlow&PyTorch双引擎驱动深度学习实战盛宴
在数据驱动时代,Python凭借简洁的语法和强大的库支持,成为数据分析与机器学习的首选语言。Pandas和NumPy是Python数据分析的基础,前者提供高效的数据处理工具,后者则支持科学计算。TensorFlow与PyTorch作为深度学习领域的两大框架,助力数据科学家构建复杂神经网络,挖掘数据深层价值。通过Python打下的坚实基础,结合TensorFlow和PyTorch的强大功能,我们能在数据科学领域探索无限可能,解决复杂问题并推动科研进步。
51 0
|
1月前
|
机器学习/深度学习 数据挖掘 TensorFlow
从数据小白到AI专家:Python数据分析与TensorFlow/PyTorch深度学习的蜕变之路
【9月更文挑战第10天】从数据新手成长为AI专家,需先掌握Python基础语法,并学会使用NumPy和Pandas进行数据分析。接着,通过Matplotlib和Seaborn实现数据可视化,最后利用TensorFlow或PyTorch探索深度学习。这一过程涉及从数据清洗、可视化到构建神经网络的多个步骤,每一步都需不断实践与学习。借助Python的强大功能及各类库的支持,你能逐步解锁数据的深层价值。
54 0
|
2月前
|
持续交付 测试技术 jenkins
JSF 邂逅持续集成,紧跟技术热点潮流,开启高效开发之旅,引发开发者强烈情感共鸣
【8月更文挑战第31天】在快速发展的软件开发领域,JavaServer Faces(JSF)这一强大的Java Web应用框架与持续集成(CI)结合,可显著提升开发效率及软件质量。持续集成通过频繁的代码集成及自动化构建测试,实现快速反馈、高质量代码、加强团队协作及简化部署流程。以Jenkins为例,配合Maven或Gradle,可轻松搭建JSF项目的CI环境,通过JUnit和Selenium编写自动化测试,确保每次构建的稳定性和正确性。
53 0
|
2月前
|
测试技术 数据库
探索JSF单元测试秘籍!如何让您的应用更稳固、更高效?揭秘成功背后的测试之道!
【8月更文挑战第31天】在 JavaServer Faces(JSF)应用开发中,确保代码质量和可维护性至关重要。本文详细介绍了如何通过单元测试实现这一目标。首先,阐述了单元测试的重要性及其对应用稳定性的影响;其次,提出了提高 JSF 应用可测试性的设计建议,如避免直接访问外部资源和使用依赖注入;最后,通过一个具体的 `UserBean` 示例,展示了如何利用 JUnit 和 Mockito 框架编写有效的单元测试。通过这些方法,不仅能够确保代码质量,还能提高开发效率和降低维护成本。
47 0

热门文章

最新文章