(self, D, M, K)
| 40 | |
| 41 | |
| 42 | def build(self, D, M, K): |
| 43 | # params |
| 44 | self.W = tf.Variable(tf.random.normal(shape=(D, K, M)) * np.sqrt(2.0 / M)) |
| 45 | self.c = tf.Variable(np.zeros(M).astype(np.float32)) |
| 46 | self.b = tf.Variable(np.zeros((D, K)).astype(np.float32)) |
| 47 | |
| 48 | # data |
| 49 | self.X_in = tf.compat.v1.placeholder(tf.float32, shape=(None, D)) |
| 50 | |
| 51 | # one hot encode X |
| 52 | # first, make each rating an int |
| 53 | X = tf.cast(self.X_in * 2 - 1, tf.int32) |
| 54 | X = tf.one_hot(X, K) |
| 55 | |
| 56 | # conditional probabilities |
| 57 | # NOTE: tf.contrib.distributions.Bernoulli API has changed in Tensorflow v1.2 |
| 58 | V = X |
| 59 | p_h_given_v = tf.nn.sigmoid(dot1(V, self.W) + self.c) |
| 60 | self.p_h_given_v = p_h_given_v # save for later |
| 61 | |
| 62 | # draw a sample from p(h | v) |
| 63 | r = tf.random.uniform(shape=tf.shape(input=p_h_given_v)) |
| 64 | H = tf.cast(r < p_h_given_v, dtype=tf.float32) |
| 65 | |
| 66 | # draw a sample from p(v | h) |
| 67 | # note: we don't have to actually do the softmax |
| 68 | logits = dot2(H, self.W) + self.b |
| 69 | cdist = tf.compat.v1.distributions.Categorical(logits=logits) |
| 70 | X_sample = cdist.sample() # shape is (N, D) |
| 71 | X_sample = tf.one_hot(X_sample, depth=K) # turn it into (N, D, K) |
| 72 | |
| 73 | # mask X_sample to remove missing ratings |
| 74 | mask2d = tf.cast(self.X_in > 0, tf.float32) |
| 75 | mask3d = tf.stack([mask2d]*K, axis=-1) # repeat K times in last dimension |
| 76 | X_sample = X_sample * mask3d |
| 77 | |
| 78 | |
| 79 | # build the objective |
| 80 | objective = tf.reduce_mean(input_tensor=self.free_energy(X)) - tf.reduce_mean(input_tensor=self.free_energy(X_sample)) |
| 81 | self.train_op = tf.compat.v1.train.AdamOptimizer(1e-2).minimize(objective) |
| 82 | # self.train_op = tf.train.GradientDescentOptimizer(1e-3).minimize(objective) |
| 83 | |
| 84 | # build the cost |
| 85 | # we won't use this to optimize the model parameters |
| 86 | # just to observe what happens during training |
| 87 | logits = self.forward_logits(X) |
| 88 | self.cost = tf.reduce_mean( |
| 89 | input_tensor=tf.nn.softmax_cross_entropy_with_logits( |
| 90 | labels=tf.stop_gradient(X), |
| 91 | logits=logits, |
| 92 | ) |
| 93 | ) |
| 94 | |
| 95 | # to get the output |
| 96 | self.output_visible = self.forward_output(X) |
| 97 | |
| 98 | |
| 99 | # for calculating SSE |
no test coverage detected