Я целый день пытаюсь понять следующий код, для меня это не имеет особого смысла.
Может кто-нибудь просветить меня, что он делает?
Некоторый контекст:
Нам присваиваются рейтинговые записи вида (user-id, item-id, rating)
.
и для каждой записи (позитивной записи), мы пытаемся захватить
несколько (четыре) отрицательных элемента (в том смысле, что пользователь не оценил).
И приведенный ниже код должен работать picking the negative items
, но ничего себе, за ним трудно следовать :( И комментарии не сильно помогают ...
Самая запутанная часть - self._total_negatives
и left_index = self.index_bounds[negative_users]
class BisectionDataConstructor(BaseDataConstructor):
"""Use bisection to index within positive examples.
This class tallies the number of negative items which appear before each
positive item for a user. This means that in order to select the ith negative
item for a user, it only needs to determine which two positive items bound
it at which point the item id for the ith negative is a simply algebraic
expression.
"""
def _index_segment(self, user):
lower, upper = self.index_bounds[user:user+2]
items = self._sorted_train_pos_items[lower:upper]
negatives_since_last_positive = np.concatenate(
[items[0][np.newaxis], items[1:] - items[:-1] - 1])
return np.cumsum(negatives_since_last_positive)
def construct_lookup_variables(self):
inner_bounds = np.argwhere(self._train_pos_users[1:] -
self._train_pos_users[:-1])[:, 0] + 1
(upper_bound,) = self._train_pos_users.shape
self.index_bounds = np.array([0] + inner_bounds.tolist() + [upper_bound])
# Later logic will assume that the users are in sequential ascending order.
assert np.array_equal(self._train_pos_users[self.index_bounds[:-1]],
np.arange(self._num_users))
self._sorted_train_pos_items = self._train_pos_items.copy()
for i in range(self._num_users):
lower, upper = self.index_bounds[i:i+2]
self._sorted_train_pos_items[lower:upper].sort()
self._total_negatives = np.concatenate([
self._index_segment(i) for i in range(self._num_users)])
def lookup_negative_items(self, negative_users, **kwargs):
output = np.zeros(shape=negative_users.shape, dtype=rconst.ITEM_DTYPE) - 1
left_index = self.index_bounds[negative_users]
right_index = self.index_bounds[negative_users + 1] - 1
num_positives = right_index - left_index + 1
num_negatives = self._num_items - num_positives
neg_item_choice = stat_utils.very_slightly_biased_randint(num_negatives)
use_shortcut = neg_item_choice >= self._total_negatives[right_index]
output[use_shortcut] = (
self._sorted_train_pos_items[right_index] + 1 +
(neg_item_choice - self._total_negatives[right_index])
)[use_shortcut]
if np.all(use_shortcut):
# The bisection code is ill-posed when there are no elements.
return output
Это от https://github.com/tensorflow/models/blob/master/official/recommendation/data_pipeline.py
when train_pos_users = np.array(
[0,0, 1,1,1, 2,2,2, 3,3,3,3,3,3, 4,4])
self.index_bounds = array([ 0, 2, 5, 8, 14, 16])
Если вам это прилично знакомо, если где-то в сети есть описание того, что он делает, я мог бы очень сильно использовать его, чтобы понять, что он делает .. Я попытался поискать bisection negative sampling
, но ничего не получается ..
Таким образом, разделение пополам означает половину, что-то близкое к двоичному поиску
Я думаю, что код не делает то, что должен, и оставил проблему с github ..
https://github.com/tensorflow/models/issues/6441