give detailed explanation of the steps for the code given below:

# https://udemy.com/recommender-systems
# https://deeplearningcourses.com/recommender-systems
from \_\_future\_\_ import print\_function, division
from builtins import range
# Note: you may need to update your version of future
# sudo pip install -U future

import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from sklearn.utils import shuffle

import pandas as pd
from scipy.sparse import lil\_matrix, csr\_matrix, save\_npz, load\_npz
from datetime import datetime

if tf.\_\_version\_\_.startswith('2'):
 tf.compat.v1.disable\_eager\_execution()
def dot1(V, W):
 # V is N x D x K (batch of visible units)
 # W is D x K x M (weights)
 # returns N x M (hidden layer size)
 return tf.tensordot(V, W, axes=[[1,2], [0,1]])

def dot2(H, W):
 # H is N x M (batch of hiddens)
 # W is D x K x M (weights transposed)
 # returns N x D x K (visible)
 return tf.tensordot(H, W, axes=[[1], [2]])
class RBM(object):
 def \_\_init\_\_(self, D, M, K):
 self.D = D # input feature size
 self.M = M # hidden size
 self.K = K # number of ratings
 self.build(D, M, K)
 def build(self, D, M, K):
 # params
 self.W = tf.Variable(tf.random.normal(shape=(D, K, M)) \* np.sqrt(2.0 / M))
 self.c = tf.Variable(np.zeros(M).astype(np.float32))
 self.b = tf.Variable(np.zeros((D, K)).astype(np.float32))

 # data
 self.X\_in = tf.compat.v1.placeholder(tf.float32, shape=(None, D))

 # one hot encode X
 # first, make each rating an int
 X = tf.cast(self.X\_in \* 2 - 1, tf.int32)
 X = tf.one\_hot(X, K)

 # conditional probabilities
 # NOTE: tf.contrib.distributions.Bernoulli API has changed in Tensorflow v1.2
 V = X
 p\_h\_given\_v = tf.nn.sigmoid(dot1(V, self.W) + self.c)
 self.p\_h\_given\_v = p\_h\_given\_v # save for later

 # draw a sample from p(h | v)
 r = tf.random.uniform(shape=tf.shape(input=p\_h\_given\_v))
 H = tf.cast(r < p\_h\_given\_v, dtype=tf.float32)

 # draw a sample from p(v | h)
 # note: we don't have to actually do the softmax
 logits = dot2(H, self.W) + self.b
 cdist = tf.compat.v1.distributions.Categorical(logits=logits)
 X\_sample = cdist.sample() # shape is (N, D)
 X\_sample = tf.one\_hot(X\_sample, depth=K) # turn it into (N, D, K)

 # mask X\_sample to remove missing ratings
 mask2d = tf.cast(self.X\_in > 0, tf.float32)
 mask3d = tf.stack([mask2d]\*K, axis=-1) # repeat K times in last dimension
 X\_sample = X\_sample \* mask3d
 # build the objective
 objective = tf.reduce\_mean(input\_tensor=self.free\_energy(X)) - tf.reduce\_mean(input\_tensor=self.free\_energy(X\_sample))
 self.train\_op = tf.compat.v1.train.AdamOptimizer(1e-2).minimize(objective)
 # self.train\_op = tf.train.GradientDescentOptimizer(1e-3).minimize(objective)

 # build the cost
 # we won't use this to optimize the model parameters
 # just to observe what happens during training
 logits = self.forward\_logits(X)
 self.cost = tf.reduce\_mean(
 input\_tensor=tf.nn.softmax\_cross\_entropy\_with\_logits(
 labels=tf.stop\_gradient(X),
 logits=logits,
 )
 )

 # to get the output
 self.output\_visible = self.forward\_output(X)
 # for calculating SSE
 self.one\_to\_ten = tf.constant((np.arange(10) + 1).astype(np.float32) / 2)
 self.pred = tf.tensordot(self.output\_visible, self.one\_to\_ten, axes=[[2], [0]])
 mask = tf.cast(self.X\_in > 0, tf.float32)
 se = mask \* (self.X\_in - self.pred) \* (self.X\_in - self.pred)
 self.sse = tf.reduce\_sum(input\_tensor=se)

 # test SSE
 self.X\_test = tf.compat.v1.placeholder(tf.float32, shape=(None, D))
 mask = tf.cast(self.X\_test > 0, tf.float32)
 tse = mask \* (self.X\_test - self.pred) \* (self.X\_test - self.pred)
 self.tsse = tf.reduce\_sum(input\_tensor=tse)
 initop = tf.compat.v1.global\_variables\_initializer()
 self.session = tf.compat.v1.Session()
 self.session.run(initop)

 def fit(self, X, X\_test, epochs=10, batch\_sz=256, show\_fig=True):
 N, D = X.shape
 n\_batches = N // batch\_sz
 costs = []
 test\_costs = []
 for i in range(epochs):
 t0 = datetime.now()
 print("epoch:", i)
 X, X\_test = shuffle(X, X\_test) # everything has to be shuffled accordingly
 for j in range(n\_batches):
 x = X[j\*batch\_sz:(j\*batch\_sz + batch\_sz)].toarray()

 \_, c = self.session.run(
 (self.train\_op, self.cost),
 feed\_dict={self.X\_in: x}
 )

 if j % 100 == 0:
 print("j / n\_batches:", j, "/", n\_batches, "cost:", c)
 print("duration:", datetime.now() - t0)

 # calculate the true train and test cost
 t0 = datetime.now()
 sse = 0
 test\_sse = 0
 n = 0
 test\_n = 0
 for j in range(n\_batches):
 x = X[j\*batch\_sz:(j\*batch\_sz + batch\_sz)].toarray()
 xt = X\_test[j\*batch\_sz:(j\*batch\_sz + batch\_sz)].toarray()

 # number of train ratings
 n += np.count\_nonzero(x)

 # number of test ratings
 test\_n += np.count\_nonzero(xt)

 # use tensorflow to get SSEs
 sse\_j, tsse\_j = self.get\_sse(x, xt)
 sse += sse\_j
 test\_sse += tsse\_j
 c = sse/n
 ct = test\_sse/test\_n
 print("train mse:", c)
 print("test mse:", ct)
 print("calculate cost duration:", datetime.now() - t0)
 costs.append(c)
 test\_costs.append(ct)
 if show\_fig:
 plt.plot(costs, label='train mse')
 plt.plot(test\_costs, label='test mse')
 plt.legend()
 plt.show()

 def free\_energy(self, V):
 first\_term = -tf.reduce\_sum(input\_tensor=dot1(V, self.b))
 second\_term = -tf.reduce\_sum(
 # tf.log(1 + tf.exp(tf.matmul(V, self.W) + self.c)),
 input\_tensor=tf.nn.softplus(dot1(V, self.W) + self.c),
 axis=1
 )
 return first\_term + second\_term

 def forward\_hidden(self, X):
 return tf.nn.sigmoid(dot1(X, self.W) + self.c)

 def forward\_logits(self, X):
 Z = self.forward\_hidden(X)
 return dot2(Z, self.W) + self.b

 def forward\_output(self, X):
 return tf.nn.softmax(self.forward\_logits(X))

 def transform(self, X):
 # accepts and returns a real numpy array
 # unlike forward\_hidden and forward\_output
 # which deal with tensorflow variables
 return self.session.run(self.p\_h\_given\_v, feed\_dict={self.X\_in: X})

 def get\_visible(self, X):
 return self.session.run(self.output\_visible, feed\_dict={self.X\_in: X})

 def get\_sse(self, X, Xt):
 return self.session.run(
 (self.sse, self.tsse),
 feed\_dict={
 self.X\_in: X,
 self.X\_test: Xt,
 })

def main():
 A = load\_npz("Atrain.npz")
 A\_test = load\_npz("Atest.npz")

 N, M = A.shape
 rbm = RBM(M, 50, 10)
 rbm.fit(A, A\_test)
if \_\_name\_\_ == '\_\_main\_\_':
 main()
아래 코드의 단계에 대한 자세한 설명을 제공합니다:# https://udemy.com/recommender-systems# https://deeplearningcourses.com/recommender-systemsfrom \_\_future\_\_ import print\_function, division내장된 가져오기 범위에서# 참고: 사용 중인 future 버전을 업데이트해야 할 수 있습니다.# sudo pip install -U futurenumpy를 np로 임포트텐서플로우를 tf로 가져옵니다.matplotlib.pyplot을 plt로 가져옵니다.sklearn.utils에서 shuffle을 가져옵니다.팬더를 pd로 가져옵니다.scipy.sparse에서 lil\_matrix, csr\_matrix, save\_npz, load\_npz를 가져옵니다.from datetime import datetimeif tf.\_\_version\_\_.startswith('2'): tf.compat.v1.disable\_eager\_execution()def dot1(V, W): # V는 N x D x K(보이는 단위의 배치) # W는 D x K x M(가중치) # 반환값은 N x M(숨김 레이어 크기) return tf.tensordot(V, W, axes=[[1,2], [0,1]])def dot2(H, W): # H는 N x M (숨김의 배치) # W는 D x K x M (가중치 전치) # 반환값은 N x D x K (표시) return tf.tensordot(H, W, axes=[[1], [2]])class RBM(object): def \_\_init\_\_(self, D, M, K): self.D = D # 입력 피처 크기 self.M = M # 숨겨진 크기 self.K = K # 등급 수 self.build(D, M, K) def build(self, D, M, K): # 파라미터 self.W = tf.Variable(tf.random.normal(shape=(D, K, M)) \* np.sqrt(2.0 / M)) self.c = tf.Variable(np.zeros(M).astype(np.float32)) self.b = tf.Variable(np.zeros((D, K)).astype(np.float32)) # 데이터 self.X\_in = tf.compat.v1.placeholder(tf.float32, shape=(None, D)) # 하나의 핫 인코딩 X # 먼저, 각 등급을 정수로 만듭니다. X = tf.cast(self.X\_in \* 2 - 1, tf.int32) X = tf.one\_hot(X, K) # 조건부 확률 # 참고: Tensorflow v1.2에서 tf.contrib.distributions.Bernoulli API가 변경되었습니다. V = X p\_h\_given\_v = tf.nn.sigmoid(dot1(V, self.W) + self.c) self.p\_h\_given\_v = p\_h\_given\_v # 나중에 사용하기 위해 저장합니다. # p(h | v)에서 샘플을 추출합니다. r = tf.random.uniform(shape=tf.shape(input=p\_h\_given\_v)) H = tf.cast(r < p\_h\_given\_v, dtype=tf.float32) # p(v | h)에서 샘플을 추출합니다. # 참고: 실제로 소프트맥스를 수행할 필요는 없습니다. logits = dot2(H, self.W) + self.b cdist = tf.compat.v1.distributions.Categorical(logits=logits) X\_sample = cdist.sample() # 모양은 (N, D) X\_sample = tf.one\_hot(X\_sample, depth=K) # (N, D, K)로 변환합니다. # X\_sample을 마스킹하여 누락된 등급을 제거합니다. mask2d = tf.cast(self.X\_in > 0, tf.float32) mask3d = tf.stack([mask2d]\*K, axis=-1) # 마지막 차원에서 K회 반복 X\_sample = X\_sample \* mask3d # 목표 구축 objective = tf.reduce\_mean(input\_tensor=self.free\_energy(X)) - tf.reduce\_mean(input\_tensor=self.free\_energy(X\_sample)) self.train\_op = tf.compat.v1.train.AdamOptimizer(1e-2).minimize(objective) # self.train\_op = tf.train.GradientDescentOptimizer(1e-3).minimize(objective) # 비용 구축 # 모델 파라미터를 최적화하는 데는 사용하지 않습니다. # 훈련 중에 어떤 일이 일어나는지 관찰하기 위해서만 사용합니다. logits = self.forward\_logits(X) self.cost = tf.reduce\_mean( input\_tensor=tf.nn.softmax\_cross\_entropy\_with\_logits( labels=tf.stop\_gradient(X), logits=logits, ) ) # 출력을 얻으려면 self.output\_visible = self.forward\_output(X) # SSE 계산용 self.one\_to\_ten = tf.constant((np.arange(10) + 1).astype(np.float32) / 2) self.pred = tf.tensordot(self.output\_visible, self.one\_to\_ten, axes=[[2], [0]]) mask = tf.cast(self.X\_in > 0, tf.float32) se = mask \* (self.X\_in - self.pred) \* (self.X\_in - self.pred) self.sse = tf.reduce\_sum(input\_tensor=se) # SSE 테스트 self.X\_test = tf.compat.v1.placeholder(tf.float32, shape=(None, D)) mask = tf.cast(self.X\_test > 0, tf.float32) tse = 마스크 \* (self.X\_test - self.pred) \* (self.X\_test - self.pred) self.tsse = tf.reduce\_sum(input\_tensor=tse) initop = tf.compat.v1.global\_변수\_이니셜라이저() self.session = tf.compat.v1.Session() self.session.run(initop) def fit(self, X, X\_test, epochs=10, batch\_sz=256, show\_fig=True): N, D = X.모양 n\_batches = N // batch\_sz costs = [] test\_costs = [] for i in range(epochs): t0 = datetime.now() print("epoch:", i) X, X\_test = shuffle(X, X\_test) # 모든 것이 적절하게 섞여 있어야 합니다. for j in range(n\_batches): x = X[j\*batch\_sz:(j\*batch\_sz + batch\_sz)].toarray() \_, c = self.session.run( (self.train\_op, self.cost), feed\_dict={self.X\_in: x} ) if j % 100 == 0: print("j / n\_배치:", j, "/", n\_배치, "cost:", c) print("duration:", datetime.now() - t0) # 실제 훈련 및 테스트 비용 계산 t0 = datetime.now() sse = 0 test\_sse = 0 n = 0 test\_n = 0 범위(n\_배치)의 j에 대해: x = X[j\*batch\_sz:(j\*batch\_sz + batch\_sz)].toarray() xt = X\_test[j\*batch\_sz:(j\*batch\_sz + batch\_sz)].toarray() # 열차 등급 수 n += np.count\_nonzero(x) # 테스트 등급 수 test\_n += np.count\_nonzero(xt) # 텐서플로우를 사용하여 SSE 가져오기 SSE\_J, TSSE\_J = self.get\_sse(x, xt) sse += sse\_j test\_sse += tsse\_j c = SSE/N ct = test\_sse/test\_n print("train mse:", c) print("test mse:", ct) print("계산 비용 기간: