昇思25天学习打卡营第12天|ResNet50迁移学习

昇思25天学习打卡营第12天|ResNet50迁移学习

  • 前言
  • ResNet50迁移学习
    • 数据准备
      • 下载数据集
    • 加载数据集
      • 数据集可视化
    • 训练模型
      • 构建Resnet50网络
      • 固定特征进行训练
        • 训练和评估
        • 可视化模型预测
  • 个人任务打卡(读者请忽略)
  • 个人理解与总结

前言

  非常感谢华为昇思大模型平台和CSDN邀请体验昇思大模型!从今天起,笔者将以打卡的方式,将原文搬运和个人思考结合,分享25天的学习内容与成果。为了提升文章质量和阅读体验,笔者会将思考部分放在最后,供大家探索讨论。同时也欢迎各位领取算力,免费体验昇思大模型!

ResNet50迁移学习

在实际应用场景中,由于训练数据集不足,所以很少有人会从头开始训练整个网络。普遍的做法是,在一个非常大的基础数据集上训练得到一个预训练模型,然后使用该模型来初始化网络的权重参数或作为固定特征提取器应用于特定的任务中。本章将使用迁移学习的方法对ImageNet数据集中的狼和狗图像进行分类。

迁移学习详细内容见Stanford University CS231n。

数据准备

下载数据集

下载案例所用到的狗与狼分类数据集,数据集中的图像来自于ImageNet,每个分类有大约120张训练图像与30张验证图像。使用download接口下载数据集,并将下载后的数据集自动解压到当前目录下。

%%capture captured_output
# 实验环境已经预装了mindspore==2.2.14,如需更换mindspore版本,可更改下面mindspore的版本号
!pip uninstall mindspore -y
!pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspore==2.2.14
# 查看当前 mindspore 版本
!pip show mindspore

在这里插入图片描述

from download import downloaddataset_url = "https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/intermediate/Canidae_data.zip"download(dataset_url, "./datasets-Canidae", kind="zip", replace=True)			#根据URL下载数据集并解压

在这里插入图片描述
数据集的目录结构如下:

datasets-Canidae/data/
└── Canidae├── train│   ├── dogs│   └── wolves└── val├── dogs└── wolves

加载数据集

狼狗数据集提取自ImageNet分类数据集,使用mindspore.dataset.ImageFolderDataset接口来加载数据集,并进行相关图像增强操作。

首先执行过程定义一些输入:

batch_size = 18                             # 批量大小
image_size = 224                            # 训练图像空间大小
num_epochs = 5                            	# 训练周期数
lr = 0.001                                  # 学习率
momentum = 0.9                              # 动量
workers = 4                                 # 并行线程个数
import mindspore as ms
import mindspore.dataset as ds
import mindspore.dataset.vision as vision# 数据集目录路径
data_path_train = "./datasets-Canidae/data/Canidae/train/"
data_path_val = "./datasets-Canidae/data/Canidae/val/"# 创建训练数据集def create_dataset_canidae(dataset_path, usage):"""数据加载"""data_set = ds.ImageFolderDataset(dataset_path,num_parallel_workers=workers,shuffle=True,)# 数据增强操作mean = [0.485 * 255, 0.456 * 255, 0.406 * 255]			#三通道均值std = [0.229 * 255, 0.224 * 255, 0.225 * 255]			#三通道标准差scale = 32if usage == "train":# Define map operations for training datasettrans = [vision.RandomCropDecodeResize(size=image_size, scale=(0.08, 1.0), ratio=(0.75, 1.333)),		#图像随机缩放裁切vision.RandomHorizontalFlip(prob=0.5),														#随机水平翻转vision.Normalize(mean=mean, std=std),														#归一化vision.HWC2CHW()																			#数据HWC转CHW格式]else:# Define map operations for inference datasettrans = [vision.Decode(),vision.Resize(image_size + scale),vision.CenterCrop(image_size),vision.Normalize(mean=mean, std=std),vision.HWC2CHW()]# 数据映射操作data_set = data_set.map(operations=trans,input_columns='image',num_parallel_workers=workers)# 批量操作data_set = data_set.batch(batch_size)return data_setdataset_train = create_dataset_canidae(data_path_train, "train")
step_size_train = dataset_train.get_dataset_size()dataset_val = create_dataset_canidae(data_path_val, "val")
step_size_val = dataset_val.get_dataset_size()

数据集可视化

mindspore.dataset.ImageFolderDataset接口中加载的训练数据集返回值为字典,用户可通过 create_dict_iterator 接口创建数据迭代器,使用 next 迭代访问数据集。本章中 batch_size 设为18,所以使用 next 一次可获取18个图像及标签数据。

data = next(dataset_train.create_dict_iterator())
images = data["image"]
labels = data["label"]print("Tensor of image", images.shape)
print("Labels:", labels)

在这里插入图片描述
对获取到的图像及标签数据进行可视化,标题为图像对应的label名称。

import matplotlib.pyplot as plt
import numpy as np# class_name对应label,按文件夹字符串从小到大的顺序标记label
class_name = {0: "dogs", 1: "wolves"}plt.figure(figsize=(5, 5))
for i in range(4):				#展示四张图# 获取图像及其对应的labeldata_image = images[i].asnumpy()data_label = labels[i]# 处理图像供展示使用data_image = np.transpose(data_image, (1, 2, 0))mean = np.array([0.485, 0.456, 0.406])std = np.array([0.229, 0.224, 0.225])data_image = std * data_image + meandata_image = np.clip(data_image, 0, 1)# 显示图像plt.subplot(2, 2, i+1)plt.imshow(data_image)plt.title(class_name[int(labels[i].asnumpy())])plt.axis("off")				#不展示轴线plt.show()

在这里插入图片描述

训练模型

本章使用ResNet50模型进行训练。搭建好模型框架后,通过将pretrained参数设置为True来下载ResNet50的预训练模型并将权重参数加载到网络中。

构建Resnet50网络

from typing import Type, Union, List, Optional
from mindspore import nn, train
from mindspore.common.initializer import Normalweight_init = Normal(mean=0, sigma=0.02)
gamma_init = Normal(mean=1, sigma=0.02)
class ResidualBlockBase(nn.Cell):expansion: int = 1  # 最后一个卷积核数量与第一个卷积核数量相等def __init__(self, in_channel: int, out_channel: int,stride: int = 1, norm: Optional[nn.Cell] = None,down_sample: Optional[nn.Cell] = None) -> None:super(ResidualBlockBase, self).__init__()if not norm:self.norm = nn.BatchNorm2d(out_channel)else:self.norm = normself.conv1 = nn.Conv2d(in_channel, out_channel,kernel_size=3, stride=stride,weight_init=weight_init)					#二维卷积,卷积核尺寸为3*3self.conv2 = nn.Conv2d(in_channel, out_channel,kernel_size=3, weight_init=weight_init)	#二维卷积,卷积核尺寸为3*3self.relu = nn.ReLU()											#激活函数ReLUself.down_sample = down_sample									#下采样def construct(self, x):"""ResidualBlockBase construct."""identity = x  # shortcuts分支out = self.conv1(x)  # 主分支第一层:3*3卷积层out = self.norm(out)out = self.relu(out)out = self.conv2(out)  # 主分支第二层:3*3卷积层out = self.norm(out)if self.down_sample is not None:identity = self.down_sample(x)out += identity  # 输出为主分支与shortcuts之和out = self.relu(out)return out
class ResidualBlock(nn.Cell):expansion = 4  # 最后一个卷积核的数量是第一个卷积核数量的4倍def __init__(self, in_channel: int, out_channel: int,stride: int = 1, down_sample: Optional[nn.Cell] = None) -> None:super(ResidualBlock, self).__init__()self.conv1 = nn.Conv2d(in_channel, out_channel,kernel_size=1, weight_init=weight_init)		#二维卷积,卷积核尺寸为1*1self.norm1 = nn.BatchNorm2d(out_channel)							#批归一化self.conv2 = nn.Conv2d(out_channel, out_channel,kernel_size=3, stride=stride,weight_init=weight_init)						#二维卷积,卷积核尺寸为3*3self.norm2 = nn.BatchNorm2d(out_channel)							#批归一化self.conv3 = nn.Conv2d(out_channel, out_channel * self.expansion,kernel_size=1, weight_init=weight_init)		#二维卷积,卷积核尺寸为1*1self.norm3 = nn.BatchNorm2d(out_channel * self.expansion)self.relu = nn.ReLU()self.down_sample = down_sampledef construct(self, x):identity = x  # shortscuts分支out = self.conv1(x)  # 主分支第一层:1*1卷积层out = self.norm1(out)out = self.relu(out)out = self.conv2(out)  # 主分支第二层:3*3卷积层out = self.norm2(out)out = self.relu(out)out = self.conv3(out)  # 主分支第三层:1*1卷积层out = self.norm3(out)if self.down_sample is not None:identity = self.down_sample(x)out += identity  # 输出为主分支与shortcuts之和out = self.relu(out)return out
def make_layer(last_out_channel, block: Type[Union[ResidualBlockBase, ResidualBlock]],channel: int, block_nums: int, stride: int = 1):down_sample = None  # shortcuts分支if stride != 1 or last_out_channel != channel * block.expansion:down_sample = nn.SequentialCell([nn.Conv2d(last_out_channel, channel * block.expansion,kernel_size=1, stride=stride, weight_init=weight_init),				#二维卷积,卷积核尺寸为1*1nn.BatchNorm2d(channel * block.expansion, gamma_init=gamma_init)])layers = []layers.append(block(last_out_channel, channel, stride=stride, down_sample=down_sample))in_channel = channel * block.expansion# 堆叠残差网络for _ in range(1, block_nums):layers.append(block(in_channel, channel))return nn.SequentialCell(layers)
from mindspore import load_checkpoint, load_param_into_netclass ResNet(nn.Cell):def __init__(self, block: Type[Union[ResidualBlockBase, ResidualBlock]],layer_nums: List[int], num_classes: int, input_channel: int) -> None:super(ResNet, self).__init__()self.relu = nn.ReLU()# 第一个卷积层,输入channel为3(彩色图像),输出channel为64self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, weight_init=weight_init)self.norm = nn.BatchNorm2d(64)# 最大池化层,缩小图片的尺寸self.max_pool = nn.MaxPool2d(kernel_size=3, stride=2, pad_mode='same')# 各个残差网络结构块定义,self.layer1 = make_layer(64, block, 64, layer_nums[0])self.layer2 = make_layer(64 * block.expansion, block, 128, layer_nums[1], stride=2)self.layer3 = make_layer(128 * block.expansion, block, 256, layer_nums[2], stride=2)self.layer4 = make_layer(256 * block.expansion, block, 512, layer_nums[3], stride=2)# 平均池化层self.avg_pool = nn.AvgPool2d()# flattern层self.flatten = nn.Flatten()# 全连接层self.fc = nn.Dense(in_channels=input_channel, out_channels=num_classes)def construct(self, x):x = self.conv1(x)x = self.norm(x)x = self.relu(x)x = self.max_pool(x)x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)x = self.avg_pool(x)x = self.flatten(x)x = self.fc(x)return xdef _resnet(model_url: str, block: Type[Union[ResidualBlockBase, ResidualBlock]],layers: List[int], num_classes: int, pretrained: bool, pretrianed_ckpt: str,input_channel: int):model = ResNet(block, layers, num_classes, input_channel)if pretrained:# 加载预训练模型download(url=model_url, path=pretrianed_ckpt, replace=True)param_dict = load_checkpoint(pretrianed_ckpt)load_param_into_net(model, param_dict)return modeldef resnet50(num_classes: int = 1000, pretrained: bool = False):"ResNet50模型"resnet50_url = "https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/models/application/resnet50_224_new.ckpt"resnet50_ckpt = "./LoadPretrainedModel/resnet50_224_new.ckpt"return _resnet(resnet50_url, ResidualBlock, [3, 4, 6, 3], num_classes,pretrained, resnet50_ckpt, 2048)

固定特征进行训练

使用固定特征进行训练的时候,需要冻结除最后一层之外的所有网络层。通过设置 requires_grad == False 冻结参数,以便不在反向传播中计算梯度。

import mindspore as ms
import matplotlib.pyplot as plt
import os
import timenet_work = resnet50(pretrained=True)# 全连接层输入层的大小
in_channels = net_work.fc.in_channels
# 输出通道数大小为狼狗分类数2
head = nn.Dense(in_channels, 2)
# 重置全连接层
net_work.fc = head# 平均池化层kernel size为7
avg_pool = nn.AvgPool2d(kernel_size=7)
# 重置平均池化层
net_work.avg_pool = avg_pool# 冻结除最后一层外的所有参数
for param in net_work.get_parameters():if param.name not in ["fc.weight", "fc.bias"]:param.requires_grad = False# 定义优化器和损失函数
opt = nn.Momentum(params=net_work.trainable_params(), learning_rate=lr, momentum=0.5)
loss_fn = nn.SoftmaxCrossEntropyWithLogits(sparse=True, reduction='mean')def forward_fn(inputs, targets):logits = net_work(inputs)loss = loss_fn(logits, targets)return lossgrad_fn = ms.value_and_grad(forward_fn, None, opt.parameters)def train_step(inputs, targets):loss, grads = grad_fn(inputs, targets)opt(grads)return loss# 实例化模型
model1 = train.Model(net_work, loss_fn, opt, metrics={"Accuracy": train.Accuracy()})

在这里插入图片描述

训练和评估

开始训练模型,与没有预训练模型相比,将节约一大半时间,因为此时可以不用计算部分梯度。保存评估精度最高的ckpt文件于当前路径的./BestCheckpoint/resnet50-best-freezing-param.ckpt。

import mindspore as ms
import matplotlib.pyplot as plt
import os
import time
dataset_train = create_dataset_canidae(data_path_train, "train")
step_size_train = dataset_train.get_dataset_size()dataset_val = create_dataset_canidae(data_path_val, "val")
step_size_val = dataset_val.get_dataset_size()num_epochs = 5# 创建迭代器
data_loader_train = dataset_train.create_tuple_iterator(num_epochs=num_epochs)
data_loader_val = dataset_val.create_tuple_iterator(num_epochs=num_epochs)
best_ckpt_dir = "./BestCheckpoint"
best_ckpt_path = "./BestCheckpoint/resnet50-best-freezing-param.ckpt"
import mindspore as ms
import matplotlib.pyplot as plt
import os
import time
# 开始循环训练
print("Start Training Loop ...")best_acc = 0for epoch in range(num_epochs):losses = []net_work.set_train()epoch_start = time.time()# 为每轮训练读入数据for i, (images, labels) in enumerate(data_loader_train):labels = labels.astype(ms.int32)loss = train_step(images, labels)losses.append(loss)# 每个epoch结束后,验证准确率acc = model1.eval(dataset_val)['Accuracy']epoch_end = time.time()epoch_seconds = (epoch_end - epoch_start) * 1000step_seconds = epoch_seconds/step_size_trainprint("-" * 20)print("Epoch: [%3d/%3d], Average Train Loss: [%5.3f], Accuracy: [%5.3f]" % (epoch+1, num_epochs, sum(losses)/len(losses), acc))print("epoch time: %5.3f ms, per step time: %5.3f ms" % (epoch_seconds, step_seconds))if acc > best_acc:best_acc = accif not os.path.exists(best_ckpt_dir):os.mkdir(best_ckpt_dir)ms.save_checkpoint(net_work, best_ckpt_path)print("=" * 80)
print(f"End of validation the best Accuracy is: {best_acc: 5.3f}, "f"save the best ckpt file in {best_ckpt_path}", flush=True)

在这里插入图片描述

可视化模型预测

使用固定特征得到的best.ckpt文件对对验证集的狼和狗图像数据进行预测。若预测字体为蓝色即为预测正确,若预测字体为红色则预测错误。

import matplotlib.pyplot as plt
import mindspore as msdef visualize_model(best_ckpt_path, val_ds):net = resnet50()# 全连接层输入层的大小in_channels = net.fc.in_channels# 输出通道数大小为狼狗分类数2head = nn.Dense(in_channels, 2)# 重置全连接层net.fc = head# 平均池化层kernel size为7avg_pool = nn.AvgPool2d(kernel_size=7)# 重置平均池化层net.avg_pool = avg_pool# 加载模型参数param_dict = ms.load_checkpoint(best_ckpt_path)ms.load_param_into_net(net, param_dict)model = train.Model(net)# 加载验证集的数据进行验证data = next(val_ds.create_dict_iterator())images = data["image"].asnumpy()labels = data["label"].asnumpy()class_name = {0: "dogs", 1: "wolves"}# 预测图像类别output = model.predict(ms.Tensor(data['image']))pred = np.argmax(output.asnumpy(), axis=1)# 显示图像及图像的预测值plt.figure(figsize=(5, 5))for i in range(4):plt.subplot(2, 2, i + 1)# 若预测正确,显示为蓝色;若预测错误,显示为红色color = 'blue' if pred[i] == labels[i] else 'red'plt.title('predict:{}'.format(class_name[pred[i]]), color=color)picture_show = np.transpose(images[i], (1, 2, 0))mean = np.array([0.485, 0.456, 0.406])std = np.array([0.229, 0.224, 0.225])picture_show = std * picture_show + meanpicture_show = np.clip(picture_show, 0, 1)plt.imshow(picture_show)plt.axis('off')plt.show()
visualize_model(best_ckpt_path, dataset_val)

在这里插入图片描述

个人任务打卡(读者请忽略)

在这里插入图片描述

个人理解与总结

本章节主要描述了使用昇思大模型完成ResNet50迁移学习的主要功能。迁移学习的本质是把为任务 A 开发的模型作为初始点,重新使用在为任务 B 开发模型的过程中。具体而言,本章节包含了迁移学习的数据准备、加载数据集、训练模型等三部分。该章节的重点在于构建ResNet50网络,然后完成固定特征进行训练,由于迁移学习的高效性,训练时间得以大幅度优化,且更容易达到更高的图像分类准确率。最终,ResNet50图像分类网络成功通过迁移学习完成了狼-狗的图像分类任务。(在常见的pytorch或其他深度学习网络框架中,如果要实现迁移学习,同样也需要需要设置pretained=trueweight='xxxx.pth'

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

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

相关文章

vite简介

vite是新一代前端构建工具,vite具有优势如下: 轻量快速的热重载(HMR),能实现快速的服务启动。对TypeScript、JSX、CSS等支持开箱即用。真正的按需编译,不再等待整个应用编译完成。webpack构建与vite构建对…

Jenkins 强制杀job

有时候有的jenkins job运行时间太长,在jenkins界面点击x按钮进行abort,会失败: 这时候点击: “Click here to forcibly terminate running steps” 会进一步kill 任务,但是也还是有杀不掉的可能性。 终极武器是jenkin…

vue3【提效】使用 VueUse 高效开发(工具库 @vueuse/core + 新增的组件库 @vueuse/components)

Vueuse 是一个功能强大的 Vue.js 生态系统工具库,提供了可重用的组件和函数,帮助开发者更轻松地构建复杂的应用程序。 官网 :https://vueuse.org/core/useWindowScroll/ 安装 VueUse npm i vueuse/core vueuse/components(可选&a…

llm学习-4(llm和langchain)

langchain说明文档:langchain 0.2.6 — 🦜🔗 langChain 0.2.6https://api.python.langchain.com/en/latest/langchain_api_reference.html#module-langchain.chat_models 1:模型 (1)自定义模型导入&#x…

跟《经济学人》学英文:2024年07月06日这期 Amazon turns 30

As Amazon turns 30, three factors will define its next decade It will have to deal with trustbusters, catch up on AI and revive its core business 它将不得不应对反垄断者,追赶人工智能并重振其核心业务 trustbuster: 美 [ˈtrəs(t)ˌbəs…

你真的会ELISA加样吗?

在ELISA实验中,研究人员需要进行多次加样步骤完成实验操作。对于常规双抗体夹心法ELISA,一般有如下加样步聚,即加样本、加检测抗体、加酶结合物、加底物(最后加终止液停止反应)。 加样步骤基础知识 加样步骤中一般使用…

云仓酒庄北京公司2024年:深耕酒业生态,以专业筑基

云仓酒庄北京公司:深耕酒业生态,以专业筑基,共绘酒业新蓝图 在竞争日益激烈的酒类市场中,云仓酒庄北京公司以其稳健的步伐、专业底蕴以及对品质的不懈追求,正逐步成为行业内一股不可忽视的力量。这家公司不仅仅是一个…

把Windows打造成一个NTP网络时间服务器,为网关提供校时服务

把Windows打造成一个NTP网络时间服务器,为网关提供校时服务。主要目的是为了解决:当网关不能上外网的时候,可以使用局域网的电脑来当做NTP服务器,实现校时功能。 跟着小编来看,如何使用NTP网络时间服务器来同步时间。 …

ubuntu关于docker部署 项目一站式教程

**假设已有ubuntu服务器并且登录root账号 ** **FinalShell中复制快捷键是 ****Ctrl+Shift+V** 卸载老版本docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker步骤 更新软件包sudo apt update sudo apt upgrade安装docker依赖sudo apt-get …

分享 10个简单实用的 JS 代码技巧

代码图片生成工具:有码高清 一、滚动到页面顶部 我们可以使用 window.scrollTo() 平滑滚动到页面顶部。 源码: const scrollToTop () > {window.scrollTo({ top: 0, left: 0, behavior: "smooth" }); };二、滚动到页面底部 当然&…

探索大型语言模型自动评估 LLM 输出长句准确性的方法

LLM现在能够自动评估较长文本中的事实真实性 源码地址:https://github.com/google-deepmind/long-form-factuality 论文地址:https://arxiv.org/pdf/2403.18802.pdf 这篇论文是关于谷歌DeepMind的,提出了新的数据集、评估方法和衡量标准&am…

vue2+element-ui新增编辑表格+删除行

实现效果&#xff1a; 代码实现 &#xff1a; <el-table :data"dataForm.updateData"border:header-cell-style"{text-align:center}":cell-style"{text-align:center}"><el-table-column label"选项字段"align"center&…

Linux 内核 GPIO 用户空间接口

文章目录 Linux 内核 GPIO 接口旧版本方式&#xff1a;sysfs 接口新版本方式&#xff1a;chardev 接口 gpiod 库及其命令行gpiod 库的命令行gpiod 库函数的应用 GPIO&#xff08;General Purpose Input/Output&#xff0c;通用输入/输出接口&#xff09;&#xff0c;是微控制器…

哪里还可以申请免费一年期的SSL证书?

目前&#xff0c;要申请免费一年期的SSL证书&#xff0c;选项较为有限&#xff0c;因为多数供应商已转向提供短期的免费证书&#xff0c;通常有效期为90天。不过&#xff0c;有一个例外是JoySSL&#xff0c;它仍然提供一年期的免费SSL证书&#xff0c;但是只针对教育版和政务版…

html三级菜单

示例 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title>Menu Example</title> <link re…

LED显示屏跟COB显示屏有哪些不同?

COB显示屏跟LED显示屏的主要区别在于产品的显示效果、封装技术、耐用性、防护力、维护以及制造成本方面的不同&#xff0c;这里所说的LED显示屏主要指的是使用SMD封装的LED显示屏&#xff0c;今天跟随COB显示屏厂家中品瑞科技一起来详细看看具体分析&#xff1a; 一、封装技术 …

品牌推广的深层逻辑:自我提升与市场认同的和谐共生

品牌推广的深层逻辑&#xff1a;自我提升与市场认同的和谐共生 著名飞行员查尔斯林德伯格(Charles Lindbergh) 曾写道:“改善生活方式比传播生活方式更重要。如果我们自己的生活方式使别人感到满意&#xff0c;那么它将自动蔓延。如果不是这样&#xff0c;那么任何武力都不可能…

如何在 Odoo 16 中继承和更新现有邮件模板

在本文中,让我们看看如何在 Odoo 16 中继承和编辑现有邮件模板。我们必须这样做才能对现有模板的内容进行任何调整或更新。让我们考虑一个在会计模块中更新邮件模板的示例。 单击“account.move”模型中的“发送并打印”按钮后,将打开上述向导。在这里,我们将进行更改。从…

8人团队历时半年打造开源版GPT-4o,零延迟演示引爆全网!人人可免费使用!

目录 01 Moshi 02 背后技术揭秘 GPT-4o可能要等到今年秋季才会公开。 然而&#xff0c;由法国8人团队开发的原生多模态Moshi&#xff0c;已经达到了接近GPT-4o的水平&#xff0c;现场演示几乎没有延迟&#xff0c;吸引了大量AI专家的关注。 令人惊讶的是&#xff0c;开源版的…

Python酷库之旅-第三方库Pandas(003)

目录 一、用法精讲 4、pandas.read_csv函数 4-1、语法 4-2、参数 4-3、功能 4-4、返回值 4-5、说明 4-6、用法 4-6-1、创建csv文件 4-6-2、代码示例 4-6-3、结果输出 二、推荐阅读 1、Python筑基之旅 2、Python函数之旅 3、Python算法之旅 4、Python魔法之旅 …