#!/usr/bin/python3 # -*- coding: utf-8 -*- import difflib from typing import List, Tuple import editdistance from project_settings import project_path from toolbox.string.tokenization import FastTokenizer class ChunkSearcher(object): def __init__(self, vocab_file: str = (project_path / "data/vocab.txt").as_posix() ): # 需要一个多语言的分词器. (找一个多语言 bert 的词汇表). self.tokenizer = self.init_tokenizer(vocab_file) @staticmethod def init_tokenizer(vocab_file): tokenizer = FastTokenizer() with open(vocab_file, "r", encoding="utf-8") as f: for row in f: token = str(row).strip() tokenizer.insert(token) return tokenizer def chunk_search(self, chunk: str, content: str, win_size_radio: float = 1.5): chunk_tokens, _ = self.tokenizer.tokenize(chunk) content_tokens, _ = self.tokenizer.tokenize(content) counter = [0] * len(content_tokens) win_score = [0] * len(content_tokens) for token1 in chunk_tokens: if len(token1.strip()) == 0: continue for idx, token2 in enumerate(content_tokens): if token1 == token2: counter[idx] = 1 win_size = len(chunk_tokens) * win_size_radio win_size = int(win_size) for begin in range(0, len(content_tokens) - win_size, 1): win = counter[begin: begin+win_size] score = sum(win) win_score[begin] = score idx = win_score.index(max(win_score)) match = content_tokens[idx: idx+win_size] match_content = "".join(match) match_content = self.rstrip_match_content(chunk, match_content) match_content = self.rstrip_match_content(chunk[::-1], match_content[::-1]) match_content = match_content[::-1] return match_content def rstrip_match_content(self, chunk: str, match_content: str): differ = difflib.Differ() diff = differ.compare(match_content, chunk) operation_list = list() for d in diff: operation = d[0] operation_list.append(operation) r_strip_count = 0 for operation in reversed(operation_list): if operation != "-": break r_strip_count += 1 if r_strip_count != 0: match_content = match_content[:-r_strip_count].strip() return match_content class ChunkSimilarity(object): def edit_distance(self, chunk: str, match_content: str) -> List[Tuple[str, float, str]]: edit_distance = editdistance.distance(chunk, match_content) chunk_length = len(chunk) content_length = len(match_content) normalized_edit_distance = edit_distance / (chunk_length + content_length) normalized_edit_distance2 = 2 * edit_distance / (chunk_length + content_length) result = [ ("edit_distance", edit_distance, ""), ( "ed_score", round(1 - normalized_edit_distance, 4), "1 - d / (l1 + l2)" ), ( "ed_score2", round(1 - normalized_edit_distance2, 4), "1 - 2*d / (l1 + l2)" ), ] return result def seq_match(self, chunk: str, match_content: str) -> List[Tuple[str, str, str]]: seq_match = difflib.SequenceMatcher() seq_match.set_seqs(chunk, match_content) score = seq_match.ratio() result = [ ("seq_match", round(score, 4), "(2.0*M / T) similar to edit_distance"), ] return result def similar(self, chunk: str, match_content: str): result = [ ("metric", "score", "note") ] scores = self.edit_distance(chunk, match_content) result.extend(scores) scores = self.seq_match(chunk, match_content) result.extend(scores) return result PAGE_CONTENT = """ 40 麦肯锡中国金融业 CEO季刊 2023年秋季刊 2023年人工智能发展现状: 生成式 AI的突破之年 Michael Chui ,Eric Hazan ,Lareina Yee ,Bryce Hall ,Alex Singla 和Alexander Sukharevsky如 今 ,生 成 式 AI工具遍地开花, 各组织均在快速部署; 麦肯锡调查的 受访者们预计, 该技术将对自己所在行业及就业产生重大影响。 41 2023年 人 工 智 能 发 展 现 状 :生 成 式 AI的突破之年 麦肯锡针对人工智能发展现状的最新年度全球调研结果证实, 生 成式人工智能 (简称 GenAI )工 具 已 出 现 爆 炸 式 增 长 。许 多 此 类 工 具 至 今 推 出 尚 不 满 一 年 ,但 已 有 1/3的 受 访 者 表 示 ,其 所 在 组 织 会 在 至少一项业务职能中经常使 用 GenAI 。 随着这些最新进展, 人工智 能 已 经 从 一 个 技 术 话 题 上 升 为 企 业 领 导 的 关 注 焦 点 :近 1/4受访高 管 表 示 ,他 们 会 在 工 作 中 使 用 GenAI 工具; 而在已应用人工智能的 企 业 中,有 超 过 1/4的受访者表示 GenAI 已 被 列 入 董 事 会 议 程 。此 外 , 40% 的受访者表示, 其所在组织将会因 GenAI 的最新进 展而增加对 人工智能的整体投入。 调查结果表明, GenAI 相关风险管理仍处于 早期阶段: 即便是针对受访者眼中最常见的不准确问题, 也只有不 """ CHUNK = """2023年人工智能发展现状:生成式AI的突破之年""" CHUNK1 = """ Among these PEFT methods, the reparameterization-based method low-rank adaptation (LoRA) (Hu et al.,2021) is considered one of the most efficient and effective methods at present. LoRA is especially popular after open-sourced LLMs become ubiquitous (Dettmers et al., 2023). LoRA assumes that the change of the model’s parameters for adaptation is intrinsically low-dimensional and performs adaptation by optimizing the matrix obtained from low-rank decomposition. Since it is in the form of weight matrix reparameterization, LoRA parameters can be merged with the original LLMs and cause no forward propagation latency. """ def main(): from project_settings import project_path searcher = ChunkSearcher() match_content = searcher.chunk_search( CHUNK, PAGE_CONTENT, win_size_radio=1.6, ) print(match_content) chunk_similarity = ChunkSimilarity() scores = chunk_similarity.similar(CHUNK, match_content) print(scores) return if __name__ == "__main__": main()