召回模塊:規則過濾器

日萌社

人工智能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 總結

  • 瞭解規則過濾器的作用和實現

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章