def select_side(hyperplane, offset, point, rng_state): margin = offset for d in range(point.shape[0]): margin += hyperplane[d] * point[d] if abs(margin) < EPS: side = abs(tau_rand_int(rng_state)) % 2 if side == 0: return 0 else: return 1 elif margin > 0: return 0 else: return 1
def sparse_select_side(hyperplane, offset, point_inds, point_data, rng_state): margin = offset hyperplane_inds = arr_unique(hyperplane[0]) hyperplane_data = hyperplane[1, :hyperplane_inds.shape[0]] aux_inds, aux_data = sparse_mul(hyperplane_inds, hyperplane_data, point_inds, point_data) for d in range(aux_data.shape[0]): margin += aux_data[d] if margin == 0: side = abs(tau_rand_int(rng_state)) % 2 if side == 0: return 0 else: return 1 elif margin > 0: return 0 else: return 1
def _nn_layout_optimize_single_epoch( head_embedding, tail_embedding, head, tail, hub_info, n_vertices, epochs_per_sample, a, b, rng_state, gamma, dim, move_other, alpha, epochs_per_negative_sample, epoch_of_next_negative_sample, epoch_of_next_sample, n, ): for i in numba.prange(epochs_per_sample.shape[0]): if epoch_of_next_sample[i] <= n: j = head[i] # j == source index k = tail[i] # k == target index current = head_embedding[j] # current == source location other = tail_embedding[k] # other == target location dist_squared = rdist(current, other) # get distance between them if dist_squared > 0.0: grad_coeff = -2.0 * a * b * pow(dist_squared, b - 1.0) grad_coeff /= a * pow(dist_squared, b) + 1.0 else: grad_coeff = 0.0 for d in range(dim): grad_d = clip(grad_coeff * (current[d] - other[d]), 10.0) grad_other = 1.0 if hub_info[k] == 2: grad_other = gamma current[d] += grad_d * alpha if move_other: # other[d] += -grad_d * alpha other[d] += -grad_d * alpha * grad_other epoch_of_next_sample[i] += epochs_per_sample[i] n_neg_samples = int( (n - epoch_of_next_negative_sample[i]) / epochs_per_negative_sample[i] ) for p in range(n_neg_samples): while True: k = tau_rand_int(rng_state) % n_vertices if hub_info[k] > 0: break other = tail_embedding[k] dist_squared = rdist(current, other) if dist_squared > 0.0: grad_coeff = 2.0 * b grad_coeff /= (0.001 + dist_squared) * ( a * pow(dist_squared, b) + 1 ) elif j == k: continue else: grad_coeff = 0.0 for d in range(dim): if grad_coeff > 0.0: grad_d = clip(grad_coeff * (current[d] - other[d]), 10.0) else: grad_d = 10.0 # current[d] += grad_d * alpha current[d] += grad_d * alpha * gamma epoch_of_next_negative_sample[i] += ( n_neg_samples * epochs_per_negative_sample[i] )
def angular_random_projection_split(data, indices, rng_state): """Given a set of ``indices`` for data points from ``data``, create a random hyperplane to split the data, returning two arrays indices that fall on either side of the hyperplane. This is the basis for a random projection tree, which simply uses this splitting recursively. This particular split uses cosine distance to determine the hyperplane and which side each data sample falls on. Parameters ---------- data: array of shape (n_samples, n_features) The original data to be split indices: array of shape (tree_node_size,) The indices of the elements in the ``data`` array that are to be split in the current operation. rng_state: array of int64, shape (3,) The internal state of the rng Returns ------- indices_left: array The elements of ``indices`` that fall on the "left" side of the random hyperplane. indices_right: array The elements of ``indices`` that fall on the "left" side of the random hyperplane. """ dim = data.shape[1] # Select two random points, set the hyperplane between them left_index = tau_rand_int(rng_state) % indices.shape[0] right_index = tau_rand_int(rng_state) % indices.shape[0] right_index += left_index == right_index right_index = right_index % indices.shape[0] left = indices[left_index] right = indices[right_index] left_norm = norm(data[left]) right_norm = norm(data[right]) if abs(left_norm) < EPS: left_norm = 1.0 if abs(right_norm) < EPS: right_norm = 1.0 # Compute the normal vector to the hyperplane (the vector between # the two points) hyperplane_vector = np.empty(dim, dtype=np.float32) for d in range(dim): hyperplane_vector[d] = (data[left, d] / left_norm) - (data[right, d] / right_norm) hyperplane_norm = norm(hyperplane_vector) if abs(hyperplane_norm) < EPS: hyperplane_norm = 1.0 for d in range(dim): hyperplane_vector[d] = hyperplane_vector[d] / hyperplane_norm # For each point compute the margin (project into normal vector) # If we are on lower side of the hyperplane put in one pile, otherwise # put it in the other pile (if we hit hyperplane on the nose, flip a coin) n_left = 0 n_right = 0 side = np.empty(indices.shape[0], np.int8) for i in range(indices.shape[0]): margin = 0.0 for d in range(dim): margin += hyperplane_vector[d] * data[indices[i], d] if abs(margin) < EPS: side[i] = abs(tau_rand_int(rng_state)) % 2 if side[i] == 0: n_left += 1 else: n_right += 1 elif margin > 0: side[i] = 0 n_left += 1 else: side[i] = 1 n_right += 1 # Now that we have the counts allocate arrays indices_left = np.empty(n_left, dtype=np.int64) indices_right = np.empty(n_right, dtype=np.int64) # Populate the arrays with indices according to which side they fell on n_left = 0 n_right = 0 for i in range(side.shape[0]): if side[i] == 0: indices_left[n_left] = indices[i] n_left += 1 else: indices_right[n_right] = indices[i] n_right += 1 return indices_left, indices_right, hyperplane_vector, None
def sparse_euclidean_random_projection_split(inds, indptr, data, indices, rng_state): """Given a set of ``indices`` for data points from a sparse data set presented in csr sparse format as inds, indptr and data, create a random hyperplane to split the data, returning two arrays indices that fall on either side of the hyperplane. This is the basis for a random projection tree, which simply uses this splitting recursively. This particular split uses cosine distance to determine the hyperplane and which side each data sample falls on. Parameters ---------- inds: array CSR format index array of the matrix indptr: array CSR format index pointer array of the matrix data: array CSR format data array of the matrix indices: array of shape (tree_node_size,) The indices of the elements in the ``data`` array that are to be split in the current operation. rng_state: array of int64, shape (3,) The internal state of the rng Returns ------- indices_left: array The elements of ``indices`` that fall on the "left" side of the random hyperplane. indices_right: array The elements of ``indices`` that fall on the "left" side of the random hyperplane. """ # Select two random points, set the hyperplane between them left_index = tau_rand_int(rng_state) % indices.shape[0] right_index = tau_rand_int(rng_state) % indices.shape[0] right_index += left_index == right_index right_index = right_index % indices.shape[0] left = indices[left_index] right = indices[right_index] left_inds = inds[indptr[left]:indptr[left + 1]] left_data = data[indptr[left]:indptr[left + 1]] right_inds = inds[indptr[right]:indptr[right + 1]] right_data = data[indptr[right]:indptr[right + 1]] # Compute the normal vector to the hyperplane (the vector between # the two points) and the offset from the origin hyperplane_offset = 0.0 hyperplane_inds, hyperplane_data = sparse_diff(left_inds, left_data, right_inds, right_data) offset_inds, offset_data = sparse_sum(left_inds, left_data, right_inds, right_data) offset_data = offset_data / 2.0 offset_inds, offset_data = sparse_mul(hyperplane_inds, hyperplane_data, offset_inds, offset_data) for d in range(offset_data.shape[0]): hyperplane_offset -= offset_data[d] # For each point compute the margin (project into normal vector, add offset) # If we are on lower side of the hyperplane put in one pile, otherwise # put it in the other pile (if we hit hyperplane on the nose, flip a coin) n_left = 0 n_right = 0 side = np.empty(indices.shape[0], np.int8) for i in range(indices.shape[0]): margin = hyperplane_offset i_inds = inds[indptr[indices[i]]:indptr[indices[i] + 1]] i_data = data[indptr[indices[i]]:indptr[indices[i] + 1]] mul_inds, mul_data = sparse_mul(hyperplane_inds, hyperplane_data, i_inds, i_data) for d in range(mul_data.shape[0]): margin += mul_data[d] if abs(margin) < EPS: side[i] = abs(tau_rand_int(rng_state)) % 2 if side[i] == 0: n_left += 1 else: n_right += 1 elif margin > 0: side[i] = 0 n_left += 1 else: side[i] = 1 n_right += 1 # Now that we have the counts allocate arrays indices_left = np.empty(n_left, dtype=np.int64) indices_right = np.empty(n_right, dtype=np.int64) # Populate the arrays with indices according to which side they fell on n_left = 0 n_right = 0 for i in range(side.shape[0]): if side[i] == 0: indices_left[n_left] = indices[i] n_left += 1 else: indices_right[n_right] = indices[i] n_right += 1 hyperplane = np.vstack((hyperplane_inds, hyperplane_data)) return indices_left, indices_right, hyperplane, hyperplane_offset