机器学习
1.机器学习的概述
1.1.1机器学习工作流程
#人工智能发展必备三要素:
数据,算法,计算力(CPU:适合I\O密集型的任务,GPU:适合计算密集型任务,TPU)
人工智能-->机器学-->深度学习
1.2机器学习的工作流程
1.获取数据
2.数据的基本处理
3.特征工程
4.机器学习
5.模型评估
#数据集介绍
1.行为样本,列为特征
2.数据类型构成:
特征值+目标值(目标值是连续的和离散的)
只有特征值,没有目标
#数据的基本处理
即对数据进行缺失值、去除异常值等处理
# 特征工程
什么是特征工程:特征工程是使用专业背景知识和技巧处理数据,使得特征能在机器学习算法上发挥更好的作用的过程。
为什么需要特征工程:数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已
特征工程包含的内容:
特征提取
特征预处理
特征降维
#机器学习
#模型评估
1.Numpy的优势
"Numpy中的ndarray与Python原生list运算效率对比"
1.
Numpy中的ndarray在存储数据的时候数据与数据的地址都是连续的
python原生list存储数据的时候数据与数据的地址并不是连续的
因此在处理大量的数据Numpy中的nadarry执行效率更高同样通用性方面Python原生list更强
2.ndarray支持向量化运算
3.Numpy底层使用C语言编写,内部解除了GIL
2.N维数组-ndarray
a = np.array([[1,2,3],[4,5,6]])
1.ndarray.shape 2*3的数组
2.ndarray.size 数组中由6个元素组成
3.ndarray.ndim 2维数组
4.ndarray.dtype 数组元素是为int32类型
5.ndarray.itemsize 一个int类型的元素占据4个字节
3.基本操作
"1:生成0和1的数组"
np.ones(shape, dtype) / np.ones_like(a, dtype)
np.zeros(shape, dtype) / np.zeros_like(a, dtype)
"2 从现有数组生成"
np.array(object, dtype)#深拷贝
np.asarray(a, dtype) #浅拷贝
"3 生成固定范围的数组"
np.linspace(0, 100, 11) #创建等差数组
np.arange(10, 50, 2) #创建等差数组
np.logspace(0, 2, 3) #10^x
"4.生成随机数组"
"正态分布"
1.np.random.randn(3,2)#从均值为0方差为1的标准正太分布中返回3行2列的随机数组
np.random.normal(1.75, 1, (3,2))#均值1.75 标准差为1,100000000个
np.random.standard_normal((3,2))#从标准正态分布的数组中产生3行2列的的数组。 注意:传参形式
"均匀分布"
2. np.random.rand(3,2)#在[0,1]的均匀分部内产生3行2列的随机数组
#注意:不同于torch.rand([3,4])的传参
np.random.uniform(40, 100, (10, 5))#生成均匀分布的随机数 元素类型为浮点型
np.random.randint(40, 100, (10, 5), dtype='l')#在[40,100]的均匀分布中生成10行5列的随机数组 元素类型为int型
1.stock_change.reshape([5, 4])
2.stock_change.resize([5, 4])
3.ndarray.T
1.stock_change.astype(np.int32)
2.ndarray.tostring() #将数组元素转换成Python字节
3.np.unique() #数组的去重
4.ndarray运算
#1.逻辑运算
#2.通用判断函数
np.all(score[0:2, :] > 60)#是否所有的满足条件
np.any(score[0:2, :] > 60)#是否有一个满足条件
#三元运算符
np.where(temp > 60, 1, 0)#满足条件的为1不满足条件为0
注意:可以和np.logical_and和np.logical_o连用
- 数组间运算
"1. 数组与数的运算"
"2 数组与数组的运算"
广播机制的两个必要条件:
1.数组的某一维度等长。
2.其中一个数组的行或列的维度为1
pytorch
1.Pytorch中创建张量
-
torch.tensor[[1., -1.], [1., -1.]])
-
torch.tensor(np.array([[1, 2, 3], [4, 5, 6]])
-
torch.empty(3,4)
torch.ones(3,4)
torch.zeros(3,4)
torch.rand(3,4)
torch.raindint(3, 10, (2, 2))
2.Pytorch中tensor的常用方法
1.tensor的基本操作
#1.取tensor中的数据(当tensor中只有一个元素可用)
a.item()
#2.转化为numpy数组
a.numpy()
#3.获取形状
a.size()
#4.改变形状
a.view([2,3,5])
b.view(5,-1) #把b展开之后等分为5分
#5.获取阶数
a.dim() #[3,4]二维数组
#6.获取最大值
a.max()
tensor.max(dim=-1)#dim=-1获取行方向最大值
#7.转置:
a.t()
#8.获取数据类型:
a.dytpe
#9.交换行列
b.transpose(0,1)
#10.b.add_(1)
2.tensor的运算
import torch
a = torch.tensor([1,2,3])
b = torch.tensor([0,0,0])
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device
a.device
a = a.to(device)#把tensor转换成cuda支持的tensor
tensor.cpu()#把cuda的tensor转换成cpu上的tensor
梯度下降和反向传播
1.梯度是什么
"""
梯度:是一个向量,导数+变化最快的方向(学习的前进方向)
梯度就是多元函数参数的变化趋势(参数学习的方向),只有一个自变量时称为导数
"""
2.反向传播算法
"1 计算图和反向传播"
反向传播:先计算最后一层偏导,之后在计算倒数第二层偏导
"2.神经网络中的反向传播 示意图/计算图:使用图来表示一个中间计算,用中间变量表示每一次的计算结果 "
注意:书写错误
Pytorch完成线性回归
1.向前计算
"1.requires_grad"
定义:追踪对于该张量的所有操作
使用方法:a.requires_grad_(True)
"2.grad_fn"
定义:用来记录做过的操作
使用方法:b.grad_fn
"3.with torch.no_grad():"
定义:防止跟踪历史记录
使用方法:
with torch.no_grad():
c = (a * a).sum()
""
2.梯度计算
1.y.backward#计算梯度函数
2.x.grad #保存梯度
3.tensor.data #require_grad=True时,tensor.data仅仅是获取tensor中的数据
4.tensor.numpy()#require_grad=True不能够直接转换,需要使用tensor.detach().numpy()
3.线性回归的实现
import torch
learning_rate=0.1
# 1.准备数据
x = torch.rand([500,1])
y = 3 * x + 0.8
w = torch.rand([], requires_grad=True)
b = torch.tensor(0, dtype=torch.float,requires_grad=True)
for i in range(500):
for j in [w, b]:
# 每次反向传播前把梯度置为0
if j.grad is not None:
j.grad.data.zero_()
# 2. 计算预测值
y_predict = x * w + b
# 3. 计算损失
loos = (y_predict - y).pow(2).mean()
loos.backward()
# 4.更新预测值
w.data -= learning_rate * w.grad
b.data -= learning_rate * b.grad
if i % 10 == 0:
print(i, loos.item(), w.item(), b.item())
#绘图
plt.figure(figsize=(20,8))
plt.scatter(x.numpy(),y.numpy())
y_predict=x*w +b
plt.plot(x.numpy(),y_predict.detach().numpy(),c='red')
plt.show()
Pytorch完成基础模型
- Pytorch完成模型常用API
"1.nn.Module"
1.定义:自定义网络的基类,构造模型类
init:
forward:
nn.Linear:为torch预定义好的线性模型,也称全链接层
class MyModel(nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.lr =nn.Linear(1,1)
def forward(self, x): #x [500,1] --->y_predit:[500,1]
return self.lr(x)
#1.实例化模型
model =MyModel()
"2.优化器类"
optimizer=optim.Adam(model.parameters(),lr=0.1) #实例化优化器
optimizer.zero_grad() #2. 梯度置为0
loss.backward() #3. 计算梯度
optimizer.step() #4. 更新参数的值
"3.损失函数:均方误差nn.MSELoss()/交叉熵损失nn.CrossEntropyLoss()"
criterion = nn.MSELoss() #2. 实例化损失函数
loss = criterion(y_true,y_predict) #5. 调用损失函数传入真实值和预测值,得到损失结果
"4.模型"
model.eval() #设置模型为评估模式,即预测模式
model.train(mode=True) #表示设置模型为训练模式
2.GPU上运行代码
"1.判断GPU是否可用"
torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
x = torch.rand([50,1]).to(device)
model = MyModel().to(device)
"""注意:
cuda的数据类型转换成 numpy类型和tensor类型
detach()是深拷贝,data是取值,是浅拷贝
predict = predict.cpu().detach().numpy()
"""
线性回归完整代码:
import torch
from torch import nn
from torch import optim
import numpy as np
from matplotlib import pyplot as plt
# 1. 定义数据
x = torch.rand([50,1])
y = x*3 + 0.8
#2 .定义模型
class Lr(nn.Module):
def __init__(self):
super(Lr,self).__init__()
self.linear = nn.Linear(1,1)
def forward(self, x):
out = self.linear(x)
return out
# 2. 实例化模型,loss,和优化器
model = Lr()
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=1e-3)
#3. 训练模型
for i in range(30000):
out = model(x) #3.1 获取预测值
loss = criterion(y,out) #3.2 计算损失
optimizer.zero_grad() #3.3 梯度归零
loss.backward() #3.4 计算梯度
optimizer.step() # 3.5 更新梯度
if (i+1) % 20 == 0:
print('Epoch[{}/{}], loss: {:.6f}'.format(i,30000,loss.data))
#4. 模型评估
model.eval() #设置模型为评估模式,即预测模式
predict = model(x)
predict = predict.data.numpy()
plt.scatter(x.data.numpy(),y.data.numpy(),c="r")
plt.plot(x.data.numpy(),predict)
plt.show()
3.常见的优化算法
算法 | 优点 | 缺点 |
---|---|---|
梯度下降算法(batch gradient descent BGD) | 每次迭代都需要把所有样本都送入 | 训练速度过慢 |
随机梯度下降法 (Stochastic gradient descent SGD) | 从样本中随机抽出一组,可能不用训练完所有的样本就可以获得一个损失值在可接受范围之内的模型了。torch.optim.SGD() | 单个样本的训练可能会带来很多噪声 |
小批量梯度下降 (Mini-batch gradient descent MBGD) | 每一次选择一波数据进行参数的更新 | 在到达最优点的时候并不能够总是真正到达最优点,而是在最优点附近徘徊。 |
动量法 | gradent=0.8▽w +0.2history_gradent w=w-α*gradent | |
AdaGrad | 将每一个参数的每一次迭代的梯度取平方累加后在开方,用全局学习率除以这个数,作为学习率的动态更新,从而达到自适应学习率的效果 g r a d e n t = h i s t o r y _ g r a d e n t + ( ∇ w ) 2 w = w − α g r a d e n t + δ ∇ w , \begin{align*}&gradent = history\_gradent + (\nabla w)^2 \\&w = w - \frac{\alpha}{\sqrt{gradent}+\delta} \nabla w ,\end{align*} gradent=history_gradent+(∇w)2w=w−gradent+δα∇w, | |
RMSProp | 进一步解决损失函数摆动幅度大的问题,并且进一步加快函数的收敛速度 g r a d e n t = 0.8 ∗ h i s t o r y _ g r a d e n t + 0.2 ∗ ( ∇ w ) 2 w = w − α g r a d e n t + δ ∇ w \begin{align*}& gradent = 0.8*history\_gradent + 0.2*(\nabla w)^2 \\& w = w - \frac{\alpha}{\sqrt{gradent}+\delta} \nabla w\end{align*} gradent=0.8∗history_gradent+0.2∗(∇w)2w=w−gradent+δα∇w | |
Adam(Adaptive Moment Estimation) | Adam=Momentum+RMSProp 使用:torch.optim.Adam()
1.
需要初始化梯度的累积量和平方累积量
v
w
=
0
,
s
w
=
0
2.
第
t
轮训练中,我们首先可以计算得到
M
o
m
e
n
t
u
m
和
R
M
S
P
r
o
p
的参数更新:
v
w
=
0.8
v
+
0.2
∇
w
,
M
o
m
e
n
t
u
m
计算的梯度
s
w
=
0.8
∗
s
+
0.2
∗
(
∇
w
)
2
,
R
M
S
P
r
o
p
计算的梯度
3.
对其中的值进行处理后,得到:
w
=
w
−
α
s
w
+
δ
v
w
<
b
r
/
>
\begin{align*}& 1. 需要初始化梯度的累积量和平方累积量 \\& v_w = 0,s_w = 0 \\& 2. 第 t 轮训练中,我们首先可以计算得到Momentum和RMSProp的参数更新:\\& v_w = 0.8v + 0.2 \nabla w \qquad,Momentum计算的梯度\\& s_w = 0.8*s + 0.2*(\nabla w)^2 \qquad,RMSProp计算的梯度\\& 3. 对其中的值进行处理后,得到:\\& w = w - \frac{\alpha}{\sqrt{s_w}+\delta} v_w\end{align*}<br/>
1.需要初始化梯度的累积量和平方累积量vw=0,sw=02.第t轮训练中,我们首先可以计算得到Momentum和RMSProp的参数更新:vw=0.8v+0.2∇w,Momentum计算的梯度sw=0.8∗s+0.2∗(∇w)2,RMSProp计算的梯度3.对其中的值进行处理后,得到:w=w−sw+δαvw<br/> |
Pytorch中的数据加载
1.模型中使用数据加载器的目的
深度学习数据量大不能一次性的训练完,为加快参数更新,提高训练效率所以使用数据加载器
2.数据集类
2.1Dataset基类介绍
1.torch.utils.data.Dataset
2. __getitem__:通过dataset[i]获取其中的第i条数据
__len__:获取其中的元素个数
2.2数据加载案例
from torch.utils.data import Dataset
class SmsDataset(Dataset):
def __init__(self):
self.file_path = "./data/SMSSpamCollection"
self.lines = open(self.file_path,'rb').readlines()
def __getitem__(self, index):
return self.lines[index].strip()
def __len__(self):
return len(self.lines)
if __name__ == '__main__':
dataset = SmsDataset()
print(dataset[0])
print(len(dataset))
"UnicodeDecodeError: 'gbk' codec can't decode byte 0x93 in position 6325: illegal multibyte sequence"
解决办法:
可能是要处理的字符串本身不是gbk编码,但是却以gbk编码去解码 。比如,字符串本身是utf-8的,但是却用gbk去解码utf-8的字符串,所以结果不用说,则必然出错
3.迭代数据集
"目的"
批处理数据(Batching the data)
打乱数据(Shuffling the data)
使用多线程 multiprocessing 并行加载数据
"API的使用"
data_loader = DataLoader(dataset=dataset,batch_size=10,shuffle=True,num_workers=2)
"注意:"
dataset的实例
batch_size:传入数据的batch的大小
shuffle:是否打乱数据
num_workers:加载数据的线程数
len(dataset) = 数据集的样本数
len(dataloader) = math.ceil(样本数/batch_size) 即向上
4.pytorch自带的数据集
4.1 torchversion.datasets
"图像数据处理"
1.torchvision.datasets.MINST
"文本数据处理"
2.torchtext.datasets.IMDB
4.2MNIST 数据集的介绍
from torchvision.datasets import MNIST
import torchvision
# 1.准备Minst数据集
mnist =MNIST(root="./data/minst",train=True,download=True)
print("1.",mnist)
print("2.",mnist[0])
print("3.",len(mnist))
print(mnist[0][0].show())
运行:
1. Dataset MNIST
Number of datapoints: 60000
Root location: ./data/minst
Split: Train
2. (<PIL.Image.Image image mode=L size=28x28 at 0x1D48B4095F8>, 5)
3. 60000
使用Pytorch实现手写数字识别
1.思路和流程分析
2.准备训练集和测试集
2.1 torchvision.transfroms的图形数据处理方法
2.1.1torchvision.transforms.ToTensor
"""
1.目的:PIL.Image或者shape为(H,W,C)的numpy.ndarray--->转换成形状为[C,H,W]
"""
H:高
W:宽
C:通道
"注意:"
1.t[2,4,3]==[大,行,列] ---->t[3,2,4]
2.t.transpose(0,2).transpose(1,2)
3.t.permute(2,0,1)
4.[[[]]]的括号个数无关于大
2.1.2 torchvision.transforms.Normalize(mean,std)
"1.将会把Tensor规范化处理"
img = transforms.ToTensor()(img) # 转换成tensor
#注意:
Normalized_image=(image-mean)/std
shape:指的每个通道的均值
std:指的是每个通道的方差
" 问题:IndexError: too many indices for tensor of dimension 0 "
解决办法:torchvision.transforms.Normalize((0.1307,),(0.3081,))
2.1.3 torchvision.transforms.Compose(transforms)
"将多个transform组合起来使用"
2.2准备MNIST数据集的Dataset和DataLoader
3.构建模型
3.1激活函数的使用
Relu激活函数由import torch.nn.functional as F提供
Relu函数:
y=0 y<0
y=x y>0
Relu函数的使用:
fc1_out_relu=F.relu(fc1_out)
3.2模型的损失函数
1.手写字体识别:多分类问题
2.二分类
2.1使用sigmoid:
P
(
x
)
=
1
1
+
e
−
x
=
e
x
1
+
e
x
P(x) = \frac{1}{1+e^{-x}} = \frac{e^x}{1+e^x}
P(x)=1+e−x1=1+exex
2.2使用
−
∑
y
l
o
g
(
P
(
x
)
)
-\sum y log(P(x))
−∑ylog(P(x))
3.多分类
3.1 使用softmax函数
3.2
J = − ∑ Y l o g ( P ) \begin{align*}& J = -\sum Y log(P)\end{align*} J=−∑Ylog(P)
其中 P = e z j ∑ k = 1 K e z K , Y 表示真实值 其中 P = \frac{e^{z_j}}{\sum^K_{k=1}e^{z_K}} ,Y表示真实值 其中P=∑k=1KezKezj,Y表示真实值
1.
criterion =nn.CrossEntropyloss()
1oss=criterion(input,target)
2.
output =F.log_softmax(x,dim=-1)#对输出计算softmax和取对数
loss=F.nll_loss(output,target)#使用torch中带权损失
4.模型训练
output = mnist_net(data) #进行向前计算 怎样的出来的
from tqdm import tqdm
bar=tqdm(enumerate(train_dataloader),total=len(train_dataloader))
bar.set_description('epcoh:{} idx:{},loss:{:.6f}'.format(epoch,idx,loss.item()))
循环神经网络和自然语言处理
1.文本的tokenization
2.N-gram表示方法
3.NLP中语言模型
1.语言模型的概念
2.语言模型的概率计算
3.N-gram语言模型概念
定义:在计算某个单词的概率的时候,不去考虑它全部的历史,而只考虑最近的N个词语(只感受前一个词语的影响,这就是二元语法模型类)
马尔科夫假设:一个词语只和他之前的有限个词语相关
4.N-gram中的平滑
目的:解决在使用极大似然估计(MLE)计算某个词语的概率的时候,会出现语料词语库中出现次数太少,或者没有出现的现象OOV(out of vocabulary),在平滑过程中我们会削减来自高计数的概率,然后填补0计数的概率
常用的平滑方法:
Laplace平滑/Good-Turing/插值法/回退法/Kneser-Ney平滑法
5.N-gram模型的评估:困惑(perplexity,PP)
词语的困惑度越小,意味着其中的单词概率乘积越大
6.N-gram语言模型的局限性
1.无法捕捉更长距离的依赖关系
2.当我们使用N捕捉长依赖的时候,会让参数呈指数级增长
3.泛化能力弱
4.神经网络语言模型
1 相比于传统的语言模型,在输入和输出上的额外操作:(Bengio2003语
言模型)
1.1:使用可训练的向量代表一个词语
1.2:根据场景不同输出可以是一个词语的概率或者其他
5.向量化
1.one-hot编码
2.word embedding:使用浮点型的稠密矩阵来表示token (token---> num ---->vector)
3.torch.nn.Embedding(num_embeddings,embedding_dim)
文本情感分类
1.案例介绍
2.思路分析
3.基础Dataset的准备
3.1.在dataset.py文件中
class ImdDataset(Dataset):
def __init__(self,train=True):
data_path =r"D:\Dpan\Document\PycharmProjects\day04\文本情感分类\data\aclImdb"
data_path +=r"\train" if train else r"\test"
self.total_path =[] #保存所有文件路径
for temp_path in [r"\pos",r"\neg"]:
cur_path =data_path +temp_path
self.total_path +=[os.path.join(cur_path,i) for i in os.listdir(cur_path) if i.endswith(".txt") ]
def __getitem__(self, idx):
file=self.total_path[idx]
#读取评论文本内容
review=utils.tokenlize(open(file).read())
#对评论文件名进行截取判断它是积极的还是消极的
label =int(file.split("_")[-1].split(".")[0])
#小于5就是0消极的反之则是1就是积极的
label =0 if label < 5 else 1
return review,label
def __len__(self):
return len(self.total_path)
3.2 在utils.py中定义tokenlize函数
import re
def tokenlize(sentence):
"""
进行文本分词
"""
filters=['!', '"', '#', '$', '%', '&', '\(', '\)', '\*', '\+', ',', '-', '\.', '/', ':', ';', '<', '=', '>',
'\?', '@', '\[', '\\', '\]', '^', '_', '`', '\{', '\|', '\}', '~', '\t', '\n', '\x97', '\x96', '”', '“', ]
# 把大写转化为小写
sentence =sentence.lower()
sentence=re.sub("<br />"," ",sentence)
# str.join(str):将原始字符串填充到参数的每个字符之间组成新的字符串返回
sentence =re.sub("|".join(filters)," ",sentence)
#split:使用参数作为分割线将原始字符串拆分成若干个字符串并组织成列表返回结果为列表
result =[i for i in sentence.split(" ") if len(i) >0]
return result
3.3在dataset.py中定义get_dataloader方法 和collate_fn方法
"在collate_fn中的默认值为default_collate会预想的值有所不同需要自己定义"
def collate_fn(batch):
review,label=zip(*batch)
#文本序列化小结
review =torch.LongTensor([config.ws.transform(i,max_len=config.max_len) for i in review])
label=torch.LongTensor(label)
return review,label
def get_dataloader(train=True):
dataset=ImdDataset(train)
batch_size= config.train_batch_size if train else config.test_batch_size
return DataLoader(dataset,batch_size=batch_size,shuffle=True,collate_fn=collate_fn)
"在config文件中"
"配置文件"
import pickle
train_batch_size =2
test_batch_size=500
"问题:NotImplementedError"
class Dataset(object):
"""An abstract class representing a Dataset.
All other datasets should subclass it. All subclasses should override
``__len__``, that provides the size of the dataset, and ``__getitem__``,
supporting integer indexing in range from 0 to len(self) exclusive.
"""
def __getitem__(self, index):
raise NotImplementedError
def __len__(self):
raise NotImplementedError
def __add__(self, other):
return ConcatDataset([self, other])
4.文本序列化
1.文本转-->向量-->数字
"""
把字典进行转换:
a = [1,2,3]
b = [4,5,6]
c = zip(a,b) #c=[(1, 4), (2, 5), (3, 6)]
c=dict(c) #c={1:4,2:5,3:6}
"""
class WordSequence():
UNK_TAG="<UNK>" #表示未知字符
PAD_TAG ="<PAD>" #填充符
PAD = 0
UNK =1
def __init__(self):
self.dict={self.UNK_TAG:self.UNK_TAG,self.PAD_TAG:self.PAD_TAG } #保存词语和对应的数字
self.count={}#统计词频
# 统计词频
def fit(self,sentence):
for word in sentence:
self.count[word]=self.count.get(word,0)+1
#self.count={"今天":1,"天气":1}
#根据条件构造词典:
def build_vocab(self,min_count=5,max_count =None,max_features=None):
"""
min_count:最小词频
max_count:最大词频
max_feature:最大词语数
1.对词语数量进行限制,对高频或者低频词语进行过滤
1.1 :根据min_count,max_count,把词频字典self.count={"今天":1,"天气":1}转换成列表[("今天",1),("天气",1)] 然后又将转化成字典
1.2: 根据max_features把词频字典self.count={"今天":1,"天气":1}转换成列表[("今天",1),("天气",1)]并进行排序 ,并取得最高的集几个词频,然后将其转化为字典
2.使用字典把词语和数字进行对应分别构造 self.dict ,self.inverse_dict
2.1:赋值self.dict={"今天":2,"天气":3}
2.2:赋值将self.dict={"今天":2,"天气":3} 转换成self.inverse_dict ={2:"今天",3:"天气"}
"""
if min_count is not None:
self.count={word:count for word,count in self.count.items() if count>=min_count}
if max_count is not None:
self.count={word:count for word,count in self.count.items() if count<=max_count}
if max_features is not None:
self.count =dict(sorted(self.count.items(),lambda x:x[-1],reverse=True)[:max_features])
for word in self.count:
self.dict[word] =len(self.dict)
self.inverse_dict =dict(zip(self.dict.values(),self.dict.keys()))
def transform(self,sentence,max_len=None):
"""
把句子转换成数字序列
sentence: [str ,str,str]
max_len:[int,int,int]
"""
return [self.dict.get(i,1) for i in sentence]
def inverse_transform(self,incides):
"""
把数字转化为字符
incides: [int,int,int]
return: [str,str,str]
"""
return [self.inverse_dict.get(i,"<UNK>") for i in incides]
if __name__ == '__main__':
sentences=[["今天","天气","很","好"],
["今天","去","吃","什么"]]
ws =WordSequence()
for sentence in sentences:
ws.fit(sentence)
ws.build_vocab(min_count=1)
print(ws.dict)
ret =ws.transform(["好","好","好","好","好","好","好","热","呀"],max_len=3)
print (ret)
ret=ws.inverse_transform(ret)
print(ret)
word_sequence的保存:
- 在word_sequence.py中
def transform(self,sentence,max_len=None):
"""
把句子转化为数字序列
:param sentence:[str,str,str]
:return: [int,int,int]
"""
if len(sentence) > max_len:
sentence = sentence[:max_len]
else:
sentence = sentence + [self.PAD_TAG] *(max_len- len(sentence)) #填充PAD
return [self.dict.get(i,1) for i in sentence]
def __len__(self):
return len(self.dict)
- 创建main.py
import pickle
from tqdm import tqdm
from dataset import get_dataloader
from word_sequence import WordSequence
if __name__ == '__main__':
ws=WordSequence()
#数据加载
dl_train=get_dataloader(True)
dl_test =get_dataloader(False)
#统计词频
for reviews,label in tqdm(dl_train,total=len(dl_train)):
for sentence in reviews:
ws.fit(sentence)
for reviews,label in tqdm (dl_test,total=len(dl_test)):
for sentence in reviews:
ws.fit(sentence)
#转换为字典
ws.build_vocab()
print(len(ws))
pickle.dump(ws,open("./models/ws.pkl","wb"))
注意:
"python的pickle模块实现了基本的数据序列和反序列化。"
1.pickle.dump(obj, file, [,protocol])
2.x = pickle.load(file)
循环神经网络
1.RNN定义
1.1循环神经网络(Recurrent Neural Network,RNN)是一类具有短期记忆能力的神经网络,神经元的输出可以在下一个时间步直接作用到自身
1.2在普通的神经网络中,信息的传递是单向的,这种限制虽然使得网络变得更容易学习,但在一定程度上也减弱了神经网络模型的能力。
2.分类
2.1:一对一 固长输入输出 图像分类
2.2:一对多 序列输出 图像转文字
2.3:多对一 数列输入 文本分类
2.4: 多对多 异步序列输入输出 文本翻译
2.4 : 同步序 列输入输出
3.LSTM
1.LSTM:(Long Short-Term Memory网络)
2.LSTM是一种RNN特殊的类型,可以学习长期依赖信息
3.LSTM是通过一个叫做门的结构实现,门可以选择让信息通过或者不通过。
4.LSTM的三个门
"1.遗忘门":决定哪些信息会被遗忘或者保存(使用sigmoid函数进行点乘从而决定遗忘或者保留)
"2.输入门":决定哪些信息会被更新(tanh会创造一个新的候选向量Ct)
"3.输出门":
5.GRU
1.GRU(Gated Recurrent Unit 门控循环单元),是一种LSTM的变形版本
2.两个门:更新门/输出门
6.双向LSTM
1.让模型不仅能够从前往后的具有记忆,还需要从后往前需要记忆
循环神经网络实现文本情感分类
1.LSTM api的使用
1.定义: lstm=torch.nn.LSTM(embedding_dim,hidden_size,num_layer,batch_first,dropout,bidirectional)
2.输入 输出:
lstm(input,(h_0,c_0))
output, (h_n, c_n)
batch_size=10
seq_len =20
num_embeddings=100
enbedding_dim=30
input =troch.ones([batch_size,seq_len],dtype=troch.long)
embedding =nn.Embedding(100,30)
input_embeded=embedding(input)
lstm=nn.LSTM(input_size=embedding_dim ,hidden_size=8,num_layer=2,batch_first=True,bidirectional=True)
output,(h_n,c_n)=lstm(input_embeded)
print(output.size())
print(h_n.size())
print(c_n.size())
***************************************************************
#获取最后一个时间步骤的输出
Last_output=output[:,-1,:]
h_n_last =h_n[-1,:,:]
#双向的LTSM中,最上层的最后一个输出
o1=output[:,-1,:8]#正向的最后一个输出
o2=output[:,0,8:]#反向最后一个输出
#双向LSTM中,最上层正向的h_n
h1=h_n[-2,:,:]#最上层正向
h2=h_n[-1,:,:]#最上层反向
print(o1.eq(h1))
print(o2.eq(h2))
线性回归
1.tanh()为双曲正切
2.ReLU():Rectified Linear Unit 修正线性单元
3.stochastic 随机
4.tokenization 符号化
"
1.子类中访问父类被重写的方法
"
class Animal(object):
def eat(self):
print("动物吃东西")
class Cat(Animal):
def eat(self):
print("猫吃鱼")
cat1 =Cat()
cat1.eat()
print(cat1)
1.父类名.方法名(对象)
Animal.eat(self)
2.super(本类名.对象).方法名()
super(Cat.self).eat()
3.super().方法()
super().eat()
操作格式/函数名称 | 功能 | 返回值 |
---|---|---|
str.casefold() | 字符串中所有字母转小写字母 | 字符串 |
str.swapcase() | 大小写互换 | 字符串 |
str.title() | 字符串中每个单词首字母大写,其余字母小写 | 字符串 |
str.capitalize() | 字符串首个字母大写 | 字符串 |
str.strip (str) | 去掉字符串左右两侧在参数字符串中包含的所有字符 | 包含多个字符串的列表对象 |
str.join(str) | 将原始字符串填充到参数的每个字符之间组成新的字符串返回 | 字符串 |
str.find() | 从左侧查找字符串从指定开始位置到指定结束位置间第一次出现的索引位置 | 结果是一个int整数,如没有查找到返回-1 |