日萌社
人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度學習實戰(不定時更新)
2.5 規則過濾器
學習目標
- 目標
- 瞭解規則過濾器的作用
- 應用
- 無
2.5.1 規則過濾器
- 什麼是規則過濾器: 爲了保證推薦內容的多樣性, 合理性, 每次的推薦內容會在內部和上次數據間做一些比較和過濾操作
- 規則過濾器作用:防止推薦數據重複, 並可按照指定規則選擇性推薦,過濾掉不同用戶發表的相同的帖子(帖子ID不一樣,內容相似或者相同)
- 如何比較推薦出去的兩個pid內容相同?
規則過濾器主體函數代碼:
import requests
import cv2
def rfilter(r_data):
with _driver.session() as session:
def get_url(pid):
cypher = "match(a:SuperfansPost{pid:%d}) return a.iv_url" % (pid)
record = session.run(cypher)
result = list(map(lambda x: x[0], record))
if result:
return result[0]
# 獲取所有要推薦的圖片url帖子地址
url_list = list(
filter(
lambda x: x is not None, map(
lambda x: get_url(x), r_data)))
# 1、帖子PID與圖片地址綁定
url_dict = dict(zip(url_list, r_data))
# 2、去重函數
url_list = d_hash_serve(url_list)
# 3、將去重之後的url和PID取出結果傳入排序模塊
result = list(map(lambda x: url_dict[x], url_list))
return result
那如何進行去重,分析步驟如下:
- 1、下載所有圖片到本地,保留圖片路徑列表
- 2、循環所有圖片列表,兩兩之間進行比較
- 通過opencv將兩個圖片的指紋進行漢明距離比較
比較圖片相同方式,獲取帖子的圖片地址然後進行相似度計算:
def d_hash_serve(url_list):
"""去重函數邏輯
"""
# 下載所有圖片
default_image = "test.png"
def download(url):
path = "./recomm/img_compare/"
try:
img = requests.get(url)
with open(path + url + ".jpg", "wb") as fp:
fp.write(img.text)
return path + url + ".jpg"
except BaseException:
return path + default_image
# 1、得到下載到本地之後的圖片列表
url_path = list(map(lambda url: download(url), url_list))
# 2、得到本地路徑與CDN路徑的對應字典
url_dict = dict(zip(url_path, url_list))
# 3、compare_img函數對該目錄下的圖片文件進行比較
compare_list = compare_img(path)
# 4、獲得比較之後應該刪除的重複圖片CDN路徑
compared_delete_list = list(
map(lambda x: url_dict[x], list(set(compare_list[::2]))))
# 5、根據CDN路徑進行列表元素刪除
list(map(lambda x: url_list.remove(x), compared_delete_list))
return url_list
def compare_img(root_path):
"""
比較圖片 (Main)
:param root_path: 目標文件夾
"""
compared_list = []
# 獲取目標文件夾下所有圖片路徑集合
img_list = get_all_img_list(root_path)
# 遍歷目標文件夾下所有圖片進行兩兩比較
for file1 in img_list:
# 已經發現是相同的圖片不再比較
if file1 in compared_list:
continue
im1 = cv2.imdecode(
np.fromfile(
file1,
dtype=np.uint8),
cv2.IMREAD_UNCHANGED)
print(im1)
if im1 is None:
continue
im1_size = os.path.getsize(file1)
# 獲取圖片指紋
img_fingerprints1 = get_img_gray_bit(im1)
print("第一張的指紋:", img_fingerprints1)
for file2 in img_list:
if file1 != file2:
# im2 = cv2.imread(files2)
im2 = cv2.imdecode(
np.fromfile(
file2,
dtype=np.uint8),
cv2.IMREAD_UNCHANGED)
if im2 is None:
continue
im2_size = os.path.getsize(file2)
print(im2_size)
# 如果兩張圖片字節數大小一樣再判斷漢明距離
if im1_size != im2_size:
# 獲取圖片指紋
img_fingerprints2 = get_img_gray_bit(im2)
print("第二張的指紋:", img_fingerprints2)
compare_result = get_mh(
img_fingerprints1, img_fingerprints2)
print(compare_result)
# 漢明距離等於0,說明兩張圖片完全一樣
if compare_result == 0:
compared_list.append(file2)
compared_list.append(file1)
return compared_list
def get_all_img_list(root_path):
"""
獲取目標文件夾下所有圖片路徑集合
:param root_path: 目標文件夾
:return: 圖片集合
"""
img_list = []
# 獲取目標文件夾下所有元組
root = os.walk(root_path)
# 循環元組,獲取目標文件夾下所有圖片路徑集合
for objects in root:
for obj in objects:
if "/" in str(obj):
# 記錄文件夾路徑
path = str(obj)
elif len(obj) > 0:
# 如果是文件,判斷是否是圖片。如果是圖片則保存進
for file in obj:
if "." in str(file) and is_image_file(file) == 1:
full_path = path + "/" + str(file)
img_list.append(full_path.replace("\\", "/"))
return img_list
def get_img_gray_bit(img, resize=(32, 32)):
"""
獲取圖片指紋
:param img: 圖片
:param resize: Resize的圖片大小
:return: 圖片指紋
"""
# 修改圖片大小
image_resize = cv2.resize(img, resize, interpolation=cv2.INTER_CUBIC)
# 修改圖片成灰度圖
image_gray = cv2.cvtColor(image_resize, cv2.COLOR_BGR2GRAY)
# 轉換灰度圖成浮點型
image_gray_f = np.float32(image_gray)
# 獲取灰度圖的DCT集合
image_gray_dct = cv2.dct(image_gray_f)
# 獲取灰度圖DCT集合的左上角8*8
# gray_dct_ul64_list = get_gray_dct_ul64_list(image_gray_dct)
gray_dct_ul64_list = image_gray_dct[0:8, 0:8]
# 獲取灰度圖DCT集合的左上角8*8對應的平均值
# gray_dct_ul64_avg = get_gray_dct_ul64_avg(gray_dct_ul64_list)
gray_dct_ul64_avg = cv2.mean(gray_dct_ul64_list)
# 獲取圖片指紋
img_fingerprints = get_img_fingerprints(
gray_dct_ul64_list, gray_dct_ul64_avg)
return img_fingerprints
def get_img_fingerprints(gray_dct_ul64_list, gray_dct_ul64_avg):
"""
獲取圖片指紋:遍歷灰度圖左上8*8的所有像素,比平均值大則記錄爲1,否則記錄爲0。
:param gray_dct_ul64_list: 灰度圖左上8*8的所有像素
:param gray_dct_ul64_avg: 灰度圖左上8*8的所有像素平均值
:return: 圖片指紋
"""
img_fingerprints = ''
avg = gray_dct_ul64_avg[0]
for i in range(8):
for j in range(8):
if gray_dct_ul64_list[i][j] > avg:
img_fingerprints += '1'
else:
img_fingerprints += '0'
return img_fingerprints
def get_mh(img_fingerprints1, img_fingerprints2):
"""
獲取漢明距離
:param img_fingerprints1: 比較對象1的指紋
:param img_fingerprints2: 比較對象2的指紋
:return: 漢明距離
"""
hm = 0
for i in range(0, len(img_fingerprints1)):
if img_fingerprints1[i] != img_fingerprints2[i]:
hm += 1
return hm
def is_image_file(file_name):
"""
判斷文件是否是圖片
:param file_name: 文件名稱(包含後綴信息)
:return: 1:圖片,0:非圖片
"""
ext = (os.path.splitext(file_name)[1]).lower()
if ext == ".jpg" or ext == ".jpeg" or ext == ".bmp" or ext == ".png":
return 1
return 0
在_get_recomm函數中加入規則過濾器
def _get_recomm(IP, uid):
"""整體推薦流程
:param IP: 用戶的IP
:param uid: 用戶ID
:return:
"""
# 1、召回的模塊接口實現
hot_data = _get_hot()
last_data = get_last()
v_data = get_v()
r_data = get_r(uid)
random_data = get_random()
# 合併召回結果
all_data = [hot_data] + [last_data] + [v_data] + [r_data] + [random_data]
# 金字塔結構實現,給PID分配權重排序輸出pid
j_data = pyramid_array(all_data)
# 將數據寫入金字塔緩存
r_data = j_data_write(uid, j_data)
# 規則過濾器
f_data = rfilter(r_data)
return r_data
2.5.2 總結
- 瞭解規則過濾器的作用和實現