A1
练习以下两个 Unix 命令的操作(根据 Markus Dickinson 的课程改编):
- 从
dates_in_may.txt
文件中创建一个单词列表,该列表按字母顺序排序,但排序方式是从右到左的。例如,tina
应该排在angst
之前。提示:命令rev
可以接受一个文件作为参数并反转每行的字符。将所有命令写入一个文件,输出结果写入另一个文件。 - 自动从
vm.pos
文件中创建一个包含词性标注(POS tags)的“字典”,即生成一个列表,每行有一个词性标注以及它的出现频率。假设所有的大写字母字符代表词性标注,而小写字母字符代表单词(因此可以删除小写字母)。
安装配置:MobaXterm,官网下载即可
任务一:难度⭐
新手村第一个小怪
简要概述:逆序单词表。思路是先把每个单词变成独立一行,再每一行的字符反转,按照字母排序,再反转回去,最后结果再输出到一个文件。
解答:
cat dates_in_may.txt | tr ' ' '\n'| tr 'A-Z' 'a-z'| tr -cd 'a-z\n_'| sed '/^$/d' | rev | sort | rev > a_result.txt
逐句解释:
cat dates_in_may.txt
:读文件,将文件内容作为输入流。tr ' ' '\n'
:把每个单词变成独立的一行tr 'A-Z' 'a-z'
:忽视大小写,全部变成小写,只关心具体的单词tr -cd 'a-z\n_'
:删除除了字母换行下划线的字符,因为考虑到数据集中有_Sound_Pattern_of_English这样的单词。sed '/^$/d'
:删除空行rev
:反转每一行字符sort
:对于反转后内容排序rev
:再反转回来,完成任务> a_result.txt
:最后一步,写入文件中
最终结果符合预期,部分结果如下。可以看到是按照右侧cd排序的
任务二:难度⭐⭐
略微复杂一点,但仍属于简单的范畴
简要概述:过滤出Tag,并统计排序
分析:数据内容RT,需要排除各种奇奇怪怪的符号,最终只留下WRB,VBZ这样的。注意:第一行中,BOS,NNK之类的编码不需要保留,所以需要小心的拆解。
解答:
cat vm.pos | tr -d 'a-z0-9[:punct:]' | sed 's/^[ \t]//;s/[ \t]$//' | sed '/^$/d' | grep '^[A-Z]*$' | sort | uniq -c | sort -nr > pos_frequency.txt
cat vm.pos
:读取文件的内容。tr -d 'a-z0-9[:punct:]'
:删除所有的小写字母(题目说了)、数字和标点符号,保留大写字母。sed 's/^[ \t]*//;s/[ \t]*$//'
:去除每行的前后空格,由上面数据可见,空格空格非常多。sed '/^$/d'
:删除空行。grep '^[A-Z]*$'
:此时我们需要的数据行已经只剩下纯大写字母,而编码内容还很混乱,我们筛选并保留只包含大写字母的行,即词性标注。sort
:对输出的词性标注按字典序排序,因为uniq -c只能统计连续重复的行。uniq -c
:统计每个词性标注的出现次数。sort -nr
:根据频率从高到低排序。> pos_frequency.txt
:保存,完成任务
最终结果符合预期,部分结果如下,BOS,NNK之类的编码没有保留:
A2
作业要求:
用 Unix 命令 来完成以下任务,并涉及两个语料库的比较分析:
- 统计“的”的频率:
- 比较 翻译汉语文本(ZCTC_raw) 和 原生汉语文本(LCMC_raw) 中“的”出现的频率。
- 分析“是…的”结构的频率:
- 比较 翻译新闻文本(ZCTC 中的 A B C 类) 和 原生新闻文本(LCMC 中的 A B C 类) 中“是…的”结构的频率。
- 提示:
- 需要使用正则表达式来匹配“是…的”结构,例如“我是交大的”“他是复旦的”。
- 使用分词后的文本文件(LCMC_seg 和 ZCTC_seg)。
- 统计“一 + 量词”结构:
- 根据文献(如 Hu and Kuebler 2021)的研究,翻译汉语中“一 + 量词”结构的频率高于原生汉语。
- 验证这一说法:
- 分别统计 LCMC 和 ZCTC 中最常见的 10 个“一 + 量词”结构及其频率。
- 统计每个语料库中“一 + 量词”结构的总频数。
- 使用带有词性标签的文本文件(LCMC_wordnpos 和 ZCTC_wordnpos)。
分析任务:
对于我们来说,核心任务就是使用 Unix 命令来完成文本搜索、匹配、计数等操作,并记录每条命令的作用。分析操作的结果,并讨论仅使用 Unix 命令完成这些任务可能存在的局限性。
任务一:难度⭐
任务要求:去统计文件夹ZCTC_raw和LCMC_raw下面所有文件中“的”出现频率。
解答思路:文本内容如下图所示,我们可用grep -o只匹配的部分,即一个“的”,单内容独成行,然后再统计行数即可。
代码实现:
# 在 LCMC_raw 文件夹中统计“的”的频率
grep -o '的' LCMC_raw/* | wc -l
# 在 ZCTC_raw 文件夹中统计“的”的频率
grep -o '的' ZCTC_raw/* | wc -l
最终结果如下,可以看出翻译文本中“的”数目显著高于原生汉语中“的”数目
- grep -o ‘的’ LCMC_raw/*:匹配 LCMC_raw 文件夹中所有文件中的“的”。
- wc -l:统计总频率。
但是这并不严谨,很显然我们并不清楚总数,此时的频率显得没有意义。于是使用下面指令统计总文本数,发现二者数目基本相当。所以此时认为翻译文本中“的”数目显著高于原生汉语中“的”数目
- wc -m LCMC_raw/*:统计每个文件的字符数,并列出每个文件的结果。
- tail -n 1:只取最后一行的总计(total)字符数。
任务二:难度⭐(⭐⭐⭐⭐)
任务要求:在LCMC_seg 和 ZCTC_seg文件夹下,统计”是…的”结构的频率
任务分析:文本已经被分开,目的还是正则匹配。示例内容概述为 A 是 B 的。如果只实现这样的内容很简单。但如何区分 A 是 B 和 C 的 ; A 是 B ,C 和 D 的。这仅仅通过正则表达式无法提取出来,具体来说:
- 交大 是 自由 ,美丽 和 和谐 的
- 你 是 谁 , 我 的 朋友 ?
很显然,第一句符合要求,第二句不符合要求。这两句没有办法通过简单的逻辑就区别出来,必须要比如词义分析后,才有可能区分出来。
这里我不妨大胆假设,需要的就是形如“A 是 B 的”这种简单句,这在一定程度上是可以说明趋势的。
解答:
# 在 ZCTC_seg 文件夹中统计ABC类中“是...的”的频率
grep -Eo '是 [^ ]+ 的' ZCTC_seg/ZCTC_A* ZCTC_seg/ZCTC_B* ZCTC_seg/ZCTC_C* | wc -l
# 在 LCMC_seg 文件夹中统计ABC类中“是...的”的频率
grep -Eo '是 [^ ]+ 的' LCMC_seg/LCMC_A* LCMC_seg/LCMC_B* LCMC_seg/LCMC_C* | wc -l
- grep -Eo ‘是 [^ ]+ 的’:正则匹配符合要求的,表达式表示中间除了开始空的一格,里面必须是非空格,这样保证是 的这种词被误入。-E是为了使用扩展正则表达式语法,-o为了分行统计
- LCMC_seg/LCMC_A* LCMC_seg/LCMC_B* LCMC_seg/LCMC_C*:观察文件格式得到的。去LCMC_seg文件夹下,得到三种文件,他们都以自己的类别打头
wc -l:统计行数,得到频率数。
结果如下,说明原生新闻中“是…的”出现评率低于翻译文本。
作业三:难度⭐⭐
在LCMC_wordnpos 和 ZCTC_wordnpos文件夹下,完成两件事
- 分别统计 LCMC 和 ZCTC 中最常见的 10 个“一 + 量词”结构及其频率。
- 统计每个语料库中“一 + 量词”结构的总频数。
任务分析:可以看到,在这两个文件夹下的文件,已经做好了词性标注,所以可以先去网站查出一和量词分别对应的POS tags(作业文档中有),然后正则即可。统计总数则简单了,直接看行数就是结果。
解答:
# 提取原生文本中的“一 + 量词”结构中最常见的10个
grep -Eho " 一/m [^ ]+/q" LCMC_wordnpos/* | sort | uniq -c | sort -nr | head -n 10
# 提取翻译文本中的“一 + 量词”结构中最常见的10个
grep -Eho " 一/m [^ ]+/q" ZCTC_wordnpos/* | sort | uniq -c | sort -nr | head -n 10
# 统计原生文本中“一 + 量词”结构的总频数
grep -Eho " 一/m [^ ]+/q" LCMC_wordnpos/* | wc -l
# 统计翻译文本中“一 + 量词”结构的总频数
grep -Eho " 一/m [^ ]+/q" ZCTC_wordnpos/* | wc -l
- grep -Eho:-h忽略文件名称,-E扩展正则表达式语法,-o为了分行统计
- ” 一/m [^ ]+/q”:按照词义,量词为/q,为了保证第一之类的词干扰,加了一个空格表示区分。
- LCMC_wordnpos/*:目录下全部文件。
- sort | uniq -c | sort -nr:统计每种结构的频率,并按降序排列。
- head -n 10:统计前十个
- wc -l:统计行数,也就是总数
如下图所示,TOP10出现的组合如下,可以看到基本趋势是差不多的,但是翻译文本 一种 出现的频率明显要更高。
所有出现的组合内容如下
所以翻译汉语中“一 + 量词”结构的频率高于原生汉语,基本得到验证(总数之前已完成统计,并无明显差异)
A3
难度:⭐⭐⭐⭐
SJTU超算不知道为什么不可以使用了?我的数据还在里面呢!?
一个好消息是之前写了一点记录https://www.haruhi.fans/?p=1108,坏消息是不符合报告格式,少测了很多很多东西。
炼丹,但是分为3个部分:(1)数据预处理;(2)模型训练;(3)模型评测
(1)数据预处理
开始是一个数据的清洗。清洗过后的数据格式大概是每一个汉字之间都有一个空格。至于英文单词,我也是如此,因为测试数据集如此。为了取得更高的分数,自然要面向数据集。
这样就完成了一个简单的清洗
(2)模型训练
我开始便是想要做一个最好的模型,记得老师提到困惑度最低的会给个小礼物(老师貌似忘了,那么最好肯定是要有最大的数据量,最高的层次,占用更大内存。但是内存过大会被交我算杀了,层过多会导致非常慢。经过一个trade-off最终如下面所示,交我办40核机器40-50分钟可以跑完训练。
cat data/full/*.txt | ./build/bin/lmplz -o 5 -S 15G > models/full/full2.arpa
(3)模型评测
对于这样大的一个模型,评测也是要花非常多时间的。评测一次也要将近1h的时间,最终困惑度大概56.多。
如果目标是冲击最高的分数,那么这个语料库和模型的能力上限就这个水平了,最多困惑度低1-2。4层到5层模型并没有变好多少,但花费时间却多了非常多,模型也大了好几倍,达到了好几十个G。可供调整的参数也不多。而且如果想要冲击更高分数,我完全可以用更多核服务器,更多时间在我的基础上修改,这与模型训练优化的初衷似乎有些违背。
A4
难度:⭐⭐⭐⭐⭐
完成一个一个一个逻辑回归项目。
配置环境推荐这一篇,讲的很详细。我还是推荐mnt挂在到系统里面一个具体位置去,这样方便操作,比如说我在E的cs124文件夹目录下,里面详细步骤都有介绍。
https://github.com/cs124/pa0-jupyter-tutorial/blob/main/platform/Windows.md
任务介绍:简单来说就是区分出一条消息是否aid的信息,并且需要找到和救援有关的信息。
为此,我们要做的是写六个函数Sigmoid,Logistic Loss 和 Logistic Regression Classifier中四个(__init__,train,classify,get_weights),最后模型评估,进行准确度测试(训练集和开发集上),和合理性检查
函数
Sigmoid
将模型的线性输出(z = W * X + b)映射到概率范围 [0, 1],按照提示使用sigmoid完成任务。
def sigmoid(x: np.ndarray) -> np.ndarray:
s = 1 / (1 + np.exp(-x))
return s
Logistic Loss
计算模型预测值与真实标签之间的损失(交叉熵损失)。这里为了防止log(0) 的问题,我们加入一个很小的epsilon,接着根据交叉熵定义完成此函数,最后返回一个平均值。使用np.clip()是为了严格保证概率处于(0, 1) 之间
def logistic_loss(y_pred: np.ndarray, y_true: np.ndarray) -> float:
epsilon = 1e-8
y_pred = np.clip(y_pred, epsilon, 1 - epsilon)
# 根据公式计算逻辑损失
losses = - (y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred))
return np.mean(losses)
下面就可以测测我们的损失了,预计值与真实值越接近,loss越低,可见趋势还是很明显的。可见哪怕是0和1也没有无穷大或者0,因为我们之前做了epsilon的缘故。
Logistic Regression Classifier
__init__()
初始化分类器的参数(如学习率、迭代次数等)和特征提取器。
但实际上他给的已经很够用了,我并没有任何的添加。由于梯度下降函数是不许变更的,那我们这部分其实自由发挥空间也并不多。
train()
训练逻辑回归模型。。example具体样子在上文提到过,可以见到是一个Vec
那么,我们需要做的是词向量变成句子,因为CountVectorizer
需要以字符串形式输入文本数据,而不是单个单词的列表。labels上面看到了,就是0和1,简单粗暴。
X根据上面梯度下降函数定义,是一个numpy array,我们要toarray()把他转变为密集矩阵,以便我们可以用它来进行梯度下降。
def train(self, examples: List[Example]) -> None:
texts = [" ".join(example.words) for example in examples]
labels = np.array([example.label for example in examples])
self.X = self.vectorizer.fit_transform(texts).toarray()
self.y = labels
self.weights, self.bias = gradient_descent(
X=self.X,
Y=self.y,
batch_size=self.batch_size,
alpha=self.alpha,
num_iterations=self.num_iterations,
print_every=self.print_every,
epsilon=self.epsilon
)
classify
用训练好的权重和偏置对新样本进行分类(0 或 1)。
先同理转换为texts,将文本转化为特征矩阵,计算线性模型的输出 z = X * W + b,再Sigmoid 函数映射到合理范围,返回结果。
def classify(self, examples: List[Example],
return_scores: bool = False) -> Union[List[int], List[float]]:
texts = [" ".join(example.words) for example in examples]
X = self.vectorizer.transform(texts).toarray()
z = np.dot(X, self.weights) + self.bias
scores = 1 / (1 + np.exp(-z))
if return_scores:
return scores.tolist()
else:
return [1 if score >= 0.5 else 0 for score in scores]
get_weights
返回训练好的权重向量。
def get_weights(self) -> np.ndarray:
return self.weights
结果:这些词都很符合我的直觉。
表现来看倒也正常,这个准确度不知道是否够好。这和他给我的结果倒是非常接近
stop_word,一些常见但意义较弱的词可能有噪声,去掉。但对我的结果并没有什么影响。但是实话说对我可能还是副作用,感觉可能是因为如果移除了停用词,可能会丢失一些上下文信息。例如,“like” 或 “to” 等词可能在上下文中有意义。
但是假阳性和假阴性结果还是存在。
从错误样本来看,False Negatives 中的文本往往是一些语义上复杂的句子,可能因为缺乏关键特征(如关键词)或上下文信息,导致模型未能识别出它们属于正类。
比如第一条 FN:"i'd like to get more information about the possibility of"
,可能比较模糊,
False Positives 中的文本通常包含一些强相关的词汇(如 “food,” “water,” “help,” 等),但这些词汇可能在上下文中并未真正表达灾难或紧急情况,而是出现在其他情境中。
第一条 FP:"these communities are in areas experiencing chronic food insecurity environmental problems and a general lack of basic services"
描述了某些困境,但是实际是负类。模型可能存在某些过拟合?导致将负类样本误判为正类
下面修改参数尝试优化。
先是尝试分类标准给成0.4,并无显著差异,硬要说那就是略有上升
当我改成0.6后,甚至出现了一定的下降。看来目前0.5以下处于一个比较合理的区间
那么再来0.3,自然显著下降。
尝试从min_df着手,之前FN有些不就是看不出来,尝试变大变小看看。这个表示CountVectorizer考虑频率的最低值。
min_df设置为10,从准确度来看,emm,no stopword removal的这两者的区别变大了。训练速度变的非常感人。
min_df设置为30,肉眼可见训练速度快了不少
也尝试过许多其它参数,比如学习率,训练数等等。但是实际感觉意义不大,Accuracy和Loss并没有显著变化,当然训练论述多,可能会更好一点点。但没有什么本质区别,区别只是时间的长短。
所以,如果想要得到更好的结果,就如上面分析一样,那么需要的应该是更好的特征捕捉,捕捉更深的词义。模型所限,优化上线如此。
A5
难度:⭐⭐⭐⭐⭐⭐⭐
Part1:Synonyms
同义词。我们的任务是完成答题,比如说找到战士的相似的词。原理就是那几种距离表示相似度。这里只需要完成四个函数,euclidean_distance,cosine_similarity,find_synonym,part1_written
euclidean_distance
计算两个向量之间的欧氏距离,就是空间中两点距离。
np.linalg.norm就是算泛式,默认是第二泛式也就是欧氏距离。
def euclidean_distance(v1, v2):
euclidean_dist = np.linalg.norm(v1 - v2)
return euclidean_dist
cosine_similarity
计算两个向量之间的余弦相似度,计算两个向量的点积,然后除以它们的模(即向量的长度)来得到的。图上大概就是两个向量之间的夹角
def cosine_similarity(v1, v2):
dot_product = np.dot(v1, v2)
magnitude_v1 = np.linalg.norm(v1)
magnitude_v2 = np.linalg.norm(v2)
cosine_sim = dot_product / (magnitude_v1 * magnitude_v2)
return cosine_sim
find_synonym
就是开始做题了,去根据相似度,找到正确的答案。如果使用余弦相似度,选择相似度最高的词;如果使用欧氏距离,选择距离最小的词。如果使用余弦相似度(’cosine_sim’),将 best_score 设为负无穷大,因为我们希望找到最大值。如果使用欧几里得距离(’euc_dist’),将 best_score 设为正无穷大,因为我们希望找到最小值。
def find_synonym(word, choices, embeddings, comparison_metric):
answer = None
best_score = float('-inf') if comparison_metric == 'cosine_sim' else float('inf')
for choice in choices:
if comparison_metric == 'cosine_sim':
score = cosine_similarity(embeddings[word], embeddings[choice])
if score > best_score:
best_score = score
answer = choice
elif comparison_metric == 'euc_dist':
score = euclidean_distance(embeddings[word], embeddings[choice])
if score < best_score:
best_score = score
answer = choice
return answer
part1_written
模型可能会选择“悲观的”而不是“积极的”,因为在训练数据中,“乐观的”和“悲观的”可能在向量空间中更接近,尽管它们的意思相反。
答案与预期一致,第一部分完成。
Part2:Analogies
类比,a:b → aa:bb,我们这里完成一个类比的推演,原理类似于平行四边形。比如说“男人:国王 → 女人:女王”
find_analogy_word()
a , b , aa,我们去找打那个最好的bb,在候选词列表中找到最能完成类比的词(利用余弦相似度作为相似性度量)。就是先平行四边形,算出期望的边,再比较相似度,选择余弦相似度最大的。
def find_analogy_word(a, b, aa, choices, embeddings):
answer = None
best_score = float('-inf')
analogy_vector = embeddings[b] - embeddings[a] + embeddings[aa]
for choice in choices:
choice_vector = embeddings[choice]
cosine_sim = np.dot(analogy_vector, choice_vector) / (
np.linalg.norm(analogy_vector) * np.linalg.norm(choice_vector)
)
if cosine_sim > best_score:
best_score = cosine_sim
answer = choice
return answer
最终结果如下,与预期一致。
Part 3: Sentence Similarity
语句相似。简单来说,给你两个句子,用0 or 1,来说明两个句子语义是否接近。比如说“我吃了饭”和“饭被我吃了”这样相似。具体实现来说就是通过余弦相似度(cosine similarity)计算两个句子嵌入向量之间的相似度,如果超过一定阈值,就认为他们相似。这里是实现两个函数,get_embedding和get_similarity。
将句子转化为单个向量嵌入的步骤有以下两种方式,要么简单求和,把子中每个单词的嵌入向量相加,得到一个总的句子向量。要么基于词性加权求和
get_embedding
将输入的句子转化为一个句子嵌入(向量表示)。初始化0向量,对于words分词,判断是否开朗根据语义分词,是的话先获取每一个的词性,加权求和,最后归一化。不是的话每个词都一样,最后还是加权求和。
def get_embedding(s, embeddings, use_POS=False, POS_weights=None):
embed = np.zeros(embeddings.vector_size)
words = word_tokenize(s)
if use_POS:
tagged_tokens = nltk.pos_tag(words)
total_weight = 0.0
for word, tag in tagged_tokens:
if word in embeddings and tag in POS_weights:
embed += embeddings[word] * POS_weights[tag]
total_weight += POS_weights[tag]
if total_weight > 0:
embed /= total_weight
else:
count = 0
for word in words:
if word in embeddings:
embed += embeddings[word]
count += 1
if count > 0:
embed /= count
return embed
get_similarity
计算两个句子的余弦相似度。s1,s2就是我们那两个句子。
开始将句子 s1
和 s2
转换为固定维度的嵌入向量 embed1
和 embed2
。检查下保证不是空向量,计算我们的余弦相似度,返回即可。是空向量就直接0.
def get_similarity(s1, s2, embeddings, use_POS, POS_weights=None):
similarity = 0
embed1 = get_embedding(s1, embeddings, use_POS, POS_weights)
embed2 = get_embedding(s2, embeddings, use_POS, POS_weights)
if np.linalg.norm(embed1) > 0 and np.linalg.norm(embed2) > 0:
similarity = np.dot(embed1, embed2) / (np.linalg.norm(embed1) * np.linalg.norm(embed2))
else:
similarity = 0.0
return similarity
可以看到,结果与预期完全一致,表明经过加权求和得到的效果更好,准确度更高。
Part 4: Exploration
有了前面的积累,现在就可以来解决实际问题了
occupation_exploration
需要实现一个函数,根据职业名称列表和词嵌入模型,找到与单词 “man” 以及 “woman” 最相似的5个职业。职业之间的相似度使用余弦相似度进行衡量。
先检查是否是man和woman,是的话继续提取词向量。然后对于合规的职业,分别计算余弦相似度,添加到相似度列表,最后排序得到了前5的职业
def occupation_exploration(occupations, embeddings):
top_man_occs = []
top_woman_occs = []
if 'man' not in embeddings or 'woman' not in embeddings:
raise ValueError("Embeddings for 'man' and 'woman' are required.")
man_embedding = embeddings['man']
woman_embedding = embeddings['woman']
man_similarities = []
woman_similarities = []
for occ in occupations:
if occ in embeddings:
occ_embedding = embeddings[occ]
similarity_to_man = np.dot(man_embedding, occ_embedding) / (np.linalg.norm(man_embedding) * np.linalg.norm(occ_embedding))
similarity_to_woman = np.dot(woman_embedding, occ_embedding) / (np.linalg.norm(woman_embedding) * np.linalg.norm(occ_embedding))
man_similarities.append((similarity_to_man, occ))
woman_similarities.append((similarity_to_woman, occ))
man_similarities.sort(key=lambda x: x[0], reverse=True)
woman_similarities.sort(key=lambda x: x[0], reverse=True)
top_man_occs = [occ for _, occ in man_similarities[:5]]
top_woman_occs = [occ for _, occ in woman_similarities[:5]]
return top_man_occs, top_woman_occs
part4_written
一些职业更接近“男人”,而另一些职业更接近“女人”,这反映了社会中存在的性别刻板印象。可能是因为用于训练词向量的数据中包含了这些偏见,导致模型学习到了这些关联。
Part 5: Entity Representation
使用 命名实体识别模型 (NER Model) 从 Wikipedia 的文档中提取命名实体 (Named Entities)。例如,Barack Obama 是一个命名实体,类别为“人名”。提取命名实体后,研究哪些实体彼此相似。
extract_named_entities
给一段文本,使用 SpaCy 的自然语言处理功能提取命名实体。
用nlp对象,把我们的段落转化为SpaCy文档,文档提取文档中的命名实体并返回。
def extract_named_entities(paragraph):
global nlp
spacy_paragraph = nlp(paragraph)
named_entities = list(spacy_paragraph.ents)
return named_entities, spacy_paragraph
compute_entity_representation
为每个实体构建一个表示向量,使用描述中的词嵌入计算实体的平均向量,收集所有符合条件的词的嵌入向量,并计算它们的平均值。
遍历描述中的每个词,检查其是否为停用词,并在嵌入字典中。
def compute_entity_representation(description, embeddings):
vector = None
word_vectors = []
for token in description:
if not token.is_stop and token.text.lower() in embeddings:
word_vectors.append(embeddings[token.text.lower()])
if word_vectors:
vector = np.mean(np.array(word_vectors), axis=0)
return vector
get_top_k_similar
计算给定实体嵌入与一组候选实体嵌入之间的相似性,返回最相似的前 k 个实体。
首先对实体嵌入和候选嵌入进行归一化,使用 NumPy 的矩阵乘法计算余弦相似度,最后根据相似度排序并选择前 k 个最相似的实体。
def get_top_k_similar(entity_embedding, choices, top_k):
similar_entities = []
if not choices:
return similar_entities
choice_names = list(choices.keys())
choice_embeddings = np.array(list(choices.values()))
entity_embedding_norm = entity_embedding / np.linalg.norm(entity_embedding)
choice_embeddings_norm = choice_embeddings / np.linalg.norm(choice_embeddings, axis=1, keepdims=True)
similarities = np.matmul(choice_embeddings_norm, entity_embedding_norm)
top_k_indices = np.argsort(similarities)[::-1][:top_k]
similar_entities = [choice_names[i] for i in top_k_indices]
return similar_entities
结果非常好,符合要求。大于了他的要求
下面的准确度和分数也都遥遥领先,任务成功落下帷幕。
大论文
难度:⭐⭐(⭐⭐⭐⭐⭐⭐⭐⭐)
采用了星火大模型,为什么呢?因为他免费额度最多了,模型还比较好用。
我的计划是对于三种不同的任务,一种是文章内容梗概,一种是小红书文案生成,一种是活动策划。为什么选择这三种呢,是因为这三种对应的文本生成策略。文章内容梗概要求内容精确,遵循原文;小红书文案生成需要一定的扩展,但也要保证原有内容的覆盖;活动策划提示内容较少,大部分为自由发挥。