机器学习 NLP 基本知识

一、自然语言处理(nlp)简介 一份思绪奔驰的前言: 语言的边界就是思想的边界。如果从人类所具有的一切中挑出一个事物,让它来显示出人与其他生物的不同之处,那一定是语言。语言是我们用来思考和交流的方式,我们的一切文明都构筑在这简单的一维序列中,可我们却几乎不曾深入了解过它。 有人说,我们不曾真正的理解语言,我们所有对语言的运用和理解,不过建立在婴儿及此后对他人的声音与书本上符号的猜测上。或许正是如此,但是我们依旧要做出猜测,向着语言的神秘进发,这是我们的信念,是我们认识我们的认识的开始。 (1)作为语言学的 nlp 早在计算机的上古时代,深度学习还未诞生的时候,自然语言处理作为语言学的一个领域就已诞生了,这个领域也被语言学家们称为计算机语言学。两个名称在一起,才表达出 nlp 的真正含义——通过机器处理语言。nlp 最早的研究方向是机器翻译,那时人们人为地总结语言的规律,对词汇进行标注,对语句进行句法分析。结果是人为的规则覆盖面不足,所设计的系统无法扩展。 (2)作为机器学习研究领域的 nlp 随着计算机的发展,出现了基于传统统计学习模型的自然语言处理方式。这些原始的模型较之之前有所进步,但受限于计算机性能,统计方法也遭遇了瓶颈。 直到近年来算力的发展,使得深度神经网络成为可能。深度神经网络结构中潜在的学习能力,在 nlp 领域发挥了作用。通过多维数据表示语言和含义,深度学习以高效且与人类认知过程相似的方式发挥了巨大的效果。 二、词向量 词汇作为符号,其形象是离散的;但词汇的所指作为定义,其含义却是丰富而连续的。比如说“母亲”这个词汇,既表示了这个概念所对应的事物是在一种血缘关系中的一方(她是孩子的母亲);又表示了这个事物是能繁殖者(母鸡);在一定程度上,同样表示了非血缘关系,但具有类似血缘关系的行为的个体(大地是母亲)。 偏个题,《来自深渊》中有对生骸语的类似的描述. 因此,我们就不能再将词汇只作为离散的符号看待了,不能认为词汇之间是相互排斥的关系了。我们需要将词汇看做某些元含义在不同程度下的集合,或者从机器学习的角度,把这些元含义称作特征。那么也就是说,我们将每个词汇都看成一定维度的向量。 但是我们要如何确定特征呢?特征的数量又有多少?如果人工地确定特征为“存在、含义、物质、精神”等等,这一过程将耗费精力且永无止境。实际上按照机器学习的一般策略,我们只需要通过统计文本,自发的构建词汇向量即可。 这一方面有许多算法,如 N-gram 算法,GloVe 算法等等。另外也可以在深度学习的过程中利用反向传播自发的调整词向量,在 pytorch 中这通过 Embedding 层来实现。 三、循环神经网络(RNN)及其变体 (1)朴素 RNN 考虑我们说话或写作时的基本逻辑。对于一段语言序列,在之后的词汇总是和之前的词汇有关,未表达的部分总是已表达部分的补全或补充。循环神经网络的机制类似,我们需要用一个或多个隐藏变量作为对之前语句含义的表示,在输出下一个词汇时,会让隐藏变量参与决策;同时每多说完一个词汇,这个词汇也会更新隐藏变量,以实现表达含义的更新。 具体来说,我们用 $t$ 表示时间序列,对某一时间 $t$,$x_t$ 表示输入,$y_t$ 表示输出,$h_t$ 表示隐含状态。那么朴素的 RNN 网络即: $$ h_t = tanh(W^{(hx)} x_t + W^{(hh)} h_{t-1}) $$ $$ y_t = W^{(S)} h_t $$ 容易看出 RNN 和 Moore 自动机有相似之处。 其中 $W^{(hx)}, W^{(hh)}, W^{(S)} h_t$ 分别为三个不同的矩阵。RNN 的激活函数也可以选择 ReLU。同时可以为激活函数中的部分添加偏置(bias)$b^{(hx)}, b^{(hh)}$ 等。...

一月 17, 2023 · 2 分钟 · 328 字 · Wokron

Spring 面向切面

一、面向切面(AOP) 有时,在按数据的处理流程编写程序时,我们不得不关心流程之外的情况,比如异常处理安全或日志。这些部分与主要事务交织在一起,使得代码功能不清,造成了强耦合。 面向切片(Aspect-Oriented Programming)就是为解决这样的问题产生的技术。该技术把那些横向影响了应用多处的功能从被其影响的主要事物流程中分离开来,作为切面。使流程只需要关注其本身,而切片则通过其他方式织入程序。 二、面向切面的术语 正如面向对象有其术语一样,面向切面也有用于描述其技术的相关概念,在介绍 Spring 的面向切面前需要加以解释。 通知(Advice) 通知是切面所具有的行为,也就是不采用面向切面编程时,那些与主要事务无关,应该被抽离出来的代码段。 连接点(Join Point) 连接点是可以应用通知的地方,也就是能够执行切面所具有的行为的地方。 切点(Poincut) 切点是真正应用通知的地方,切点一定是连接点。 切面(Aspect) 切面是通知和切点的总和。当程序执行到切点所在的位置时,就会执行对应的通知。 引入(Introduction) 引入是作为切面的类作用到处理主要事务的类的过程。这一过程为处理主要事物的类引入了新的方法和属性,但却没有对这个类本身进行修改。 织入(Weaving) 织入是为了实现切面的引入而采取的操作。织入将切面引入目标对象,创建了融合切面和目标的代理对象。这一操作可以发生在编译期、类加载期和运行期,需要看具体的实现。Spring 会在运行期完成切面的织入。 三、Spring的AOP:利用切点表达式选择切点 通知和切点共同组成了切面,在这一部分将讲述如何确定切点的位置。我们使用的是称为切点表达式的语法规范,用这一表达式确定我们所指定的切点,以便之后通知的编写。 Spring AOP 使用的是 AspectJ 切点指示器中的一部分,包括如下的内容 AspectJ指示器 描述 arg() 限制连接点匹配参数为指定类型的执行方法 @args() 限制连接点匹配参数由指定注解标注的执行方法 execution() 用于匹配是连接点的执行方法 this() 限制连接点匹配AOP代理的bean引用为指定类型的类 target 限制连接点匹配目标对象为指定类型的类 @target() 限制连接点匹配特定的执行对象,这些对象对应的类要具有指定类型的注解 within() 限制连接点匹配指定的类型 @within() 限制连接点匹配指定注解所标注的类型(当使用Spring AOP时,方法定义在由指定的注解所标注的类里) @annotation 限定匹配带有指定注解的连接点 通过组合使用这些类似于函数的指示器的,就可以确定我们想要引入通知的连接点究竟在哪里。接下来我们通过一些示例展示切点表达式的使用。如 execution(* concert.Performance.perform(..)) 表示匹配一个在方法执行时触发的连接点,这个方法是 concert 包下的 Performance 类中名为 perform 的方法,不考虑方法的返回值和参数(匹配所有同名的 perform 方法)。 切点表达式中还可以使用与(&&)或(||)非(!)操作。如 execution(* concert.Performance.perform(..)) && within(concert.*) 表示同时满足是 concert 包下的类方法调用,并且满足上一条的条件的切点。...

一月 10, 2023 · 3 分钟 · 433 字 · Wokron

Spring 高级装配

上一篇文章已经讲解了 spring 依赖注入装配的方法。但是为了处理一些特殊的问题,或者为了更好地实现某些功能,spring 还提供了更多的装配设置。 一、条件化声明 Bean 让我们回到上一篇第一节的例子,假设这次我们需要在开发时使用 SQLite,而在生产环境使用 Oracle 要怎么办呢? 或许可以这样,我们在生产环境注意将 DBUtil Bean 改成 Oracle,把原来的部分注释掉,就像是这样。 @Bean public DBUtil databaseUtil() { // return new SQLiteUtil(); // for dev return new OracleUtil(); // for prod } 但这样做很明显是不合适的。如果许多组件都需要进行调整的话,修改上就会十分复杂,且很容易出错。 我们可以使用注释 @Profile 实现不同环境条件下选择不同的装配方式。这需要给带有 @Bean 或 @Configuration 注释的方法或类添加注释 @Profile("某某环境")。于是数据库的选择就可以改为如下形式: @Bean @Profile("dev") public DBUtil sqliteUtil() { return new SQLiteUtil(); } @Bean @Profile("prod") public DBUtil oracleUtil() { return new OracleUtil(); } 想要启用某个 Bean 需要设置环境。具体来说,这通过两个环境变量来实现,spring.profiles.default 和 spring.profiles.active。这两个值可以在许多地方定义。一种方式是在 properties 或 yaml 文件中定义,如...

一月 10, 2023 · 3 分钟 · 502 字 · Wokron

Spring 依赖注入

一、依赖注入 考虑这样一个例子,CustomerDAO 类使用了 DBUtil 类中的方法连接到 MySQL 数据库 public class CustomerDAO { private DBUtil databaseUtil = new DBUtil(); public Customer findCustomerByName(String name) { databaseUtil.doSomething() } } 假设现在想要改为使用 Oracle 数据库,需要怎么做?可以使用 OracleDBUtil 继承 DBUtil,并重写其相关方法。但是由于 CustomerDAO 中将 DBUtil 实例添加到其初始化过程中。因此想要修改的话还是需要对 CustomerDAO 本身进行修改。这违反了开-闭原则。 public class CustomerDAO { private DBUtil databaseUtil = new OracleDBUtil(); public Customer findCustomerByName(String name) { databaseUtil.doSomething() } } 为了使对 dbUtil 的修改不影响 CustomerDAO 本身,我们可以将实例的创建移到 CustomerDAO 之外。 public class CustomerDAO { private DBUtil databaseUtil; public CustomerDAO(DBUtil databaseUtil) { this....

一月 9, 2023 · 3 分钟 · 481 字 · Wokron

Django 创建表结构

一、对象关系映射(ORM) 面向对象与关系型数据库中的数据存储方式并不匹配,因此为了在编程中实现对数据库的操作,需要 ORM 技术将数据库中数据映射到对象之中。通过对对象的操作,做到对数据库的操作,从而实现增删改查等功能。 面向对象编程中,“关系”体现在类与其属性之间以及同一类的不同属性之间;而在关系型数据库中,“关系”体现在同一表中的不同列字段中。 二、django 的 ORM 实现 django 通过 models.Model 类来对应数据库中的表结构,如 class User(models.Model): 即表示了 User 类,也对应了数据库中的 user 表。django 会根据类的声明自动在数据库中建表。 django 用类中的属性来表示表的列字段。如 class User(models.Model): id = models.IntegerField(primary_key=True) name = models.CharField(max_length=50) password = models.CharField(max_length=50) 定义了 user 表的主键、名字、密码信息。 表间关系通过类与其属性表示,如 class User(models.Model): id = models.IntegerField(primary_key=True) name = models.CharField(max_length=50) password = models.CharField(max_length=50) courses = models.ManyToManyField(to="Course") courses 属性表示用户具有的课程,反映了用户与课程之间的关系。 三、类属性与数据库字段的对应 如上一节所述,django 建立了类属性与数据库字段之间的对应关系。常见的如 models.CharField models.TextField models.IntegerField models.FloatField 就对应了数据库中的 char(n),text,int,float 类型。不一一详述。 四、主键与外键 在表中要定义主键,作为该表一条记录的唯一标识。相应的,在 django 中定义主键需要在对应属性上添加 primary_key=True 参数。例如...

一月 9, 2023 · 2 分钟 · 234 字 · Wokron

用 Pytorch 搭建神经网络

一、前言 本文作为自己学习 pytorch 的记录。以搭建一个神经网络为例,介绍 pytorch 的基本使用。 本文不会讲 conda、python、pycharm 等的配置和使用,也不会讲各神经层的原理及使用。只是按照自己之前学习的理解,总结神经网络训练的基本流程。 本文所使用的例子是自己写的第一个神经网路,如下: import os.path import torch.utils.data from torch.utils.data import DataLoader from torch import nn from torch.utils.tensorboard import SummaryWriter from torchvision import transforms, datasets device = torch.device("cpu") if torch.cuda.is_available(): print("cuda available, use cuda to train module") device = torch.device("cuda") train_set = datasets.CIFAR10("./CIFAR10", transform=transforms.ToTensor(), download=True) test_set = datasets.CIFAR10("./CIFAR10", transform=transforms.ToTensor(), train=False, download=True) train_set_size = len(train_set) test_set_size = len(test_set) print(f"train set size: {train_set_size}") print(f"test set size: {test_set_size}") train_dataloader = DataLoader(train_set, 64, shuffle=True, drop_last=True) test_dataloader = DataLoader(test_set, 64) class MyModule(nn....

一月 2, 2023 · 5 分钟 · 884 字 · Wokron