基于图的去中心化社会推荐过滤器

news2024/12/28 8:29:02

🏡作者主页:点击! 

🤖编程探索专栏:点击!

⏰️创作时间:2024年11月11日19点20分

点击开启你的论文编程之旅icon-default.png?t=O83Ahttps://www.aspiringcode.com/content?id=17176636216843&uid=eba758a1550b46bb94314cb8eeea8c3f

原论文研究背景与研究意义概述


这篇论文由中国科学技术大学团队于2023年发表在TKDE期刊上,主要研究领域是基于用户-用户和用户-事件社会关系的推荐生成。由于这些社会关系可以轻松地用图结构数据来表示,因此图神经网络在这一领域具有很大的发展潜力。然而,现有的基于图的算法在处理数据时往往忽略了用户或事件的偏好偏移量。作者给出的一个示例说明了这种偏移量的重要性:挑剔的用户给出的低评分并不一定意味着他们对产品的态度是消极的,因为这些用户通常会给出低评分,这可能会导致图结构数据分析产生误差。现有的方法通常将这种偏差作为标量融入模型训练中,但作者认为这种做法不足以捕捉所有相关信息。此外,作者指出,用户之间的社会联系也应被考虑在内,因为具有相似偏好的用户往往会对彼此产生更大的影响。基于此,作者提出了一种新的算法来解决这些问题。

论文所提出算法的主要贡献

这篇文章的主要贡献包括:
首先,作者将评价偏移量处理为向量,并将其融入到用户和事件的表征学习中。具体做法是计算用户与其他用户的评价差异向量,从而获得每个用户的评价偏移。具体做法是,他们对原始图进行去中心化处理,然后从中学习到用户和事件的表征。去中心化的图是基于原始图中的统计信息生成的。

接着,作者提出了一种用户-用户之间社会关系的建模方式,并将其融入到预测规则中,以提高推荐表现。

然后,基于去中心化图,他们提出了一种基于图神经网络(GNN)的社会推荐协同过滤模型。

最后,作者在两个数据集上验证了所提出算法的有效性,证明了其在处理用户偏好偏移量和社会关系建模方面的优势。

原论文中采用了大量的数学公式来表示算法过程,这里笔者认为实际上读起来有点费力,所以本文主要从感性的角度来对这篇论文进行讲解,尽量少用公式而是用文字描述来给大家建立一个感性的理解。

GDSRec算法原理与流程


问题定义


原文采用的建图方式是将用户和事件作为节点,用户-事件之间的连线权重为关系系数Tij,用于衡量两个用户的相似度。

关系系数的计算方式可以看作是设定一个阈值,当两个用户对同一个事件的评分差距在阈值之内时,就将相似度加一,累加起来就是两个用户的相似度,这里称为关系系数。而用户-事件连线的权重为用户对事件的评分。然而,作者指出,直接使用这种原始图会带来一些不足,也就是无法准确反映真正的用户偏好。这是因为用户对事件的评分可能受到不同用户的打分标准的影响,从而导致误解用户的真实偏好。因此,作者对图结构进行了去中心化处理,以更好地捕捉用户的真实偏好。

去中心化图(decentralized graph)


去中心化图有三种不同的边:用户-事件、事件-用户、用户-用户。对于每个用户-事件交互的边,用原始权重减去所有权重的平均值得到新的权重,而用户-用户连线的权重保持不变。通过这种方式,作者将统计信息融入到图中。接下来,作者针对这种去中心化图进行了对用户、事件、社会联系三种方向的建模,从而计算出三种潜在因素偏移量。依据这些偏移量,可以计算出最终用户ui和事件vj的最终偏好评分,即:

所提出方法(三种并行建模)

用户建模(user modelling)

然后我们具体介绍一下作者提出的三种建模方式。我们以用户建模(user modeling)为例,期望得到的输出是潜在因素偏移量hui。整个流程可以用上面的公式表示,我们可以逐步拆分这个过程。

首先,需要提到的是,在这个过程中使用的用户-事件交互权重都是进行取整后的。原文指出,使用小数进行embedding不太方便,但同时也提到一些量化方法可以解决这个问题,他们将这部分留作未来工作。前面提到,这篇文章的一大贡献是将评价偏移量处理为向量。

具体做法是将事件𝑣𝑙vl

用户-事件交互的权重进行embedding后的表征进行拼接,然后通过一个多层感知机进行处理,从而融入到学习过程中。𝑞,𝑠qs分别是事件𝑢u和社会关联𝑟r的表征,𝐿𝑈LU是多层感知机,这种方法可以将该向量融入用户表征的学习过程中

同时,作者指出,一个用户和相关联事件之间的每个关联对用户潜在因素的影响贡献是不同的。因此,他们采用了注意力机制来捕捉用户偏好中的差异。公式8中𝑥x前面乘的系数实际上是注意力权重。需要注意的是,在输入注意力网络时,他们将前面的评价偏移向量与用户的embedding向量进行了拼接,然后通过一个两层神经网络进行处理。通过这一流程,就可以得到用户的潜在因素偏移量hui。

事件建模(item modeling)和社会关系建模(social modeling)的处理方式与用户建模类似。三种建模处理后,我们可以得到三种潜在因素偏移量。基于此,偏好评分可以通过三层神经网络获得,用公式9,10,11表示。这个偏好评分可以理解为包括用户自己的意见和对其社会关联用户评级的参考。对于用户ui的社会关联用户,我们可以用相同的方式得到他们的偏好评分,从而得到方程f的返回值,计算方式如公式12。

最终,我们回到前面公式4就可以计算出用户ui和事件vj之间的最终评分。以这种方式就可以实现对用户更全面偏好信息的捕获,以及考虑到有着更强社会关联的用户对用户ui的影响。

模版代码讲解


main.py顶层文件:用于集成模与函数功能

main.py文件在这里仍然是起到一个调用模型和所有函数进行数据输入、处理、训练、结果输出的功能,值得注意的是这里原文作者使用了config参数定义的方式,让整个工程看起来更加简洁、标准

import os
os.environ['KMP_DUPLICATE_LIB_OK'] = 'TRUE'
import pickle
import torch
from torch.utils.data import DataLoader
from utils import collate_fn
from model.GDSRec_model import GDSRec_Engine


config = {
    'model': 'GDSRec', 
    'dataset': 'Ciao',  # Ciao/Epinions
    'optimizer': 'adam',
    'l2_regularization': 0.01,
    'embed_size': 64,
    'batch_size': 128,
    'layers': [256,128,128,64,64],
    'epoch': 20,
    'lr': 0.0005,  # 0.01, 0.001, 0.0001
    'lr_dc': 0.1,  # learning rate decay
    'lr_dc_step': 100,  # the number steps for decay
    'test':False,
    'model_dir': 'checkpoints/{}_{}_best_checkpoint.model'
}
print(config)
here = os.path.dirname(os.path.abspath(__file__))
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)
config['device'] = device
workdir = 'C:/Users/meicr/Desktop/GDSRec_rank/data/'
with open(workdir + config['dataset'] + '/' + config['model'] + '_dataset.pkl', 'rb') as f:
    train_dataset, evaluate_dataset, test_dataset, user_count, item_count = pickle.loads(f.read())
config['num_users'] = user_count
config['num_items'] = item_count
config['num_rates'] = 5

if config['test'] is False:
    engine = GDSRec_Engine(config)
    train_loader = DataLoader(train_dataset, batch_size=config['batch_size'], shuffle=True, collate_fn=collate_fn)
    evaluate_loader = DataLoader(evaluate_dataset, batch_size=config['batch_size'], shuffle=False,
                                    collate_fn=collate_fn)
    index_sum = []
    for epoch in range(config['epoch']):
        print('Epoch {} starts !'.format(epoch))
        engine.train_an_epoch(train_loader, epoch)
        recall, ndcg = engine.evaluate(evaluate_loader, epoch)
        if epoch == 0:
            pre_sum = recall + ndcg
            index_sum.append(0)
        else:
            if recall + ndcg < pre_sum:
                index_sum.append(1)
            else:
                pre_sum = recall + ndcg
                index_sum.append(0)
        if sum(index_sum[-10:]) == 10:
            break
        if epoch == 0:
            best_sum = recall + ndcg
            engine.save()
        elif recall + ndcg > best_sum:
            best_sum = recall + ndcg
            engine.save()
else:
    engine = GDSRec_Engine(config)
    print('Load checkpoint and testing...')
    engine.resume()
    test_loader = DataLoader(test_dataset, batch_size=config['batch_size'], shuffle=True, collate_fn=collate_fn)
    recall, ndcg = engine.evaluate(test_loader, epoch_id=0)

preprocess.py:对输入数据进行预处理符合模型输入要求


这里preprocess.py文件的作用是对我们输入的数据进行了处理和分析得到模型可以处理的对象,主要包括格式转换、用户相似度计算之类的功能

"""
@author: Jiajia Chan
@date: 20 June, 2020
"""
import random
import argparse
import pickle
import pandas as pd
from scipy.io import loadmat
from rating_data import SingleGenerator
from trust_data import SocialGenerator

random.seed(1234)


if __name__ == '__main__':
    parser = argparse.ArgumentParser() 
    parser.add_argument('--dataset', default='Ciao', help='dataset name: Ciao/Epinions')
    parser.add_argument('--test_prop', default=0.2, help='the proportion of data used for test')
    args = parser.parse_args() 
    workdir = 'data/'

    click_f = loadmat(workdir + args.dataset + '/rating.mat')['rating']
    trust_f = loadmat(workdir + args.dataset + '/trustnetwork.mat')['trustnetwork']
    click_dt = pd.DataFrame(click_f)
    trust_dt = pd.DataFrame(trust_f, columns=['userID', 'freID'])
    click_dt = click_dt[[0, 1, 3]]
    click_dt.dropna(inplace=True)
    click_dt.drop_duplicates(inplace=True)
    click_dt.columns = ['userID', 'itemID', 'rating']
    trust_dt.dropna(inplace=True)
    trust_dt.drop_duplicates(inplace=True)

    single_generator = SingleGenerator(ratings=click_dt, prob=args.test_prop)
    social_generator = SocialGenerator(singlegenerator=single_generator, trust=trust_dt)
    GDSRec_dataset = social_generator.instance_GDSRec_dataset()
    general_dataset = single_generator.instance_general_dataset()
    with open(workdir + args.dataset +'/' + 'GDSRec' + '_dataset.pkl', 'wb') as f:
        str1 = pickle.dumps(GDSRec_dataset)
        f.write(str1)
        f.close()

model.py:GDSRec模型实现


这个文件里面存放的就是所提出方法和相关算法的所有实现,原理和流程就如上述介绍所示

from torch import nn
from torch.nn import init
import torch
import numpy as np

class _MultiLayerPercep(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(_MultiLayerPercep, self).__init__()
        self.mlp = nn.Sequential(
            nn.Linear(input_dim, input_dim // 2, bias=True),
            nn.ReLU(),
            nn.Linear(input_dim // 2, output_dim, bias=True),
        )

    def forward(self, x):
       return self.mlp(x)


class _MultiLayerPercep_tanh(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(_MultiLayerPercep_tanh, self).__init__()
        self.mlp = nn.Sequential(
            nn.Linear(input_dim, input_dim // 2, bias=True),
            nn.Tanh(),
            nn.Linear(input_dim // 2, output_dim, bias=True),
        )

    def forward(self, x):
       return self.mlp(x)


class _Aggregation(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(_Aggregation, self).__init__()
        self.aggre = nn.Sequential(
            nn.Linear(input_dim, output_dim, bias=True),
            nn.Tanh(),
        )

    def forward(self, x):
        return self.aggre(x)


class _UserModel(nn.Module):
    ''' User modeling to learn user latent factors.
    User modeling leverages two types aggregation: item aggregation and social aggregation
    '''

    def __init__(self, emb_dim, user_emb, item_emb, rate_emb):
        super(_UserModel, self).__init__()
        self.user_emb = user_emb
        self.item_emb = item_emb
        self.rate_emb = rate_emb
        self.emb_dim = emb_dim

        self.g_v = _MultiLayerPercep_tanh(2 * self.emb_dim, self.emb_dim)

        self.user_items_att = _MultiLayerPercep(2 * self.emb_dim, 1)
        self.aggre_items = _Aggregation(self.emb_dim, self.emb_dim)


        self.combine_mlp = nn.Sequential(
            nn.Linear(2 * self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
            nn.Linear(self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
            nn.Linear(self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
        )

        self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
        # used for preventing zero div error when calculating softmax score
        self.eps = 1e-10

    def forward(self, uids, u_item_pad):
        # item aggregation
        q_a = self.item_emb(u_item_pad[:, :, 0])  
        mask_u = torch.where(u_item_pad[:, :, 0] > 0, torch.tensor([1.], device=self.device),
                             torch.tensor([0.], device=self.device))  
        u_item_er = self.rate_emb(u_item_pad[:, :, 1])  

        x_ia = self.g_v(torch.cat([q_a, u_item_er], dim=2).view(-1, 2 * self.emb_dim)).view(
            q_a.size())  

        ## calculate attention scores in item aggregation
        p_i = mask_u.unsqueeze(2).expand_as(x_ia) * self.user_emb(uids).unsqueeze(1).expand_as(
            x_ia)  
        alpha = self.user_items_att(torch.cat([x_ia, p_i], dim=2).view(-1, 2 * self.emb_dim)).view(
            mask_u.size())  # B x maxi_len
        alpha = torch.exp(alpha) * mask_u
        alpha = alpha / (torch.sum(alpha, 1).unsqueeze(1).expand_as(alpha) + self.eps)

        h_iI = self.aggre_items(torch.sum(alpha.unsqueeze(2).expand_as(x_ia) * x_ia, 1))  # B x emb_dim

        return h_iI


class _ItemModel(nn.Module):
    '''Item modeling to learn item latent factors.
    '''

    def __init__(self, emb_dim, user_emb, item_emb, rate_emb):
        super(_ItemModel, self).__init__()
        self.emb_dim = emb_dim
        self.user_emb = user_emb
        self.item_emb = item_emb
        self.rate_emb = rate_emb

        self.g_u = _MultiLayerPercep_tanh(2 * self.emb_dim, self.emb_dim)

        self.item_users_att = _MultiLayerPercep(2 * self.emb_dim, 1)
        self.aggre_users = _Aggregation(self.emb_dim, self.emb_dim)

        self.combine_mlp = nn.Sequential(
            nn.Linear(2 * self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
            nn.Linear(self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
            nn.Linear(self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
        )

        self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
        self.eps = 1e-10

    def forward(self, iids, i_user_pad):
        # user aggregation
        p_t = self.user_emb(i_user_pad[:, :, 0])
        mask_i = torch.where(i_user_pad[:, :, 0] > 0, torch.tensor([1.], device=self.device),
                             torch.tensor([0.], device=self.device))
        i_user_er = self.rate_emb(i_user_pad[:, :, 1])

        f_jt = self.g_u(torch.cat([p_t, i_user_er], dim=2).view(-1, 2 * self.emb_dim)).view(p_t.size())

        # calculate attention scores in user aggregation
        q_j = mask_i.unsqueeze(2).expand_as(f_jt) * self.item_emb(iids).unsqueeze(1).expand_as(f_jt)

        miu = self.item_users_att(torch.cat([f_jt, q_j], dim=2).view(-1, 2 * self.emb_dim)).view(mask_i.size())
        miu = torch.exp(miu) * mask_i
        miu = miu / (torch.sum(miu, 1).unsqueeze(1).expand_as(miu) + self.eps)

        z_jU = self.aggre_users(torch.sum(miu.unsqueeze(2).expand_as(f_jt) * f_jt, 1))

        return z_jU


class _SocialModel(nn.Module):
    '''
    socialmodel to learn the rating for specific user exploiting social related users
    '''
    def __init__(self, emb_dim, user_emb, item_emb, rate_emb, sim_emb):
        super(_SocialModel, self).__init__()
        self.emb_dim = emb_dim
        self.user_emb = user_emb
        self.item_emb = item_emb
        self.rate_emb = rate_emb
        self.sim_emb = sim_emb
        self.g_v = _MultiLayerPercep_tanh(2 * self.emb_dim, self.emb_dim)

        self.user_items_att = _MultiLayerPercep(2 * self.emb_dim, 1)
        self.user_users_att = _MultiLayerPercep(2 * self.emb_dim, 1)
        self.aggre_items = _Aggregation(self.emb_dim, self.emb_dim)

        self.combine_mlp = nn.Sequential(
            nn.Linear(2 * self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
            nn.Linear(self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
            nn.Linear(self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
        )
        self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
        self.eps = 1e-10

    def forward(self, u_user_pad, u_user_item_pad):
        q_a_s = self.item_emb(u_user_item_pad[:, :, :, 0])  
        mask_s = torch.where(u_user_item_pad[:, :, :, 0] > 0, torch.tensor([1.], device=self.device),
                             torch.tensor([0.], device=self.device)) 
        u_user_item_er = self.rate_emb(u_user_item_pad[:, :, :, 1]) 

        x_ia_s = self.g_v(torch.cat([q_a_s, u_user_item_er], dim=3).view(-1, 2 * self.emb_dim)).view(
            q_a_s.size())  

        p_i_s = mask_s.unsqueeze(3).expand_as(x_ia_s) * self.user_emb(u_user_pad[:, :, 0]).unsqueeze(2).expand_as(
            x_ia_s)  

        alpha_s = self.user_items_att(torch.cat([x_ia_s, p_i_s], dim=3).view(-1, 2 * self.emb_dim)).view(
            mask_s.size())  
        alpha_s = torch.exp(alpha_s) * mask_s
        alpha_s = alpha_s / (torch.sum(alpha_s, 2).unsqueeze(2).expand_as(alpha_s) + self.eps)

        h_oI_temp = torch.sum(alpha_s.unsqueeze(3).expand_as(x_ia_s) * x_ia_s, 2) 
        h_oI = self.aggre_items(h_oI_temp.view(-1, self.emb_dim)).view(h_oI_temp.size())  

        return h_oI


class GDSRec(nn.Module):
    '''

    Args:
        number_users: the number of users in the dataset.
        number_items: the number of items in the dataset.
        num_rate_levels: the number of rate levels in the dataset.
        emb_dim: the dimension of user and item embedding (default = 64).

    '''

    def __init__(self, num_users, num_items, num_rate_levels, emb_dim=64):
        super(GDSRec, self).__init__()
        self.num_users = num_users
        self.num_items = num_items
        self.num_rate_levels = num_rate_levels
        self.emb_dim = emb_dim
        self.user_emb = nn.Embedding(self.num_users, self.emb_dim, padding_idx=0)
        self.item_emb = nn.Embedding(self.num_items, self.emb_dim, padding_idx=0)
        self.rate_emb = nn.Embedding(self.num_rate_levels, self.emb_dim, padding_idx=0)
        self.sim_dim = nn.Embedding(self.num_items, self.emb_dim, padding_idx=0)
        self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
        self.eps = 1e-10
        self.user_model = _UserModel(self.emb_dim, self.user_emb, self.item_emb, self.rate_emb)

        self.item_model = _ItemModel(self.emb_dim, self.user_emb, self.item_emb, self.rate_emb)

        self.social_model = _SocialModel(self.emb_dim, self.user_emb, self.item_emb, self.rate_emb, self.sim_dim)

        self.rate_pred = nn.Sequential(
            nn.Linear(2 * self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
            nn.Linear(self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
            nn.Linear(self.emb_dim, 1),
        )

    def forward(self, uids, iids, u_itemdiv_pad, u_avgs, u_user_pad, u_user_item_pad, i_user_pad, i_avgs):
        '''
        Args:
            uids: the user id sequences.
            iids: the item id sequences.
            u_itemdiv_pad: the padded user-item-div graph
            u_item_pad: the padded user-item graph.
            u_avgs: the avg rating of user
            u_user_pad: the padded user-user graph.
            u_user_item_pad: the padded user-user-item graph.
            i_user_pad: the padded item-user graph.
            i_avgs: the avg rating of item
        Shapes:
            uids: (B).
            iids: (B).
            u_item_pad: (B, ItemSeqMaxLen, 2).
            u_avgs: (B)
            u_user_pad: (B, UserSeqMaxLen).
            u_user_item_pad: (B, UserSeqMaxLen, truncate_len, 2).
            i_user_pad: (B, UserSeqMaxLen, 2).
            i_avgs: (B)
        Returns:
            the predicted rate scores of the user to the item.
        '''

        h_i = self.user_model(uids, u_itemdiv_pad)  
        z_j = self.item_model(iids, i_user_pad) 
        y_i = self.social_model(u_user_pad, u_user_item_pad) 
        mask = u_user_pad[:, :, 1].unsqueeze(2).float() 

        # make prediction
        r_ij_1 = self.rate_pred(torch.cat([h_i, z_j], dim=1))
        r_ij_2 = torch.sum(self.rate_pred(torch.cat([y_i, z_j.unsqueeze(1).expand_as(y_i)], dim=2)) * mask, dim=1)\
                 /(torch.sum(mask, dim=1) + self.eps)
        r_ij = 0.5 *(r_ij_1 + r_ij_2) + 0.5*(u_avgs.unsqueeze(1) + i_avgs.unsqueeze(1))

        return r_ij

本地部署方法


我们在github官方链接上只能找到一个数据集Ciao(原论文是在Ciao和Epinions上都进行了实验),我们需要将数据集整理成上述格式,这里可以打开看一下。整理的格式如右图所示,第一列是学生id, 第二列是问题id,第三列是无关变量原文代码中并没有用到,第四列是rating,trustnetwork.mat文件中保存的是学生与学生之间的关系网络。因此我们在进行本地私有数据集训练时也需要将数据处理成对应的格式

该篇论文作者在github上公布了源代码,但笔者下载下来实际运行了之后发现完全按照模版代码运行仍然会出现一些问题。研究之后发现可能是原作者在编写代码后改动了数据集目录格式,导致一些设定的环境路径参数错误。如果我们想要跑通代码或者在本地运行自己的数据集进行实验,还需要对相应的参数进行修改,修改后的代码我已经放在本文附件中了,并且在附件的压缩包内新增了一个Readme文件来提示大家如何修改数据集路径为自己的私有数据集

成功的路上没有捷径,只有不断的努力与坚持。如果你和我一样,坚信努力会带来回报,请关注我,点个赞,一起迎接更加美好的明天!你的支持是我继续前行的动力!"

"每一次创作都是一次学习的过程,文章中若有不足之处,还请大家多多包容。你的关注和点赞是对我最大的支持,也欢迎大家提出宝贵的意见和建议,让我不断进步。"

神秘泣男子

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2240979.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习模型评价指标介绍

模型评价指标 模型评价指标1.混淆矩阵2.Overall Accuracy3.Average accuracy4.Kappa系数5.Recall6.Precision7.F18.PR曲线9.置信度10.IOU11.AP12.mAP 模型评价指标 在我们学习机器学习以及深度学习&#xff0c;甚至在计算机视觉领域&#xff0c;我们不可避免的要利用一些指标评…

k8s 1.28.2 集群部署 docker registry 接入 MinIO 存储

文章目录 [toc]docker registry 部署生成 htpasswd 文件生成 secret 文件 生成 registry 配置文件创建 service创建 statefulset创建 ingress验证 docker registry docker registry 监控docker registry ui docker registry dockerfile docker registry 配置文件 S3 storage dr…

【自用】0-1背包问题与完全背包问题的Java实现

引言 背包问题是计算机科学领域的一个经典优化问题&#xff0c;分为多种类型&#xff0c;其中最常见的是0-1背包问题和完全背包问题。这两种问题的核心在于如何在有限的空间内最大化收益&#xff0c;但它们之间存在一些关键的区别&#xff1a;0-1背包问题允许每个物品只能选择…

Zookeeper的安装与使用

一、简介 1.1、概念 ZooKeeper 是一个开源的分布式协调服务&#xff0c;主要用于解决分布式系统中的数据一致性问题。它提供了一种可靠的机制来管理和协调分布式系统的各个节点。ZooKeeper 的设计目标是简化分布式应用的开发&#xff0c;提供简单易用的接口和高性能、高稳定性…

【模块一】kubernetes容器编排进阶实战之etcd的介绍与使用

etcd进阶 etcd简介&#xff1a;  etcd是CoreOS团队于2013年6月发起的开源项目&#xff0c;它的目标是构建一个高可用的分布式键值(key-value)数据库。etcd内部采用raft协议作为一致性算法&#xff0c;etcd基于Go语言实现。 官方网站&#xff1a;https://etcd.io/  gith…

【机器学习】如何配置anaconda环境(无脑版)

马上就要上机器学习的实验&#xff0c;这里想写一下我配置机器学习的anaconda环境的二三事 一、首先&#xff0c;下载安装包&#xff1a; Download Now | Anaconda 二、打开安装包&#xff0c;一直点NEXT进行安装 这里要记住你要下载安装的路径在哪&#xff0c;后续配置环境…

矩阵中的路径(dfs)-acwing

题目 23. 矩阵中的路径 - AcWing题库 代码 class Solution { public://以每一个坐标作为dfs起点bool hasPath(vector<vector<char>>& matrix, string str) {for (int i 0; i < matrix.size(); i )for (int j 0; j < matrix[i].size(); j )if (dfs(…

WEB攻防-通用漏洞SQL注入sqlmapOracleMongodbDB2等

SQL注入课程体系&#xff1a; 1、数据库注入-access mysql mssql oracle mongodb postgresql 2、数据类型注入-数字型 字符型 搜索型 加密型&#xff08;base64 json等&#xff09; 3、提交方式注入-get post cookie http头等 4、查询方式注入-查询 增加 删除 更新 堆叠等 …

android studio 更改gradle版本方法(备忘)

如果出现类似以下&#xff1a; Your build is currently configured to use Java 17.0.11 and Gradle 6.1.1. 或者类似&#xff1a; Failed to calculate the value of task ‘:app:compileDebugJavaWithJavac‘ property ‘options.generatedSo 消息时需要修改gradle版本&…

设计模式之装饰器模式(SSO单点登录功能扩展,增加拦截用户访问方法范围场景)

前言&#xff1a; 两个本想描述一样的意思的词&#xff0c;只因一字只差就让人觉得一个是好牛&#xff0c;一个好搞笑。往往我们去开发编程写代码时也经常将一些不恰当的用法用于业务需求实现中&#xff0c;但却不能意识到。一方面是由于编码不多缺少较大型项目的实践&#xff…

日志:中文 URI 参数乱码之 encodeURI、encodeURIComponent、escape 作为 Ajax 中文参数编码给 ASP 的记录

前面提到的了 ASP 输出 UTF-8 编码的中文不定时出现乱码的解决方案&#xff1a;ASP页面改为UTF-8编码后&#xff0c;刷新页面中文输入输出不定时乱码终极解决方案 今天遇到的则是输入 UTF-8 编码中文 URI 参数乱码的问题&#xff0c;第一次可以&#xff0c;刷新后取得的输入参…

Intern大模型训练营(八):Llamaindex RAG 实践

1. 基于 LlamaIndex 构建自己的 RAG 知识库 首先在Intern Studio中申请30% A100的开发机。 进入开发机后&#xff0c;创建新的conda环境&#xff0c;命名为 llamaindex&#xff0c;在命令行模式下运行&#xff1a; conda create -n llamaindex python3.10 复制完成后&#…

leetcode104:二叉树的最大深度

给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3示例 2&#xff1a; 输入&#xff1a;root [1,null,2] 输出…

Unity插件-Smart Inspector 免费的,接近虚幻引擎的蓝图Tab管理

习惯了虚幻的一张蓝图&#xff0c;关联所有Tab &#xff08;才发现Unity&#xff0c;的Component一直被人吐槽&#xff0c;但实际上是&#xff1a;本身结构Unity 的GameObject-Comp结构&#xff0c;是好的不能再好了&#xff0c;只是配上 smart Inspector就更清晰了&#xff0…

RDIFramework.NET CS敏捷开发框架 V6.1发布(.NET6+、Framework双引擎、全网唯一)

RDIFramework.NET C/S敏捷开发框架V6.1版本迎来重大更新与调整&#xff0c;全面重新设计业务逻辑代码&#xff0c;代码量减少一半以上&#xff0c;开发更加高效。全系统引入全新字体图标&#xff0c;整个界面焕然一新。底层引入最易上手的ORM框架SqlSugar&#xff0c;让开发更加…

运行springBlade项目历程

框架选择 官网地址&#xff1a;https://bladex.cn 使用手册&#xff1a;https://www.kancloud.cn/smallchill/blade 常见问题&#xff1a;https://sns.bladex.cn/article-14966.html 问答社区&#xff1a;https://sns.bladex.cn 环境配置 存在jdk8的情况下安装jdk17 jdk17gi…

图形 2.7 LDR与HDR

LDR与HDR B站视频&#xff1a;图形 2.7 LDR与HDR 文章目录 LDR与HDR基本概念LDRHDR为什么需要HDR不同显示屏的差异 Unity中的HDRCamera HDR 设置Lightmap HDR设置拾色器 HDR设置优缺点 HDR与Bloom通常Bloom渲染步骤渲染出原图获取图像中较亮部分高斯模糊叠加 Unity中Bloom渲染…

单片机设计智能翻译手势识别系统

目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 电路图采用Altium Designer进行设计&#xff1a; 三、实物设计图 四、程序源代码设计 五、获取资料内容 前言 在全球化的浪潮下&#xff0c;语言的多样性也为人们的交流带来了不小的挑战…

Python调用API翻译Excel中的英语句子并回填数据

一、问题描述 最近遇到一个把Excel表中两列单元格中的文本读取&#xff0c;然后翻译&#xff0c;再重新回填到单元格中的案例。大约有700多行&#xff0c;1400多个句子&#xff0c;一个个手动复制粘贴要花费不少时间&#xff0c;而且极易出错。这时&#xff0c;我们就可以请出…

TypeORM在Node.js中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 TypeORM在Node.js中的应用 TypeORM在Node.js中的应用 TypeORM在Node.js中的应用 引言 TypeORM 概述 定义与特点 发展历程 TypeO…