文本表示(二)c&w模型

文本表示(二)

c&w模型

在前面提到的神经网络语言模型中,词向量只是一个副产品,并不是核心任务(它主要训练了一个用来度量语言流畅程度的模型,其中词向量是它中间产品),而且神经网络模型中的矩阵运算操作会极大的降低模型的训练效率。

所以如果目标只是学习词向量的话,可以没必要采用语言模型的方式,而可以直接从分布式假说的角度来设计模型和目标函数,c&w模型就是直接以学习和优化词向量为最终任务的。

模型定义

  • 给定训练语料中的任意一个n元组(n=2C+1): ( w i , C ) = w i − C . . . w i − 1 w i w i + 1 . . . w i + C (w_i,C)=w_{i-C}...w_{i-1}w_iw_{i+1}...w_{i+C} (wi,C)=wiC...wi1wiwi+1...wi+C
  • 如果将中心词 w i w_i wi随机的替换成词汇表中的任意其他词 w i ′ w^{\\'}_i wi,得到一个新的n元组 ( w i ′ , C ) = w i − C . . . w i − 1 w i ′ w i + 1 . . . w i + C (w^{\\'}_i,C)=w_{i-C}...w_{i-1}w^{\\'}_iw_{i+1}...w_{i+C} (wi,C)=wiC...wi1wiwi+1...wi+C
  • 那么 ( w i , C ) (w_i,C) (wi,C)一定比 ( w i ′ , C ) (w^{\\'}_i,C) (wi,C)更加合理,即如果对每个n元组进行打分那么 ( w i , C ) (w_i,C) (wi,C)一定比 ( w i ′ , C ) (w^{\\'}_i,C) (wi,C)的分数高: s ( w i , C ) > s ( w i ′ , C ) s(w_i,C)>s(w^{\\'}_i,C) s(wi,C)>s(wi,C)

如图,是一个简单的前馈神经网络,目的是计算n元组的得分,并从得分区分文本是来自真实的训练文本还是随机生成的文本。真实的训练文本中的n元组 ( w i , C ) (w_i,C) (wi,C)为正样本,随机生成的文本 ( w i ′ , C ) (w^{\\'}_i,C) (wi,C)为负样本。
在这里插入图片描述

  • 首先,对于 s ( w i , C ) s(w_i,C) s(wi,C),将 w i − C . . . w i − 1 w i w i + 1 . . . w i + C w_{i-C}...w_{i-1}w_iw_{i+1}...w_{i+C} wiC...wi1wiwi+1...wi+C中的每一个词从词向量矩阵L中获取对应的词向量,并进行拼接作为第一层 h 0 h_0 h0
  • h 0 h_0 h0经过一层隐藏层的学习,得到 h 1 = f ( W 0 h 0 + b 0 ) h_1=f(W_0h_0+b_0) h1=f(W0h0+b0),其中f(·)是非线形激活函数
  • h 1 h_1 h1再经过线形变换,得到n元组 ( w i , C ) (w_i,C) (wi,C)的得分: s ( w i , C ) = W 1 h 1 + b 1 s(w_i,C)=W_1h_1+b_1 s(wi,C)=W1h1+b1
  • 在词向量优化的过程中,c&W模型希望每一个正样本应该比对应的负样本打分高1分: s ( w i , C ) > s ( w i ′ , C ) + 1 s(w_i,C)>s(w'_i,C)+1 s(wi,C)>s(wi,C)+1
  • 对于整个训练语料,模型需要遍历所有的n元组,并对目标函数进行最小化优化:
    • ∑ ( w i , C ) ∈ D ∑ w i ′ ∈ V m a x ( 0 , 1 + s ( w i ′ , C ) − s ( w i , C ) ) \sum_{(w_i,C)\in{D}}\sum_{w'_i\in{V}}max(0, 1+s(w'_i,C)-s(w_i,C)) (wi,C)DwiVmax(0,1+s(wi,C)s(wi,C))

总结

  • 从上面的运算图中可以看出,c&w是只有隐藏层到输出层的简单矩阵运算,计算复杂度相对于神经网络语言模型更为高效
  • 模型复杂度: o ( ∣ h ∣ ) o(|h|) o(h)
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言文本分类算法的实现主要分为以下几个步骤: 1. 数据预处理:将文本数据转换成数字,也就是将每个单词转换成一个数字。这可以通过词袋模型和TF-IDF算法来实现。 2. 特征提取:对文本数据进行特征提取,常用的特征包括词频、TF-IDF值、主题模型等。 3. 分类器训练:选择合适的分类器进行训练,常用的分类器包括朴素贝叶斯、支持向量机、决策树等。 4. 测试模型:使用测试集对训练好的模型进行测试,评估模型的性能。 下面是一个简单的C语言文本分类算法实现代码: ```c #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #define MAX_WORDS 10000 // 最大单词数 #define MAX_DOCS 1000 // 最大文档数 // 单词结构体 typedef struct _word{ char *text; // 单词内容 int count; // 单词出现次数 double idf; // 单词IDF值 }Word; // 文档结构体 typedef struct _doc{ char *text; // 文档内容 Word **words; // 文档包含的单词数组 int *counts; // 文档包含的单词出现次数数组 int num_words; // 文档包含的单词数 int label; // 文档类别 }Doc; // 数据集结构体 typedef struct _dataset{ Doc **docs; // 文档数组 int num_docs; // 文档数 Word **words; // 单词数组 int num_words; // 单词数 }Dataset; // 读取文本文件 char *read_file(char *filename){ FILE *fp = fopen(filename, "r"); if(fp == NULL){ printf("File not found!\n"); return NULL; } fseek(fp, 0, SEEK_END); long size = ftell(fp); char *text = (char *)malloc(size + 1); fseek(fp, 0, SEEK_SET); fread(text, size, 1, fp); fclose(fp); text[size] = '\0'; return text; } // 分割文本为单词数组 Word **split_text(char *text, int *num_words){ Word **words = (Word **)malloc(sizeof(Word *) * MAX_WORDS); char *token = strtok(text, " \n\t\r"); int count = 0; while(token != NULL){ int found = 0; for(int i = 0; i < count; i++){ if(strcmp(words[i]->text, token) == 0){ words[i]->count++; found = 1; break; } } if(!found){ Word *w = (Word *)malloc(sizeof(Word)); w->text = token; w->count = 1; words[count++] = w; } token = strtok(NULL, " \n\t\r"); } *num_words = count; return words; } // 计算单词IDF值 void calc_idf(Dataset *data){ for(int i = 0; i < data->num_words; i++){ int num_docs = 0; for(int j = 0; j < data->num_docs; j++){ for(int k = 0; k < data->docs[j]->num_words; k++){ if(strcmp(data->docs[j]->words[k]->text, data->words[i]->text) == 0){ num_docs++; break; } } } data->words[i]->idf = log((double)data->num_docs / (double)num_docs); } } // 数据集预处理 void preprocess(Dataset *data, char **filenames, int num_files){ for(int i = 0; i < num_files; i++){ char *text = read_file(filenames[i]); Word **words = split_text(text, &(data->docs[i]->num_words)); data->docs[i]->text = text; data->docs[i]->words = words; } for(int i = 0; i < data->num_docs; i++){ int *counts = (int *)calloc(data->num_words, sizeof(int)); for(int j = 0; j < data->docs[i]->num_words; j++){ for(int k = 0; k < data->num_words; k++){ if(strcmp(data->docs[i]->words[j]->text, data->words[k]->text) == 0){ counts[k] = data->docs[i]->words[j]->count; break; } } } data->docs[i]->counts = counts; } calc_idf(data); } // 训练朴素贝叶斯分类器 void train_naive_bayes(Dataset *data, double *priors, double **likelihoods){ for(int i = 0; i < data->num_docs; i++){ priors[data->docs[i]->label]++; for(int j = 0; j < data->num_words; j++){ likelihoods[data->docs[i]->label][j] += data->docs[i]->counts[j] * data->words[j]->idf; } } for(int i = 0; i < 2; i++){ double total = 0.0; for(int j = 0; j < data->num_words; j++){ total += likelihoods[i][j]; } for(int j = 0; j < data->num_words; j++){ likelihoods[i][j] /= total; } priors[i] /= (double)data->num_docs; } } // 预测文档类别 int predict(Dataset *data, double *priors, double **likelihoods, char *filename){ char *text = read_file(filename); Word **words = split_text(text, &(data->docs[data->num_docs]->num_words)); Doc *doc = (Doc *)malloc(sizeof(Doc)); doc->text = text; doc->words = words; int *counts = (int *)calloc(data->num_words, sizeof(int)); for(int i = 0; i < doc->num_words; i++){ for(int j = 0; j < data->num_words; j++){ if(strcmp(doc->words[i]->text, data->words[j]->text) == 0){ counts[j] = doc->words[i]->count; break; } } } doc->counts = counts; double scores[2] = {0.0}; for(int i = 0; i < 2; i++){ for(int j = 0; j < data->num_words; j++){ scores[i] += likelihoods[i][j] * doc->counts[j] * data->words[j]->idf; } scores[i] += log(priors[i]); } int label = (scores[0] > scores[1]) ? 0 : 1; return label; } // 主函数 int main(){ char *filenames[MAX_DOCS] = {"doc1.txt", "doc2.txt", "doc3.txt", "doc4.txt"}; Dataset *data = (Dataset *)malloc(sizeof(Dataset)); data->num_docs = 4; data->num_words = 0; data->docs = (Doc **)malloc(sizeof(Doc *) * data->num_docs); for(int i = 0; i < data->num_docs; i++){ data->docs[i] = (Doc *)malloc(sizeof(Doc)); data->docs[i]->label = i % 2; } char *text = read_file(filenames[0]); Word **words = split_text(text, &(data->num_words)); data->words = words; preprocess(data, filenames, data->num_docs); double priors[2] = {0.0}; double **likelihoods = (double **)malloc(sizeof(double *) * 2); for(int i = 0; i < 2; i++){ likelihoods[i] = (double *)calloc(data->num_words, sizeof(double)); } train_naive_bayes(data, priors, likelihoods); for(int i = 0; i < data->num_docs; i++){ int label = predict(data, priors, likelihoods, filenames[i]); printf("Document %d is classified as %d\n", i+1, label); } return 0; } ``` 上述代码实现了一个简单的朴素贝叶斯分类器,使用TF-IDF作为特征,并且只能分类两个类别。完整的文本分类算法还需要考虑更多的特征和更复杂的分类器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值