一直有个疑问,那就是“强化学习算法如何将GPU利用率提高到100%”,在一些论坛中也有人会提出这样的问题,但是一直也没有人比较正面的回答过这个问题,为此正好自己又想到了这么一个问题,于是想在这里正面的谈论下这个问题。

特别说明下,本文主要讨论的是在线强化学习算法(其实离线强化学习算法的这个问题可以参考下面的相关回答)

首先说下,强化学习算法由于计算过程包括多个部分,因此要想使强化学习算法的GPU利用率为100%就必然要使用并行化算法,串行方式下的强化学习算法是无法保证GPU利用率为100%的。

在线强化学习算法的并行化可以分为同步并行和异步并行,在同步并行化的情况下GPU的利用率也难以达到100%,因为GPU的利用率并不意味着GPU的核心的利用率,而是代表GPU的使用时长,而GPU在没有开启单独用户独享的模式下每个进程在调用GPU的时候都是独占使用的,因此同步并行化情况下GPU的利用率可以写为b/(a+b),其中b为每step计算过程中GPU的使用时长,a为每step计算过程中CPU的使用时长,因此如果b/(a+b)近似的等于100%,那么必然存在两种可能,第一种就是a足够小,另一种就是b足够大;之所以前面说到强化学习算法如果要想GPU的利用率为100%就必须使用并行化,其原因就是只有并行化才会减少a的时长,而b的时长却是无法无限制的增大的,因为强化学习所使用的网络往往比较简单,因此一次正反传的时间往往很短,唯一可以增加b的时长的方法就是增大batch_size,而由于GPU的计算特性所限制,在GPU的计算能力下batch_size为1和某个较大数值(如:32或64)下的单次计算时长相同,而大于这个数值的batch_size则会显著的增加GPU的计算时长(这里可以看做是使数值b增加),但是该种情况下并不会对计算性能有显著提升,比如batch_size为64时GPU的正反传是0.01秒,但是batch_size为128时则为0.02秒,该种方式支行减低整体计算的效率与提高GPU利用率的初衷相反(该种方式虽然会提高GPU利用率但是会使整体算法的计算效率下降),因此我们知道同步并行强化学习算法可以去提高GPU的利用率但是却无法到达100%;单step的CPU计算时长a是无法降低到足够小,而GPU的计算时长b也是无法增加到足够大,因此b/(a+b)是无法近似等于100%的。

有了上面的分析我们也就知道了这么一个结论,那就是只有异步的并行强化学习算法才可以保证GPU的利用率达到100%,当然这里讨论的都是在线强化学习算法,正是因为在线强化学习必须要在每step的计算中都要生成数据才导致出这个GPU利用率低的问题;虽然异步强化学习算法可以保证GPU的利用率为100%,但是其实这里有两种情况,分别为同策略的异步强化学习算法和异策略的异步强化学习算法。异策略的强化学习算法,如DQN算法的异步形式是可以保证GPU的利用率为100%的,同时该种异步方式是不会对算法性能起到不良影响的;但是同策略的强化学习算法就存在影响算法性能的问题,因为异步计算的方式难以保证同策略中的同策略要求,这样必然导致由于数据的生成策略和训练策略存在一定的分布偏差从而影响算法的整体性能,该种情况完全可以在GPU利用率为100%的情况下使算法的整体性能下降,这也是为什么A3C算法没有A2C算法好的一个主要原因。

可以说在不影响算法整体性能的情况下,通过并行方式加速计算且保证GPU利用率为100%的算法只有异步并行的异策略强化学习算法,如异步并行化的DQN,给出示意图:

上面讨论的都是在线学习强化学习算法,可以说由于强化学习算法的特殊性所以难以是GPU利用率达到100%,而将GPU利用率提高也难免会影响算法的整体性能,可以说往往没有使GPU利用率达到100%的强化学习算法才是计算效率最高的,如果一味的去求GPU的高利用率甚至会使强化学习算法更加难以收敛,如同策略算法。而同步并行的方式使GPU利用率到达100%,即使不影响算法收敛也会较大程度增加算法的复杂度,从而引发其他的问题。

这里再多说一下,由于强化学习的神经网络比较简单,难以在不影响整体性能的情况下增加单次计算的GPU时长,但是我们可以通过设置用户独享GPU的计算模式从而开启多个GPU进程,以此来提高GPU的使用率,该种情况往往两个或三个GPU进程就可以使GPU的利用率达到100%,但是这里就不仅存在数据生成策略间的同异步并行的问题也有了训练进程的同异步并行的问题,当然这种方式也有较为简单的形式,那就是在标准串行DQN基础上增加训练进程的数量,该种情况也可以保证GPU利用率100%。

在不影响算法收敛,不影响算法整体性能的情况下提升GPU利用率才是有意义的。

也正是因为使用GPU训练难以最大限度的提高运行效率,因此也有人提出使用CPU训练的方式,该种情况则需要使用大量的CPU进行计算,如A2C,而该种情况则可以使用HPC平台进行计算,往往也可以得到非常好的性能,而且CPU的扩展性往往强于GPU,因此如果你有足够多的CPU,那么你完全可以通过足够数量的CPU计算来获得高于GPU计算性能的表现,但是这里需要知道这么一个问题,那就是1个3090显卡好找,但是有着2000个CPU的HPC平台不好找,因此该种提升计算性能的方式不太适合个人用户而是比较适合企业用户。

PS:

大部分的在线强化学习算法难以在不影响算法收敛和整体性能的情况下提高GPU利用率,目前可以知道的可以提高GPU利用率到100%的在线情况学习算法大致有异步DQN和开启用户独占模式的并行训练的强化学习算法,当然即使是开启用户显卡独占也难以使同策略强化学习算法的GPU利用率为100%,这其中也难免要用到将异策略采样的数据通过重要性采样转为近似同策略的数据从而使多个训练进程使用,当然这种方式往往也难以就一定可以保证GPU利用率为100%,该种情况可以考虑在impala算法基础撒花姑娘进行改进。

=======================================================

这里给出一个实践的例子:

https://github.com/PacktPublishing/Deep-Reinforcement-Learning-Hands-On-Second-Edition

中的Chapter06中的DQN算法为例:

我们伪造假数据来用DQN的神经网络进行计算:

import torch
import torch.nn as nn
import numpy as np class DQN(nn.Module):
def __init__(self, input_shape, n_actions):
super(DQN, self).__init__() self.conv = nn.Sequential(
nn.Conv2d(input_shape[0], 32, kernel_size=8, stride=4),
nn.ReLU(),
nn.Conv2d(32, 64, kernel_size=4, stride=2),
nn.ReLU(),
nn.Conv2d(64, 64, kernel_size=3, stride=1),
nn.ReLU()
) conv_out_size = self._get_conv_out(input_shape)
self.fc = nn.Sequential(
nn.Linear(conv_out_size, 512),
nn.ReLU(),
nn.Linear(512, n_actions)
) def _get_conv_out(self, shape):
o = self.conv(torch.zeros(1, *shape))
return int(np.prod(o.size())) def forward(self, x):
conv_out = self.conv(x).view(x.size()[0], -1)
return self.fc(conv_out) if __name__=="__main__":
import torch.nn as nn
import torch.optim as optim batch_size=64 model=DQN((4, 84, 84), 6).to("cuda:0")
optimizer = optim.Adam(model.parameters(), lr=0.0001) while True:
images=torch.rand((batch_size, 4, 84, 84), device="cuda:0")
labels=torch.rand((batch_size, ), device="cuda:0")
_label=model(images).max(1)[0]
# _label=model(images)[:, 0]
# _label=model(images)
loss=nn.MSELoss()(_label, labels) optimizer.zero_grad()
loss.backward()
optimizer.step()

GPU的利用率为100%。

-----------------------------------------

标准的DQN算法:

#!/usr/bin/env python3
from lib import wrappers
from lib import dqn_model import argparse
import time
import numpy as np
import collections import torch
import torch.nn as nn
import torch.optim as optim from tensorboardX import SummaryWriter DEFAULT_ENV_NAME = "PongNoFrameskip-v4"
MEAN_REWARD_BOUND = 19 GAMMA = 0.99
BATCH_SIZE = 32
REPLAY_SIZE = 10000
LEARNING_RATE = 1e-4
SYNC_TARGET_FRAMES = 1000
REPLAY_START_SIZE = 10000 EPSILON_DECAY_LAST_FRAME = 150000
EPSILON_START = 1.0
EPSILON_FINAL = 0.01 Experience = collections.namedtuple(
'Experience', field_names=['state', 'action', 'reward',
'done', 'new_state']) class ExperienceBuffer:
def __init__(self, capacity):
self.buffer = collections.deque(maxlen=capacity) def __len__(self):
return len(self.buffer) def append(self, experience):
self.buffer.append(experience) def sample(self, batch_size):
indices = np.random.choice(len(self.buffer), batch_size,
replace=False)
states, actions, rewards, dones, next_states = \
zip(*[self.buffer[idx] for idx in indices])
return np.array(states), np.array(actions), \
np.array(rewards, dtype=np.float32), \
np.array(dones, dtype=np.uint8), \
np.array(next_states) class Agent:
def __init__(self, env, exp_buffer):
self.env = env
self.exp_buffer = exp_buffer
self._reset() def _reset(self):
self.state = env.reset()
self.total_reward = 0.0 @torch.no_grad()
def play_step(self, net, epsilon=0.0, device="cpu"):
done_reward = None if np.random.random() < epsilon:
action = env.action_space.sample()
else:
state_a = np.array([self.state], copy=False)
state_v = torch.tensor(state_a).to(device)
q_vals_v = net(state_v)
_, act_v = torch.max(q_vals_v, dim=1)
action = int(act_v.item()) # do step in the environment
new_state, reward, is_done, _ = self.env.step(action)
self.total_reward += reward exp = Experience(self.state, action, reward,
is_done, new_state)
self.exp_buffer.append(exp)
self.state = new_state
if is_done:
done_reward = self.total_reward
self._reset()
return done_reward def calc_loss(batch, net, tgt_net, device="cpu"):
states, actions, rewards, dones, next_states = batch states_v = torch.tensor(np.array(
states, copy=False)).to(device)
next_states_v = torch.tensor(np.array(
next_states, copy=False)).to(device)
actions_v = torch.tensor(actions).to(device)
rewards_v = torch.tensor(rewards).to(device)
done_mask = torch.BoolTensor(dones).to(device) state_action_values = net(states_v).gather(
1, actions_v.unsqueeze(-1)).squeeze(-1)
with torch.no_grad():
next_state_values = tgt_net(next_states_v).max(1)[0]
next_state_values[done_mask] = 0.0
next_state_values = next_state_values.detach() expected_state_action_values = next_state_values * GAMMA + \
rewards_v
return nn.MSELoss()(state_action_values,
expected_state_action_values) if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--cuda", default=False,
action="store_true", help="Enable cuda")
parser.add_argument("--env", default=DEFAULT_ENV_NAME,
help="Name of the environment, default=" +
DEFAULT_ENV_NAME)
args = parser.parse_args()
device = torch.device("cuda" if args.cuda else "cpu") env = wrappers.make_env(args.env) net = dqn_model.DQN(env.observation_space.shape,
env.action_space.n).to(device)
tgt_net = dqn_model.DQN(env.observation_space.shape,
env.action_space.n).to(device)
writer = SummaryWriter(comment="-" + args.env)
print(net) buffer = ExperienceBuffer(REPLAY_SIZE)
agent = Agent(env, buffer)
epsilon = EPSILON_START optimizer = optim.Adam(net.parameters(), lr=LEARNING_RATE)
total_rewards = []
frame_idx = 0
ts_frame = 0
ts = time.time()
best_m_reward = None while True:
frame_idx += 1
epsilon = max(EPSILON_FINAL, EPSILON_START -
frame_idx / EPSILON_DECAY_LAST_FRAME) reward = agent.play_step(net, epsilon, device=device)
if reward is not None:
total_rewards.append(reward)
speed = (frame_idx - ts_frame) / (time.time() - ts)
ts_frame = frame_idx
ts = time.time()
m_reward = np.mean(total_rewards[-100:])
print("%d: done %d games, reward %.3f, "
"eps %.2f, speed %.2f f/s" % (
frame_idx, len(total_rewards), m_reward, epsilon,
speed
))
writer.add_scalar("epsilon", epsilon, frame_idx)
writer.add_scalar("speed", speed, frame_idx)
writer.add_scalar("reward_100", m_reward, frame_idx)
writer.add_scalar("reward", reward, frame_idx)
if best_m_reward is None or best_m_reward < m_reward:
torch.save(net.state_dict(), args.env +
"-best_%.0f.dat" % m_reward)
if best_m_reward is not None:
print("Best reward updated %.3f -> %.3f" % (
best_m_reward, m_reward))
best_m_reward = m_reward
if m_reward > MEAN_REWARD_BOUND:
print("Solved in %d frames!" % frame_idx)
break if len(buffer) < REPLAY_START_SIZE:
continue if frame_idx % SYNC_TARGET_FRAMES == 0:
tgt_net.load_state_dict(net.state_dict()) optimizer.zero_grad()
batch = buffer.sample(BATCH_SIZE)
loss_t = calc_loss(batch, net, tgt_net, device=device)
loss_t.backward()
optimizer.step()
writer.close()

GPU的利用率为 40% 。

-----------------------------------------

如果我们把训练过程中的数据生成部分屏蔽掉,代码:

#!/usr/bin/env python3
from lib import wrappers
from lib import dqn_model import argparse
import time
import numpy as np
import collections import torch
import torch.nn as nn
import torch.optim as optim from tensorboardX import SummaryWriter DEFAULT_ENV_NAME = "PongNoFrameskip-v4"
MEAN_REWARD_BOUND = 19 GAMMA = 0.99
BATCH_SIZE = 32 #32
REPLAY_SIZE = 10000
LEARNING_RATE = 1e-4
SYNC_TARGET_FRAMES = 1000
REPLAY_START_SIZE = 10000 EPSILON_DECAY_LAST_FRAME = 150000
EPSILON_START = 1.0
EPSILON_FINAL = 0.01 Experience = collections.namedtuple(
'Experience', field_names=['state', 'action', 'reward',
'done', 'new_state']) class ExperienceBuffer:
def __init__(self, capacity):
self.buffer = collections.deque(maxlen=capacity) def __len__(self):
return len(self.buffer) def append(self, experience):
self.buffer.append(experience) def sample(self, batch_size):
indices = np.random.choice(len(self.buffer), batch_size,
replace=False)
states, actions, rewards, dones, next_states = \
zip(*[self.buffer[idx] for idx in indices])
return np.array(states), np.array(actions), \
np.array(rewards, dtype=np.float32), \
np.array(dones, dtype=np.uint8), \
np.array(next_states) class Agent:
def __init__(self, env, exp_buffer):
self.env = env
self.exp_buffer = exp_buffer
self._reset() def _reset(self):
self.state = env.reset()
self.total_reward = 0.0 @torch.no_grad()
def play_step(self, net, epsilon=0.0, device="cpu"):
done_reward = None if np.random.random() < epsilon:
action = env.action_space.sample()
else:
state_a = np.array([self.state], copy=False)
state_v = torch.tensor(state_a).to(device)
q_vals_v = net(state_v)
_, act_v = torch.max(q_vals_v, dim=1)
action = int(act_v.item()) # do step in the environment
new_state, reward, is_done, _ = self.env.step(action)
self.total_reward += reward exp = Experience(self.state, action, reward,
is_done, new_state)
self.exp_buffer.append(exp)
self.state = new_state
if is_done:
done_reward = self.total_reward
self._reset()
return done_reward def calc_loss(batch, net, tgt_net, device="cpu"):
states, actions, rewards, dones, next_states = batch states_v = torch.tensor(np.array(
states, copy=False)).to(device)
next_states_v = torch.tensor(np.array(
next_states, copy=False)).to(device)
actions_v = torch.tensor(actions).to(device)
rewards_v = torch.tensor(rewards).to(device)
done_mask = torch.BoolTensor(dones).to(device) state_action_values = net(states_v).gather(
1, actions_v.unsqueeze(-1)).squeeze(-1)
with torch.no_grad():
next_state_values = tgt_net(next_states_v).max(1)[0]
next_state_values[done_mask] = 0.0
next_state_values = next_state_values.detach() expected_state_action_values = next_state_values * GAMMA + \
rewards_v
return nn.MSELoss()(state_action_values,
expected_state_action_values) first = True
states_v = None
next_states_v = None
actions_v = None
rewards_v = None
done_mask = None
def calc_loss2(batch, net, tgt_net, device="cpu"):
global first
global states_v,next_states_v,actions_v,rewards_v,done_mask """
if first:
states, actions, rewards, dones, next_states = batch states_v = torch.tensor(np.array(
states, copy=False)).to(device)
next_states_v = torch.tensor(np.array(
next_states, copy=False)).to(device)
actions_v = torch.tensor(actions).to(device)
rewards_v = torch.tensor(rewards).to(device)
done_mask = torch.BoolTensor(dones).to(device)
first=False
"""
states, actions, rewards, dones, next_states = batch states_v = torch.tensor(np.array(
states, copy=False)).to(device)
next_states_v = torch.tensor(np.array(
next_states, copy=False)).to(device)
actions_v = torch.tensor(actions).to(device)
rewards_v = torch.tensor(rewards).to(device)
done_mask = torch.BoolTensor(dones).to(device)
first=False state_action_values = net(states_v).gather(
1, actions_v.unsqueeze(-1)).squeeze(-1)
with torch.no_grad():
next_state_values = tgt_net(next_states_v).max(1)[0]
next_state_values[done_mask] = 0.0
next_state_values = next_state_values.detach() expected_state_action_values = next_state_values * GAMMA + \
rewards_v
return nn.MSELoss()(state_action_values,
expected_state_action_values) if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--cuda", default=False,
action="store_true", help="Enable cuda")
parser.add_argument("--env", default=DEFAULT_ENV_NAME,
help="Name of the environment, default=" +
DEFAULT_ENV_NAME)
args = parser.parse_args()
device = torch.device("cuda" if args.cuda else "cpu") env = wrappers.make_env(args.env) net = dqn_model.DQN(env.observation_space.shape,
env.action_space.n).to(device)
tgt_net = dqn_model.DQN(env.observation_space.shape,
env.action_space.n).to(device)
writer = SummaryWriter(comment="-" + args.env)
print(net) buffer = ExperienceBuffer(REPLAY_SIZE)
agent = Agent(env, buffer)
epsilon = EPSILON_START optimizer = optim.Adam(net.parameters(), lr=LEARNING_RATE)
total_rewards = []
frame_idx = 0
ts_frame = 0
ts = time.time()
best_m_reward = None while True:
frame_idx += 1 if frame_idx < 20000:
epsilon = max(EPSILON_FINAL, EPSILON_START -
frame_idx / EPSILON_DECAY_LAST_FRAME) reward = agent.play_step(net, epsilon, device=device)
if reward is not None:
total_rewards.append(reward)
speed = (frame_idx - ts_frame) / (time.time() - ts)
ts_frame = frame_idx
ts = time.time()
m_reward = np.mean(total_rewards[-100:])
print("%d: done %d games, reward %.3f, "
"eps %.2f, speed %.2f f/s" % (
frame_idx, len(total_rewards), m_reward, epsilon,
speed
))
writer.add_scalar("epsilon", epsilon, frame_idx)
writer.add_scalar("speed", speed, frame_idx)
writer.add_scalar("reward_100", m_reward, frame_idx)
writer.add_scalar("reward", reward, frame_idx)
if best_m_reward is None or best_m_reward < m_reward:
torch.save(net.state_dict(), args.env +
"-best_%.0f.dat" % m_reward)
if best_m_reward is not None:
print("Best reward updated %.3f -> %.3f" % (
best_m_reward, m_reward))
best_m_reward = m_reward
if m_reward > MEAN_REWARD_BOUND:
print("Solved in %d frames!" % frame_idx)
break if len(buffer) < REPLAY_START_SIZE:
continue if frame_idx % SYNC_TARGET_FRAMES == 0:
tgt_net.load_state_dict(net.state_dict()) optimizer.zero_grad()
batch = buffer.sample(BATCH_SIZE)
loss_t = calc_loss(batch, net, tgt_net, device=device)
loss_t.backward()
optimizer.step()
continue optimizer.zero_grad()
loss_t = calc_loss2(batch, net, tgt_net, device=device)
loss_t.backward()
optimizer.step()
writer.close()

GPU的利用率为 100% 。

其中有意思的一个地方是,发现下面代码:

def calc_loss(batch, net, tgt_net, device="cpu"):
states, actions, rewards, dones, next_states = batch states_v = torch.tensor(np.array(
states, copy=False)).to(device)
next_states_v = torch.tensor(np.array(
next_states, copy=False)).to(device)
actions_v = torch.tensor(actions).to(device)
rewards_v = torch.tensor(rewards).to(device)
done_mask = torch.BoolTensor(dones).to(device)

CPU 的使用率为99%,也就是说上面的这个numpy转pytorch的操作会使CPU的利用率为接近100%。

从这里我们可以知道,如果要保证GPU的利用率为100%,那么就必须使调用GPU计算的进程只进行GPU的前后向计算,即使是这种类型转换的操作也应该由数据生成进程完成,这样才可以保证训练进程的GPU利用率为100% 。

PS:

在强化学习算法中,使GPU利用率为100%的最本质的原理就是在GPU计算的时候覆盖掉CPU端的计算,而这种情况则要使用多进程或多线程并行,同时我们也需要保证GPU端有足够的数据以保证GPU不空转;但是保证这样的条件往往会使算法的收敛性和整体性能受到影响,因此有时候过分追求GPU的高利用率是没有意义和价值的,即使有的类型的强化学习算法可以通过并行的方式使GPU利用率达到100%并且不影响算法性能,但是也会大幅度提高算法的复杂度,从而引起其他的难以预知的问题。

-----------------------------------------

强化学习算法如何将GPU利用率提高到100%——在线强化学习如何将GPU利用率提升至100%的更多相关文章

  1. 感知机学习算法Java实现

    感知机学习算法Java实现. Perceptron类用于实现感知机, 其中的perceptronOriginal()方法用于实现感知机学习算法的原始形式: perceptronAnother()方法用 ...

  2. [ios-必看] 国人当自强:两岸三地在线编程学习网站大搜罗 [转]

    http://blog.csdn.net/lyy_whg/article/details/17350923 说到国内的在线编程学习网站,很多人都是一脸茫然,即使是资深开发者也是如此.在许多人眼中,尽管 ...

  3. win10+anaconda+cuda配置dlib,使用GPU对dlib的深度学习算法进行加速(以人脸检测为例)

    在计算机视觉和机器学习方向有一个特别好用但是比较低调的库,也就是dlib,与opencv相比其包含了很多最新的算法,尤其是深度学习方面的,因此很有必要学习一下.恰好最近换了一台笔记本,内含一块GTX1 ...

  4. 一文读懂 深度强化学习算法 A3C (Actor-Critic Algorithm)

    一文读懂 深度强化学习算法 A3C (Actor-Critic Algorithm) 2017-12-25  16:29:19   对于 A3C 算法感觉自己总是一知半解,现将其梳理一下,记录在此,也 ...

  5. 强化学习算法DQN

    1 DQN的引入 由于q_learning算法是一直更新一张q_table,在场景复杂的情况下,q_table就会大到内存处理的极限,而且在当时深度学习的火热,有人就会想到能不能将从深度学习中借鉴方法 ...

  6. 提升学习算法简述:AdaBoost, GBDT和XGBoost

    1. 历史及演进 提升学习算法,又常常被称为Boosting,其主要思想是集成多个弱分类器,然后线性组合成为强分类器.为什么弱分类算法可以通过线性组合形成强分类算法?其实这是有一定的理论基础的.198 ...

  7. 深度信任网络的快速学习算法(Hinton的论文)

    也没啥原创,就是在学习深度学习的过程中丰富一下我的博客,嘿嘿. 不喜勿喷! Hinton是深度学习方面的大牛,跟着大牛走一般不会错吧-- 来源:A fast learning algorithm fo ...

  8. 学习笔记TF053:循环神经网络,TensorFlow Model Zoo,强化学习,深度森林,深度学习艺术

    循环神经网络.https://github.com/aymericdamien/TensorFlow-Examples/blob/master/examples/3_NeuralNetworks/re ...

  9. 集成学习算法总结----Boosting和Bagging(转)

    1.集成学习概述 1.1 集成学习概述 集成学习在机器学习算法中具有较高的准去率,不足之处就是模型的训练过程可能比较复杂,效率不是很高.目前接触较多的集成学习主要有2种:基于Boosting的和基于B ...

  10. Ensemble_learning 集成学习算法 stacking 算法

    原文:https://herbertmj.wikispaces.com/stacking%E7%AE%97%E6%B3%95 stacked 产生方法是一种截然不同的组合多个模型的方法,它讲的是组合学 ...

随机推荐

  1. cdn静态资源加速

    阿里云cdn产品 https://www.aliyun.com/product/cdn CDN通过广泛的网络节点分布,提供快速.稳定.安全.可编程的全球内容分发加速服务,支持将网站.音视频.下载等内容 ...

  2. Centos7部署FytSoa项目至Docker——第二步:安装Mysql、Redis

    FytSoa项目地址:https://gitee.com/feiyit/FytSoaCms 部署完成地址:http://82.156.127.60:8001/ 先到腾讯云申请一年的云服务器,我买的是一 ...

  3. LocalDateTime与LocalDate之间转换

    LocalDateTime与LocalDate之间转换 //LocalDateTime转换LocalDate LocalDateTime now2 = LocalDateTime.now(); Loc ...

  4. http请求方式-OkHttpClient

    http请求方式-OkHttpClient import com.example.core.mydemo.http.OrderReqVO; import okhttp3.*; import org.s ...

  5. Java中的栈、堆和常量池

    Java程序是运行在JVM(Java虚拟机)上的,因此Java的内存分配是在JVM中进行的,JVM是内存分配的基础和前提. Java程序的运行会涉及以下的内存区域: 寄存器:JVM内部虚拟寄存器,存取 ...

  6. springboot 整合 pagehelper

    pom.xml <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pa ...

  7. SpringBoot2.X定时任务schedule

    什么是定时任务和常见定时任务区别? 某个时间定时处理某个任务 发邮件.短信等 消息提醒 统计报表系统 ... 常见定时任务 Java自带的java.util.Timer类配置比较麻烦,时间延后问题 Q ...

  8. 某手创作服务 __NS_sig3 sig3 | js 逆向

    拿获取作品列表为例 https://cp.kuaishou.com/rest/cp/works/v2/video/pc/photo/list?__NS_sig3=xxxxxxxxxxx 搜索__NS_ ...

  9. 最简GIF解析代码gif_jumper,用于stb_image的小改进

    gif jumper gif支持多帧动画,但是没有存储总帧数,解析gif直到结束才能知道总帧数. 所以gif解析代码,要么采用链表,要么不停realloc()分配内存,stb_image的代码就是如此 ...

  10. TokenObtainPairSerialize和TokenObtainPairView

    TokenObtainPairSerializer和TokenObtainPairView是Django REST framework的SimpleJWT库提供的两个相关的类. TokenObtain ...