深度学习笔记之优化算法(八)Adam算法的简单认识

news2024/11/19 6:19:28

深度学习笔记之优化算法——Adam算法的简单认识

  • 引言
    • 回顾:基于Nesterov动量的RMSProp算法
    • Adam算法的简单认识
    • 一阶矩、二阶矩修正偏差的功能
    • Adam的算法过程描述
    • Adam示例代码

引言

上一节介绍了基于 Nesterov \text{Nesterov} Nesterov动量与 RMSProp \text{RMSProp} RMSProp的融合算法,本节将介绍《深度学习(花书)》 P187 8.5 \text{P187 8.5} P187 8.5自适应学习率算法中的最后一个算法 Adam \text{Adam} Adam算法

回顾:基于Nesterov动量的RMSProp算法

基于 Nesterov \text{Nesterov} Nesterov动量的 RMSProp \text{RMSProp} RMSProp算法,其特点在于:对梯度大小(学习率)梯度方向同时优化。其对应的迭代公式表示如下:
关于动量、学习率加权平均方法的差异性描述,详见上一节链接。
{ θ ^ t = θ t − 1 + γ ⋅ m t − 1 G t = ∇ θ ; t − 1 J ( θ ^ t ) R t = β ⋅ R t − 1 + ( 1 − β ) ⋅ G t ⊙ G t m t = γ ⋅ m t − 1 − η R t ⊙ G t θ t = θ t − 1 + m t \begin{cases} \hat \theta_{t} = \theta_{t-1} + \gamma \cdot m_{t-1} \\ \mathcal G_t = \nabla_{\theta;t-1} \mathcal J(\hat \theta_t) \\ \mathcal R_t = \beta \cdot \mathcal R_{t-1} + (1 - \beta) \cdot \mathcal G_t \odot \mathcal G_t \\ \begin{aligned} m_t = \gamma \cdot m_{t-1} - \frac{\eta}{\sqrt{\mathcal R_t}} \odot \mathcal G_t \end{aligned} \\ \theta_t = \theta_{t-1} + m_t \end{cases} θ^t=θt1+γmt1Gt=θ;t1J(θ^t)Rt=βRt1+(1β)GtGtmt=γmt1Rt ηGtθt=θt1+mt

Adam算法的简单认识

Adam \text{Adam} Adam算法与上述算法的思想相同,即迭代过程中,对梯度大小、方向均进行优化。不同点在于:

  • 无论是梯度大小(学习率)还是梯度方向,均使用指数加权移动平均法进行更新:
    { G = ∇ θ ; t − 1 J ( θ t − 1 ) m t = ρ 1 ⋅ m t − 1 + ( 1 − ρ 1 ) ⋅ G R t = ρ 2 ⋅ R t − 1 + ( 1 − ρ 2 ) ⋅ G ⊙ G \begin{cases} \mathcal G = \nabla_{\theta;t-1} \mathcal J(\theta_{t-1}) \\ m_t = \rho_1 \cdot m_{t-1} + (1 - \rho_1) \cdot \mathcal G \\ \mathcal R_t = \rho_2 \cdot \mathcal R_{t-1} + (1 - \rho_2) \cdot \mathcal G \odot \mathcal G \end{cases} G=θ;t1J(θt1)mt=ρ1mt1+(1ρ1)GRt=ρ2Rt1+(1ρ2)GG
  • 使用指数加权移动平均法更新的基础上,分别对更新结果 m t , R t m_t,\mathcal R_t mt,Rt进行偏差修正
    • 关于第一个公式,我们对累积梯度(向量) m t m_t mt进行修正,其本质是对梯度向量 G \mathcal G G进行修正,因而称其为一阶矩偏差修正
    • 同理,第二个公式,我们对累积梯度内积(标量) R t \mathcal R_t Rt进行修正,其本质对梯度内积 G ⊙ G \mathcal G \odot \mathcal G GG进行修正,因而称其为二阶矩偏差修正
    • 其中 t t t表示迭代步骤的编号
      { m ^ t = 1 1 − ( ρ 1 ) t ⋅ m t R ^ t = 1 1 − ( ρ 2 ) t ⋅ R t \begin{cases} \begin{aligned} \hat {m}_t & = \frac{1}{1 - (\rho_1)^t} \cdot m_t \\ \hat {\mathcal R}_t & = \frac{1}{1 - (\rho_2)^t} \cdot \mathcal R_t \end{aligned} \end{cases} m^tR^t=1(ρ1)t1mt=1(ρ2)t1Rt
  • 最终对权重进行更新:
    该操作与 AdaGrad,RMSProp \text{AdaGrad,RMSProp} AdaGrad,RMSProp原理相同。
    θ t = θ t − 1 + Δ θ = θ t − 1 − η ϵ + R ^ t ⋅ m ^ t \begin{aligned} \theta_t & = \theta_{t-1} + \Delta \theta \\ & = \theta_{t-1} - \frac{\eta}{\epsilon + \sqrt{\hat {\mathcal R}_t}} \cdot \hat {m}_t \end{aligned} θt=θt1+Δθ=θt1ϵ+R^t ηm^t

下面从个人理解的角度认知:为什么要使用一个关于迭代步骤 t t t非线性函数对一阶矩、二阶矩的偏差进行修正

一阶矩、二阶矩修正偏差的功能

首先,从《深度学习(花书)》中关于 ρ 1 , ρ 2 \rho_1,\rho_2 ρ1,ρ2描述开始:

  • ρ 1 , ρ 2 \rho_1,\rho_2 ρ1,ρ2分别是调整当前梯度/梯度内积与历史累积梯度/梯度内积的比例因子

  • 在书中关于 ρ 1 , ρ 2 \rho_1,\rho_2 ρ1,ρ2初始化步骤中分别为: ρ 1 = 0.9 , ρ 2 = 0.999 \rho_1 = 0.9,\rho_2 = 0.999 ρ1=0.9,ρ2=0.999。可以看出:无论是梯度还是梯度内积,在迭代过程中极其依赖历史信息,而不是当前步骤信息

    与此同时,完全可以作出 ρ 1 , ρ 2 \rho_1,\rho_2 ρ1,ρ2固定条件下,一阶矩系数 1 1 − ( ρ 1 ) t \begin{aligned}\frac{1}{1 - (\rho_1)^t}\end{aligned} 1(ρ1)t1、二阶矩系数 1 1 − ( ρ 2 ) t \begin{aligned}\frac{1}{1 - (\rho_2)^t}\end{aligned} 1(ρ2)t1随迭代步骤 t t t增长的修正变化曲线
    修正变化曲线效果图
    结合上面的权重更新公式可以看出:在迭代初始的几个步骤内,给予 m t ⇒ m ^ t m_t \Rightarrow \hat {m}_t mtm^t较高的增长;但与此同时,同样使用较低 η ϵ + R ^ t \begin{aligned}\frac{\eta}{\epsilon + \sqrt{\hat {\mathcal R}_t}}\end{aligned} ϵ+R^t η约束 m ^ t \hat {m}_t m^t增长的幅度
    虽然从图中可以看出迭代初期 ρ 1 , ρ 2 \rho_1,\rho_2 ρ1,ρ2之间的函数结果相差几十倍,但通过 ⋅ \sqrt{\cdot} 的消减,使得它们的增长与约束处于同一个量级

很明显,这是一场对抗,但这场对抗仅仅持续了迭代初期的若干次步骤中。那么换一种思路:为什么在迭代初期的对抗最激烈 ? ? ? 迭代初期发生了什么 ? ? ? 不要忘记,由于 ρ 1 , ρ 2 \rho_1,\rho_2 ρ1,ρ2取值的原因,导致整个迭代过程都非常依赖历史信息,并且初始点通常是随机初始化的,也就是说:初始位置的梯度信息是不确定、不稳定的

初始的几次迭代步骤,可能会出现大幅度的折叠、震荡,而这种变化剧烈的梯度若累积历史梯度/历史梯度内积中,会导致后续的迭代不稳定。虽然这种不稳定被系数 1 1 − ( ρ 1 ) t \begin{aligned}\frac{1}{1 - (\rho_1)^t}\end{aligned} 1(ρ1)t1小规模放大,但同样被强劲的系数 1 ϵ + R t \begin{aligned}\frac{1}{\epsilon + \sqrt{\mathcal R_t}}\end{aligned} ϵ+Rt 1压制,使其虽然梯度方向震荡的很厉害(梯度方向较大),但这种状态没有办法移动较大的步长(梯度大小较小),从而压制住震荡的产生

该部分更多是对算法的个人理解,不否认,我们可以尝试修改 ρ 1 , ρ 2 \rho_1,\rho_2 ρ1,ρ2的值,但需要知道的是:两者之间的取值存在一种均衡关系

Adam的算法过程描述

基于 Adam \text{Adam} Adam算法步骤表示如下:
初始化操作

  • 学习率 η \eta η;一阶矩、二阶矩衰减速率 ρ 1 , ρ 2 ∈ [ 0 , 1 ) ( 0.9 , 0.999 ) \rho_1,\rho_2 \in [0,1)(0.9,0.999) ρ1,ρ2[0,1)(0.9,0.999)
  • 超参数 ϵ = 1 0 − 8 \epsilon = 10^{-8} ϵ=108;初始权重参数 θ \theta θ;初始化迭代步骤 t = 0 t=0 t=0
  • 初始化历史累积梯度 m = O m = \mathcal O m=O( O \mathcal O O表示零向量);初始化历史累积梯度内积 R = 0 \mathcal R = 0 R=0

算法过程

  • While \text{While} While没有达到停止准则 do \text{do} do
  • 从训练集 D \mathcal D D中采集出包含 k k k个样本的小批量 { ( x ( i ) , y ( i ) ) } i = 1 k \{(x^{(i)},y^{(i)})\}_{i=1}^k {(x(i),y(i))}i=1k
  • 计算当前迭代步骤参数 θ \theta θ梯度信息 G \mathcal G G
    G ⇐ 1 k ∑ i = 1 k ∇ θ L [ f ( x ( i ) ; θ ) , y ( i ) ] \mathcal G \Leftarrow \frac{1}{k} \sum_{i=1}^k \nabla_{\theta} \mathcal L[f(x^{(i)};\theta),y^{(i)}] Gk1i=1kθL[f(x(i);θ),y(i)]
  • 迭代步骤 t ⇐ t + 1 t \Leftarrow t + 1 tt+1
  • 使用指数加权移动平均法历史累积梯度 m m m进行更新
    m ⇐ ρ 1 ⋅ m + ( 1 − ρ 1 ) ⋅ G m \Leftarrow \rho_1 \cdot m + (1 - \rho_1) \cdot \mathcal G mρ1m+(1ρ1)G
  • 使用指数加权移动平均法历史累积梯度内积 R \mathcal R R进行更新
    R ⇐ ρ 2 ⋅ R + ( 1 − ρ 2 ) ⋅ G ⊙ G \mathcal R \Leftarrow \rho_2 \cdot \mathcal R + (1 - \rho_2) \cdot \mathcal G \odot \mathcal G Rρ2R+(1ρ2)GG
  • 历史累积梯度 m m m进行偏差修正
    m ^ ⇐ 1 1 − ( ρ 1 ) t ⋅ m \hat m \Leftarrow \frac{1}{1 - (\rho_1)^t} \cdot m m^1(ρ1)t1m
  • 历史累积梯度内积 R \mathcal R R进行偏差修正
    R ^ ⇐ 1 1 − ( ρ 2 ) t ⋅ R \hat {\mathcal R} \Leftarrow \frac{1}{1 - (\rho_2)^t}\cdot \mathcal R R^1(ρ2)t1R
  • 计算当前迭代步骤权重参数更新量 Δ θ \Delta \theta Δθ
    标量乘向量,即向量中的每一个分量均乘一个 − η ϵ + R ^ \begin{aligned}-\frac{\eta}{\sqrt{\epsilon + \hat {\mathcal R}}}\end{aligned} ϵ+R^ η
    Δ θ = − η ϵ + R ^ ⋅ m ^ \Delta \theta = -\frac{\eta}{\sqrt{\epsilon + \hat {\mathcal R}}} \cdot \hat {m} Δθ=ϵ+R^ ηm^
  • 应用更新:
    θ ⇐ θ + Δ θ \theta \Leftarrow \theta + \Delta\theta θθ+Δθ
  • End While \text{End While} End While

Adam示例代码

依然使用凸函数 f ( x ) = x T Q x ; x = ( x 1 , x 2 ) T ; Q = ( 0.5 0 0 20 ) f(x) = x^T \mathcal Qx;x=(x_1,x_2)^T;\mathcal Q = \begin{pmatrix}0.5 \quad 0 \\ 0 \quad 20\end{pmatrix} f(x)=xTQx;x=(x1,x2)T;Q=(0.50020)作为目标函数,观察其迭代过程。对应代码表示如下:
复制粘贴过来的,哈哈~

import numpy as np
import math
import matplotlib.pyplot as plt
from tqdm import tqdm

def f(x, y):
    return 0.5 * (x ** 2) + 20 * (y ** 2)

def ConTourFunction(x, Contour):
    return math.sqrt(0.05 * (Contour - (0.5 * (x ** 2))))

def Derfx(x):
    return x

def Derfy(y):
    return 40 * y

def DrawBackGround():
    ContourList = [0.2, 1.0, 4.0, 8.0, 16.0, 32.0]
    LimitParameter = 0.0001
    for Contour in ContourList:
        # 设置范围时,需要满足x的定义域描述。
        x = np.linspace(-1 * math.sqrt(2 * Contour) + LimitParameter, math.sqrt(2 * Contour) - LimitParameter, 200)
        y1 = [ConTourFunction(i, Contour) for i in x]
        y2 = [-1 * j for j in y1]
        plt.plot(x, y1, '--', c="tab:blue")
        plt.plot(x, y2, '--', c="tab:blue")

def Adam():
    def DeviationCorrection(Input,RhoParameter,Step):
        if type(Input) == tuple:
            Res = (Input[0] / (1 - (RhoParameter ** Step)),Input[1] / (1 - (RhoParameter ** Step)))
            return Res
        else:
            return Input / (1 - (RhoParameter ** Step))

    Start = (8.0, 1.0)
    LocList = list()
    LocList.append(Start)
    StartMomentum = (0.0, 0.0)
    R = 0.0
    Eta = 0.3
    Step = 0
    Rho1 = 0.9
    Rho2 = 0.999
    Epsilon = 0.00000001
    Delta = 0.1

    while True:
        DerStart = (Derfx(Start[0]),Derfy(Start[1]))
        Step += 1

        UpdateMomentum = ((Rho1 * StartMomentum[0]) + ((1 - Rho1) * DerStart[0]),
                          (Rho1 * StartMomentum[1]) + ((1 - Rho1) * DerStart[1]))
        InnerProduct = (DerStart[0] ** 2) + (DerStart[1] ** 2)
        
        DecayR = R * Rho2
        R = DecayR + ((1.0 - Rho2) * InnerProduct)
        CorrectionMomentum = DeviationCorrection(UpdateMomentum,Rho1,Step)
        CorrectionR = DeviationCorrection(R,Rho2,Step)

        UpdateMessage = (-1 * (Eta * CorrectionMomentum[0]) / (math.sqrt(CorrectionR) + Epsilon),
                         -1 * (Eta * CorrectionMomentum[1]) / (math.sqrt(CorrectionR) + Epsilon))
        Next = (Start[0] + UpdateMessage[0],Start[1] + UpdateMessage[1])
        DerNext = (Derfx(Next[0]),Derfy(Next[1]))

        if math.sqrt((DerNext[0] ** 2) + (DerNext[1] ** 2)) < Delta:
            break
        else:
            LocList.append(Next)
            StartMomentum = UpdateMomentum
            Start = Next
    return LocList

def DrawPicture():
    NesterovRMSPropLocList = Adam()
    plt.figure(figsize=(10,5))
    NesterovRMSPropplotList = list()
    DrawBackGround()
    for (x, y) in tqdm(NesterovRMSPropLocList):
        NesterovRMSPropplotList.append((x, y))
        plt.scatter(x, y, s=30, facecolor="none", edgecolors="tab:red", marker='o')
        if len(NesterovRMSPropplotList) < 2:
            continue
        else:
            plt.plot([NesterovRMSPropplotList[0][0], NesterovRMSPropplotList[1][0]], [NesterovRMSPropplotList[0][1], NesterovRMSPropplotList[1][1]], c="tab:red")
            NesterovRMSPropplotList.pop(0)
    plt.show()

if __name__ == '__main__':
    DrawPicture()

对应图像结果表示如下:
Adam算法示例
关于 ρ 1 , ρ 2 \rho_1,\rho_2 ρ1,ρ2取值情况,为了保证它们之间的均衡关系,在取值过程中需要注意一下。例如: ρ 1 = 0.3 , ρ 2 = 0.9 \rho_1 = 0.3,\rho_2 = 0.9 ρ1=0.3,ρ2=0.9对应的函数图像结果表示如下:
因为这个凸函数示例过于简单,大家可以试一试其他的参数组合方式~
Adam算法示例2
至此,深度学习中的优化方法暂时告一段落。

Reference \text{Reference} Reference
《深度学习(花书)》 P189 8.5.3 Adam \text{P189 8.5.3 Adam} P189 8.5.3 Adam

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

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

相关文章

文字与视频结合效果

效果展示 CSS 知识点 mix-blend-mode 属性的运用 实现整体页面布局 <section class"sec"><video autoplay muted loop><source src"./video.mp4" type"video/mp4" /></video><h2>Run</h2><!-- 用于切…

【Java 进阶篇】JavaScript 与 HTML 的结合方式

JavaScript是一种广泛应用于Web开发中的脚本语言&#xff0c;它与HTML&#xff08;Hypertext Markup Language&#xff09;结合使用&#xff0c;使开发人员能够创建交互式和动态的网页。在这篇博客中&#xff0c;我们将深入探讨JavaScript与HTML的结合方式&#xff0c;包括如何…

Web知识:markupsafe.escape() 函数的作用

1、markupsafe.escape() 函数是 MarkupSafe 库中的一个函数&#xff0c;它的作用是对字符串进行 HTML 转义&#xff0c;以防止在 HTML 文档中引起意外的解析结果或安全漏洞。 2、在 Web 开发中&#xff0c;如果用户提供的数据直接插入到 HTML 页面中&#xff0c;而没有经过转义…

SpringBoot调用存储过程(入参,返参)(亲测有效!!!)

存储过程和函数是有区别的&#xff01;&#xff01;&#xff01; 创建函数&#xff0c;只是演示&#xff0c;以下函数不完整&#xff01;&#xff01;&#xff01;(只是看P_xxx参数) CREATE OR REPLACE PROCEDURE SP_TICKET_CHECKE_ONLINE_TEST (p_transcode IN OUT VA…

Java反射获取抽象类方法属性问题讲解

Java反射获取抽象类方法属性问题讲解 结论一、案例准备二、测试方法&#xff1a;使用反射获取抽象类私有方法和私有属性具体操作&#xff08;获取私有方法&#xff09;具体操作&#xff08;获取私有属性&#xff09; 结论 Java 通过反射可以获得抽象类的任何修饰符&#xff08…

Vue2 Watch的语法

Watch语法 一、监听普通数据类型&#xff08;1&#xff09;把要监听的msg值看作方法名&#xff0c;来进行监听。&#xff08;2&#xff09;把要监听的msg值看作对象&#xff0c;利用hanler方法来进行监听 二、监听对象&#xff1a;&#xff08;1&#xff09;监听对象需要用到深…

LeetCode【300】最长递增子序列

题目&#xff1a; 思路&#xff1a; 通常来说&#xff0c;子序列不要求连续&#xff0c;而子数组或子字符串必须连续&#xff1b;对于子序列问题&#xff0c;第一种动态规划方法是&#xff0c;定义 dp 数组&#xff0c;其中 dp[i] 表示以 i 结尾的子序列的性质。在处理好每个…

1808_ChibiOS基本的架构介绍

全部学习汇总&#xff1a; GreyZhang/g_ChibiOS: I found a new RTOS called ChibiOS and it seems interesting! (github.com) 简单看了一下ChibiOS的架构介绍&#xff0c;感觉这种OS以及组件非常适合快速构建一个应用。这里做一个简单的资料整理。。 1. 不同于其他的OS&#…

TCP/IP(九)TCP的连接管理(六)TIME_WAIT状态探究

一 TIME_WAIT探究 要明确TIME_WAIT状态在tcp四次挥手的阶段 ① 为什么 TIME_WAIT 等待的时间是 2MSL? 背景&#xff1a; 客户端在收到服务端第三次FIN挥手后,就会进入TIME_WAIT 状态,开启时长为2MSL的定时器1、MSL 是 Maximum Segment Lifetime 报文最大生存时间2、2MSL…

4.(vue3.x+vite)style动态绑定的方式

前端技术社区总目录(订阅之前请先查看该博客) 效果浏览 代码如下: <template><div><div :style="{

改造Vue-admin-template登录

这是是将Vue-admin-template改为登录自己的&#xff0c;拿自己的数据&#xff0c;原作者是gitee花裤衩或者github devServer: {proxy: {/dev-api: {target: http://localhost:8035,changeOrigin: true,pathRewrite: {^/dev-api: }}} }, main.js如下 import Vue from vueimpor…

VMware虚拟机安装Linux教程(图文超详细)

1.安装VMware 官方正版VMware下载地址 https://www.vmware.com/ 双击安装 以上就是VMware在安装时的每一步操作&#xff0c;基本上就是点击 "下一步" 一直进行安装。 2.安装Linux VMware虚拟机安装完毕之后&#xff0c;我们就可以打开VMware&#xff0c;并在上面来…

validator库的使用详解

TOC 基本使用 前言 在做API开发时&#xff0c;需要对请求参数的校验&#xff0c;防止用户的恶意请求。例如日期格式&#xff0c;用户年龄&#xff0c;性别等必须是正常的值&#xff0c;不能随意设置。以前会使用大量的if判断参数的值是否符合规范&#xff0c;现在可以使用val…

电脑如何查看是否支持虚拟化及如何开启虚拟化

什么是虚拟化? Intel Virtualization Technology就是以前众所周知的“Vanderpool”技术&#xff08;简称VT&#xff0c;中文译为虚拟化技术&#xff09;&#xff0c;这种技术可以让一个CPU工作起来就像多个CPU并行运行&#xff0c;从而使得在一部电脑内同时运行多个操作系统成…

rabbitmq-----黑马资料

rabbit的三种发送订阅模式 消息从发送&#xff0c;到消费者接收&#xff0c;会经理多个过程&#xff1a; 其中的每一步都可能导致消息丢失&#xff0c;常见的丢失原因包括&#xff1a; 发送时丢失&#xff1a;生产者发送的消息未送达exchange消息到达exchange后未到达queueMQ…

使用Python进行食品配送时间预测

一般的食品配送服务需要显示交付订单所需的准确时间&#xff0c;以保持与客户的透明度。这些公司使用机器学习算法来预测食品配送时间&#xff0c;基于配送合作伙伴过去在相同距离上花费的时间。 食品配送时间预测 为了实时预测食物的交付时间&#xff0c;我们需要计算食物准…

[安洵杯 2019]easy_web - RCE(关键字绕过)+md5强碰撞+逆向思维

[安洵杯 2019]easy_web 1 解题流程1.1 阶段一1.2 阶段二2 思考总结1 解题流程 1.1 阶段一 1、F12发现提示md5 is funny ~;还有img标签中,有伪协议和base64编码 2、url地址是index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=   这就有意思了,这里的img明显是编码后的…

如何给苹果ipa和安卓apk应用APP包体修改手机屏幕上logo图标iocn?

虽然修改应用文件图标是一个简单的事情&#xff0c;但是还是有很多小可爱是不明白的&#xff0c;你要是想要明白的话&#xff0c;那我就让你今天明白明白&#xff0c;我们今天采用的非常规打包方式&#xff0c;常规打包方式科技一下教程铺天盖地&#xff0c;既然小弟我出马&…

阿里云华中1(武汉)本地地域公网带宽价格表

阿里云华中1&#xff08;武汉&#xff09;地域上线&#xff0c;本地地域只有一个可用区A&#xff0c;高可用需要多可用区部署的应用&#xff0c;不建议选择本地地域&#xff0c;可以选择上海或杭州地域&#xff0c;阿里云服务器华中1&#xff08;武汉&#xff09;地域公网带宽价…

windows下开启Telnet功能并访问百度

Telnet 是一个实用的远程连接命令&#xff0c;采用的是 TCP/IP 协议。它为用户提供了在本地计算机上完成远程主机工作的能力&#xff0c;在终端使用者的电脑上使用 Telnet 程序&#xff0c;用它连接到服务器。终端使用者可以在 Telnet 程序中输入命令&#xff0c;这些命令会在服…