[深度学习]图像分类项目-食物分类

news2025/3/29 1:49:36

图像分类项目-食物分类(监督学习和半监督学习)

文章目录

  • 图像分类项目-食物分类(监督学习和半监督学习)
    • 项目介绍
    • 数据处理
      • 设定随机种子
      • 读取文件内容
      • 图像增广
      • 定义Dataset类
    • 模型定义
      • 迁移学习
    • 定义超参
      • Adam和AdamW
    • 训练过程
    • 半监督学习
      • 定义Dataset类
      • 模型定义
      • 定义超参
      • 训练过程

项目介绍

image-20250214102822207

数据处理

设定随机种子

由于神经网络的训练具有随机性,为了保证之前得到的好的训练效果可以得到复现,设定随机种子,让训练过程中的随机行为每次训练都是相同。

def seed_everything(seed):
    torch.manual_seed(seed)
    torch.cuda.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    torch.backends.cudnn.benchmark = False
    torch.backends.cudnn.deterministic = True
    random.seed(seed)
    np.random.seed(seed)
    os.environ['PYTHONHASHSEED'] = str(seed)
#################################################################
seed_everything(0)
###############################################

读取文件内容

进行数据处理前,需要了解数据的形式训练集中,有标签的数据按照11类分别存放在11个文件夹中,因此要循环依次读取这11个文件夹的内容:

image-20250214104855956

首先从文件夹中读出每张图片和对应标签(读取的是带标签的数据):

HW = 224

def read_file(path):
    for i in tqdm(range(11)):
        file_dir = path + "/%02d" % i
        file_list = os.listdir(file_dir)  # 列出文件夹下所有文件名字

        xi = np.zeros((len(file_list), HW, HW, 3), dtype=np.uint8)  # 每个元素存一个图片,图片为整形类型
        yi = np.zeros(len(file_list))

        for j, img_name in enumerate(file_list):
            img_path = os.path.join(file_dir, img_name)  # 拼接地址
            img = Image.open(img_path)  # 打开图片
            img = img.resize((HW, HW))  # 修改成模型接受的大小
            xi[j, ...] = img
            yi[j] = i

        if i == 0:#第一个数据赋值
            X = xi
            Y = yi
        else:#后续数据尾插
            X = np.concatenate((X, xi), axis=0)
            Y = np.concatenate((Y, yi), axis=0)
    print("读到了%d个数据" % len(Y))
    return X, Y

图像增广

模型对训练使用的图片数据有好的效果,但是如果对图片数据进行一定的变化,模型的效果就变差,因此在训练时,不仅使用原图片训练,还要对图片进行旋转,放大裁切等图像操作,将原图片和操作后的图片都作为训练数据,也就是图像增广,让模型的效果更好。

image-20250221112528853

train_transform = transforms.Compose(#定义训练集增广方式
    [
        transforms.ToPILImage(), #224,224,3模型:3,224,244
        transforms.RandomResizedCrop(224),#随机放大裁切
        transforms.RandomRotation(50),#50度以内随机旋转
        transforms.ToTensor()#模型运行的数据类型为张量
    ]
)

val_transform = transforms.Compose(#验证集不需要增广
    [
        transforms.ToPILImage(),  # 224,224,3模型:3,224,244
        transforms.ToTensor()  # 模型运行的数据类型为张量
    ]
)

定义Dataset类

class food_Dataset(Dataset):#继承Dateset类
    def __init__(self, path, mode="train"):
        self.X, self.Y = read_file(path)
        self.Y = torch.LongTensor(self.Y)#图片数据类型为整形
        if mode == "train":#根据模式选择增广类型
            self.transform = train_transform
        else:
            self.transform = val_transform

    def __getitem__(self, item):
        return self.transform(self.X[item]), self.Y[item] #使用图片增广

    def __len__(self):
        return len(self.Y)

模型定义

在模型中设定一些卷积、归一化、池化、激活函数对数据进行特征提取。

class myModel(nn.Module):
    def __init__(self, num_class):
        super(myModel, self).__init__()
        #3*224*224->512*7*7->拉直->全连接分类
        self.conv1 = nn.Conv2d(3, 64, 3, 1, 1) #3厚度,64个卷积核,卷积核大小3,padding为1,步长为1 64*224*224
        self.bn1 = nn.BatchNorm2d(64)#归一化
        self.relu = nn.ReLU()
        self.pool1 = nn.MaxPool2d(2)   #64*112*112


        self.layer1 = nn.Sequential(
            nn.Conv2d(64, 128, 3, 1, 1),    # 128*112*112
            nn.BatchNorm2d(128),
            nn.ReLU(),
            nn.MaxPool2d(2)   #128*56*56
        )
        self.layer2 = nn.Sequential(
            nn.Conv2d(128, 256, 3, 1, 1),
            nn.BatchNorm2d(256),
            nn.ReLU(),
            nn.MaxPool2d(2)   #256*28*28
        )
        self.layer3 = nn.Sequential(
            nn.Conv2d(256, 512, 3, 1, 1),
            nn.BatchNorm2d(512),
            nn.ReLU(),
            nn.MaxPool2d(2)   #512*14*14
        )

        self.pool2 = nn.MaxPool2d(2)    #512*7*7
        self.fc1 = nn.Linear(25088, 1000)   #25088->1000
        self.relu2 = nn.ReLU()
        self.fc2 = nn.Linear(1000, num_class)  #1000-11

    def forward(self, x):#使用定义的模型进行前向过程
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.pool1(x)
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.pool2(x)
        x = x.view(x.size()[0], -1) #拉直,x.size(0) 就是批量大小(batch_size),表示你有多少个样本输入到模型中。-1 是自动计算剩下的维度以便将数据展平。
        x = self.fc1(x)
        x = self.relu2(x)
        x = self.fc2(x)
        return x

迁移学习

良好的模型是需要大量的数据训练得到的,由于我们设备加上数据量的限制训练出来的模型效果不会特别好,甚至预测效果接近随机预测,因此我们要进行迁移学习。简单来说,**迁移学习就是使用大佬们用大量数据训练出来的现成模型,**由于大佬的模型经过训练后有很好的特征提取效果,因此我们只需要使用大佬的模型然后加上分类头作为训练的模型即可。

image-20250221105346896

预训练是指在无关当前任务的模型训练,迁移学习使用的模型就是进行过预训练的模型,迁移学习时可以进行线性探测微调,线性探测就是在训练中不进行参数的调整,完全信任迁移学习使用的模型,微调就是在训练过程中会进行参数调整。

迁移学习时可选择只使用架构和使用架构和参数,虽然迁移学习使用的架构很优秀但是参数是更加重要的部分,因此使用架构和参数的效果要更好,要想使用迁移学习的预训练参数要保持架构一致。

from torchvision.models import resnet18#导入模型
model = resnet18(pretrained=True)#使用架构和参数
in_fetures = model.fc.in_features#获取模型的特征提取后的输出维度
model.fc = nn.Linear(in_fetures, 11)#全连接分类头

定义超参

定义学习率、损失函数、优化器、训练轮次等超参数。

Adam和AdamW

Adam优化器不仅考虑当前点的梯度还考虑之前的梯度,并且会自动更改学习率,由于参数更改时要减去学习率×梯度,当这个值过大时,Adam会自动更改学习率,AdamW是在Adam的基础上增加了权重衰减使得模型曲线更加平滑。

训练过程

def train_val(model, train_loader, val_loader, device, epochs, optimizer, loss, save_path):
    model = model.to(device)

    plt_train_loss = [] #记录所有轮次的LOSS
    plt_val_loss = []

    plt_train_acc = [] #记录准确率
    plt_val_acc = []

    max_acc = 0.0

    for epoch in range(epochs): #开始训练
        train_loss = 0.0
        val_loss = 0.0
        train_acc = 0.0#用准确率表示模型效果
        val_acc = 0.0

        start_time = time.time()

        model.train() #模型调为训练模式,有时训练模式和测试模式的模型不同
        for batch_x, batch_y in train_loader:
            x, target = batch_x.to(device), batch_y.to(device)
            pred = model(x)
            train_bat_loss = loss(pred, target) #获取一批数据的LOSS
            train_bat_loss.backward() #梯度回传
            optimizer.step()#更新模型
            optimizer.zero_grad()
            train_loss += train_bat_loss.cpu().item() #将gpu上的张量数据放到cpu上取出数据计算,累加记录本轮LOSS
            train_acc += np.sum(np.argmax(pred.detach().cpu().numpy(), axis=1) == target.cpu().numpy())#记录预测对的数量

        plt_train_loss.append(train_loss / train_loader.__len__()) #除以轮次数,得到每个轮次的LOSS平均值
        plt_train_acc.append(train_acc/train_loader.dataset.__len__()) #记录准确率,

        model.eval()#调为验证模式
        with torch.no_grad():#所有模型中的张量计算都积攒梯度,而验证时不需要梯度
            for batch_x, batch_y in val_loader:
                x, target = batch_x.to(device), batch_y.to(device)
                pred = model(x)
                val_bat_loss = loss(pred, target)
                val_loss += val_bat_loss.cpu().item()
                val_acc += np.sum(np.argmax(pred.detach().cpu().numpy(), axis=1) == target.cpu().numpy())  # 记录预测对的数量

        plt_val_loss.append(val_loss / val_loader.dataset.__len__())
        plt_val_acc.append(val_acc/val_loader.dataset.__len__()) #记录准确率,

        if val_acc > max_acc: #如果当前模型效果更好,进行记录
            torch.save(model, save_path)
            max_acc = val_loss
		
        
        #训练效果打印
        print('[%03d/%03d] %2.2f sec(s) TrainLoss : %.6f | valLoss: %.6f Trainacc : %.6f | valacc: %.6f' % \
              (epoch, epochs, time.time() - start_time, plt_train_loss[-1], plt_val_loss[-1], plt_train_acc[-1],
               plt_val_acc[-1])
              )  # 打印训练结果。 注意python语法, %2.2f 表示小数位为2的浮点数, 后面可以对应。

        plt.plot(plt_train_loss)
        plt.plot(plt_val_loss)
        plt.title("loss")
        plt.legend(["train", "val"])
        plt.show()

        plt.plot(plt_train_acc)
        plt.plot(plt_val_acc)
        plt.title("loss")
        plt.legend(["train", "val"])
        plt.show()

半监督学习

监督学习是指每个训练样本都有对应的标签,模型通过学习这些标注数据训练,目标是让模型能够根据新的输入数据预测正确的标签。

半监督学习是介于监督学习和无监督学习之间的一种方法。在半监督学习中,训练数据包含大量的未标注数据和少量的标注数据。模型利用少量的标注数据来进行学习,同时也借助未标注数据来进一步提高模型的性能。

  • 模型首先使用标注数据进行训练。
  • 模型的效果达到一定程度后,用训练得到的模型对未标注数据进行预测。
  • 若预测结果结果的置信值(成功率)达到一定值后,将预测结果(伪标签)添加到训练数据集中。

image-20250221121136819

为了加入半监督学习,对监督学习的代码进行修改。

定义Dataset类

class food_Dataset(Dataset):
    def __init__(self, path, mode="train"):
        self.mode = mode
        if mode == "semi":#若为半监督模式,数据只有X,没有标签Y
            self.X = self.read_file(path)
        else:
            self.X, self.Y = self.read_file(path)
            self.Y = torch.LongTensor(self.Y)  #标签转为长整形

        if mode == "train":#训练模式需要图片增广等操作
            self.transform = train_transform
        else:#非训练模式,包括半监督模式下,只需要让数据转换成符合模型输入的格式即可
            self.transform = val_transform

    def read_file(self, path):#读取数据函数
        if self.mode == "semi":
            file_list = os.listdir(path)
            xi = np.zeros((len(file_list), HW, HW, 3), dtype=np.uint8)
            # 列出文件夹下所有文件名字
            for j, img_name in enumerate(file_list):
                img_path = os.path.join(path, img_name)
                img = Image.open(img_path)
                img = img.resize((HW, HW))
                xi[j, ...] = img
            print("读到了%d个数据" % len(xi))
            return xi
        else:
            for i in tqdm(range(11)):
                file_dir = path + "/%02d" % i
                file_list = os.listdir(file_dir)

                xi = np.zeros((len(file_list), HW, HW, 3), dtype=np.uint8)
                yi = np.zeros(len(file_list), dtype=np.uint8)

                # 列出文件夹下所有文件名字
                for j, img_name in enumerate(file_list):
                    img_path = os.path.join(file_dir, img_name)
                    img = Image.open(img_path)
                    img = img.resize((HW, HW))
                    xi[j, ...] = img
                    yi[j] = i

                if i == 0:
                    X = xi
                    Y = yi
                else:
                    X = np.concatenate((X, xi), axis=0)
                    Y = np.concatenate((Y, yi), axis=0)
            print("读到了%d个数据" % len(Y))
            return X, Y

    def __getitem__(self, item):
        if self.mode == "semi":
            return self.transform(self.X[item]), self.X[item]#前者为为了输入模型进行转换的X用于训练得到伪标签,后者为原始数据X用于加入半监督数据集
        else:
            return self.transform(self.X[item]), self.Y[item]

    def __len__(self):
        return len(self.X)

class semiDataset(Dataset):#半监督数据集Dataset类
    def __init__(self, no_label_loder, model, device, thres=0.99):#传入无标签数据,预测模型,置信度
        x, y = self.get_label(no_label_loder, model, device, thres)
        if x == []:#如果预测得到的伪标签都不符合要求,如置信度低,导致半监督数据集为空进行标记
            self.flag = False

        else:
            self.flag = True
            self.X = np.array(x)
            self.Y = torch.LongTensor(y)
            self.transform = train_transform#得到的半监督数据集同样用于模型训练
    def get_label(self, no_label_loder, model, device, thres):#给半监督数据打标签
        model = model.to(device)
        pred_prob = []#记录预测类型中最高概率
        labels = []#记录最高概率对应的标签
        x = []
        y = []
        soft = nn.Softmax()
        with torch.no_grad():#只要通过模型就会积攒梯度,只要不进行模型训练调整,积攒的梯度就没用
            for bat_x, _ in no_label_loder:
                bat_x = bat_x.to(device)
                pred = model(bat_x)
                pred_soft = soft(pred)
                pred_max, pred_value = pred_soft.max(1)#维度1为横向,取出最高概率和其对应的标签,由于loader中一个元素是一批数据,因此pred_max和pred_value的一个元素中包含对应批数个值
                pred_prob.extend(pred_max.cpu().numpy().tolist())
                labels.extend(pred_value.cpu().numpy().tolist())

        for index, prob in enumerate(pred_prob):
            if prob > thres:#大于置信度加入半监督数据集
                x.append(no_label_loder.dataset[index][1])   #调用到原始的getitem,因为要加入半监督数据集
                y.append(labels[index])
        return x, y

    def __getitem__(self, item):
        return self.transform(self.X[item]), self.Y[item]
    def __len__(self):
        return len(self.X)
    
def get_semi_loader(no_label_loder, model, device, thres):#获取半监督数据集
    semiset = semiDataset(no_label_loder, model, device, thres)
    if semiset.flag == False:
        return None
    else:
        semi_loader = DataLoader(semiset, batch_size=16, shuffle=False)
        return semi_loader

模型定义

加入半监督学习只需要复用监督学习的训练模型进行预测即可。

定义超参

加入半监督学习要额外定义包括置信度的超参。

训练过程

def train_val(model, train_loader, val_loader, no_label_loader, device, epochs, optimizer, loss, thres, save_path):
    model = model.to(device)
    semi_loader = None
    plt_train_loss = []
    plt_val_loss = []

    plt_train_acc = []
    plt_val_acc = []

    max_acc = 0.0

    for epoch in range(epochs):
        train_loss = 0.0
        val_loss = 0.0
        train_acc = 0.0
        val_acc = 0.0
        semi_loss = 0.0#半监督数据集LOSS
        semi_acc = 0.0#对半监督数据集的预测准确率


        start_time = time.time()

        model.train()#训练模式
        for batch_x, batch_y in train_loader:#使用有标签训练集训练
            x, target = batch_x.to(device), batch_y.to(device)
            pred = model(x)
            train_bat_loss = loss(pred, target)
            train_bat_loss.backward()
            optimizer.step()  # 更新参数 之后要梯度清零否则会累积梯度
            optimizer.zero_grad()
            train_loss += train_bat_loss.cpu().item()
            train_acc += np.sum(np.argmax(pred.detach().cpu().numpy(), axis=1) == target.cpu().numpy())
        plt_train_loss.append(train_loss / train_loader.__len__())
        plt_train_acc.append(train_acc/train_loader.dataset.__len__()) #记录准确率,

        if semi_loader!= None:#若半监督数据集非空,使用半监督数据集进行训练
            for batch_x, batch_y in semi_loader:
                x, target = batch_x.to(device), batch_y.to(device)
                pred = model(x)
                semi_bat_loss = loss(pred, target)
                semi_bat_loss.backward()
                optimizer.step()  # 更新参数 之后要梯度清零否则会累积梯度,因为下一轮数据要重新计算梯度
                optimizer.zero_grad()
                semi_loss += train_bat_loss.cpu().item()
                semi_acc += np.sum(np.argmax(pred.detach().cpu().numpy(), axis=1) == target.cpu().numpy())
            print("半监督数据集的训练准确率为", semi_acc/train_loader.dataset.__len__())


        model.eval()
        with torch.no_grad():
            for batch_x, batch_y in val_loader:
                x, target = batch_x.to(device), batch_y.to(device)
                pred = model(x)
                val_bat_loss = loss(pred, target)
                val_loss += val_bat_loss.cpu().item()
                val_acc += np.sum(np.argmax(pred.detach().cpu().numpy(), axis=1) == target.cpu().numpy())
        plt_val_loss.append(val_loss / val_loader.dataset.__len__())
        plt_val_acc.append(val_acc / val_loader.dataset.__len__())

        if epoch%3 == 0 and plt_val_acc[-1] > 0.6:#将模型训练至一定能力后,再进行半监督学习
            semi_loader = get_semi_loader(no_label_loader, model, device, thres)

        if val_acc > max_acc:
            torch.save(model, save_path)
            max_acc = val_loss

        print('[%03d/%03d] %2.2f sec(s) TrainLoss : %.6f | valLoss: %.6f Trainacc : %.6f | valacc: %.6f' % \
              (epoch, epochs, time.time() - start_time, plt_train_loss[-1], plt_val_loss[-1], plt_train_acc[-1], plt_val_acc[-1])
              )  # 打印训练结果。 注意python语法, %2.2f 表示小数位为2的浮点数, 后面可以对应。

    plt.plot(plt_train_loss)
    plt.plot(plt_val_loss)
    plt.title("loss")
    plt.legend(["train", "val"])
    plt.show()


    plt.plot(plt_train_acc)
    plt.plot(plt_val_acc)
    plt.title("acc")
    plt.legend(["train", "val"])
    plt.show()

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

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

相关文章

java8循环解压zip文件---实现Excel文件数据追加

java8循环追加Excel数据 实际遇到问题:定期获取zip文件,zip文件内有几个固定模板的Excel文件,有的Excel文件可能还包含多个sheet。 有段时间一次性获取到好几个zip包,需要将这些包都解压,并且按照不同的文件名、sheet进…

基于SpringBoot的电影售票系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…

SQL Server 2022 安装问题

一、安装与配置问题 1. SQL Server 2022 安装失败怎么办? 常见原因: 硬件或操作系统不满足最低要求(如内存、磁盘空间不足)。未关闭防火墙或杀毒软件。之前版本的 SQL Server 残留文件未清理。 解决方案: 确保硬件配…

MySQL 8.0.41安装教程(附安装包)mysql8.0.41图文详细安装教程

文章目录 前言一、MySQL 8.0.41下载安装包二、MySQL 8.0.41安装教程1.启动安装程序2.选择安装模式3.选定安装组件4.确认安装设置5.执行安装操作6.安装进行中7.设置数据库密码8.继续点击下一步9.执行配置操作10.完成配置11. 再次点击下一步12.结束安装向导 三、MySQL 8.0.41配置…

深入解析 C++20 中的 std::bind_front:高效函数绑定与参数前置

文章目录 1. 什么是 std::bind_front?2. 使用 std::bind_front2.1 基本用法2.2 绑定多个参数 3. 优势与特点3.1 简化代码3.2 支持可调用对象3.3 支持完美转发 4. 实际应用场景4.1 事件处理4.2 算法通用化4.3 成员函数调用 5. 总结 在现代 C 编程中,函数绑…

python裁剪nc文件数据

问题描述: 若干个nc文件储存全球的1850-2014年月尺度的mrro数据(或其他数据),从1850-1到2014-12一共1980个月,要提取出最后35年1980.1~2014.12年也就是420个月的数据。 代码实现 def aaa(input_file,output_file,bianliang,start_index,en…

CSS网格布局Grid

目录 一、Grid 网格布局 1.Grid 布局基础 2.网格容器属性 3.网格项目属性 4.高级功能 5.典型应用场景 6.最佳实践 二、Flex和Grid对比 示例: 一、Grid 网格布局 CSS Grid 是一种强大的二维布局系统,能够以行和列的方式精确控制网页布局。它比传…

医院挂号预约小程序|基于微信小程序的医院挂号预约系统设计与实现(源码+数据库+文档)

医院挂号预约小程序 目录 基于微信小程序的医院挂号预约系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、小程序用户端 2、系统服务端 (1) 用户管理 (2)医院管理 (3)医生管理 &#xf…

蓝桥杯第十届 特别的数

题目描述 小明对数位中含有 2、0、1、9 的数字很感兴趣(不包括前导 0),在 1 到 40 中这样的数包括 1、2、9、10 至 32、39 和 40,共 28 个,他们的和是 574。 请问,在 1 到 n 中,所有这样的数的…

Qt开发:QInputDialog的使用

文章目录 一、QInputDialog的介绍二、 QInputDialog的基本用法三、使用 QInputDialog的实例四、QInputDialog的信号与槽 一、QInputDialog的介绍 QInputDialog 是 Qt 提供的一个对话框类,用于获取用户输入的文本、整数或浮点数。它提供了简单易用的静态方法和可定制…

redis--JavaSpring客户端

目录 一、引言 二、配置 三、相关操作 四、总结 一、引言 本篇文章会将redis与spring项目进行结合,看看再spring项目中,redis是如何使用的 二、配置 三、相关操作 四、总结 在spring项目中的使用和在基础项目上的使用有差异,但是差异并不大…

2、二分和贪心

一、二分 这里有个小技巧,你会发现,只要是求最大最小最多等等的贪心过程,我们就有3种方法:①二分②贪心算法③动态规划 我们先讲二分和贪心,动态规划比较麻烦,留到后期。 1、了解 2、模版 class Solution …

QuecPython 网络协议之TCP/UDP协议最祥解析

概述 IP 地址与域名 IP 地址是网络中的主机地址,用于两台网络主机能够互相找到彼此,这也是网络通信能够成功进行的基础。IP 地址一般以点分十进制的字符串来表示,如192.168.1.1。 ​ 我们日常访问的网站,其所在的服务器主机都有…

ISIS-2 邻居建立关系

上一章我们介绍了ISIS的基础概念以及报文内容和作用在什么样的场景下面的 这一章我们来介绍IS-IS的邻居建立关系 一、概念 IS-IS中路由器的角色可分为L1、L2、L1/2这三种类型其中的L1/L2有点类似与我们OSPF中的ABR IS-IS中的邻居关系分为L1与L2邻居关系,其中所有建立L2邻居关…

Nature Machine Intelligence 嵌入式大语言模型使机器人能够在不可预测的环境中完成复杂的任务

近期英国爱丁堡大学发表Nature Machine Intelligence研究工作,提出了一种名为ELLMER(具身大型语言模型支持机器人)的创新框架,通过整合大型语言模型(如GPT-4)、检索增强生成(RAG)、视…

Springboot整合elasticsearch详解 封装模版 仓库方法 如何在linux里安装elasticsearch

目录 版本 下载地址 ElasticSearch频繁报503错误 开放 9300 和 9200 两个端口 测试联通性 改动包装类 elasticsearchTemplate getAllRespRepository 封装elasticsearchService 业务逻辑 版本 首先要对应版本 这是我在官网找到的版本信息 一定要 springboot 和 es 相…

【矩阵快速幂】P6601 「EZEC-2」机器|普及+

本文涉及知识点 【矩阵快速幂】封装类及测试用例及样例 P6601 「EZEC-2」机器 题目背景 tlx 喜欢科幻小说。 小宇宙中只剩下漂流瓶和生态球。漂流瓶隐没于黑暗里,在一千米见方的宇宙中,只有生态球里的小太阳发出一点光芒。在这个小小的生命世界中,几只清澈的水球在零重力环…

FPGA助力智能机器人应用

今年开年AI机器人引爆科技圈,都说FPGA是“万能芯”,在AI方向上已经挣扎了几年,仍旧不能“破圈”,那么在机器人方向呢? 个人观点我是不太看好目前FPGA能在机器人方面能“破圈”,但是一切皆有可能&#xff0c…

如何在jupyter notebook中使用django框架

(最好以管理员身份进入,否则在安装某些内容时会报错) 一.创建一个名为new_env虚拟环境 输入以下指令创建名为new_env的虚拟环境: conda create -n new_env python3.8 回车,出现以下内容,输入y确认安装,等待安装完毕…