LSTM笔记

RNN, LSTM, GRU模型的作用, 构建, 优劣势比较,attention机:
https://blog.csdn.net/sinat_28015305/article/details/109355828?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167903492816800182195114%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=167903492816800182195114&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-109355828-null-null.142^v74^insert_down38,201^v4^add_ask,239^v2^insert_chatgpt&utm_term=RNN%E6%A8%A1%E5%9E%8B&spm=1018.2226.3001.4187

LSTM的输出和参数:
https://blog.csdn.net/ssswill/article/details/88429794?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167870775616800184190436%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=167870775616800184190436&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-3-88429794-null-null.142^v73^insert_down4,201^v4^add_ask,239^v2^insert_chatgpt&utm_term=LSTM%E8%BE%93%E5%87%BA%E6%98%AF%E4%BB%80%E4%B9%88&spm=1018.2226.3001.4187
# 数据集的准备
1:定义好Field
2:建立词表
3:建立迭代器

import spacy
import torchfrom torchtext.datasets import Multi30k #pytorchtext自带的Multi30k数据集
from torchtext.data  import Field,BucketIterator# 1:定义好Field
#创建分词器器
spacy_en=spacy.load("en_core_web_sm")#英语分词器
spacy_de=spacy.load("de_core_news_sm")#德语分词器def en_seq(text):return [word.text for word in spacy_en.tokenizer(text)]def de_seq(text):return [word.text for word in spacy_de.tokenizer(text)][::-1]#源端倒序#源端的处理手段
#field函数的参数说明:https://blog.csdn.net/bqw18744018044/article/details/109150802
SRC=Field(tokenize=de_seq,#分词函数init_token="<sos>", #起始字符eos_token="<eos>", #结束字符lower=True) #把数据转换为小写#目标端的处理手段
TRG=Field(tokenize=en_seq,init_token="<sos>",eos_token="<eos>",lower=True)
#定义dataset数据集,这里将其数据经过fiels处理
#splits方法可以同时读取训练集,验证集,测试集
train_data,valid_data,test_data=Multi30k.splits(exts=(".de",".en"),fields=(SRC,TRG))print(f"Number of training examples: {len(train_data.examples)}")
print(f"Number of validation examples: {len(valid_data.examples)}")
print(f"Number of testing examples: {len(test_data.examples)}")

结果:

Number of training examples: 29000
Number of validation examples: 1014
Number of testing examples: 1000
#查看一下每一个样本,主要也是观察是否源端是否逆序:
vars(train_data.examples[1]) # vars() 函数返回对象object的属性和属性值的字典对象。

 

{'src': ['.','antriebsradsystem','ein','bedienen','schutzhelmen','mit','männer','mehrere'],'trg': ['several','men','in','hard','hats','are','operating','a','giant','pulley','system','.']}
# 2:建立词表#可以发现源端已经逆序。接下来为源端和目标端分别建立词表,要求每个词最少出现2次,否则为<unk>
SRC.build_vocab(train_data,min_freq=2) #min_freq:取出词汇表中大于等于该值的数据 
##设置最小词频为2,当一个单词在数据集中出现次数小于2时会被转换为<unk>字符。TRG.build_vocab(train_data,min_freq=2)#建立好词表以后,我们建立迭代索引,若batch_size=1的话,文本长度不相等也是无所谓的,但是batch_size>1的时候,就有有问题,同一批样本不一样长,那么我们在训练的时候,循环时间步到底设置多少,所以一般我们都会对句子进行pad操作补齐,幸运的是torchtext迭代器自动帮助pad填充,其中BucketIterator迭代器更是选择最合适的长度作为所有句子的固定长度,低于词长度的进行pad,高于此长度则进行裁剪。(这个固定长度是依据数据集里面所有的样本长度得出最合适的)# 3:建立迭代器
cuda = torch.cuda.is_available()#看GPU能不能用
print(cuda)BATCH_SIZE = 128 #一批次多少个词语
#建立迭代器
train_iterator, valid_iterator, test_iterator=BucketIterator.splits((train_data,valid_data,test_data),batch_size=BATCH_SIZE,device=torch.device('cuda' if cuda else 'cpu')
)for example in train_iterator:break
print('1:源数据设备,目标数据设备',example.src.device,example.trg.device,len(example))
print('2:源数据shape,目标数据shape',example.src.shape,example.trg.shape)
print('3:源数据',example.src)
print('4:目标数据',example.trg)
1:源数据设备,目标数据设备 cuda:0 cuda:0 128
2:源数据shape,目标数据shape torch.Size([27, 128]) torch.Size([29, 128])
3:源数据 tensor([[   2,    2,    2,  ...,    2,    2,    2],[   4,    4,    4,  ...,    4,    4,    4],[ 445, 1054,  284,  ...,  441,   34,  996],...,[   1,    1,    1,  ...,   16,    1,    1],[   1,    1,    1,  ...,    8,    1,    1],[   1,    1,    1,  ...,    3,    1,    1]], device='cuda:0')
4:目标数据 tensor([[  2,   2,   2,  ...,   2,   2,   2],[360,   7,   4,  ...,   4,   4,   4],[351, 399,  33,  ...,  14,   9,  14],...,[  1,   1,   1,  ...,   3,   1,   1],[  1,   1,   1,  ...,   1,   1,   1],[  1,   1,   1,  ...,   1,   1,   1]], device='cuda:0')

我们发现输出的样本是[seq_len,batch_size],而非[batch_size,seq_len]。我的习惯是batch_size放前面,但是Pytorch机制默认的是seq_len放在前面,后面的LSTM也是一样的。针对这个问题,可以通过permute函数进行交换

example.src=example.src.permute(1,0) #将0维和1维交换位置 就变为(一轮大小,句子长度)
example.trg=example.trg.permute(1,0)
print('源数据shape,目标数据shape:',example.src.shape,example.trg.shape)

这里我们必须要知道填充的位置,即 pad 的位置,因为无论是词嵌入的Embedding中还是计算损失函数的Loss中,都是不参与计算的。因此其,查看源端与目标端 pad 的index

# 建立模型import torch.nn as nn
class  Encoder(nn.Module):#src_vocab_size德语词汇表大小 有多少个词#emb_model词向量维度:用多少维来表示一个符号#hidden_size隐藏节点个数,n_layers层数def __init__(self,src_vocb_size,emb_model,hidden_size,n_layers,dropout):super(Encoder,self).__init__()self.embed=nn.Embedding(src_vocab_size,emb_model,padding_idx=1)self.lstm=nn.LSTM(input_size=emb_model,hidden_size=hidden_size,num_layers=n_layers,batch_first=True,dropout=dropout)# LSTM的输入:input(seq_len, batch_size, input_size) 、(初始的隐状态h_0,初始的单元状态c_0)# seq_len:如果一个句子有7个单词,则seq_len=7 # batch_size:一次性输入LSTM中的样本个数。一个轮回多少句话# 每个单词用一个100维向量来表示,那么这里input_size=100# h_0(num_directions * num_layers, batch_size, hidden_size)# c_0(num_directions * num_layers, batch_size, hidden_size)# 如果是双向LSTM,则num_directions=2# num_layers:层数# hidden_size:隐藏层节点个数。# LSTM输出由两部分组成:otput、(隐状态h_n,单元状态c_n)# output(seq_len, batch_size, num_directions * hidden_size)def forward(self,src):#src[batch_size,seq_len]src=self.embed(src)#src[batch_size,seq_len,emb_model]output,(h_n,c_n)=self.lstm(src) #没有指定h,c 就默认为0 和后面要采取强制教学做对比#output[batch_size,seq_len,hidden_size]  最后一层每个时间步的隐状态h_t#h_n[batch_size,n_layers,hidden_size] 最后一个时间步每层的隐状态(实际上并非这样,Pytorch机制原因)#c_n[batch_size,n_layers,hidden_size] 最后一个时间步每层的记忆c(实际上并非这样,Pytorch机制原因)return output,(h_n,c_n)#output的意义不大,主要是(h_n,c_n),其作为上下文向量

这里要重点提示一下的是:LSTM默认输入的是[seq_len,batch_size,embed]。若输入的是[batch_size,seq_len,embed],则需要将batch_first参数填写True。另一个值得注意的是LSTM的输出有3个变量,即output,(h_n,c_n),其中output是LSTM最后一层每个时间步的输出,h_n和_c_n为最后一个时间步每层的隐状态和记忆,其中经过batch_first以后,我们的输出是[batch_size,seq_len,hidden_sizen_direction]。但是h_n与c_n的shape均为[n_layersn_direction,batch_size,hidden_size],其并未将batch_size放于首位,以下进行编码器模型的测试与这个注意点检验:

#测试,参数
emb_model=256 #用256个数字描述一个词
hidden_size=512 #中间隐藏层为512个小点
n_layers=4 #一共四层
dropout=0.5 #置0比率
src_vocab_size=len(SRC.vocab) #词表长度#输入样本的维度
example.src.shape
结果:torch.Size([128, 27])
#建立源端模型
enModel=Encoder(src_vocab_size,emb_model,hidden_size,n_layers,dropout)
if(cuda):enModel=enModel.cuda()
output,(h_n,c_n)=enModel(example.src) #对源数据进行操作#只有输入input和输出output的batch会在第一维,hn和cn是不会变的。使用的时候要注意,会很容易弄混。
print('output大小,h_n大小,c_n大小:',output.shape,h_n.shape,c_n.shape)

结果:

output大小,h_n大小,c_n大小: torch.Size([128, 27, 512]) torch.Size([4, 128, 512]) torch.Size([4, 128, 512]

output(128个数表示一个词,这个句子27个词,中间隐藏层为512小点) h_n(4层,128个数表示一个词,中间隐藏层为512小点) c_n(4层,128个数表示一个词,中间隐藏层为512小点)

下面建立目标端,目标端的起始与源端几乎一样,不过与源端不一样的地方在于,目标端的输入不是特定的,其采用教学的形式,即要么自学(即上一时间步的输出是当前时间步的输入),要么教学(当前时间步的输入为目标端)。因此,在目标端中,我们无法一次性给定一个单词序列,而是一个一个单词的给入,即输入的seq_len=1。最后模型的输出我们需要将其映射到英语单词的向量空间中。还有一个值得需要提的就是lstm若不传入h和c则默认帮你创建一个全为0的h和c但是我们这里需要传入,传入的h和c不能以batch为开头!格式为[n_layers*n_direction,batch_size,hidden_size]。Pytorch为什么有了batch_first这里还不管,因为我们正常这两个参数用不到可能(个人猜测)

class Decoder(nn.Module):#trg_vocab_size 目标端的词汇表大小#emb_dim为词向量维度(我们将其设置与源端一样大小)#hidden_size 为目标端隐层维度(将其设置为与源端一样大小)#n_layers 网络层数(将其设置为一样大小)def __init__(self,trg_vocab_size,emb_dim,hidden_size,n_layers,dropout):super(Decoder,self).__init__()self.emb=nn.Embedding(trg_vocab_size,emb_dim,padding_idx=1)self.lstm=nn.LSTM(emb_dim,hidden_size,num_layers=n_layers,batch_first=True,dropout=dropout)#batch_first=True就是将batch放在第一维self.classify=nn.Linear(hidden_size,trg_vocab_size)#输入维度,输出维度def forward(self,trg,h_n,c_n):#trg为应该为[batch,seq_len],不过实际训练中是一个一个传入(要考虑是否采用强制教学),所以seq_len为1#trg真正的输入维度为[batch]#h_n与c_n是源端的上下文向量(若计算不指定,则默认为0(若Encoder编码中))#维度均为:[n_layers,batch_size,hidden_size]trg=trg.unsqueeze(1)#trg[batch,1]trg=self.emb(trg)#trg[batch,1,emb]output,(h_n,c_n)=self.lstm(trg,(h_n,c_n))#这里的lstm指定了h,c,因此其内部不会自己创建一个全为0的h,c#output[batch,1,emb]#h_i[1,batch,emb]#c_i[1,batch,emb]output=self.classify(output.squeeze())#output.squeeze()使得output[batch 1 emb]->[batch emb]#output[batch trg_vocab_size]return output,(h_n,c_n) #返回(h_n,c_n)是为了下一解码器继续使用#测试,参数
trg_vocab_size = len(TRG.vocab)Demodel=Decoder(trg_vocab_size,emb_model,hidden_size,n_layers,dropout)
if cuda:Demodel=Demodel.cuda()
#查看目标端的shape
print('目标端的shape:',example.trg.shape)#结果:
#目标端的shape: torch.Size([128, 29])trg=example.trg[:,1]#假设这一次为强制教学output,(h_n,c_n) = Demodel(trg,h_n,c_n)
print('h_n的shape:',h_n.shape)
print('c_n的shape:',c_n.shape)#结果:
#h_n的shape: torch.Size([4, 128, 512])
#c_n的shape: torch.Size([4, 128, 512])

我们用一个tensor保存每一个时间步映射到英语单词向量空间的输出(其实就是每一个Decode的输出),每一个输出所在概率最大的分类即为需要翻译的单词,我们需要遍历句子中的每一个单词。还有一个值得注意的就是,由于我们在句子开头设置的,其不参与运算。

import random#生成本次强制教学的概率
class Seq2Seq(nn.Module):#是一种不限输入输出长度的RNN结构, 它由编码器和解码器两部分组成, 两者的内部结构都是某类RNN, 它也被称为seq2seq架构.def __init__(self,encoder,decoder):super(Seq2Seq,self).__init__()self.encoder = encoderself.decoder = decoderdef forward(self,src,trg,teach_rate=0.5):#src [bacth,seq_len]#trg  [bacth,seq_len]#teach_radio 强制教学的阈值batch_size = trg.shape[0] #一次128个词trg_seqlen = trg.shape[1] #句子多少个词组成#保存每次输出的结果outputs_save = torch.zeros(batch_size,trg_seqlen,trg_vocab_size)if(cuda):outputs_save=outputs_save.cuda()#对源端进行编码_,(h_n,c_n)=self.encoder(src) #output不重要 就用 _ 代替了#第一个输入到解码器中为<sos>trg_i=trg[:,0]#trg_i [batch]for i in range(1,trg_seqlen): #一个词一个词给ioutput,(h_n,c_n)=self.decoder(trg_i,h_n,c_n)#output[batch trg_vocab_size]outputs_save[:,i,:] = output  #将output传给save保存#产生一个随机概率(即是否强制教学)probability=random.random()#获取时间步预测的结果top = output.argmax(1) # 返回指定维度最大值的序号#top[batch]#下一时间步的输入trg_i = trg[:,i] if probability>teach_rate else top #看是否使用强制教学return outputs_save#测试
model = Seq2Seq(enModel,Demodel) #就是整个模型了if(cuda):model=model.cuda()outputs = model(example.src,example.trg) #这里返回就是outputs_saveoutputs.shape

结果:

torch.Size([128, 29, 5893])
#训练
from torch.optim import Adam #优化器epochs=10
optim=Adam(model.parameters())
criterion = nn.CrossEntropyLoss(ignore_index = 1)
# 损失函数用:交叉熵损失函数     ignore_index = 1代表 pad不参与损失函数的计算 model
Seq2Seq((encoder): Encoder((embed): Embedding(7853, 256, padding_idx=1)(lstm): LSTM(256, 512, num_layers=4, batch_first=True, dropout=0.5))(decoder): Decoder((emb): Embedding(5893, 256, padding_idx=1)(lstm): LSTM(256, 512, num_layers=4, batch_first=True, dropout=0.5)(classify): Linear(in_features=512, out_features=5893, bias=True))
)
#参数初始化
def init_weights(m):for name, param in m.named_parameters():nn.init.uniform_(param.data, -0.08, 0.08) #初始化为均匀分布model.apply(init_weights)
Seq2Seq((encoder): Encoder((embed): Embedding(7853, 256, padding_idx=1)(lstm): LSTM(256, 512, num_layers=4, batch_first=True, dropout=0.5))(decoder): Decoder((emb): Embedding(5893, 256, padding_idx=1)(lstm): LSTM(256, 512, num_layers=4, batch_first=True, dropout=0.5)(classify): Linear(in_features=512, out_features=5893, bias=True))
)

分别建立训练和测试函数(写开),其中model.train()和model.eval()主要的作用在于在训练的时候我们dropout会随机丢弃神经元,而在测试阶段的时候,不在进行丢弃神经元。

def train(model,train_iter,optim,criterion):model.train()#即dropout产生作用epoch_loss = 0for i,example in enumerate(train_iter):# enumerate用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标src = example.src.permute(1,0)trg = example.trg.permute(1,0)#src[batch seqlen]#trg[batch seqlen]optim.zero_grad()  #先将梯度值归零output = model(src,trg) #output[batch trg_seqlen trq_vocab_size]#<sos>不参与运算,pad也不参与运算(criterion已经设置了ignore)output = output[:,1:,:].reshape(-1,trg_vocab_size)trg = trg[:,1:].reshape(-1)#output[batch*(trg_len-1),trg_vocab_size]#trg[batch*(trg_len-1)]loss = criterion(output,trg) # 求解lossloss.backward() # 反向传播求解梯度optim.step() #更新权重参数epoch_loss+=loss.item() return epoch_loss/len(train_iter)def evaluate(model,test_iter,criterion):model.eval()#即dropout产生作用epoch_loss = 0with torch.no_grad():#是 torch 中一个上下文管理器,在这个上下文中#所有操作都不会被追踪以用于求导。这样可以节省内存和加速计算。for i,example in enumerate(test_iter):src = example.src.permute(1,0)trg = example.trg.permute(1,0)#src[batch seqlen]#trg[batch seqlen]#即无法在进行强制教学output = model(src,trg,0) #output[batch trg_seqlen trq_vocab_size]#<sos>不参与运算,pad也不参与运算(criterion已经设置了ignore)output=output[:,1:].reshape(-1,trg_vocab_size)trg=trg[:,1:].reshape(-1)#output[batch*(trg_len-1),trg_vocab_size]#trg[batch*(trg_len-1)]loss=criterion(output,trg)epoch_loss+=loss.item()return epoch_loss/len(test_iter)import time,math
#统计每个迭代器的一个训练周期:
def epoch_time(start_time, end_time):elapsed_time = end_time - start_time #间隔时间elapsed_mins = int(elapsed_time / 60)elapsed_secs = int(elapsed_time - (elapsed_mins * 60))return elapsed_mins, elapsed_secs#训练,我们的损失函数简单表示为:困惑度
for epoch in range(epochs):start_time = time.time()#开始时间train_loss = train(model,train_iterator,optim,criterion)valid_loss = evaluate(model,valid_iterator,criterion)end_time = time.time()#结束时间epoch_mins, epoch_secs = epoch_time(start_time, end_time)print(f'Epoch: {epoch+1:02} | Time: {epoch_mins}m {epoch_secs}s')print(f'\tTrain Loss: {train_loss:.3f} | Train PPL: {math.exp(train_loss):7.3f}')print(f'\t Val. Loss: {valid_loss:.3f} |  Val. PPL: {math.exp(valid_loss):7.3f}')
Epoch: 01 | Time: 0m 47sTrain Loss: 5.152 | Train PPL: 172.720Val. Loss: 4.859 |  Val. PPL: 128.945
Epoch: 02 | Time: 0m 47sTrain Loss: 4.788 | Train PPL: 120.025Val. Loss: 4.153 |  Val. PPL:  63.628
Epoch: 03 | Time: 0m 47sTrain Loss: 4.516 | Train PPL:  91.456Val. Loss: 3.927 |  Val. PPL:  50.748
Epoch: 04 | Time: 0m 47sTrain Loss: 4.342 | Train PPL:  76.858Val. Loss: 3.833 |  Val. PPL:  46.187
Epoch: 05 | Time: 0m 33sTrain Loss: 4.153 | Train PPL:  63.632Val. Loss: 3.671 |  Val. PPL:  39.311
Epoch: 06 | Time: 0m 29sTrain Loss: 3.996 | Train PPL:  54.388Val. Loss: 3.494 |  Val. PPL:  32.923
Epoch: 07 | Time: 0m 29sTrain Loss: 3.892 | Train PPL:  49.000Val. Loss: 3.389 |  Val. PPL:  29.635
Epoch: 08 | Time: 0m 28sTrain Loss: 3.791 | Train PPL:  44.290Val. Loss: 3.292 |  Val. PPL:  26.886
Epoch: 09 | Time: 0m 28sTrain Loss: 3.689 | Train PPL:  40.014Val. Loss: 3.216 |  Val. PPL:  24.931
Epoch: 10 | Time: 0m 29sTrain Loss: 3.607 | Train PPL:  36.855Val. Loss: 3.157 |  Val. PPL:  23.490
test_loss = evaluate(model, test_iterator, criterion)
print(f'| Test Loss: {test_loss:.3f} | Test PPL: {math.exp(test_loss):7.3f} |')
| Test Loss: 3.178 | Test PPL:  24.008 |

PPL是什么: 语言模型评价指标Perplexity_ppl指标_Joy_Shen的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/64091.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手把手教你生成正式签名的APK文件

一&#xff0c;使用Android Studio生成 1. 2. 3.如果先前没有则先点Create new 4. 5. 6. 7.点击Finish 8. 二.使用Gradle生成&#xff1a; 1.在安卓闭包中加上 上图紫色字体跟第一种生成方式填的内容一样&#xff0c;这里我把它隐藏起来了 注&#xff1a;一定要放在buildTy…

Android购物软件制作(毕业设计)

本篇博客为了展示自己的实战结果&#xff0c;完成了对淘宝功能的实现&#xff0c;主要用于毕业设计的完成。 首先贴图以表效果&#xff0c;虽然拉跨&#xff0c;但是毕业够用&#xff01; 首先&#xff1a;要开发一款淘宝类的APP&#xff0c;其实分为两种&#xff0c;一种是淘…

[干货]手把手教你写一个安卓app

摘要&#xff1a;最近有很多小伙伴在后台留言&#xff1a;Android Studio。我想大家是想写一个手机app&#xff0c;前面已经分享了在QT上如何写一个安卓蓝牙app&#xff0c;虽然qt可以做app&#xff0c;但是比起Android Studio还是差很多。这里介绍一种快速入门的方法来制作一款…

Android手机通讯录制作

Android手机通讯录制作 要求样图展示代码1.创建数据库2.主界面MainActivityCustomAdapter.javaactivity_main.xml 3.添加联系人AddContacts.java(添加界面)addactivity.xml 要求 设计一个基于Android的手机通讯录&#xff0c;此通讯录包括添加、搜索、修改、删除联系人的功能。…

安卓APP源码和设计报告——个人通讯录

摘 要 随着移动设备制造技术和移动通信网络的迅猛发展,全球手机用户日益增加,手机成为了很多人日常生活中必不可少的一部分,手机业在日益发展的同时,人们对手机的功能需求和体验需求也越来越高,因此各种智能手机相继而出&#xff0c;当前市场上最流行的智能手机的操作系统非An…

【视觉基础篇】12 # 如何使用滤镜函数实现美颜效果?

说明 【跟月影学可视化】学习笔记。 如何理解像素化&#xff1f; 像素化 所谓像素化&#xff0c;就是把一个图像看成是由一组像素点组合而成的。每个像素点负责描述图像上的一个点&#xff0c;并且带有这个点的基本绘图信息。 像素点是怎么存储的&#xff1f; Canvas2D 以…

C++ / Opencv 简单实现美颜效果(瘦脸、大眼、磨皮等)

最近项目需要用到美颜的一些效果&#xff0c;因此开始接触opencv 计算机视觉库,在腾讯课堂上找到一个简单且免费的入门视频《Opencv4 快速入门视频30讲》&#xff0c;看完视频后&#xff0c;初步才对opencv 有一个比较清晰的概念和基本用法。 接下来就是开始对美颜的一些初步接…

Ps人像磨皮皮肤美白插件哪个好_安装教程

今天这个PS插件挺好用的&#xff0c;我们可以用它快速给人像照片磨皮、皮肤美白、上妆等功能&#xff0c;还是非常方便我们后期修图的&#xff0c;有需要这个插件的可以至陌鱼社区瞧一下。插件支持:Adobe PhotoshopCC2015 - CC2018,这里我们用Adobe PhotoshopCC2018做为演示&am…

对皮肤美白算法的一些研究

本篇博文来自博主Imageshop&#xff0c;打赏或想要查阅更多内容可以移步至Imageshop。 转载自&#xff1a;https://www.cnblogs.com/Imageshop/p/3843635.html 侵删 皮肤美白是现在任何一款流行的美颜软件必备的功能之一&#xff0c;不过你如果在互联网上搜索关于美白算法&a…

Portraiture4.0最新PS专属修图磨皮美白插件

作为PS的插件&#xff0c;被众多照片后期高手使用&#xff0c;评价颇高。主要原因在于它操作简便、磨皮效果好、软件很小&#xff0c;特别是它可以自动感应皮肤区域磨皮&#xff0c;只对皮肤作用更令人称奇的是&#xff1a;Portraiture 磨皮能保留下细小的毛孔和皮肤质感&#…

photoshop ps 美白 去污 磨皮 方法

目录 1.美白 2.去污 3.磨皮 1.美白 使用PS打开照片&#xff0c;然后复制一个图层。 复制的快捷方式就是 CTRLJ 复制的图层&#xff0c;把混合模式选择在“滤色”&#xff0c;然后调整旁边的透明度。 这个过程其实是把照片调亮。 完成之后&#xff0c;合并图层。合并图层的…

图像滤镜艺术---人脸编辑(五官微调+瘦脸美型)

写本文的目的&#xff0c;实际上是对目前人脸美型这一块技术做个总结&#xff0c;跟大家 分享一下&#xff01; 目前提到美颜算法&#xff0c;大家都会想到磨皮美白 /大眼瘦脸&#xff0c;实际上做好 美颜这件事情&#xff0c;关乎的不仅仅是这些&#xff0c;还有五官的协调比…

ps美白磨皮处理第三方插件portraiture

ps的功能这么强大&#xff0c;其美白磨皮方法当然不止一种。本文就给大家细数一下ps美白磨皮常用的几种方法。在各种方法中&#xff0c;插件法的操作更为简单&#xff0c;效果也更好&#xff0c;因此我们还会介绍ps磨皮美白插件哪个好。事不宜迟&#xff0c;一起来看看吧。 一…

初中英语知识水平测试软件,初中英语学科知识与能力模拟测试一

一、单项选择题(本大题共30小题,每小题2分,共60分) 在每小题列出的四个备选项中选择一个最佳答案,错选、多选或未选均无分。 *1. Which of the following doesnt contain liaison&#xff1f; A. Put it on, please B. Not at all C. Please pick it up D. Great minds…

轻松完成公司数据分析、业务数据探查的秘诀

2022年即将结束&#xff0c;您企业经营目标达成情况如何&#xff1f;是否可以快速对企业进行数据体检分析&#xff1f;天通眼带您快速了解企业各个维度的经营状况。 PART 01 年度计划检视 2022年还剩余1个月&#xff0c;您企业年度目标达成情况如何&#xff1f;每个月、每个季度…

数据分析真的很火吗?真的有很多企业需要这样的岗位吗?求大佬指点。

“我是去年毕业的&#xff0c;因为疫情影响&#xff0c;整个就业环境都很不好&#xff0c;很多企业都裁员了。加上疫情三年基本都是玩过去&#xff0c;也没啥一技之长&#xff0c;就业就更难了。听说现在做数据分析的人很多&#xff0c;我身边的朋友都在转行做数据分析。 其实…

数据分析师应该了解的数据湖

数据湖 数据湖是一个集中式存储库&#xff0c;允许您以任意规模存储所有结构化和非结构化数据。您可以按原样存储数据&#xff08;无需先对数据进行结构化处理&#xff09;&#xff0c;并运行不同类型的分析 – 从控制面板和可视化到大数据处理、实时分析和机器学习&#xff0c…

数据分析师获取数据的方式有哪些?

1、外部购买数据 有很多公司或者平台是专门做数据收集和分析的&#xff0c;企业会直接从那里购买数据或者相关服务给数据分析师&#xff0c;这是一种常见的获取数据的方式之一。 2、网络爬取数据 除了购买数据以外&#xff0c;数据分析师还可以通过网络爬虫从网络上爬取数据…

计算机网络b站里谁讲得好,除了罗翔,B站还有多少神仙老师?

本文由【哔哩哔哩】授权转载, 【作者:小尹 编辑:会厌】 【图片来自网络,若侵则删】 如果苏格拉底和孔子生活在这个时代,他们会不会上B站,并成为一名UP主呢? 提出这个问题的,是B站UP主、中国政法大学教授罗翔老师。罗翔的粉丝超过千万,是B站最受欢迎的老师之一。 此外,…