-
实验目标通过本案例的学习和课后作业的练习:了解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中的训练参数,重新训练一个模型,使它在游戏中获得更好的表现。
-
yy,并安踏画面查询nn鞥难手↵很荣幸地能参与到本次华为云手机benchmark工具开发项目中,本次参与的项目主要目的是实现在移动手机终端上对云游戏以及云手机等各个平台的性能和各项基础指标进行测试。测试内容包括有基础硬件信息、流畅性、稳定性、触控体验和音画质量。在本次项目中,我从初期架构设计到中期模块开发再到后期测试以及文档编写等环节都完整地参与了进来,感受到了完整的开发流程,极大地提高了我的开发能力,受益匪浅。在项目初期,先是由华为方面的老师介绍了项目的总体方案与实现分析,然后项目指导老师给团队的每个成员分配大致的模块和具体的任务,让我们很快的明确了自己要学习努力的方向。我初期负责的主要是云手机的流畅性测试模块。起初,我尝试使用Choreographer编舞者的回调函数来实现对云手机播放视频时画面刷新的fps捕捉,但是在测试过程中发现,通过编舞者来监听手机视频播放的fps会出现虚高的情况,播放一个30帧率的测试视频,但是测试结果会出现高于50帧的情况。经过查询资料发现这是因为编舞者Choreographer的回调是基于VSync信号的,而当画面没有发生变化,画面是不需要重新渲染的,但VSync信号总是会发出来,所以Choreographer.FrameCallback在画面没有重新渲染时也会被回调到。随后,尝试使用其他方法,通过结合使用glsurface和mediaplay成功地监听到了播放视频的fps,并以此为基础完成了计算了云手机的流畅性指标计算。最后,非常感谢华为我们提供了这次项目实践的机会,让我们能实际参与一个一线公司项目的完整开发流程。希望我以后能有更多机会参与到类似的项目中,学到更多的知识。重庆邮电大学-数据分析与智能决策创新团队-唐庐指导老师-刘勇老师
-
中奖用户公布 华为云昵称yd_265908769yd_213618615亲爱的用户们,第一期闯关赛活动顺利结束。总回帖数32+,经专家评选,共2位用户获得100元京东券奖励,感谢大家的积极参与。 有一些朋友在第三关闯关答题中出现错误,离成功只差一步,非常可惜。现公布第三关答案,让我们再接再厉! ★ 问题1: 面向设备侧的驱动包,是什么? B. SND ★ 问题2: 做驱动包自定义业务时,业务逻辑应该被写入哪个文件中? A. Python ★ 问题3:GND包分为几部分?分别是什么? C. 2部分,模型包+配置包 请中奖的小伙伴私信版主或微信添加AOC服务体验官进行礼品登记!也请大家期待下次的活动吧~2022年9月7日--2022年10月7日书籍名称:《iMaster NCE AOC 开放可编程平台》在本帖下回帖 ,谈谈阅读感受,书中所讲架构、能力和应用等内容,对您有哪些帮助?观看下方任意一个视频,在任意渠道进行无屏蔽转发分享(包括但不限制于微信朋友圈、微信群、微博、welink群等),保留后在本帖下截图回帖。★ PC端转发:扫描相关二维码打开转发★ 移动端转发:下方链接直接打开转发1开发HillStone防火墙SND包2开发防火墙封禁GND包★ 问题1: 面向设备侧的驱动包,是什么? A. GND, B. SND, C. SSP, D. NCE ★ 问题2: 做驱动包自定义业务时,业务逻辑应该被写入哪个文件中? A. Python, B. Jinja, C. YANG, D. Html ★ 问题3:GND包分为几部分?分别是什么? A. 1部分,模型包,B. 1部分,配置包,C. 2部分,模型包+配置包,D. 3部分,Runbook+模型包+配置包 上述三关通关完成,由iMaster NCE AOC专家评选优秀参与者,每人奖励100元京东E卡。第一关:●留言点评:如网络作为整个社会数字化、智能化的基础支撑,其本身也需要有数字化的运维手段。本书对网络运维数字化转型提供了解决方案,相关技术实现内容详实,可为数据中心网络从业人员提供最佳参考。--袁航,中国银联金融科技研究院高级研究员第二关:● 转发截图:如第三关:●问题一:xxx;●问题二:xxx;●问题三:xxx----------------------------------------------------------------------------------------------重要说明:如有无法上传图片问题,可以将图片大小控制在100k以下尝试,或联系体验官解决。每一关活动可以分开回帖,最后一关完成,回帖时请写上“通关完成”字样。活动解释权归AOC社区所有。请获得京东E卡的用户在1个月内与AOC服务体验官联系(vx:huawei520aoc),进行实名礼品登记发放。
-
在2022年游戏开发者大会上,微软Xbox Game Studios Publishing正式宣布成立了新的“云游戏”部门。根据微软的说法,该部门“将与游戏工作室合作开发云原生游戏,并将它们引入Xbox生态系统”。该部门由去年加入Xbox担任云游戏总监的Kim Swift领导。Kim Swift曾是Valv的《传送门》游戏项目负责人和设计师,之后担任了《求生之路》系列的设计师和艺术家,后担任谷歌Stadia云游戏平台的游戏设计总监。转载于CSDN微信公众号
-
来源标题:暴雪云计算宣布推出基于Filecoin网络的“云游戏”解决方案据MACQUARIE官方消息,深耕分布式存储领域的暴雪云计算正在重点部署为网络视频游戏提供云计算服务的IPFS网络建设。暴雪云计算联合澳大利亚麦格理集团(MACQUARIE), 美国费城大学数据中心,2K Games游戏厂商,中国网络游戏产业联盟及中国通信工业协会数字经济专委会等机构在全球首推基于Filecoin网络的“云游戏”解决方案。该方案由暴雪云计算技术团队经过长期的优化测试后获得的最佳方案。未来暴雪云计算矿工将成为“云游戏”服务商。随着IPFS技术的全球化推进,为低成本高标准实现云游戏商业落地提供了良好的可行性。同时,暴雪云计算coo张磊也表示,未来将联合各大节点数据中心加速布局全球节点,全力推进”云游戏”进程,暴雪云计算也会持续加大这方面的研发投入。云游戏是以云计算为基础的游戏方式,在云游戏的运行模式下,所有游戏都在服务器端运行,并将渲染完毕后的游戏画面压缩后通过网络传送给用户。在客户端,用户的游戏设备不需要任何高端处理器和显卡,只需要基本的视频解压能力就可以了。这意味着游戏玩家可以不用购买昂贵的专业游戏设备和电脑的情况下就可以玩上高品质游戏。在IPFS技术的加持下,云游戏方案得已飞速发展,突破众多技术瓶颈。相信在不就的将来,玩家只需要一台显示器连接网络就可以流程的遨游在网游世界。
-
云游戏是一种以云计算技术为基础的在线游戏方式,具 有免配置、免下载、跨平台、跨终端的特性。 云游戏场景实现对终端限制的突破 对于数量庞大的低端机型用户而言,由于存储空间、内 存配置、手机 CPU 性能等设备条件方面的限制,运行热门游 戏往往存在诸多问题;对于家庭用户而言,主机游戏硬件及 CD-KEY 价格昂贵,而传统 TV 游戏内容相对粗糙,难以提 供优质的游戏体验。云游戏的发展解决了这些痛点,让用户 在云端实现“秒玩”热门手机游戏及主机游戏,真正做到随心 所欲、“即点即玩”、尽情畅享海量游戏大作。 在云游戏场景下,用户的游戏设备只需具备基本的视频 解压能力和联网功能,而无需任何高端处理器或显卡的支持 即可进行游戏。云游戏的出现和发展解决了长期以来的终端 限制难题,让用户不用购买高级、昂贵的设备,在能够播放 视频的多媒体终端,就可以作为游戏主机终端,随时随地畅 玩精彩游戏,拓展了游戏的用户群体,满足不同层次玩家的 差异化需求。 5G 与云游戏业务相辅相成 过去,游戏的精美画质和动态渲染只能在专业游戏主机 上实现,现在,云游戏业务可借助 5G 高带宽通过云主机处 理在 5G 手机上以视频流的形式实现。同时,5G 超低延迟特 性与边缘节点计算能力相结合,可在 5G 手机上畅快运行响 应要求在 20ms 以内的主机游戏。因此,云游戏的市场需求 也将进一步推动 5G、千兆网的发展和普及。 云游戏作为未来的市场重点,具有广阔的业务前景。一 旦打开从云游戏平台到用户间的壁垒,搭建出成熟的云游戏 解决方案,便有机会探索出更加丰富的服务模式及多样的盈 利方式,为行业内的创意人员提供了一片亟待开发的沃土。云游戏业务实现原理 依靠云端部署的高性能渲染节点, 通过串流技术把游戏画面实时推送到终端。游戏中所有的计 算(包括画面渲染、数据同步、交互逻辑等)全部在云端服 务器进行,利用 5G 网络的超低延迟特性配合强大的边缘节 点计算能力,并通过互联网接受用户的输入指令,再将处理 完成后的最终画面结果显示在用户的前端设备上。 媒体终端 包括手机、平板电脑、笔记本电脑、TV 等 能播放视频的多媒体终端,都可以作为游戏主机终端; 业务平台 负责调度、鉴权、计费等相关业务功能; 渲染节点 利用高性能 GPU 实时完成复杂的游戏渲染 和串流。 支持游戏可在云端全天候运行,完成复杂的游戏渲染和 串流后将游戏场景以高清视频流的形式返回媒体终端,实现 在电视机顶盒或普通手机上玩 3A 级主机游戏大作和海量休 闲游戏高响应无缝游戏衔接体验。 在云游戏场景中,关键性的技术包括: 游戏实时性:游戏的整体延迟包括了游戏逻辑运算时间、 音画渲染的时间,加上编码的延时、网路传输的延时、客户 端解码的延时、客户端向服务端发送控制信息的延时,云游 戏的实时性需要达到可令玩家接受的程度。此外还要依靠硬 件和网络本身的性能。 虚拟化技术:游戏依赖 GPU 渲染,GPU 的虚拟化是实 现云游戏的必要条件。 实时网络传输:同样得益于短视频、直播业务的发展, 已有的网络协议优化技术为云游戏奠定了一定的基础,可以 进化为适应大带宽、低时延的网络优化技术。
-
看见云手机,眼前一亮,耳闻过没亲手用过,倒底是什么样子的呢?但是今天的实验不是很顺利,实验手册这里是这样的,ADB公网连接设置在这里。实际实验环境是这样的:木有,翻了半天,哪都木有~好吧好吧,放着慢慢玩~
-
泛云游戏Server端套件软件开发包主要包含:1、Server安装程序(包含安装密码)2、数据库表模板3、主机License申请工具4、Server启动bat脚本模板
推荐直播
-
HDC深度解读系列 - Serverless与MCP融合创新,构建AI应用全新智能中枢2025/08/20 周三 16:30-18:00
张昆鹏 HCDG北京核心组代表
HDC2025期间,华为云展示了Serverless与MCP融合创新的解决方案,本期访谈直播,由华为云开发者专家(HCDE)兼华为云开发者社区组织HCDG北京核心组代表张鹏先生主持,华为云PaaS服务产品部 Serverless总监Ewen为大家深度解读华为云Serverless与MCP如何融合构建AI应用全新智能中枢
回顾中 -
关于RISC-V生态发展的思考2025/09/02 周二 17:00-18:00
中国科学院计算技术研究所副所长包云岗教授
中科院包云岗老师将在本次直播中,探讨处理器生态的关键要素及其联系,分享过去几年推动RISC-V生态建设实践过程中的经验与教训。
回顾中 -
一键搞定华为云万级资源,3步轻松管理企业成本2025/09/09 周二 15:00-16:00
阿言 华为云交易产品经理
本直播重点介绍如何一键续费万级资源,3步轻松管理成本,帮助提升日常管理效率!
回顾中
热门标签