人工智能底层自行实现篇3——逻辑回归(下)

3. 代码实现


接上一篇文章

3.1 问题背景

应用案例背景

假设我们有一个数据集,包含患者的多种生理指标(如年龄、性别、体重指数(BMI)、血糖水平等)以及他们是否被诊断为糖尿病(是或否)。我们的目标是建立一个逻辑回归模型,根据这些生理指标预测一个患者是否有糖尿病的概率。

数据集表示

假设我们的数据集包含以下特征:

  • X 1 X_1 X1: 年龄
  • X 2 X_2 X2: 性别(0表示女性,1表示男性)
  • X 3 X_3 X3: 体重指数(BMI)
  • X 4 X_4 X4: 血糖水平
  • Y Y Y: 是否有糖尿病(0表示没有,1表示有)
逻辑回归模型

我们将使用逻辑回归模型来预测 P ( Y = 1 ∣ X ) P(Y=1|X) P(Y=1∣X),即给定生理指标X时,患者有糖尿病的概率。模型的形式为:

P ( Y = 1 ∣ X ) = 1 1 + e − ( β 0 + β 1 X 1 + β 2 X 2 + β 3 X 3 + β 4 X 4 ) P(Y=1|X) = \frac{1}{1 + e^{-(\beta_0 + \beta_1X_1 + \beta_2X_2 + \beta_3X_3 + \beta_4X_4)}} P(Y=1∣X)=1+e(β0+β1X1+β2X2+β3X3+β4X4)1

3.2 数据准备

# 模拟创建数据
import pandas as pd
import numpy as np
# 设置随机种子以保证结果可复现
np.random.seed(0)
# 创建数据
data_size = 1000  # 数据集大小
# 年龄范围从20到80
ages = np.random.randint(20, 80, size=data_size)
# 性别为0或1
genders = np.random.randint(0, 2, size=data_size)
# BMI范围从18到35
bmis = np.random.uniform(18, 35, size=data_size)
# 血糖水平范围从70到140
glucose_levels = np.random.uniform(70, 140, size=data_size)
# 指定结果:是否有糖尿病
labels = np.random.randint(0, 2, size=data_size)
# 定义结果变量——先假定一个模型来生成数据的结果
# 使用逻辑函数生成糖尿病的概率,并依此生成0或1的标签
beta = np.array([-8, 0.05, 0.25, 0.1, 0.05])  # 假定的模型参数
X = np.column_stack((np.ones(data_size), ages, genders, bmis, glucose_levels))
linear_combination = X.dot(beta)
probabilities = 1 / (1 + np.exp(-linear_combination))
labels = np.random.binomial(1, probabilities)# 创建DataFrame
df = pd.DataFrame({'Age': ages,'Gender': genders,'BMI': bmis,'Glucose_Level': glucose_levels,'Diabetes': labels
})# 显示前几行数据
print(df.head())
   Age  Gender        BMI  Glucose_Level  Diabetes
0   64       1  21.150926      74.332242         1
1   67       0  34.928860     127.491243         1
2   73       0  20.199048      96.576651         1
3   20       1  26.014774     110.008514         1
4   23       1  19.157583     138.848879         1

3.3 数据探索

# 数据集中有多少患者被诊断为糖尿病
print(df['Diabetes'].value_counts())
1    880
0    120
Name: Diabetes, dtype: int64

3.4 手动实现逻辑回归

逻辑回归模型的训练过程就是最大化似然函数的过程。我们可以使用梯度下降法来最大化似然函数。下面我们将手动实现逻辑回归模型的训练过程。

使用梯度下降来最大化逻辑回归的似然函数,实际上我们通常是在最小化对数似然函数的负值,这被称为对数损失或交叉熵损失。这种方法称为梯度下降,其目标是找到一组参数(权重和偏置),使得损失函数最小化。
公式为:
J ( w , b ) = − ∑ i = 1 n [ y ( i ) log ⁡ ( σ ( z ( i ) ) ) + ( 1 − y ( i ) ) log ⁡ ( 1 − σ ( z ( i ) ) ) ] J(\mathbf{w}, b) = -\sum_{i=1}^n \left[y^{(i)} \log(\sigma(z^{(i)})) + (1 - y^{(i)}) \log(1 - \sigma(z^{(i)}))\right] J(w,b)=i=1n[y(i)log(σ(z(i)))+(1y(i))log(1σ(z(i)))]

其中 β 0 \beta_0 β0就是b,w就是 β 1 到 β n \beta_1 到 \beta_n β1βn,z就是线性组合 β 0 + β 1 X 1 + β 2 X 2 + β 3 X 3 + β 4 X 4 \beta_0 + \beta_1X_1 + \beta_2X_2 + \beta_3X_3 + \beta_4X_4 β0+β1X1+β2X2+β3X3+β4X4 σ \sigma σ就是sigmoid函数。
现在我们的目标就是最小化上面的公式,要求它的最小值对应的 β \beta β,我们就又需要用到梯度下降法了。
在梯度下降法中,我们更新权重 w \mathbf{w} w 和偏置 b b b 以最小化损失 J J J,更新规则为:

w ← w − α ∇ w J \mathbf{w} \leftarrow \mathbf{w} - \alpha \nabla_{\mathbf{w}} J wwαwJ

b ← b − α ∂ J ∂ b b \leftarrow b - \alpha \frac{\partial J}{\partial b} bbαbJ

所以现在我们就先要对上面的公式求导,求出梯度,然后再用梯度下降法来更新 β \beta β

β 0 \beta_0 β0 的偏导数(对于偏置项)

  1. 写出损失函数 J J J
    J ( w , b ) = − ∑ i = 1 n [ y ( i ) log ⁡ ( σ ( z ( i ) ) ) + ( 1 − y ( i ) ) log ⁡ ( 1 − σ ( z ( i ) ) ) ] J(w, b) = -\sum_{i=1}^n \left[y^{(i)} \log(\sigma(z^{(i)})) + (1 - y^{(i)}) \log(1 - \sigma(z^{(i)}))\right] J(w,b)=i=1n[y(i)log(σ(z(i)))+(1y(i))log(1σ(z(i)))]
  2. 写出 z ( i ) z^{(i)} z(i)
    z ( i ) = β 0 + β 1 x 1 ( i ) + … + β n x n ( i ) z^{(i)} = \beta_0 + \beta_1 x_1^{(i)} + \ldots + \beta_n x_n^{(i)} z(i)=β0+β1x1(i)++βnxn(i)
  3. z ( i ) z^{(i)} z(i) β 0 \beta_0 β0 的偏导数:
    ∂ z ( i ) ∂ β 0 = 1 \frac{\partial z^{(i)}}{\partial \beta_0} = 1 β0z(i)=1
  4. 对 Sigmoid 函数求导:
    d σ d z = σ ( z ) ⋅ ( 1 − σ ( z ) ) \frac{d\sigma}{dz} = \sigma(z) \cdot (1 - \sigma(z)) dzdσ=σ(z)(1σ(z))
    其中, σ ( z ) = 1 1 + e − z \sigma(z) = \frac{1}{1 + e^{-z}} σ(z)=1+ez1
  5. 对损失函数 J J J 关于 σ ( z ( i ) ) \sigma(z^{(i)}) σ(z(i)) 求偏导数:
    ∂ J ∂ σ ( z ( i ) ) = − ( y ( i ) σ ( z ( i ) ) − 1 − y ( i ) 1 − σ ( z ( i ) ) ) \frac{\partial J}{\partial \sigma(z^{(i)})} = -\left(\frac{y^{(i)}}{\sigma(z^{(i)})} - \frac{1 - y^{(i)}}{1 - \sigma(z^{(i)})}\right) σ(z(i))J=(σ(z(i))y(i)1σ(z(i))1y(i))
  6. 应用链式法则得到 J J J 关于 β 0 \beta_0 β0 的偏导数:
    ∂ J ∂ β 0 = ∑ i = 1 n ∂ J ∂ σ ( z ( i ) ) ⋅ d σ d z ( i ) ⋅ ∂ z ( i ) ∂ β 0 \frac{\partial J}{\partial \beta_0} = \sum_{i=1}^n \frac{\partial J}{\partial \sigma(z^{(i)})} \cdot \frac{d\sigma}{dz^{(i)}} \cdot \frac{\partial z^{(i)}}{\partial \beta_0} β0J=i=1nσ(z(i))Jdz(i)dσβ0z(i)
  7. 计算最终的偏导数表达式:
    ∂ J ∂ β 0 = ∑ i = 1 n ( σ ( z ( i ) ) − y ( i ) ) \frac{\partial J}{\partial \beta_0} = \sum_{i=1}^n \left(\sigma(z^{(i)}) - y^{(i)}\right) β0J=i=1n(σ(z(i))y(i))

β j \beta_j βj 的偏导数(对于权重项)

  1. z ( i ) z^{(i)} z(i) β j \beta_j βj 的偏导数:
    ∂ z ( i ) ∂ β j = x j ( i ) \frac{\partial z^{(i)}}{\partial \beta_j} = x_j^{(i)} βjz(i)=xj(i)

  2. 使用链式法则得到 J J J 关于 β j \beta_j βj 的偏导数:
    ∂ J ∂ β j = ∑ i = 1 n ∂ J ∂ σ ( z ( i ) ) ⋅ d σ d z ( i ) ⋅ ∂ z ( i ) ∂ β j \frac{\partial J}{\partial \beta_j} = \sum_{i=1}^n \frac{\partial J}{\partial \sigma(z^{(i)})} \cdot \frac{d\sigma}{dz^{(i)}} \cdot \frac{\partial z^{(i)}}{\partial \beta_j} βjJ=i=1nσ(z(i))Jdz(i)dσβjz(i)

  3. 计算最终的偏导数表达式:
    ∂ J ∂ β j = ∑ i = 1 n ( σ ( z ( i ) ) − y ( i ) ) x j ( i ) \frac{\partial J}{\partial \beta_j} = \sum_{i=1}^n \left(\sigma(z^{(i)}) - y^{(i)}\right) x_j^{(i)} βjJ=i=1n(σ(z(i))y(i))xj(i)

    在实际的算法实现中,这些导数会用来更新 β 0 \beta_0 β0 β j \beta_j βj

因为 σ ( z ( i ) ) \sigma(z^{(i)}) σ(z(i))其实就是我们的预测值,所以这个公式的意思就是我们的预测值减去实际值,然后再求和,就是我们的偏导数。

β 0 : = β 0 − α ∂ J ∂ β 0 \beta_0 := \beta_0 - \alpha \frac{\partial J}{\partial \beta_0} β0:=β0αβ0J
β j : = β j − α ∂ J ∂ β j \beta_j := \beta_j - \alpha \frac{\partial J}{\partial \beta_j} βj:=βjαβjJ

  1. 定义 Sigmoid 函数: 这是逻辑回归中的核心函数,将线性组合映射到 (0, 1) 区间。
  2. 定义损失函数: 这个函数计算当前权重和偏置下的对数损失。
  3. 定义梯度计算函数: 计算损失函数关于每个参数的梯度。
  4. 定义梯度下降更新规则: 使用计算得到的梯度更新权重和偏置。
  5. 执行训练过程: 迭代执行梯度下降步骤,直至满足收敛条件或达到指定的迭代次数。
# 定义 Sigmoid 函数
def sigmoid(z):return 1 / (1 + np.exp(-z))

定义损失函数
公式为:J(w, b) = − ∑ i = 1 n [ y ( i ) log ⁡ ( σ ( z ( i ) ) + ( 1 − y ( i ) ) log ⁡ ( 1 − σ ( z ( i ) ) ) ] -\sum_{i=1}^n [y^{(i)} \log(\sigma(z^{(i)}) + (1 - y^{(i)}) \log(1 - \sigma(z^{(i))})] i=1n[y(i)log(σ(z(i))+(1y(i))log(1σ(z(i)))]

# 定义对数损失函数——我们的目的就是让损失最小,就是让似然函数最大,当求的这些beta能够使得损失最小的时候,就是我们的最优解,beta就是我们的最优参数
def compute_loss(X, y, w, b):# 对应上面的z=(β0+β1X1+β2X2+β3X3+β4X4)z = np.dot(X, w) + b probs = sigmoid(z)# np.mean()求损失的均值loss = -np.mean(y * np.log(probs) + (1 - y) * np.log(1 - probs))return loss

在 compute_gradients 函数中,参数的含义如下:

X: 特征数据矩阵。它是一个二维数组,其中每一行代表一个训练样本,每一列代表一个特征。
y: 标签向量。它是一个一维数组,包含与特征矩阵 X 中的每一行相对应的标签。在二分类逻辑回归中,这些标签通常是 0 或 1。
w: 权重向量。这是一个一维数组,其中每个元素对应于 X 矩阵中某个特征的权重。
b: 偏置项。这是一个标量,它与权重向量 w 一起决定了模型的预测。

# 定义梯度计算函数——这个函数就是对上面的损失函数求导,求出梯度
# w对应beta1到beta4,b对应beta0,X对应X1到X4,y对应Y(实际的值)
def compute_gradients(X, y, w, b):z = np.dot(X, w) + bprobs = sigmoid(z)error = probs - y # 对应sigmoid(z)-y# 梯度计算,就是前面推导的公式grad_w = np.dot(X.T, error) / len(y) # 对应(1/n)*sum((sigmoid(z)-y)*X)grad_b = np.mean(error) # 对应(1/n)*sum(sigmoid(z)-y)return grad_w, grad_b
# 定义梯度下降函数
def gradient_descent(X, y, w, b, alpha, iterations):''':param X: 表示特征数据矩阵:param y: 表示标签向量(实际值):param w: 权重向量:param b: 偏置项:param alpha: 学习率——就是我们的步长,每一次更新多少,是一个自己定义的参数:param iterations: 迭代次数——就是我们的梯度下降要迭代多少次:return: 返回最终的权重和偏置'''for i in range(iterations):grad_w, grad_b = compute_gradients(X, y, w, b)# 更新权重和偏置w -= alpha * grad_wb -= alpha * grad_b# 每迭代一定次数打印损失if i % 100 == 0:print(f"Iteration {i}: Loss = {compute_loss(X, y, w, b)}")return w, b

准备数据

  • X 1 X_1 X1: 年龄
  • X 2 X_2 X2: 性别(0表示女性,1表示男性)
  • X 3 X_3 X3: 体重指数(BMI)
  • X 4 X_4 X4: 血糖水平
  • Y Y Y: 是否有糖尿病(0表示没有,1表示有)
# 准备数据
# x = df的前四列,y = df的最后一列
X = df.iloc[:, :-1].values # iloc是通过行号来取行数据的,这里取所有行,去掉最后一列
y = df.iloc[:, -1].values # 取所有行,取最后一列
X.shape, y.shape
((1000, 4), (1000,))
# 将X和y分为训练集和测试集
from sklearn.model_selection import train_test_split
# 这里就是把X和y分为训练集和测试集,test_size=0.2表示测试集占20%,random_state=0表示随机种子,保证每次运行结果一样
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
# 特征标准化——目的是让数据的均值为0,方差为1,这样可以加快梯度下降的收敛速度
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# 初始化权重和偏置
# 这里的w是一个一维数组,长度为X_train的列数,也就是特征的个数,这里是4
w = np.zeros(X_train.shape[1])
b = 0
# 训练模型
# 这里的alpha是学习率,iterations是迭代次数
w, b = gradient_descent(X_train, y_train, w, b, alpha=0.1, iterations=10000)
Iteration 0: Loss = 0.67694848293987
Iteration 100: Loss = 0.31170512579698983
Iteration 200: Loss = 0.28006450564964497
Iteration 300: Loss = 0.26967717122142904
Iteration 400: Loss = 0.2649489155820069
Iteration 500: Loss = 0.26246507021700166
Iteration 600: Loss = 0.2610482148241369
Iteration 700: Loss = 0.26019578953398675
.........................................
Iteration 8300: Loss = 0.2586331617938211
Iteration 8400: Loss = 0.25863316179381984
Iteration 8500: Loss = 0.2586331617938189
Iteration 8600: Loss = 0.25863316179381834
Iteration 8700: Loss = 0.25863316179381785
Iteration 8800: Loss = 0.2586331617938175
Iteration 8900: Loss = 0.2586331617938173
Iteration 9000: Loss = 0.2586331617938171
Iteration 9100: Loss = 0.25863316179381696
Iteration 9200: Loss = 0.25863316179381696
Iteration 9300: Loss = 0.2586331617938169
Iteration 9400: Loss = 0.25863316179381685
Iteration 9500: Loss = 0.25863316179381685
Iteration 9600: Loss = 0.2586331617938168
Iteration 9700: Loss = 0.2586331617938168
Iteration 9800: Loss = 0.2586331617938168
Iteration 9900: Loss = 0.2586331617938168
# 训练好模型后,我们可以使用它来进行预测
# 预测概率
test_probs = sigmoid(np.dot(X_test, w) + b)
# 预测类别
test_preds = np.where(test_probs > 0.5, 1, 0)
test_preds
array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1])
# 计算准确率
from sklearn.metrics import accuracy_score
accuracy = accuracy_score(y_test, test_preds)
accuracy
0.885
# 比较真实值和预测值
results = pd.DataFrame({'Actual': y_test,'Predicted': test_preds,'Probability': test_probs
})
results.head(100)
ActualPredictedProbability
0110.974574
1110.961203
2110.874061
3110.996859
4110.832528
............
95010.873257
96110.944671
97110.903943
98110.979292
99110.998257

100 rows × 3 columns

# 最终的权重和偏置
print(f"Weight: {w}")
print(f"Bias: {b}")
# 最终准确度
print(f"Final Accuracy: {accuracy}")
Weight: [1.41949725 0.42282911 0.70729532 0.90150334]
Bias: 3.0447132565927673
Final Accuracy: 0.885

总结

在这个项目中,我们手动实现了逻辑回归模型的训练过程。我们首先定义了 Sigmoid 函数和对数损失函数,然后使用梯度下降法最小化损失函数。我们将这个模型应用于一个模拟数据集,其中包含患者的生理指标和是否患有糖尿病的标签。最终,我们评估了模型的准确性,并展示了预测结果。
通过最终的结果,我们可以看到我们的模型在测试集上的准确率为 0.885,说明我们的逻辑回归模型在这个数据集上表现还是不错的。

补充——采用sklearn库实现逻辑回归
# 使用sklearn库实现逻辑回归
from sklearn.linear_model import LogisticRegression
# 创建逻辑回归模型
model = LogisticRegression()
# 训练模型
model.fit(X_train, y_train)
# 预测
y_pred = model.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
accuracy
0.885
# 比较调库实现的逻辑回归和手动实现的逻辑回归的权重和偏置
print("Manual Model:")
print(f"Weight: {w}")
print(f"Bias: {b}")
print("\nSklearn Model:")
print(f"Weight: {model.coef_}")
print(f"Bias: {model.intercept_}")
Manual Model:
Weight: [1.41949725 0.42282911 0.70729532 0.90150334]
Bias: 3.0447132565927673Sklearn Model:
Weight: [[1.37051336 0.40978953 0.68512706 0.87338347]]
Bias: [2.988773]
可以发现,两者的权重和偏置非常接近,这说明我们手动实现的逻辑回归模型是正确的。同时,我们也可以看到,使用sklearn库实现的逻辑回归模型的准确率与我们手动实现的模型准确率相同,这说明我们的模型在这个数据集上表现良好。

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

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

相关文章

Vue3 el-table 动态高度(element-plus)

先回顾一下vue2element-ui的策略 export default (config) > {const {subtractHeight 250,} config;return {data() {return {subtractHeight,// 列表高度tableHeight: ${document.body.clientHeight - this.subtractHeight}px,};},created() {window.addEventListener(r…

RUST学习过程

一、基础知识&#xff1a; todo!&#xff1a;这个宏用来标记未实现功能。可以不写retuen的写法(if/else不能写分号&#xff0c;break带分号&#xff0c;loop写不写看情况)&#xff1a; fn fib(n: u32) -> u32 {if n < 2 {// The base case.1} else {// The recursive c…

vue-router学习9:过渡动效transition

<transition> 组件 <transition> 是 Vue 提供的一个内置组件&#xff0c;它可以为被包裹的元素或组件添加进入、离开和列表的过渡效果。当包裹的元素或组件的状态改变时&#xff08;例如&#xff0c;v-if 的条件变化或路由切换&#xff09;&#xff0c;<transi…

(python)动态规划

前言 曾经有一位叫做小明的年轻人,他生活在一个被困在连绵不断的山脉中的村庄里。这座村庄每年都会受到洪水的威胁,而村民们只能通过一条崎岖而危险的小路逃离洪水的侵袭。小明决定解决这个问题。他花了很长时间研究了地形图和洪水的模式,最终他发现了一种方法:他可以在山脚…

『大模型OS笔记』Meta 宣布推出 Llama 3 的介绍视频

Meta 宣布推出 Llama 3 的介绍视频 文章目录 一. Meta 宣布推出 Llama 3 的介绍视频一、引言二、Llama 模型历史回顾三、Llama 3 模型介绍四、Llama 3 背后的开发思路五、许可证和生态系统六、安全和信任七、其他亮点八、未来计划九、现场演示四. 参考文献一. Meta 宣布推出 Ll…

[iOS]APP优化

一、性能优化 性能优化是一个至关重要的过程&#xff0c;它对提高应用的用户体验、增强应用的市场竞争力以及维持用户的长期参与度具有深远的影响。 1.CPU 使用优化 工具&#xff1a;Instruments (Time Profiler)使用方法&#xff1a;利用 Xcode 的 Instruments 工具中的 Ti…

Unity 异步与工作线程(多线程)

文章目录 前言一、异步加载二、工作线程总结 前言 工作线程&#xff08;多线程&#xff09;是指在一个程序中同时执行多个任务的能力。多线程编程可以提高程序的性能和响应性&#xff0c;特别是在需要同时执行多个任务的情况下。工作线程通常用于执行耗时的任务&#xff0c;以…

linux驱动-CCF-2 of_clk_provider

CCF: common clock frameword of_clk_provider 总结 1. provider 注册时钟 hws[i] desc->clk_register(cprman, desc->data); 参考https://mp.csdn.net/mp_blog/creation/editor/138153040 2. provider 注册 of_clk_provider 1. provider 创建了of_clk_provider 结构体…

R语言 统计篇之相关性分析与线性回归

《Cookbook for R》数据统计篇 相关性分析与线性回归 示例数据 # 生成一些数据 # X 呈增加趋势 # Z 呈增加趋势 (缓慢) # Y 与 xvar 成反比&#xff0c;xvar*zvar 成正比set.seed(955) xvar <- 1:20 rnorm(20,sd3) zvar <- 1:20/4 rnorm(20,sd2) yvar <- -2*xvar…

FebHost:摩洛哥.ma域名注册介绍,规则有哪些?

摩洛哥国家域名介绍 摩洛哥是位于非洲西北部的一个国家&#xff0c;北部和西部面向地中海和大西洋&#xff0c;东部和南部则与阿尔及利亚、西撒哈拉和毛里塔尼亚接壤。摩洛哥的首都是拉巴特&#xff0c;但最大城市是卡萨布兰卡。摩洛哥的官方语言是阿拉伯语和柏柏尔语&#xf…

token接口设计

token接口设计 登录/注册&#xff1a;Token生成&#xff1a;Token验证&#xff1a;Token刷新&#xff1a;总结 登录/注册&#xff1a; 首先&#xff0c;用户通过提交用户名和密码或其他认证方式登录系统&#xff0c;服务器验证通过后&#xff0c;生成Token。 Token生成&#x…

使用 Python 和 DirectShow 从相机捕获图像

在 Python 中使用 OpenCV 是视觉应用程序原型的一个非常好的解决方案,它允许您快速起草和测试算法。处理从文件中读取的图像非常容易,如果要处理从相机捕获的图像,则不那么容易。OpenCV 提供了一些基本方法来访问链接到 PC 的相机(通过对象),但大多数时候,即使对于简单的…

Github创建远程仓库(项目)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

制作Android分区镜像

1 python生成一个sector数据 def get_oem_bootmode(): # Header size SECTOR_SIZE_IN_BYTES 512 header [0 for i in \ range(SECTOR_SIZE_IN_BYTES)] # magic # The ord() built-in function in # Python converts a character # into …

MongoDB的安装(Linux环境)

登录到Linux服务器执行 lsb_release -a &#xff0c;即可得知服务器的版本信息为&#xff1a;CentOS 7。 # CentOS安装lsb_release包 [rootlinux100 ~]# sudo yum install redhat-lsb# 查看Linux版本 [rootlinux100 ~]# lsb_release -a LSB Version: :core-4.1-amd64:core-…

git tag管理

1. Git 创建tag并推送到云端 首先&#xff0c;在本地创建一个新的tag&#xff0c;可以使用 -a 选项添加带有注释信息的annotated tag&#xff0c;或直接创建lightweight tag。例如&#xff0c;若要标记最近一次提交为 v1.0 并附带注释信息&#xff1a; # 创建带有注释信息的a…

Blender笔记之基本操作

code review! —— 2024-04-27 杭州 Blender笔记…

c++理论篇(一) ——浅谈tcp缓存与tcp的分包与粘包

介绍 在网络通讯中,Linux系统为每一个socket创建了接收缓冲区与发送缓冲区,对于TCP协议来说,这两个缓冲区是必须的.应用程序在调用send/recv函数时,Linux内核会把数据从应用进程拷贝到socket的发送缓冲区中,应用程序在调用recv/read函数时,内核把接收缓冲区中的数据拷贝到应用…

黑马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day1

你好,我是Qiuner. 为记录自己编程学习过程和帮助别人少走弯路而写博客 这是我的 github gitee 如果本篇文章帮到了你 不妨点个赞吧~ 我会很高兴的 &#x1f604; (^ ~ ^) 想看更多 那就点个关注吧 我会尽力带来有趣的内容 2024黑马程序员 SpringCloud微服务开发与实战&#xff…

FPGA高端项目:FPGA帧差算法多目标图像识别+目标跟踪,提供11套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐FPGA帧差算法单个目标图像识别目标跟踪 3、详细设计方案设计原理框图运动目标检测原理OV5640摄像头配置与采集OV7725摄像头配置与采集RGB视频流转AXI4-StreamVDMA图像缓存多目标帧差算法图像识别目标跟踪模块视频输出Xilinx系列FPGA工程源…