• 浅谈强化学习
    强化学习(Reinforcement Learning, RL),是机器学习的范式和方法论之一,用于描述和解决智能体(agent)在与环境的交互过程中通过学习策略以达成回报最大化或实现特定目标的问题 。强化学习是智能体(Agent)以“试错”的方式进行学习,通过与环境进行交互获得的奖赏指导行为,目标是使智能体获得最大的奖赏,强化学习不同于连接主义学习中的监督学习,主要表现在强化信号上,强化学习中由环境提供的强化信号是对产生动作的好坏作一种评价(通常为标量信号),而不是告诉强化学习系统RLS(reinforcement learning system)如何去产生正确的动作。由于外部环境提供的信息很少,RLS必须靠自身的经历进行学习。通过这种方式,RLS在行动-评价的环境中获得知识,改进行动方案以适应环境。强化学习的常见模型是标准的马尔可夫决策过程(Markov Decision Process)。按给定条件,强化学习可分为基于模式的强化学习(model-based RL)和无模式强化学习(model-free RL),以及主动强化学习(active RL)和被动强化学习(passive RL)。强化学习的变体包括逆向强化学习、阶层强化学习和部分可观测系统的强化学习。求解强化学习问题所使用的算法可分为策略搜索算法和值函数(value function)算法两类。深度学习可以在强化学习中得到使用,形成深度强化学习 。强化学习理论受到行为主义心理学启发,侧重在线学习并试图在探索-利用(exploration-exploitation)间保持平衡。不同于监督学习和非监督学习,强化学习不要求预先给定任何数据,而是通过接收环境对动作的奖励(反馈)获得学习信息并更新模型参数。强化学习问题在信息论、博弈论、自动控制等领域有得到讨论,被用于解释有限理性条件下的平衡态、设计推荐系统和机器人交互系统 。一些复杂的强化学习算法在一定程度上具备解决复杂问题的通用智能,可以在围棋和电子游戏中达到人类水平。
  • [其他] 有监督机器学习和无监督机器学习的核心哲学
    有监督机器学习的核心哲学:使用“数据驱动”方法让计算机可以学习输入/输出之间的正确映射。它需要一系列“标记”记录,其中包含训练集中的输入和期望的输出,以便将输入到输出的映射学习为一种准确的行为表现。可以用下面这个图来表示:无监督机器学习的核心哲学:让计算机学习输入的内部结构而不是输入/输出之间的正确映射。它通过对数据的模式和相关关系进行分析来理解不存在标记数据要求的输入数据。它通常会发现输入数据内部的隐藏模式。个人觉得 无监督机器学习应该更高级一些,因为它有更多一点的无为而治的意思在里面。
  • ModelArts
    如何通过python代码在桶中创建文件夹?想把训练完的数据保存起来,报错没有这样的目录,mkdir没创建出来
  • [其他] 浅谈机器学习算法—高斯混合模型 (GMM)
    机器学习算法:高斯混合模型 (GMM) 。它们用于根据概率分布将数据分类为不同的类别。高斯混合模型可用于许多不同的领域,包括金融、营销等等!这里要对高斯混合模型进行介绍以及真实世界的示例、它们的作用以及何时应该使用GMM。        高斯混合模型 (GMM) 是一个概率概念,用于对真实世界的数据集进行建模。GMM是高斯分布的泛化,可用于表示可聚类为多个高斯分布的任何数据集。        高斯混合模型是一种概率模型,它假设所有数据点都是从具有未知参数的高斯分布的混合中生成的。        高斯混合模型可用于聚类,这是将一组数据点分组为聚类的任务。GMM 可用于在数据集中可能没有明确定义的集群中查找集群。此外,GMM 可用于估计新数据点属于每个集群的概率。高斯混合模型对异常值也相对稳健,这意味着即使有一些数据点不能完全适合任何集群,它们仍然可以产生准确的结果。这使得 GMM 成为一种灵活而强大的数据聚类工具。它可以被理解为一个概率模型,其中为每个组假设高斯分布,并且它们具有定义其参数的均值和协方差。        GMM 由两部分组成——均值向量 (μ) 和协方差矩阵 (Σ)。高斯分布被定义为呈钟形曲线的连续概率分布。高斯分布的另一个名称是正态分布。这是高斯混合模型的图片:它可以被理解为一个概率模型,其中为每个组假设高斯分布,并且它们具有定义其参数的均值和协方差。GMM 由两部分组成——均值向量 (μ) 和协方差矩阵 (Σ)。高斯分布被定义为呈钟形曲线的连续概率分布。高斯分布的另一个名称是正态分布。高斯混合模型的图片:        GMM 有许多应用,例如密度估计、聚类和图像分割。对于密度估计,GMM 可用于估计一组数据点的概率密度函数。对于聚类,GMM 可用于将来自相同高斯分布的数据点组合在一起。对于图像分割,GMM 可用于将图像划分为不同的区域。        高斯混合模型可用于各种用例,包括识别客户群、检测欺诈活动和聚类图像。在这些示例中的每一个中,高斯混合模型都能够识别数据中可能不会立即明显的聚类。因此,高斯混合模型是一种强大的数据分析工具,应该考虑用于任何聚类任务。        在高斯混合模型中,期望最大化方法是估计高斯混合模型(GMM)参数的有力工具。期望称为E,最大化称为M。期望用于找到用于表示高斯混合模型的每个分量的高斯参数。最大化被称为 M 并且它涉及确定是否可以添加新数据点,可以从下面链接进一步了解期望最大化。
  • [技术干货] 如何全面掌握图机器学习?最新《图学习》全面综述
    图学习旨在学习现实世界中常见的复杂节点关系和图的拓扑结构,如社交网络、学术网络和电子商务网络等。这些关系使得图数据与传统的表格数据不同,其中节点依赖于非欧氏空间,包含了丰富的信息。图学习从图论发展到图数据挖掘,现在被赋予表示学习的能力,使其在各种场景中取得了出色的性能,甚至包括文本、图像、化学和生物。由于在现实世界中的广泛应用前景,图学习已经成为机器学习中一个热门且有前景的领域。近年来,已有成千上万的研究成果被提出用于解决图学习中的各种问题,引起了学术界越来越多的关注,因此对已有的有价值的研究成果进行综述变得至关重要。尽管一些研究人员已经注意到这种现象,并完成了关于图学习的令人印象深刻的调研。然而,由于图学习的快速扩展,它们未能以更合乎逻辑的方式将相关目标、方法和应用联系起来,并涵盖当前丰富的场景和具有挑战性的问题。1. 引言图学习旨在对图进行建模,图是一种广泛存在于真实场景中的非欧氏数据,与以往机器学习中的数据结构有很大不同,如社交网络[1]、[2]、[3],学术网络[4]、[5]、[6],电子商务网络[7]、[8]、[9],企业知识图谱[10]、[11]、[12]等。挖掘图中节点间复杂连接关系和拓扑结构中蕴含的丰富信息,对于图上的许多任务和应用具有重要意义。此外,传统应用也可以转换为图数据(如计算机视觉[13]、[14]、[15]、语言模型[16]、[17]、[18]、物理[19]、[20]和化学[21]、[22])。重点假设不同实体之间存在许多未直接观察到的潜在联系。这使得图学习不仅是一种处理自然图结构的方法,而且是一种思考各种问题的方式。由于图学习具有广阔的应用前景,因此在国内外引起了广泛的关注。尽管之前关于图的理论工作帮助人们理解图上的各种字符,并提供了基本的分析框架。这些工作通常集中在较小的模拟图上,这限制了它们在真实场景中的应用,特别是当图上存在复杂的关系和结构时。尽管在这一领域已经有了一些显著而详细的调查。目前还缺乏一个综合的、将相关的目标、方法和应用联系起来,形成一个有机的、逻辑的综述。此外,每年在顶级会议上都有数百篇关于图学习的研究,并且数量还在高速增长。由于其发展迅速,缺乏涵盖最新趋势和挑战的全面调研。图2按时间顺序展示了有影响力的图学习方法。这些方法主要分为3类(图挖掘方法、图表示方法和深度图学习方法)。在图学习早期,大多数方法集中于图的字符[1]或利用图的结构信息在小图[25]、[26]上完成一些下游任务。图表示学习目前占据主流地位,可归纳为图嵌入方法和图神经网络方法两大类。这两类方法都旨在学习节点、边或图的语义表示。前者直接优化嵌入,可以减少图结构信息的损失;后者利用深度神经网络,在图上建模信息传递过程。如图3所示,在本综述中,我们从图学习目标的角度提供了一个直观的分类法。根据图的元素(即节点、边和图结构)对以前对图的工作进行排序。基于这种逻辑,综述了图上的相关方法和任务。展示了图学习在现实世界中的各种应用上的出色性能。最后,提出了图学习的发展趋势和挑战,以期进一步推动该领域的研究。本综述的主要贡献总结如下。提供了一个新的分类法,以调查以前关于数据、模型和任务的研究。总结了当前图学习在现实世界中的应用。提出了图学习的当前趋势和挑战。本文的其余部分组织如下。第2节从数据、模型和任务3个角度,基于节点、边和图结构对已有工作进行了直观的分类。第3节展示了用于图学习的主要方法和当前的研究趋势。第四部分总结了该方法在实际中的应用。第5节提出了当今图学习面临的挑战。2 方法在本节中,我们将当前的模型分为两大类(即传统模型和图神经网络)。传统模型可以进一步分为3类(即矩阵分解模型、基于随机游走的模型和基于自编码器的模型)。首先回顾了传统模型,其中一些仍然活跃或与GNN相结合,并给出了当前模型的许多启示。在大多数场景下,与传统模型相比,GNN表现出更高的表达能力和出色的性能。本文将GNN归纳为两个方面。3 应用介绍当前图学习在现实世界中的主要应用,包括传统的机器学习场景,如推荐系统、自然语言处理、计算机视觉和金融科技,以及科学场景中的新兴应用,如化学、生物、物理和数学。最后,总结了图学习中流行的数据集。
  • [AI大赛] 巴山楚水凄凉地
    ↵欢迎大家来我的画进行点评
  • [执行问题] 向大佬请教一个在Mindspore中遇到的问题,ValueError: For 'MatMul', the input dimensions must be equal, but got 'x1_col':
    import os# os.environ['DEVICE_ID'] = '6'import numpy as npimport mindspore as msfrom mindspore import nnfrom mindspore import contextfrom mindspore import datasetfrom mindspore.train.callback import LossMonitorfrom mindspore.common.api import ms_functionfrom mindspore.ops import operations as Pfrom PIL import Image#当前实验选择算力为Ascend,如果在本地体验,参数device_target设置为"CPU”context.set_context(mode=context.GRAPH_MODE, device_target="Ascend")#要筛选的分辨率条件targetWidth=426targetHeight=640targetChannal=3#读取animal文件夹下所有文件的名字rootDir='animal'fileNameList=['cat','elephant','sheep']label_map = { 'cat': 0, 'elephant': 1, 'sheep': 2}X,Y=[],[]for fileName in fileNameList: fileDir=rootDir+'/'+fileName #print(fileDir) imgNameList=os.listdir(fileDir) #print(imgNameList) for imgName in imgNameList: imgDir=fileDir+'/'+imgName img=Image.open(imgDir) img=np.array(img) if(len(img.shape)==3): width,height,channal=img.shape if width==targetWidth and height==targetHeight and channal==targetChannal:#符合筛选条件的样本留下放到X,其标签放到Y X.append(img.flatten()) Y.append(label_map[fileName])#类别#print(X,Y)#划分训练集和测试集合sampleNum=len(X)train_idx = np.random.choice(sampleNum, int(sampleNum*0.8), replace=False)#取80%的样本作为训练集test_idx = np.array(list(set(range(sampleNum)) - set(train_idx)))#剩下的样本作为测试集X_train=[X[i].astype(np.float32) for i in range(len(X)) if i in train_idx]Y_train=[Y[i] for i in range(len(Y)) if i in train_idx]X_test=[X[i].astype(np.float32) for i in range(len(X)) if i in test_idx]Y_test=[Y[i] for i in range(len(Y)) if i in test_idx]XY_train = list(zip(X_train, Y_train))ds_train = dataset.GeneratorDataset(XY_train, ['x', 'y'])# ds_train.set_dataset_size(sampleNum)ds_train = ds_train.shuffle(buffer_size=sampleNum).batch(32, drop_remainder=True)XY_test = list(zip(X_test, Y_test))ds_test = dataset.GeneratorDataset(XY_test, ['x', 'y'])ds_test = ds_test.batch(30)#具体作用#print(XY_test)for e in X_train: print(e.shape)net = nn.Dense(targetWidth*targetHeight, 3)loss = nn.loss.SoftmaxCrossEntropyWithLogits(sparse=True, reduction='mean')opt = nn.optim.Momentum(net.trainable_params(), learning_rate=0.05, momentum=0.9)model = ms.train.Model(net, loss, opt, metrics={'acc', 'loss'})model.train(25, ds_train, callbacks=[LossMonitor(per_print_times=ds_train.get_dataset_size())], dataset_sink_mode=False)metrics = model.eval(ds_test)print(metrics)本小白正学习如何使用Mindspore,打算用逻辑回归对图片进行分类。输入到回归模型的每个样本数据都是426*640的图片经过flatten后产生的数组,该数组的shape为(817920,),X_train就是若干这样的数组组成的。构建完模型之后,开始训练时产生了如下的错误:[ERROR] ANALYZER(8534,ffffb5cca780,python):2022-11-30-10:59:18.593.719 [mindspore/ccsrc/pipeline/jit/static_analysis/async_eval_result.cc:66] HandleException] Exception happened, check the information as below.The function call stack (See file '/home/ma-user/work/rank_0/om/analyze_fail.dat' for more details):# 0 In file /home/ma-user/anaconda3/envs/MindSpore/lib/python3.7/site-packages/mindspore/nn/wrap/cell_wrapper.py(373) loss = self.network(*inputs) ^# 1 In file /home/ma-user/anaconda3/envs/MindSpore/lib/python3.7/site-packages/mindspore/nn/wrap/cell_wrapper.py(111) out = self._backbone(data) ^# 2 In file /home/ma-user/anaconda3/envs/MindSpore/lib/python3.7/site-packages/mindspore/nn/layer/basic.py(323) if len(x_shape) != 2:# 3 In file /home/ma-user/anaconda3/envs/MindSpore/lib/python3.7/site-packages/mindspore/nn/layer/basic.py(326) if self.has_bias:# 4 In file /home/ma-user/anaconda3/envs/MindSpore/lib/python3.7/site-packages/mindspore/nn/layer/basic.py(325) x = self.matmul(x, self.weight) ^---------------------------------------------------------------------------ValueError Traceback (most recent call last)/tmp/ipykernel_8534/2891349598.py in 1 model = ms.train.Model(net, loss, opt, metrics={'acc', 'loss'})----> 2 model.train(25, ds_train, callbacks=[LossMonitor(per_print_times=ds_train.get_dataset_size())], dataset_sink_mode=False) 3 metrics = model.eval(ds_test) 4 print(metrics)~/anaconda3/envs/MindSpore/lib/python3.7/site-packages/mindspore/train/model.py in train(self, epoch, train_dataset, callbacks, dataset_sink_mode, sink_size) 904 callbacks=callbacks, 905 dataset_sink_mode=dataset_sink_mode,--> 906 sink_size=sink_size) 907 908 def build(self, train_dataset=None, valid_dataset=None, sink_size=-1, epoch=1, jit_config=None):~/anaconda3/envs/MindSpore/lib/python3.7/site-packages/mindspore/train/model.py in wrapper(self, *args, **kwargs) 85 raise e 86 else:---> 87 func(self, *args, **kwargs) 88 return wrapper 89 ~/anaconda3/envs/MindSpore/lib/python3.7/site-packages/mindspore/train/model.py in _train(self, epoch, train_dataset, callbacks, dataset_sink_mode, sink_size) 540 self._check_reuse_dataset(train_dataset) 541 if not dataset_sink_mode:--> 542 self._train_process(epoch, train_dataset, list_callback, cb_params) 543 elif context.get_context("device_target") == "CPU": 544 logger.info("The CPU cannot support dataset sink mode currently."~/anaconda3/envs/MindSpore/lib/python3.7/site-packages/mindspore/train/model.py in _train_process(self, epoch, train_dataset, list_callback, cb_params) 792 cb_params.train_dataset_element = next_element 793 list_callback.step_begin(run_context)--> 794 outputs = self._train_network(*next_element) 795 cb_params.net_outputs = outputs 796 if self._loss_scale_manager and self._loss_scale_manager.get_drop_overflow_update():~/anaconda3/envs/MindSpore/lib/python3.7/site-packages/mindspore/nn/cell.py in __call__(self, *args, **kwargs) 584 logger.warning(f"For 'Cell', it's not support hook function in graph mode. If you want to use hook " 585 f"function, please use context.set_context to set pynative mode.")--> 586 out = self.compile_and_run(*args) 587 return out 588 ~/anaconda3/envs/MindSpore/lib/python3.7/site-packages/mindspore/nn/cell.py in compile_and_run(self, *inputs) 962 """ 963 self._auto_parallel_compile_and_run = True--> 964 self.compile(*inputs) 965 966 new_inputs = []~/anaconda3/envs/MindSpore/lib/python3.7/site-packages/mindspore/nn/cell.py in compile(self, *inputs) 935 """ 936 if self._dynamic_shape_inputs is None or self._dynamic_shape_inputs[0] is None:--> 937 _cell_graph_executor.compile(self, *inputs, phase=self.phase, auto_parallel_mode=self._auto_parallel_mode) 938 else: 939 self._check_compile_dynamic_shape(*inputs)~/anaconda3/envs/MindSpore/lib/python3.7/site-packages/mindspore/common/api.py in compile(self, obj, phase, do_convert, auto_parallel_mode, *args) 1004 enable_ge = context.get_context("enable_ge") 1005 self._graph_executor.set_weights_values(obj.parameters_dict())-> 1006 result = self._graph_executor.compile(obj, args_list, phase, self._use_vm_mode()) 1007 obj.compile_cache.add(phase) 1008 if not result:~/anaconda3/envs/MindSpore/lib/python3.7/site-packages/mindspore/ops/primitive.py in __check__(self, *args) 465 for track in tracks: 466 fn = getattr(self, 'check_' + track)--> 467 fn(*(x[track] for x in args)) 468 469 ~/anaconda3/envs/MindSpore/lib/python3.7/site-packages/mindspore/ops/operations/math_ops.py in check_shape(self, x1, x2) 1387 if np.all(np.array(x1) != -1) and np.all(np.array(x2) != -1): 1388 if x1_col != x2_row:-> 1389 raise ValueError(f"For '{cls_name}', the input dimensions must be equal, but got 'x1_col': {x1_col} " 1390 f"and 'x2_row': {x2_row}. And 'x' shape {x1}(transpose_a={self.transpose_a}), " 1391 f"'y' shape {x2}(transpose_b={self.transpose_b}).")ValueError: For 'MatMul', the input dimensions must be equal, but got 'x1_col': 817920 and 'x2_row': 272640. And 'x' shape [32, 817920](transpose_a=False), 'y' shape [3, 272640](transpose_b=True).请教各位有经验的大佬,我这个模型或者其他代码有什么问题,如何修改?
  • [安装经验] Mindspore实现简单线性回归
    本文将实现简单的线性回归,演示如何搭建和训练网络待拟合的目标函数为f(x)=5x+3文章分为五部分:生成数据构建拟合模型并初始化参数训练模型训练结果生成数据集​​​​​​在[-10,10]的范围内,生成一系列的随机自变量x并生成对应的因变量y,同时生成一系列的正态分布随机数作为噪声。将噪声加到自变量x对应的因变量y上,得到原始数据。定义数据集生成函数create_data:def create_data(num, w=5.0, b=3.0): for _ in range(num): x = np.random.uniform(-10.0, 10.0) noise = np.random.normal(0, 1) y = x * w + b + noise yield np.array([x]).astype(np.float32), np.array([y]).astype(np.float32)# 用 yield 函数生成可迭代的生成器,当 num 很大时,可很有效的减小内存占用eval_data = list(create_data(50,5,3))#生成50个带噪声的随机点为提高模型泛化能力、提高模型店鲁棒性,我们还会引入增强函数来对原始数据进行数据增强。定义数据集增强函数enhance_data():可以指定数据集的分组大小batch和重复次数。同时用mindspore.dataset.GeneratorDataset将数据集转化为MindSpore所能够识别的数据格式。def enhance_data(num_data, batch_size=16, repeat_size=1): input_data = ds.GeneratorDataset(list(create_data(num_data)), column_names=['data','label']) input_data = input_data.batch(batch_size) input_data = input_data.repeat(repeat_size) return input_data#构建了1600个训练的数据:每个batch的大小为1600,分为100个batch进行训练data_number = 1600batch_number = 16repeat_number = 1data_train = enhance_data(data_number, batch_number, repeat_number)构建拟合模型并初始化参数用mindspore.nn.Dense的方法我们可以构造一个线性拟合的模型:f(x)=wx+bmindspore.nn.Dense的官方文档说明如下定义:(可以在MindSpore查看相关文档说明)​​​​class LinearNet(nn.Cell): def __init__(self): super(LinearNet, self).__init__() self.fc = nn.Dense(1, 1, Normal(0.02), Normal(0.02)) def construct(self, x):# 必须要有这个函数,MindSpore 对 construct 接口有一定约束 x = self.fc(x) return xnet = LinearNet()model_params = net.trainable_params()for param in model_params:#查看初始化的参数 print(param, param.asnumpy())训练模型首先定义损失函数(Loss Function)来衡量拟合结果的好坏,在这里我们采取均方误差函数MSE定义好损失函数后我们需要定义一个向前传播的网络,用于执行损失函数的计算,这里采用mindspore定义好的接口mindspore.nn.loss.MSELoss​​​​在计算好对应参数的损失函数值后,我们需要更新迭代参数来计算下一组参数的损失值,以判断下一步往哪个方向“前进”来找到最终的最低损失函数值;这一功能将用反向传播网络来实现。参数更新迭代我们这里采用Momentum方法,使用mindspore定义好的接口mindspore.nn.Momentum​​​​定义好后,我们可以使用mindspore.Model来进行封装训练定义训练模型:net_loss = nn.loss.MSELoss()opt = nn.Momentum(net.trainable_params(), learning_rate=0.005, momentum=0.9)model = Model(net, net_loss, opt)训练结果最后训练出来的结果:y=4.979354x+3.0504797 和预期y=5x+3比较接近​​
  • [技术干货] 使用DQN算法玩“2048”游戏
    实验目标通过本案例的学习和课后作业的练习:了解DQN算法的基本概念了解如何基于DQN训练一个小游戏了解强化学习训练推理游戏的整体流程你也可以将本案例相关的 ipynb 学习笔记分享到 AI Gallery Notebook 版块获得成长值,分享方法请查看此文档。案例内容介绍《2048》是一款单人在线和移动端游戏,由19岁的意大利人Gabriele Cirulli于2014年3月开发。游戏任务是在一个网格上滑动小方块来进行组合,直到形成一个带有有数字2048的方块。该游戏可以上下左右移动方块。如果两个带有相同数字的方块在移动中碰撞,则它们会合并为一个方块,且所带数字变为两者之和。每次移动时,会有一个值为2或者4的新方块出现,所出现的数字都是2的幂。当值为2048的方块出现时,游戏即胜利,该游戏因此得名。(源自维基百科) DQN是强化学习的经典算法之一,最早由DeepMind于2013年发表的论文“Playing Atari with Deep Reinforcement Learning”中提出,属于value based的model free方法,在多种游戏环境中表现稳定且良好。 在本案例中,我们将展示如何基于simple dqn算法,训练一个2048的小游戏。整体流程:安装基础依赖->创建2048环境->构建DQN算法->训练->推理->可视化效果DQN算法的基本结构Deep Q-learning(DQN)是Q-learing和神经网络的结合,利用经验回放来进行强化学习的训练,结构如下:神经网络部分神经网络用来逼近值函数,一般采用全连接层表达特征输入,采用卷积层表达图像输入。其损失函数表达为γ经验折扣率,γ取0,表示只考虑当下,γ取1,表示只考虑未来。经验回放经验回放是指:模型与环境交互得到的(s,a,r,s')会存入一个replay buffer,然后每次从中随机采样出一批样本进行学习。采用该策略的优点如下:减少样本之间的相关性,以近似符合独立同分布的假设;同时增大样本的利用率。探索策略一般采用贪婪探索策略,即agent以ε的概率进行随机探索,其他时间则采取模型计算得到的动作。DQN的整体结构可以简单的表示为:​DQN论文Nature DQN论文Nature DQN在DQN的基础上,采用两个结构一样的网络,一个当前Q网络用来选择动作,更新模型参数,另一个目标Q网络用于计算目标Q值。这样可以减少目标Q值和当前的Q值相关性。2048游戏环境简介2048环境来源于GitHub开源项目,继承于gym基本环境类。玩家可以上下左右移动方块,如果方块数字相同,则合并且所带数字变成两者之和。当值为2048的方块出现时,则获得胜利。结束标志只要出现非法移动,即移动的方向的数字无法合并,则该局结束。相比较于传统的可试验多次更加严格,难度提高。奖励函数奖励值为当前方块和累加最大合成数字最大能合成4096注意事项本案例运行环境为 Pytorch-1.0.0,支持 GPU和CPU 运行,请查看《ModelAtrs JupyterLab 硬件规格使用指南》了解切换硬件规格的方法;如果您是第一次使用 JupyterLab,请查看《ModelAtrs JupyterLab使用指导》了解使用方法;如果您在使用 JupyterLab 过程中碰到报错,请参考《ModelAtrs JupyterLab常见问题解决办法》尝试解决问题。实验步骤1. 程序初始化第1步:安装基础依赖!pip install gym第2步:导入相关的库import sysimport timeimport loggingimport argparseimport itertoolsfrom six import StringIOfrom random import sample, randintimport gymfrom gym import spacesfrom gym.utils import seedingimport numpy as npimport torchimport torch.nn as nnfrom PIL import Image, ImageDraw, ImageFontfrom IPython import displayimport matplotlibimport matplotlib.pyplot as plt2. 训练参数初始化¶本案例设置的 epochs = 3000,可以达到较好的训练效果,GPU下训练耗时约10分钟。CPU下训练较慢,建议调小 epochs 的值,如50,以便快速跑通代码。parser = argparse.ArgumentParser()parser.add_argument("--learning_rate", type=float, default=0.001) # 学习率parser.add_argument("--gamma", type=float, default=0.99) # 经验折扣率parser.add_argument("--epochs", type=int, default=50) # 迭代多少局数parser.add_argument("--buffer_size", type=int, default=10000) # replaybuffer大小parser.add_argument("--batch_size", type=int, default=128) # batchsize大小parser.add_argument("--pre_train_model", type=str, default=None) # 是否加载预训练模型parser.add_argument("--use_nature_dqn", type=bool, default=True) # 是否采用nature dqnparser.add_argument("--target_update_freq", type=int, default=250) # 如果采用nature dqn,target模型更新频率parser.add_argument("--epsilon", type=float, default=0.9) # 探索epsilon取值args, _ = parser.parse_known_args()3. 创建环境2048游戏环境继承于gym.Env,主要几个部分:init函数 定义动作空间、状态空间和游戏基本设置step函数 与环境交互,获取动作并执行,返回状态、奖励、是否结束和补充信息reset函数 一局结束后,重置环境render函数 绘图,可视化环境def pairwise(iterable): "s -> (s0,s1), (s1,s2), (s2, s3), ..." a, b = itertools.tee(iterable) next(b, None) return zip(a, b)class IllegalMove(Exception): passdef stack(flat, layers=16): """Convert an [4, 4] representation into [4, 4, layers] with one layers for each value.""" # representation is what each layer represents representation = 2 ** (np.arange(layers, dtype=int) + 1) # layered is the flat board repeated layers times layered = np.repeat(flat[:, :, np.newaxis], layers, axis=-1) # Now set the values in the board to 1 or zero depending whether they match representation. # Representation is broadcast across a number of axes layered = np.where(layered == representation, 1, 0) return layeredclass Game2048Env(gym.Env): metadata = {'render.modes': ['ansi', 'human', 'rgb_array']} def __init__(self): # Definitions for game. Board must be square. self.size = 4 self.w = self.size self.h = self.size self.squares = self.size * self.size # Maintain own idea of game score, separate from rewards self.score = 0 # Members for gym implementation self.action_space = spaces.Discrete(4) # Suppose that the maximum tile is as if you have powers of 2 across the board. layers = self.squares self.observation_space = spaces.Box(0, 1, (self.w, self.h, layers), dtype=np.int) self.set_illegal_move_reward(-100) self.set_max_tile(None) # Size of square for rendering self.grid_size = 70 # Initialise seed self.seed() # Reset ready for a game self.reset() def seed(self, seed=None): self.np_random, seed = seeding.np_random(seed) return [seed] def set_illegal_move_reward(self, reward): """Define the reward/penalty for performing an illegal move. Also need to update the reward range for this.""" # Guess that the maximum reward is also 2**squares though you'll probably never get that. # (assume that illegal move reward is the lowest value that can be returned self.illegal_move_reward = reward self.reward_range = (self.illegal_move_reward, float(2 ** self.squares)) def set_max_tile(self, max_tile): """Define the maximum tile that will end the game (e.g. 2048). None means no limit. This does not affect the state returned.""" assert max_tile is None or isinstance(max_tile, int) self.max_tile = max_tile # Implement gym interface def step(self, action): """Perform one step of the game. This involves moving and adding a new tile.""" logging.debug("Action {}".format(action)) score = 0 done = None info = { 'illegal_move': False, } try: score = float(self.move(action)) self.score += score assert score <= 2 ** (self.w * self.h) self.add_tile() done = self.isend() reward = float(score) except IllegalMove: logging.debug("Illegal move") info['illegal_move'] = True done = True reward = self.illegal_move_reward # print("Am I done? {}".format(done)) info['highest'] = self.highest() # Return observation (board state), reward, done and info dict return stack(self.Matrix), reward, done, info def reset(self): self.Matrix = np.zeros((self.h, self.w), np.int) self.score = 0 logging.debug("Adding tiles") self.add_tile() self.add_tile() return stack(self.Matrix) def render(self, mode='human'): if mode == 'rgb_array': black = (0, 0, 0) grey = (200, 200, 200) white = (255, 255, 255) tile_colour_map = { 2: (255, 255, 255), 4: (255, 248, 220), 8: (255, 222, 173), 16: (244, 164, 96), 32: (205, 92, 92), 64: (240, 255, 255), 128: (240, 255, 240), 256: (193, 255, 193), 512: (154, 255, 154), 1024: (84, 139, 84), 2048: (139, 69, 19), 4096: (178, 34, 34), } grid_size = self.grid_size # Render with Pillow pil_board = Image.new("RGB", (grid_size * 4, grid_size * 4)) draw = ImageDraw.Draw(pil_board) draw.rectangle([0, 0, 4 * grid_size, 4 * grid_size], grey) fnt = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf', 30) for y in range(4): for x in range(4): o = self.get(y, x) if o: draw.rectangle([x * grid_size, y * grid_size, (x + 1) * grid_size, (y + 1) * grid_size], tile_colour_map[o]) (text_x_size, text_y_size) = draw.textsize(str(o), font=fnt) draw.text((x * grid_size + (grid_size - text_x_size) // 2, y * grid_size + (grid_size - text_y_size) // 2), str(o), font=fnt, fill=black) assert text_x_size < grid_size assert text_y_size < grid_size return np.asarray(pil_board) outfile = StringIO() if mode == 'ansi' else sys.stdout s = 'Score: {}\n'.format(self.score) s += 'Highest: {}\n'.format(self.highest()) npa = np.array(self.Matrix) grid = npa.reshape((self.size, self.size)) s += "{}\n".format(grid) outfile.write(s) return outfile # Implement 2048 game def add_tile(self): """Add a tile, probably a 2 but maybe a 4""" possible_tiles = np.array([2, 4]) tile_probabilities = np.array([0.9, 0.1]) val = self.np_random.choice(possible_tiles, 1, p=tile_probabilities)[0] empties = self.empties() assert empties.shape[0] empty_idx = self.np_random.choice(empties.shape[0]) empty = empties[empty_idx] logging.debug("Adding %s at %s", val, (empty[0], empty[1])) self.set(empty[0], empty[1], val) def get(self, x, y): """Return the value of one square.""" return self.Matrix[x, y] def set(self, x, y, val): """Set the value of one square.""" self.Matrix[x, y] = val def empties(self): """Return a 2d numpy array with the location of empty squares.""" return np.argwhere(self.Matrix == 0) def highest(self): """Report the highest tile on the board.""" return np.max(self.Matrix) def move(self, direction, trial=False): """Perform one move of the game. Shift things to one side then, combine. directions 0, 1, 2, 3 are up, right, down, left. Returns the score that [would have] got.""" if not trial: if direction == 0: logging.debug("Up") elif direction == 1: logging.debug("Right") elif direction == 2: logging.debug("Down") elif direction == 3: logging.debug("Left") changed = False move_score = 0 dir_div_two = int(direction / 2) dir_mod_two = int(direction % 2) shift_direction = dir_mod_two ^ dir_div_two # 0 for towards up left, 1 for towards bottom right # Construct a range for extracting row/column into a list rx = list(range(self.w)) ry = list(range(self.h)) if dir_mod_two == 0: # Up or down, split into columns for y in range(self.h): old = [self.get(x, y) for x in rx] (new, ms) = self.shift(old, shift_direction) move_score += ms if old != new: changed = True if not trial: for x in rx: self.set(x, y, new[x]) else: # Left or right, split into rows for x in range(self.w): old = [self.get(x, y) for y in ry] (new, ms) = self.shift(old, shift_direction) move_score += ms if old != new: changed = True if not trial: for y in ry: self.set(x, y, new[y]) if changed != True: raise IllegalMove return move_score def combine(self, shifted_row): """Combine same tiles when moving to one side. This function always shifts towards the left. Also count the score of combined tiles.""" move_score = 0 combined_row = [0] * self.size skip = False output_index = 0 for p in pairwise(shifted_row): if skip: skip = False continue combined_row[output_index] = p[0] if p[0] == p[1]: combined_row[output_index] += p[1] move_score += p[0] + p[1] # Skip the next thing in the list. skip = True output_index += 1 if shifted_row and not skip: combined_row[output_index] = shifted_row[-1] return (combined_row, move_score) def shift(self, row, direction): """Shift one row left (direction == 0) or right (direction == 1), combining if required.""" length = len(row) assert length == self.size assert direction == 0 or direction == 1 # Shift all non-zero digits up shifted_row = [i for i in row if i != 0] # Reverse list to handle shifting to the right if direction: shifted_row.reverse() (combined_row, move_score) = self.combine(shifted_row) # Reverse list to handle shifting to the right if direction: combined_row.reverse() assert len(combined_row) == self.size return (combined_row, move_score) def isend(self): """Has the game ended. Game ends if there is a tile equal to the limit or there are no legal moves. If there are empty spaces then there must be legal moves.""" if self.max_tile is not None and self.highest() == self.max_tile: return True for direction in range(4): try: self.move(direction, trial=True) # Not the end if we can do any move return False except IllegalMove: pass return True def get_board(self): """Retrieve the whole board, useful for testing.""" return self.Matrix def set_board(self, new_board): """Retrieve the whole board, useful for testing.""" self.Matrix = new_board4. 定义DQN算法DQN算法分了两部分构造,拟合函数部分-神经网络算法逻辑本身Replay Buffer部分神经网络结构包含三层卷积网络和一层全连接网络,输出维度为动作空间维度。 神经网络部分可自由设计,以训练出更好的效果。class Net(nn.Module): #obs是状态空间输入,available_actions_count为动作输出维度 def __init__(self, obs, available_actions_count): super(Net, self).__init__() self.conv1 = nn.Conv2d(obs, 128, kernel_size=2, stride=1) self.conv2 = nn.Conv2d(128, 64, kernel_size=2, stride=1) self.conv3 = nn.Conv2d(64, 16, kernel_size=2, stride=1) self.fc1 = nn.Linear(16, available_actions_count) self.relu = nn.ReLU(inplace=True) def forward(self, x): x = x.permute(0, 3, 1, 2) x = self.relu(self.conv1(x)) x = self.relu(self.conv2(x)) x = self.relu(self.conv3(x)) x = self.fc1(x.view(x.shape[0], -1)) return xDQN核心逻辑部分class DQN: def __init__(self, args, obs_dim, action_dim): # 是否加载预训练模型 if args.pre_train_model: print("Loading model from: ", args.pre_train_model) self.behaviour_model = torch.load(args.pre_train_model).to(device) # 如果采用Nature DQN,则需要额外定义target_network self.target_model = torch.load(args.pre_train_model).to(device) else: self.behaviour_model = Net(obs_dim, action_dim).to(device) self.target_model = Net(obs_dim, action_dim).to(device) self.optimizer = torch.optim.Adam(self.behaviour_model.parameters(), args.learning_rate) self.criterion = nn.MSELoss() # 动作维度 self.action_dim = action_dim # 统计学习步数 self.learn_step_counter = 0 self.args = args def learn(self, buffer): # 当replaybuffer中存储的数据大于batchsize时,从中随机采样一个batch的数据学习 if buffer.size >= self.args.batch_size: # 更新target_model的参数 if self.learn_step_counter % args.target_update_freq == 0: self.target_model.load_state_dict(self.behaviour_model.state_dict()) self.learn_step_counter += 1 # 从replaybuffer中随机采样一个五元组(当前观测值,动作,下一个观测值,是否一局结束,奖励值) s1, a, s2, done, r = buffer.get_sample(self.args.batch_size) s1 = torch.FloatTensor(s1).to(device) s2 = torch.FloatTensor(s2).to(device) r = torch.FloatTensor(r).to(device) a = torch.LongTensor(a).to(device) if args.use_nature_dqn: q = self.target_model(s2).detach() else: q = self.behaviour_model(s2) # 每个动作的q值=r+gamma*(1-0或1)*q_max target_q = r + torch.FloatTensor(args.gamma * (1 - done)).to(device) * q.max(1)[0] target_q = target_q.view(args.batch_size, 1) eval_q = self.behaviour_model(s1).gather(1, torch.reshape(a, shape=(a.size()[0], -1))) # 计算损失函数 loss = self.criterion(eval_q, target_q) self.optimizer.zero_grad() loss.backward() self.optimizer.step() def get_action(self, state, explore=True): # 判断是否探索,如果探索,则采用贪婪探索策略决定行为 if explore: if np.random.uniform() >= args.epsilon: action = randint(0, self.action_dim - 1) else: # Choose the best action according to the network. q = self.behaviour_model(torch.FloatTensor(state).to(device)) m, index = torch.max(q, 1) action = index.data.cpu().numpy()[0] else: q = self.behaviour_model(torch.FloatTensor(state).to(device)) m, index = torch.max(q, 1) action = index.data.cpu().numpy()[0] return actionreplay buffer数据存储部分class ReplayBuffer: def __init__(self, buffer_size, obs_space): self.s1 = np.zeros(obs_space, dtype=np.float32) self.s2 = np.zeros(obs_space, dtype=np.float32) self.a = np.zeros(buffer_size, dtype=np.int32) self.r = np.zeros(buffer_size, dtype=np.float32) self.done = np.zeros(buffer_size, dtype=np.float32) # replaybuffer大小 self.buffer_size = buffer_size self.size = 0 self.pos = 0 # 不断将数据存储入buffer def add_transition(self, s1, action, s2, done, reward): self.s1[self.pos] = s1 self.a[self.pos] = action if not done: self.s2[self.pos] = s2 self.done[self.pos] = done self.r[self.pos] = reward self.pos = (self.pos + 1) % self.buffer_size self.size = min(self.size + 1, self.buffer_size) # 随机采样一个batchsize def get_sample(self, sample_size): i = sample(range(0, self.size), sample_size) return self.s1[i], self.a[i], self.s2[i], self.done[i], self.r[i]5. 训练模型初始化环境和算法# 初始化环境env = Game2048Env()device = torch.device("cuda" if torch.cuda.is_available() else "cpu")# 初始化dqndqn = DQN(args, obs_dim=env.observation_space.shape[2], action_dim=env.action_space.n)# 初始化replay buffermemory = ReplayBuffer(buffer_size=args.buffer_size, obs_space=(args.buffer_size, env.observation_space.shape[0], env.observation_space.shape[1], env.observation_space.shape[2]))开始训练print('\ntraining...')begin_t = time.time()max_reward = 0for i_episode in range(args.epochs): # 每局开始,重置环境 s = env.reset() # 累计奖励值 ep_r = 0 while True: # 计算动作 a = dqn.get_action(np.expand_dims(s, axis=0)) # 执行动作 s_, r, done, info = env.step(a) # 存储信息 memory.add_transition(s, a, s_, done, r) ep_r += r # 学习优化过程 dqn.learn(memory) if done: print('Ep: ', i_episode, '| Ep_r: ', round(ep_r, 2)) if ep_r > max_reward: max_reward = ep_r print("current_max_reward {}".format(max_reward)) # 保存模型 torch.save(dqn.behaviour_model, "2048.pt") break s = s_print("finish! time cost is {}s".format(time.time() - begin_t))6. 使用模型推理游戏¶#加载模型model = torch.load("2048.pt").to(device)model.eval()s = env.reset()img = plt.imshow(env.render(mode='rgb_array'))while True: plt.axis("off") img.set_data(env.render(mode='rgb_array')) display.display(plt.gcf()) display.clear_output(wait=True) s = torch.FloatTensor(np.expand_dims(s, axis=0)).to(device) a = torch.argmax(model(s), dim=1).cpu().numpy()[0] # take action s_, r, done, info = env.step(a) time.sleep(0.1) if done: break s = s_env.close()plt.close()7. 作业请你调整步骤2中的训练参数,重新训练一个模型,使它在游戏中获得更好的表现。
  • [执行问题] 为什么Mindspore.numpy不支持tensor转换
    如图我想把numpy创建的变量转换成Tensor但是报错如图
  • [其他问题] RuntimeError: For 'Conv2D', 'C_in' of input 'x' shape divide by parameter 'group' must be equal to 'C_in' of input 'weig
    运行报错:RuntimeError: For 'Conv2D', 'C_in' of input 'x' shape divide by parameter 'group' must be equal to 'C_in' of input 'weight' shape: 3, but got 'C_in' of input 'x' shape: 224, and 'group': 1.使用的卷积层:输入的图片shape为:对应的输入维度就是3,为什么还是报错是224呢?
  • [技术干货] 基于PCA的人脸识别
    PCA(主成分分析)PCA(Principal Component Analysis,主成分分析)是一种常用的数据分析方法。PCA通过线性变换将原始数据变换为一组各维度线性无关的表示,可用于提取数据的主要特征分量,常用于高维数据的降维。PCA已在人脸识别和图像压缩等领域得到了广泛应用。PCA相关的数学概念•标准差公式为为标准差 在概率统计中最常使用作为统计分布程度上的测量。标准差定义是总体各单位标准值与其平均数离差平方的算术平均数的平方根。它反映组内个体间的离散程度。•标准差在Matlab中的计算如下:•定义一个3*3的矩阵如下•std(a)求矩阵标准差,std(a,0,1)求矩阵列的标准差。Std(a,0,2)求矩阵行的标准差,如果是求整个矩阵的标准差使用std2(a)函数•方差公式为方差是在概率论和统计方差衡量随机变量或一组数据时离散程度的度量。•方差在Matlab中的使用方法如下•V=var(X,flag,dim)•参数解释如下:•X为矩阵或者向量;•flag为权值,当flag等于0时:前置因子是1/(n-1),当flag等于0时:前置因子是1/(n),默认是0;•dim为维数,当dim=1时,表示计算列,当dim=2时,表示计算行,下图为计算行和列的方差的结果。•Matlab中没有直接计算矩阵方差的函数,可以先求得标准差再平方得到•协方差计算公式为协方差在概率论和统计学中用于衡量两个变量的总体误差。而方差是协方差的一种特殊情况,即当两个变量是相同的情况。•协方差矩阵:在统计学与概率论中,协方差矩阵的每个元素是各个向量元素之间的协方差,是从标量随机变量到高维度随机向量的自然推广。•举个例子,我们将为一个假想的三维数据集建立协方差矩阵,实用3个维度,协方差矩阵将有3行3列如下所示:先初始化两个矩阵a,b•其中,对角线的值是两个向量的方差,斜对角线的是两个向量之间的协方差PCA算法的步骤•设有m条n维数据。•1)将原始数据按列组成n行m列矩阵X•2)将X的每一行(代表一个属性字段)进行零均值化,即减去这一行的均值•3)求出协方差矩阵•4)求出协方差矩阵的特征值及对应的特征向量•5)将特征向量按对应特征值大小从上到下按行排列成矩阵,取前k行组成矩阵P•6)Y=PX即为降维到k维后的数据•使用PCA的方法将二维数组降到一维•初始化矩阵a,如下图•数组a的每行都已经是零均值,求协方差矩阵如下•再求其特征值和特征向量,如下图即特征值为特征向量为我们所求的P矩阵为•最后我们用P的第一行乘以数据矩阵,就得到了降维后的表示:Y即为最终结果人脸识别的实现•1. 准备一个训练集的人脸图像。本实验选取剑桥大学ORL人脸数据库。一共40个不同的人,每人10张人脸图像,随机选取7张用作训练(取平均后作为一张脸),图像分辨率为112*92.•2. 将原始图像的每一行的像素串联在一起,产生一个具有112*92个元素的列向量,每个图像被视为一个向量。然后,使所有的训练集的图像(一共40张)存储在一个单一的矩阵T中,矩阵的每一列是一个图像。•3. 减去均值向量. 均值向量a要首先计算,并且T中的每一个图像都要减掉均值向量。•4. 计算协方差矩阵S的特征值和特征向量。每一个特征向量的维数与原始图像的一致,因此可以被看作是一个图像。因此这些向量被称作特征脸。•5. 选择主成分。一般选择最大的k个特征值,保留对应的特征向量。6. 对每个训练图像的向量,投影到特征空间后得到一组坐标。对测试图像,也作同样的投影运算,得到坐标,与训练图像的坐标进行二范数最小匹配原始图像灰度图像在计算机中的存储形式为a*b*3的矩阵特征脸及生成特征脸的主要代码得到结果(横坐标为特征维数,纵坐标为准确率)
  • [技术干货] 机器学习真能产生智能决策吗?-转载
     历经三年时间,我们在2022年完成了图灵奖获得者、加州大学洛杉矶分校计算机科学教授,美国国家科学院院士,被誉为“贝叶斯网络之父”的朱迪亚·珀尔大作《因果论:模型、推理和推断》。  这本书原版的第1版写于2000年,开创了因果分析和推断的新思想和新方法,一出版就得到广泛的好评,促进了数据科学、人工智能、机器学习、因果分析等领域新的革命,在学术界产生了很大的影响。  后来又于2009年修订出了第2版,内容上结合当时因果研究的新发展,做了较大的改动。目前我们翻译的这本书英文原版是在2009年出版的,到目前已经有十多年了。  该书中文版的出版有利于广大中国学者、学生和各领域的实践人员了解和掌握因果模型、推理和推断相关的内容。特别是在当前统计学和机器学习流行的时代,如何实现从“数据拟合”到“数据理解”的转变?如何在下一个十年里,从“所有知识都来自数据本身”这一目前占据主流的假设到一个全新的机器学习范式?是否会引发“第二次人工智能革命”?  正如图灵奖授予珀尔时评价他的工作为“人工智能领域的基础性贡献,他提出概率和因果性推理演算法,彻底改变了人工智能最初基于规则和逻辑的方向。” 我们期待这种范式能够为机器学习带来新的技术方向和前进动力,并且最终能够在实际应用中发挥作用。  正如珀尔所说“数据拟合目前牢牢地统治着当前的统计学和机器学习领域,是当今大多数机器学习研究者的主要研究范式,尤其是那些从事连接主义、深度学习和神经网络技术的研究者。” 这种以“数据拟合”为核心的范式在计算机视觉、语音识别和自动驾驶等应用领域取得了令人瞩目的成功。但是,许多数据科学领域的研究人员也已经意识到,从当前实践效果来看,机器学习无法产生智能决策所需的那种理解能力。这些问题包括:稳健性、可迁移性、可解释性等。下面我们来看看例子。   数据统计靠谱吗?  近年来自媒体上的很多人都会觉得自己是统计学家。因为“数据拟合”“所有知识都来自数据本身”为许多重大决策提供了数据统计依据。但是,在进行分析时,我们需要谨慎分析。毕竟,事情可能并不总是乍看之下!一个与我们生活息息相关的案例。10年前,某城市市中心的房价是8000元/平米,共销售了1000万平;高新区是4000元/平米,共销售了100万平;整体来看,该市的平均房价为7636元/平米。现在,市中心10000元/平米,但由于市中心的土地供应少了,只销售了200万平;高新区是6000元/平米,但由于新开发的土地变多了,销售了2000万平;整体来看,现在该市的平均房价为6363元/平米。因此,分区来看房价分别都涨了,但从整体上看,会有产生疑惑:为什么现在的房价反而跌了呢?   图1 房价趋势按照不同区域划分后与总体结论相悖  我们知道这种现象叫作辛普森悖论。这些案例清楚地表明当我们没有给予足够的观察变量时,我们是如何从统计数据中得到了完全错误的模型和结论。就这次新冠大流行而言,我们通常会获得全国范围的统计数据。如果我们按地区或市县进行分组,我们可能会得出截然不同的结论。在全国范围内,我们可以观察到新冠病例数量在下降,尽管某些地区的病例数量会有所增加(这可能预示着下一波浪潮的开始)。如果存在差异很大的群体,例如人口差异很大的地区,则也可能会发生这种情况。在国家数据中,人口密度较低地区的病例激增可能与人口稠密地区的病例下降相形见绌。  类似的基于“数据拟合”的统计问题比比皆是。比如下面两个有趣的例子。  如果我们每年收集尼古拉斯·凯奇每年出演的电影数量和美国溺死人数的数据,我们会发现这两个变量高度相关,数据拟合程度奇高。   图2 尼古拉斯·凯奇每年出演的电影数与美国溺死的人数  如果我们收集每个国家人均牛奶销售量和获得诺贝尔奖人数的数据,我们会发现这两个变量高度相关。   图3 人均牛奶消费量与诺贝尔奖人数  从我们人类的常识认知来说,这些都是伪相关,甚至是悖论。但从数学和概率论的角度来看,表现出伪相关或者悖论的案例无论从数据上还是计算上都是没有问题的。如果有一些因果基础的人都知道,发生这种情况是因为数据中隐藏着所谓的潜伏变量,即未被观察到的混杂因子。   图4 独立变量导致了两个变量之间伪相关  珀尔在《因果论》中给出了解决的范式,详细分析和推导了以上问题,强调了因果与统计之间有着本质的区别,虽然因果分析与推断仍然是建立在统计学的语境上。珀尔提出了干预操作(算子)的基本计算模式,包括后门原则和具体的计算公式,这是当前对于因果关系最为数学化的描述。“因果以及相关的概念(例如随机化、混杂、干预等)不是统计概念”,这是贯穿珀尔因果分析思想的一条基本原理,珀尔称之为第一原理[2]。  那么,目前基于数据驱动的机器学习方法,特别是那些严重依赖于统计学方法的算法,学习到的模型极大可能也会出现半真半假、误导性或者反转性的结果。这是因为这些模型往往是基于观察数据的分布情况进行学习,而非数据生成的机制。   机器学习亟需解决的三个问题  稳健性:随着深度学习方法的流行,计算机视觉、自然语言处理和语音识别等研究大量利用了最先进的深层神经网络结构。但仍然长期存在这样一个事实问题,即在现实世界中,我们采集到数据的分布通常很少是完整的,与实际世界中的分布可能不一致。在计算机视觉应用中,训练集与测试集数据分布可能受到来自诸如像素差、压缩质量,或来自于摄像机位移、旋转或角度等的影响。这些变量其实就是因果概念中的“干预”问题。由此,人们提出了简单的算法来模拟干预,以专门测试分类和识别模型的泛化能力,如空间偏移、模糊、亮度或对比度的变化、背景控制和旋转,以及在多种环境中采集的图像等。到目前为止,尽管我们利用数据增强、预训练、自监督学习等方法在稳健性上取得了一定的进展,但对于如何解决这些问题还没有明确的共识。有人认为这些修正可能是不够的,在独立同分布假设之外进行泛化不仅需要学习变量之间的统计关联,还需要学习潜在的因果模型,以明确数据生成的机制,并允许通过干预概念模拟分布变化。   可迁移性:婴儿对物体的理解基于跟踪随时间变化表现一致的物体,这样的方法可以让婴儿快速学习新的任务,因为他们对物体的知识和直观理解可以重复使用。类似地,能够高效地解决现实世界中的任务需要在新的场景中重用学习到的知识技能。研究已经证明,学习了环境知识的机器学习系统效率更高,通用性更好。如果我们将现实世界模型化,许多模块在不同的任务和环境中表现出相似的行为。因此,面对新环境或新任务,人类或者机器可能只需要调整其内部表示中的几个模块。当学习因果模型时,由于大多数知识(即模块)可以在无须进一步训练的情况下重复使用,从而只需要较少的样本以适应新环境或新任务。  可解释性:可解释性是一个微妙的概念,不能仅仅使用布尔逻辑或统计概率的语言完全描述,它需要额外的干预概念,甚至是反事实的概念。因果关系中的可操纵性定义关注的是这样一个事实,即条件概率(“看到人们打开雨伞表明正在下雨”)无法可靠地预测主动干预的结果(“收起雨伞并不能阻止下雨”)。因果关系被视为推理链的组成部分,它可以为与观察到的分布相去甚远的情况提供预测,甚至可以为纯粹假设的场景提供结论。从这个意义上说,发现因果关系意味着获得可靠的知识,这些知识不受观察到的数据分布和训练任务的限制,从而为可解释的学习提供明确的说明。   因果学习建模的三个层次  具体地说,基于统计模型的机器学习模型只能对相关关系进行建模,而相关关系往往会随着数据分布的变化而变化;而因果模型基于因果关系建模,则抓住了数据生成的本质,反映了数据生成机制的关系,这样的关系更加稳健,具有分布外泛化的能力。比如,在决策理论中,因果关系和统计之间的区别更加清楚。决策理论中有两类问题,一类是已知当前环境,拟采取干预,预测结果。另一类是已知当前环境和结果,反推原因。前者称为求果问题,后者称为溯因问题[3]。  在独立同分布条件下的预测能力  统计模型只是对观察到的现实世界的粗浅描述,因为它们只关注相关关系。对于样本和标签,我们可以通过估计来回答这样的问题:“这张特定的照片中有一只狗的概率是多少?”“已知一些症状,心力衰竭的概率是多少?”。这样的问题是可以通过观察足够多的由所生成的独立同分布数据来回答的。尽管机器学习算法可以把这些事做得很好,但是准确的预测结果对于我们的决策是不够,而因果学习为其提供了一种有益的补充。就前面的例子来说,尼古拉斯·凯奇出演电影的频率和美国溺亡率正相关,我们的确可以训练一个统计学习模型通过尼古拉斯·凯奇出演电影的频率来预测美国溺亡率,但显然这两者并没有什么直接的因果关系。统计模型只有在独立同分布的情况下才是准确的,如果我们做任何的干预来改变数据分布,就会导致统计学习模型出错。  在分布偏移/干预下的预测能力  我们进一步讨论干预问题,它更具挑战性,因为干预(操作)会使我们跳出统计学习中独立同分布的假设。继续用尼古拉斯·凯奇的例子,“今年增加邀请尼古拉斯·凯奇出演电影的数量会增加美国的溺亡率吗?”就是一个干预问题。显然,人为的干预会使得数据分布发生变化,统计学习赖以生存的条件就会被打破,所以它会失效。另一方面,如果我们可以在存在干预的情况下学习一个预测模型,那么这有可能让我们得到一个在现实环境中对分布变化更加稳健的模型。实际上,这里所谓的干预并不是什么新鲜事,很多事情本身就是随时间变化的,例如人的兴趣偏好,或者模型的训练集与测试集本身在分布上就存在不匹配的现象。我们前面已经提到,神经网络的稳健性已经获得了越来越多的关注,成为一个与因果推断紧密连接的研究话题。在分布偏移的情况下预测不能只局限于在测试集上取得高准确率,如果我们希望在实际应用中使用机器学习算法,那么我们必须相信在环境条件改变的情况下,模型的预测结果也是准确的。实际应用中的分布偏移类别可能多种多样,一个模型仅仅在某些测试集上取得好效果,不能代表我们可以在任何情况下都能够信任这个模型,这些测试集可能只是恰好符合这些测试集样本的分布。为了让我们可以在尽可能多的情况下信任预测模型,就必须采用具有回答干预问题能力的模型,至少仅仅使用统计学习模型是不行的。  回答反事实问题的能力  反事实问题涉及推理事情为什么会发生,想象实施不同行为所带来的后果,并由此可以决定采取何种行为来达到期望的结果。回答反事实问题比干预更加困难,但也是对于AI非常关键的挑战。如果一个干预问题是“如果我们现在让一个病人有规律地进行锻炼,那么他心力衰竭的概率会如何变化?”,对应的反事实问题就是“如果这个已经发生心力衰竭的病人一年前就开始锻炼,那他还会得心力衰竭吗?”显然回答这样的反事实问题对于强化学习是很重要的,它们可以通过反思自己的决策,制定反事实假说,再通过实践验证,就像我们的科学研究一样。   因果学习应用  最后,我们来看看如何在各个领域上应用因果学习。2021年诺贝尔经济学奖授予了约书亚·安格里斯特(Joshua D.Angrist)和吉多·因本斯(Guido W.Imbens),表彰“他们对因果关系分析的方法论”贡献。他们研究了因果推断在实证劳动经济学中的应用。诺贝尔经济学奖评选委员认为“自然实验(随机试验或者对照试验)有助于回答重要问题”,但如何“使用观测数据回答因果关系”更具有挑战性。经济学中的重要问题是因果关系问题。如移民如何影响当地人的劳动力市场前景?读研究生能够影响收入增加吗?最低工资对技术工人的就业前景有何影响?这些问题很难回答,因为我们缺乏正确的反事实解释方法。  自从20世纪70年代以来,统计学家就发明了一套计算“反事实”的框架,以揭示两个变量之间的因果效应。经济学家又在此基础上进一步发展了断点回归、双重差分、倾向得分等方法,并且大量地应用在各种经济政策问题的因果性研究上。从6世纪的宗教文本到2021年的因果机器学习,包括因果自然语言处理,我们可以使用机器学习、统计学和计量经济学来模拟因果效应。经济和其他社会科学的分析主要围绕因果效应的估计,即一个特征变量对于结果变量的干预效应。实际上,在大多数情况下,我们感兴趣的事情是所谓的干预效应。干预效应是指干预或者治疗对结果变量的因果影响。比如在经济学中,分析最多的干预效应之一是对企业进行补贴对企业收入的因果影响。为此,鲁宾(Rubin)提出了潜在结果框架(potential outcome framework)。  尽管经济学家和其他社会科学家对因果效应的精确估计能力强于预测能力,但他们对机器学习方法的预测优势也十分感兴趣。例如,精确的样本预测能力或处理大量特征的能力。但正如我们所见到的,经典机器学习模型并非旨在估计因果效应,使用机器学习中现成的预测方法会导致对因果效应的估计存在偏差。那么,我们必须改进现有的机器学习技术,以利用机器学习的优势来持续有效地估计因果效应,这就促使了因果机器学习的诞生!  目前,根据要估计的因果效应类型,因果机器学习可以大致分为两个研究方向。一个重要的方向是改进机器学习方法以用于无偏且一致的平均干预效应估计。该研究领域的模型试图回答以下问题:客户对营销活动的平均反应是什么?价格变化对销售额的平均影响是多少?此外,因果机器学习研究的另一条发展路线是侧重于改进机器学习方法以揭示干预效应的特异性,即识别具有大于或小于平均干预效应的个体亚群。这类模型旨在回答以下问题:哪些客户对营销活动的反应最大?价格变化对销售额的影响如何随着顾客年龄的变化而变化?  除了这些活生生的例子,我们还可以感觉到因果机器学习引起数据科学家兴趣的一个更深刻的原因是模型的泛化能力。具备描述数据之间因果关系的机器学习模型可泛化到新的环境中,但这仍然是目前机器学习的最大挑战之一。  珀尔更深层次地分析这些问题,认为如果机器不会因果推理,我们将永远无法获得达到真正人类水平的人工智能,因为因果关系是我们人类处理和理解周围复杂世界的关键机制。珀尔在《因果论》中文版的序中写到“在下一个十年里,这个框架将与现有的机器学习系统相结合,从而可能引发‘第二次因果革命’。我希望这本书也能使中国读者积极参与到这一场即将到来的革命之中。”  参考文献:  [1] 珀尔. 因果论:模型、推理和推断(原书第2版)[M]. 刘礼,等译. 北京:机械工业出版社,2022.  [2] 刘礼,吴飞,李廉. 因果关系学习的思维取向和概念分析[J]. 中国大学教学,2021(10):35-42.  [3] WANG A G, LIU L, YANG J Y, LI L, Causality Fields in Nonlinear Causal Effect Analysis [J]. Frontiers of Information Technology & Electronic Engineering, 2022,23(8):1277-1286.  推荐阅读:  《因果论:模型、推理和推断(原书第2版)》   作者:[美] 朱迪亚·珀尔(Judea Pearl)  译者:刘礼 杨矫云 廖军 李廉  图灵奖获得者、贝叶斯网络奠基人、美国国家科学院院士、结构因果图的创始人朱迪亚·珀尔因果论代表作  第二次因果革命即将到来?因果推断会是下一个AI热潮吗?本书全面阐述了现代因果关系分析,展示了因果关系如何从一个模糊的概念发展成为一套数学理论,并广泛用于统计学、人工智能、经济学、哲学、认知科学、卫生科学和社会学等领域。本书第1版曾获2001年拉卡托斯奖,作者朱迪亚·珀尔是2011年图灵奖得主。本书的出版将有利于中国的广大学者、学生和各领域研究人员了解和掌握因果模型、推理和推断相关的内容,在相关领域做出优异的成果。 ———————————————— 版权声明:本文为CSDN博主「AI科技大本营」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/dQCFKyQDXYm3F8rB0/article/details/127116130 
  • [问题求助] Hello_RPA双击编辑后怎么返回
    Hello_RPA双击编辑后怎么返回
  • [问题求助] studio关闭后出现报错页面
    关闭studio后出现报错页面,但不影响使用,询问出现这个页面有没有什么影响
总条数:4846 到第
上滑加载中