基于飞桨实现乒乓球时序动作定位大赛 :B榜第12名方案


该方案基于飞桨实现乒乓球时序动作定位,获B榜第12名。采用宽4s滑窗分割视频为100帧数据,改进BMN模型,将TEM改为双分支融合输出,用DIOU-soft-NMS替代Soft-NMS避免漏检。经数据处理、模型训练与推理,A榜得分44.45754,B榜45.22373,还提出了后续改进方向。

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

基于飞桨实现乒乓球时序动作定位大赛 :b榜第12名方案 -

基于飞桨实现乒乓球时序动作定位大赛 :B榜第12名方案

赛题介绍

在众多大规模视频分析情景中,从冗长未经修剪的视频中定位并识别短时间内发生的人体动作成为一个备受关注的课题。当前针对人体动作检测的解决方案在大规模视频集上难以奏效,高效地处理大规模视频数据仍然是计算机视觉领域一个充满挑战的任务。其核心问题可以分为两部分,一是动作识别算法的复杂度仍旧较高,二是缺少能够产生更少视频提案数量的方法(更加关注短时动作本身的提案)。

这里所指的视频动作提案是指一些包含特定动作的候选视频片段。为了能够适应大规模视频分析任务,时序动作提案应该尽可能满足下面两个需求: (1)更高的处理效率,例如可以设计出使时序视频片段编码和打分更高效的机制; (2)更强的判别性能,例如可以准确定位动作发生的时间区间。

本次比赛旨在激发更多的开发者和研究人员关注并参与有关视频动作定位的研究,创建性能更出色的动作定位模型。

数据集介绍

本次比赛的数据集包含了19-21赛季兵乓球国际比赛(世界杯、世锦赛、亚锦赛,奥运会)和国内比赛(全运会,乒超联赛)中标准单机位高清转播画面的特征信息,共包含912条视频特征文件,每个视频时长在0~6分钟不等,特征维度为2048,以pkl格式保存。我们对特征数据中面朝镜头的运动员的回合内挥拍动作进行了标注,单个动作时常在0~2秒不等,训练数据为729条标注视频,A测数据为91条视频,B测数据为92条视频,训练数据标签以json格式给出。

本赛题中的数据包含912条ppTSM抽取的视频特征,特征保存为pkl格式,文件名对应视频名称,读取pkl之后以(num_of_frames, 2048)向量形式代表单个视频特征。其中num_of_frames是不固定的,同时数量也比较大,所以pkl的文件并不能直接用于训练。同时由于乒乓球每个动作时间非常短,为了可以让模型更好的识别动作,所以需要将数据进行分割。

思路介绍

  • 本赛题的视频数据帧数不固定,单个pkl文件包含的乒乓球动作数量也不固定,参考BMN_tabletennis的数据分割方式,使用宽4s的滑窗,把每一个视频里的动作片段提取出来,分割为4X25=100帧的数据。
  • 本项目基于BMN模型开发,借鉴TVNet中对TEM模块的改进思路,将TEM改成双分支融合后直接输出xs\xe的思路。
  • 改进了删除冗余proposal的策略,将原本的Soft-NMS改进为DIOU-soft-NMS,避免漏检。

具体方案分享

  1. 整体流程框图

基于飞桨实现乒乓球时序动作定位大赛 :B榜第12名方案 -

  1. BMN模型结构

基于飞桨实现乒乓球时序动作定位大赛 :B榜第12名方案 -

  1. TEM模块改进

基于飞桨实现乒乓球时序动作定位大赛 :B榜第12名方案 -

BMN中原本的TEM实现为两个分支单独进行xs和xe的预测,考虑到一个动作的起止互相是具有强关联性的,起始时间和终止时间的特征应该共同用于预测,因此改进后的TEM模块先通过两个分支分别提取起始时间和终止时间相关的特征,再将特征进行融合最后预测输出。

  1. DIOU-soft-NMS

原本的Soft-NMS采用IOU来表示proposal的重叠程度以判断冗余性,而预测过程中可能出现强包含关系如下图所示:

基于飞桨实现乒乓球时序动作定位大赛 :B榜第12名方案 -

p1与p2、p3具有相同的重叠度,但很明显p1与p2中心点重合大概率为同一动作的不同保守程度的估计,而p1与p3中心点偏离较大,可以认为是两个不同的动作。

为了避免漏检p3这样的动作,本项目采用diou来替代iou进行非极大值抑制,diou的计算公式如下:

基于飞桨实现乒乓球时序动作定位大赛 :B榜第12名方案 -

其中ρ(·)是两proposal中心点的欧几里得距离,c是覆盖两个proposal的最小时间长度。

Openflow Openflow

一键极速绘图,赋能行业工作流

Openflow 88 查看详情 Openflow

代码运行与训练测试

  1. 首先解压数据集 执行以下命令解压数据集,解压之后将压缩包删除,保证项目空间小于100G。否则项目会被终止。
In [1]
%cd /home/aistudio/data/
!tar xf data122998/Features_competition_train.tar.gz
!tar xf data123004/Features_competition_test_A.tar.gz
!tar xf data123009/Features_competition_test_B.tar.gz
!cp data122998/label_cls14_train.json .
!rm -rf data12*
/home/aistudio/data
In [2]
import osimport sysimport jsonimport randomimport pickleimport numpy as np
  1. 解压好数据之后,首先对label标注文件进行分割。本赛题的视频数据帧数不固定,单个pkl文件包含的乒乓球动作数量也不固定,参考BMN_tabletennis的数据分割方式,使用宽4s的滑窗,把每一个视频里的动作片段提取出来,分割为4X25=100帧的数据。
In [3]
source_path = "/home/aistudio/data/label_cls14_train.json"
In [ ]
import jsonwith open('/home/aistudio/data/label_cls14_train.json') as f:
   data = json.load(f)
f.close()
In [5]
#按照9:1划分训练 测试集l=len(data['gts'])
l=int(l*0.1)
val = {'gts': data['gts'][0:l], 'fps': 25}
jsonString = json.dumps(val, indent=4, ensure_ascii=False)
jsonFile = open('/home/aistudio/data/label_cls14_val.json', 'w')
jsonFile.write(jsonString)
jsonFile.close()

train = {'gts': data['gts'][l:], 'fps': 25}
jsonString = json.dumps(train, indent=4, ensure_ascii=False)
jsonFile = open('/home/aistudio/data/label_cls14_train.json', 'w')
jsonFile.write(jsonString)
jsonFile.close()
In [6]
"""
get instance for bmn
使用winds=4的滑窗,将所有子窗口的长度之和小于winds的进行合并
合并后,父窗口代表bmn训练数据,子窗口代表tsn训练数据
"""import osimport sysimport jsonimport randomimport pickleimport numpy as npimport math# for table tennisbmn_window = 4dataset = "/home/aistudio/data"feat_dir = dataset + '/Features_competition_train'out_dir = dataset + '/Input_for_bmn'label_files = {    'train': 'label_cls14_train.json',    'validation': 'label_cls14_val.json'}global fpsdef gen_gts_for_bmn(gts_data):
    """
    @param, gts_data, original gts for action detection
    @return, gts_bmn, output gts dict for bmn
    """
    fps = gts_data['fps']
    gts_bmn = {'fps': fps, 'gts': []}    for sub_item in gts_data['gts']:
        url = sub_item['url']

        max_length = sub_item['total_frames']

        gts_bmn['gts'].append({            'url': url,            'total_frames': max_length,            'root_actions': []
        })
        sub_actions = sub_item['actions']        # 跳过没有动作的片段
        if len(sub_actions) == 0:            continue
        # duration > bmn_window, 动作持续时间大于bmn_windows,直接删除
        for idx, sub_action in enumerate(sub_actions):            if sub_action['end_id'] - sub_action['start_id'] > bmn_window:
                sub_actions.pop(idx)        # 【滑动窗口,把每一个视频里的动作片段提取出来】
        root_actions = [sub_actions[0]]        # before_id, 前一动作的最后一帧
        # after_id, 后一动作的第一帧
        before_id = 0
        for idx in range(1, len(sub_actions)):
            cur_action = sub_actions[idx]
            duration = (cur_action['end_id'] - root_actions[0]['start_id'])            if duration > bmn_window:  # windows只能包住一个动作就包,包不住就包多个
                after_id = cur_action['start_id']
                gts_bmn['gts'][-1]['root_actions'].append({                    'before_id':
                    before_id,                    'after_id':
                    after_id,                    'actions':
                    root_actions
                })
                before_id = root_actions[-1]['end_id']  #更新滑窗
                root_actions = [cur_action]            else:
                root_actions.append(cur_action)            if idx == len(sub_actions) - 1:
                after_id = max_length
                gts_bmn['gts'][-1]['root_actions'].append({                    'before_id':
                    before_id,                    'after_id':
                    after_id,                    'actions':
                    root_actions
                })    return gts_bmndef combile_gts(gts_bmn, gts_process, mode):
    """
    1、bmn_window 范围内只有一个动作,只取一个目标框
    2、bmn_window 范围内有多个动作,取三个目标框(第一个动作、最后一个动作、所有动作)
    """
    global fps
    fps = gts_process['fps']
    duration_second = bmn_window * 1.0
    duration_frame = bmn_window * fps
    feature_frame = duration_frame    for item in gts_process['gts']:
        url = item['url']
        basename = os.path.basename(url).split('.')[0]
        root_actions = item['root_actions']        # 把每一个视频里的动作片段提取出来
        for root_action in root_actions:
            segments = []            # all actions
            segments.append({                'actions': root_action['actions'],                'before_id': root_action['before_id'],                'after_id': root_action['after_id']
            })            if len(root_action['actions']) > 1:  #如果有多个动作,则第一个动作和最后一个动作,额外添加一次
                # first action
                segments.append({                    'actions': [root_action['actions'][0]],                    'before_id':
                    root_action['before_id'],                    'after_id':
                    root_action['actions'][1]['start_id']
                })                # last action
                segments.append({                    'actions': [root_action['actions'][-1]],                    'before_id':
                    root_action['actions'][-2]['end_id'],                    'after_id':
                    root_action['after_id']
                })            # 把动作片段处理成window size大小,以适配BMN输入
            for segment in segments:
                before_id = segment['before_id']
                after_id = segment['after_id']
                actions = segment['actions']                # before_id到after_id太长了,从里面取window_size帧,要先确定一个起始点,然后动作都要包住
                box0 = max(actions[-1]['end_id'] - bmn_window,
                           before_id)  #确定起始点
                box1 = min(actions[0]['start_id'],
                           after_id - bmn_window)  #确实起始点
                if box0 <= box1:  # 一次检查
                    if int(box0) - int(box1) == 0:
                        cur_start = box0                    else:
                        box0 = math.ceil(box0)
                        box1 = int(box1)
                        cur_start = random.randint(box0, box1)
                    cur_end = cur_start + bmn_window
                    cur_start = round(cur_start, 2)
                    cur_end = round(cur_end, 2)
                    name = '{}_{}_{}'.format(basename, cur_start, cur_end)
                    annotations = []                    for action in actions:
                        label = str(1.0 * action['label_ids'][0])
                        label_name = action['label_names'][0]
                        seg0 = 1.0 * round((action['start_id'] - cur_start),                                           2)  #存储的是到开始位置(时间: s)的距离
                        seg1 = 1.0 * round((action['end_id'] - cur_start), 2)
                        annotations.append({                            'segment': [seg0, seg1],                            'label': label,                            'label_name': label_name
                        })
                    gts_bmn[name] = {                        'duration_second': duration_second,                        'duration_frame': duration_frame,                        'feature_frame': feature_frame,                        'subset': mode,                        'annotations': annotations
                    }    return gts_bmndef s*e_feature_to_numpy(gts_bmn, folder):
    global fps    print('s*e feature for bmn ...')    if not os.path.exists(folder):
        os.mkdir(folder)
    process_gts_bmn = {}
    miss = 0
    for item, value in gts_bmn.items():        # split to rsplit 针对文件命名修改
        basename, start_id, end_id = item.rsplit('_', 2)        if not basename in process_gts_bmn:
            process_gts_bmn[basename] = []
        process_gts_bmn[basename].append({            'name': item,            'start': float(start_id),            'end': float(end_id)
        })    for item, values in process_gts_bmn.items():
        feat_path = os.path.join(feat_dir, item + '.pkl')
        feature_video = pickle.load(open(feat_path, 'rb'))['image_feature']        for value in values:
            s*e_cut_name = os.path.join(folder, value['name'])
            a, b, c = s*e_cut_name.rsplit('_', 2)            if float(b) > 360:                print(b)
            start_frame = round(value['start'] * fps)
            end_frame = round(value['end'] * fps)            if end_frame > len(feature_video):
                miss += 1
                continue
            feature_cut = [
                feature_video[i] for i in range(start_frame, end_frame)
            ]
            np_feature_cut = np.array(feature_cut, dtype=np.float32)
            np.s*e(s*e_cut_name, np_feature_cut)    print('miss number (broken sample):', miss)if __name__ == "__main__":    if not os.path.exists(out_dir):
        os.mkdir(out_dir)
    gts_bmn = {}    for item, value in label_files.items():
        label_file = os.path.join(dataset, value)
        gts_data = json.load(open(label_file, 'rb'))
        gts_process = gen_gts_for_bmn(gts_data)
        gts_bmn = combile_gts(gts_bmn, gts_process, item)    with open(out_dir + '/label.json', 'w', encoding='utf-8') as f:
        data = json.dumps(gts_bmn, indent=4, ensure_ascii=False)
        f.write(data)

    s*e_feature_to_numpy(gts_bmn, out_dir + '/feature')
s*e feature for bmn ...
miss number (broken sample): 116
In [7]
import copyimport jsonimport reimport os

url = '/home/aistudio/data/Input_for_bmn/feature/'directory = os.fsencode(url)
count = 0target_set = []for file in os.listdir(directory):
    filename = os.fsdecode(file)
    target_name = filename.split('.npy')[0]
    target_set.append(target_name)
    count += 1print('Feature size:', len(target_set))with open('/home/aistudio/data/Input_for_bmn/label.json') as f:
    data = json.load(f)

delet_set = []for key in data.keys():    if not key in target_set:
        delet_set.append(key)print('(Label) Original size:', len(data))print('(Label) Deleted size:', len(delet_set))for item in delet_set:
    data.pop(item, None)print('(Label) Fixed size:', len(data))

jsonString = json.dumps(data, indent=4, ensure_ascii=False)
jsonFile = open('/home/aistudio/data/Input_for_bmn/label_fixed.json', 'w')
jsonFile.write(jsonString)
jsonFile.close()
Feature size: 19712
(Label) Original size: 19828
(Label) Deleted size: 116
(Label) Fixed size: 19712

执行完毕后,在data/Input_for_bmn/目录中生成了新的标注文件label_fixed.json。下面开始分割训练集和测试集的数据。

  1. 执行以下脚本,分割训练集。
In [8]
!rm /home/aistudio/data/Features_competition_train/*.pkl

执行后在data/Features_competition_train/npy目录下生成了训练用的numpy数据。

In [3]
import osimport os.path as ospimport globimport pickleimport paddleimport numpy as np

file_list = glob.glob("/home/aistudio/data/Features_competition_test_B/*.pkl")

max_frames = 9000npy_path = ("/home/aistudio/data/Features_competition_test_B/npy/")if not osp.exists(npy_path):
    os.makedirs(npy_path)for f in file_list:
    video_feat = pickle.load(open(f, 'rb'))
    tensor = paddle.to_tensor(video_feat['image_feature'])
    pad_num = 9000 - tensor.shape[0]
    pad1d = paddle.nn.Pad1D([0, pad_num])
    tensor = paddle.transpose(tensor, [1, 0])
    tensor = paddle.unsqueeze(tensor, axis=0)
    tensor = pad1d(tensor)
    tensor = paddle.squeeze(tensor, axis=0)
    tensor = paddle.transpose(tensor, [1, 0])

    sps = paddle.split(tensor, num_or_sections=90, axis=0)    for i, s in enumerate(sps):
        file_name = osp.join(npy_path, f.split('/')[-1].split('.')[0] + f"_{i}.npy")
        np.s*e(file_name, s.detach().numpy())    pass
W0228 15:00:00.428351   176 device_context.cc:447] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 11.0, Runtime API Version: 10.1
W0228 15:00:00.432513   176 device_context.cc:465] device: 0, cuDNN Version: 7.6.

训练模型

数据集分割好之后,可以开始训练模型,使用以下命令进行模型训练。首先需要安装PaddleVideo的依赖包。

In [ ]
# 从Github上下载PaddleVideo代码# %cd ~/work/# 从Github上下载PaddleVideo代码# !git clone https://github.com/PaddlePaddle/PaddleVideo.git
In [ ]
%cd /home/aistudio/PaddleVideo/
!pip install -r requirements.txt

开始训练模型。 在/home/aistudio/work/PaddleVideo/applications/TableTennis/configs/bmn_tabletennis.yaml文件中更改文件的路径

DATASET:                                            #DATASET field  batch_size: 16                                 #single card bacth size  test_batch_size: 1  num_workers: 8  train:    format: "BMNDataset"    file_path: "/home/aistudio/data/Input_for_bmn/label_fixed.json"    subset: "train"  valid:    format: "BMNDataset"    file_path: "/home/aistudio/data/Input_for_bmn/label_fixed.json"    subset: "validation"  test:    format: "BMNDataset"    test_mode: True    file_path: "/home/aistudio/work/BMN/Input_for_bmn/label_fixed.json"    subset: "validation"
PIPELINE:                                           #PIPELINE field
  train:                                            #Mandotary, indicate the pipeline to deal with the training data
    load_feat:
      name: "LoadFeat"
      feat_path: "/home/aistudio/data/Input_for_bmn/feature"
    transform:                                      #Mandotary, image transfrom operator
      - GetMatchMap:
          tscale: 100
      - GetVideoLabel:
          tscale: 100
          dscale: 100

  valid:                                            #Mandotary, indicate the pipeline to deal with the training data
    load_feat:
      name: "LoadFeat"
      feat_path: "/home/aistudio/data/Input_for_bmn/feature"
    transform:                                      #Mandotary, image transfrom operator
      - GetMatchMap:
          tscale: 100
      - GetVideoLabel:
          tscale: 100
          dscale: 100
In [ ]
%cd /home/aistudio/PaddleVideo/#!python main.py -c  configs/localization/bmn.yaml!python -B main.py  --validate -c  applications/TableTennis/configs/bmn_tabletennis.yaml

实际共训练了18个epoch。 基于飞桨实现乒乓球时序动作定位大赛 :B榜第12名方案 -

模型导出

将训练好的模型导出用于推理预测,执行以下脚本。

In [5]
%cd /home/aistudio/
!python PaddleVideo/tools/export_model.py -c  PaddleVideo/applications/TableTennis/configs/bmn_tabletennis.yaml -p  PaddleVideo/output/BMN/BMN_epoch_00018.pdparams -o PaddleVideo/inference/BMN
/home/aistudio
Building model(BMN)...
W0228 15:04:40.308302   894 device_context.cc:447] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 11.0, Runtime API Version: 10.1
W0228 15:04:40.312518   894 device_context.cc:465] device: 0, cuDNN Version: 7.6.
Loading params from (PaddleVideo/output/BMN/BMN_epoch_00018.pdparams)...
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/layers/utils.py:77: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  return (isinstance(seq, collections.Sequence) and
model (BMN) has been already s*ed in (PaddleVideo/inference/BMN).

推理预测

使用导出的模型进行推理预测,执行以下命令。

In [ ]
%cd /home/aistudio/PaddleVideo/
!python tools/predict.py --input_file /home/aistudio/data/Features_competition_test_B/npy \
 --config configs/localization/bmn.yaml \
 --model_file inference/BMN/BMN.pdmodel \
 --params_file inference/BMN/BMN.pdiparams \
 --use_gpu=True \
 --use_tensorrt=False

基于飞桨实现乒乓球时序动作定位大赛 :B榜第12名方案 -

上面程序输出的json文件是分割后的预测结果,还需要将这些文件组合到一起。执行以下脚本:

In [6]
import osimport jsonimport glob

json_path = "/home/aistudio/data/Features_competition_test_B/npy/"json_files = glob.glob(os.path.join(json_path, '*_*.json'))
In [7]
len(json_files)
8190
In [8]
submit_dic = {"version": None,              "results": {},              "external_data": {}
              }
results = submit_dic['results']for json_file in json_files:
    j = json.load(open(json_file, 'r'))
    old_video_name = list(j.keys())[0]
    video_name = list(j.keys())[0].split('/')[-1].split('.')[0]
    video_name, video_no = video_name.split('_')
    start_id = int(video_no) * 4
    if len(j[old_video_name]) == 0:        continue
    for i, top in enumerate(j[old_video_name]):        if video_name in results.keys():
            results[video_name].append({'score': round(top['score'], 2),                                        'segment': [round(top['segment'][0] + start_id, 2), round(top['segment'][1] + start_id, 2)]})        else:
            results[video_name] = [{'score':round(top['score'], 2),                                        'segment': [round(top['segment'][0] + start_id, 2), round(top['segment'][1] + start_id, 2)]}]

json.dump(submit_dic, open('/home/aistudio/submission.json', 'w', encoding='utf-8'))

最后会在用户目录生成submission.json文件,压缩后下载提交即可。

In [9]
%cd /home/aistudio/
!zip submission.zip submission.json
/home/aistudio
updating: submission.json (deflated 91%)

最终A榜得分44.45754, B榜得分45.22373

总结和改进思路

  1. 尝试了SSTAP中的"Temporal feature shift"进行数据扩增,效果不增反降,可能是使用方法不对。

基于飞桨实现乒乓球时序动作定位大赛 :B榜第12名方案 -

  1. BMN输出的proposal后处理方法只采用了不可学习的NMS方法,没有尝试引入Softer-nms等。

  2. 没有引入PGCN等图神经网络对Proposal进行后处理,或许可以提高效果。

以上就是基于飞桨实现乒乓球时序动作定位大赛 :B榜第12名方案的详细内容,更多请关注其它相关文章!


# 中心点  # 山西seo优化定制  # 网站建设外包是指  # 卢保林seo  # 衡阳网站建设总结与体会  # 推广营销百度云  # 牛仔裤营销推广计划书  # 四川SEO优化规则  # 如何推广滑雪场景营销  # 三级seo综合查询  # 内衣推广营销策略研究论文  # 第一个  # 成了  # 时长  # 也不  # 把每  # python  # 多个  # 一言  # 中文网  # type  # fig  # udio  # operator  # 视频时长  # 征信  # igs  # red  # ai  # windows  # git 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894


相关推荐: 人工智能和你聊天 成本有多高  猿辅导推出Motiff,整合三大AI功能,助力UI设计生产力革新  马斯克反讽人工智能AI炒作:“机器学习”本质就是统计  ChatGPT只讲这25个笑话!实验上千次有90%重复,网友:幽默是人类最后的尊严  大型无人机FH-98国内首次夜航转场成功  出门问问亮相2025世界人工智能大会,展示AI CoPilot解决方案  新华三集团总裁兼首席执行官于英涛:人工智能时代需要想象力,更需要精耕务实  击败LLaMA?史上超强「猎鹰」排行存疑,符尧7行代码亲测,LeCun转赞  华为发布两款AI存储新品  Transformer六周年:当年连NeurIPS Oral都没拿到,8位作者已创办数家AI独角兽  第四范式“式说”大模型入选《2025年通用人工智能创新应用案例集》  DreamAvatar数字人使用教程  明略科技发布免费开源TensorBoard.cpp,促进大型模型的预训练工作  人工智能进入绿植界,智能庭院市场初具规模  天翼云在国际AI顶会大模型挑战赛中获得冠军  苹果CEO库克:持续研究生成式人工智能技术  调研海尔智家:AI名,家电命?  无人机在电力巡检中的应用:全面解析高效巡检流程  研究发现AI聊天机器人ChatGPT不会讲笑话,只会重复25个老梗  比尔盖茨:AI确实存在风险,但可控  AI创作广告文案等同2.47年工作经验,且消费者无法区分|AI营销前沿  电池比 Air 2S 大 20%,大疆 Air 3 无人机现身 FCC  人工智能自己玩自己  应用生成式人工智能技术改善农业产业  百度举办AIGC创作沙龙,现场传授AI绘画“咒语”技巧  对话式论文阅读工具PaperMate上线,综述细节AI告诉你  猿力科技入选北京市通用人工智能产业创新伙伴计划  无人机巡检方案是什么,该如何选择适合的巡检方案  国网辉南供电:无人机空中巡检 全力护航端午佳节  人工智能助力精准学习,猿辅导小猿学练机满足学生个性化学习需求  ​布局智能物联新时代,中国移动“5G+物联网”亮相2025 MWC  从GOXR到PartyOn,XRSPACE致力打造多元共赢的元宇宙世界  面向AI大模型,腾讯云首次完整披露自研星脉高性能计算网络  70年前他本想逃避考试,却影响了整个互联网  Win11 的画图应用将包含 Windows Copilot 的 AI 工具整合  美版贴吧8000小组自爆停摆!拒绝数据被谷歌OpenAI白嫖,CEO被网友骂翻:背刺第三方应用  灯塔AI大模型票房预测上线:开源算法不断提升精准度  当一切设备都受到人工智能的控制  Snap宣布研发出新技术 可大幅提升AI生成图像速度  传字节内测对话式 AI 产品,代号「Grace」;马斯克嘲讽苹果 头显;比亚迪 F 品牌定名「方程豹」  发布最新版本的 PICO OS 5.7.0:支持VR头盔录屏并跨平台分享至微信  重塑未来生活的五项技术趋势  Snow Kylin登陆中国列车,打造全球首条元宇宙专列  Vision Pro 太贵,苹果基于 iPhone 的 VR 头显专利曝光  实现人工智能和物联网的协同运作  AI室内设计软件流行,室内设计行业如何应对效率变革  令人惊叹!AI模型能够以iPhone照片为基础创作诗歌  静安大宁功能区企业云天励飞亮相2025世界人工智能大会,秀出AI硬实力!  人工智能即将进入Windows:企业准备好安全策略设置了吗?  Meta推出VR订阅服务Quest +:每月免费玩两款游戏,7.99美元/月 

 2025-08-01

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.