《动手学深度学习 Pytorch版》 9.2 长短期记忆网络(LSTM)

news2024/11/20 20:35:26

解决隐变量模型长期信息保存和短期输入缺失问题的最早方法之一是长短期存储器(long short-term memory,LSTM)。它与门控循环单元有许多一样的属性。长短期记忆网络的设计比门控循环单元稍微复杂一些,却比门控循环单元早诞生了近 20 年。

9.2.1 门控记忆元

为了记录附加的信息,长短期记忆网络引入了与隐状态具有相同的形状的记忆元(memory cell),或简称为单元(cell)。

为了控制记忆元又需要引入许多门:

  • 输出门(output gate):用来从单元中输出条目,决定是不是使用隐藏状态。

  • 输入门(input gate):用来决定何时将数据读入单元,决定是不是忽略掉输入数据。

  • 遗忘门(forget gate):用来重置单元的内容,将值朝 0 减少。

这种设计的动机与门控循环单元相同, 能够通过专用机制决定什么时候记忆或忽略隐状态中的输入。

9.2.1.1 输入门、遗忘门和输出门

特征:

  • 以当前时间步的输入和前一个时间步的隐状态为数据送入长短期记忆网络的门

  • 由三个具有 sigmoid 激活函数的全连接层计算输入门、遗忘门和输出门的值

  • 值都在的 ( 0 , 1 ) (0,1) (0,1) 范围内

在这里插入图片描述

它们的计算方法如下:

I t = σ ( X t W x i + H t − 1 W h i + b i ) F t = σ ( X t W x f + H t − 1 W h f + b f ) O t = σ ( X t W x o + H t − 1 W h o + b o ) \begin{align} \boldsymbol{I}_t&=\sigma(\boldsymbol{X}_t\boldsymbol{W}_{xi}+\boldsymbol{H}_{t-1}\boldsymbol{W}_{hi}+b_i)\\ \boldsymbol{F}_t&=\sigma(\boldsymbol{X}_t\boldsymbol{W}_{xf}+\boldsymbol{H}_{t-1}\boldsymbol{W}_{hf}+b_f)\\ \boldsymbol{O}_t&=\sigma(\boldsymbol{X}_t\boldsymbol{W}_{xo}+\boldsymbol{H}_{t-1}\boldsymbol{W}_{ho}+b_o) \end{align} ItFtOt=σ(XtWxi+Ht1Whi+bi)=σ(XtWxf+Ht1Whf+bf)=σ(XtWxo+Ht1Who+bo)

参数列表:

  • X t ∈ R n × d \boldsymbol{X}_t\in\R^{n\times d} XtRn×d 表示小批量输入

    • n n n 表示批量大小

    • d d d 表示输入个数

  • H t − 1 ∈ R n × h \boldsymbol{H}_{t-1}\in\R^{n\times h} Ht1Rn×h 表示上一个时间步的隐状态

    • h h h 表示隐藏单元个数
  • I t ∈ R n × h \boldsymbol{I}_t\in\R^{n\times h} ItRn×h 表示输入门

  • F t ∈ R n × h \boldsymbol{F}_t\in\R^{n\times h} FtRn×h 表示遗忘门

  • O t ∈ R n × h \boldsymbol{O}_t\in\R^{n\times h} OtRn×h 表示输出门

  • W x i , W x f , W x o ∈ R d × h \boldsymbol{W}_{xi},\boldsymbol{W}_{xf},\boldsymbol{W}_{xo}\in\R^{d\times h} Wxi,Wxf,WxoRd×h W h i , W h f , W h o ∈ R h × h \boldsymbol{W}_{hi},\boldsymbol{W}_{hf},\boldsymbol{W}_{ho}\in\R^{h\times h} Whi,Whf,WhoRh×h 表示权重参数

  • b i , b f , b o ∈ R 1 × h b_i,b_f,b_o\in\R^{1\times h} bi,bf,boR1×h 表示偏重参数

9.2.1.2 候选记忆单元

候选记忆元(candidate memory cell) C t ~ ∈ R n × h \tilde{\boldsymbol{C}_t}\in\R^{n\times h} Ct~Rn×h 的计算与上面描述的三个门的计算类似,但是使用 tanh 函数作为激活函数,函数的值范围为 ( 0 , 1 ) (0,1) (0,1)

在这里插入图片描述

它的计算方式如下:

C t ~ = t a n h ( X t W x c + H t − 1 W h c + b c ) \tilde{\boldsymbol{C}_t}=tanh(\boldsymbol{X}_t\boldsymbol{W}_{xc}+\boldsymbol{H}_{t-1}\boldsymbol{W}_{hc}+\boldsymbol{b}_c) Ct~=tanh(XtWxc+Ht1Whc+bc)

参数列表:

  • W x c ∈ R d × h \boldsymbol{W}_{xc}\in\R^{d\times h} WxcRd×h W h c ∈ R h × h \boldsymbol{W}_{hc}\in\R^{h\times h} WhcRh×h 表示权重参数

  • b c ∈ R 1 × h \boldsymbol{b}_c\in\R^{1\times h} bcR1×h 表示偏置参数

9.2.1.3 记忆元

  • 输入门 I t I_t It 控制采用多少来自 C t ~ \tilde{\boldsymbol{C}_t} Ct~ 的新数据

  • 遗忘门 F t F_t Ft 控制保留多少过去的记忆元 C t − 1 ∈ R n × h \boldsymbol{C}_{t-1}\in\R^{n\times h} Ct1Rn×h 的内容。

计算方法:

C t = F t ⊙ C t − 1 + I t ⊙ C t ~ \boldsymbol{C}_t=\boldsymbol{F}_t\odot\boldsymbol{C}_{t-1}+\boldsymbol{I}_t\odot\tilde{\boldsymbol{C}_t} Ct=FtCt1+ItCt~

如果遗忘门始终为 1 且输入门始终为 0,则过去的记忆元 C t − 1 \boldsymbol{C}_{t-1} Ct1 将随时间被保存并传递到当前时间步。

引入这种设计是为了:

  • 缓解梯度消失问题

  • 更好地捕获序列中的长距离依赖关系。

    在这里插入图片描述

9.2.1.4 隐状态

计算隐状态 H t ∈ R n × h \boldsymbol{H}_t\in\R^{n\times h} HtRn×h 是输出门发挥作用的地方。实际上它仅仅是记忆元的 tanh 的门控版本。 这就确保了 H t \boldsymbol{H}_t Ht 的值始终在区间 ( − 1 , 1 ) (-1,1) (1,1)内:

H t = O t ⊙ t a n h ( C t ) \boldsymbol{H}_t=\boldsymbol{O}_t\odot tanh(\boldsymbol{C}_t) Ht=Ottanh(Ct)

只要输出门接近 1,我们就能够有效地将所有记忆信息传递给预测部分,而对于输出门接近 0,我们只保留记忆元内的所有信息,而不需要更新隐状态。

在这里插入图片描述

9.2.2 从零开始实现

import torch
from torch import nn
from d2l import torch as d2l
batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)

9.2.2.1 初始化模型参数

def get_lstm_params(vocab_size, num_hiddens, device):
    num_inputs = num_outputs = vocab_size

    def normal(shape):
        return torch.randn(size=shape, device=device)*0.01

    def three():
        return (normal((num_inputs, num_hiddens)),
                normal((num_hiddens, num_hiddens)),
                torch.zeros(num_hiddens, device=device))

    W_xi, W_hi, b_i = three()  # 输入门参数
    W_xf, W_hf, b_f = three()  # 遗忘门参数
    W_xo, W_ho, b_o = three()  # 输出门参数
    W_xc, W_hc, b_c = three()  # 候选记忆元参数
    # 输出层参数
    W_hq = normal((num_hiddens, num_outputs))
    b_q = torch.zeros(num_outputs, device=device)
    # 附加梯度
    params = [W_xi, W_hi, b_i, W_xf, W_hf, b_f, W_xo, W_ho, b_o, W_xc, W_hc,
              b_c, W_hq, b_q]
    for param in params:
        param.requires_grad_(True)
    return params

9.2.2.2 定义模型

def init_lstm_state(batch_size, num_hiddens, device):
    return (torch.zeros((batch_size, num_hiddens), device=device),  # 隐状态需要返回一个额外的单元的值为0形状为(批量大小,隐藏单元数)记忆元
            torch.zeros((batch_size, num_hiddens), device=device))
def lstm(inputs, state, params):
    [W_xi, W_hi, b_i, W_xf, W_hf, b_f, W_xo, W_ho, b_o, W_xc, W_hc, b_c,
     W_hq, b_q] = params
    (H, C) = state
    outputs = []
    for X in inputs:
        I = torch.sigmoid((X @ W_xi) + (H @ W_hi) + b_i)  # 输入门运算
        F = torch.sigmoid((X @ W_xf) + (H @ W_hf) + b_f)  # 遗忘门运算
        O = torch.sigmoid((X @ W_xo) + (H @ W_ho) + b_o)  # 输出门运算
        C_tilda = torch.tanh((X @ W_xc) + (H @ W_hc) + b_c)  # 候选记忆元运算
        C = F * C + I * C_tilda  # 记忆元计算
        H = O * torch.tanh(C)  # 隐状态计算
        Y = (H @ W_hq) + b_q  # 输出计算
        outputs.append(Y)
    return torch.cat(outputs, dim=0), (H, C)

9.2.2.3 训练与预测

vocab_size, num_hiddens, device = len(vocab), 256, d2l.try_gpu()
num_epochs, lr = 500, 1
model = d2l.RNNModelScratch(len(vocab), num_hiddens, device, get_lstm_params,
                            init_lstm_state, lstm)
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)
perplexity 1.1, 28093.3 tokens/sec on cuda:0
time traveller well pnatter ats sho in the geet on the battle of
traveller oft chat in all dore think of mowh of stace assio

在这里插入图片描述

9.2.3 简洁实现

num_inputs = vocab_size
lstm_layer = nn.LSTM(num_inputs, num_hiddens)
model = d2l.RNNModel(lstm_layer, len(vocab))
model = model.to(device)
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)
perplexity 1.0, 171500.8 tokens/sec on cuda:0
time travelleryou can show black is white by argument said filby
travelleryou can show black is white by argument said filby

在这里插入图片描述

练习

(1)调整和分析超参数对运行时间、困惑度和输出顺序的影响。

跟上一节类似,五个参数轮着换。

def test(Hyperparameters):  # [batch_size, num_steps, num_hiddens, lr, num_epochs]
    train_iter_now, vocab_now = d2l.load_data_time_machine(Hyperparameters[0], Hyperparameters[1])
    
    lstm_layer_now = nn.LSTM(len(vocab_now), Hyperparameters[2])
    model_now = d2l.RNNModel(lstm_layer_now, len(vocab_now))
    model_now = model_now.to(d2l.try_gpu())
    d2l.train_ch8(model_now, train_iter_now, vocab_now, Hyperparameters[3], Hyperparameters[4], d2l.try_gpu())

Hyperparameters_lists = [
    [64, 35, 256, 1, 500],  # 加批量大小
    [32, 64, 256, 1, 500],  # 加时间步
    [32, 35, 512, 1, 500],  # 加隐藏单元数
    [32, 35, 256, 0.5, 500],  # 减半学习率
    [32, 35, 256, 1, 200]  # 减轮数
]

for Hyperparameters in Hyperparameters_lists:
    test(Hyperparameters)
perplexity 4.3, 164389.7 tokens/sec on cuda:0
time traveller the the that the grome that he a thee tho ghith o
traveller the that that that this that the go that have the

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


(2)如何更改模型以生成适当的单词,而不是字符序列?

浅浅的改了一下预测函数和训练函数。

def predict_ch8_word(prefix, num_preds, net, vocab, device):  # 词预测
    """在prefix后面生成新字符"""
    state = net.begin_state(batch_size=1, device=device)
    outputs = [vocab[prefix[0]]]  # 调用 vocab 类的 __getitem__ 方法
    get_input = lambda: torch.tensor([outputs[-1]], device=device).reshape((1, 1))  # 把预测结果(结果的最后一个)作为下一个的输入
    for y in prefix[1:]:  # 预热期 把前缀先载进模型
        _, state = net(get_input(), state)
        outputs.append(vocab[y])
    for _ in range(num_preds):  # 预测 num_preds 步
        y, state = net(get_input(), state)
        outputs.append(int(y.argmax(dim=1).reshape(1)))  # 优雅
    return ''.join([vocab.idx_to_token[i] + ' ' for i in outputs])  # 加个空格分隔各词

def train_ch8_word(net, train_iter, vocab, lr, num_epochs, device,  # 词训练
              use_random_iter=False):
    loss = nn.CrossEntropyLoss()
    animator = d2l.Animator(xlabel='epoch', ylabel='perplexity',
                            legend=['train'], xlim=[10, num_epochs])
    # 初始化
    if isinstance(net, nn.Module):
        updater = torch.optim.SGD(net.parameters(), lr)
    else:
        updater = lambda batch_size: d2l.sgd(net.params, lr, batch_size)
    predict = lambda prefix: predict_ch8_word(prefix, 50, net, vocab, device)
    # 训练和预测
    for epoch in range(num_epochs):
        ppl, speed = d2l.train_epoch_ch8(
            net, train_iter, loss, updater, device, use_random_iter)
        if (epoch + 1) % 10 == 0:
            print(predict(['time', 'traveller']))  # 使用 word 而非 char
            animator.add(epoch + 1, [ppl])
    print(f'困惑度 {ppl:.1f}, {speed:.1f} 词元/秒 {str(device)}')
    print(predict(['time', 'traveller']))
    print(predict(['traveller']))

class SeqDataLoader_word:  # 词加载器
    def __init__(self, batch_size, num_steps, use_random_iter, max_tokens):
        if use_random_iter:
            self.data_iter_fn = d2l.seq_data_iter_random
        else:
            self.data_iter_fn = d2l.seq_data_iter_sequential
        lines = d2l.read_time_machine()
        tokens = d2l.tokenize(lines, token='word')  # 使用 word 而非 char
        self.vocab_word = d2l.Vocab(tokens)  # 构建 word 词表
        self.corpus_word = [self.vocab_word[token] for line in tokens for token in line]
        if max_tokens > 0:
            self.corpus_word = self.corpus_word[:max_tokens]
        self.batch_size, self.num_steps = batch_size, num_steps

    def __iter__(self):
        return self.data_iter_fn(self.corpus_word, self.batch_size, self.num_steps)

train_iter_word = SeqDataLoader_word(
        64, 35, False, 10000)
vocab_word = train_iter_word.vocab_word

lstm_layer_word = nn.LSTM(len(vocab_word), 256)
model_word = d2l.RNNModel(lstm_layer_word, len(vocab_word))
model_word = model_word.to(d2l.try_gpu())
train_ch8_word(model_word, train_iter_word, vocab_word, 1.5, 1000, d2l.try_gpu())
困惑度 1.7, 40165.1 词元/秒 cuda:0
time traveller s his hand at last to me that with his own to the psychologist with his grew which i had said filby time travelling yes said the time traveller with his mouth full nodding his head i d give a shilling a line for a verbatim note said the editor 
traveller and i was so the sun in my marble smote to the world for for the long pressed he was the little of the sun and presently for a certain heap of cushions and robes i saw on the sun in my confident anticipations it seemed a large figure of 

在这里插入图片描述


(3)在给定隐藏层维度的情况下,比较门控循环单元、长短期记忆网络和常规循环神经网络的计算成本。要特别注意训练和推断成本。

咋好像每个都差不多。

batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)

num_inputs = len(vocab)
device = d2l.try_gpu()
num_hiddens = 256
num_epochs, lr = 500, 1
rnn_layer = nn.RNN(len(vocab), num_hiddens)
model_RNN = d2l.RNNModel(rnn_layer, vocab_size=len(vocab))
model_RNN = model_RNN.to(device)
d2l.train_ch8(model_RNN, train_iter, vocab, lr, num_epochs, device)  # 34.3s
perplexity 1.3, 218374.6 tokens/sec on cuda:0
time travelleryou can show black is whith basimat very hu and le
travellerit so drawly us our dimsas absulladt nt havi gerea

在这里插入图片描述

gru_layer = nn.GRU(num_inputs, num_hiddens)
model_GRU = d2l.RNNModel(gru_layer, len(vocab))
model_GRU = model_GRU.to(device)
d2l.train_ch8(model_GRU, train_iter, vocab, lr, num_epochs, device)  # 35.1s
perplexity 1.0, 199203.7 tokens/sec on cuda:0
time travelleryou can show black is white by argument said filby
travelleryou can show black is white by argument said filby

在这里插入图片描述

lstm_layer = nn.LSTM(num_inputs, num_hiddens)
model_LSTM = d2l.RNNModel(lstm_layer, len(vocab))
model_LSTM = model_LSTM.to(device)
d2l.train_ch8(model_LSTM, train_iter, vocab, lr, num_epochs, device)  # 35.4s
perplexity 1.0, 199069.6 tokens/sec on cuda:0
time travelleryou can show black is white by argument said filby
travelleryou can show black is white by argument said filby

在这里插入图片描述


(4)既然候选记忆元通过使用 tanh 函数来确保值范围在 ( − 1 , 1 ) (-1,1) (1,1) 之间,那么为什么隐状态需要再次使用 tanh 函数来确保输出值范围在 (-1,1) 之间呢?

候选记忆元和隐状态之间还有个记忆元呐,这个: C t = F t ⊙ C t − 1 + I t ⊙ C t ~ \boldsymbol{C}_t=\boldsymbol{F}_t\odot\boldsymbol{C}_{t-1}+\boldsymbol{I}_t\odot\tilde{\boldsymbol{C}_t} Ct=FtCt1+ItCt~

很有可能出范围的。


(5)实现一个能够基于时间序列进行预测而不是基于字符序列进行预测的长短期记忆网络模型。

不会,略。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

最新XFF注入攻击和代码分析技术

点击星标,即时接收最新推文 本文选自《web安全攻防渗透测试实战指南(第2版)》 点击图片五折购书 XFF注入攻击 XFF注入攻击的测试地址在本书第2章。 X-Forwarded-For简称XFF头,它代表客户端真实的IP地址,通过修改X-Forw…

Day 07 python学习笔记

函数 函数的传参 关键字参数 函数调用时,指定参数的名称,即为关键字参数 允许传入0个或者多个含参数名的参数关键字参数必须放在普通参数的后面 例: def abc(x,a,b):print(x)print(a)print(b)abc(100,b4,a2) #其中a,b作为关键字参数可以随意…

软件性能测试-初步分析性能瓶颈

完成工具使用和脚本编写后,剩下的流程是执行和结果分析,以及复测。现在来学学结果分析,主要是要学会判断压力的来源,当响应时间远远超出我们的期望,测试人员如何判断是由于什么导致的过载响应。 一、性能瓶颈出现的表…

Spring Security登录表单配置(3)

1、登录表单配置 1.1、快速入门 理解了入门案例之后&#xff0c;接下来我们再来看一下登录表单的详细配置&#xff0c;首先创建一个新的Spring Boot项目&#xff0c;引入Web和Spring Security依赖&#xff0c;代码如下&#xff1a; <dependency><groupId>org.sp…

竹云荣膺2023粤港澳大湾区高质量发展标杆企业

10月12日&#xff0c;由深圳市前海深港现代服务业合作区管理局指导&#xff0c;广东省粤港澳大湾区产业协同发展联合会&#xff08;简称&#xff1a;湾区产联&#xff09;、香港大湾区工商业联合会主办的“深港合作前海向前”2023粤港澳大湾区高质量发展企业发布会、香港大湾区…

[计算机提升] 环境变量

1.5 环境变量 在Windows系统中&#xff0c;环境变量是一组参数或值&#xff0c;用于配置和控制操作系统的行为。它们用来确定系统的默认设置、执行文件路径以及其他系统行为。环境变量可以被所有的应用程序和命令行工具访问和使用&#xff0c;而不需要每次手动指定路径或设置参…

SELECT COUNT(*) 会造成全表扫描吗?

前言 SELECT COUNT(*)会不会导致全表扫描引起慢查询呢&#xff1f; SELECT COUNT(*) FROM SomeTable 网上有一种说法&#xff0c;针对无 where_clause 的 COUNT(*)&#xff0c;MySQL 是有优化的&#xff0c;优化器会选择成本最小的辅助索引查询计数&#xff0c;其实反而性能…

笔记本触摸板没反应?实用技巧助你成功修复!

笔记本电脑是我们日常工作和学习的得力工具之一&#xff0c;而触摸板作为一个重要的输入设备&#xff0c;对于操作的流畅性至关重要。然而&#xff0c;有时候我们可能会遇到笔记本触摸板没反应的问题&#xff0c;这可能会导致困扰和不便。本文将介绍解决笔记本触摸板无响应问题…

SPSS|偏度和峰度|正态性分布检验|实战小练-SPSS学习(1)

目录 学习目的软件版本基础数据实战数据准备数据初探输出结果分析两个重要统计量&#xff1a;偏度和峰度正态性检验结果其他图件输出 学习目的 检验数据集是否服从正态分布。 软件版本 IBM SPSS Statistics 26。 基础数据 一组数据&#xff0c;如&#xff1a;73 76 78 77 …

ES6 Promise

1.Promise 是异步编程的一种解决方案 const promise new Promise(function(resolve, reject) {if (/* 异步操作成功 */){resolve(value);} else {reject(error);} }) 2.Promise的三种状态 待定&#xff08;pending&#xff09;: 初始状态&#xff0c;既没有被兑现&#xff…

情绪即需求

情绪即需求 心理学认为&#xff0c;每个情绪背后都藏着一个未被满足的心里需求. 模型介绍 每一个情绪背后&#xff0c;都有一个未被满足的心理需求。情绪没有好坏之分&#xff0c;存在即合理。情绪是人类不断进化的产物&#xff0c;每一种情绪都是在保护我们&#xff0c;都有其…

一起学数据结构(9)——二叉树的链式存储及相关功能实现

目录 1. 二叉树的链式存储&#xff1a; 2. 二叉树的前序遍历&#xff1a; 3. 二叉树的中序遍历&#xff1a; 4. 二叉树的后序遍历&#xff1a; 5. 统计二叉树的结点总数 6.统计二叉树的叶子结点数&#xff1a; 7. 统计二叉树第层的结点数量&#xff1a; 8. 二叉树的销毁…

如何修改模型颜色

1、模型材质颜色介绍 在3D模型中&#xff0c;材质&#xff08;Material&#xff09;是指表面质感的特性&#xff0c;包括颜色、光泽、透明度等属性。其中&#xff0c;颜色是最基本的属性之一&#xff0c;它决定了物体表面的外观和感觉。 在现代计算机图形学中&#xff0c;通常…

使用 Typhoeus 和 Ruby 编写的爬虫程序

以下是一个使用 Typhoeus 和 Ruby 编写的爬虫程序&#xff0c;用于爬取 &#xff0c;同时使用了 jshk.com.cn/get_proxy 这段代码获取代理&#xff1a; #!/usr/bin/env rubyrequire typhoeus require jsondef get_proxyurl "https://www.duoip.cn/get_proxy"respon…

CTF是黑客大赛?新手如何入门CTF?

CTF是啥 CTF 是 Capture The Flag 的简称&#xff0c;中文咱们叫夺旗赛&#xff0c;其本意是西方的一种传统运动。在比赛上两军会互相争夺旗帜&#xff0c;当有一方的旗帜已被敌军夺取&#xff0c;就代表了那一方的战败。在信息安全领域的 CTF 是说&#xff0c;通过各种攻击手…

随手记录第十话 -- 升级SpringBoot3.0 + JDK17的踩坑记录

随着有些jar包的升级&#xff0c;JDK1.8已经不是最稳定的版本了。 前段时间接触到Web3相关&#xff0c;jar包的编译最低要JDK13了&#xff0c;碰巧另一个使用Kotlin写的jar包依赖需要17了&#xff0c;那就直接上17吧&#xff0c;同时Springboot也上到3.0。 1. 框架说明 Spri…

哪个牌子的护眼灯防蓝光效果好?2023防蓝光护眼灯推荐

可以肯定的是&#xff0c;护眼灯一般可以达到护眼的效果。 看书和写字时&#xff0c;光线应适度&#xff0c;不宜过强或过暗&#xff0c;护眼灯光线较柔和&#xff0c;通常并不刺眼&#xff0c;眼球容易适应&#xff0c;可以防止光线过强或过暗导致的用眼疲劳。如果平时生活中需…

Python国庆祝福

系列文章 序号文章目录直达链接1浪漫520表白代码https://want595.blog.csdn.net/article/details/1306668812满屏表白代码https://want595.blog.csdn.net/article/details/1297945183跳动的爱心https://want595.blog.csdn.net/article/details/1295031234漂浮爱心https://want…

软件开发线上维护方案

编写软件维护方案是确保软件系统长期稳定运行和满足不断变化需求的关键步骤。以下是编写软件维护方案的一般步骤和建议&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 文档概述&#xff1a; 开始文档…

Java (day 3)方法、数组、面向对象和异常

Java方法、数组、面向对象和异常 1.方法1.1 什么是方法&#xff1f;1.2 方法的定义1.3 方法的调用1.4 值传递和引用传递1.5 方法的重载1.6 命令行传参1.7 可变参数1.8 递归 2.数组2.1 数组概述2.2 数组声明创建2.3 三种初始化及内存分析和总结&#xff08;1&#xff09;java内存…