Tensorflow2.2.0模型 绘制ROC、PR曲线、保存模型

一、ROC曲线demo

安装好包之后,下面的代码可以一键运行

# 导包
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve, auc

# 数据示例
y_true = [0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 ,0, 0, 1, 0 ,0 ,1, 1]
y_score = [-0.763011 ,-0.202245, 0.118015, -0.907809 ,-0.0111619 ,-0.604873 ,0.0228349 ,-0.610769 ,-0.375728
, -0.470174 ,-0.422242 ,-0.335587 ,-0.227239, -0.0785673 , -0.533834, 0.121637 ,-0.713569, -0.551115
 ,0.379913, -0.111076]

# 计算
fpr, tpr, thread = roc_curve(y_true , y_score)
roc_auc = auc(fpr, tpr)
# 绘图
plt.figure()
lw = 2
plt.plot(fpr, tpr, color='darkorange',
         lw=lw, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
plt.savefig('roc.png',)
plt.show()

运行结果:

 函数的参数解释见:如何使用python绘制ROC曲线?_张小李的风的博客-优快云博客

另一篇UEBA作图的参考:User-and-Entity-Behavior-Analytics-UEBA/7-MLP_Training_and_Metrics.py at master · variationalkk/User-and-Entity-Behavior-Analytics-UEBA · GitHub 

二、如何给下面的代码加ROC曲线绘制 

# 1、导入TensorFlow包
import tensorflow as tf

file_path = 'file:/F:/3_研究生/1_研一下/深度学习推荐系统/SparrowRecSys-python/src/main/resources'
# Training samples path, change to your local path
training_samples_file_path = tf.keras.utils.get_file("trainingSamples.csv",
                                                     file_path+"/webroot/sampledata/trainingSamples.csv")
# Test samples path, change to your local path
test_samples_file_path = tf.keras.utils.get_file("testSamples.csv",
                                                 file_path+"/webroot/sampledata/testSamples.csv")


# load sample as tf dataset
def get_dataset(file_path):
    dataset = tf.data.experimental.make_csv_dataset(
        file_path,
        batch_size=12,
        label_name='label',
        na_value="0",
        num_epochs=1,
        ignore_errors=True)
    return dataset

# 2、载入训练数据
# split as test dataset and training dataset
train_dataset = get_dataset(training_samples_file_path)
test_dataset = get_dataset(test_samples_file_path)
# movieId,userId,rating,timestamp,label,releaseYear,movieGenre1,movieGenre2,movieGenre3,movieRatingCount,movieAvgRating,movieRatingStddev,userRatedMovie1,userRatedMovie2,userRatedMovie3,userRatedMovie4,userRatedMovie5,userRatingCount,userAvgReleaseYear,userReleaseYearStddev,userAvgRating,userRatingStddev,userGenre1,userGenre2,userGenre3,userGenre4,userGenre5

# 3、载入类别型特征
# genre features vocabulary
genre_vocab = ['Film-Noir', 'Action', 'Adventure', 'Horror', 'Romance', 'War', 'Comedy', 'Western', 'Documentary',
               'Sci-Fi', 'Drama', 'Thriller','Crime', 'Fantasy', 'Animation', 'IMAX', 'Mystery', 'Children', 'Musical']
# 用户有5个电影风格特征,电影有3个电影风格特征
GENRE_FEATURES = {
    'userGenre1': genre_vocab,
    'userGenre2': genre_vocab,
    'userGenre3': genre_vocab,
    'userGenre4': genre_vocab,
    'userGenre5': genre_vocab,
    'movieGenre1': genre_vocab,
    'movieGenre2': genre_vocab,
    'movieGenre3': genre_vocab
}

# all categorical features
# 分别是 genre、userId 和 movieId。在载入 genre 类特征时,
# 我们采用了 tf.feature_column.categorical_column_with_vocabulary_list 方法把字符串型的特征转换成了 One-hot 特征。
# 在这个转换过程中我们需要用到一个词表,你可以看到我在开头就定义好了包含所有 genre 类别的词表 genre_vocab。
# 在转换 userId 和 movieId 特征时,我们又使用了 tf.feature_column.categorical_column_with_identity 方法把 ID 转换成 One-hot 特征,这个方法不用词表,它会直接把 ID 值对应的那个维度置为 1。
# 比如,我们输入这个方法的 movieId 是 340,总的 movie 数量是 1001,使用这个方法,就会把这个 1001 维的 One-hot movieId 向量的第 340 维置为 1,剩余的维度都为 0。
# 为了把稀疏的 One-hot 特征转换成稠密的 Embedding 向量,我们还需要在 One-hot 特征外包裹一层 Embedding 层,可以看到 tf.feature_column.embedding_column(movie_col, 10) 方法完成了这样的操作,它在把 movie one-hot 向量映射到了一个 10 维的 Embedding 层上。

#
categorical_columns = []

# 把字符串型特征转换成One-hot特征
for feature, vocab in GENRE_FEATURES.items():
    cat_col = tf.feature_column.categorical_column_with_vocabulary_list(
        key=feature, vocabulary_list=vocab)
    emb_col = tf.feature_column.embedding_column(cat_col, 10)
    categorical_columns.append(emb_col)

# movie id embedding feature
movie_col = tf.feature_column.categorical_column_with_identity(key='movieId', num_buckets=1001)
movie_emb_col = tf.feature_column.embedding_column(movie_col, 10)
categorical_columns.append(movie_emb_col)

# user id embedding feature
user_col = tf.feature_column.categorical_column_with_identity(key='userId', num_buckets=30001)
user_emb_col = tf.feature_column.embedding_column(user_col, 10)
categorical_columns.append(user_emb_col)

# 4、数值型特征的处理
# all numerical features
numerical_columns = [tf.feature_column.numeric_column('releaseYear'),
                     tf.feature_column.numeric_column('movieRatingCount'),
                     tf.feature_column.numeric_column('movieAvgRating'),
                     tf.feature_column.numeric_column('movieRatingStddev'),
                     tf.feature_column.numeric_column('userRatingCount'),
                     tf.feature_column.numeric_column('userAvgRating'),
                     tf.feature_column.numeric_column('userRatingStddev')]

# 5、定义模型结构
# embedding + MLP model architecture
model = tf.keras.Sequential([
    tf.keras.layers.DenseFeatures(numerical_columns + categorical_columns),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(1, activation='sigmoid'),
])

# 6、定义模型训练相关的参数
# compile the model, set loss function, optimizer and evaluation metrics
model.compile(
    loss='binary_crossentropy',
    optimizer='adam',
    metrics=['accuracy', tf.keras.metrics.AUC(curve='ROC'), tf.keras.metrics.AUC(curve='PR')])


# 7、模型的训练
# train the model
model.fit(test_dataset, epochs=1)

# model.save('saved_model/my_model')

# 模型的评估
# evaluate the model
test_loss, test_accuracy, test_roc_auc, test_pr_auc = model.evaluate(test_dataset)
print('\n\nTest Loss {}, Test Accuracy {}, Test ROC AUC {}, Test PR AUC {}'.format(test_loss, test_accuracy,
                                                                                   test_roc_auc, test_pr_auc))


# print some predict results
predictions = model.predict(test_dataset)
for prediction, goodRating in zip(predictions[:12], list(test_dataset)[0][1][:12]):
    print("Predicted good rating: {:.2%}".format(prediction[0]),
          " | Actual rating label: ",
          ("Good Rating" if bool(goodRating) else "Bad Rating"))

本来是可以跑的,但是加了两个包(sklearn.metrics和matplotlib)就报错了,错误的原因是numpy的版本太低/高,猜测是安装这两个包的时候更换了numpy的版本! 

因为我这次下载sklearn.metrics和matplotlib包的时候不是手动用pip或者conda去下的,而是用IDEA快捷键自动帮我下的,,

我想把numpy卸载了重新按,执行了conda uninstall以后

conda uninstall numpy

md,怎么连依赖numpy的包都删了!还删了很多TensorFlow要用的包!

救不了了,把整个环境删了重新按!

# 退出虚拟环境
conda deactivate

# 删除虚拟环境里所有的包
conda remove -n recsys --all

# 删除虚拟环境
conda env remove -n recsys


# 创建新虚拟环境
conda create -n recsys2

# 进入新虚拟环境
conda activate recsys2

# 一定要先在虚拟环境中安装pip,不然执行pip命令的时候用的是全局pip,安装到全局环境中去了!
conda install pip

# 安装tensorflow-gpu==2.2.0
pip install tensorflow-gpu==2.2.0 -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn

# 安装python3.6 (tensorflow 2.2.0自动匹配Python3.6)
conda install python

一键运行,又出现新错误 (第一次训练成功的时候没有这个错误的!但我记得lvning貌似出现了这个错误,可能我第一次跑这个代码安装pip的时候,装了一个小版本的protobuf。反正上面的一系列错误都是版本冲突的原因!)

 

 再运行,成功了!

安装画图用的两个包

pip install -i https://mirrors.aliyun.com/pypi/simple matplotlib
pip install -i https://mirrors.aliyun.com/pypi/simple scikit-learn

pip+阿里云果然好用,我爱阿里云!清华镜像真完蛋

惨痛教训,不要让IDEA帮你安包,一定要自己手动按!

自己按的不冲突了!

绘制ROC曲线,根据上面给出的两个示例,

示例①:

如何使用python绘制ROC曲线?_张小李的风的博客-优快云博客

示例②:User-and-Entity-Behavior-Analytics-UEBA/7-MLP_Training_and_Metrics.py at master · variationalkk/User-and-Entity-Behavior-Analytics-UEBA · GitHub

可以得出结论:绘制ROC曲线只需要我们整理出

y_true, y_score

这两个列表来就行。y_true表示测试集的label值,取值为0或1;y_socre表示测试集的预测值。

改动后的代码如下:

不过有个问题在于,model.predict只能预测一个batch的数据,比如我们一个batch大小为20,那么预测的结果里只有20个预测值,也就意味着 y_true, y_score的元素个数都为20.

# 1、导入TensorFlow包
import tensorflow as tf
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve, auc

file_path = 'file:/F:/3_研究生/1_研一下/深度学习推荐系统/SparrowRecSys-python/src/main/resources'
# Training samples path, change to your local path
training_samples_file_path = tf.keras.utils.get_file("trainingSamples.csv",
                                                     file_path+"/webroot/sampledata/trainingSamples.csv")
# Test samples path, change to your local path
test_samples_file_path = tf.keras.utils.get_file("testSamples.csv",
                                                 file_path+"/webroot/sampledata/testSamples.csv")


# load sample as tf dataset
def get_dataset(file_path):
    dataset = tf.data.experimental.make_csv_dataset(
        file_path,
        batch_size=20,
        label_name='label',
        na_value="0",
        num_epochs=1,
        ignore_errors=True)
    return dataset

# 2、载入训练数据
# split as test dataset and training dataset
train_dataset = get_dataset(training_samples_file_path)
test_dataset = get_dataset(test_samples_file_path)
# movieId,userId,rating,timestamp,label,releaseYear,movieGenre1,movieGenre2,movieGenre3,movieRatingCount,movieAvgRating,movieRatingStddev,userRatedMovie1,userRatedMovie2,userRatedMovie3,userRatedMovie4,userRatedMovie5,userRatingCount,userAvgReleaseYear,userReleaseYearStddev,userAvgRating,userRatingStddev,userGenre1,userGenre2,userGenre3,userGenre4,userGenre5

# 3、载入类别型特征
# genre features vocabulary
genre_vocab = ['Film-Noir', 'Action', 'Adventure', 'Horror', 'Romance', 'War', 'Comedy', 'Western', 'Documentary',
               'Sci-Fi', 'Drama', 'Thriller','Crime', 'Fantasy', 'Animation', 'IMAX', 'Mystery', 'Children', 'Musical']
# 用户有5个电影风格特征,电影有3个电影风格特征
GENRE_FEATURES = {
    'userGenre1': genre_vocab,
    'userGenre2': genre_vocab,
    'userGenre3': genre_vocab,
    'userGenre4': genre_vocab,
    'userGenre5': genre_vocab,
    'movieGenre1': genre_vocab,
    'movieGenre2': genre_vocab,
    'movieGenre3': genre_vocab
}

# all categorical features
# 分别是 genre、userId 和 movieId。在载入 genre 类特征时,
# 我们采用了 tf.feature_column.categorical_column_with_vocabulary_list 方法把字符串型的特征转换成了 One-hot 特征。
# 在这个转换过程中我们需要用到一个词表,你可以看到我在开头就定义好了包含所有 genre 类别的词表 genre_vocab。
# 在转换 userId 和 movieId 特征时,我们又使用了 tf.feature_column.categorical_column_with_identity 方法把 ID 转换成 One-hot 特征,这个方法不用词表,它会直接把 ID 值对应的那个维度置为 1。
# 比如,我们输入这个方法的 movieId 是 340,总的 movie 数量是 1001,使用这个方法,就会把这个 1001 维的 One-hot movieId 向量的第 340 维置为 1,剩余的维度都为 0。
# 为了把稀疏的 One-hot 特征转换成稠密的 Embedding 向量,我们还需要在 One-hot 特征外包裹一层 Embedding 层,可以看到 tf.feature_column.embedding_column(movie_col, 10) 方法完成了这样的操作,它在把 movie one-hot 向量映射到了一个 10 维的 Embedding 层上。

#
categorical_columns = []

# 把字符串型特征转换成One-hot特征
for feature, vocab in GENRE_FEATURES.items():
    cat_col = tf.feature_column.categorical_column_with_vocabulary_list(
        key=feature, vocabulary_list=vocab)
    emb_col = tf.feature_column.embedding_column(cat_col, 10)
    categorical_columns.append(emb_col)

# movie id embedding feature
movie_col = tf.feature_column.categorical_column_with_identity(key='movieId', num_buckets=1001)
movie_emb_col = tf.feature_column.embedding_column(movie_col, 10)
categorical_columns.append(movie_emb_col)

# user id embedding feature
user_col = tf.feature_column.categorical_column_with_identity(key='userId', num_buckets=30001)
user_emb_col = tf.feature_column.embedding_column(user_col, 10)
categorical_columns.append(user_emb_col)

# 4、数值型特征的处理
# all numerical features
numerical_columns = [tf.feature_column.numeric_column('releaseYear'),
                     tf.feature_column.numeric_column('movieRatingCount'),
                     tf.feature_column.numeric_column('movieAvgRating'),
                     tf.feature_column.numeric_column('movieRatingStddev'),
                     tf.feature_column.numeric_column('userRatingCount'),
                     tf.feature_column.numeric_column('userAvgRating'),
                     tf.feature_column.numeric_column('userRatingStddev')]

# 5、定义模型结构
# embedding + MLP model architecture
model = tf.keras.Sequential([
    tf.keras.layers.DenseFeatures(numerical_columns + categorical_columns),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(1, activation='sigmoid'),
])

# 6、定义模型训练相关的参数
# compile the model, set loss function, optimizer and evaluation metrics
model.compile(
    loss='binary_crossentropy',
    optimizer='adam',
    metrics=['accuracy', tf.keras.metrics.AUC(curve='ROC'), tf.keras.metrics.AUC(curve='PR')])


# 7、模型的训练
# train the model
model.fit(train_dataset, epochs=5)

# model.save('saved_model/my_model')

# 模型的评估
# evaluate the model
test_loss, test_accuracy, test_roc_auc, test_pr_auc = model.evaluate(test_dataset)
print('\n\nTest Loss {}, Test Accuracy {}, Test ROC AUC {}, Test PR AUC {}'.format(test_loss, test_accuracy,
                                                                                   test_roc_auc, test_pr_auc))

# for goodRating in list(test_dataset)[0][1]:
#     print(goodRating)

# print some predict results
y_true = []
y_score = []
predictions = model.predict(test_dataset)
for prediction, goodRating in zip(predictions[:20], list(test_dataset)[0][1][:20]):
    if bool(goodRating):
        y_true.append(1)
    else:
        y_true.append(0)
    y_score.append(prediction[0])
    print("Predicted good rating: {:.2%}".format(prediction[0]),
          " | Actual rating label: ",
          ("Good Rating" if bool(goodRating) else "Bad Rating"))

# ----------------------- 绘制ROC 曲线
print(y_true)
print(y_score)

# 计算
fpr, tpr, thread = roc_curve(y_true, y_score)
roc_auc = auc(fpr, tpr)
# 绘图
plt.figure()
lw = 2
plt.plot(fpr, tpr, color='darkorange',
         lw=lw, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic')
plt.legend(loc="lower right")
plt.savefig('roc.png',)
plt.show()


# -------------------------------绘制PR曲线

上面得到y_true和y_score的逻辑(按理说)应该是没有问题的,但是model.evaluate计算出的ROC AUC值是0.75,而我计算出的是0.64。毕竟evaluate用的是整个测试集,而画图用的prediction只用了一个batch,有偏差正常

三、绘制PR曲线

和绘制AUC曲线一样,绘制PR曲线也只需要我们整理出y_true, y_score这两个列表来就行

# -------------------------------绘制PR曲线
# 计算
P, R, thresholds = precision_recall_curve(y_true, y_score)
# 绘图
plt.figure()
lw = 2
plt.plot(R, P, color='darkorange',
         lw=lw)
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.title('Precision/Recall Curve')
plt.legend(loc="lower right")
plt.savefig('roc.png',)
plt.show()

四、保存模型

TensorFlow的模型有很多种模型保存格式,根据已有的部署方式

可以知道我们要使用的是SavedModel 格式

SavedModel

SavedModel 格式是tensorflow 2.0 推荐的格式,他很好地支持了tf-serving等部署,并且可以简单被python,java等调用。

通常SavedModel由以下几个部分组成

├── assets/ # 所需的外部文件,例如说初始化的词汇表文件,一般无
├── assets.extra/ # TensorFlow graph 不需要的文件, 例如说给用户知晓的如何使用SavedModel的信息. Tensorflow 不使用这个目录下的文件。
├── saved_model.pb # 保存的是MetaGraph的网络结构
├── variables # 参数权重,包含了所有模型的变量(tf.Variable objects)参数
    ├── variables.data-00000-of-00001
    └── variables.index

导出为SavedModel(tf 2.0方式)

model.save('saved_model/my_model')  
"""saved as SavedModel by default"""

 运行后,可以在下图左边列表中看到保存的模型文件

五、后续

任务:训练其他的推荐模型

出现问题

问题①:Cast string to int32 is not supported

问题②:Column dtype and SparseTensors dtype must be compatible. key: userGenre1, column dtype:string   tensor dtype:int32

解决方法:以为是源码被改动过,上网搜了一下模型的源码,发现源码没有问题(没有被改动过)。按理说应该能一键运行,所以考虑是包的版本问题,有的包的函数太low了,欠缺一些功能。

准备升级一下tensorflow版本到2.4.0,虽然升级失败了,但是升级的过程中自己升级了一些东西,然后就能跑了。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值