神经网络:Zero2Hero 1 - Simple Language Model

news2024/12/22 11:50:04

Zero → \to Hero : 1

 实现了一个字符级中文语言模型,数据采用的是开源中文姓名数据集中的一部分,主要内容如下:

  1. 字符的预处理
    • 统计频次
    • 计算字符对频次矩阵
  2. 实现一个简单的先验概率模型
    • 从训练数据中计算字符的先验概率
    • 根据先验概率通过采样生成字符串
    • 根据先验概率计算字符串的平均负对数似然度
  3. 优化语言模型,简单神经网络模型
    • 模拟一个简单语言模型的预测过程
    • 计算模型预测结果的负对数似然度
    • 通过梯度优化模型的参数,最小化模型的负对数似然度
import torch
import matplotlib.pyplot as plt 
import torch.nn.functional as F
from matplotlib.font_manager import FontProperties
font = FontProperties(fname='../chinese_pop.ttf', size=10)

数据集

数据是一个中文名数据集

  • 名字最小长度为 2:
  • 名字最大长度为 3:
words = open('../Chinese_Names_Corpus.txt', 'r').read().splitlines()
# 数据包含100多万个姓名,过滤出一个姓氏用来测试
names = [name for name in words if name[0] == '王' and len(name) == 3]
len(names)
52127
names[:10]
['王阿宝', '王阿炳', '王阿成', '王阿达', '王阿大', '王阿迪', '王阿多', '王阿芳', '王阿凤', '王阿福']

字符对统计:

把数据拆分为简单的上下文对,并统计在数据集中出现的频次:

b = {}
for w in names:
    chs = ['.'] + list(w) + ['.']
    for ch1, ch2 in zip(chs, chs[1:]):
        bigram = (ch1, ch2)
        b[bigram] = b.get(bigram, 0) + 1
# top 100
sorted(b.items(), key = lambda kv: -kv[1])[:10]
[(('.', '王'), 52127),
 (('王', '文'), 599),
 (('华', '.'), 555),
 (('王', '晓'), 538),
 (('王', '子'), 500),
 (('平', '.'), 481),
 (('明', '.'), 472),
 (('文', '.'), 450),
 (('林', '.'), 432),
 (('王', '建'), 431)]

从统计结果可以看到,以(‘平’, ‘明’, ‘文’,‘林’)结尾的名字最多,因为数据只包含王姓,所以('.', '王')频次最高。

构建词汇表到索引,索引到词汇表的映射,词汇表大小为:1561(加上开始和结束填充字符):

chars = sorted(list(set(''.join(names))))
char2i = {s:i+1 for i,s in enumerate(chars)}
char2i['.'] = 0               # 填充字符
i2char = {i:s for s,i in char2i.items()}
len(chars)
1650

计算字符频次矩阵:

N = torch.zeros((1651, 1651), dtype=torch.int32)
for w in names:
    chs = ['.'] + list(w) + ['.']
    for ch1, ch2 in zip(chs, chs[1:]):
        ix1 = char2i[ch1]
        ix2 = char2i[ch2]
        N[ix1, ix2] += 1

部分字符组合和可视化:

  • 行和列是全部的字符共1650+1(‘.’)
  • 每行统计数据中,所有两两字符组合的频次
plt.figure(figsize=(20, 20))
plt.imshow(N[:27,:54], cmap='Blues')
for i in range(27):
    for j in range(54):
        chstr = i2char[i] + i2char[j]
        plt.text(j, i, chstr, ha="center", va="bottom", color='gray', fontproperties=font)
        plt.text(j, i, N[i, j].item(), ha="center", va="top", color='gray')
plt.axis('off')

在这里插入图片描述

构建简单的语言模型

根据词频矩阵对频次进行行方向的归一化,得到先验概率矩阵,根据概率矩阵预测下一个词,过程如下:

  1. 根据矩阵的第一行,选择概率最高的词组(.x),(.王)被选中的概率最高。
  2. 然后根据对应的索引,查询矩阵的对应行,选择(王x)概率最高的组合。
  3. 如此这般,…直到遇到(x.)或者字符达到最大长度结束。

第一行是.和所有字符的组合的概率分布,由于数据是过滤了全部的王姓,所以的概率是最高的,这个结果是正常的。

# 计算每个字符组合的先验概率
p = N[0].float()
p = p / p.sum()
# 根据先验概率采样
g = torch.Generator().manual_seed(2147483647)
ix = torch.multinomial(p, num_samples=1, replacement=True, generator=g).item()
i2char[ix]
'王'

下面计算先验概率矩阵,根据先验概率生成10个名字:

# 字符对儿的先验概率矩阵
P = (N+1).float()
P /= P.sum(1, keepdims=True)
P.shape
torch.Size([1651, 1651])
g = torch.Generator().manual_seed(2147483647)

for i in range(10):
    out = []
    ix = 0
    while True:
        p = P[ix]
        ix = torch.multinomial(p, num_samples=1, replacement=True, generator=g).item()
        out.append(i2char[ix])
        if ix == 0 or len(out) == 3:
            break
    print(''.join(out))
王静修
王映凤
王定罗
戈佶次
王安.
王永仰
王娆拥
王牡右
王友缨
王梓集

以上就是最简单的概率模型,通过查表的方式生成名字字符串,生成过程都是基于可观察数据中的真实概率。

概率模型的量化评估

如何量化概率模型的生成结果?

答案是:likelihood,也叫做可能性或似然度,计算方式简单就是把所有词的概率相乘即可。例如,王阿宝:

l i k e l i h o o d = p ( . 王 ) × p ( 王阿 ) × p ( 阿宝 ) × p ( 宝 . ) likelihood = p(.王)\times p(王阿)\times p(阿宝) \times p(宝.) likelihood=p(.)×p(王阿)×p(阿宝)×p(.)

但是这会出现一个问题,就是概率都是小于1的值,只会越乘越小,所以可以计算log_likelihood,更利于观察:

l o g l i k e l i h o o d = l o g ( p ( . 王 ) ) + l o g ( p ( 王阿 ) ) + l o g ( p ( 阿宝 ) ) + l o g ( p ( 宝 . ) ) {log}_{likelihood} = log(p(.王)) + log(p(王阿)) + log(p(阿宝)) + log(p(宝.)) loglikelihood=log(p(.))+log(p(王阿))+log(p(阿宝))+log(p(.))

对数变换后,在增加一些常用的变换,取负值和计算平均似然度:

M e a n N e g a t i v e L o g L i k e l i h o o d = − l o g l i k e l i h o o d n = ( l o g ( p ( . 王 ) ) + l o g ( p ( 王阿 ) ) + l o g ( p ( 阿宝 ) ) + l o g ( p ( 宝 . ) ) b i g ) ∗ − 1 n MeanNegativeLogLikelihood = \frac{-{log}_{likelihood}}{n} = \frac{\big(log(p(.王)) + log(p(王阿)) + log(p(阿宝)) + log(p(宝.))\\big)*-1}{n} MeanNegativeLogLikelihood=nloglikelihood=n(log(p(.))+log(p(王阿))+log(p(阿宝))+log(p(.))big)∗−1

这意味着,如果生成的结果越好,平均负对数似然度就应该越小,反之越大。

下面计算部分模型生成结果的MNLL=MeanNegativeLogLikelihood:

# 计算字符串的对数似然度
log_likelihood = 0.0
n = 0

for w in ["王静修","王映凤","戈佶次"]:
    chs = ['.'] + list(w) + ['.']        
    for ch1, ch2 in zip(chs, chs[1:]):
        ix1 = char2i[ch1]
        ix2 = char2i[ch2]
        prob = P[ix1, ix2]
        logprob = torch.log(prob)
        log_likelihood += logprob
        n += 1
        print(f'{ch1}{ch2}: {prob:.4f} {logprob:.4f}')
print(f'{log_likelihood=}')
print('negative log likelihood =',-log_likelihood)
mean_nll = -log_likelihood/n
print(f'{mean_nll=}')
.王: 0.9693 -0.0312
王静: 0.0028 -5.8954
静修: 0.0005 -7.5648
修.: 0.0143 -4.2474
.王: 0.9693 -0.0312
王映: 0.0005 -7.5968
映凤: 0.0006 -7.4260
凤.: 0.1019 -2.2840
.戈: 0.0000 -10.8926
戈佶: 0.0006 -7.4146
佶次: 0.0006 -7.4097
次.: 0.0006 -7.4103
log_likelihood=tensor(-68.2039)
negative log likelihood = tensor(68.2039)
mean_nll=tensor(5.6837)

下面根据先验概率计算出整个数据的MNLL:

# 计算全部样本的平均负对数似然度
log_likelihood = 0.0
n = 0

for w in names:
    chs = ['.'] + list(w) + ['.']        
    for ch1, ch2 in zip(chs, chs[1:]):
        ix1 = char2i[ch1]
        ix2 = char2i[ch2]
        prob = P[ix1, ix2]
        logprob = torch.log(prob)
        log_likelihood += logprob
        n += 1

nll = -log_likelihood
mean_nll = nll/n
print(f'{mean_nll=}')
mean_nll=tensor(3.9716)

下面随机测试一些名字:

# 计算字符串的对数似然度
log_likelihood = 0.0
n = 0

for w in ["一乃乃","乃乃乃","丁丫丫"]:
    chs = ['.'] + list(w) + ['.']        
    for ch1, ch2 in zip(chs, chs[1:]):
        ix1 = char2i[ch1]
        ix2 = char2i[ch2]
        prob = P[ix1, ix2]
        logprob = torch.log(prob)
        log_likelihood += logprob
        n += 1
        print(f'{ch1}{ch2}: {prob:.4f} {logprob:.4f}')
print(f'{log_likelihood=}')
print('negative log likelihood =',-log_likelihood)
mean_nll = -log_likelihood/n
print(f'{mean_nll=}')
.一: 0.0000 -10.8926
一乃: 0.0005 -7.6406
乃乃: 0.0006 -7.4559
乃.: 0.0006 -7.4559
.乃: 0.0000 -10.8926
乃乃: 0.0006 -7.4559
乃乃: 0.0006 -7.4559
乃.: 0.0006 -7.4559
.丁: 0.0000 -10.8926
丁丫: 0.0006 -7.4236
丫丫: 0.0006 -7.4103
丫.: 0.0012 -6.7172
log_likelihood=tensor(-99.1490)
negative log likelihood = tensor(99.1490)
mean_nll=tensor(8.2624)

通过上面的测试结果,可以发现数据中真实正常的名字MNLL = 3.97,根据先验概率生成的结果MNLL = 5.68,随机编的奇葩名字MNLL = 8.26。这也验证生成效果越差,MNLL值越大。

优化模型:

接下就是通过神经网络模型来替代之前的简单模型,通过找到一组参数可以实现以下目标:

  • 最大化生成结果的对数似然度 = = = 最小化负对数似然度 = = = 最小化平均负对数似然度,生成更加符合数据分布的结果。

在这里插入图片描述

x n ∗ 1651 × W 1651 ∗ 1651 = l o g i t s n ∗ 1651 x_{n*1651} \times W_{1651*1651} = {logits}_{n*1651} xn1651×W16511651=logitsn1651

M N L L = − ∑ i = 1 n l o g ( f p ( l o g i t s ) [ i ] ) n MNLL = \frac{-\sum_{i=1}^{n} log(f_p(logits)[i])}{n} MNLL=ni=1nlog(fp(logits)[i])

  • W W W : 模型的参数矩阵
  • 1651 : 词汇表的大小,也是输入向量化后的长度
  • n :输入输出序列的长度
  • f p f_p fp : 转换函数把logits缩放为0~1之间概率值
  • MNLL : 平均负对数似然度

创建训练数据:(x,y)

xs, ys = [], []

for w in names[:1]:
    chs = ['.'] + list(w) + ['.']
    for ch1, ch2 in zip(chs, chs[1:]):
        ix1 = char2i[ch1]
        ix2 = char2i[ch2]
        print(ch1, ch2)
        xs.append(ix1)
        ys.append(ix2)
    
xs = torch.tensor(xs)
ys = torch.tensor(ys)
. 王
王 阿
阿 宝
宝 .
xs(char)ys(char)xs(index)ys(index)
.0993
9931539
1539409
.4090

下面我们模拟神经网络模型的推理过程,简单起见,模型只有一个权重矩阵(输入 → \to 输出),计算模型输出:

  1. 对输入进行向量化,one-hot编吗:
xenc = F.one_hot(xs, num_classes=1651).float()
xenc
tensor([[1., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.]])

模型输入向量的可视化:
在这里插入图片描述

  1. 随机初始化的输入到输出之间的权重矩阵 W W W,计算模型的输出:预测ys的概率分布,即xs每个词对应下个词的概率分布。
W = torch.randn((1651, 1651))
W.shape
torch.Size([1651, 1651])

权重矩阵的可视化:

在这里插入图片描述

  1. 计算模型的输出:矩阵乘法
logits = xenc @ W # log-counts
counts = logits.exp() # equivalent N
probs = counts / counts.sum(1, keepdims=True) # scale to 0~1
probs
tensor([[2.6660e-04, 3.3742e-03, 1.3357e-03,  ..., 3.4182e-04, 2.3816e-04,
         3.4352e-04],
        [2.1228e-04, 1.5516e-03, 5.3819e-05,  ..., 1.5116e-03, 1.8045e-04,
         1.7484e-04],
        [7.3022e-04, 8.9569e-04, 1.9453e-04,  ..., 1.0783e-04, 2.8304e-03,
         9.5034e-05],
        [2.9773e-04, 6.6036e-04, 1.1865e-03,  ..., 1.6132e-04, 1.7862e-04,
         4.8288e-04]])

模型输出的可视化:

在这里插入图片描述

  1. 下面根据最终的输出,每一行概率最大元素对应的索引即模型的预测值:
for i in torch.argmax(probs, axis=1):
    print(i.item(),i2char[i.item()])
1316 萱
30 乐
869 济
573 惜
  1. 计算随机模型预测结果的MNLL:
xs,ys
(tensor([   0,  993, 1539,  409]), tensor([ 993, 1539,  409,    0]))

nlls = torch.zeros(4)
for i in range(4):
    # i-th bigram:
    x = xs[i].item() # input character index
    y = ys[i].item() # label character index
    print('--------')
    print(f'example {i+1}: {i2char[x]}{i2char[y]} (indexes {x},{y})')
    print('input to the neural net:', x)
    print('label (next  character):', y)
    p = probs[i, y]
    print('probability assigned by net:', p.item())
    logp = torch.log(p)
    print('log likelihood:', logp.item())
    nll = -logp
    print('negative log likelihood:', nll.item())
    nlls[i] = nll

print('=========')
print('average negative log likelihood, i.e. loss =', nlls.mean().item())
--------
example 1: .王 (indexes 0,993)
input to the neural net: 0
label (next  character): 993
probability assigned by net: 0.00024021849094424397
log likelihood: -8.333961486816406
negative log likelihood: 8.333961486816406
--------
example 2: 王阿 (indexes 993,1539)
input to the neural net: 993
label (next  character): 1539
probability assigned by net: 0.0004108154389541596
log likelihood: -7.797366619110107
negative log likelihood: 7.797366619110107
--------
example 3: 阿宝 (indexes 1539,409)
input to the neural net: 1539
label (next  character): 409
probability assigned by net: 0.002926822518929839
log likelihood: -5.833837985992432
negative log likelihood: 5.833837985992432
--------
example 4: 宝. (indexes 409,0)
input to the neural net: 409
label (next  character): 0
probability assigned by net: 0.0002977268013637513
log likelihood: -8.11933422088623
negative log likelihood: 8.11933422088623
=========
average negative log likelihood, i.e. loss = 7.521124839782715

对比之前的测试结果,随机初始化的模型预测结果和随机生成的名字差不多。

梯度下降

通过MNLL(loss)对参数 W W W求导计算梯度,根据梯度更新模型。

# 使用全量数据
xs, ys = [], []
for w in names:
    chs = ['.'] + list(w) + ['.']
    for ch1, ch2 in zip(chs, chs[1:]):
        ix1 = char2i[ch1]
        ix2 = char2i[ch2]
        xs.append(ix1)
        ys.append(ix2)
xs = torch.tensor(xs)
ys = torch.tensor(ys)
num = xs.nelement()
print('number of examples: ', num)
number of examples:  208508
# 随机初始化
g = torch.Generator().manual_seed(202304191424)
W = torch.randn((1651, 1651), generator=g, requires_grad=True)
# gradient descent
history = {'loss':[]}
for k in range(100):
    # forward pass
    xenc = F.one_hot(xs, num_classes=1651).float()  # one-hot encoding
    logits = xenc @ W                             # predict log-counts
    counts = logits.exp()                         # counts, equivalent to N
    probs = counts / counts.sum(1, keepdims=True) # probabilities for next character
    loss = -probs[torch.arange(num), ys].log().mean() + 0.01*(W**2).mean() # Add a regular
    #print(loss.item())
    history['loss'].append(loss.item())
    # backward pass
    W.grad = None                                 # set to zero the gradient
    loss.backward()
    # update
    W.data += -300 * W.grad
plt.figure(figsize=(8,3))
plt.plot(history['loss'], label='NN model')
plt.axhline(y=3.9716, c='red')
plt.grid()

在这里插入图片描述

经过100多轮的训练,模型的预测结果已经达到了真实数据的水平,下面是测试结果:

# finally, sample from the 'neural net' model
g = torch.Generator().manual_seed(202304191533)

for i in range(10):
    out = []
    ix = 0
    while True:
        xenc = F.one_hot(torch.tensor([ix]), num_classes=1651).float()
        logits = xenc @ W # predict log-counts
        counts = logits.exp() # counts, equivalent to N
        p = counts / counts.sum(1, keepdims=True) # probabilities for next character
        ix = torch.multinomial(p, num_samples=1, replacement=True, generator=g).item()
        out.append(i2char[ix])
        if ix == 0 or len(out) == 3:
            break
    print(''.join(out))
王骏杭
王桂普
王晓薪
王亦麒
王英.
王长萍
王丙能
王中.
王占郢
王光皓

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

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

相关文章

渗透测试--4.捕获和监听数据

目录 目录 1.监听捕获数据方法 2.kali监听捕获工具介绍 arpspoof arpspoof实战(同一局域网断网实战) driftnet 实战使用drifnet和工具捕获网络图片 1、扫描目标主机,开启ip转发 2、打开ettercap 3、进行arp欺骗: 4、使用drif…

Gap Hours,我在内卷和摆烂之间的折中选择

点击文末“阅读原文”即可参与节目互动 剪辑、音频 / 卷圈 运营 / SandLiu 卷圈 监制 / 姝琦 文案 / 粒粒 产品统筹 / bobo 场地支持 / 声湃轩天津录音间 一个名词解释: Gap Day,是工作和生活中为了从不好的状态中跳脱出来,享受了躺平…

技术支持内容

平台技术简介: 前端:采用Vue、uni-app等技术。 后端:采用Spring Boot 。 权限:采用Jwt,支持多终端认证系统。 邮箱: postmasterzhonghuisoft.cn 平台基础功能: 用户管理: 管理…

常数整数乘法优化

常数整数乘法优化 文章目录 常数整数乘法优化基于正则有符号数的常数整数乘法优化Example 1: 20 x 20x 20xExample 2: 153 x 153x 153xExample 3: 15 x 15x 15x正则有符号数编码 CSD二进制序列转CSD编码算法流程代码实现欢迎关注公众号【三戒纪元】 嵌入式机器学习或深度学习…

人工智能的机器人技术为啥那么强,对于未来意味着什么?

前言 人工智能技术的发展,推动了机器人技术的不断进步。机器人技术在工业、医疗、服务等领域发挥着越来越重要的作用。本文将详细介绍人工智能的机器人技术。 机器人技术的发展历程 机器人技术的发展可以追溯到20世纪50年代。当时,机器人主要用于工业生…

怎么给移动硬盘查错?移动硬盘查错能恢复数据吗

移动硬盘在长期使用或使用不当的情况下,可能会出现硬盘文件损坏或者出现坏道等问题,影响数据安全和文件操作。这时候,移动硬盘查错工具就派上用场了。它可以帮助用户发现移动硬盘中的问题,并且还可以对移动硬盘进行修复。 但是&a…

chatgpt赋能Python-python3_7怎么改颜色

Python3.7中如何改变颜色的方法 Python是一门广泛应用于各种领域的编程语言,其强大的数据分析能力和简单易用的语法得到了越来越多的开发者的青睐。在Python中,要想使文本在输出时带有颜色,可以使用ANSI转义序列进行操作。 什么是ANSI转义序…

国考省考行测:数量关系,消三法,比,分数,百分数,n倍

国考省考行测: 2022找工作是学历、能力和运气的超强结合体! 公务员特招重点就是专业技能,附带行测和申论,而常规国考省考最重要的还是申论和行测,所以大家认真准备吧,我讲一起屡屡申论和行测的重要知识点 遇到寒冬&am…

spring数据校验:Validation

目录 Spring Validation概述 通过Validator接口实现 Bean Validation注解实现 基于方法实现校验 实现自定义校验 Spring Validation概述 在开发中,我们经常遇到参数校验的需求,比如用户注册的时候,要校验用户名不能为空、用户名长度不超…

从眼中窥视:Google AI 模型如何通过眼睛预测你的年龄

新的模型可以通过分析眼部照片揭示衰老的秘密 近年来,谷歌一直在研究各种人工智能模型,可以分析眼睛(内部和外部)的图像并监测某些参数。正如之前提到的,开发能够从眼睛中提取信息的 AI 模型意味着能够以经济高效和无创…

Array-Deque-Queue等的区别

🔎Deque(双端队列): Deque 是 “double-ended queue” 的缩写,表示双端队列。它是一种可以在两端进行插入和删除操作的数据结构。你可以在队列的头部和尾部同时进行插入和删除操作。Deque 接口定义了这些操作的方法,如…

国际博物馆日|科技与文化的碰撞:大势智慧助力博物馆赋能美好生活

近年来,我国博物馆事业蓬勃发展,而科技与文博领域的深度融合,将继续成为博物馆事业高质量发展的助推器。作为连接过去、现在、未来的桥梁和新时代文化交流与传播的窗口,博物馆不仅是保护和传承人类文明的重要殿堂,也是…

网络优化干扰培训讲解

一、系统外干扰 1、信号放大器 1、特征:RB尖峰突起(类似于互调干扰,极少数会形成宽频干扰。信号放大器为目前FDD频段主要干扰源 2、影响范围:周边站点 3、干扰来源:用户私装信号放大器、黑直放站. 4、原因分析:放…

javaIO流之字节流

目录 1、字节输出流(OutputStream)2、FileOutputStream类2.1FileOutputStrea 的构造方法2.2FileOutputStream 写入字节数据2.3FileOutputStream实现数据追加、换行 3、字节流入流(InputStream)4、FileInputStream类4.1FileInputSt…

介绍自己的产品时,常犯的那些错

最近的一个轻咨询客户,在“全面提升组织产品能力”的项目中,正处于内部自学的“读书会”环节。 为了“用以致学”,而不是“学以致用”地读书,我给他们出了一道看起来很简单的题——介绍一下自己手头正在负责的产品。 前几天&#…

Java枚举

Java枚举 🍺1 背景及定义🍺🧃2 使用🧃🥤3 枚举优点缺点🥤🍵4 枚举和反射🍵🍷4.1 枚举是否可以通过反射,拿到实例对象呢?🍷 ☕️5 总结…

正负压力精密控制在隐形牙齿矫正器成型机中的应用

摘要:真空压力热成型技术作为一种精密成型工艺在诸如隐形牙套等制作领域得到越来越多的重视,其主要特点是要求采用高精度的正负压力控制手段来抵消重力对软化膜变形的影响以及精密控制成型膜厚度。本文提出了相应的改进解决方案,通过可编程的…

Greenplum数据库系统架构

Greenplum数据库系统架构 Greenplum是一个纯软件的MPP数据库服务器,其系统架构专门用于管理大规模分析型数据仓库或商业智能工作负载。从技术上讲,MPP无共享架构是指具有多个节点的系统,每个节点都有自己的内存、操作系统和磁盘,…

【天线专题】天线(Antenna)的理解

天线,英文名称是(Antenna),本义是指像蚂蚁、蜜蜂这样的小动物头顶上的触角。天线的作用就是将调制到射频频率的数字信号或模拟信号发射到空间无线信道,或从空间无线信道接收调制在射频频率上的数字或模拟信号。简单来说就是有发射和接收电磁波的功能。 所以两只蚂…

chatgpt赋能Python-python3_5怎么用

Python 3.5是什么? Python是一种高级编程语言,非常流行并广泛使用。Python3.5是Python编程语言的一个较新的版本,它具有许多新的功能和改进。Python 3.5已包含许多流行的Python框架。它可以用于各种任务,例如web开发,数据科学&a…