text传输页面

这篇论文提出了以下具体的可变导向车道优化方法:

  1. 确定可变导向车道设置阈值的方法,并改善了可变导向车道自适应控制系统。
  2. 对交叉口转向交通流不均衡特性及不均衡程度进行研究,分析了交叉口进口道交通流的运行与排队特征,阐述了交叉口供需间的不匹配关系,并进一步分析转向交通分布的各类影响因素,总结了转向交通不均衡特性。
  3. 研究了设置可变导向车道的阈值与最佳范围。通过调查国内典型城市可变导向车道的设置,将其设置形式分为三类进行了阐述,总结了交叉口设置可变导向车道需满足的渠化条件、交通条件及信号控制条件;为确定设置可变导向车道的流量临界条件及最佳范围,本文以左转可变导向车道为例,将可变导向车道设置前后进口道车均延误相等作为目标,构建等车均延误模型,求解得左转流量比例阈值及最佳范围,并通过实例验证了方法的可行性。

(参考页码:摘要第一段、第二段;第一章绪论第二节、第三节)

好的,具体讲一下阈值方法。本文提出的阈值方法是针对左转可变导向车道的设置而言的。该方法通过构建等车均延误模型,利用试值法对模型进行求解,绘制阈值曲线图,确定左转流量比例阈值及最佳范围。

具体流程如下:

  1. 得到交叉口数据,包括交叉口车道数N、设置可变导向车道前后车道组车道数、信号周期时长C、绿信比、饱和流率等参数。
  2. 给定一组判别条件值即左转流量和直行流量,代入等车均延误模型中计算设置可变导向车道前后进口道各转向车道组车均延误。
  3. 保持直行流量不变,不断改变左转流量,直到确定满足式(3-4)的左转流量值,并标记这组流量值。
  4. 改变直行车流量,然后返回步骤2,不断重复后得到满足式(3-4)的不同流量组合。
  5. 将直行流量作为横坐标,左转流量作为纵坐标,在坐标系中标记各个流量组合,并对组合值进行拟合即可绘制阈值曲线。

通过上述步骤可以得到设置可变导向车道前后的阈值曲线图。该图将坐标系分为两部分:上部分表示设置可变导向车道后车均延误减小,下部分表示设置可变导向车道后车均延误增大。通过该曲线图可以判断一个交叉口是否应该设置可变导向车道。当实际交叉口转向流量在满
细讲第一点
好的,我来详细讲一下第一点,即确定可变导向车道设置阈值的方法,并改善了可变导向车道自适应控制系统。

本文提出的方法是基于等车均延误模型,通过试值法求解得到左转流量比例阈值及最佳范围。具体步骤如下:

  1. 首先,得到交叉口数据,包括交叉口车道数N、设置可变导向车道前后车道组车道数、信号周期时长C、绿信比、饱和流率等参数。
  2. 然后,将原本交叉口渠化条件作为不设置可变导向车道时的情况,一条直行车道变为左转车道作为设置后情况。
  3. 接着,给定一组判别条件值即左转流量和直行流量,代入等车均延误模型中计算设置可变导向车道前后进口道各转向车道组车均延误。
  4. 保持直行流量不变,不断改变左转流量,直到确定满足式(3-4)的左转流量值,并标记这组流量值。
  5. 改变直行车流量,然后返回步骤3和4,不断重复后得到满足式(3-4)的不同流量组合。
  6. 将直行流量作为横坐标,左转流量作为纵坐标,在坐标系中标记各个流量组合,并对组合值进行拟合即可绘制阈值曲线。

通过上述步骤可以得到设置可变导向车道前后的阈值曲线图。该图将坐标系分为两部分:上部分表示设置可变导向车道后车均延误减小

机器学习-静态图和动态图的区别

主要内容如下

  • 什么是静态图
  • 什么是动态图
  • 什么是优化器,优化器是干什么的?
  • 静态图的弊端
  • 动态图的动态计算图是什么意思,可否修改动态图实现动态计算图的底层机制
    举一个简单例子展示下动态图和静态图尽可能简单
    假设我们要用 TensorFlow 实现一个简单的线性回归模型 y = wx + b,其中 w 和 b 是需要学习的参数,x 是输入数据。

在静态图中,我们需要定义计算图,并在图中定义变量 w 和 b,如下所示:

python
Copy code
import tensorflow as tf

定义计算图

graph = tf.Graph()
with graph.as_default():

定义变量

w = tf.Variable(0.0, name='w')
b = tf.Variable(0.0, name='b')

# 定义输入和输出
x = tf.placeholder(tf.float32, name='x')
y = tf.placeholder(tf.float32, name='y')
y_pred = w * x + b

# 定义损失函数和优化器
loss = tf.reduce_mean(tf.square(y - y_pred))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
train_op = optimizer.minimize(loss)

在上面的代码中,我们先定义了一个计算图 graph,然后在图中定义了变量 w 和 b,输入和输出 x、y 和 y_pred,损失函数 loss 和优化器 optimizer。最后,我们使用 train_op 来进行梯度下降优化。

在动态图中,我们不需要事先定义计算图,可以直接使用 TensorFlow 的函数来定义模型,如下所示:

python
Copy code
import tensorflow as tf

定义模型

w = tf.Variable(0.0, name='w')
b = tf.Variable(0.0, name='b')
x = tf.placeholder(tf.float32, name='x')
y = tf.placeholder(tf.float32, name='y')
y_pred = w * x + b

定义损失函数和优化器

loss = tf.reduce_mean(tf.square(y - y_pred))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
train_op = optimizer.minimize(loss)
在上面的代码中,我们直接定义了变量 w 和 b,输入和输出 x、y 和 y_pred,损失函数 loss 和优化器 optimizer,然后使用 train_op 来进行梯度下降优化。

需要注意的是,在上面的代码中,我们使用了 TensorFlow 的变量来定义 w 和 b。这些变量在每次迭代中都会被更新,从而使模型能够逐渐逼近最优解。因此,无论是在动态图还是静态图中,我们都需要定义变量来存储需要学习的参数。

pp oo
静态图例子中似乎只有一层神经网络,至少我看起来是这样,还有我可以认为w和b是某种意义上的偏置和权重吗?
是的,静态图的例子中只包含了一个神经网络的结构,其中只有一层权重和一层偏置。在静态图中,我们需要手动定义整个计算图的结构,包括输入、输出、变量、损失函数和优化器等。因此,静态图相对来说更加复杂,但是可以提供更好的性能和灵活性。

对于 w 和 b,可以把它们理解为神经网络中的权重和偏置。在线性回归模型中,w 代表输入特征和输出之间的权重,b 代表偏置,可以看作是一个常量。在训练过程中,我们需要不断更新 w 和 b 的值,以最小化损失函数。

pp oo
嗯嗯,静态图的损失函数我可以非常轻松的理解,我认为train_op = optimizer.minimize(loss)这一行代码封装了大量底层逻辑,比如我只看到传入了一个损失函数计算得到的值但具体是如何进行梯度下行化的我并看不到1,但是我知道他一定按照某种算法修改了w和x的值,只不过封装后我看不到,对啊没?
是的,你的理解是正确的。在静态图中,我们只需要定义损失函数,然后使用优化器对象的 minimize 方法来最小化损失函数,框架会自动进行梯度计算和参数更新等底层操作。虽然我们看不到具体的实现细节,但是我们可以确定优化器对象会按照某种算法来更新模型参数,以最小化损失函数。所以,使用静态图可以更加方便地进行模型训练,但是可能会牺牲一定的灵活性。

pp oo
所以最小化损失函数这行是预定义的我们作为开发者只能简单地去调用接口没法去修改他的底层逻辑和实现对吗?
是的,最小化损失函数的底层逻辑是由优化器对象实现的,我们无法直接修改其底层逻辑。不过,我们可以通过调整优化器对象的超参数(如学习率、动量等)来影响参数更新的方式和速度。此外,一些深度学习框架(如 TensorFlow)还提供了自定义优化器的接口,可以根据需求自行实现优化器的底层逻辑。

pp oo
优化器的顾名思义就是借助损失函数计算得到的值用来优化权重和偏置的对吧
是的,优化器的作用就是根据损失函数计算出的损失值来更新模型的权重和偏置,以使模型能够更好地拟合训练数据。不同的优化器使用的更新策略有所不同,例如随机梯度下降法、动量法、自适应学习率法等,这些算法会根据损失函数的梯度信息来计算出参数的更新方向和大小。优化器的选择和调整对于模型的性能和训练速度都有着很重要的影响。

那么动态图相对静态图灵活性更高对吗?如果以上面的例子举例是那几行代码呢?

是的,相对于静态图,动态图具有更高的灵活性,因为它允许我们在运行时动态地构建计算图,并且可以在图中使用控制流语句(如条件语句、循环语句等),从而更加灵活地实现复杂的模型结构。

以之前的例子为例,动态图的代码相对简单,可以像下面这样实现:

lua
Copy code
import torch

x = torch.tensor([[1.0, 2.0]])
w = torch.tensor([[2.0], [1.0]])
b = torch.tensor([1.0])

for i in range(100):
y = x.mm(w) + b
loss = (y - torch.tensor([[4.0]])).pow(2).sum()
print(loss)
loss.backward()
with torch.nograd():
w -= 0.1 w.grad
b -= 0.1
b.grad
w.grad.zero
()
b.grad.zero_()
在动态图中,我们可以直接使用 PyTorch 提供的张量计算库来实现模型计算,同时使用 Python 语言中的流程控制语句来实现训练过程的迭代,这使得代码的可读性和灵活性都得到了很好的保证。

pp oo
loss.backward()是反向传递函数启的作用和静态图优化器类似对吗?
是的,loss.backward()函数是PyTorch中的反向传播函数,它的作用类似于静态图中的优化器,用来计算参数的梯度并更新参数。在动态图中,反向传播函数会自动跟踪计算图中的梯度信息,从而实现灵活的动态计算图。

pp oo
我注意到with torch.no_grad()这行代码里面似乎定义了权重和偏置的变动幅度,而静态图中没有这些代码,这就是为什么静态图不如动态图灵活,对吗?
with torch.no_grad() 是一个上下文管理器,用于告诉PyTorch在此上下文中不进行梯度计算。在这个上下文管理器中,我们可以手动更新模型的参数,而不会影响模型的梯度计算。

在静态图中,我们需要在定义计算图时指定每个变量的形状和数据类型,这就限制了模型的灵活性。而在动态图中,模型的计算图是在运行时动态构建的,因此我们可以更灵活地改变模型的结构和参数。

所以可以说,在动态图中,我们可以更加灵活地改变模型的参数,并且可以使用Python原生的流程控制语句(如循环、条件语句等),使得模型的定义更加直观、简洁。而在静态图中,我们需要在定义计算图时对所有变量进行预定义,这就限制了模型的灵活性和可读性。

pp oo
我还是不明白静态图中模型技术图是动态运行时动态构建的这个概念,可以用代码展示下吗?
在静态图中,模型的计算图是在编译时就被构建好了,而在动态图中,模型的计算图是在运行时根据输入数据动态构建的。

下面是一个简单的示例代码,使用 TensorFlow 实现了一个静态图和一个动态图的计算:

python
Copy code
import tensorflow as tf

定义输入占位符

x = tf.placeholder(tf.float32, [None, 2])
y_true = tf.placeholder(tf.float32, [None, 1])

静态图

w1 = tf.Variable(tf.random_normal([2, 4]))
b1 = tf.Variable(tf.random_normal([4]))
h1 = tf.nn.relu(tf.matmul(x, w1) + b1)

w2 = tf.Variable(tf.random_normal([4, 1]))
b2 = tf.Variable(tf.random_normal([1]))
y_pred_static = tf.matmul(h1, w2) + b2

loss_static = tf.reduce_mean(tf.square(y_pred_static - y_true))

动态图

@tf.function
def model_dynamic(x):
w1 = tf.Variable(tf.random_normal([2, 4]))
b1 = tf.Variable(tf.random_normal([4]))
h1 = tf.nn.relu(tf.matmul(x, w1) + b1)

w2 = tf.Variable(tf.random_normal([4, 1]))
b2 = tf.Variable(tf.random_normal([1]))
y_pred_dynamic = tf.matmul(h1, w2) + b2

loss_dynamic = tf.reduce_mean(tf.square(y_pred_dynamic - y_true))
return y_pred_dynamic, loss_dynamic

x_sample = tf.random.normal([10, 2])
y_true_sample = tf.random.normal([10, 1])

y_pred_dynamic, loss_dynamic = model_dynamic(x_sample)

定义优化器和训练操作

optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
train_op_static = optimizer.minimize(loss_static)

在动态图中,需要显式地调用优化器进行参数更新

@tf.function
def train_step_dynamic(x, y_true):
with tf.GradientTape() as tape:
y_pred_dynamic, loss_dynamic = model_dynamic(x)
gradients = tape.gradient(loss_dynamic, model_dynamic.variables)
optimizer.apply_gradients(zip(gradients, model_dynamic.variables))
return y_pred_dynamic, loss_dynamic

y_pred_dynamic, loss_dynamic = train_step_dynamic(x_sample, y_true_sample)
可以看到,在静态图中,模型的计算图是在编译时构建好的,可以直接使用 optimizer.minimize() 函数来进行优化;而在动态图中,模型的计算图是在运行时动态构建的,需要使用 tf.GradientTape() 来记录梯度信息,并且需要显式地调用优化器来进行参数更新。

pp oo
静态图构建好的模型是指什么?类似线性回归模型中 y = wx + b这种数学关系吗?
静态图构建好的模型通常是指一个计算图,该计算图由一些节点和边构成,每个节点代表一个操作,每条边代表数据流向。这些节点和边构成的计算图可以看作是一个预定义好的模型,每个节点的操作已经被固定下来,无法动态调整。我们可以通过填充计算图的输入来执行这个模型,并得到相应的输出结果。在这种情况下,线性回归模型中的 y = wx + b 确实可以看作是一个静态图的计算节点,其中的 w 和 b 可以看作是节点的参数。

pp oo
我了解了,计算图真的只是一个图而已,这个图给我们展示了可能简单可能复杂的运算关系,总之是一系列相互关联的计算,画出来就成为了一个图
正是的,计算图本质上就是一张图,它用节点和边来表示计算操作和数据流动的关系,展示了计算的过程和依赖关系。在神经网络中,节点通常表示神经元,边则表示神经元之间的连接和传递的数据。计算图的好处是能够清晰地描述计算流程和依赖关系,方便进行优化和并行化等操作。

pp oo
动态图是不是封装底层的动态计算图
是的,动态图是指在计算图中,每个操作都是在需要的时候动态构建的,每个操作的输出都可以作为另一个操作的输入,这种方式下,计算图是动态生成的,可以根据数据和代码的不同来生成不同的计算图,从而使得模型更加灵活。动态图通常被用于一些需要动态构建计算图的任务,如自然语言处理和强化学习等领域。在PyTorch中,动态图是通过PyTorch的Autograd自动求导机制实现的。

pp oo
我们可以修改底层的计算图生成机制吗?还是说我们只能简单地调用动态图
在动态图中,可以通过编写 Python 代码来构建计算图,因此我们可以直接修改计算图的生成机制,从而实现更加灵活和个性化的计算图。此外,动态图还提供了一些底层 API,可以更加细粒度地控制计算图的构建和执行。但需要注意的是,直接修改动态图的底层机制需要对 PyTorch 的底层代码有一定的了解,所以并不是所有开发者都需要或者能够修改动态图的底层实现。

借助chatgpt学习机器学习的基础概念

基础概念包括以下

  • 什么是神经网络
  • 什么是权重和偏置
  • 偏置和权重的作用是什么
  • 什么是激活函数
  • 为什么要使用激活函数对输入数据计算后的结果进行二次加工?
  • 什么是梯度
  • 梯度和权重与偏置的关系
  • 梯度是如何影响偏置和权重的跟新的
  • loss.back函数是如何得到各个量的偏置的
  • 反向回归算法是如何工作的
    还记得我吗?
    抱歉,由于我是一个计算机程序,我无法记住过去的事情或记录与单个用户的交互。但我很高兴能够再次与您交流!请告诉我您有什么问题或需要帮助。

pp oo
记得我之前问的关于神经网络的内容吗?
我抱歉,由于我是一个计算机程序,我无法记住与单个用户的交互或者询问的具体内容。不过如果您愿意,请告诉我您关于神经网络的问题,我将尽力回答。

pp oo
神经网络的激活函数是干什么的为什么第一层和第二层的激活函数不一样?
神经网络的激活函数用于将每个神经元的输入信号转换为输出信号,使得神经元之间产生非线性映射关系。激活函数在神经网络中扮演着非常重要的角色,它可以增强模型的非线性拟合能力,使得神经网络能够适应更加复杂的数据分布。

一般来说,第一层和第二层的激活函数可以相同,也可以不同,这取决于具体的任务需求和实际效果。但是,在某些情况下,为了增加神经网络的非线性拟合能力和优化梯度下降算法的表现,通常会选择不同的激活函数。

在实践中,通常使用ReLU(Rectified Linear Unit)作为第一层和第二层的激活函数,因为它具有计算简单、非线性强、不会发生梯度消失等优点。而在输出层,根据不同的任务需求,可以选择不同的激活函数,例如sigmoid函数或softmax函数用于二分类或多分类任务。

pp oo
用代码展示一个简单的神经网络
好的,以下是一个使用Python语言和NumPy库实现的简单的神经网络示例,它包含一个输入层、一个隐藏层和一个输出层,并使用ReLU作为激活函数:

python
Copy code
import numpy as np

定义神经网络类

class NeuralNetwork:
def init(self, input_dim, hidden_dim, output_dim):

定义权重矩阵和偏置向量

    self.weights1 = np.random.randn(input_dim, hidden_dim)
    self.bias1 = np.zeros((1, hidden_dim))
    self.weights2 = np.random.randn(hidden_dim, output_dim)
    self.bias2 = np.zeros((1, output_dim))

def forward(self, X):
    # 前向传播计算
    self.z1 = np.dot(X, self.weights1) + self.bias1
    self.a1 = np.maximum(0, self.z1)  # ReLU激活函数
    self.z2 = np.dot(self.a1, self.weights2) + self.bias2
    self.a2 = np.exp(self.z2) / np.sum(np.exp(self.z2), axis=1, keepdims=True)  # softmax激活函数
    return self.a2

def loss(self, X, y):
    # 计算交叉熵损失
    y_hat = self.forward(X)
    loss = -np.mean(np.log(y_hat[np.arange(len(y)), y]))
    return loss

def backward(self, X, y, learning_rate):
    # 反向传播更新权重矩阵和偏置向量
    y_hat = self.forward(X)
    delta3 = y_hat
    delta3[np.arange(len(y)), y] -= 1
    delta2 = np.dot(delta3, self.weights2.T) * (self.z1 > 0)
    self.weights2 -= learning_rate * np.dot(self.a1.T, delta3)
    self.bias2 -= learning_rate * np.sum(delta3, axis=0, keepdims=True)
    self.weights1 -= learning_rate * np.dot(X.T, delta2)
    self.bias1 -= learning_rate * np.sum(delta2, axis=0)

def train(self, X, y, num_epochs, learning_rate):
    # 训练神经网络
    for epoch in range(num_epochs):
        self.backward(X, y, learning_rate)
        if epoch % 100 == 0:
            print('Epoch %d | Loss: %.4f' % (epoch, self.loss(X, y)))

测试神经网络

X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([0, 1, 1, 0])
nn = NeuralNetwork(input_dim=2, hidden_dim=10, output_dim=2)
nn.train(X, y, num_epochs=1000, learning_rate=0.1)
print(nn.forward(X))
这个神经网络可以用来解决一个简单的异或(XOR)分类问题。在这个例子中,我们使用随机初始化的权重矩阵和偏置向量来训练网络,并使用交叉熵损失和梯度下降算法进行优化。最终,我们得到了一个在

pp oo
所以a1代表的是第一层的输出信号吗?
是的,a1代表的是第一层(也称为隐藏层)的输出信号,它是通过对输入信号进行线性变换和非线性激活后得到的结果。在这个示例中,我们使用ReLU激活函数将线性变换的结果进行非线性映射,得到了a1作为隐藏层的输出信号。隐藏层的输出信号会作为输入信号传递给下一层。

pp oo
能细节解释下loss()这个函数里面的内容吗?
当我们训练神经网络时,我们需要定义一个损失函数来衡量模型的预测值与真实值之间的差距。在这个示例中,我们使用交叉熵损失作为损失函数,它可以用来衡量多分类问题中预测值与真实值之间的差距。

具体地说,假设我们的神经网络有K个输出节点,我们的训练集中有N个样本,每个样本的真实类别标签用一个K维的one-hot向量表示(即除了真实类别所对应的位置为1之外,其他位置都为0),而神经网络的预测值也是一个K维的向量。那么,对于每个样本i,交叉熵损失的计算公式如下:

$lossi = -\sum{j=1}^{K} y{i,j} * \log(\hat{y}{i,j})$

其中,$y{i,j}$表示第i个样本的第j个类别标签的值,$\hat{y}{i,j}$表示神经网络对第i个样本的第j个类别的预测值。

整个训练集的交叉熵损失可以通过对所有样本的损失取平均得到:

$loss = \frac{1}{N} \sum_{i=1}^{N} loss_i$

在loss()函数中,我们首先通过调用forward()方法计算出神经网络对输入数据的预测值y_hat,然后根据上面的公式计算出每个样本的交叉熵损失。最后,我们对所有样本的损失取平均并返回结果。

pp oo
我是说解释下loss()里面的每一行代码作用,不需要解释交叉熵这个概念
好的,让我逐行解释一下loss()函数中的每一行代码的作用:

python
Copy code
def loss(self, X, y):
y_hat = self.forward(X) # 计算神经网络对输入数据的预测值
L = -np.sum(y * np.log(y_hat), axis=1) # 计算每个样本的交叉熵损失
loss = np.mean(L) # 对所有样本的损失取平均
return loss
y_hat = self.forward(X):调用forward()方法计算神经网络对输入数据的预测值,并将结果赋值给y_hat。

L = -np.sum(y * np.log(y_hat), axis=1):使用上面的公式计算每个样本的交叉熵损失。np.log()表示求对数,np.sum()表示对所有元素求和,axis=1表示沿着第二个维度(也就是类别维度)进行求和。最终得到一个长度为N的一维数组L,其中N为样本数。

loss = np.mean(L):对所有样本的损失取平均,得到一个标量值,即整个训练集的平均交叉熵损失。

return loss:返回计算得到的损失值。

pp oo
解释下forward函数里面每一行代码的功能
好的,让我逐行解释一下forward()函数中每一行代码的功能:

python
Copy code
def forward(self, X):

隐藏层输入

self.z1 = np.dot(X, self.W1) + self.b1
# 隐藏层输出
self.a1 = self.relu(self.z1)
# 输出层输入
self.z2 = np.dot(self.a1, self.W2) + self.b2
# 输出层输出
self.y_hat = self.softmax(self.z2)
return self.y_hat

self.z1 = np.dot(X, self.W1) + self.b1:计算第一层(也称为隐藏层)的输入,即将输入数据X与第一层的权重W1相乘并加上偏置b1得到的结果。其中,np.dot()表示矩阵乘法,self.W1和self.b1分别是第一层的权重矩阵和偏置向量。

self.a1 = self.relu(self.z1):对第一层的输入进行ReLU激活,得到隐藏层的输出。ReLU激活函数可以将所有小于0的值设为0,而保留所有大于等于0的值。

self.z2 = np.dot(self.a1, self.W2) + self.b2:计算第二层(也称为输出层)的输入,即将隐藏层的输出self.a1与第二层的权重矩阵self.W2相乘并加上偏置向量self.b2得到的结果。

self.y_hat = self.softmax(self.z2):对第二层的输入进行softmax激活,得到神经网络对输入数据的预测结果。softmax函数可以将任意长度的向量映射为一个概率分布,其中每个元素都在0到1之间且总和为1。

return self.y_hat:返回神经网络对输入数据的预测结果。

pp oo
举一个简单的损失函数例子吧,交叉熵函数我很难理解
好的,下面举一个简单的损失函数例子:均方误差(Mean Squared Error,简称MSE)。

均方误差是一种常用的回归损失函数,用于衡量神经网络对连续变量的预测值与真实值之间的差距。假设神经网络的预测值为y_hat,真实值为y,则MSE的计算公式如下:

$$MSE = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y_i})^2$$

其中,n为样本数量。该公式计算了所有样本的预测值与真实值之间的平均平方误差。

下面是一个简单的Python代码,用于计算均方误差:

python
Copy code
def mse(y, y_hat):
return np.mean((y - y_hat) ** 2)
其中,y表示真实值,y_hat表示预测值。该函数首先计算了每个样本的预测值与真实值之间的平方误差,然后对所有样本的误差取平均,得到整个训练集的均方误差。

pp oo
所以损失函数是通过对向前函数的调用得到最终层的输出,这个输出就是预测值,损失函数通过这个预测值计算得到损失值,对吧
是的,您说得对。损失函数通常是通过对神经网络的前向传播函数(也就是forward()函数)的调用得到最终的预测值,然后将预测值与真实值进行比较,得到一个损失值。这个损失值反映了神经网络对训练数据的拟合程度,损失值越小,则代表神经网络对训练数据的拟合越好。在训练过程中,神经网络的目标是最小化损失函数的值,从而使得神经网络的预测结果与真实值更加接近。

pp oo
那么损失函数可以影响权重和偏置对吧
是的,损失函数的选择会影响到权重和偏置的更新过程。在神经网络的训练过程中,我们需要不断地调整神经元之间的权重和偏置,使得损失函数的值不断降低,从而提高神经网络的预测准确率。

在反向传播算法中,我们需要计算损失函数对每个参数(包括权重和偏置)的偏导数(也就是梯度),以便更新这些参数。不同的损失函数具有不同的导数形式,因此选择不同的损失函数会导致不同的参数更新策略。比如,对于均方误差损失函数,参数更新的策略是按照梯度下降法来更新权重和偏置,而对于交叉熵损失函数,则需要使用更为复杂的参数更新策略。

总之,损失函数的选择会对权重和偏置的更新过程产生影响,从而影响神经网络的训练效果。

pp oo
对于均方误差损失函数,我们是如何在具体的神经网络里面使用的呢?我已经知道了他们是如何被定义的了,现在我想知道损失函数在代码中是如何影响偏置和权重跟新的。最好能够具体说明每行代码的功能
好的,下面我以一个简单的单层神经网络为例,来说明在代码中如何使用均方误差损失函数,以及如何通过损失函数来影响偏置和权重的更新。假设这个神经网络的输入为一个向量$x$,输出为一个标量$y$,神经元的激活函数为$f$,那么我们可以用如下的方式来定义神经网络的前向传播函数:

python
Copy code
def forward(x, w, b):

计算加权输入

z = np.dot(x, w) + b
# 计算输出
y = f(z)
return y

其中,$w$和$b$分别表示神经元的权重和偏置,$f$为激活函数。

对于均方误差损失函数,其定义如下:


(

,

)

1
2
(



)
2
L(y,t)=
2
1

(y−t)
2

其中,$y$表示神经网络的输出,$t$表示真实值。

那么,我们可以用如下的方式来定义损失函数:

python
Copy code
def loss(y, t):

计算均方误差

mse = 0.5 * np.sum((y - t) ** 2)
return mse

其中,$y$表示神经网络的输出,$t$表示真实值。

接下来,我们需要通过反向传播算法来计算梯度,从而更新权重和偏置。具体来说,我们需要计算损失函数对权重和偏置的偏导数(即梯度),然后按照梯度下降法的方式来更新权重和偏置。

假设我们使用批量梯度下降法来进行训练,那么我们可以用如下的方式来更新权重和偏置:

python
Copy code
def backward(x, y, t):

计算误差

delta = y - t
# 计算权重的梯度
dw = np.dot(x.T, delta)
# 计算偏置的梯度
db = np.sum(delta, axis=0)
return dw, db

更新权重和偏置

dw, db = backward(x, y, t)
w -= learning_rate dw
b -= learning_rate
db
其中,$x$表示输入数据,$y$表示神经网络的输出,$t$表示真实值,$learning_rate$表示学习率。我们首先需要计算误差$delta$,然后根据误差计算权重和偏置的梯度,最后按照梯度下降法的方式来更新权重和偏置。

pp oo
这个T是什么?他既不是传入参数也不是其他东西
非常抱歉我之前的回答有误。在这个例子中,T指的是目标标签(label),是训练数据中对应的真实值。在代码中,我们先将T和模型的输出Y之间求差,得到误差E。然后根据误差E对模型的参数进行更新,这个过程被称为反向传播(backpropagation)。具体来说,我们通过调用loss.backward()来计算每个参数对于损失函数的梯度,然后使用梯度下降(gradient descent)方法来更新参数。

在本例中,我们使用了均方误差损失函数,也称为平方误差损失函数。它的定义是所有误差平方的平均值。在代码中,我们使用torch.nn.MSELoss函数来计算损失值,它返回的是一个标量,也就是一个单一的数值,用来表示当前模型的表现。损失值越小,表示模型的预测结果越接近真实值,这也是我们要最小化损失函数的原因。

pp oo
dw是如何得到的结合代码详细说一下
在神经网络中,参数更新的目标是最小化损失函数,而这个目标可以通过梯度下降算法来实现。梯度下降算法的核心思想是沿着损失函数的负梯度方向更新参数,以便找到一个更优的参数组合来最小化损失函数。具体来说,对于每个参数,我们需要计算其对应的梯度,然后沿着负梯度方向更新参数。

在代码中,dw是权重W的梯度,是通过反向传播算法计算得到的。我们首先计算损失函数对输出Y的梯度,也就是loss.backward()这一步,然后使用PyTorch自动计算的机制,将梯度从输出层向输入层传播,计算每个参数的梯度。在本例中,我们使用的是随机梯度下降算法,即每次更新只使用一个样本的信息,因此我们需要将梯度除以样本数,以便计算平均梯度。最后,我们根据梯度下降的公式,使用梯度和学习率alpha来更新参数W和b,即 W = W - alpha dw 和 b = b - alpha db。这个过程在代码中的实现如下:

makefile
Copy code

compute gradients

dw = 1/m torch.mm(X, (Y_hat - T).T)
db = 1/m
torch.sum(Y_hat - T)

update parameters

W = W - alpha dw
b = b - alpha
db
其中,X是输入数据,Y_hat是模型输出,T是真实标签,m是样本数,dw和db分别是权重和偏置的梯度,alpha是学习率,用于控制参数更新的步长。

pp oo
所以上面例子中alpha可以控制我们每次迭代权重和偏置的速率,即这两个参数的变换幅度对吧
是的,学习率alpha可以控制每次迭代权重和偏置的更新速率,即它决定了参数在每次迭代中的变化幅度。如果学习率过小,更新速度会很慢,需要更多次的迭代才能收敛;而如果学习率过大,更新速度会很快,但可能会跳过最优解或导致不稳定的收敛。因此,选择合适的学习率是非常重要的,通常需要进行试验和调整。

pp oo
torch.mm这个函数对于我们传入的参数做了什么?
torch.mm()函数是PyTorch中的矩阵乘法函数,它接受两个张量作为输入参数,返回两个张量的矩阵乘积。

具体来说,如果我们传入的参数为张量A和张量B,torch.mm(A, B)将会对它们进行矩阵乘法运算,返回结果张量C,其中C[i][j]表示矩阵A的第i行与矩阵B的第j列的点积。

举个例子,假设我们有两个形状分别为(2, 3)和(3, 2)的张量:

lua
Copy code
A = torch.tensor([[1, 2, 3],
[4, 5, 6]])

B = torch.tensor([[7, 8],
[9, 10],
[11, 12]])
那么执行C = torch.mm(A, B)后,得到的C张量将会是一个形状为(2, 2)的张量:

lua
Copy code
C = torch.tensor([[58, 64],
[139, 154]])
其中C[0][0] = 17 + 29 + 311 = 58,C[0][1] = 18 + 210 + 312 = 64,以此类推。

pp oo
所以loss.back得到的是梯度对吧
是的,loss.backward()函数会计算损失函数对于所有需要求导的参数的梯度,并将它们存在这些参数的.grad属性中,即backward()函数得到的就是梯度。在神经网络中,这些需要求导的参数通常是模型中的权重和偏置等参数。

具体地,loss.backward()会利用自动微分机制计算出损失函数对于每个需要求导的参数的梯度,并将它们加起来。这个过程实际上就是反向传播算法,其结果是一个梯度张量,包含了所有需要求导的参数相对于损失函数的梯度信息。

一旦得到了这些参数的梯度,我们就可以利用它们来更新这些参数,从而让损失函数的值不断减小,达到训练模型的目的。

pp oo
可以讲一下loss.back中具体是如何通过微分算法求到损失函数对于权重的梯度吗?借助代码,还有损失函数对于权重的梯度是否就是损失函数对权重求偏导?
在loss.backward()中,PyTorch会自动使用反向传播算法计算每个需要求导的参数的梯度,其中包括权重。在这个过程中,PyTorch会构建一个计算图,将参数的计算过程按照顺序连接起来,然后沿着计算图的反向方向进行梯度传播,最终得到每个参数的梯度。

具体来说,PyTorch会利用自动微分机制,在计算图中为每个需要求导的参数添加一个叶节点,并记录这个叶节点的梯度信息。然后,PyTorch会沿着计算图的反向方向,将梯度信息从损失函数传递到每个叶节点,最终计算出每个叶节点的梯度。

损失函数对权重的梯度,实际上就是损失函数对权重求偏导数,也就是说,对于每个权重,损失函数对它的梯度表示了在当前权重值下,损失函数对于输出结果的变化率。通过梯度下降等优化算法,我们可以将这个变化率最小化,从而得到更好的模型。

下面是一个示例代码,展示了如何计算简单的线性模型中的损失函数对权重的梯度:

python
Copy code
import torch

定义模型

class LinearModel(torch.nn.Module):
def init(self):
super(LinearModel, self).init()
self.linear = torch.nn.Linear(2, 1)

def forward(self, x):
    out = self.linear(x)
    return out

定义数据

x = torch.tensor([[1.0, 2.0], [2.0, 4.0], [3.0, 6.0]])
y = torch.tensor([[2.0], [4.0], [6.0]])

定义模型和损失函数

model = LinearModel()
criterion = torch.nn.MSELoss()

计算损失函数对于权重的梯度

output = model(x)
loss = criterion(output, y)
loss.backward()

打印权重和梯度

print(model.linear.weight)
print(model.linear.weight.grad)
在这个例子中,我们定义了一个简单的线性模型,并使用均方误差损失函数作为模型的损失函数。我们将模型输入的数据x和对应的标签y定义为张量,然后计算模型在这些数据上的损失函数。最后,我们调用loss.backward()函数来计算损失函数对于模型中所有需要求导的参数的梯度,包括权重。

在这个例子中,我们只有一个线性层,因此只有一个权重,我们可以通过打印model.linear.weight和model.linear.weight.grad来查看这个权重和对应的梯度。

pp oo
output是预测值对吗?
是的,output是神经网络模型的预测值。在该例子中,output是一个形状为 (1, 1) 的张量,表示模型预测的单个数值。在其他问题中,output可能是一个向量或矩阵,表示模型的输出。

pp oo
loss是损失函数计算得到的结果值对吗?
是的,loss是损失函数计算得到的结果值。在该例子中,我们使用的是均方误差损失函数,计算出的loss是一个标量值,表示模型预测值与真实值之间的差异。在其他问题中,loss可以是其他类型的损失函数计算得到的结果,例如交叉熵损失函数、对比损失函数等。

pp oo
梯度是用来评估损失函数和偏置,权重的关系的,对吗?
是的,梯度是用来评估损失函数和模型参数(包括权重和偏置)之间的关系的。在机器学习中,我们通过最小化损失函数来优化模型,使其能够更好地拟合训练数据。而梯度告诉我们,当模型参数发生变化时,损失函数的变化方向和大小,从而帮助我们找到一个更优的模型参数组合。具体来说,当我们计算损失函数对某个参数的梯度时,得到的结果告诉我们在当前参数值下,如果我们稍微改变一下这个参数,损失函数会发生多大的变化,从而指导我们如何调整模型参数,让损失函数更小。

Mybatis

foreach 标签

  • collection是指定传入类型,array数组 list列表集合 可自定义分隔符和开头结尾
  • 多表联查属性同名需要别名
  • 返回对象中有lsit属性需要collection标签中设置属性名property
    Road AI - Smart road inspection:这是一款由挪威的一个名为VoxelFly AS的公司开发的应用于道路检测的软件。它使用深度学习和计算机视觉技术,通过图像和视频数据来检测道路上的缺陷和损坏。

RoadBotics:这是一家位于美国匹兹堡的公司开发的道路检测软件。他们使用计算机视觉和深度学习算法来检测道路的状况,例如裂缝、坑洞等。

Road Rover:这是由英国公司RoadBotics Technologies Ltd.开发的一款道路检测软件。它使用计算机视觉和深度学习技术来识别道路上的缺陷,并生成路面质量报告。

RoadView:这是由美国的一个名为JTC Inc.的公司开发的道路检测应用程序。它提供了一个网站,用户可以上传道路图像或视频,然后通过后端深度学习算法来检测道路上的缺陷和损坏。

RoadSnap:这是由美国的一家名为Cogniac的公司开发的道路检测应用程序。它提供了一个网站和移动应用,用户可以上传道路图像或视频,并使用深度学习和计算机视觉技术来检测道路上的裂缝和坑洞等问题。

RoadSense:这是由加拿大的一家名为Sensemetrics的公司开发的道路检测应用程序。它提供了一个网站,用户可以上传道路图像或视频,然后使用计算机视觉技术来检测道路上的缺陷和损坏。

RoadBotics:这是由美国匹兹堡的一家公司开发的道路检测应用程序。它提供了一个网站和移动应用,用户可以上传道路图像或视频,然后使用计算机视觉和深度学习技术来检测道路上的裂缝和坑洞等问题。

RoadAI:这是由挪威的一个名为VoxelFly AS的公司开发的道路检测应用程序。它提供了一个网站,用户可以上传道路图像或视频,然后使用计算机视觉和深度学习技术来检测道路上的缺陷和损坏。

Road Rover:这是由英国的一家名为RoadBotics Technologies Ltd.的公司开发的道路检测应用程序。它提供了一个网站,用户可以上传道路图像或视频,然后使用计算机视觉和深度学习技术来检测道路上的缺陷和损坏。

具体来说,在前端技术方面,常用的前端框架包括React、Vue、Angular等。在后端技术方面,常用的Web框架包括Django、Flask、Express等,常用的数据库包括MySQL、PostgreSQL、MongoDB等。在计算机视觉和深度学习技术方面,常用的开源深度学习框架包括TensorFlow、PyTorch、Keras、MXNet等。

道路病害自动识别与评价软件:该软件是由中国交通运输部公路科学研究院开发的,可以自动识别道路病害,包括裂缝、坑槽、坑洼等,同时也可以进行评价和统计分析。

道路病害检测软件:该软件是由清华大学建设与环境工程系开发的,采用计算机视觉和机器学习技术,能够对道路裂缝、坑槽、翘起等进行自动化检测和评估。

道路损伤检测系统:该系统是由上海辰安科技开发的,采用深度学习算法和高精度地图数据,能够自动检测道路损伤,包括路面坑洞、路面破损等,并提供实时监控和数据分析功能。

道路病害自动识别与评价软件:http://www.rhi.org.cn

道路病害检测软件:http://homepage.tsinghua.edu.cn/luojian

道路损伤检测系统:http://www.chenankeji.com.cn

设计:创建软件的架构和流程图,并确保其与需求一致。您可以使用工具如 UML 或流程图来完成这项工作。

编码:将设计转化为实际代码。您需要选择一个编程语言和相应的开发工具,如集成开发环境(IDE)。

测试:测试软件以确保它满足需求,并纠正错误。测试可以手动进行,也可以使用自动化测试工具。

发布:发布软件并使其可用于公众。您需要选择适当的发布渠道,如应用商店或软件下载网站。

维护:监控和维护软件以确保其长期稳定性和可用性。您需要及时修复错误,并考虑添加新功能或改进现有功能。
环境配置:您需要在Linux上安装Java运行环境,并将其配置到系统的环境变量中。

网络配置:如果您的应用需要访问网络资源,您需要配置网络代理和防火墙以确保应用程序可以正常连接到互联网。

安全性:您需要确保应用程序具有足够的安全性保护措施,如配置HTTPS证书、设置安全连接和身份验证等。

资源配置:您需要在Linux上配置足够的硬件资源来支持应用程序的运行,如CPU、内存和存储等。

服务管理:您可以使用Linux的服务管理工具来管理应用程序的生命周期,并设置应用程序在系统启动时自动运行。

日志和监控:您需要设置日志和监控系统来跟踪应用程序的性能和错误,并定期检查和维护系统。

针对使用Spring框架开发的应用程序,您还需要注意以下几点:

配置文件:您需要在Linux上正确配置Spring框架的配置文件,如application.properties或application.yml文件。

端口设置:您需要在应用程序中指定正确的端口号,以便Linux可以正确地将请求路由到应用程序。

依赖项管理:您需要在Linux上安装正确的依赖项,如数据库驱动程序和其他必要的库文件。

打包部署:您可以使用Maven或Gradle等工具将应用程序打包成可执行文件,并在Linux上部署。

目视检查法:道路维护人员通过巡查、目视观察等手段检测道路灾害,包括路面破损、沉降、水损等。这种方法的优点是简单易行,但是需要大量的人力、时间和物力投入,并且对于深埋在地下的问题很难发现。

非接触式测量法:包括遥感技术、激光扫描技术等。这种方法可以获取更广泛的数据和更快的检测速度,但是需要专业的设备和技术,并且可能会受到天气、光照等因素的影响。

机械检测法:包括钻孔、探伤等。这种方法可以检测路基、桥梁、隧道等深埋地下的问题,但是需要大量的人力、时间和物力投入,并且对交通造成一定的影响。

这些传统的道路灾害检测手段存在以下问题和弊端:

人力、时间和物力成本高:目视检查法和机械检测法需要大量的人力、时间和物力投入,测量成本高。

检测精度不高:目视检查法的结果可能存在主观性和不确定性,非接触式测量法和机械检测法的精度可能受到多种因素的影响,比如遮挡、光照、天气等。

覆盖范围受限:机械检测法只能对局部区域进行检测,而目视检查法和非接触式测量法的范围也有一定限制。

SSO单点登录

微服务和session存储的问题

  • session工作机制:用户登录验证后服务器生成相关session,返回客户端特定的sessionId,即Cookies,下次客户端携带Cookies进行访问即可免登录
  • 使用session的问题:跨服务器无法共享本地内存中存储的session
  • 解决方案:使用redis缓存服务器进行存储session,由redis对session进行管理
  • 缺点:redis需要大量存储空间

JWT

  • JWT工作机制,服务器不对用户信息进行保存,返回加密且携带用户信息的JWT,用户自己携带JWT即Token,二次登录时前端LocalStorey发送请求时放入请求头提交Token,后端过滤器会先对JWT进行解析,解析完成后整个项目就知道了该用户的权限状态,后续service和controller即可提供springsecurityApi查询该用户权限

MQ消息队列

  • 解耦:解耦生产者和消费者的过耦合- 功能:解耦生产者和消费者的过耦合
    远端调用:生产者调用的函数方法里面包含消费者服务器的相干信息,消费者频繁切换造成生产者代码频繁修改,MQ服务器作为中间人解耦两者关系,接收生产者群发消费者
  • 消峰:把请求放入MQ消息服务器,避免高并发打垮数据库
  • 异步调用
    发送消息后不等待远端调用返回,直接继续进行自己的代码

Rabbitmq消息收发的六种模式

  • 队列参数详解
    //连接
    ConnectionFactory f = new ConnectionFactory();
    f.setHost("192.168.64.140");
    f.setPort(5672);
    f.setUsername("guest");
    f.setPassword("guest");
    Channel c = f.newConnection().createChannel();
    //创建队列 helloworld
    名称 是否持久化消息队列到内存 是否独占消息通道 其他配置(map类型)
    c.queueDeclare("helloworld",false,false,false,null);

  • 快速启动 rabbitmq -r start

简单模式

  • 工作原理轮询,每次分配一个消息
  • 缺点,当一个消费者服务器繁忙时依旧会分配任务而不是分配给空闲消费者

工作模式

  • 多消费者默认是轮询
  • 工作原理:空闲优先,设置为手动确认模型,然后自定义一次性最多分配到多少个消息,rabbitmq会自动分配给空闲服务器,对于没有空闲服务器的情况下rabbitmq会停止分配消息
  • 缺点,没有持久化消息队列任意导致消息队列的消息在rabbitmq宕机或重启时丢失。

交换机群发模式

  • 消费者上线要自带消息队列 消费者可以设置关键词进行过滤
    1. 不使用独享队列/交换机默认简单模式和工作模式都是轮询要使用交换解决群发,广播的问题
    2. 因为消费者可能随时离开所以用的是非持久化随机队列 名称随机

RPC远程调用

商城实战rabbitmq

  1. 添加pom 配置yml 自动化生成队列
  2. 去除原有的SQL存储操作
  3. 同1
  4. 创建一个制动注入的监听类用于监听,里面写监听方法并自动存入消息,调用service服务
  5. serviceImpl服务取出存入队列的数据。进行数据存储操作

https://gitcode.net/weixin_38305440/jsd2209/-/tree/master/project/rabbitmq/src/main/java/m1
https://gitcode.net/weixin_38305440/jsd2208/-/blob/master/%E7%AC%94%E8%AE%B0/Rabbitmq.md

从零开始创建微服务项目(非教程向)

创建父级Maven项目

    • spring boot版本
    • 配置相关依赖
      小心:配置了子类一定会用,隐式的,子类无需二次配置
    • 配置版本锁
      配置了子类不一样会用

      创建子类Modle项目

    • 父子互关联
      改parent那行为父类的自己说明
    • 同级相关
      调用方添加依赖即可
    • 删除test和其他不用模块比如启动器和静态资源

创建错误类

    • 枚举错误类
      单纯枚举类 加个标准的getter
    • Josn返回结果类
      只是一个自定义的简单类,实例化时赋值变量message和status
      真实的josn格式是靠mvc框架实现的
    • 自定义运行时错误类
      单纯继承了runtimeException
      有message和code参数
      message用于调用父类的构造函数时赋值message变量
      errorCode单纯是给自定义的errorCode变量赋值
    • exception全局错误处理器类
      @ExceptionHandler通过这个标签配置要主动捕获的异常类 然后没什么特别的
      就和普通的handler方法一样,只不过把业务的调用换成了错误的打印
      把成功的Josn静态方法换成了失败的Josn静态方法 返回的都是josn对象

配置yml

    • 服务器相关:端口
    • mybatis相关:驼峰 二缓
    • knife4j API文档:
    • spring: 配置文件启用

配置dev yml

    • 生产者业务modle需要额外配置mysql数据库连接、 nacos、 生产者还需要Dubbo

配置pom

    • 业务生产者

创建config文件

    • knife4j默认配置cv
    • 同级Modle扫包配置

创建service层

    • 接口:@事务标签
    • impl实现类:@service标签 @Slf4j日志标签

创建controller层

    • 类:@restController @Slf4j日志标签 @RequestMapping全局路径设置 @Api文档名称
    • 方法API文档三剑客 @ApiOperation@ApiOperationSupport@ApiImplicitParam + 请求post/get

配置nacos相关

    • 当然你需要添加依赖

      com.alibaba.cloud
      spring-cloud-starter-alibaba-nacos-discovery
    • 而且需要yml配置
      spring:
      application:
      name: nacos-business # 定义当前服务名称
      cloud:
      nacos:
      discovery:
      server-addr: localhost:8848 # 指定正在运行的Nacos服务器的位置
      sentinel:
      transport:
      dashboard: localhost:8080 # Sentinel仪表台的ip:端口
      port: 8722 # 是localhost的8722 这个端口真正参与当前项目的限流措施

cart业务开发:

    • 其他内容:pom父子相认/添加依赖,修改yml配置文件 参考上文
    • 例外: 作为cart业务 必须要pom添加mybatis依赖和配置config文件 注意扫包路径的修改
      knif4j api文档:调整业务handler扫包路径 非常重要!
      knif4j api文档: 次要 主机名 组名 描述 简介
      mybatis :mapper包的扫描路径
    • 业务三层: mapper持久层, service服务层, handler业务层 本地test文档test略过
    • 错误:
      未开启nacos将导致knife4j api无法启动 空指针异常

Dubbo

  • 快速上手
    1. 消费者想要调用生产者的功能模块或者方法就需要提前引入这个方法和模块
    2. 默认的pom依赖引入将会导入大量不必要文件
    3. 将生产者拆分为父类下的俩个小modle,一个只包含接口的service modle和一个包含其他功能的webapi modle,service model的pom最小依赖只包含common类因为接口有传入类型
    4. api modle:pom 剪切父类依赖后额外添加dubbo依赖/service modle依赖(逻辑接口),yml配置dubbo配置,
    5. 复制父类文件,修改config mapperConfig/knife4jConfig 1. 配置文件
    6. 去除父类src,test,target
    7. IMPL添加DubboService标签(激活方法到nacos),生产者启动类添加@EnableDubbo,
    8. 启用RPC服务@DubboReferance 自动注入

seata 事务回滚

  • 原理
    1. seata 有TL,带有GlobalTransactional标签方法启动时TL会自动把与之相关的全部数据库操作添加到一个组中,由RL收集各个模块数据库处理结果,若全成功RL通知所有模块提交数据库,若失败就全部按照各种的undolog表回滚。
  • 快速上手
    1. 生产者消费者pom均添加依赖 seata及其seata依赖 config文件配置seata
    2. 生产者不要添加seata的子依赖否则数据库配置找不到报错
    3. 生产者事务发起点impl方法添加@GlobalTransactional 启动事务一致性

Sentiel 限流

  • 快速上手
    1. pom+yml+impl方法上写标签@SentinelResource
    2. 消费者运行服务(注册)后才能被sentiel服务发现,(重要)才能在sentielweb 网页控制设置
    3. @SentinelResource标签需要配置限流的错误方法名,类需要新增错误方法

网关

  • 解释
    1. 安全性,过滤器更安全
    2. 负载均衡,自动分配服务
  • 快速上手
    1. 配置gate 项目 pom + yml 即可
    2. uri 不是 url!
    3. 重启gateway项目
    4. 自动设置代理和主动设置代理url

elasticsearch搜索引擎

  • 解释
    1. 关系型数据库的常规索引不能快速进行模糊查询,使用elasticsearch的倒序分词索引进行查询比较快
  • 快速上手
    1. 无需pom yml
    2. 配置ik中文分词插件
    3. 这玩意没有数据库表取而代之的是数据段?

SpringData

  • 解释
    1. elasticsearch添加数据非常麻烦需要通过Socket套接字,之前是借助tmocat实现的
    2. 借助SpringData可以快速实现批量写入读取elasticsearch的数据
  • 快速上手
    1. 配置pom依赖 和yml
    2. 和普通业务一样也是需要service接口及标准类的pojo。
    3. 不需要impl实现类。
    4. 接口类需要继承ElasticsearchRepository<Item,Long>接口,无需添加额外方法父类即可拥有有常用的elasticsearch服务代码 单写读 多写读

快捷键合集

  • shift + F6 重命名
  • shift + alt + ctrl + c 复制包名
  • ctrl + alt + s 搜索快捷面板
  • inspection + UID = 序列化自定义uuid alt + enter = 插入序列化uuid
  • cmd 文件开头字母 + tab = 快速补全

经验

  • commons是必不可少的,因为错误类,commons也有不少依赖
  • 除了service几乎所有类都有knife4j api依赖
  • 除了service几乎所有类都有nacos/dubbo 来注册服务和远程调用
  • service是依赖最少的
  • 父类容易写掉版本文件只有property文件
  • ym文件没有配置但添加了pom依赖会造成大量warning knife4j一个error
  • mybatis pom添加依赖后是需要进行数据库连接的
  • 应当删除webapi的test

csmall项目相关

迁移jwt认证模块

  • pom依赖 jjwt fastjson security
  • 错误处理:serviceCode 码
  • 错误处理:globalHander
  • loginPricple类
  • 主要文件:filter过滤器
  • 主要文件:securityConfig配置类(密码模块移除)

mapper规范

  • 拿去标准对象的方法名统一为:getStandardById(service也是)

globle hander规范

  • 一般fail类型 统一返回范式类型为

handler规范

  • 主要getmapping和postmapping0

PASSMAll

  • 默认用户登录 所有页面均可访问
  • 去掉默认登录页面 所有页面开启权限检测 白名单除外
  • 和框架的loadUserByUsername方法对接(根据框架方法给的用户名自己去拿或者新建userDeteil对象并返回,框架帮你做验证这就是security框架的验证原理) 案例:在对接框架方法时 创建自定义对象

Redis repository

  • Redis三种数据的CRUD 一般value ,list ,set
  • repository层的简单实现 list() 2种 save 2种 get 一种
  • 预加载 清理redis 预加载list到redis内存
  • 定时任务

一些前端细节

  • 如何跳转页面
    function{
    this.$router.push("add-new-2")
    }
    router.push() 

    前缀相同仅添加url最后的名称即可不要加/

  • 如何在页面跳转时保持侧边栏选中不变 修改页面的router的default-active配置
            <el-menu
              router
              :default-active="activeRoute"
              class="el-menu-vertical-demo"
              background-color="#222c32"
              text-color="#fff"
              active-text-color="#fff">
  • 如何使用localStory保存对象数据
    localStorage.setItem("key",Object) 加this前缀会报错无法识别
    localStorage.getItem("key")
    JSON.stringify(Object)
    JOSN.parse(ObjectString)