5月24日day35打卡

模型可视化与推理

知识点回顾:

  1. 三种不同的模型可视化方法:推荐torchinfo打印summary+权重分布可视化
  2. 进度条功能:手动和自动写法,让打印结果更加美观
  3. 推理的写法:评估模式

作业:调整模型定义时的超参数,对比下效果。

#  nn.Module 的内置功能,直接输出模型结构
print(model)

简单来说,你看到的是一个神经网络模型的“内部结构清单”,就像拆开一台机器后看到的零件列表。咱们用生活中的例子来理解:

假设你要做一个“判断水果类型”的模型(比如区分苹果、香蕉、橘子),输入可能是水果的4个特征(比如重量、颜色、表皮光滑度、大小),输出是3种水果的概率。这个MLP模型的结构就像一条“数据加工流水线”:

  1. 第一关(fc1层):有个“4转10的转换器”。它拿到输入的4个特征数据后,会做一些数学计算(比如加权求和+偏移),把这4个数据“变”成10个新的数据。就像把4种原材料加工成10种中间产物。

  2. 激活关(relu层):这一步会“过滤掉没用的中间产物”。比如如果某个中间产物算出来是负数(可能代表“没用的信息”),它就会直接变成0(相当于丢弃),只保留正数的部分。这样能让模型更“聪明”,只关注有用的信息。

  3. 第二关(fc2层):有个“10转3的转换器”。它拿到前面过滤后的10个数据,再做一次数学计算,最终把它们“浓缩”成3个结果。这3个结果就对应你要判断的3种水果的概率(比如哪个数值大,就更可能是对应的水果)。

所以整体看,这个模型就是通过两层“数据转换器”+一层“过滤无用信息”的步骤,把输入的4个特征,一步步处理成3个最终结果。

 

 

# nn.Module 的内置功能,返回模型的可训练参数迭代器
for name, param in model.named_parameters():print(f"Parameter name: {name}, Shape: {param.shape}")

这些是神经网络模型中各个层的可学习参数(权重和偏置)的信息,用大白话解释就是模型“内部用来做计算的规则”。我们一个一个看:


1. fc1.weight(形状 [10, 4])

这是第一个全连接层(fc1)的“权重矩阵”。

  • 作用:负责把输入的4维数据“转换”成10维数据。
  • 形状含义:10行(对应输出的10个维度),4列(对应输入的4个维度)。可以理解为:每个输出维度(共10个)需要和输入的4个维度“一一配对”计算,所以需要10×4个“小规则”(即权重参数)。

2. fc1.bias(形状 [10])

这是第一个全连接层的“偏置参数”。

  • 作用:给每个输出维度的计算结果加一个“偏移量”(类似数学里的 y = kx + b 中的 b),让模型能拟合更复杂的规律。
  • 形状含义:因为fc1输出是10维,所以需要10个偏置参数(每个输出维度对应1个)。

3. fc2.weight(形状 [3, 10])

这是第二个全连接层(fc2)的“权重矩阵”。

  • 作用:负责把前一层(fc1)输出的10维数据“转换”成最终的3维结果。
  • 形状含义:3行(对应最终输出的3个维度),10列(对应前一层输入的10个维度)。每个输出维度(共3个)需要和前一层的10个维度“配对”计算,所以需要3×10个权重参数。

4. fc2.bias(形状 [3])

这是第二个全连接层的“偏置参数”。

  • 作用:给最终输出的每个维度加一个“偏移量”。
  • 形状含义:因为最终输出是3维,所以需要3个偏置参数(每个输出维度对应1个)。

总结

这些参数是模型在训练过程中自动学习的(比如通过调整这些参数的值,让模型预测更准)。简单说,它们就像模型内部的“计算器”,输入数据经过这些参数的计算后,最终得到你想要的结果(比如分类、回归等)。

 

 

# 提取权重数据
import numpy as np
weight_data = {}
for name, param in model.named_parameters():if 'weight' in name:weight_data[name] = param.detach().cpu().numpy()# 可视化权重分布
fig, axes = plt.subplots(1, len(weight_data), figsize=(15, 5))
fig.suptitle('Weight Distribution of Layers')for i, (name, weights) in enumerate(weight_data.items()):# 展平权重张量为一维数组weights_flat = weights.flatten()# 绘制直方图axes[i].hist(weights_flat, bins=50, alpha=0.7)axes[i].set_title(name)axes[i].set_xlabel('Weight Value')axes[i].set_ylabel('Frequency')axes[i].grid(True, linestyle='--', alpha=0.7)plt.tight_layout()
plt.subplots_adjust(top=0.85)
plt.show()# 计算并打印每层权重的统计信息
print("\n=== 权重统计信息 ===")
for name, weights in weight_data.items():mean = np.mean(weights)std = np.std(weights)min_val = np.min(weights)max_val = np.max(weights)print(f"{name}:")print(f"  均值: {mean:.6f}")print(f"  标准差: {std:.6f}")print(f"  最小值: {min_val:.6f}")print(f"  最大值: {max_val:.6f}")print("-" * 30)

 

这里的“每层权重”指的是神经网络中每个可学习层(比如全连接层)内部的“核心参数”,也就是模型通过训练自动调整的“规则数值”。咱们结合你的代码和神经网络的工作原理,用大白话解释:

1. 什么是“权重”?

简单说,权重是神经网络里神经元之间的“连接强度”。就像你做数学题时的“计算公式”——比如输入4个特征(x1, x2, x3, x4),输出10个中间结果(y1~y10),每个y的计算可能是:
y1 = x1*w11 + x2*w12 + x3*w13 + x4*w14
这里的w11、w12、w13、w14就是“权重”(weight),它们决定了输入特征对输出结果的影响程度。

2. “每层权重”具体指什么?

你的代码里,model.named_parameters()会遍历模型所有可训练参数(包括权重和偏置),而if 'weight' in name筛选出了属于“权重”的参数。例如:

  • 如果模型有fc1(第一个全连接层),对应的权重是fc1.weight
  • 如果有fc2(第二个全连接层),对应的权重是fc2.weight
    这些就是代码中“每层权重”的具体对象。

3. 代码在“提取”和“分析”它们的什么?

你的代码做了两件关键的事:

(1)提取权重数据

把模型中每个层的权重参数(比如fc1.weightfc2.weight)从PyTorch的张量(Tensor)转成numpy数组,存到weight_data字典里。这样后续可以用numpy和matplotlib分析。

(2)可视化+统计分析
  • 直方图:把每个层的权重值“摊平”成一维数组(比如fc1.weight是10×4的矩阵,摊平后是40个数值),然后统计这些数值的分布(比如大部分权重是0附近的小数?还是有很多大的正数/负数?)。
  • 统计信息:计算每个层权重的均值、标准差、最小/最大值。这些数值能帮你快速判断:
    • 权重是否初始化合理(比如均值是否接近0,标准差是否太小/太大);
    • 训练是否正常(比如训练后权重是否有明显变化,是否出现梯度消失/爆炸)。

总结

“每层权重”就是模型中每个层(比如全连接层)里用于“计算输入→输出”的核心参数。你的代码在“检查”这些参数的分布和统计特征,就像给模型做“体检”——通过它们的数值表现,你可以判断模型是否训练正常、参数初始化是否合理,甚至定位训练中的问题(比如权重全为0可能是初始化错误)。

 

from torchsummary import summary
# 打印模型摘要,可以放置在模型定义后面
summary(model, input_size=(4,))

 

这是用 torchsummary 工具打印的模型“详细体检报告”,帮你快速看清模型每一层的“输出尺寸”和“参数数量”。咱们逐行用大白话解释:

第一部分:各层的具体信息(表格)

表格里的具体行:
  1. Linear-1(第一个全连接层)

    • Output Shape [-1, 10]:不管输入多少个样本(-1 代表批量大小),每个样本经过这层后会变成10个特征的数据。
    • Param # 50:这层有50个参数。计算方式是:输入4个特征,输出10个特征 → 权重参数是 10×4=40(类似“4转10的转换规则”),再加上10个偏置参数(每个输出特征一个),总共 40+10=50
  2. ReLU-2(激活函数层)

    • Output Shape [-1, 10]:激活函数不会改变数据的特征数量,所以输出还是10个特征。
    • Param # 0:ReLU激活函数(比如 max(0, x))没有需要学习的参数,只是单纯的数学运算,所以参数数为0。
  3. Linear-3(第二个全连接层)

    • Output Shape [-1, 3]:每个样本经过这层后会变成3个特征的数据(比如对应3分类任务的结果)。
    • Param # 33:输入是前一层的10个特征,输出3个特征 → 权重参数是 3×10=30,加上3个偏置参数,总共 30+3=33

第二部分:模型整体统计(表格下方)

  • Total params: 83:整个模型所有层的参数总和(50+0+33=83)。
  • Trainable params: 83:所有参数都可以被训练(比如用数据调整这些参数的值)。
  • Non-trainable params: 0:没有“冻结”的参数(有些模型会固定部分参数不训练,这里没有这种情况)。

第三部分:内存占用估计(最下方)

这部分是模型运行时的内存消耗估算(输入数据、计算过程、参数本身占用的内存)。这里显示 0.00 可能是因为输入数据的尺寸太小(比如输入是4维的小数),实际项目中如果输入数据很大(如图像),这里会显示具体数值。

总结:这个摘要是模型的“透明化报告”,让你一眼看清每一层怎么“加工数据”,以及模型总共需要学多少参数(参数越多,模型“记忆能力”越强,但可能越容易过拟合)。

 

该方法不显示输入层的尺寸,因为输入的神经网是自己设置的,所以不需要显示输入层的尺寸。但是在使用该方法时,input size=(4,)参数是必需的,因为PyTorch需要知道输入数据的形状才能推断模型各层的输出形状和参数数量。


这是因为PyTorch的模型在定义时是动态的,它不会预先知道输入数据的具体形状。nn.Linear(4,10)只定义了"输入维度是4,输出维度是10”,但不知道输入的批量大小和其他维度,比如卷积层需要知道输入的通道数、高度、宽度等信息。-并非所有输入数据都是结构化数据


因此,要生成模型摘要(如每层的输出形状、参数数量),必须提供一个示例输入形状,让PyTorch"运行”一次模型,从而推断出各层的信息。


summary函数的核心逻辑是:

  1. 创建一个与input size形状匹配的虚拟输入张量(通常填充零)
  2. 将虚拟输入传递给模型,执行一次前向传播(但不计算梯度)
  3. 记录每一层的输入和输出形状,以及参数数量
  4. 生成可读的摘要报告

构建神经网络的时候

  1. 输入层不需要写:x多少个特征输入层就有多少神经元
  2. 隐藏层需要写,从第一个隐藏层可以看出特征的个数
  3. 输出层的神经元和任务有关,比如分类任务,输出层有3个神经元,一个对应每个类别

 

上图只是帮助你理解,和上述架构不同,每条线记录权重w,在每个神经元内计算并且输出Relu(w*x+b)


可以看做,线记录权重,神经元记录偏置和损失函数


可学习参数计算

  1. Linear-1对应self.fc1=nn.Linear(4,10),表明前一层有4个神经元,这一层有10个神经元,每2个神经元之间靠着线相连,所有有4*10个权重参数+10个偏置参数=50个参数
  2. rlu层不涉及可学习参数,可以把它和前一个线性层看成一层,图上也是这个含义
  3. Linear-3层对应代码self.fc2=nn.Linear(10,3),10*3个权重参数+3个偏置=33个参数

总参数83个,占用内存几乎为0

 torchinfo是提供比torchsummary更详细的模型摘要信息,包括每层的输入输出形状、参数数量、计算量等。

torchinfo是提供比torchsummary更详细的模型摘要信息,包括每层的输入输出形状、参数数
量、计算量等。

进度条功能:

我们介绍下tgdm这个库,他非常适合用在循环中观察进度。尤其在深度学习这种训练是循环的场景中。他最核心的逻辑如下:

  1. 创建一个进度条对象,并传入总迭代次数。一般用wth语句创建对象,这样对象会在with语句结束后自动销毁,保证资源释放。wth是常见的上下文管理器,这样的使用方式还有用with打开文件,结束后会自动关闭文件。
  2. 更新进度条,通过pbar.update(n)指定每次前进的步数n(适用于非固定步长的循环)。

手动更新:

from tqdm import tqdm  # 先导入tqdm库
import time  # 用于模拟耗时操作# 创建一个总步数为10的进度条
with tqdm(total=10) as pbar:  # pbar是进度条对象的变量名# pbar 是 progress bar(进度条)的缩写,约定俗成的命名习惯。for i in range(10):  # 循环10次(对应进度条的10步)time.sleep(0.5)  # 模拟每次循环耗时0.5秒pbar.update(1)  # 每次循环后,进度条前进1步

 

from tqdm import tqdm
import time# 创建进度条时添加描述(desc)和单位(unit)
with tqdm(total=5, desc="下载文件", unit="个") as pbar:# 进度条这个对象,可以设置描述和单位# desc是描述,在左侧显示# unit是单位,在进度条右侧显示for i in range(5):time.sleep(1)pbar.update(1)  # 每次循环进度+1

 

unit参数的核心作用是明确进度条中每个进度单位的含义,使可视化信息更具可读性。在深度学习训练中,常用的单位包括:

  • epoch:训练轮次(遍历整个数据集一次)。
  • batch:批次(每次梯度更新处理的样本组)。
  • sample:样本(单个数据点)

自动更新:

from tqdm import tqdm
import time# 直接将range(3)传给tqdm,自动生成进度条
# 这个写法我觉得是有点神奇的,直接可以给这个对象内部传入一个可迭代对象,然后自动生成进度条
for i in tqdm(range(3), desc="处理任务", unit="epoch"):time.sleep(1)

 

for i in tqdm(range(3),desc="处理任务",unit="个")这个写法则不需要在循环中调用update()方法,更加简洁
实际上这2种写法都随意选取,这里都介绍下 

# 用tqdm的set_postfix方法在进度条右侧显示实时数据(如当前循环的数值、计算结果等):
from tqdm import tqdm
import timetotal = 0  # 初始化总和
with tqdm(total=10, desc="累加进度") as pbar:for i in range(1, 11):time.sleep(0.3)total += i  # 累加1+2+3+...+10pbar.update(1)  # 进度+1pbar.set_postfix({"当前总和": total})  # 显示实时总和

 

import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
import time
import matplotlib.pyplot as plt
from tqdm import tqdm  # 导入tqdm库用于进度条显示# 设置GPU设备
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(f"使用设备: {device}")# 加载鸢尾花数据集
iris = load_iris()
X = iris.data  # 特征数据
y = iris.target  # 标签数据# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# 归一化数据
scaler = MinMaxScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)# 将数据转换为PyTorch张量并移至GPU
X_train = torch.FloatTensor(X_train).to(device)
y_train = torch.LongTensor(y_train).to(device)
X_test = torch.FloatTensor(X_test).to(device)
y_test = torch.LongTensor(y_test).to(device)class MLP(nn.Module):def __init__(self):super(MLP, self).__init__()self.fc1 = nn.Linear(4, 10)  # 输入层到隐藏层self.relu = nn.ReLU()self.fc2 = nn.Linear(10, 3)  # 隐藏层到输出层def forward(self, x):out = self.fc1(x)out = self.relu(out)out = self.fc2(out)return out# 实例化模型并移至GPU
model = MLP().to(device)# 分类问题使用交叉熵损失函数
criterion = nn.CrossEntropyLoss()# 使用随机梯度下降优化器
optimizer = optim.SGD(model.parameters(), lr=0.01)# 训练模型
num_epochs = 20000  # 训练的轮数# 用于存储每100个epoch的损失值和对应的epoch数
losses = []
epochs = []start_time = time.time()  # 记录开始时间# 创建tqdm进度条
with tqdm(total=num_epochs, desc="训练进度", unit="epoch") as pbar:# 训练模型for epoch in range(num_epochs):# 前向传播outputs = model(X_train)  # 隐式调用forward函数loss = criterion(outputs, y_train)# 反向传播和优化optimizer.zero_grad()loss.backward()optimizer.step()# 记录损失值并更新进度条if (epoch + 1) % 200 == 0:losses.append(loss.item())epochs.append(epoch + 1)# 更新进度条的描述信息pbar.set_postfix({'Loss': f'{loss.item():.4f}'})# 每1000个epoch更新一次进度条if (epoch + 1) % 1000 == 0:pbar.update(1000)  # 更新进度条# 确保进度条达到100%if pbar.n < num_epochs:pbar.update(num_epochs - pbar.n)  # 计算剩余的进度并更新time_all = time.time() - start_time  # 计算训练时间
print(f'Training time: {time_all:.2f} seconds')# # 可视化损失曲线
# plt.figure(figsize=(10, 6))
# plt.plot(epochs, losses)
# plt.xlabel('Epoch')
# plt.ylabel('Loss')
# plt.title('Training Loss over Epochs')
# plt.grid(True)
# plt.show()

 

 

模型的推理:

之前我们说完了训练模型,那么现在我们来测试模型。测试这个词在大模型领域叫做推理(inference),意味着把数据输入到训练好的模型的过程。
 

注意损失和优化器在训练阶段。 

“注意损失和优化器在训练阶段”是指:在深度学习模型的训练阶段(而非测试/评估阶段),损失函数(Loss Function)和优化器(Optimizer)是核心组件,用于更新模型参数;而在测试/评估阶段不需要这两个组件。

具体解释如下:

1. 损失函数(Loss Function)的作用

损失函数用于衡量模型预测值与真实值之间的误差。在训练阶段,我们需要通过损失函数计算当前模型的“错误程度”(例如分类任务常用交叉熵损失)。这个损失值会作为信号,指导优化器调整模型参数。

2. 优化器(Optimizer)的作用

优化器根据损失函数计算出的误差,通过反向传播(Backward Propagation)更新模型的权重参数(例如SGD、Adam等优化器)。训练的核心目标就是通过优化器不断调整参数,使得损失值逐渐降低,模型性能提升。

3. 为什么测试阶段不需要损失和优化器?

测试/评估阶段的目标是验证模型在未见过数据上的表现(如你提供的代码中的model.eval()torch.no_grad())。此时模型参数已经固定(通过训练阶段优化完成),只需前向传播得到预测结果(如outputs = model(X_test)),不需要计算损失(因为不关心“误差多大”,只关心“预测是否正确”),也不需要优化器(因为不更新参数)。

与你当前代码的关系

提供的代码是测试阶段的评估逻辑,因此没有出现损失函数和优化器的代码。但在训练阶段(例如for epoch in range(num_epochs)的循环中),一定会包含类似以下逻辑:

# 训练阶段示例代码(非修改你的原代码)
model.train()  # 开启训练模式
optimizer.zero_grad()  # 清空优化器梯度
outputs = model(X_train)  # 前向传播
loss = criterion(outputs, y_train)  # 计算损失(criterion是损失函数)
loss.backward()  # 反向传播计算梯度
optimizer.step()  # 优化器更新参数
# 在测试集上评估模型,此时model内部已经是训练好的参数了
# 评估模型
model.eval() # 设置模型为评估模式
with torch.no_grad(): # torch.no_grad()的作用是禁用梯度计算,可以提高模型推理速度outputs = model(X_test)  # 对测试数据进行前向传播,获得预测结果_, predicted = torch.max(outputs, 1) # torch.max(outputs, 1)返回每行的最大值和对应的索引#这个函数返回2个值,分别是最大值和对应索引,参数1是在第1维度(行)上找最大值,_ 是Python的约定,表示忽略这个返回值,所以这个写法是找到每一行最大值的下标# 此时outputs是一个tensor,p每一行是一个样本,每一行有3个值,分别是属于3个类别的概率,取最大值的下标就是预测的类别# predicted == y_test判断预测值和真实值是否相等,返回一个tensor,1表示相等,0表示不等,然后求和,再除以y_test.size(0)得到准确率# 因为这个时候数据是tensor,所以需要用item()方法将tensor转化为Python的标量# 之所以不用sklearn的accuracy_score函数,是因为这个函数是在CPU上运行的,需要将数据转移到CPU上,这样会慢一些# size(0)获取第0维的长度,即样本数量correct = (predicted == y_test).sum().item() # 计算预测正确的样本数accuracy = correct / y_test.size(0)print(f'测试集准确率: {accuracy * 100:.2f}%')

模型的评估模式简单来说就是评估阶段会关闭一些训练相关的操作和策略,比如更新参数正则化等操作,确保模型输出结果的稳定性和一致性。


为什么评估模式不关闭梯度计算,推理不是不需要更新参数么?


主要还是因为在某些场景下,评估阶段可能需要计算梯度(虽然不更新参数)。例如:计算梯度用于可视化(如CAM热力图,主要用于cnn相关)。所以为了避免这种需求不被满足,还是需要手动关闭梯度计算。
 @浙大疏锦行

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

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

相关文章

野火鲁班猫(arrch64架构debian)从零实现用MobileFaceNet算法进行实时人脸识别(三)用yolov5-face算法实现人脸检测

环境直接使用第一篇中安装好的环境即可 先clone yolov5-face项目 git clone https://github.com/deepcam-cn/yolov5-face.git 并下载预训练权重文件yolov5n-face.pt 网盘链接: https://pan.baidu.com/s/1xsYns6cyB84aPDgXB7sNDQ 提取码: lw9j &#xff08;野火官方提供&am…

R语言科研编程-柱状图

R语言简介 R语言是一种开源的统计计算和图形绘制编程语言&#xff0c;广泛应用于数据分析、机器学习、数据可视化等领域。它由Ross Ihaka和Robert Gentleman于1993年开发&#xff0c;具有丰富的统计函数库和图形功能&#xff0c;尤其适合数据科学研究和可视化任务。 使用R语言…

Android-Handler学习总结

​​面试官​&#xff1a;你好&#xff01;我看你简历里提到熟悉 Android 的 Handler 机制&#xff0c;能简单说一下它的作用吗&#xff1f; ​候选人​&#xff1a; Handler 是 Android 中用来做线程间通信的工具。比如Android 应用的 UI 线程&#xff08;也叫主线程…

【iOS】分类、扩展、关联对象

分类、扩展、关联对象 前言分类扩展扩展和分类的区别关联对象key的几种用法流程 总结 前言 最近的学习中笔者发现自己对于分类、扩展相关知识并不是很熟悉&#xff0c;刚好看源码类的加载过程中发现有类扩展与关联对象详解。本篇我们来探索一下这部分相关知识&#xff0c;首先…

30.第二阶段x64游戏实战-认识网络数据包发送流程

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;图灵Python学院 上一个内容&#xff1a;29.第二阶段x64游戏实战-技能冷却 发送数据包的方式&#xff08;函数&#xff09;操作系统提供…

【每日一题】【前缀和优化】【前/后缀最值】牛客练习赛139 B/C题 大卫的密码 (Hard Version) C++

牛客练习赛139 B题 大卫的密码 (Easy Version) 牛客练习赛139 C题 大卫的密码 (Hard Version) 大卫的密码 题目背景 牛客练习赛139 题目描述 给定一个 n m n\times m nm的网格图&#xff0c;我们使用 ( i , j ) (i,j) (i,j)表示网格中从上往下数第 i i i行和从左往右数第…

文件夹图像批处理教程

前言 因为经常对图像要做数据清洗&#xff0c;又很费时间去重新写一个&#xff0c;我一直在想能不能写一个通用的脚本或者制作一个可视化的界面对文件夹图像做批量的修改图像大小、重命名、划分数据训练和验证集等等。这里我先介绍一下我因为写过的一些脚本&#xff0c;然后我…

【Unity实战笔记】第二十四 · 使用 SMB+Animator 实现基础战斗系统

转载请注明出处&#xff1a;&#x1f517;https://blog.csdn.net/weixin_44013533/article/details/146409453 作者&#xff1a;CSDN|Ringleader| 1 结构 1.1 状态机 1.2 SMB 2 代码实现 2.1 核心控制 Player_Base_SMB 继承 StateMachineBehaviour &#xff0c;控制变量初始…

Python虚拟环境再PyCharm中自由切换使用方法

Python开发中的环境隔离是必不可少的步骤,通过使用虚拟环境可以有效地管理不同项目间的依赖,避免包冲突和环境污染。虚拟环境是Python官方提供的一种独立运行环境,每个项目可以拥有自己单独的环境,不同项目之间的环境互不影响。在日常开发中,结合PyCharm这样强大的IDE进行…

大模型智能体入门扫盲——基于camel的概述

前言 本篇博客想带读者进行一个智能体入门扫盲&#xff0c;了解基础知识&#xff0c;为什么用camel呢&#xff0c;因为小洛发现它们文档对这种智能体的基本组件介绍得很全面深入。 基础概念 agent 一个典型的agent智能体包含三个核心部分&#xff1a; 感知模块&#xff1…

目标检测 RT-DETR(2023)详细解读

文章目录 主干网络&#xff1a;Encoder&#xff1a;不确定性最小Query选择Decoder网络&#xff1a; 将DETR扩展到实时场景&#xff0c;提高了模型的检测速度。网络架构分为三部分组成&#xff1a;主干网络、混合编码器、带有辅助预测头的变换器编码器。具体来说&#xff0c;先利…

DeepSeek 赋能数字农业:从智慧种植到产业升级的全链条革新

目录 一、数字农业的现状与挑战二、DeepSeek 技术解析2.1 DeepSeek 的技术原理与优势2.2 DeepSeek 在人工智能领域的地位与影响力 三、DeepSeek 在数字农业中的应用场景3.1 精准种植决策3.2 病虫害监测与防治3.3 智能灌溉与施肥管理3.4 农产品质量追溯与品牌建设 四、DeepSeek …

<uniapp><vuex><状态管理>在uniapp中,如何使用vuex实现数据共享与传递?

前言 本专栏是基于uniapp实现手机端各种小功能的程序&#xff0c;并且基于各种通讯协议如http、websocekt等&#xff0c;实现手机端作为客户端&#xff08;或者是手持机、PDA等&#xff09;&#xff0c;与服务端进行数据通讯的实例开发。 发文平台 CSDN 环境配置 系统&…

高速串行差分信号仿真分析及技术发展挑战续

7.3 3.125Gbps 差分串行信号设计实例仿真分析 7.3.1 设计用例说明 介绍完 Cadence 系统本身所具有的高速差分信号的仿真分析功能之后&#xff0c;我们以一个实例来说明 3.125Gbps 以下的高速差分系统的仿真分析方法。 在网上下载的设计文件“Booksi_Demo_Allegro160_Finishe…

【Golang】部分语法格式和规则

1、时间字符串和时间戳的相互转换 func main() {t1 : int64(1546926630) // 外部传入的时间戳&#xff08;秒为单位&#xff09;&#xff0c;必须为int64类型t2 : "2019-01-08 13:50:30" // 外部传入的时间字符串//时间转换的模板&#xff0c;golang里面只能是 &quo…

第十六章:数据治理之数据架构:数据模型和数据流转关系

本章我们说一下数据架构&#xff0c;说到数据架构&#xff0c;就很自然的想到企业架构、业务架构、软件架构&#xff0c;因为个人并没有对这些内容进行深入了解&#xff0c;所以这里不做比对是否有相似或者共通的地方&#xff0c;仅仅来说一下我理解的数据架构。 1、什么是架构…

Day126 | 灵神 | 二叉树 | 层数最深的叶子结点的和

Day126 | 灵神 | 二叉树 | 层数最深的叶子结点的和 1302.层数最深的叶子结点的和 1302. 层数最深叶子节点的和 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 这道题用层序遍历的思路比较好想&#xff0c;就把每层的都算一下&#xff0c;然后返回最后一层的和就…

PCIE 4.0 vs PCIE 5.0固态硬盘——区别、科普与选购场景全解析

随着数字内容和高性能计算需求的爆发&#xff0c;固态硬盘&#xff08;SSD&#xff09;已成为PC、游戏主机和工作站不可或缺的核心硬件。面对市面上层出不穷的新一代SSD产品&#xff0c;大家最常见的一个疑惑&#xff1a;**PCIe 4.0和PCIe 5.0固态硬盘&#xff0c;到底有啥区别…

vue pinia 独立维护,仓库统一导出

它允许您跨组件/页面共享状态 持久化 安装依赖pnpm i pinia-plugin-persistedstate 将插件添加到 pinia 实例上 pinia独立维护 统一导出 import { createPinia } from pinia import piniaPluginPersistedstate from pinia-plugin-persistedstateconst pinia creat…

Dify源码学习

文章目录 1 大模型基本原理1.1 model_context_tokens、max_tokens和prompt_tokens1.1.1 三者之间的关系1.1.2 总结对比 2 Dify源代码2.0 前后端代码跑起来【0】准备开发环境【1】下载代码【2】运行后端&#xff08;1&#xff09;Start the docker-compose stack&#xff08;2&a…