基于 CNN + RNN 的个人征信预测

使用 RNN+CNN 的方式进行对用户是否会逾期还款的预测,最终效果不算非常理想,但比较之前几次直接使用 RNN 的尝试至少显得有点效果了,在这个程序上花了较长的时间,就还是发上来,但是测试结果就不说了。【封面图片也就不设置了,就当无事发生过(┐「ε:)

准备工作

导入所需库

1
2
3
4
5
6
7
print('Kernel Connected')
import pandas as pd
import numpy as np
import os
import time
from tqdm import tqdm
import tensorflow as tf
Kernel Connected

加载数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
start_t = time.time()
os.chdir('/var/Datasets/Credit/')
# 用户的基本属性user_info.txt
# - 其中,字段性别为0表示性别未知。 用户id,性别,职业,教育程度,婚姻状态,户口类型
user_info_train = pd.read_csv('./train/user_info_train.txt',
names = ['UID','Sex','Work','Edu','Marriage','Htype']).sort_values('UID')

# 放款时间信息loan_time.txt。 用户id,放款时间
loan_time_train = pd.read_csv('./train/loan_time_train.txt',
names = ['UID','LoanTime']).sort_values('UID')

# 银行流水记录 bank_detail.txt
# - 其中,第2个字段,时间戳为0表示时间未知;
# - 第3个字段,交易类型有两个值,1表示支出、0表示收入;
# - 第5个字段,工资收入标记为1时,表示工资收入。 用户id,时间戳,交易类型,交易金额,工资收入标记
bank_detail_train = pd.read_csv('./train/bank_detail_train_modified.txt',
names = ['UID','TimeStamp','Type','Amount','Flag']).sort_values(by = ['UID', 'TimeStamp'])

# 用户浏览行为browse_history.txt
# - 其中,第2个字段,时间戳为0表示时间未知。 用户id,时间戳,浏览行为数据,浏览子行为编号
browse_history_train = pd.read_csv('./train/browse_history_train_modified.txt',
names = ['UID','TimeStamp','Data','subN']).sort_values(by = ['UID', 'TimeStamp'])

# 信用卡账单记录bill_detail.txt。共15个字段,其中,第2个字段,时间戳为0表示时间未知。为方便浏览,字段以表格的形式给出。
# 用户id,账单时间戳,银行id,上期账单金额,上期还款金额,信用卡额度,本期账单余额,
#本期账单最低还款额,消费笔数,本期账单金额,调整金额,循环利息,可用金额,
#预借现金额度,还款状态
bill_detail_train = pd.read_csv('./train/bill_detail_train_modified1.txt',
names = ['UID','TimeStamp','BID','LastAMT','LastRTN','Max','CuBalance',
'CuMinRTN','Payments','CuPaied','调整金额','CurrInt','AvaliAMT',
'预借现金额度','RTNState']).sort_values(by = ['UID', 'BID', 'TimeStamp'])

#共2个字段。样本标签为1,表示逾期30天以上;样本标签为0,表示逾期10天以内。
#注意:逾期10天~30天之内的用户,并不在此问题考虑的范围内
overdue_train = pd.read_csv('./train/overdue_train.txt', names = ['UID','Tag']).sort_values('UID')

os.chdir('/home/jupyter_hub_users/aeonni_ai/TensorFlow-Learning/Credit')
print('数据加载完毕,用时: %d 秒'%(time.time()-start_t))
数据加载完毕,用时: 12 秒

划分训练集与测试集

以 UserID 待遇 50000 为分界线,分为训练集与测试集,并打包成 dict

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
start_t = time.time()
sep_n = 50000

bill_detail_train.TimeStamp /= 3600000
browse_history_train.TimeStamp /= 3600000
bank_detail_train.TimeStamp /= 3600000

bill_detail_train['Last'] = (bill_detail_train.LastRTN - bill_detail_train.LastAMT)

bill_detail_train.BID[bill_detail_train.BID > 20] = np.nan#-= 510000
bill_detail_train = bill_detail_train.dropna()

bill_detail_test = bill_detail_train[bill_detail_train.UID > sep_n]
bill_detail_train = bill_detail_train[bill_detail_train.UID <= sep_n]

browse_history_test = browse_history_train[browse_history_train.UID > sep_n]
browse_history_train = browse_history_train[browse_history_train.UID <= sep_n]

bank_detail_test = bank_detail_train[bank_detail_train.UID > sep_n]
bank_detail_train = bank_detail_train[bank_detail_train.UID <= sep_n]

user_info_test = user_info_train[user_info_train.UID > sep_n]
user_info_train = user_info_train[user_info_train.UID <= sep_n]

loan_time_test = loan_time_train[loan_time_train.UID > sep_n]
loan_time_train = loan_time_train[loan_time_train.UID <= sep_n]

overdue_test = overdue_train[overdue_train.UID > sep_n]
overdue_train = overdue_train[overdue_train.UID <= sep_n]

user_info_train = pd.merge(user_info_train, overdue_train, on=['UID'])
t_df = user_info_train[user_info_train['Tag'] == 1]
for i in range(4):
user_info_train = pd.concat([user_info_train,t_df])
user_info_train = user_info_train.sample(frac=1.0).loc[:,['UID','Sex','Work','Edu','Marriage','Htype']]

train_data = dict(
user_info = user_info_train,
bill_detail = bill_detail_train,
browse_history = browse_history_train,
bank_detail = bank_detail_train,
overdue = overdue_train,
)

test_data = dict(
user_info = user_info_test,
bill_detail = bill_detail_test,
browse_history = browse_history_test,
bank_detail = bank_detail_test,
overdue = overdue_test,
)

print('数据处理完毕,用时: %d 秒'%(time.time()-start_t))

定义数据迭代的生成器

生成器每次返回的格式为:

【5维的用户信息】,
【形状为 16length8 的交易信息】,
【形状为 length3 的银行信息】,
【形状为 length
3 的浏览信息】,
【是否预期的标签】,
【三个length的大小】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def dataset_generator(data, balance = 5):
for uinfo in data['user_info'].iterrows():
ui = uinfo[1].values
uid = ui[0]
ui = np.array(ui[1:])
u = data['bill_detail'][data['bill_detail'].UID == uid].loc[:,
['TimeStamp','BID','Last','Max','CuBalance','CuMinRTN','Payments','CuPaied','RTNState']]
li = []
m_len = 3
for b in range(16):
item = u[u.BID == b+1].loc[:,
['TimeStamp','Last','Max','CuBalance','CuMinRTN','Payments','CuPaied','RTNState']].values
li.append(item)
m_len = max(m_len, len(item))
o = np.array([])
for each in li:
o = np.append(o,np.pad(each,((0,m_len-each.shape[0]),(0,0)),'constant', constant_values=(0,0)))
bill = o.reshape(16, m_len, 8)

bank = data['bank_detail'][data['bank_detail'].UID == uid].loc[:,['TimeStamp','Amount','Flag']].values
if len(bank) == 0: bank = np.zeros([5,3])#np.array([[0,0,0]])
browse = data['browse_history'][data['browse_history'].UID == uid].loc[:,['TimeStamp','Data','subN']].values
if len(browse) == 0: browse = np.zeros([5,3])#np.array([[0,0,0]])
tag = int(data['overdue'][data['overdue'].UID == uid].Tag)
yield ui, bill, bank, browse, tag, np.array([len(bill),len(bank),len(browse)], dtype = np.int32)

模型的构建与训练

构建 tf.data.Dataset 迭代器

在创建数据集的迭代器时,使用了 train_dataset.padded_batch() 原因是如果想用一定 batch 大小的数据来进行投喂,batch 内的数据必须要有同样的形状,而因为每个人的数据长度都不同,所以在生成 batch 的时候需要做 padding。

test_dataset 的 repeat 次数视情况而定,在训练时可以设置成始终 repeat,为的是每隔一定训练步数进行一次小小的测试,而在完整测试的时候则可以设置为 1 次.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
tf.reset_default_graph()
Batch_Size = 30
Epochs = 30

train_dataset = tf.data.Dataset.from_generator(
lambda: dataset_generator(train_data, balance = 4),
(tf.int32,tf.float32,tf.float32,tf.float32,tf.int64, tf.int32),
(tf.TensorShape([5]),tf.TensorShape([16, None, 8]),
tf.TensorShape([None,3]),tf.TensorShape([None,3]),
tf.TensorShape([]),tf.TensorShape([3])))

train_dataset = train_dataset.padded_batch(Batch_Size,
(tf.TensorShape([5]),tf.TensorShape([16, None, 8]),
tf.TensorShape([None,3]),tf.TensorShape([None,3]),
tf.TensorShape([]),tf.TensorShape([3])))

test_dataset = tf.data.Dataset.from_generator(
lambda: dataset_generator(test_data, balance = 0),
(tf.int32,tf.float32,tf.float32,tf.float32,tf.int64, tf.int32),
(tf.TensorShape([5]),tf.TensorShape([16, None, 8]),
tf.TensorShape([None,3]),tf.TensorShape([None,3]),
tf.TensorShape([]),tf.TensorShape([3])))

test_dataset = test_dataset.padded_batch(Batch_Size,
(tf.TensorShape([5]),tf.TensorShape([16, None, 8]),
tf.TensorShape([None,3]),tf.TensorShape([None,3]),
tf.TensorShape([]),tf.TensorShape([3])))

train_dataset = train_dataset.repeat(Epochs)
train_dataset = train_dataset.shuffle(buffer_size = 60)

test_dataset = test_dataset.repeat(1)
test_dataset = test_dataset.shuffle(buffer_size = 50)

iter_ = train_dataset.make_one_shot_iterator()
iter_out = iter_.get_next()

iter_test = test_dataset.make_one_shot_iterator()
iter_test_out = iter_test.get_next()

一些 Placeholder

1
2
3
4
5
6
bill_phd = tf.placeholder(tf.float32, [None, 16, None, 8], name='bill_phd') #None 8 16
bank_phd = tf.placeholder(tf.float32, [None, None, 3], name='bank_phd')
browse_phd = tf.placeholder(tf.float32, [None, None, 3], name='browse_phd')
user_i = tf.placeholder(tf.float32, [None, 5], name='user_i')
keep_prob = tf.placeholder(tf.float32, name='keep_prob')
tag = tf.placeholder(tf.int64, name='tag')

模型的搭建

之前的失败

之前使用过纯 RNN 的方法,也使用过 RNN 提取特征, 再用 CNN 对变形之后的特征进行卷积的方法,但是不管哪种方法模型都显得十分臃肿,不直观,并且逻辑也比较混乱,在尝试了很多次训练了很久之后也没办法做到收敛。做了 RNN/CNN 的 MNIST 作业之后,一开始也没想到如何在个人征信预测上使用 RNN+CNN 的方式。直到后来知道了 tf.nn.top_k() 这样的池化方式,我尝试性的写了下面这个比较简单,但至少逻辑清晰的网络,虽然一开始也没法收敛,但是多次尝试后取得了成果。

本模型简介

这个模型使用了 CNN 和 RNN 进行特征的提取,对于 browse_historybank_detail 这两项数据,直接使用 CNN 时间上相近的行进行卷积,最后得到一定长度的,64个通道的数据,随后对每个通道的数据进行 top2 池化,展开得到 128 维的特征。对这128维的特征用全连接层降至32维。

CNN_For_browse_history_Features

1
2
3
4
5
6
7
8
9
10
with tf.variable_scope('CNN_For_browse_history_Features', reuse = tf.AUTO_REUSE) as scope:
hc1 = conv_layer(tf.reshape(browse_phd, [Batch_Size, -1, 3, 1]),
kernel_shape = [3,3,1,16], name = 'history_conv1',
padding='VALID', activ=tf.nn.sigmoid)
hc2 = conv_layer(hc1, kernel_shape = [3,1,16,64],
name = 'history_conv2', padding ='SAME', activ=tf.nn.sigmoid)
h_pool = tf.reshape(tf.nn.top_k(tf.transpose(hc2,[0,2,3,1]),
k=2, sorted=True)[0], [Batch_Size,64*2])
print(h_pool)
h_out = fc_layer(h_pool, 32, name = 'history_fc')
Output shape of history_conv1 is : (30, ?, 1, 16)
Output shape of history_conv2 is : (30, ?, 1, 64)
Tensor("CNN_For_browse_history_Features/Reshape_1:0", shape=(30, 128), dtype=float32)
Output shape of history_fc is : (30, 32)

CNN_For_bank_detail_Features

1
2
3
4
5
6
7
8
9
10
with tf.variable_scope('CNN_For_bank_detail_Features', reuse = tf.AUTO_REUSE) as scope:
bc1 = conv_layer(tf.reshape(bank_phd, [Batch_Size, -1, 3, 1]),
kernel_shape = [3,3,1,16], name = 'bank_conv1',
padding='VALID', activ=tf.nn.sigmoid)
bc2 = conv_layer(bc1, kernel_shape = [3,1,16,64],
name = 'bank_conv2', padding ='SAME', activ=tf.nn.sigmoid)
b_pool = tf.reshape(tf.nn.top_k(tf.transpose(bc2,[0,2,3,1]),
k=2, sorted=True)[0], [Batch_Size,64*2])
print(b_pool)
b_out = fc_layer(b_pool, 32, name = 'bank_fc')
Output shape of bank_conv1 is : (30, ?, 1, 16)
Output shape of bank_conv2 is : (30, ?, 1, 64)
Tensor("CNN_For_bank_detail_Features/Reshape_1:0", shape=(30, 128), dtype=float32)
Output shape of bank_fc is : (30, 32)

bill_detail 的处理

对于 bill_detail 这项数据,前期数据处理的时候把16个银行的信息分到16个通道,没有的用0填充。

随后将数据喂入 CNN ,它的工作方式与之前一致,top2 池化之后得到了64个通道26维的特征,也就是64个通道,12维的特征。随后将其丢入 RNN,对RNN 的输出做一个全连接(矩阵乘法),得到 32 维的特征。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
rnn_out_dim = 128
Learning_Rate = 0.01

with tf.variable_scope('CNN_For_bill_detail_Features', reuse = tf.AUTO_REUSE) as scope:
dc1 = conv_layer(tf.transpose(bill_phd,[0,2,3,1]),
kernel_shape = [3,3,16,32], name = 'bill_conv1',
padding='VALID', activ=tf.nn.sigmoid)
dc2 = conv_layer(dc1, kernel_shape = [3,1,32,64],
name = 'bill_conv2', padding ='SAME', activ=tf.nn.sigmoid)
d_pool = tf.reshape(tf.transpose(tf.nn.top_k(tf.transpose(dc2,[0,2,3,1]),
k=2, sorted=True)[0], [0,2,1,3]), [Batch_Size,64,2*6])
print(d_pool)
with tf.variable_scope('RNN_For_bill_detail_Features', reuse = tf.AUTO_REUSE) as scope:
bill_cell = tf.nn.rnn_cell.GRUCell(num_units = rnn_out_dim, dtype = tf.float32)
bill_initial_state = bill_cell.zero_state(Batch_Size, dtype=tf.float32)
bill_outputs, bill_state = tf.nn.dynamic_rnn(bill_cell, d_pool,
initial_state = bill_initial_state)
d_out = fc_layer(tf.unstack(tf.transpose(bill_outputs, [1,0,2]))[-1], 32, name = 'bill_fc')
Output shape of bill_conv1 is : (?, ?, 6, 32)
Output shape of bill_conv2 is : (?, ?, 6, 64)
Tensor("CNN_For_bill_detail_Features/Reshape:0", shape=(30, 64, 12), dtype=float32)
Output shape of bill_fc is : (30, 32)

User_info 的处理

User_info 这项数据先把每一类别项作为 one-hot 向量进行 embedding,连接形成 32 维的特征。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
with tf.variable_scope('User_info_Features', reuse = tf.AUTO_REUSE) as scope:
user_i_sex_embeddings = tf.get_variable(
'user_i_sex_embeddings', [3, 4])
user_i_work_embeddings = tf.get_variable(
'user_i_work_embeddings', [5, 6])
user_i_edu_embeddings = tf.get_variable(
'user_i_edu_embeddings', [5, 6])
user_i_marriage_embeddings = tf.get_variable(
'user_i_marriage_embeddings', [6, 10])
user_i_type_embeddings = tf.get_variable(
'user_i_type_embeddings', [5, 6])
user_i_sex_embedded = tf.nn.embedding_lookup(
user_i_sex_embeddings, tf.cast(user_i[:,0], dtype=tf.int32))
user_i_work_embedded = tf.nn.embedding_lookup(
user_i_work_embeddings, tf.cast(user_i[:,1], dtype=tf.int32))
user_i_edu_embedded = tf.nn.embedding_lookup(
user_i_edu_embeddings, tf.cast(user_i[:,2], dtype=tf.int32))
user_i_marriage_embedded = tf.nn.embedding_lookup(
user_i_marriage_embeddings, tf.cast(user_i[:,3], dtype=tf.int32))
user_i_type_embedded = tf.nn.embedding_lookup(
user_i_type_embeddings, tf.cast(user_i[:,4], dtype=tf.int32))

user_i_o = tf.reshape(tf.concat(
[user_i_sex_embedded, user_i_work_embedded,
user_i_edu_embedded, user_i_marriage_embedded, user_i_type_embedded],
axis = 1), [Batch_Size, 32])
print(user_i_o)
Tensor("User_info_Features/Reshape:0", shape=(30, 32), dtype=float32)

最后的全连接

最后的全连接层将之前的几项特征 concat 之后,运算,最终输出一个二维的结果,代表0或1的可能性。

1
2
3
4
5
6
7
8
9
with tf.variable_scope('Features_FC_Layer', reuse = tf.AUTO_REUSE) as scope:
direct_fc = tf.concat([user_i_o, b_out, d_out, h_out], axis = 1)
print(direct_fc)
fc1 = fc_layer(direct_fc, 128, name = 'fc1')
dropout1 = tf.nn.dropout(fc1, keep_prob)
fc2 = fc_layer(dropout1, 32, name = 'fc2')
dropout2 = tf.nn.dropout(fc2, keep_prob)
fc3 = fc_layer(dropout2, 2, name = 'fc3')
cnn_out = tf.nn.softmax(fc3)
Tensor("Features_FC_Layer/concat:0", shape=(30, 128), dtype=float32)
Output shape of fc1 is : (30, 128)
Output shape of fc2 is : (30, 32)
Output shape of fc3 is : (30, 2)

损失函数与优化器

损失函数的定义上我在平均平方误差之后又自己加了一项,加上的是没有判断出失信用户的数量*常数,我在这里把常数设置为2。

理由是因为在其训练过程中,虽然我做了平衡数据集,但是模型仍然偏向于输出0,也就是说没有失信,并且如果判断出少量的失信用户,则被误判的正常用户就更多,也就是说准确率反而下降,这个时候,我需要鼓励模型去认为用户是失信的,对没有判断出失信用户增加惩罚力度。

优化器的选用上,我使用了 tf.train.FtrlOptimizer 其它很多优化器除了SGD之外几乎全部局部最优,而SGD则又比较难用,这个优化器的效果不错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
my_global_step = tf.Variable(0, name='global_step', trainable=False) 

pred = tf.argmax(cnn_out, 1)
cost = tf.losses.mean_pairwise_squared_error(cnn_out, tf.one_hot(tag, 2)) + \
tf.cast(tf.reduce_sum(tf.clip_by_value(tag-pred, 0, 1)*2),tf.float32)

tf.summary.scalar('train_loss', cost)

optimizer = tf.train.FtrlOptimizer(learning_rate = Learning_Rate).minimize(cost, global_step = my_global_step)

correct_pred = tf.equal(pred, tag)

accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
tf.summary.scalar('train_accuracy', accuracy)
<tf.Tensor 'test_accuracy:0' shape=() dtype=string>

训练步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
saver = tf.train.Saver()
MODEL_SAVE_PATH = "Credit/"
MODEL_NAME = "model_credit"

with tf.Session() as sess:
sess.run(tf.group(tf.global_variables_initializer(),tf.local_variables_initializer()))
merged = tf.summary.merge_all() #将图形、训练过程等数据合并在一起
merge_train_summary = tf.summary.merge([tf.get_collection(tf.GraphKeys.SUMMARIES,'train_loss'),
tf.get_collection(tf.GraphKeys.SUMMARIES,'train_accuracy')])
merge_test_summary = tf.summary.merge([tf.get_collection(tf.GraphKeys.SUMMARIES,'test_loss'),
tf.get_collection(tf.GraphKeys.SUMMARIES,'test_accuracy')])
writer = tf.summary.FileWriter('logs/%s'%str(time.clock()),sess.graph) #将训练日志写入到logs文件夹下
for e in range(Epochs):
for i in range(2531):
try:
ui, bill, bank, browse, tag_, seq_len = sess.run(iter_out)
_, loss, t, p, a = sess.run([optimizer, cost, tag, pred, accuracy], feed_dict={bank_phd: bank, tag: tag_,
browse_phd: browse, user_i: ui, keep_prob: 0.3, bill_phd: bill})
if i%20 == 0:
print("Epoch %d Step %d: "%(e,i),loss, t, p, a)
result = sess.run(merge_train_summary, feed_dict={bank_phd: bank, tag: tag_,
browse_phd: browse, user_i: ui, keep_prob: 0.5, bill_phd: bill})
writer.add_summary(result,sess.run(my_global_step))
except:
print('err')
continue
if (i+1)%1000 == 0:
saver.save(sess, os.path.join(MODEL_SAVE_PATH, MODEL_NAME), global_step=my_global_step)
if i%100 == 0:
tms = 1
acc = 0
try:
a_mat = np.zeros([2,2])
for j in range(10):
ui, bill, bank, browse, tag_, seq_len = sess.run(iter_test_out)
t, p, a = sess.run([tag, pred, accuracy], feed_dict={bank_phd: bank, tag: tag_,
browse_phd: browse, user_i: ui, keep_prob: 1, bill_phd: bill})
for x in range(30):
a_mat[t[x], p[x]] += 1
print('Test', a_mat)
except:
print('No. ', i, ' TEST: ', acc/tms)

训练、测试与结果

训练过程

一共训练了10多个EPOCH,迭代将近35000次,loss 和 准确率 的变化如下图所示

Loss变化图

准确率变化图

附录:其它用到的代码

定义网络结构的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
def arg_with_default(d, name, default=None):
return d[name] if d.get(name) else default

def conv_layer(input_tensor, kernel_shape = [5,5,3,16], name = 'Undefined', dtype=tf.float32,
padding='SAME', activ=tf.nn.elu, v=True, **args):
if args.get('regularizer'):
args['kernel_regularizer'] = args['regularizer']
args['biases_regularizer'] = args['regularizer']
with tf.name_scope(name) as scope:
kernel_weight = tf.get_variable(name+'_kernel', kernel_shape, dtype = dtype,
initializer = arg_with_default(args, 'kernel_initializer', tf.contrib.layers.xavier_initializer()),
regularizer = arg_with_default(args, 'kernel_regularizer', None))
biases = tf.get_variable(name+'_biases', [kernel_shape[-1]], dtype = dtype,
initializer = arg_with_default(args, 'biases_initializer', tf.constant_initializer(0.0)),
regularizer = arg_with_default(args, 'biases_regularizer', None))
conv = tf.nn.conv2d(input_tensor, kernel_weight,
strides=[1,1,1,1], padding=padding, name=name+'_conv')
bias = tf.nn.bias_add(conv, biases, name=name+'_bias_add')
actived = activ(bias)
if v:
print('Output shape of %s is :'%name, actived.shape)
return actived

def fc_layer(input_tensor, output_shape, name = 'Undefined', dtype=tf.float32,
activ=tf.nn.elu, **args):
n_in = input_tensor.get_shape()[-1].value
if args.get('regularizer'):
args['kernel_regularizer'] = args['regularizer']
args['biases_regularizer'] = args['regularizer']
with tf.name_scope(name) as scope:
weight = tf.get_variable(name+'_weight',shape = [n_in, output_shape], dtype = dtype,
initializer = arg_with_default(args, 'weight_initializer', tf.contrib.layers.xavier_initializer()),
regularizer = arg_with_default(args, 'weight_regularizer', None))
# biases = tf.Variable(tf.constant(0.1, shape = [output_shape], dtype = tf.float32), name = 'b')
biases = tf.get_variable(name+'_biases', shape = [output_shape], dtype = dtype,
initializer = arg_with_default(args, 'biases_initializer', tf.constant_initializer(0.1)),
regularizer = arg_with_default(args, 'biases_regularizer', None))
# tf.nn.relu_layer对输入变量input_op与kernel做矩阵乘法加上bias,再做RELU非线性变换得到activation
if activ:
actived = activ(tf.nn.bias_add(tf.matmul(input_tensor, weight), biases))
else:
actived = tf.add(tf.matmul(input_tensor, weight), biases)
print('Output shape of %s is :'%name, actived.shape)
return actived

测试的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
MODEL_SAVE_PATH = "Credit/"
MODEL_NAME = "model_credit"

TAG = []
PRED = []
a_mat = np.zeros([2,2])


with tf.Session() as sess:
saver = tf.train.import_meta_graph(MODEL_SAVE_PATH+'model_credit-34890.meta')
saver.restore(sess, MODEL_SAVE_PATH+'model_credit-34890')
i = 0
while True:
i += 1
ui, bill, bank, browse, tag_, seq_len = sess.run(iter_test_out)

t, p = sess.run(['tag:0', 'ArgMax_1:0'],
feed_dict={'bank_phd:0': bank, 'tag:0': tag_,
'browse_phd:0': browse, 'user_i:0': ui,
'keep_prob:0': 1, 'bill_phd:0': bill})
for x in range(30):
a_mat[t[x], p[x]] += 1
print(i, t, p)

# 准确率
print('准确率: ', (a_mat[0,0] + a_mat[1,1])/a_mat.sum())
# 1 准确率
print('1 准确率: ', a_mat[1,1]/(a_mat[1,0] + a_mat[1,1]))
# 0 准确率
print('0 准确率: ', a_mat[0,0]/(a_mat[0,0] + a_mat[0,1]))
# 误判率
print('误判率: ', a_mat[0,1]/(a_mat[0,1] + a_mat[1,1]))

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×