ShiftViT:采用简单高效的移位操作证明Attention是否必要

注意力机制被视为视觉Transformer成功关键,但研究质疑其必要性。通过零参数零计算的Shift操作构建ShiftViT,替代注意力层,在分类、检测和分割等任务中表现媲美甚至优于Swin Transformer,表明注意力机制或非ViT成功关键,未来应关注其剩余部分。

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

shiftvit:采用简单高效的移位操作证明attention是否必要 - 创想鸟

ShiftViT:采用简单高效的移位操作证明Attention是否必要

摘要

        注意力机制被广泛认为是视觉Transformer成功的关键,因为它提供了一种灵活而强大的方式来建模空间关系。然而,注意力机制真的是ViT不可或缺的一部分吗?它能被其他替代品取代吗?为了揭开注意力机制的神秘面纱,我们将其简化为一个极其简单的例子:ZERO FLOP和ZERO parameter。具体来说,我们要重新审视Shift操作。它不包含任何参数或算术计算。唯一的操作是在相邻特性之间交换一小部分通道。基于这个简单的操作,我们构建了一个新的骨干网络,即ShiftViT,其中的注意层被Shift操作所取代。令人惊讶的是,ShiftViT在几个主流任务中工作得相当好,例如,分类,检测和分割。性能与强大的基线Swin Transformer相当,甚至更好。这些结果表明,注意力机制可能不是使ViT成功的关键因素。它甚至可以被零参数操作取代。在今后的工作中,我们应该更多地关注ViT的剩余部分。

1. ShiftViT

        为验证Transformer中的Attention机制是否是必要的,ShiftViT采用一个简单高效的Shift操作来代替Attention机制,Shift操作是沿上下左右对Shift部分进行偏移操作(与S2MLP特别相似,不同的是S2MLP将所有都采用Shift操作,而ShiftViT仅对一部分使用Shift操作):

z^[0:H,1:W,0:γC]←z[0:H,0:W−1,0:γC]z^[0:H,0:W−1,γC:2γC]←z[0:H,1:W,γC:2γC]z^[0:H−1,0:W,2γC:3γC]←z[1:H,0:W,2γC:3γC]z^[1:H,0:W,3γC:4γC]←z[0:H−1,0:W,3γC:4γC]z^[0:H,0:W,4γC:C]←z[0:H,0:W,4γC:C]z^[0:H,1:W,0:γC]z^[0:H,0:W−1,γC:2γC]z^[0:H−1,0:W,2γC:3γC]z^[1:H,0:W,3γC:4γC]z^[0:H,0:W,4γC:C]←z[0:H,0:W−1,0:γC]←z[0:H,1:W,γC:2γC]←z[1:H,0:W,2γC:3γC]←z[0:H−1,0:W,3γC:4γC]←z[0:H,0:W,4γC:C]

ShiftViT:采用简单高效的移位操作证明Attention是否必要 - 创想鸟

2. 代码复现

2.1 下载并导入所需的库

In [ ]

!pip install einops-0.3.0-py3-none-any.whl

In [ ]

%matplotlib inlineimport paddleimport numpy as npimport matplotlib.pyplot as pltfrom paddle.vision.datasets import Cifar10from paddle.vision.transforms import Transposefrom paddle.io import Dataset, DataLoaderfrom paddle import nnimport paddle.nn.functional as Fimport paddle.vision.transforms as transformsimport osimport matplotlib.pyplot as pltfrom matplotlib.pyplot import figurefrom einops.layers.paddle import Rearrange, Reducefrom einops import rearrange

2.2 创建数据集

In [16]

train_tfm = transforms.Compose([    transforms.Resize((230, 230)),    transforms.ColorJitter(brightness=0.2,contrast=0.2, saturation=0.2),    transforms.RandomResizedCrop(224, scale=(0.6, 1.0)),    transforms.RandomHorizontalFlip(0.5),    transforms.RandomRotation(20),    transforms.ToTensor(),    transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),])test_tfm = transforms.Compose([    transforms.Resize((224, 224)),    transforms.ToTensor(),    transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),])

In [17]

paddle.vision.set_image_backend('cv2')# 使用Cifar10数据集train_dataset = Cifar10(data_file='data/data152754/cifar-10-python.tar.gz', mode='train', transform = train_tfm, )val_dataset = Cifar10(data_file='data/data152754/cifar-10-python.tar.gz', mode='test',transform = test_tfm)print("train_dataset: %d" % len(train_dataset))print("val_dataset: %d" % len(val_dataset))
train_dataset: 50000val_dataset: 10000

In [18]

batch_size=128

In [19]

train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, drop_last=True, num_workers=4)val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False, drop_last=False, num_workers=4)

2.3 模型的创建

2.3.1 标签平滑

In [8]

class LabelSmoothingCrossEntropy(nn.Layer):    def __init__(self, smoothing=0.1):        super().__init__()        self.smoothing = smoothing    def forward(self, pred, target):        confidence = 1. - self.smoothing        log_probs = F.log_softmax(pred, axis=-1)        idx = paddle.stack([paddle.arange(log_probs.shape[0]), target], axis=1)        nll_loss = paddle.gather_nd(-log_probs, index=idx)        smooth_loss = paddle.mean(-log_probs, axis=-1)        loss = confidence * nll_loss + self.smoothing * smooth_loss        return loss.mean()

2.3.2 DropPath

In [8]

def drop_path(x, drop_prob=0.0, training=False):    """    Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).    the original name is misleading as 'Drop Connect' is a different form of dropout in a separate paper...    See discussion: https://github.com/tensorflow/tpu/issues/494#issuecomment-532968956 ...    """    if drop_prob == 0.0 or not training:        return x    keep_prob = paddle.to_tensor(1 - drop_prob)    shape = (paddle.shape(x)[0],) + (1,) * (x.ndim - 1)    random_tensor = keep_prob + paddle.rand(shape, dtype=x.dtype)    random_tensor = paddle.floor(random_tensor)  # binarize    output = x.divide(keep_prob) * random_tensor    return outputclass DropPath(nn.Layer):    def __init__(self, drop_prob=None):        super(DropPath, self).__init__()        self.drop_prob = drop_prob    def forward(self, x):        return drop_path(x, self.drop_prob, self.training)

2.3.3 ShiftViT模型的创建

In [9]

class MLP(nn.Layer):    def __init__(self, in_features, hidden_features=None, out_features=None,act_layer=nn.GELU, drop=0.):        super().__init__()        out_features = out_features or in_features        hidden_features = hidden_features or in_features        self.fc1 = nn.Conv2D(in_features, hidden_features, 1)        self.act = act_layer()        self.fc2 = nn.Conv2D(hidden_features, out_features, 1)        self.drop = nn.Dropout(drop)    def forward(self, x):        x = self.fc1(x)        x = self.act(x)        x = self.drop(x)        x = self.fc2(x)        x = self.drop(x)        return x

In [10]

class Shift(nn.Layer):    def __init__(self, n_div):        super().__init__()        self.n_div = n_div    def forward(self, x):        B, C, H, W = x.shape        g = C // self.n_div        # out = paddle.zeros_like(x)        x[:, g * 0:g * 1, :, :-1] = x[:, g * 0:g * 1, :, 1:]  # shift left        x[:, g * 1:g * 2, :, 1:] = x[:, g * 1:g * 2, :, :-1]  # shift right        x[:, g * 2:g * 3, :-1, :] = x[:, g * 2:g * 3, 1:, :]  # shift up        x[:, g * 3:g * 4, 1:, :] = x[:, g * 3:g * 4, :-1, :]  # shift down        x[:, g * 4:, :, :] = x[:, g * 4:, :, :]  # no shift        return x

In [11]

class ShiftViTBlock(nn.Layer):    def __init__(self, dim, n_div=12, mlp_ratio=4., drop=0., drop_path=0., act_layer=nn.GELU, norm_layer=nn.LayerNorm,                input_resolution=None):        super().__init__()        self.input_resolution = input_resolution        self.mlp_ratio = mlp_ratio        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()        self.norm = norm_layer(dim)        mlp_hidden_dim = int(dim * mlp_ratio)        self.mlp = MLP(in_features=dim,                       hidden_features=mlp_hidden_dim,                       act_layer=act_layer,                       drop=drop)        self.n_div = n_div        self.shift = Shift(n_div)    def forward(self, x):        x = self.shift(x)        shortcut = x        x = shortcut + self.drop_path(self.mlp(self.norm(x.transpose([0, 2, 3, 1])).transpose([0, 3, 1, 2])))        return x

In [12]

class BasicLayer(nn.Layer):    def __init__(self, dim, input_resolution, depth, n_div=12, mlp_ratio=4., drop=0., drop_path=None, norm_layer=None, downsample=True,                act_layer=nn.GELU):        super(BasicLayer, self).__init__()        self.dim = dim        self.input_resolution = input_resolution        self.depth = depth        # build blocks        self.blocks = nn.LayerList([            ShiftViTBlock(dim=dim,                          n_div=n_div,                          mlp_ratio=mlp_ratio,                          drop=drop,                          drop_path=drop_path[i],                          norm_layer=norm_layer,                          act_layer=act_layer,                          input_resolution=input_resolution)            for i in range(depth)        ])        # patch merging layer        if downsample:            self.downsample = nn.Sequential(                nn.GroupNorm(num_groups=1, num_channels=dim),                nn.Conv2D(dim, dim * 2, kernel_size=2, stride=2,bias_attr=False)            )        else:            self.downsample = None    def forward(self, x):        for blk in self.blocks:            x = blk(x)        if self.downsample is not None:            x = self.downsample(x)        return x

In [13]

class ShiftViT(nn.Layer):    def __init__(self,n_div=12, img_size=224, patch_size=4, in_chans=3, num_classes=1000, embed_dim=96, depths=(2, 2, 6, 2), mlp_ratio=2.,                drop_rate=0., drop_path_rate=0.1, patch_norm=True, **kwargs):        super().__init__()        norm_layer = nn.LayerNorm        act_layer = nn.GELU        self.num_classes = num_classes        self.num_layers = len(depths)        self.embed_dim = embed_dim        self.patch_norm = patch_norm        self.num_features = int(embed_dim * 2 ** (self.num_layers - 1))        self.mlp_ratio = mlp_ratio        # split image into non-overlapping patches        self.patch_embed = nn.Sequential(            nn.Conv2D(in_chans, embed_dim, kernel_size=patch_size, stride=patch_size),            Rearrange('b c h w->b h w c'),            nn.LayerNorm(embed_dim) if self.patch_norm else nn.Identity(),            Rearrange('b h w c->b c h w')        )        # num_patches = self.patch_embed.num_patches        patches_resolution = [img_size // patch_size, img_size // patch_size]        self.patches_resolution = patches_resolution        self.pos_drop = nn.Dropout(p=drop_rate)        # stochastic depth decay rule        dpr = [x.item()               for x in paddle.linspace(0, drop_path_rate, sum(depths))]        # build layers        self.layers = nn.LayerList()        for i_layer in range(self.num_layers):            layer = BasicLayer(dim=int(embed_dim * 2 ** i_layer),                               n_div=n_div,                               input_resolution=(patches_resolution[0] // (2 ** i_layer),                                                 patches_resolution[1] // (2 ** i_layer)),                               depth=depths[i_layer],                               mlp_ratio=self.mlp_ratio,                               drop=drop_rate,                               drop_path=dpr[sum(depths[:i_layer]):sum(depths[:i_layer + 1])],                               norm_layer=norm_layer,                               downsample=(i_layer  0 else nn.Identity()        self.apply(self._init_weights)    def _init_weights(self, m):        tn = nn.initializer.TruncatedNormal(std=.02)        zeros = nn.initializer.Constant(0.)        ones = nn.initializer.Constant(1.)        if isinstance(m, nn.Linear):            tn(m.weight)            if isinstance(m, nn.Linear) and m.bias is not None:                zeros(m.bias)        elif isinstance(m, (nn.Conv1D, nn.Conv2D)):            tn(m.weight)            if m.bias is not None:                zeros(m.bias)        elif isinstance(m, (nn.LayerNorm, nn.GroupNorm)):            zeros(m.bias)            ones(m.weight)    def forward_features(self, x):        x = self.patch_embed(x)        x = self.pos_drop(x)        for layer in self.layers:            x = layer(x)        x = self.norm(x.transpose([0, 2, 3, 1])).transpose([0, 3, 1, 2])         x = self.avgpool(x)         x = paddle.flatten(x, 1)        return x    def forward(self, x):        x = self.forward_features(x)        x = self.head(x)        return x

2.3.4 模型的参数

In [ ]

# Shift-Tmodel = ShiftViT(n_div=12, embed_dim=96, depths=(6, 8, 18, 6), num_classes=10)paddle.summary(model, (1, 3, 224, 224))

ShiftViT:采用简单高效的移位操作证明Attention是否必要 - 创想鸟

In [ ]

# Shift-Smodel = ShiftViT(n_div=12, embed_dim=96, depths=(10, 18, 36, 10), num_classes=10)paddle.summary(model, (1, 3, 224, 224))

ShiftViT:采用简单高效的移位操作证明Attention是否必要 - 创想鸟

In [ ]

# Shift-Bmodel = ShiftViT(n_div=16, embed_dim=128, depths=(10, 18, 36, 10), num_classes=10)paddle.summary(model, (1, 3, 224, 224))

ShiftViT:采用简单高效的移位操作证明Attention是否必要 - 创想鸟

YOO必优科技-AI写作 YOO必优科技-AI写作

智能图文创作平台,让内容创作更简单

YOO必优科技-AI写作 14 查看详情 YOO必优科技-AI写作 In [ ]

# Shift-oursmodel = ShiftViT(n_div=12, embed_dim=96, depths=(3, 4, 9, 3), num_classes=10)paddle.summary(model, (1, 3, 224, 224))

ShiftViT:采用简单高效的移位操作证明Attention是否必要 - 创想鸟

2.4 训练

In [19]

learning_rate = 0.001n_epochs = 100paddle.seed(42)np.random.seed(42)

In [ ]

work_path = 'work/model'# Shift-oursmodel = ShiftViT(n_div=12, embed_dim=96, depths=(3, 4, 9, 3), num_classes=10)criterion = LabelSmoothingCrossEntropy()scheduler = paddle.optimizer.lr.CosineAnnealingDecay(learning_rate=learning_rate, T_max=50000 // batch_size * n_epochs, verbose=False)optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=scheduler, weight_decay=1e-5)gate = 0.0threshold = 0.0best_acc = 0.0val_acc = 0.0loss_record = {'train': {'loss': [], 'iter': []}, 'val': {'loss': [], 'iter': []}}   # for recording lossacc_record = {'train': {'acc': [], 'iter': []}, 'val': {'acc': [], 'iter': []}}      # for recording accuracyloss_iter = 0acc_iter = 0for epoch in range(n_epochs):    # ---------- Training ----------    model.train()    train_num = 0.0    train_loss = 0.0    val_num = 0.0    val_loss = 0.0    accuracy_manager = paddle.metric.Accuracy()    val_accuracy_manager = paddle.metric.Accuracy()    print("#===epoch: {}, lr={:.10f}===#".format(epoch, optimizer.get_lr()))    for batch_id, data in enumerate(train_loader):        x_data, y_data = data        labels = paddle.unsqueeze(y_data, axis=1)        logits = model(x_data)        loss = criterion(logits, y_data)        acc = accuracy_manager.compute(logits, labels)        accuracy_manager.update(acc)        if batch_id % 10 == 0:            loss_record['train']['loss'].append(loss.numpy())            loss_record['train']['iter'].append(loss_iter)            loss_iter += 1        loss.backward()        optimizer.step()        scheduler.step()        optimizer.clear_grad()                train_loss += loss        train_num += len(y_data)    total_train_loss = (train_loss / train_num) * batch_size    train_acc = accuracy_manager.accumulate()    acc_record['train']['acc'].append(train_acc)    acc_record['train']['iter'].append(acc_iter)    acc_iter += 1    # Print the information.    print("#===epoch: {}, train loss is: {}, train acc is: {:2.2f}%===#".format(epoch, total_train_loss.numpy(), train_acc*100))    # ---------- Validation ----------    model.eval()    for batch_id, data in enumerate(val_loader):        x_data, y_data = data        labels = paddle.unsqueeze(y_data, axis=1)        with paddle.no_grad():          logits = model(x_data)        loss = criterion(logits, y_data)        acc = val_accuracy_manager.compute(logits, labels)        val_accuracy_manager.update(acc)        val_loss += loss        val_num += len(y_data)    total_val_loss = (val_loss / val_num) * batch_size    loss_record['val']['loss'].append(total_val_loss.numpy())    loss_record['val']['iter'].append(loss_iter)    val_acc = val_accuracy_manager.accumulate()    acc_record['val']['acc'].append(val_acc)    acc_record['val']['iter'].append(acc_iter)        print("#===epoch: {}, val loss is: {}, val acc is: {:2.2f}%===#".format(epoch, total_val_loss.numpy(), val_acc*100))    # ===================save====================    if val_acc > best_acc:        best_acc = val_acc        paddle.save(model.state_dict(), os.path.join(work_path, 'best_model.pdparams'))        paddle.save(optimizer.state_dict(), os.path.join(work_path, 'best_optimizer.pdopt'))print(best_acc)paddle.save(model.state_dict(), os.path.join(work_path, 'final_model.pdparams'))paddle.save(optimizer.state_dict(), os.path.join(work_path, 'final_optimizer.pdopt'))

ShiftViT:采用简单高效的移位操作证明Attention是否必要 - 创想鸟

2.5 结果分析

In [21]

def plot_learning_curve(record, title='loss', ylabel='CE Loss'):    ''' Plot learning curve of your CNN '''    maxtrain = max(map(float, record['train'][title]))    maxval = max(map(float, record['val'][title]))    ymax = max(maxtrain, maxval) * 1.1    mintrain = min(map(float, record['train'][title]))    minval = min(map(float, record['val'][title]))    ymin = min(mintrain, minval) * 0.9    total_steps = len(record['train'][title])    x_1 = list(map(int, record['train']['iter']))    x_2 = list(map(int, record['val']['iter']))    figure(figsize=(10, 6))    plt.plot(x_1, record['train'][title], c='tab:red', label='train')    plt.plot(x_2, record['val'][title], c='tab:cyan', label='val')    plt.ylim(ymin, ymax)    plt.xlabel('Training steps')    plt.ylabel(ylabel)    plt.title('Learning curve of {}'.format(title))    plt.legend()    plt.show()

2.5.1 loss和acc曲线

In [22]

plot_learning_curve(loss_record, title='loss', ylabel='CE Loss')

In [23]

plot_learning_curve(acc_record, title='acc', ylabel='Accuracy')

In [24]

import timework_path = 'work/model'model = ShiftViT(n_div=12, embed_dim=96, depths=(3, 4, 9, 3), num_classes=10)model_state_dict = paddle.load(os.path.join(work_path, 'best_model.pdparams'))model.set_state_dict(model_state_dict)model.eval()aa = time.time()for batch_id, data in enumerate(val_loader):    x_data, y_data = data    labels = paddle.unsqueeze(y_data, axis=1)    with paddle.no_grad():        logits = model(x_data)bb = time.time()print("Throughout:{}".format(int(len(val_dataset)//(bb - aa))))
Throughout:794

2.5.2 预测与真实标签比较

In [25]

def get_cifar10_labels(labels):      """返回CIFAR10数据集的文本标签。"""    text_labels = [        'airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog',        'horse', 'ship', 'truck']    return [text_labels[int(i)] for i in labels]

In [26]

def show_images(imgs, num_rows, num_cols, pred=None, gt=None, scale=1.5):      """Plot a list of images."""    figsize = (num_cols * scale, num_rows * scale)    _, axes = plt.subplots(num_rows, num_cols, figsize=figsize)    axes = axes.flatten()    for i, (ax, img) in enumerate(zip(axes, imgs)):        if paddle.is_tensor(img):            ax.imshow(img.numpy())        else:            ax.imshow(img)        ax.axes.get_xaxis().set_visible(False)        ax.axes.get_yaxis().set_visible(False)        if pred or gt:            ax.set_title("pt: " + pred[i] + "ngt: " + gt[i])    return axes

In [27]

work_path = 'work/model'X, y = next(iter(DataLoader(val_dataset, batch_size=18)))model = ShiftViT(n_div=12, embed_dim=96, depths=(3, 4, 9, 3), num_classes=10)model_state_dict = paddle.load(os.path.join(work_path, 'best_model.pdparams'))model.set_state_dict(model_state_dict)model.eval()logits = model(X)y_pred = paddle.argmax(logits, -1)X = paddle.transpose(X, [0, 2, 3, 1])axes = show_images(X.reshape((18, 224, 224, 3)), 1, 18, pred=get_cifar10_labels(y_pred), gt=get_cifar10_labels(y))plt.show()
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).

3. 对比实验

Model Parameter Val Acc

ShiftViT146845540.93453Swin145415000.86659

注:Swin代码来自浅析 Swin Transformer,实验结果在main-Copy2.ipynb

总结

        本文用了一个简单的Shift操作证明了Vision Transformer中的Attention不是必要的,与Swin在参数可比的情况下精度高了0.06794(小数据集如CIFAR10上ShiftViT比Swin优势明显,在大数据集上ShiftViT与Swin性能差不多)

ShiftViT:采用简单高效的移位操作证明Attention是否必要 - 创想鸟

以上就是ShiftViT:采用简单高效的移位操作证明Attention是否必要的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/319801.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
开启内存XMP后系统不稳定
上一篇 2026年11月1日 09:37:49
币安交易所官网入口 币安官方热门版v3.10.0APP下载安装指南
下一篇 2025年12月11日 21:30:39

相关推荐

  • PDF在线去水印平台网址 PDF文件水印去除工具

    PDF在线去水印平台网址 PDF文件水印去除工具PDF在线去水印平台网址 PDF文件水印去除工具PDF在线去水印平台网址 PDF文件水印去除工具PDF在线去水印平台网址 PDF文件水印去除工具

    PDF在线去水印平台网址是https://www.pdf365.cn/,该平台提供无需安装软件的在线PDF处理服务,支持水印识别与移除、多格式转换及批量操作,采用自主解析内核确保内容完整性,界面简洁且兼容多设备,用户可便捷上传、预览并下载处理后的文件。 PDF在线去水印平台网址在哪里?这是不少网友都…

    2026年11月1日 • 用户投稿
    000
  • Swoole进阶:使用协程扩展PHP并发处理能力

    随着互联网技术的不断发展,对于php服务的高并发处理需求也越来越强烈,尤其是在web应用程序中。而swoole协程正是一个强大的扩展库,可以帮助php开发者轻松地实现高并发的处理。 Swoole是一款C语言编写的常驻内存型PHP协程框架,它提供了高效的多进程、多线程、异步IO等特性。Swoole的协…

    用户投稿 2026年11月1日
    000
  • 个人实现的反向文心(无需训练的AI看图说话,你不心动?)

    个人实现的反向文心(无需训练的AI看图说话,你不心动?)个人实现的反向文心(无需训练的AI看图说话,你不心动?)个人实现的反向文心(无需训练的AI看图说话,你不心动?)个人实现的反向文心(无需训练的AI看图说话,你不心动?)

    本文介绍ZeroCap的中文Paddle迁移实现,这是一个零样本图像描述模型。项目用Ernie-VIL替换原论文的CLIP,GPT采用中文版,涉及GPTChineseTokenizer、GPTLMHeadModel等模型。代码包含安装库、模型初始化、定义相关函数及生成文本等内容,还展示了效果示例,适…

    2026年11月1日 • 用户投稿
    100
  • safari浏览器怎么设置成中文界面_Safari浏览器语言切换与本地化设置

    safari浏览器怎么设置成中文界面_Safari浏览器语言切换与本地化设置safari浏览器怎么设置成中文界面_Safari浏览器语言切换与本地化设置safari浏览器怎么设置成中文界面_Safari浏览器语言切换与本地化设置safari浏览器怎么设置成中文界面_Safari浏览器语言切换与本地化设置

    首先调整系统语言设置以更改Safari界面语言,进入“系统设置”中的“语言与地区”,将简体或繁体中文拖至首选语言首位并重启浏览器;其次确保网站内容显示中文,需在系统及Safari的偏好设置中确认中文位于语言列表前列,使浏览器发送中文请求头;最后若语言异常,可重置Safari设置,清除历史记录与网站数…

    2026年11月1日 • 用户投稿
    000
  • 如何让VSCode识别Laravel Facade类 Laravel外观模式代码提示插件用法

    如何让VSCode识别Laravel Facade类 Laravel外观模式代码提示插件用法如何让VSCode识别Laravel Facade类 Laravel外观模式代码提示插件用法如何让VSCode识别Laravel Facade类 Laravel外观模式代码提示插件用法如何让VSCode识别Laravel Facade类 Laravel外观模式代码提示插件用法

    安装barryvdh/laravel-ide-helper开发依赖并注册服务提供者;2. 运行php artisan ide-helper:generate和ide-helper:meta生成辅助文件;3. 确保vscode安装php intelephense等插件以读取这些文件并提供准确代码提示,…

    2026年11月1日 • 用户投稿
    100
  • Steam新销量榜:《天外世界2》上榜《战地6》霸榜!

    Steam新销量榜:《天外世界2》上榜《战地6》霸榜!Steam新销量榜:《天外世界2》上榜《战地6》霸榜!Steam新销量榜:《天外世界2》上榜《战地6》霸榜!Steam新销量榜:《天外世界2》上榜《战地6》霸榜!

    Top 10榜单: 1、《战地6》 2、《超英派遣中心》 3、《我们到了吗?》 4、《逃离鸭科夫》 5、《ARC Raiders》 6、《足球经理26》 7、《侏罗纪世界:进化3》 商汤商量 商汤科技研发的AI对话工具,商量商量,都能解决。 36 查看详情 8、《天外世界2》 9、《EA SPORT…

    2026年11月1日 • 用户投稿
    100
  • 如何在MySQL中使用Python编写自定义存储过程、触发器和函数

    如何在MySQL中使用Python编写自定义存储过程、触发器和函数如何在MySQL中使用Python编写自定义存储过程、触发器和函数如何在MySQL中使用Python编写自定义存储过程、触发器和函数如何在MySQL中使用Python编写自定义存储过程、触发器和函数

    如何在MySQL中使用Python编写自定义存储过程、触发器和函数 数据库的存储过程、触发器和函数是一种强大的工具,可以帮助我们在数据库中实现一些复杂的操作和逻辑。在MySQL中,我们可以使用Python来编写自定义的存储过程、触发器和函数。本文将介绍如何在MySQL中使用Python完成这些任务,…

    2026年11月1日 • 用户投稿
    000
  • composer的“Installation failed, reverting ./composer.json”怎么解决_说明解决安装失败回滚composer.json的方法

    composer的“Installation failed, reverting ./composer.json”怎么解决_说明解决安装失败回滚composer.json的方法composer的“Installation failed, reverting ./composer.json”怎么解决_说明解决安装失败回滚composer.json的方法composer的“Installation failed, reverting ./composer.json”怎么解决_说明解决安装失败回滚composer.json的方法composer的“Installation failed, reverting ./composer.json”怎么解决_说明解决安装失败回滚composer.json的方法

    安装失败因环境或依赖问题导致,需查看错误日志,确认PHP版本、扩展、网络及权限,解决冲突后重试即可避免回滚。 当使用 Composer 安装或更新依赖时,出现 “Installation failed, reverting ./composer.json” 提示,说明安装过程…

    2026年11月1日 • 用户投稿
    000
  • 【情人节特辑】:虚拟女友教你如何正确“回答”

    【情人节特辑】:虚拟女友教你如何正确“回答”【情人节特辑】:虚拟女友教你如何正确“回答”【情人节特辑】:虚拟女友教你如何正确“回答”【情人节特辑】:虚拟女友教你如何正确“回答”

    该项目旨在通过技术手段将“直男话术”转化为高情商表达,以增进情侣感情。其核心是让虚拟女友纠正不当话语,具体步骤如下:首先,输入直男语句(如“多喝热水”)转换为对应编号的高情商表达;接着用Pixel2Pixel模型将卡通照片真人化;再将真人化照片输入PaddleBoBo生成女友动画;最后让虚拟女友纠正…

    2026年11月1日 • 用户投稿
    100
  • Python自学之路-安装与初步调试

    Python自学之路-安装与初步调试Python自学之路-安装与初步调试Python自学之路-安装与初步调试Python自学之路-安装与初步调试

    自从上一篇「python自学之路-前期准备」之后,现在正式踏上python的学习之路。首先当然是要安装开发环境了。 (一)选择Python2.x还是Python3.x 因为Python的两个版本互不兼容,2.x版本的第三方库较为齐全,但考虑到3.x版本如今已越来越普及,所以决定使用最新的3.5.x版…

    2026年11月1日 • 用户投稿
    100
  • 《DayZ》之父谈AI恐惧:就像当年害怕谷歌和互联网一样

    《DayZ》之父谈AI恐惧:就像当年害怕谷歌和互联网一样《DayZ》之父谈AI恐惧:就像当年害怕谷歌和互联网一样《DayZ》之父谈AI恐惧:就像当年害怕谷歌和互联网一样《DayZ》之父谈AI恐惧:就像当年害怕谷歌和互联网一样

    随着时间的推移,人工智能(ai)正在不断融入各行各业,游戏产业也不例外。长久以来,游戏开发者一直在运用ai技术来打造虚拟世界。然而,如今兴起的生成式ai相比以往的技术更为强大,同时也带来了更多潜在风险。包括微软、亚马逊和ea在内的科技与游戏巨头,已经开始削减人力成本(或正在考虑中),以腾出资源加大对…

    2026年11月1日 • 用户投稿
    100
  • 【Autoregressive】从0构造一个基于Paddle的自回归模型库

    【Autoregressive】从0构造一个基于Paddle的自回归模型库【Autoregressive】从0构造一个基于Paddle的自回归模型库【Autoregressive】从0构造一个基于Paddle的自回归模型库【Autoregressive】从0构造一个基于Paddle的自回归模型库

    本文展示基于Paddle构建自回归模型库PaddleAutoregressive的过程。先介绍自回归模型原理,说明其本质为线性模型组合。接着展示基础模块Autoregressive类的搭建,以此封装出AR模型,还介绍了数据读取、模型训练与预测的实现。最后说明将代码封装为库的方法,方便用户通过源码下载…

    2026年11月1日 • 用户投稿
    100
  • 远程办公项目管理软件有哪些_远程办公十大管理工具效率测评

    远程办公项目管理软件有哪些_远程办公十大管理工具效率测评远程办公项目管理软件有哪些_远程办公十大管理工具效率测评远程办公项目管理软件有哪些_远程办公十大管理工具效率测评远程办公项目管理软件有哪些_远程办公十大管理工具效率测评

    轻流适合自定义流程,禅道支持国产化信创,Asana优化跨时区协同,Jira专注研发全周期,板栗看板助力中小团队高效协作。 如果您正在为远程团队寻找合适的项目管理软件,面对分散的成员和复杂的任务流程,选择一个能集中管理、清晰追踪进度的工具至关重要。以下是针对不同需求场景的多种解决方案,帮助您高效组织远…

    2026年11月1日 • 用户投稿
    000
  • 电脑外设驱动更新

    电脑外设驱动更新电脑外设驱动更新电脑外设驱动更新电脑外设驱动更新

    常见的需要更新驱动的外设包括打印机、扫描仪、鼠标、键盘、摄像头、麦克风及游戏外设;可通过设备管理器、官网下载或厂商工具安全更新,注意备份驱动版本并避免第三方软件风险。 电脑外设驱动更新是保持设备正常运行和提升使用体验的重要操作。过时或损坏的驱动可能导致外设无法识别、功能异常或性能下降。定期检查并更新…

    2026年11月1日 • 用户投稿
    000
  • MAC系统声音图标是灰色的无法调节怎么办_MAC系统声音图标灰色解决方法

    MAC系统声音图标是灰色的无法调节怎么办_MAC系统声音图标灰色解决方法MAC系统声音图标是灰色的无法调节怎么办_MAC系统声音图标灰色解决方法MAC系统声音图标是灰色的无法调节怎么办_MAC系统声音图标灰色解决方法MAC系统声音图标是灰色的无法调节怎么办_MAC系统声音图标灰色解决方法

    声音图标变灰无法调节时,先检查音频输出设备并选择内置扬声器;若无效,通过终端命令sudo killall coreaudiod重启音频服务;仍无响应则重置NVRAM/PRAM;再排查第三方软件干扰,进入安全模式测试;最后创建新用户账户判断是否配置文件损坏,逐步恢复音频功能。 如果您在使用 Mac 时…

    2026年11月1日 • 用户投稿
    000
  • 显示器响应时间与刷新率如何共同影响动态清晰度?

    高刷新率与低响应时间协同决定动态清晰度,前者提升画面更新速度,后者减少拖影,二者缺一不可。 显示器的响应时间与刷新率,这两个参数就像是动态画面清晰度这枚硬币的两面,它们紧密协作,共同决定了我们肉眼所见的运动画面究竟有多么流畅和锐利。简单来说,高刷新率负责以更快的速度“送达”新画面,而低响应时间则保证…

    2026年11月1日
    100
  • 独家丨百川智能联合创始人谢剑将离职

    独家丨百川智能联合创始人谢剑将离职独家丨百川智能联合创始人谢剑将离职独家丨百川智能联合创始人谢剑将离职独家丨百川智能联合创始人谢剑将离职

    谢剑本科毕业于武汉大学人工智能专业,后继续深造并获得该校硕士学位。2012 年完成学业后,他加入百度,并在工作期间攻读博士学位,最终取得清华大学计算机科学方向的博士学位。他在百度集团内曾是最年轻的主任研发架构师之一,同时担任集团总技术委员会成员。 任职百度期间,谢剑深度参与了凤巢广告系统、搜索引擎以…

    2026年11月1日 • 用户投稿
    1500
  • 华为携多款明星产品闪耀2025中国移动大会:以技术创新定义智慧生活新范式

    华为携多款明星产品闪耀2025中国移动大会:以技术创新定义智慧生活新范式华为携多款明星产品闪耀2025中国移动大会:以技术创新定义智慧生活新范式华为携多款明星产品闪耀2025中国移动大会:以技术创新定义智慧生活新范式华为携多款明星产品闪耀2025中国移动大会:以技术创新定义智慧生活新范式

      当 “碳硅共生” 的理念与 “ai+” 的浪潮在广州琶洲保利世贸展馆交汇,2025中国移动全球合作伙伴大会便成了洞察科技未来的重要窗口。10月10日,作为中国移动的重要合作伙伴,华为以800平方米的展区(4 号馆 4e – 01)为舞台,将 “1 + 8 + n” 全场景智慧生活解决…

    2026年11月1日 • 用户投稿
    100
  • laravel怎么配置计划任务定时执行_laravel计划任务配置方法

    Laravel通过Kernel.php定义计划任务,需配置系统Cron每分钟执行schedule:run,支持多种频率方法与日志记录,可手动测试任务生效情况。 如果您希望在 Laravel 应用中自动执行某些命令或脚本,例如定时清理日志、发送邮件通知或同步数据,可以通过配置计划任务来实现。Larav…

    2026年11月1日
    100
  • composer fund命令是做什么用的

    composer fund命令是做什么用的composer fund命令是做什么用的composer fund命令是做什么用的composer fund命令是做什么用的

    composer fund 是 Composer 2.0 引入的可选命令,用于展示项目依赖中支持资金赞助的开源包及其赞助链接,如 GitHub Sponsors 或 Open Collective,提高用户对开源维护者的支持意识,不执行任何安装或更新操作,仅作信息展示。 Composer 并没有 f…

    2026年11月1日 • 用户投稿
    000

发表回复

登录后才能评论
关注微信