วิธีใช้ OpenAis Whisper เพื่อถอดความและทำให้ไฟล์เสียงดีขึ้น
Whisper เป็นระบบการรู้จำเสียงพูดที่ทันสมัยจาก OpenAI ที่ได้รับการฝึกฝนเกี่ยวกับข้อมูลที่มีการพูดหลายภาษาและมัลติทาสก์ที่รวบรวมจากเว็บ 680,000 ชั่วโมง ชุดข้อมูลขนาดใหญ่และหลากหลายนี้นำไปสู่การปรับปรุงความทนทานต่อการเน้นเสียงพื้นหลังและภาษาทางเทคนิค นอกจากนี้ยังช่วยให้การถอดความในหลายภาษารวมถึงการแปลจากภาษาเหล่านั้นเป็นภาษาอังกฤษ OpenAI เปิดตัวโมเดลและรหัสเพื่อทำหน้าที่เป็นรากฐานสำหรับการสร้างแอพพลิเคชั่นที่มีประโยชน์ซึ่งใช้ประโยชน์จากการจดจำเสียงพูด
ข้อเสียอย่างหนึ่งของเสียงกระซิบคือมันไม่สามารถบอกคุณได้ว่าใครกำลังพูดในการสนทนา นั่นเป็นปัญหาเมื่อวิเคราะห์การสนทนา นี่คือที่มาของ diarization diarization เป็นกระบวนการของการระบุว่าใครกำลังพูดในการสนทนา
ในบทช่วยสอนนี้คุณจะได้เรียนรู้วิธีการระบุลำโพงแล้วจับคู่กับการถอดความของ Whisper เราจะใช้ pyannote-audio เพื่อทำสิ่งนี้ให้สำเร็จ เริ่มต้นกันเถอะ!
ก่อนอื่นเราต้องเตรียมไฟล์เสียง เราจะใช้พอดคาสต์ Lex Fridmans 20 นาทีแรกพร้อมดาวน์โหลด Yann ในการดาวน์โหลดวิดีโอและแยกเสียงเราจะใช้แพ็คเกจ yt-dlp
! pip install -U yt-dlpเราจะต้องติดตั้ง FFMPEG
! wget -O - -q https://github.com/yt-dlp/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-gpl.tar.xz | xz -qdc | tar -xตอนนี้เราสามารถทำการดาวน์โหลดจริงและการสกัดเสียงผ่านบรรทัดคำสั่ง
! yt-dlp -xv --ffmpeg-location ffmpeg-master-latest-linux64-gpl/bin --audio-format wav -o download.wav -- https://youtu.be/SGzMElJ11Cc ตอนนี้เรามีไฟล์ download.wav ในไดเรกทอรีการทำงานของเรา มาตัดเสียง 20 นาทีแรก เราสามารถใช้แพ็คเกจ PYDUB สำหรับสิ่งนี้ด้วยรหัสเพียงไม่กี่บรรทัด
! pip install pydub from pydub import AudioSegment
t1 = 0 * 1000 # works in milliseconds
t2 = 20 * 60 * 1000
newAudio = AudioSegment . from_wav ( "download.wav" )
a = newAudio [ t1 : t2 ]
a . export ( "audio.wav" , format = "wav" ) audio.wav ตอนนี้เป็น 20 นาทีแรกของไฟล์เสียง
pyannote.audio เป็นชุดเครื่องมือโอเพนซอร์ซที่เขียนใน Python สำหรับการ diarization ลำโพง ขึ้นอยู่กับกรอบการเรียนรู้ของเครื่อง Pytorch มันมีชุดของหน่วยการสร้างระบบประสาทแบบ end-to-end ที่สามารถฝึกอบรมได้ซึ่งสามารถรวมกันได้ pyannote.audio ยังมาพร้อมกับแบบจำลองที่ผ่านการฝึกฝนและท่อที่ครอบคลุมโดเมนที่หลากหลายสำหรับการตรวจจับกิจกรรมเสียงการแบ่งส่วนลำโพงการตรวจจับคำพูดที่ซ้อนทับกัน
การติดตั้ง pyannote และเรียกใช้บนเสียงวิดีโอเพื่อสร้าง diarizations
! pip install pyannote.audio from pyannote . audio import Pipeline
pipeline = Pipeline . from_pretrained ( 'pyannote/speaker-diarization' ) DEMO_FILE = { 'uri' : 'blabal' , 'audio' : 'audio.wav' }
dz = pipeline ( DEMO_FILE )
with open ( "diarization.txt" , "w" ) as text_file :
text_file . write ( str ( dz ))ให้พิมพ์สิ่งนี้เพื่อดูว่ามันเป็นอย่างไร
print(*list(dz.itertracks(yield_label = True))[:10], sep="n")
เอาต์พุต:
(<Segment(2.03344, 36.8128)>, 0, 'SPEAKER_00')
(<Segment(38.1122, 51.3759)>, 0, 'SPEAKER_00')
(<Segment(51.8653, 90.2053)>, 1, 'SPEAKER_01')
(<Segment(91.2853, 92.9391)>, 1, 'SPEAKER_01')
(<Segment(94.8628, 116.497)>, 0, 'SPEAKER_00')
(<Segment(116.497, 124.124)>, 1, 'SPEAKER_01')
(<Segment(124.192, 151.597)>, 1, 'SPEAKER_01')
(<Segment(152.018, 179.12)>, 1, 'SPEAKER_01')
(<Segment(180.318, 194.037)>, 1, 'SPEAKER_01')
(<Segment(195.016, 207.385)>, 0, 'SPEAKER_00')
สิ่งนี้ดูดีอยู่แล้ว แต่เรามาทำความสะอาดข้อมูลกันหน่อย:
def millisec ( timeStr ):
spl = timeStr . split ( ":" )
s = ( int )(( int ( spl [ 0 ]) * 60 * 60 + int ( spl [ 1 ]) * 60 + float ( spl [ 2 ]) ) * 1000 )
return s
import re
dz = open ( 'diarization.txt' ). read (). splitlines ()
dzList = []
for l in dz :
start , end = tuple ( re . findall ( '[0-9]+:[0-9]+:[0-9]+.[0-9]+' , string = l ))
start = millisec ( start ) - spacermilli
end = millisec ( end ) - spacermilli
lex = not re . findall ( 'SPEAKER_01' , string = l )
dzList . append ([ start , end , lex ])
print ( * dzList [: 10 ], sep = ' n ' ) [33, 34812, True]
[36112, 49375, True]
[49865, 88205, False]
[89285, 90939, False]
[92862, 114496, True]
[114496, 122124, False]
[122191, 149596, False]
[150018, 177119, False]
[178317, 192037, False]
[193015, 205385, True]
ตอนนี้เรามีข้อมูล diarization ในรายการ ตัวเลขสองตัวแรกคือเวลาเริ่มต้นและสิ้นสุดของเซ็กเมนต์ลำโพงในมิลลิวินาที หมายเลขที่สามคือบูลีนที่บอกเราว่าลำโพงเป็น Lex หรือไม่
ต่อไปเราจะแนบกลุ่มเสียงตาม diarization โดยมีตัวเว้นวรรคเป็นตัวคั่น
from pydub import AudioSegment
import re
sounds = spacer
segments = []
dz = open ( 'diarization.txt' ). read (). splitlines ()
for l in dz :
start , end = tuple ( re . findall ( '[0-9]+:[0-9]+:[0-9]+.[0-9]+' , string = l ))
start = int ( millisec ( start )) #milliseconds
end = int ( millisec ( end )) #milliseconds
segments . append ( len ( sounds ))
sounds = sounds . append ( audio [ start : end ], crossfade = 0 )
sounds = sounds . append ( spacer , crossfade = 0 )
sounds . export ( "dz.wav" , format = "wav" ) #Exports to a wav file in the current path. print ( segments [: 8 ])[2000, 38779, 54042, 94382, 98036, 121670, 131297, 160702]ต่อไปเราจะใช้ Whisper เพื่อคัดลอกส่วนต่างๆของไฟล์เสียง สำคัญ: มีความขัดแย้งในเวอร์ชันกับ pyannote.audio ส่งผลให้เกิดข้อผิดพลาด วิธีแก้ปัญหาของเราคือการเรียกใช้ Pyannote ก่อนแล้วก็กระซิบ คุณสามารถเพิกเฉยต่อข้อผิดพลาดได้อย่างปลอดภัย
การติดตั้ง Open AI Whisper
! pip install git+https://github.com/openai/whisper.git รันเปิด AI Whisper บนไฟล์เสียงที่เตรียมไว้ มันเขียนการถอดความลงในไฟล์ คุณสามารถปรับขนาดรุ่นตามความต้องการของคุณ คุณสามารถค้นหาทุกรุ่นบนการ์ดรุ่นบน GitHub
! whisper dz.wav --language en --model base [00:00.000 --> 00:04.720] The following is a conversation with Yann LeCun,
[00:04.720 --> 00:06.560] his second time on the podcast.
[00:06.560 --> 00:11.160] He is the chief AI scientist at Meta, formerly Facebook,
[00:11.160 --> 00:15.040] professor at NYU, touring award winner,
[00:15.040 --> 00:17.600] one of the seminal figures in the history
[00:17.600 --> 00:20.460] of machine learning and artificial intelligence,
...
ในการทำงานกับไฟล์. VTT เราจำเป็นต้องติดตั้งไลบรารี WebVTT-PY
! pip install -U webvtt-pyมาดูข้อมูล:
import webvtt
captions = [[( int )( millisec ( caption . start )), ( int )( millisec ( caption . end )), caption . text ] for caption in webvtt . read ( 'dz.wav.vtt' )]
print ( * captions [: 8 ], sep = ' n ' ) [0, 4720, 'The following is a conversation with Yann LeCun,']
[4720, 6560, 'his second time on the podcast.']
[6560, 11160, 'He is the chief AI scientist at Meta, formerly Facebook,']
[11160, 15040, 'professor at NYU, touring award winner,']
[15040, 17600, 'one of the seminal figures in the history']
[17600, 20460, 'of machine learning and artificial intelligence,']
[20460, 23940, 'and someone who is brilliant and opinionated']
[23940, 25400, 'in the best kind of way,']
...
ต่อไปเราจะจับคู่แต่ละบรรทัดการถอดเสียงกับ diarizations บางอย่างและแสดงทุกอย่างโดยการสร้างไฟล์ HTML เพื่อให้ได้เวลาที่ถูกต้องเราควรดูแลชิ้นส่วนในเสียงดั้งเดิมที่ไม่มีส่วนร่วม เราผนวก Div ใหม่สำหรับแต่ละเซ็กเมนต์ในเสียงของเรา
# we need this fore our HTML file (basicly just some styling)
preS = '<!DOCTYPE html>n<html lang="en">n <head>n <meta charset="UTF-8">n <meta name="viewport" content="width=device-width, initial-scale=1.0">n <meta http-equiv="X-UA-Compatible" content="ie=edge">n <title>Lexicap</title>n <style>n body {n font-family: sans-serif;n font-size: 18px;n color: #111;n padding: 0 0 1em 0;n }n .l {n color: #050;n }n .s {n display: inline-block;n }n .e {n display: inline-block;n }n .t {n display: inline-block;n }n #player {nttposition: sticky;ntttop: 20px;nttfloat: right;nt}n </style>n </head>n <body>n <h2>Yann LeCun: Dark Matter of Intelligence and Self-Supervised Learning | Lex Fridman Podcast #258</h2>n <div id="player"></div>n <script>n var tag = document.createElement('script');n tag.src = "https://www.youtube.com/iframe_api";n var firstScriptTag = document.getElementsByTagName('script')[0];n firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);n var player;n function onYouTubeIframeAPIReady() {n player = new YT.Player('player', {n height: '210',n width: '340',n videoId: 'SGzMElJ11Cc',n });n }n function setCurrentTime(timepoint) {n player.seekTo(timepoint);n player.playVideo();n }n </script><br>n'
postS = 't</body>n</html>'
from datetime import timedelta
html = list(preS)
for i in range(len(segments)):
idx = 0
for idx in range(len(captions)):
if captions[idx][0] >= (segments[i] - spacermilli):
break;
while (idx < (len(captions))) and ((i == len(segments) - 1) or (captions[idx][1] < segments[i+1])):
c = captions[idx]
start = dzList[i][0] + (c[0] -segments[i])
if start < 0:
start = 0
idx += 1
start = start / 1000.0
startStr = '{0:02d}:{1:02d}:{2:02.2f}'.format((int)(start // 3600),
(int)(start % 3600 // 60),
start % 60)
html.append('ttt<div class="c">n')
html.append(f'tttt<a class="l" href="#{startStr}" id="{startStr}">link</a> |n')
html.append(f'tttt<div class="s"><a href="javascript:void(0);" onclick=setCurrentTime({int(start)})>{startStr}</a></div>n')
html.append(f'tttt<div class="t">{"[Lex]" if dzList[i][2] else "[Yann]"} {c[2]}</div>n')
html.append('ttt</div>nn')
html.append(postS)
s = "".join(html)
with open("lexicap.html", "w") as text_file:
text_file.write(s)
print(s)
ใน Lablab Discord เราพูดถึง repo นี้และหัวข้ออื่น ๆ อีกมากมายที่เกี่ยวข้องกับปัญญาประดิษฐ์! เช็คเอาต์กิจกรรม Hackathons ปัญญาประดิษฐ์ที่กำลังจะมาถึง