混合专家模型(Mixture of Experts,简称MoE)是一种高效的神经网络架构,它将多个专业化的子模型(即“专家”)与一个门控网络相结合,以处理复杂任务。
混合专家模型的核心思想是将一个大问题分解为多个小问题,每个小问题由一个在该领域有专业知识的专家模型来处理。通过这种方式,混合专家模型能够充分利用多个专家模型的专长,提高整体模型的性能。
而对于混合专家模型来说,许多人比较陌生,其实可以认为这是一种较为通用的方法,适用于许多领域,比如自然语言处理、图像识别、语音识别、推荐系统等领域。
在这里,写者在图像识别中滑块匹配领域应用有所使用,效果良好。
未使用前87.2%准确率,使用后95.8%准确率,提升了约10%的准确率,错误率减少了约67.2%,对于大多数模型而言,基本上都已经到80-90%准确率,错误率减少才是最重要的。
使用前的算法(经过优化):
import cv2
import numpy as np
## 采用的是基础版本
def sliderSlip(address, width=50):
"""
识别准确率为:0.872
这里要说明一下,滑块可能与拼图的滑动长度不一致,要细微调整比例关系
address:图片地址和名字
width:从左边开始裁剪x轴宽度是多少
list_class:边缘识别阈值
list_d:边缘识别阈值下限
list_h:边缘识别阈值上限
list_val:保存每种阈值的最高匹配度
list_tl_x:保存每种阈值的滑动距离
return: X:移动X轴上的长度
"""
# 读取图片,通过灰度加载来更好完成识别任务
image = cv2.imread(address, cv2.IMREAD_GRAYSCALE)
# 指定裁剪区域的起始位置和宽度、高度
x, y = 0, 0
# 从左边开始裁剪x轴宽度是多少
width = width
# 获取图片的高
height = image.shape[0]
# 裁剪图像
tp_image = image[y:y + height, x:x + width] # 裁剪图片
bg_image = image[y:y + height, width:image.shape[1]] # 识别的背景图片
# 高斯模糊
tp_image = cv2.GaussianBlur(tp_image, (5, 5), sigmaX=0)
bg_image = cv2.GaussianBlur(bg_image, (5, 5), sigmaX=0)
# 灰度直方图均衡
tp_image = cv2.equalizeHist(tp_image)
bg_image = cv2.equalizeHist(bg_image)
# 识别图片边缘
# bg_edge = cv2.Canny(bg_image, 100, 200)
# tp_edge = cv2.Canny(tp_image, 100, 200)
# 匹配算法
# res = cv2.matchTemplate(bg_edge, tp_edge, cv2.TM_CCOEFF_NORMED) #寻图
# min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) # 寻找最优匹配
# tl = max_loc # 左上角点的坐标
# X = tl[0]+width #x轴长度
list_class = ["较高", "正常", "调试", "中", "低"]
list_d = [150, 100, 10, 80, 10]
list_h = [250, 200, 150, 150, 80]
list_val = []
list_tl_x = []
# 所有分辨匹配机制
for i in range(len(list_class)):
bg_edge = cv2.Canny(bg_image, list_d[i], list_h[i])
tp_edge = cv2.Canny(tp_image, list_d[i], list_h[i])
res = cv2.matchTemplate(bg_edge, tp_edge, cv2.TM_CCOEFF_NORMED) # 寻图
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) # 寻找最优匹配
list_val.append(max_val)
tl = max_loc # 左上角点的坐标
list_tl_x.append(tl[0])
# 去除匹配为1.0
n = 0
for i in list_val:
if i == 1.0:
list_val[n] = 0
n += 1
# 获取最大匹配度的索引
index = list_val.index(max(list_val))
X = list_tl_x[index] + width # x轴长度
if list_val[index] < 0.2:
# 最佳匹配度过低,采用众数匹配
list_l = np.arange(10, 500, 50)
list_u = np.arange(10, 500, 50)
v = []
x = []
for i in list_l:
for k in list_u:
bg_edge = cv2.Canny(bg_image, i, k)
tp_edge = cv2.Canny(tp_image, i, k)
res = cv2.matchTemplate(bg_edge, tp_edge, cv2.TM_CCOEFF_NORMED) # 寻图
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) # 寻找最优匹配
v.append(max_val)
x.append(max_loc[0])
n = 0
for i in v:
if i == 1.0:
v[n] = 0
n += 1
word_dict = {}
n = 0
for word in x:
# 去除不匹配
if word > 10:
if word not in word_dict:
word_dict[word] = v[n]
else:
word_dict[word] += v[n]
n += 1
# 修改滑动距离
X = max(word_dict, key=word_dict.get) + width
# 返回长度
return X
而这里引入专家,滑块识别中就是算子可以作为专家,每个算子专家会有自己的特长,将他们提供的正确答案汇总,则会提高正确答案准确率。
Roberts算子
优点:
定位精度高,尤其在检测垂直边缘时表现优异。
缺点:
对噪声敏感,容易在噪声较多的图像中产生虚假边缘。
边缘检测结果可能较粗,不够精细。
Prewitt算子
优点:
实现简单,计算效率高。
对噪声有一定的抑制能力。
缺点:
边缘定位精度相对较低,可能产生边缘模糊。
对于细节丰富的图像,可能忽略一些细小的边缘信息。
Sobel算子
优点:
对噪声有较好的平滑作用,能够减少噪声对边缘检测的影响。
提供边缘方向信息,有助于后续的边缘处理。
缺点:
检测出的边缘可能出现多像素宽度,影响边缘的精确性。
对于复杂纹理的图像,边缘检测效果可能不理想。
Laplacian算子
优点:
各方向同性,能够检测任意方向的边缘。
二阶微分增强了边缘定位能力,锐化效果更好。
缺点:
对噪声非常敏感,容易在噪声区域产生虚假边缘。
单独使用时,可能无法准确区分边缘和噪声。
模拟专家模型算法如下:
## 采用的是专家模型
def sliderSlipHigh(address, width=50):
"""
识别准确率为:0.9583
这里要说明一下,滑块可能与拼图的滑动长度不一致,要细微调整比例关系
address:图片地址和名字
width:从左边开始裁剪x轴宽度是多少
list_class:边缘识别阈值
list_d:边缘识别阈值下限
list_h:边缘识别阈值上限
list_val:保存每种阈值的最高匹配度
list_tl_x:保存每种阈值的滑动距离
return: X:移动X轴上的长度
"""
# Roberts算子
def Roberts(image):
kernelx = np.array([[-1, 0], [0, 1]], dtype=int)
kernely = np.array([[0, -1], [1, 0]], dtype=int)
x = cv2.filter2D(image, cv2.CV_16S, kernelx)
y = cv2.filter2D(image, cv2.CV_16S, kernely)
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
image = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
return image
# Prewitt 算子
def Prewitt(image):
kernelx = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]], dtype=int)
kernely = np.array([[-1, -1, -1], [0, 0, 0], [1, 1, 1]], dtype=int)
x = cv2.filter2D(image, cv2.CV_16S, kernelx)
y = cv2.filter2D(image, cv2.CV_16S, kernely)
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
image = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
return image
# Sobel 算子
def Sobel(image):
x = cv2.Sobel(image, cv2.CV_16S, 1, 0)
y = cv2.Sobel(image, cv2.CV_16S, 0, 1)
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
image = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
return image
# 拉普拉斯算法
def Laplacian(image):
dst = cv2.Laplacian(image, cv2.CV_16S, ksize=3)
image = cv2.convertScaleAbs(dst)
return image
# Roberts算子
# kernelx = np.array([[-1, 0], [0, 1]], dtype=int)
# kernely = np.array([[0, -1], [1, 0]], dtype=int)
# Prewitt 算子
# kernelx = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]], dtype=int)
# kernely = np.array([[-1, -1, -1], [0, 0, 0], [1, 1, 1]], dtype=int)
# x = cv2.filter2D(image, cv2.CV_16S, kernelx)
# y = cv2.filter2D(image, cv2.CV_16S, kernely)
# # Sobel 算子
# x = cv2.Sobel(image, cv2.CV_16S, 1, 0)
# y = cv2.Sobel(image, cv2.CV_16S, 0, 1)
#
#
# 转uint8
# absX = cv2.convertScaleAbs(x)
# absY = cv2.convertScaleAbs(y)
# image = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
# # 拉普拉斯算法
# dst = cv2.Laplacian(image, cv2.CV_16S, ksize=3)
# image = cv2.convertScaleAbs(dst)
# 图片预处理
def imageDeal(image,width):
# 指定裁剪区域的起始位置和宽度、高度
x = 0
y = 0
width = width # 从左边开始裁剪x轴宽度是多少
height = image.shape[0]
# 裁剪图像
tp_image = image[y:y + height, x:x + width]
bg_image = image[y:y + height, width:image.shape[1]]
# 高斯模糊
tp_image = cv2.GaussianBlur(tp_image, (5, 5), sigmaX=0)
bg_image = cv2.GaussianBlur(bg_image, (5, 5), sigmaX=0)
# 灰度直方图均衡
tp_image = cv2.equalizeHist(tp_image)
bg_image = cv2.equalizeHist(bg_image)
return tp_image, bg_image
# 识别图片边缘
# bg_edge = cv2.Canny(bg_image, 100, 200)
# tp_edge = cv2.Canny(c_image, 100, 200)
# 匹配算法
# res = cv2.matchTemplate(bg_edge, tp_edge, cv2.TM_CCOEFF_NORMED)
# min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) # 寻找最优匹配
# tl = max_loc # 左上角点的坐标
# print("匹配率:",max_val)
# X= tl[0]+width
# print(X)
list_val = [] # 匹配值
list_tl_x = [] # 匹配坐标
# 循环处理将图片进行匹配处理
def matchTemplate(bg_image, tp_image):
list_l = np.arange(10, 400, 50)
#list_l = np.arange(10, 200, 20) #更高精确度,但是时间更多一些
list_u = np.arange(10, 400, 50)
list_repeat = []
for i in list_l:
list_repeat.append(i)
for k in list_u:
if k not in list_repeat :
bg_edge = cv2.Canny(bg_image, i, k)
tp_edge = cv2.Canny(tp_image, i, k)
res = cv2.matchTemplate(bg_edge, tp_edge, cv2.TM_CCOEFF_NORMED) # 寻图
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) # 寻找最优匹配
list_val.append(max_val)
tl = max_loc # 左上角点的坐标
list_tl_x.append(tl[0])
# 通过不同算子的处理
image = cv2.imread(address, cv2.IMREAD_GRAYSCALE)
b, t = imageDeal(Roberts(image),width)
matchTemplate(b, t)
b, t = imageDeal(Prewitt(image),width)
matchTemplate(b, t)
b, t = imageDeal(Sobel(image),width)
matchTemplate(b, t)
b, t = imageDeal(Laplacian(image),width)
matchTemplate(b, t)
# 普通边缘识别
b, t = imageDeal(image,width)
matchTemplate(b, t)
# 显示裁剪后的图像
n = 0
for i in list_val:
if i == 1.0:
list_val[n] = 0
n += 1
word_dict = {}
n = 0
# 去除坐标异常的数据
for word in list_tl_x:
if word > 10 and word < image.shape[1] - width* 2 - 10:
if word not in word_dict:
word_dict[word] = list_val[n]
else:
word_dict[word] += list_val[n]
n += 1
# 排序
list_d = sorted(word_dict.items(), key=lambda d: d[1], reverse=True)
list_keys = []
for i in list_d:
list_keys.append(i[0])
# 使用集合来跟踪已考虑的元素
seen = set()
val_dict = {}
n = 3 # 聚类距离
# 寻找相似距离
def seen_find(number):
for i in seen:
if i - n <= number <= i + n:
return i
# 聚类合并
for i in list_keys:
change = 0
# 检查当前元素是否在允许的范围内
if not any(abs(i - k) <= n and k != i for k in seen):
change = 1
seen.add(i)
if i not in val_dict:
val_dict[i] = word_dict.pop(i)
if change == 0: # 当没有改变值的时候说明没有通过判断语句,所以是合并的值,将值放入
# 通过找到相似key来传递value
val_dict[seen_find(i)] += word_dict.pop(i)
# 拿取最大权重对应的距离
X = max(val_dict, key=val_dict.get) + width
# 返回长度
return X
其他领域思想参考:
对于图像识别多分类问题,可以训练识别几种分类作为一种专家,然后将几个专家协调起来,通过它们对图像的匹配度打分,或者是对图像多标签标记(颜色专家、形状专家)这样能实现小模型就能训练出特别好的效果。
标签:bg,匹配,val,滑块,list,image,cv2,tp,模拟 From: https://blog.csdn.net/weixin_52810349/article/details/144764610