Skip to content

Commit 85b2614

Browse files
authored
Update init args, fix dimension mismatch in ConvMF (#348)
1 parent 64aa63c commit 85b2614

File tree

3 files changed

+115
-52
lines changed

3 files changed

+115
-52
lines changed

cornac/models/conv_mf/convmf.py

Lines changed: 68 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,29 @@
1616
import tensorflow as tf
1717

1818

19-
def conv_layer(input, num_input_channels,
20-
filter_height, filter_width,
21-
num_filters, seed=None, use_pooling=True):
19+
def conv_layer(
20+
input,
21+
num_input_channels,
22+
filter_height,
23+
filter_width,
24+
num_filters,
25+
seed=None,
26+
use_pooling=True,
27+
):
2228
shape = [filter_height, filter_width, num_input_channels, num_filters]
2329
weights = tf.Variable(tf.truncated_normal(shape, stddev=0.05, seed=seed))
2430
biases = tf.Variable(tf.constant(0.05, shape=[num_filters]))
25-
layer = tf.nn.conv2d(input=input, filter=weights,
26-
strides=[1, 1, 1, 1], padding="VALID")
31+
layer = tf.nn.conv2d(
32+
input=input, filter=weights, strides=[1, 1, 1, 1], padding="VALID"
33+
)
2734
layer = layer + biases
2835
if use_pooling:
29-
layer = tf.nn.max_pool(value=layer, ksize=[1, input.shape[1] - filter_height + 1, 1, 1],
30-
strides=[1, 1, 1, 1], padding="VALID")
36+
layer = tf.nn.max_pool(
37+
value=layer,
38+
ksize=[1, input.shape[1] - filter_height + 1, 1, 1],
39+
strides=[1, 1, 1, 1],
40+
padding="VALID",
41+
)
3142
layer = tf.nn.relu(layer)
3243
return layer, weights
3344

@@ -40,28 +51,39 @@ def flatten_layer(layer):
4051

4152

4253
def fc_layer(input, num_input, num_output, seed=None):
43-
weights = tf.Variable(tf.truncated_normal([num_input, num_output], stddev=0.05, seed=seed))
54+
weights = tf.Variable(
55+
tf.truncated_normal([num_input, num_output], stddev=0.05, seed=seed)
56+
)
4457
biases = tf.Variable(tf.constant(0.05, shape=[num_output]))
4558
layer = tf.matmul(input, weights) + biases
4659
layer = tf.nn.tanh(layer)
4760
return layer
4861

4962

50-
class CNN_module():
51-
52-
def __init__(self, output_dimension, dropout_rate,
53-
emb_dim, max_len, nb_filters, seed,
54-
init_W, learning_rate=0.001):
63+
class CNN_module:
64+
def __init__(
65+
self,
66+
output_dimension,
67+
dropout_rate,
68+
emb_dim,
69+
max_len,
70+
filter_sizes,
71+
num_filters,
72+
hidden_dim,
73+
seed,
74+
init_W,
75+
learning_rate=0.001,
76+
):
5577
self.drop_rate = dropout_rate
5678
self.max_len = max_len
5779
self.seed = seed
5880
self.learning_rate = learning_rate
5981
self.init_W = tf.constant(init_W)
6082
self.output_dimension = output_dimension
6183
self.emb_dim = emb_dim
62-
self.nb_filters = nb_filters
63-
self.filter_lengths = [3, 4, 5]
64-
self.vanila_dimension = 200
84+
self.filter_lengths = filter_sizes
85+
self.nb_filters = num_filters
86+
self.vanila_dimension = hidden_dim
6587

6688
self._build_graph()
6789

@@ -76,28 +98,46 @@ def _build_graph(self):
7698
self.reshape = tf.reshape(self.seq_emb, [-1, self.max_len, self.emb_dim, 1])
7799
self.convs = []
78100

79-
# Convolutional layer
101+
# Convolutional layers
80102
for i in self.filter_lengths:
81-
convolutional_layer, weights = conv_layer(input=self.reshape, num_input_channels=1,
82-
filter_height=i, filter_width=self.emb_dim,
83-
num_filters=self.nb_filters, use_pooling=True)
103+
convolutional_layer, weights = conv_layer(
104+
input=self.reshape,
105+
num_input_channels=1,
106+
filter_height=i,
107+
filter_width=self.emb_dim,
108+
num_filters=self.nb_filters,
109+
use_pooling=True,
110+
)
84111

85112
flat_layer, _ = flatten_layer(convolutional_layer)
86113
self.convs.append(flat_layer)
87114

88115
self.model_output = tf.concat(self.convs, axis=-1)
89116
# Fully-connected layers
90-
self.model_output = fc_layer(input=self.model_output, num_input=self.model_input.get_shape()[1].value,
91-
num_output=self.vanila_dimension)
117+
self.model_output = fc_layer(
118+
input=self.model_output,
119+
num_input=self.model_output.get_shape()[-1].value,
120+
num_output=self.vanila_dimension,
121+
)
92122
# Dropout layer
93123
self.model_output = tf.nn.dropout(self.model_output, self.drop_rate)
94124
# Output layer
95-
self.model_output = fc_layer(input=self.model_output, num_input=self.vanila_dimension,
96-
num_output=self.output_dimension)
125+
self.model_output = fc_layer(
126+
input=self.model_output,
127+
num_input=self.vanila_dimension,
128+
num_output=self.output_dimension,
129+
)
97130
# Weighted MEA loss function
98-
self.mean_square_loss = tf.losses.mean_squared_error(labels=self.v, predictions=self.model_output,
99-
reduction=tf.losses.Reduction.NONE)
131+
self.mean_square_loss = tf.losses.mean_squared_error(
132+
labels=self.v,
133+
predictions=self.model_output,
134+
reduction=tf.losses.Reduction.NONE,
135+
)
100136
self.weighted_loss = tf.reduce_sum(
101-
tf.reduce_sum(self.mean_square_loss, axis=1, keepdims=True) * self.sample_weight)
137+
tf.reduce_sum(self.mean_square_loss, axis=1, keepdims=True)
138+
* self.sample_weight
139+
)
102140
# RMSPro optimizer
103-
self.optimizer = tf.train.RMSPropOptimizer(learning_rate=self.learning_rate).minimize(self.weighted_loss)
141+
self.optimizer = tf.train.RMSPropOptimizer(
142+
learning_rate=self.learning_rate
143+
).minimize(self.weighted_loss)

cornac/models/conv_mf/recom_convmf.py

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414
# ============================================================================
1515

16+
import os
1617
import time
1718
import math
1819

@@ -35,6 +36,9 @@ class ConvMF(Recommender):
3536
n_epochs: int, optional, default: 50
3637
Maximum number of epochs for training.
3738
39+
cnn_epochs: int, optional, default: 5
40+
Number of epochs for optimizing the CNN for each overall training epoch.
41+
3842
lambda_u: float, optional, default: 1.0
3943
The regularization hyper-parameter for user latent factor.
4044
@@ -47,8 +51,14 @@ class ConvMF(Recommender):
4751
max_len: int, optional, default 300
4852
The maximum length of item's document
4953
50-
num_kernel_per_ws: int, optional, default: 100
51-
The number of kernel filter in convolutional layer
54+
filter_sizes: list, optional, default: [3, 4, 5]
55+
The length of filters in convolutional layer
56+
57+
num_filters: int, optional, default: 100
58+
The number of filters in convolutional layer
59+
60+
hidden_dim: int, optional, default: 200
61+
The dimension of hidden layer after the pooling of all convolutional layers
5262
5363
dropout_rate: float, optional, default: 0.2
5464
Dropout rate while training CNN
@@ -71,19 +81,21 @@ class ConvMF(Recommender):
7181

7282
def __init__(
7383
self,
74-
give_item_weight=True,
75-
cnn_epochs=5,
84+
name="ConvMF",
85+
k=50,
7686
n_epochs=50,
87+
cnn_epochs=5,
7788
lambda_u=1,
7889
lambda_v=100,
79-
k=50,
80-
name="ConvMF",
81-
trainable=True,
82-
verbose=False,
83-
dropout_rate=0.2,
8490
emb_dim=200,
8591
max_len=300,
86-
num_kernel_per_ws=100,
92+
filter_sizes=[3, 4, 5],
93+
num_filters=100,
94+
hidden_dim=200,
95+
dropout_rate=0.2,
96+
give_item_weight=True,
97+
trainable=True,
98+
verbose=False,
8799
init_params=None,
88100
seed=None,
89101
):
@@ -96,7 +108,9 @@ def __init__(
96108
self.dropout_rate = dropout_rate
97109
self.emb_dim = emb_dim
98110
self.max_len = max_len
99-
self.num_kernel_per_ws = num_kernel_per_ws
111+
self.filter_sizes = filter_sizes
112+
self.num_filters = num_filters
113+
self.hidden_dim = hidden_dim
100114
self.name = name
101115
self.verbose = verbose
102116
self.cnn_epochs = cnn_epochs
@@ -138,7 +152,7 @@ def fit(self, train_set, val_set=None):
138152
Recommender.fit(self, train_set, val_set)
139153

140154
self._init()
141-
155+
142156
if self.trainable:
143157
self._fit_convmf()
144158

@@ -175,16 +189,22 @@ def _fit_convmf(self):
175189
item_weight = np.ones(n_item, dtype=float)
176190

177191
# Initialize cnn module
192+
import tensorflow.compat.v1 as tf
178193
from .convmf import CNN_module
179-
import tensorflow as tf
194+
195+
# less verbose TF
196+
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
197+
tf.logging.set_verbosity(tf.logging.ERROR)
180198

181199
tf.set_random_seed(self.seed)
182200
cnn_module = CNN_module(
183201
output_dimension=self.k,
184202
dropout_rate=self.dropout_rate,
185203
emb_dim=self.emb_dim,
186204
max_len=self.max_len,
187-
nb_filters=self.num_kernel_per_ws,
205+
filter_sizes=self.filter_sizes,
206+
num_filters=self.num_filters,
207+
hidden_dim=self.hidden_dim,
188208
seed=self.seed,
189209
init_W=self.W,
190210
)
@@ -207,8 +227,10 @@ def _fit_convmf(self):
207227
history = 1e-50
208228
loss = 0
209229

210-
for iter in range(self.n_epochs):
211-
print("Iteration {}".format(iter + 1))
230+
for epoch in range(1, self.n_epochs + 1):
231+
if self.verbose:
232+
print("Epoch: {}/{}".format(epoch, self.n_epochs))
233+
212234
tic = time.time()
213235

214236
user_loss = np.zeros(n_user)
@@ -229,17 +251,15 @@ def _fit_convmf(self):
229251
U_j = self.U[idx_user]
230252
R_j = R_item[j]
231253

232-
A = self.lambda_v * item_weight[j] * np.eye(self.k) + U_j.T.dot(
233-
U_j
234-
)
254+
A = self.lambda_v * item_weight[j] * np.eye(self.k) + U_j.T.dot(U_j)
235255
B = (U_j * (np.tile(R_j, (self.k, 1)).T)).sum(
236256
0
237257
) + self.lambda_v * item_weight[j] * theta[j]
238258
self.V[j] = np.linalg.solve(A, B)
239259

240260
item_loss[j] = -np.square(R_j - U_j.dot(self.V[j])).sum()
241261

242-
loop = trange(self.cnn_epochs, desc="CNN", disable=not self.verbose)
262+
loop = trange(self.cnn_epochs, desc="Optimizing CNN", disable=not self.verbose)
243263
for _ in loop:
244264
for batch_ids in self.train_set.item_iter(batch_size=128, shuffle=True):
245265
batch_seq = self.train_set.item_text.batch_seq(
@@ -271,9 +291,12 @@ def _fit_convmf(self):
271291
toc = time.time()
272292
elapsed = toc - tic
273293
converge = abs((loss - history) / history)
274-
print(
275-
"Loss: %.5f Elpased: %.4fs Converge: %.6f " % (loss, elapsed, converge)
276-
)
294+
295+
if self.verbose:
296+
print(
297+
"Loss: %.5f Elpased: %.4fs Converge: %.6f " % (loss, elapsed, converge)
298+
)
299+
277300
history = loss
278301
if converge < converge_threshold:
279302
endure -= 1
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
tensorflow>=1.10.0
1+
tensorflow>=1.15.2

0 commit comments

Comments
 (0)