范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

用TensorFlow训练midi文件实现AI作曲

  想让 AI  学会作曲,首先要找到一批音乐样本,让它学。
  AI  作曲,遵循"种瓜得瓜,种豆得豆"的原则:你给它训练什么风格的样本,它最终就会生成什么风格的音乐。
  因此,我们需要找一些轻松活泼的音乐,这适合新年播放。
  音乐文件的格式,我们选择 MIDI  格式。MIDI  的全称是:Musical Instrument Digital Interface  ,翻译成中文就是:乐器数字接口。
  这是一种什么格式?为什么会有这种格式呢?
  话说,随着计算机的普及,电子乐器也出现了。电子乐器的出现,极大地节省了成本,带来了便利。
  基本上有一个电子乐器,世间的乐器就都有了。
  这个按钮是架子鼓,那个按钮是萨克斯。而在此之前,你想要发出这类声音,真的得敲架子鼓或者吹萨克斯管。
  而且还有更为放肆的事情。你想用架子鼓一秒敲五下,得有专业的技能。但是用电子乐器,一秒敲五十下也毫不费力,因为程序就给搞定了。
  这些新生事物的出现,常常让老艺术家们口吐鲜血。
  电子乐器既然可以演奏音乐,那么就有乐谱。这乐谱还得有标准,因为它得在所有电子乐器中都起作用。这个"计算机能理解的乐谱",就是 MIDI  格式。
  下面我们就来解析一下 MIDI  文件。看看它的结构是怎么样的。
  我找到一个机器猫(哆啦A梦)的主题曲,采用 python  做一下解析:import pretty_midi # 加载样本文件 pm = pretty_midi.PrettyMIDI("jqm.midi")  # 循环乐器列表 for i, instrument in enumerate(pm.instruments):   instrument_name = pretty_midi.program_to_instrument_name(instrument.program)   print(i,  instrument_name) # 输出乐器名称
  这个音乐,相信大家都很熟悉,就是:哦、哦、哦,哆啦A梦和我一起,让梦想发光……
  通过 pretty_midi  库加载MIDI  文件,获取它的乐器列表pm.instruments  ,打印如下:
  Acoustic Grand Piano(原声大钢琴)、Glockenspiel(钢片琴)、String Ensemble(弦乐合奏) 、Muted Trumpet(闷音小号)、Trombone(长号)、Electric Bass(电贝斯)、Acoustic Guitar(原声吉他)、Flute(长笛)、Acoustic Grand Piano(原声大钢琴)、Harmonica(口琴)、Vibraphone(电颤琴)、Bagpipe(苏格兰风笛)、Marimba(馬林巴琴)……
  我们看到,短短一个片头曲,就动用了近 20  种乐器。如果不是专门分析它,我们还真的听不出来呐。
  那么,每种乐器的音符可以获取到吗?我们来试试: # 承接上个代码片段,假设选定了乐器instrument for j, note in enumerate(instrument.notes):     # 音高转音符名称     note_name = pretty_midi.note_number_to_name(note.pitch)     info = ("%s:%.2f->%.2f")%(note_name, note.start, note.end)
  打印如下: Acoustic Grand Piano
  F#3:1.99->2.04 F#2:1.98->2.06 E2:1.99->2.07 C2:1.98->2.08 F#3:2.48->2.53 F#2:2.48->2.56 F#3:2.98->3.03 F#2:2.98->3.06 ……
  通过获取 instrument  的notes  ,可以读到此乐器的演奏信息。包含:pitch  音高,start  开始时间,end  结束时间,velocity  演奏力度。
  名称
  pitch
  start
  end
  velocity
  示例
  24
  1.98   2.03   82
  解释   音高(C1、C2)   开始时间   结束时间   力度   范围   128个音高   单位为秒   单位为秒   最高100   上面的例子中, F#3:1.99->2.04 表示:音符F#3 ,演奏时机是从1.99 秒到2.04 秒。   如果把这些数据全都展开,其实挺壮观的,应该是如下这样:   其实, MIDI 文件对于一首乐曲来说,就像是一个程序的源代码,也像是一副药的配方。MIDI 文件里,描述了乐器的构成,以及该乐器的演奏数据。   这类文件要比 WAV 、MP3 这些波形文件小得多。一段30 分钟钢琴曲的MIDI 文件,大小一般不超过100KB 。   因此,让人工智能去学习 MIDI 文件,并且实现自动作曲,这是一个很好的选择。实战:TensorFlow实现AI作曲   我在 datasets 目录下,放了一批节奏欢快的MIDI 文件。   这批文件,除了节奏欢快适合在新年播放,还有一个特点:全部是钢琴曲。也就是说,如果打印他的乐器的话,只有一个,那就是: Acoustic Grand Piano (原声大钢琴)。   这么做降低了样本的复杂性,仅需要对一种乐器进行训练和预测。同时,当它有朝一日练成了 AI 作曲神功,你也别妄想它会锣鼓齐鸣,它仍然只会弹钢琴。   多乐器的复杂训练当然可行。但是目前在业内,还没有足够的数据集来支撑这件事情。   开搞之前,我们必须得先通盘考虑一下。不然,我们都不知道该把数据搞成么个形式。   AI 作曲,听起来很高端。其实跟文本生成、诗歌生成,没有什么区别。我之前讲过很多相关的例子《NLP实战:基于LSTM自动生成原创宋词》《NLP实战:基于GRU的自动对春联》《NLP实战:基于RNN的自动藏头诗》。如果感兴趣,大家可以先预习一下。不看也不要紧,后面我也会简单描述,但深度肯定不如上面的专项介绍。   利用 RNN ,生成莎士比亚文集,是NLP 领域的HelloWorld 入门程序。那么,AI 作曲,只不过是引入了音乐的概念。另外,在出入参数上,维度也丰富了一些。但是,从本质上讲,它还是那一套思路。   所有 AI 自动生成的模式,基本上都是给定一批输入值+ 输出值。然后,让机器去学习,自己找规律。最后,学成之后,再给输入,让它自己预测出下一个值。   举个例子,莎士比亚文集的生成,样本如下: First Citizen:   Before we proceed any further, hear me speak.   All:   Speak, speak.   它是如何让 AI 训练和学习呢?其实,就是从目前的数据不断观察,观察出现下一个字符的概率。   当前   下一个   经验值   F   i   Fi   r   Fir   s   Firs   t   ……   ……   ……   F 后面大概率会出现i 。如果现在是Fi ,那么它的后面该出现r 了。这些,AI 作为经验记了下了。   这种记录概率的经验,在少量样本的情况下,是无意义的。   但是,当这个样本变成人类语言库的时候,那么这个概率就是语法规范,就是上帝视角。   举个例子,当我说:冬天了,窗外飘起了__!   你猜,飘起了什么?是的,窗外飘起了雪。   当 AI 分析过人类历史上,出现过的所有语言之后。当它进行数据分析的时候,最终它会计算出:在人类的语言库里,冬天出现飘雪花的情况,要远远高于冬天飘落叶的情况。所以,它肯定也会告诉你那个空该填:雪花。   这就是 AI 自动作词、作曲、作画的本质。它的技术支撑是带有链式的循环神经网络(RNN ),数据支撑就是大量成型的作品。 准备:构建数据集   首先,读取这些数据,然后把它们加工成输入 input 和输出output 。   展开一个 MIDI 文件,我们再来看一下原始数据:Note(start=1.988633, end=2.035121, pitch=54, velocity=82), Note(start=1.983468, end=2.060947, pitch=42, velocity=78), Note(start=2.479335, end=2.525823, pitch=54, velocity=82)……   我们可以把前几组,比如前 24 组音符数据作为输入,然后第25 个作为预测值。后面依次递推。把这些数据交给AI ,让它研究去。   训练完成之后,我们随便给 24 个音符数据,让它预测第25 个。然后,再拿着2~25 ,让它预测第26 个,以此循环往后,连绵不绝。   这样可以吗?   可以(能训练)。但存在问题(结果非所愿)。   在使用循环神经网络的时候,前后之间要带有通用规律的联系。比如:前面有"冬天"做铺垫,后面遇到"飘"时,可以更准确地推测出来是"飘雪"。   我们看上面的数据,假设我们忽略 velocity (力度)这个很专业的参数。仅仅看pitch 音高和start 、end 起始时间。其中,音高是128 个音符。它是普遍有规律的,值是1~128 ,不会出圈儿。但是这个起始时间却很随机,这里可以是啊1 秒开始,再往后可能就是100 秒开始。   如果,我们只预测 2 个音符,结果200 秒的时间出现的概率高。那么,第二个音符岂不是到等到3 分钟后再演奏。另外,很显然演奏是有先后顺序的,因此要起止时间遵从随机的概率分布,是不靠谱的。   我觉得,一个音符会演奏多久,以及前后音符的时间间距,这两项相对来说是比较稳定的。他们更适合作为训练参数。   因此,我们决定把音符预处理成如下格式: Note(duration=0.16, step=0.00, pitch=54), Note(duration=0.56, step=0.31, pitch=53), Note(duration=0.26, step=0.22, pitch=24), ……   duration 表示演奏时长,这个音符会响多久,它等于end-start 。   step 表示步长,本音符距离上一个出现的时间间隔,它等于start2-start1 。   原始数据格式 [start,end] ,同预处理后的数据格式[duration,step] ,两者是可以做到相互转化的。   我们把所有的训练集文件整理一下: import pretty_midi import tensorflow as tf midi_inputs = [] # 存放所有的音符 filenames = tf.io.gfile.glob("datasets/*.midi") # 循环所有midi文件 for f in filenames: pm = pretty_midi.PrettyMIDI(f) # 加载一个文件 instruments = pm.instruments # 获取乐器 instrument = instruments[0] # 取第一个乐器,此处是原声大钢琴 notes = instrument.notes # 获取乐器的演奏数据 # 以开始时间start做个排序。因为默认是依照end排序 sorted_notes = sorted(notes, key=lambda note: note.start) prev_start = sorted_notes[0].start # 循环各项指标,取出前后关联项 for note in sorted_notes: step = note.start - prev_start # 此音符与上一个距离 duration = note.end - note.start # 此音符的演奏时长 prev_start = note.start # 此音符开始时间作为最新 # 指标项:[音高(音符),同前者的间隔,自身演奏的间隔] midi_inputs.append([note.pitch, step, duration])   上面的操作,是把所有的 MIDI 文件,依照预处理的规则,全部处理成[pitch, step, duration] 格式,然后存放到midi_inputs 数组中。   这只是第一步操作。后面我们要把这个朴素的格式,拆分成输入和输出的结对。然后,转化为 TensorFlow 框架需要的数据集格式。seq_length = 24 # 输入序列长度 vocab_size = 128 # 分类数量 # 将序列拆分为输入和输出标签对 def split_labels(sequences): inputs = sequences[:-1] # 去掉最后一项最为输入 # 将音高除以128,便于 inputs_x = inputs/[vocab_size,1.0,1.0] y = sequences[-1] # 截取最后一项作为输出 labels = {"pitch":y[0], "step":y[1],"duration":y[2]} return inputs_x, labels # 搞成tensor,便于流操作,比如notes_ds.window notes_ds = tf.data.Dataset.from_tensor_slices(midi_inputs) cut_seq_length = seq_length+1 # 截取的长度,因为要拆分为输入+输出,因此+1 # 每次滑动一个数据,每次截取cut_seq_length个长度 windows = notes_ds.window(cut_seq_length, shift=1, stride=1,drop_remainder=True) flatten = lambda x: x.batch(cut_seq_length, drop_remainder=True) sequences = windows.flat_map(flatten) # 将25,拆分为24+1。24是输入,1是预测。进行训练 seq_ds = sequences.map(split_labels, num_parallel_calls=tf.data.AUTOTUNE) buffer_size = len(midi_inputs) - seq_length # 拆分批次,缓存等优化 train_ds = (seq_ds.shuffle(buffer_size) .batch(64, drop_remainder=True) .cache().prefetch(tf.data.experimental.AUTOTUNE))   我们先分析 split_labels 这个方法。它接收一段序列数组。然后将其分为两段,最后1 项作为后段,其余部分作为前段。   我们把 seq_length 定义为24 ,从总数据midi_inputs 中,利用notes_ds.window 实现每次取25 个数据,取完了向后移动1 格,再继续取数据。直到凑不齐25 个数据(drop_remainder=True 意思是不足25 弃掉)停止。   至此,我们就有了一大批以 25 为单位的数据组。其实,他们是:1~25 、2~26 、3~27 ……   然后,我们再调用 split_labels ,将其全部搞成24+1 的输入输出对。此时数据就变成了:(1~24,25) 、(2~25,26) ……。接着,再调用batch 方法,把他们搞成每64 组为一个批次。这一步是框架的要求。   至此,我们就把准备工作做好了。后面,就该交给神经网络训练去了。 训练:构建神经网络结构   这一步,我们将构建一个神经网络模型。它将不断地由 24 个音符观察下一个出现的音符。它记录,它思考,它尝试推断,它默写并对照答案。一旦见得多了,量变就会引起质变,它将从整个音乐库的角度,给出作曲的最优解。   好了,上代码: input_shape = (seq_length, 3) # 输入形状 inputs = tf.keras.Input(input_shape) x = tf.keras.layers.LSTM(128)(inputs) # 输出形状 outputs = { "pitch": tf.keras.layers.Dense(128, name="pitch")(x), "step": tf.keras.layers.Dense(1, name="step")(x), "duration": tf.keras.layers.Dense(1, name="duration")(x), } model = tf.keras.Model(inputs, outputs)   上面代码我们定义了输入和输出的格式,然后中间加了个 LSTM 层。   先说输入。因为我们给的格式是 [音高,间隔,时长] 共3 个关键指标。而且每24 个音,预测下一个音。所以input_shape = (24, 3) 。   再说输出。我们最终期望 AI 可以自动预测音符,当然要包含音符的要素,那也就是outputs = {"pitch","step","duration"} 。其中,step 和duration 是一个数就行,也就是Dense(1) 。但是,pitch 却不同,它需要是128 个音符中的一个。因此,它是Dense(128) 。   最后说中间层。我们期望有人能将输入转为输出,而且最好还有记忆。前后之间要能综合起来,要根据前面的铺垫,后面给出带有相关性的预测。那么,这个长短期记忆网络 LSTM (Long Short-Term Memory)就是最佳的选择了。   最终, model.summary() 打印结构如下所示:   Layer (type)   Output Shape   Param   Connected to   input (InputLayer)   [(None, 24, 3)]   0
  []   lstm (LSTM)   (None, 128)   67584
  ["input[0][0]"]   duration (Dense)   (None, 1)   129
  ["lstm[0][0]"]   pitch (Dense)   (None, 128)   16512
  ["lstm[0][0]"]   step (Dense)   (None, 1)   129
  ["lstm[0][0]"]   Total params: 84,354   后面,配置训练参数,开始训练: checkpoint_path = "model/model.ckpt" # 模型存放路径 model.compile( # 配置参数 loss=loss, loss_weights={"pitch": 0.05,"step": 1.0,"duration":1.0}, optimizer=tf.keras.optimizers.Adam(learning_rate=0.01), ) # 模型保存参数 cp_callback = tf.keras.callbacks.ModelCheckpoint( filepath=checkpoint_path ,save_weights_only=True, save_best_only=True) # 启动训练,训练50个周期 model.fit(train_ds, validation_data=train_ds , epochs=50,callbacks=[cp_callback])   训练完成之后,会将模型保存在 "model/model.ckpt" 目录下。而且,我们设置了只保存最优的一个模型save_best_only=True 。   上面有个需要特别说明的地方,那就是在 model.compile 中,给损失函数加了一个权重loss_weights 的配置。这是因为,在输出的三个参数中,pitch 音高的128 分类跨度较大,一旦预测有偏差,就会导致损失函数的值很大。而step 和duration 本身数值就很小,都是0.0x 秒,损失函数的值变化较小。这种不匹配,会导致后两个参数的变化被忽略,只关心pitch 的训练。因此需要降低pitch 的权重平衡一下。至于具体的数值,是调试出来的。   出于讲解的需要,上面的代码仅仅是关键代码片段。文末我会把完整的项目地址公布出来,那个是可以运行的。   好了,训练上 50 轮,保存完结果模型。下面,就该去做预测了。 预测和播放:实现AI作曲   现在这个模型,已经可以根据 24 个音符去推测出下一个音符了。我们来试一下。# 加载模型 if os.path.exists(checkpoint_path + ".index"): model.load_weights(checkpoint_path) # 从音符库中随机拿出24个音符,当然你也可以自己编 sample_notes = random.sample(midi_inputs, 24) num_predictions = 600 # 预测后面600个 # 循环600次,每次取最新的24个 for i in range(num_predictions): # 拿出最后24个 n_notes = sample_notes[-seq_length:] # 主要给音高做一个128分类归一化 notes = [] for input in n_notes: notes.append([input[0]/vocab_size,input[1],input[2]]) # 将24个音符交给模型预测 predictions = model.predict([notes]) # 取出预测结果 pitch_logits = predictions["pitch"] pitch = tf.random.categorical(pitch_logits, num_samples=1)[0] step = predictions["step"][0] duration = predictions["duration"][0] pitch, step, duration = int(pitch), float(step), float(duration) # 将预测值添加到音符数组中,进行下一次循环 sample_notes.append([pitch, step, duration])   其实,关键代码就一句 predictions = model.predict([notes]) 。根据24 个音符,预测出来下一个音符的pitch 、step 和duration 。其他的,都是辅助操作。   我们从素材库里,随机生成了 24 个音符。其实,如果你懂声乐,你也可以自己编24 个音符。这样,起码能给音乐定个基调。因为,后面的预测都是根据前面特征来的。当然,也可以不是24 个,根据2 个生成1 个也行。那前提是,训练的时候也得是2+1 的模式。但是,我感觉还是24 个好,感情更深一些。   从 24 个生成1 个后,变成了25 个。然后再取这25 个中的最后24 个,继续生成下一个。循环600 次,最后生成了624 个音符。打印一下:[[48, 0.001302083333371229, 0.010416666666628771], [65, 0.11979166666674246, 0.08463541666651508] …… [72, 0.03634712100028992, 0.023365378379821777], [41, 0.04531348496675491, 0.011086761951446533]]   但是,这是预处理后的特征,并非是可以直接演奏的音符。是否还记得 duration = end-start 以及step=start2-start1 。我们需要把它们还原成为MIDI 体系下的属性:# 复原midi数据 prev_start = 0 midi_notes = [] for m in sample_notes: pitch, step, duration = m start = prev_start + step end = start + duration prev_start = start midi_notes.append([pitch, start, end])   这样,就把 [pitch, step, duration] 转化成了[pitch, start, end] 。打印midi_notes 如下:[[48, 0.001302083333371229, 0.01171875], [65, 0.12109375000011369, 0.20572916666662877], …… [72, 32.04372873653976, 32.067094114919584], [41, 32.08904222150652, 32.100128983457964]]   我们从数据可以看到,最后播放到了 32 秒。也就说我们AI 生成的这段600 多个音符的乐曲,可以播放32 秒。   听一听效果,那就把它写入 MIDI 文件吧。# 写入midi文件 pm = pretty_midi.PrettyMIDI() instrument = pretty_midi.Instrument( program=pretty_midi.instrument_name_to_program("Acoustic Grand Piano")) for n in midi_notes: note = pretty_midi.Note(velocity=100,pitch=n[0],start=n[1],end=n[2]) instrument.notes.append(note) pm.instruments.append(instrument) pm.write("out.midi")   MIDI 文件有5 个必需的要素。其中,乐器我们设置为"Acoustic Grand Piano" 原声大钢琴。velocity 没有参与训练,但也需要,我们设为固定值100 。其他的3 个参数,都是AI 生成的,依次代入。最后,把结果生成到out.midi 文件中。   使用 Window 自带的Media Player 就可以直接播放这个文件。你听不到,我可以替你听一听。   听完了,我谈下感受吧。   怎么描述呢?我觉得,说好听对不起良心,反正,不难听。   好了, AI 作曲就到此为止了。   源代码已上传到 GitHub 地址是:https://github.com/hlwgy/ai_music。

一加Ace第一天使用就烫手?用户不必惊慌,温度在正常范围内玩游戏烫手就要退货?不懂手机确实可能不太理解,但一加Ace这款产品的散热做得不错。天气热了,玩游戏都会发烫,所以大家不必过度惊慌。尽管现在智能手机已经非常普及了,但是真正了解这个行孙杨的座驾是什么?看到4000万的布加迪威龙后,网友不淡定了提起泳坛一哥孙杨,相信大家都比较熟悉,对于他在国家游泳队的表现也会竖起大拇指。作为国家游泳队的队长,孙杨保持着男子1500米游泳和男子400米游泳的世界纪录。在19年结束的韩国光州腾讯的二当家张志东低调的千亿富豪,马化腾背后的男人都说一个成功男人的背后,都会有一个默默付出的女人,但马化腾成功的背后,却有一个一直默默付出的男人,这个男人就是腾讯的二当家张志东。张志东是和马化腾一起打下腾讯帝国的超级元老,是腾讯A股但凡股票出现以下特征,说明主力准备拉升股价,请捂住股票古时军事家作战讲究知己知彼,百战不殆。散户投资者若想达到成功猎庄的目的,首先要对庄家有个深入且细致的了解,通晓庄家的优势,明了庄家的劣势。坐庄过程中,庄家的招数往往虚虚实实忽真忽假五月的风,落杯为酒,入心为念看不出奇她很能喝只是很难呷上一口一般情况下,只要我在她就忍痛割爱说好的不喝,怎么又开瓶了真好,看得出生啤的后劲很足开始还算淡定,笑起来还算风雅即便上墙,也是貌美如花最后就有点不像话(32)名人名言名句今天应做的事没有做,明天再早也是耽误了。瑞士裴斯泰洛齐裴斯泰洛齐是19世纪瑞士著名的民主主义教育家。浪费别人的时间是谋财害命,浪费自己的时间是慢性自杀。苏列宁弗拉基米尔伊里奇列宁俄和谁在一起,真的很重要你是谁?你身边都有谁?Whoareyou?Whoareyouwith?这两个问题,决定了你的一生会是什么样的。Thesetwoquestionsdeterminewhatyourl甜美阳光的文案做大胆的女孩,大胆地去经历所有的快乐把自己打扮得得体养眼不单是对别人和自己的尊重,更是能力的象征,代表着你能从容地兼顾工作和生活的事情,而不是疲于奔波。我途经一场花的盛放,想把它们拍给你看,我拍给你看,并不是为了称赞2。33亿年前,地球下了一场持续100万年的大雨,这是真的吗?综述白垩纪时期的事情,我们很多人都已经从多年来的科普读物上有所耳闻,这个时期,是恐龙主宰地球的时期,体型巨大的恐龙充斥四处,所有的动物仿佛在进行一场军备竞赛,体型都往大了生长。其实越南最繁华的城市西贡,富裕程度堪比上海,人人都是百万富翁跟随关注越南靠近柬埔寨。根据小日子的旅行习惯,在访问柬埔寨后顺道去越南是很自然的。这是湄公河快线在金边的起点。你试过开车越境吗?柬埔寨出境,叫到名字的上车六小时前是柬埔寨边境。越南北京三环路内,新建一片城市公园风景好,运动休闲拍照遛娃特别棒这几年北京的城市发展日新月异,自然环境与城市人文的结合度也越来越高,尤其是公园文化更是普通的北京市民每天都能清晰感受的一种舒适氛围。据说,在几年之内,北京市政府要求城市公园和绿地要
柿饼葡萄干一定要洗了之后再吃吗?你都误解这么多年了对于嗜甜如命的人群来说,像柿饼葡萄干这种甜甜的食物,是他们的最爱,直接吃泡水喝煮粥煮汤等等,都是别有一番滋味。可这里有一个细节,你注意到了吗?柿饼葡萄干一定要洗了之后再吃吗?有的人结婚20多年住出租屋,不要孩子,只牵初恋手,李健到底有多干净?文流水十年闲编辑9号探秘人如今,娱乐圈明星塌房情况时有发生,除了常见的流量明星,还有一些有才情的实力艺人也不免走上歪路,令人咋舌。高晓松曾说年轻时,我们都想一生穿着白衬衣,一生只爱高熵协同!锂电最新Nature子刊,首次阐明鸡尾酒效应!第一作者KaiWang通讯作者穆晓科,ChristianKbel通讯单位德国卡尔斯鲁厄理工学院论文DOIhttpsdoi。org10。1038s41467023370346全文速览数据存储比大龄未婚更让我头秃,入手极空间Z4S轻松治愈内存焦虑最近,刷知乎热榜时,一条过了30岁,未婚男生和女生哪一个更焦虑?的话题引起了我的关注,同样作为大龄剩男中的一员,曾经也为婚姻焦虑过,但是相比大龄未婚更让我头秃的是数据存储。作为一家姻缘殿里无人问津,财神殿里长跪不起这届年轻人只上香,不上进?停一停!别贴标签了!不是去心心念念的网红店打卡不是去桌游店里来一盘刺激的狼人杀不是在电影院里宅一下午现在年轻人的周末到底被谁占领了?答案是去上香了不知道啥时候起虔诚寺庙之类的词汇和年轻人绑定在了一起票4年时间,从9。3涨到9。6,它是最好的战争剧,也是最真实残酷的经典的电视剧,总是能够在时间的长河里变得越发有魅力。好的故事值得反复咀嚼,从中看到过去的历史,当下的警惕,以及未来的思考。2019年看我的团长我的团的时候,这部剧口碑是9。3分,分CDESS认证数据中心环境可持续专家课程背景在物联网传感器和人工智能所需数据和处理能力爆炸的推动下,更多的数据中心正在建设中。数据中心在总功耗中所占的比例也在同步增长。数据中心的能源效率优化和环境可持续性设计已变得至北京石景山区特色产业建设加磅中关村工业互联网产业园二期项目启动央广网北京3月22日消息(记者庞婷)3月22日,位于北京石景山区的中关村工业互联网产业园项目二期(605地块)正式开工启动。随着二期项目建设推进,这座投资90亿元总建筑面积达45万盘点2023年广东省重点项目有哪些广州大手笔广东省发改委近日印发广东省2023年重点建设项目计划。2023年,广东省共安排省重点项目1530个,总投资8。5万亿元,年度计划投资1万亿元安排开展前期工作的省重点建设前期预备项目三星也放大招!一部手机一部平板已在路上,可惜国内用户不会买账关注数码圈的小伙伴都知道,手机行业中除了苹果之外,大部分厂商的销量都是靠中低端机堆起来了,旗舰机的销量其实很少。就拿三星来说,虽然旗舰S系列以及折叠屏在全球范围内的出货量也是上千万另一个宇宙的证据?科学家发现重力正在逃逸到其他维度宇宙是否只有一个,一直是人类存在的最大谜团之一。然而,这个谜团可能终于有了解决的办法,科学家们认为他们可能找到了一种革命性的方法,可以帮助他们探测隐藏的维度。关键要点科学家们认为他